/* * file: server.c * written by: Christian Zahl * description: Server for PPP link * * Id * * Log */ static char rcsid[] = "Id\n";/*----- standard includefiles ----------------------------------------------*/ #include <stdio.h> #include <errno.h> #include <sys/types.h> #include <netinet/in_systm.h> #include <netinet/in.h> #include <netinet/ip.h> #include <netinet/udp.h> #include <sys/socket.h>
#include <fcntl.h> #include <sys/stat.h> #include <termio.h>
/*----- user includefiles --------------------------------------------------*/ #include "misc.h" #include "hdlc.h" #include "ppp.h" #include "ipUdpRtpCompr.h" #include "filehandler.h" #include "rtp.h"
/*----- defines ------------------------------------------------------------*/ #define SERVER_EXIT 2 #define DEF_TTL 127
/*----- type definitions ---------------------------------------------------*/ typedef struct { u32bit srcAddr; u32bit dstAddr; u16bit srcPort; u16bit dstPort; u16bit id; u8bit ttl; int s; } t_Cxt;
/*----- local functions ----------------------------------------------------*/ void RtpOutCb (u8bit *frame, int len, int type);
/*----- global functions ---------------------------------------------------*/ u32bit srcAddr; u16bit srcPort; u32bit dstAddr; u16bit dstPort;
/*----- local variables ----------------------------------------------------*/ static int linkInFd; static int linkOutFd; static int udpOutSocket; static int dstPt; /* dst RTP payload-type */ static t_Cxt cxtList[10];
#ifdef _AIX #define WITH_LOG 0 #define WITH_RCV_LOG 0 #define DEBUG(xxx) xxx #else #define DEBUG(xxx) #endif
#if WITH_LOG static FILE *log = NULL; #endif #if WITH_RCV_LOG static time_t t0; static FILE *rcvLog = NULL; static time_t lastRcv; static int nRcv; #endif
/*----- global variables ---------------------------------------------------*/
/*-------------------------------------------------------------------------*/ void TTYIn (int fd, int mode, void *date) { char buf[100]; int n; int i;
n = read (fd, buf, sizeof (buf)); for (i=0; i<n; i++) if (buf[i] == SERVER_EXIT) FileHandlerStop (); else { if (buf[i] == '\n') write (linkOutFd, "\r", 1); fprintf (stderr, "[1]"); write (linkOutFd, buf+i, 1); } fflush (stderr); } /* TTYIn */ /*-------------------------------------------------------------------------*/ void LinkInCb (int fd, int mode, void *data) /* * Callback will be called when there are data available from the link */ { u8bit buf[512]; int n; int i;
n = read (fd, buf, sizeof (buf)); if (n == -1 && errno == EINTR) return; if (n == 0) { /* EOF condition */ FileHandlerStop (); return; } for (i=0; i<n; i++) if (buf[i] == SERVER_EXIT) { FileHandlerStop (); return; } #ifdef TEST write (1, buf, n); #else HDLCReceive (buf, n); #endif } /* LinkInCb */ /*-------------------------------------------------------------------------*/ void LinkOutCb (u8bit *buf, int len) { #ifdef LOOPBACK_TEST HDLCReceive (buf, len); #else write (linkOutFd, buf, len); #endif } /* LinkOutCb */ /*-------------------------------------------------------------------------*/ void LinkInit () { FileHandlerCreate (linkInFd, FILEHANDLER_READ, LinkInCb, NULL); } /* LinkInit */ /*-------------------------------------------------------------------------*/ void LinkFini () { FileHandlerStop (); } /* LinkFini */ /*-------------------------------------------------------------------------*/ void IPInit () { PPPRegister (PPP_PROT_FULL_HEADERS, RtpOutCb, TYPE_FULL_HEADERS); PPPRegister (PPP_PROT_COMPRESSED_UDP, RtpOutCb, TYPE_COMPRESSED_UDP); PPPRegister (PPP_PROT_COMPRESSED_RTP, RtpOutCb, TYPE_COMPRESSED_RTP); PPPRegister (PPP_PROT_CONTEXT_STATE, RtpOutCb, TYPE_CONTEXT_STATE); #if WITH_LOG { char fn[100]; int now; now = time (NULL); sprintf (fn, "log.%d.rtp", now); log = fopen (fn, "wb"); } #endif } /* IPInit */ /*-------------------------------------------------------------------------*/ void IPFini () { #if WITH_LOG fclose (log); #endif } /* IPFini */ /*-------------------------------------------------------------------------*/ static int SendRtpPacket (t_Cxt *cxt, u8bit *rtpBuf, int len) /* * Generate a new IP/UDP/RTP packet and send it over the PPP link. */ { u8bit buf[1500]; u8bit out[1500]; struct ip *ip = (struct ip*) buf; struct udphdr *udp = (struct udphdr*) (buf +20); u8bit *rtp = buf +20 +8; int type; int outLen;
/*** generate a new IP header ***/ ip->ip_v = 4; /* IP v4 */ ip->ip_hl = 20 /4; /* fix 20 byte hdr */ ip->ip_tos = 0; /* no TOS */ ip->ip_len = 20 +8 +len; /* unimportant, because of compression */ ip->ip_id = cxt->id++; ip->ip_off = 0; /* no fragment, so no offset */ ip->ip_ttl = cxt->ttl; /* copy TTL */ ip->ip_p = 17; /* set to UDP */ ip->ip_sum = 0; ip->ip_src.s_addr = cxt->srcAddr; ip->ip_dst.s_addr = cxt->dstAddr; /* dst mcast addr */ /*** generate the UDP header ***/ udp->uh_sport = cxt->srcPort; udp->uh_dport = cxt->dstPort; udp->uh_ulen = len +8; udp->uh_sum = 0; /* no checksum */ /*** generate the RTP header + data ***/ memcpy (rtp, rtpBuf, len); /*** compress the generated packet ***/ len += 20 +8; outLen = IpUdpRtpCompress (buf, len, out, &type); if (outLen <= 0) return 0; /*** send it over the link ***/ if (type == TYPE_FULL_HEADERS) PPPSend (out, outLen, PPP_PROT_FULL_HEADERS); else if (type == TYPE_COMPRESSED_UDP) PPPSend (out, outLen, PPP_PROT_COMPRESSED_UDP); else if (type == TYPE_COMPRESSED_RTP) PPPSend (out, outLen, PPP_PROT_COMPRESSED_RTP); else { fprintf (stderr, "?"); return 0; } return outLen; } /* SendRtpPacket */ /*-------------------------------------------------------------------------*/ void RtpInCb (int fd, int mode, t_Cxt *cxt) /* * This callback is registered for every local RTP UDP socket. It receives the * RTP packet, and sends it to the RTP translator. If the translator has * something to transmit, we send the RTP packet over the link. */ { u8bit in[1500]; u8bit out[1500]; int len; struct sockaddr_in sin; int sinLen = sizeof (sin); int outLen;
len = recvfrom (fd, in, sizeof (in), 0, (struct sockaddr*)&sin, &sinLen); if (len <= 0) return; #if WITH_RCV_LOG { time_t t; time (&t); if (t != lastRcv) { if (lastRcv) for (; lastRcv<t; lastRcv++) { fprintf (rcvLog, "%d %9.6f\n", lastRcv-t0, 8.0*nRcv/1000.0); nRcv = 0; } lastRcv = t; nRcv = 0; } nRcv += len + 20 + 8; } #endif #ifdef _AIX if (sin.sin_addr.s_addr == 0xC06F6F03) return; #endif outLen = RtpTranslator (NULL, in, len, out); if (outLen <= 0) return; outLen = SendRtpPacket (cxt, out, outLen); #if WITH_LOG len += 20 +8; /* + IP + UDP header */ fprintf (log, "%d\t%d\t%d\n", len, outLen, outLen *100/len); #endif } /* RtpInCb */ /*-------------------------------------------------------------------------*/ void RtpOutCb (u8bit *frame, int len, int type) /* * CB, which receives the compressed IP/UDP/RTP frame from the PPP link and * sends it into the local network. */ { t_Cxt *cxt; u8bit buf[1500]; struct sockaddr_in sin; struct ip *ip = (struct ip*)buf; struct udphdr *udp; struct rtp *rtp; int rtpLen; static u8bit lastRtpBuf[1500]; static struct rtp* lastRtp = (struct rtp*)lastRtpBuf; static int lastSeq = 0; int s;
len = IpUdpRtpDecompress (frame, len, type, buf); /*** frame sucsessfully decompressed, so send it on the way ***/ if (len > 0) { udp = (struct udphdr*)IP_DATA(ip); rtp = (struct rtp*)UDP_DATA(udp); rtpLen = len - IP_HDR_BYTES (ip) - UDP_HDR_BYTES (udp); /*** search the context ***/ cxt = &cxtList[0]; /*** generate the output packet ***/ sin.sin_family = AF_INET; sin.sin_port = udp->uh_dport; sin.sin_addr.s_addr = ip->ip_dst.s_addr; #ifdef _AIX if (rtp->m) fprintf (stderr, "M"); else if (rtp->seq-lastRtp->seq == 1) { ; } else { fprintf (stderr, "%d:", rtp->seq-lastRtp->seq); s = (rtp->timestamp -lastRtp->timestamp) / (rtp->seq -lastRtp->seq); if (rtp->seq-lastSeq < 10) { while (++lastRtp->seq < rtp->seq) { lastRtp->timestamp += s; sendto (cxt->s, (void*)lastRtp, rtpLen, 0, (struct sockaddr*)&sin, sizeof (sin)); } } } memcpy (lastRtp, rtp, rtpLen); lastSeq = rtp->seq; #endif sendto (cxt->s, (void*)rtp, rtpLen, 0, (struct sockaddr*)&sin, sizeof (sin)); } else if (len < -2) { DEBUG (fprintf (stderr, "c");) PPPSend (buf, -len, PPP_PROT_CONTEXT_STATE); } } /* RtpOutCb */ /*-------------------------------------------------------------------------*/ RTPInit (u32bit srcAddr, u16bit srcPort, u32bit dstAddr, u16bit dstPort) /* * Initializes the RTP proxy server. This is done in a constant manner here * and should be done by some other kind of signalling. */ { int on = 1; int s; struct sockaddr_in sin; struct ip_mreq mr; int ttl = DEF_TTL; int off = 0;
s = socket (AF_INET, SOCK_DGRAM, 0); if (s < 0) { #ifdef _AIX perror ("RTPInit: socket"); #endif return; } setsockopt (s, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof (on)); memset (&sin, '\0', sizeof (sin)); sin.sin_family = AF_INET; sin.sin_port = htons (srcPort); sin.sin_addr.s_addr = htonl (srcAddr); if (bind (s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { sin.sin_addr.s_addr = INADDR_ANY; bind (s, (struct sockaddr*)&sin, sizeof(sin)); } if (IN_CLASSD (srcAddr)) { mr.imr_multiaddr.s_addr = htonl (srcAddr); mr.imr_interface.s_addr = INADDR_ANY; setsockopt (s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void*)&mr, sizeof (mr)); setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&ttl, sizeof(ttl)); setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&off, sizeof (off)); } /*** update the context ***/ cxtList[0].s = s; cxtList[0].srcAddr = srcAddr; cxtList[0].srcPort = srcPort; cxtList[0].dstAddr = dstAddr; cxtList[0].dstPort = dstPort; /*** install the filehandler ***/ FileHandlerCreate (s, FILEHANDLER_READ, RtpInCb, &cxtList[0]); udpOutSocket = s; RtpTranslatorInit (); #if WITH_RCV_LOG { char fn[100]; int now; now = time (NULL); t0 = now; sprintf (fn, "log.%d.rtp.rcv", now); rcvLog = fopen (fn, "wb"); } #endif } /* RTPInit */ /*-------------------------------------------------------------------------*/ RTPFini () { close (cxtList[0].s); RtpTranslatorFini (); #if WITH_RCV_LOG fclose (rcvLog); #endif } /* RTPFini */ /*-------------------------------------------------------------------------*/ ServerMainLoop (int _linkInFd, int _linkOutFd) { u32bit accm;
FileHandlerInit (); /*** initialize the physical layer ***/ linkInFd = _linkInFd; linkOutFd = _linkOutFd; LinkInit (); /*** initialize the HDLC layer ***/ accm = 0; accm |= (0x01 << SERVER_EXIT); /* special exit key */ accm |= (0x01 << 0x11); /* XON */ accm |= (0x01 << 0x13); /* XOFF */ HDLCInit (LinkOutCb); HDLCSetSndAccm (accm); HDLCSetRcvAccm (accm); HDLCSetAddrCtrlCompr (1); /*** initialize PPP layer ***/ PPPInit (); /*** initialize IP layer ***/ IPInit (); RTPInit (srcAddr, srcPort, dstAddr, dstPort); /*** enter the server's mainloop ***/ #ifdef _AIX FileHandlerCreate (0, FILEHANDLER_READ, TTYIn, NULL); #endif FileHandler (); /*** teminate the whole stack ***/ RTPFini (); IPFini (); PPPFini (); HDLCFini (); LinkFini (); FileHandlerFini (); } /* ServerMainLoop */ /*-------------------------------------------------------------------------*/ #ifndef _AIX main (int argc, char *argv[]) { struct termio savedTermio; struct termio termio; int i;
if (argc >= 2) { for (i=0; argv[1][i]; i++) if (argv[1][i] == '/') { argv[1][i] = '\0'; i++; break; } srcAddr = inet_addr (argv[1]); srcPort = atoi (argv[1]+i); } else { srcAddr = inet_addr ("224.2.0.1"); srcPort = 23456; } if (argc >= 3) { for (i=0; argv[2][i]; i++) if (argv[2][i] == '/') { argv[2][i] = '\0'; i++; break; } dstAddr = inet_addr (argv[2]); dstPort = atoi (argv[2]+i); } else { dstAddr = inet_addr ("224.2.0.1"); dstPort = 23456; } /*** save the current tty settings ***/ if (ioctl (0, TCGETA, &savedTermio) == -1) { perror ("ioctl"); exit (1); } /*** setup the tty interface ***/ ioctl (0, TCGETA, &termio); termio.c_iflag = 0; termio.c_oflag = 0; termio.c_cflag &= CBAUD; termio.c_cflag |= CS8 |CREAD |HUPCL; termio.c_lflag = 0; termio.c_cc [VMIN] = 1; termio.c_cc [VTIME] = 0; ioctl (0, TCSETA, &termio); /*** start the PPP interface ***/ ServerMainLoop (0, 1); /*** reset the TTY settings ***/ if (ioctl (0, TCSETA, &savedTermio) == -1) { perror ("ioctl"); } } /* main */ #endif
/* * file: modem.c * creation date: 11-Feb-1994 * last update: <obsolete> * written by: Christian Zahl * description: * *update history: * date who why */ static char rcsid[] = "Id: modem.c,v 1.18 1997/02/05 15:47:41 czahl Exp \n";/*** standard includefiles ***/ #include <stdio.h> #include <fcntl.h> #include <sgtty.h> #include <sys/ioctl.h> #include <sys/devinfo.h> /* #include <sys/tty.h> */ #include <signal.h> #include <termio.h> #include <sys/select.h> #include <sys/types.h> #include <unistd.h>
#include <sys/types.h> #include <sys/socket.h> #include <sys/socketvar.h> #include <netinet/in.h> #include <signal.h> #include <sys/errno.h> #include <sys/stat.h> #include <time.h> #include <netdb.h>
#include <sys/wait.h>
/*** user includefiles ***/ #include "misc.h"
/*** defines ***/ #define BUF_LEN 1024 #define PORT 8000
#define CHEXIT 1 #define MAX(a,b) ((a>b) ? a : b)
#define TERM_LOCAL 0 #define TERM_MODEM 1 #define TIMEOUT 60 #define DEBUG(xxx) xxx; fflush (stdout); #define LOG_FN "LOG.MODEM"
/*** type definitions ***/ typedef struct { int f; /* has to be the first! */ struct termio Termio; struct sgttyb Sgttyb; struct tchars Tchars; struct ltchars LTchars; int Localmode; } t_TermState;
/*** local functions ***/ static void Alarm (int SigNo, int Pid); static void Terminate (int SigNo, int Pid); static void SigAlarm ();
/*** global functions ***/
/*** local variables ***/ int baudRate; int dataBits; int parity; int stopBits; t_TermState Term[2] = {{-1}, {-1}}; int modemFlowControl = 99999; char *modemTtyName; char *modemTty; int modemFd; int channelNo = 0; int dataSend = 4; struct sigaction sa; int stop = 0;
/*** global variables ***/ extern u32bit srcAddr; extern u16bit srcPort; extern u32bit dstAddr; extern u16bit dstPort;
/*------------------------------------------------------------------*/ Usage () { printf ("usage: modem [-b baud] [-d databits] [-p parity] [-f{x|r}] <tty>\n"); printf ("\t<tty>\te.g. /dev/tty0\n"); printf ("\t<baud>\t50 75 110 150 3[00] 6[00] 12[00] 24[00] 48[00] 96[00] 192[00] 384[00]\n"); exit (1); } /*------------------------------------------------------------------*/ ParseArgs (int argc, char *argv[]) { int c;
baudRate = 38400; dataBits = 8; parity = 'n'; stopBits = 1; while ((c = getopt (argc, argv, "b:d:f:p:s:")) != -1) { switch (c) { case 'b': baudRate = atoi (optarg); break; case 'd': dataBits = atoi (optarg); break; case 'f': modemFlowControl = *optarg; break; case 'p': parity = *optarg; break; case 's': stopBits = atoi (optarg); break; default: case '?': Usage (); } } switch (baudRate) { case 50: baudRate = B50; break; case 75: baudRate = B75; break; case 110: baudRate = B110; break; case 150: baudRate = B150; break; case 3: case 300: baudRate = B300; break; case 6: case 600: baudRate = B600; break; case 12: case 1200: baudRate = B1200; break; case 24: case 2400: baudRate = B2400; break; case 48: case 4800: baudRate = B4800; break; default: printf ("\aInvalid baudRate, using 9600!\n"); case 96: case 9600: baudRate = B9600; break; case 192: case 19200: baudRate = B19200; break; case 384: case 38400: baudRate = B38400; break; } switch (dataBits) { case 5: dataBits = CS5; break; case 6: dataBits = CS6; break; case 7: dataBits = CS7; break; default: printf ("\aInvalid databits, using 8!\n"); case 8: dataBits = CS8; break; } switch (modemFlowControl) { case 'x': modemFlowControl = IXON; break; case 'r': modemFlowControl = 0; break; default: modemFlowControl = 0; break; } switch (parity) { default: printf ("\aInvaid parity, using no parity!\n"); case 'n': parity = 0; break; case 'e': parity = PARENB; break; case 'o': parity = PARENB | PARODD; break; case 'm': parity = PARENB | PAREXT; break; case 's': parity = PARENB | PAREXT; break; } switch (stopBits) { default: printf ("\aInvaid stopbits, using 1!\n"); case 1: stopBits = 0; break; case 2: stopBits = CSTOPB; break; } if (optind == argc) { printf ("\asorry, no tty given, aborting!\n"); exit (1); } else { modemTty = argv[optind++]; } if (optind != argc) { printf ("\ainvalid argument!\n"); Usage (); exit (1); } } /* ParseArgs */ /*------------------------------------------------------------------*/ CmdMode () { char cmd[100];
printf ("COMMAND MODE (type ? for help)\n"); while (1) { printf ("==> "); fflush (stdout); if (!gets (cmd)) continue; switch (cmd[0]) { case 'f': if (cmd[1] == 'i') tcflush (Term[TERM_MODEM].f, TCIFLUSH); else if (cmd[1] == 'o') tcflush (Term[TERM_MODEM].f, TCOFLUSH); else if (cmd[1] == 'b') tcflush (Term[TERM_MODEM].f, TCIOFLUSH); else printf ("\aillegal option for f(lush) [i|o|b]\n"); break; case 'o': printf ("USE CTRL/A FOR COMMAND MODE\n"); Server (); break; case 'r': RtpProxy (cmd+1); break; case 'q': Terminate (0, 0); break; case '?': case 'h': printf ("AVAILABLE COMMANDS:\n"); printf ("\tflush [i|o|b] flush IN, OUT or BOTH\n"); printf ("\tr)tp proxy serve as RTP proxy\n"); printf ("\to)nline go online\n"); printf ("\tq)uit say good-bye\n"); printf ("\t? or h)elp prints this help information\n"); break; case '\0': break; default: printf ("\aINVALID COMMAND (h for help)\n"); break; } /* switch */ } /* while */ } /* CmdMode */ /*------------------------------------------------------------------*/ Server () { #define BUFSIZE (32*1024) struct termio Termio; int i; char Buf[BUFSIZE]; fd_set ReadSet; int Fds; int j;
signal (SIGTERM, Terminate); signal (SIGINT, Terminate); signal (SIGQUIT, Terminate); signal (SIGHUP, Terminate); sa.sa_handler = SigAlarm; sa.sa_flags = SA_RESTART; sigaction (SIGALRM, &sa, NULL); alarm (TIMEOUT);
/*** Einstellungen für local Term ***/ ioctl (0, TCGETA, &Termio); /* Termio.c_iflag = IXON|IXOFF; */ Termio.c_iflag = 0; Termio.c_oflag = 0; Termio.c_lflag = 0; Termio.c_cc [VMIN] = BUFSIZE; Termio.c_cc [VTIME] = 3; ioctl (0, TCSETA, &Termio); /*** MAINLOOP ***/ Fds = 0; Fds = MAX (Fds, 0); Fds = MAX (Fds, Term[TERM_MODEM].f); Fds++; while (1) { FD_ZERO (&ReadSet); FD_SET (0, &ReadSet); FD_SET (Term[TERM_MODEM].f, &ReadSet); if ((i = select (Fds, &ReadSet, NULL, NULL, NULL)) == -1) { if (errno == EINTR) continue; perror ("select"); } /*** Daten vom Modem gekommen? ***/ if (FD_ISSET (Term[TERM_MODEM].f, &ReadSet)) { if ((i = read (Term[TERM_MODEM].f, Buf, BUFSIZE)) >= 1) { write (1, Buf, i); } /* if */ } /* if */ /*** Tasten vom tty behandeln ***/ if (FD_ISSET (0, &ReadSet)) { i = read (0, Buf, BUFSIZE); /* von KBD lesen */ dataSend = 4; if (i == 1) { if (Buf[0] == CHEXIT) /* in den cmd Modem */ break; else write (Term[TERM_MODEM].f, Buf, i); /* hinschicken */ } else write (Term[TERM_MODEM].f, Buf, i); } /* if */ } /* while */ alarm (0); SetTtyStates (&Term[TERM_LOCAL]); } /* Server */ /*------------------------------------------------------------------*/ static void Terminate (int SigNo, int Pid) /* * Signal Händler für den bösen Fall und für den Fall, das jemand * ^A gedrückt hat. */ { int i;
/*** flush in and output ***/ tcflush (Term[TERM_MODEM].f, TCIOFLUSH); /*** restore tty states ***/ /* SetTtyStates (&Term[TERM_MODEM]); */ SetTtyStates (&Term[TERM_LOCAL]); close (Term[TERM_MODEM].f); DEBUG (printf ("\rSignal %d catched...", SigNo);) /*** remove the lock file ***/ DEBUG (printf ("\nRemoving TTY lock...");) ttyunlock (modemTtyName); DEBUG (printf ("done!\n");) DEBUG (printf ("Bye!\n");) exit (0); } /* Terminate */ /*------------------------------------------------------------------*/ SaveTtyStates (t_TermState *Term) { if (Term->f == -1) return 0; if (ioctl (Term->f, TCGETA, &Term->Termio) == -1) perror ("tty TCGETA\n"); if (ioctl (Term->f, TIOCGLTC, &Term->LTchars) == -1) perror ("tty TIOCGLTC"); if (ioctl (Term->f, TIOCGETP, &Term->Sgttyb) == -1) perror ("tty TIOCGETP"); if (ioctl (Term->f, TIOCGETC, &Term->Tchars) == -1) perror ("tty TIOCGETC"); if (ioctl (Term->f, TIOCLGET, &Term->Localmode) == -1) perror ("tty TIOCLGET"); } /* SaveTtyStates */ /*------------------------------------------------------------------*/ SetTtyStates (t_TermState *Term) { if (Term->f == -1) return 0; if (ioctl (Term->f, TIOCLSET, &Term->Localmode) == -1) perror ("TIOCLSET"); if (ioctl (Term->f, TIOCSETC, &Term->Tchars) == -1) perror ("TIOCSETC"); if (ioctl (Term->f, TIOCSETP, &Term->Sgttyb) == -1) perror ("TIOCSETP"); if (ioctl (Term->f, TIOCSLTC, &Term->LTchars) == -1) perror ("TIOCSLTC"); if (ioctl (Term->f, TCSETA, &Term->Termio) == -1) perror ("TCSETA"); } /* SetTtyStates */ /*------------------------------------------------------------------*/ InitModem (int f) { struct termio Term; int i;
DEBUG (printf ("Getting modem paramters...");) ioctl (f, TCGETA, &Term); DEBUG (printf ("done!\n");) if (modemFlowControl == IXON) Term.c_iflag = IXON|IXOFF; else Term.c_iflag = 0; Term.c_oflag = 0; Term.c_cflag = baudRate |CS8 |CREAD |CLOCAL; Term.c_cflag = baudRate |dataBits |parity |stopBits |CREAD |CLOCAL; Term.c_lflag = 0; Term.c_cc [VMIN] = 1; Term.c_cc [VTIME] = 0; DEBUG (printf ("Setting modem paramter...");) ioctl (f, TCSETAF, &Term); DEBUG (printf ("done!\n");) return 0; } /* InitModem */ /*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/ RtpProxy (char *buf) { int i;
while (*buf && *buf == ' ') buf++; if (srcAddr == 0) { srcAddr = inet_addr ("224.2.0.1"); srcPort = 23456; dstAddr = inet_addr ("224.2.0.1"); dstPort = 23456; } for (i=0; buf[i]; i++) if (buf[i] == '/') { buf[i] = '\0'; srcAddr = inet_addr (buf); i++; buf += i; srcPort = atoi (buf); break; } while (*buf && *buf != ' ') buf++; while (*buf && *buf == ' ') buf++; for (i=0; buf[i]; i++) if (buf[i] == '/') { buf[i] = '\0'; dstAddr = inet_addr (buf); i++; buf += i; dstPort = atoi (buf); break; } printf ("ENTERING RTP / PPP PROXY MODE NOW, LEAVE WITH ^B...\n"); printf ("%08X/%d -> %08X/%d\n", srcAddr, srcPort, dstAddr, dstPort); ServerMainLoop (modemFd, modemFd); } /* RtpProxy */ /*------------------------------------------------------------------*/ static void SigAlarm () { if (dataSend == 0) { write (Term[TERM_MODEM].f, "\x11", 1); dataSend = 4; } dataSend--; alarm (TIMEOUT); } /* SigAlarm */ /*------------------------------------------------------------------*/ main (int argc, char *argv[]) { int i; int a; int fd;
printf ("[compiled on %s at %s]\n", __DATE__, __TIME__); ParseArgs (argc, argv); /*** strip the modem tty name from the device path ***/ modemTtyName = modemTty; for (i=strlen (modemTtyName)-1; i>0; i--) if (modemTtyName[i] == '/') { modemTtyName += i+1; break; } Term[TERM_LOCAL].f = 0; /*** check for any locks to this tty ***/ if (ttylock (modemTtyName) == -1) { fprintf (stderr, "Sorry, but the TTY %s is locked by another process!\n", modemTty); exit (1); } /*** istall various signal handler ***/ signal (SIGTERM, Terminate); signal (SIGINT, Terminate); signal (SIGQUIT, Terminate); signal (SIGHUP, Terminate); /*** open the modem tty without waiting ***/ if ((Term[TERM_MODEM].f = open (modemTty, O_RDWR |O_NDELAY)) == -1) { perror ("fopen"); ttyunlock (modemTtyName); exit (1); } modemFd = Term[TERM_MODEM].f; DEBUG (printf ("done!\n");) /*** save the tty states ***/ SaveTtyStates (&Term[TERM_LOCAL]); SaveTtyStates (&Term[TERM_MODEM]); InitModem (Term[TERM_MODEM].f); CmdMode (); } /* main */ /*------------------------------------------------------------------*/
/* * COPYRIGHT BY OERTEL & ZAHL SOFTWAREENTWICKLUNG GbR * file: HDLC.c * written by: Christian Zahl * description: Impelements an HDLC framing protocol (RFC-1662). * * Id * * Log */ static char rcsid[] = "Id\n";/*----- standard includefiles ----------------------------------------------*/ #include <stdio.h> #include <sys/time.h>
/*----- user includefiles --------------------------------------------------*/ #include "misc.h" #include "hdlc.h"
/*----- defines ------------------------------------------------------------*/ #define FRAME_LEN 1500 #define HDLC_FLAG 0x7E #define HDLC_ADDR 0xFF #define HDLC_CTRL 0x03 #define HDLC_ESC 0x7D #define HDLC_PUT_BYTE(out,nnn,byte) { \ u8bit b = byte; \ if (sndAccm[b]) { \ out[nnn++] = HDLC_ESC; \ out[nnn++] = b ^ 0x20; \ } else \ out[nnn++] = b;\ } #define PPPINITFCS16 0xffff /* Initial FCS value */ #define PPPGOODFCS16 0xf0b8 /* Good final FCS value */ #define FCS16(fff,xxx) fff = (fff >> 8) ^ fcstab[(fff ^ (xxx)) & 0xff] #ifdef _AIX #define DEBUG(xxx) xxx #else #define DEBUG(xxx) #endif
/*----- type definitions ---------------------------------------------------*/
/*----- local functions ----------------------------------------------------*/
/*----- global functions ---------------------------------------------------*/
/*----- local variables ----------------------------------------------------*/ static u8bit rcvAccm[256]; static u8bit sndAccm[256]; static u8bit frame[FRAME_LEN]; static int frameLen; static int esc; static int addrCtrlCompr; static void (*cb) (); /* cb for incomming HDLC frames */ static void (*linkOutCb) (); /* cb for sending HDLC frames */ static int errFCS = 0; /* # of FCS errors */ static int errTooShort = 0; /* # of frames too short */ static int errTooLong = 0; /* # of frames too long */ static int errFrame = 0; /* # of general framing errors */ static int goodFrames = 0; /* # of received good frames */ static u16bit fcstab[256] = { 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 }; #ifdef _AIX #define WITH_LOG 0 #define WITH_XMIT_LOG 0 #define WITH_RCV_LOG 0 #endif #if WITH_LOG static FILE *log = NULL; static struct timeval now; static struct timeval before; #endif #if WITH_XMIT_LOG static FILE *xmitLog = NULL; static time_t lastXmit; /* time of last xmit */ static int nXmit; /* octets xmited in last second */ #endif #if WITH_RCV_LOG static FILE *rcvLog = NULL; static time_t lastRcv; /* time of last rcv */ static int nRcv; /* octets received in last second */ #endif #if WITH_LOG || WITH_RCV_LOG || WITH_XMIT_LOG static time_t t0; #endif
/*----- global variables ---------------------------------------------------*/
/*-------------------------------------------------------------------------*/ void HDLCInit (void (*_linkOutCb) ()) /* * Initializes the HDLC layer. */ { int i; #if WITH_LOG || WITH_XMIT_LOG || WITH_RCV_LOG char fn[100]; int now; now = time (NULL); t0 = now; #endif
/*** init the ACCM map ***/ for (i=0; i<32; i++) sndAccm[i] = rcvAccm[i] = 1; for (; i<256; i++) sndAccm[i] = rcvAccm[i] = 0; sndAccm[HDLC_FLAG] = 1; sndAccm[HDLC_ESC] = 1; /*** init various stuff ***/ frameLen = 0; esc = 0; addrCtrlCompr = 0; cb = NULL; linkOutCb = _linkOutCb; errFCS = 0; errTooShort = 0; errTooLong = 0; errFrame = 0; goodFrames = 0; #if WITH_LOG sprintf (fn, "log.%d.hdlc", now); log = fopen (fn, "wb"); #endif #if WITH_XMIT_LOG sprintf (fn, "log.%d.hdlc.xmit", now); xmitLog = fopen (fn, "wb"); #endif #if WITH_RCV_LOG sprintf (fn, "log.%d.hdlc.rcv", now); rcvLog = fopen (fn, "wb"); #endif } /* HDLCInit */ /*-------------------------------------------------------------------------*/ void HDLCFini () { printf ("HDLC Statistics:\r\n"); printf ("\tFCS errors: %d\r\n", errFCS); printf ("\ttoo short: %d\r\n", errTooShort); printf ("\ttoo long: %d\r\n", errTooLong); printf ("\tframing error: %d\r\n", errFrame); printf ("\tgood frames: %d\r\n", goodFrames); cb = NULL; linkOutCb = NULL; #if WITH_LOG if (log) fclose (log); log = NULL; #endif #if WITH_XMIT_LOG if (xmitLog) fclose (xmitLog); xmitLog = NULL; #endif #if WITH_RCV_LOG if (rcvLog) fclose (rcvLog); rcvLog = NULL; #endif } /* HDLCFini */ /*-------------------------------------------------------------------------*/ void HDLCSetRcvAccm (u32bit map) /* * Sets the internal receiving ACCM map according to the ACCM map given. */ { int i;
for (i=0; i<32; i++) if ((map >> i) & 0x01) rcvAccm[i] = 1; else rcvAccm[i] = 0; } /* HDLCSetRcvAccm */ /*-------------------------------------------------------------------------*/ void HDLCSetSndAccm (u32bit map) /* * Sets the internal sending ACCM map according to the ACCM map given. */ { int i;
for (i=0; i<32; i++) if ((map >> i) & 0x01) sndAccm[i] = 1; else sndAccm[i] = 0; } /* HDLCSetSndAccm */ /*-------------------------------------------------------------------------*/ void HDLCSetAddrCtrlCompr (int compr) { addrCtrlCompr = compr; } /*-------------------------------------------------------------------------*/ void HDLCSend (u8bit *buf, int len) /* * Generates an HDLC frame containing the data from 'in' of 'len' bytes. * It then calls the link output callback. * RC >0 length of frame in bytes * <=0 error */ { u8bit frame[FRAME_LEN]; int n = 0; u16bit fcs;
if (!linkOutCb) return; frame[n++] = HDLC_FLAG; fcs = PPPINITFCS16; fcs = FCS16 (fcs, HDLC_ADDR); fcs = FCS16 (fcs, HDLC_CTRL); if (!addrCtrlCompr) { HDLC_PUT_BYTE (frame, n, HDLC_ADDR); HDLC_PUT_BYTE (frame, n, HDLC_CTRL); } while (len-- > 0) if (n < FRAME_LEN -1 -2 -1) { fcs = FCS16 (fcs, *buf); HDLC_PUT_BYTE (frame, n, *buf++); } fcs ^= 0xFFFF; HDLC_PUT_BYTE (frame, n, (fcs >> 0) & 0xff); HDLC_PUT_BYTE (frame, n, (fcs >> 8) & 0xff); frame[n++] = HDLC_FLAG; #if WITH_XMIT_LOG { time_t t; time (&t); if (t != lastXmit) { if (lastXmit) for (; lastXmit<t; lastXmit++) { fprintf (xmitLog, "%d %9.6f\n", lastXmit-t0, 8.0*nXmit/1000.0); nXmit = 0; } lastXmit = t; nXmit = 0; } nXmit += n; } #endif linkOutCb (frame, n); } /* HDLCSend */ /*-------------------------------------------------------------------------*/ void HDLCReceive (u8bit *buf, int len) /* * Handles the received byte. */ { int n; u8bit byte; u16bit fcs; int i;
while (len-- > 0) { byte = *buf++; /*** check for start or end of frame ***/ if (byte == HDLC_FLAG) { /* end of frame? */ #if WITH_LOG if (frameLen >= 1+1+2) { int t;
gettimeofday (&now, NULL); t = (now.tv_sec -before.tv_sec)*1000*1000+(now.tv_usec -before.tv_usec); fprintf (log, "%2.6f\t# %4d in %3d.%03d ms\n", 8.0*frameLen/t*1000, frameLen, t /(1000), t%(1000)); fflush (log); } before = now; #endif #if WITH_RCV_LOG time_t t; time (&t); if (t != lastRcv) { if (lastRcv) for (; lastRcv<t; lastRcv++) { fprintf (rcvLog, "%d %9.6f\n", lastRcv-t0, 8.0*nRcv/1000.0); nRcv = 0; } lastRcv = t; nRcv = 0; } nRcv += frameLen +1; #endif if (frameLen == 0) { /* FLAG after FLAG? */ n = 0; } else if (frameLen <= 1+1+2) { /* too short? ADDR+CRTL+FCS16 */ n = 0; errTooShort++; } else if (frame[0] != HDLC_ADDR) { /* ADDR missing? */ n = 0; errFrame++; } else if (frame[1] != HDLC_CTRL) { /* CTRL missing? */ n = 0; errFrame++; } else if (frameLen >= FRAME_LEN) { /* too long? */ n = 0; errTooLong++; } else { /*** check the CFS ***/ fcs = PPPINITFCS16; for (i=0; i<frameLen; i++) fcs = FCS16 (fcs, frame[i]); if (fcs != PPPGOODFCS16) { DEBUG (fprintf (stderr, "FCS[%04X]\a\n", fcs);) n = 0; errFCS++; } else { goodFrames++; n = frameLen -1 -1 -2; /* len of payload */ if (cb) cb (frame+2, n); } } frameLen = 0; esc = 0; /*** check for flaged ctrl-seq ***/ } else if (rcvAccm[byte]) { ; /*** check for ESC ***/ } else if (byte == HDLC_ESC) { esc = 1; /*** check for pending escape ***/ } else if (esc) { byte ^= 0x20; if (frameLen == 0 && byte != HDLC_ADDR) { frame[frameLen++] = HDLC_ADDR; frame[frameLen++] = HDLC_CTRL; } if (frameLen < FRAME_LEN) frame[frameLen++] = byte; esc = 0; /*** store the byte for the frame ***/ } else { if (frameLen == 0 && byte != HDLC_ADDR) { frame[frameLen++] = HDLC_ADDR; frame[frameLen++] = HDLC_CTRL; } if (frameLen < FRAME_LEN) frame[frameLen++] = byte; } } /* while */ } /* HDLCReceive */ /*-------------------------------------------------------------------------*/ void HDLCRegister (void (*_cb) ()) /* * Registers the given callback _cb for incomming HDLC frames. */ { cb = _cb; } /* HDLCRegister */ /*-------------------------------------------------------------------------*/ void HDLCUnregister (void (*_cb) ()) /* * Removes the registered callback for HDLC frames. */ { cb = NULL; } /* HDLCUnregister */ /*-------------------------------------------------------------------------*/
/* * COPYRIGHT BY OERTEL & ZAHL SOFTWAREENTWICKLUNG GbR * file: ppp.h * written by: Christian Zahl * description: Defines various types for PPP * * Id * * Log */#ifndef INCL_PPP_H #define INCL_PPP_H
/*----- standard includefiles ------------------------------------------------*/
/*----- local includefiles ---------------------------------------------------*/
/*----- defines --------------------------------------------------------------*/ #define PPP_PROT_FULL_HEADERS 0x0073 #define PPP_PROT_COMPRESSED_UDP 0x0075 #define PPP_PROT_COMPRESSED_RTP 0x0077 #define PPP_PROT_CONTEXT_STATE 0x0079 #define PPP_PROT_START_TIMER 0x8073 #define PPP_PROT_CSAP 0x8075
/*----- type definitions -----------------------------------------------------*/
/*----- global functions -----------------------------------------------------*/
/*----- global variables -----------------------------------------------------*/
#endif /* INCL_PPP_H */
/* * COPYRIGHT BY OERTEL & ZAHL SOFTWAREENTWICKLUNG GbR * file: ppp.c * written by: Christian Zahl * description: Implements an part of the PPP (RFC-1661) * * Id * * Log */ static char rcsid[] = "Id\n";/*----- standard includefiles ----------------------------------------------*/ #include <stdio.h> #include <errno.h> #include <sys/time.h>
/*----- user includefiles --------------------------------------------------*/ #include "misc.h" #include "hdlc.h" #include "ppp.h"
/*----- defines ------------------------------------------------------------*/ #define CB_LIST 100 #define PPP_MTU 1490
/*----- type definitions ---------------------------------------------------*/ typedef struct { u16bit proto; void (*cb)(); void *data; } t_Cb;
/*----- local functions ----------------------------------------------------*/
/*----- global functions ---------------------------------------------------*/ void PPPReceive (u8bit *frame, int len);
/*----- local variables ----------------------------------------------------*/ static t_Cb cbList[CB_LIST]; static struct timeval bandwTimer; #ifdef _AIX #define WITH_LOG 0 #define WITH_BLOG 1 #endif #if WITH_LOG FILE *log; struct timeval now; struct timeval before; int octets; #endif #if WITH_BLOG static FILE *bLog; #endif
/*----- global variables ---------------------------------------------------*/
/*-------------------------------------------------------------------------*/ void PPPInit () { int i;
#if WITH_LOG int t; char fn[100]; time (&t); sprintf (fn, "log.%d.ppp", t); log = fopen (fn, "wb"); #endif #if WITH_BLOG { int t; char fn[100]; time (&t); sprintf (fn, "log.%d.ppp.bandw", t); bLog = fopen (fn, "wb"); } #endif for (i=0; i<CB_LIST; i++) { cbList[i].proto = 0; cbList[i].cb = NULL; cbList[i].data = NULL; } HDLCRegister (PPPReceive); } /* PPPInit */ /*-------------------------------------------------------------------------*/ void PPPFini () { #if WITH_LOG fclose (log); #endif #if WITH_BLOG fclose (bLog); #endif HDLCUnregister (PPPReceive); } /* PPPFini */ /*-------------------------------------------------------------------------*/ static void PPPBandwidthTimerStart () /* * Signals that we have to start the time for the bandwidth estimation. */ { gettimeofday (&bandwTimer, NULL); } /* PPPBandwidthTimerStart */ /*-------------------------------------------------------------------------*/ static void PPPBandwidthTimerStop (int len) /* * Signals that we have to stop the time for the bandwidth estimation. Len * specifies the number of bytes received in the meanwhile. */ { struct timeval now; int delta;
gettimeofday (&now, NULL); delta = (now.tv_sec -bandwTimer.tv_sec) *1000 *1000; delta += now.tv_usec -bandwTimer.tv_usec; #if WITH_BLOG fprintf (bLog, "%9.6f # %d bytes in %7.3f ms\n", 8.0 *len /delta *1000, len, 1.0*delta /1000); #endif } /* PPPBandwidthTimerStop ***/ /*-------------------------------------------------------------------------*/ void PPPRegister (u16bit proto, void (*cb)(), void *data) { int i; int j = -1;
for (i=0; i<CB_LIST; i++) if (cbList[i].proto == proto) { j = i; break; } else if (j == -1 && cbList[i].proto == 0) j = i; if (j < CB_LIST && j != -1) { cbList[j].proto = proto; cbList[j].cb = cb; cbList[j].data = data; } } /* PPPRegister */ /*-------------------------------------------------------------------------*/ void PPPUnregister (u16bit proto, void (*cb)()) { int i;
for (i=0; i<CB_LIST; i++) if (cbList[i].proto == proto) break; if (i < CB_LIST) { cbList[i].proto = 0; cbList[i].cb = NULL; cbList[i].data = NULL; } } /* PPPUnregister */ /*-------------------------------------------------------------------------*/ void PPPReceive (u8bit *frame, int len) /* * Handles the received PPP frame. Calls the approriate protocol callback, * if the protocol has been registered. Otherwise the packet will be * silently discarded. */ { u16bit proto; int i;
#if WITH_LOG int t; gettimeofday (&now, NULL); t = (now.tv_sec -before.tv_sec)*1000*1000+(now.tv_usec -before.tv_usec); fprintf (log, "%2.6f\t", 8.0*len/t*1000); fprintf (log, "# %4d in %3d.%03d ms", len, t /(1000), t%(1000)); fprintf (log, "\n"); fflush (log); before = now; #endif if (len < 2) return; /*** check for PPP protocol field compression ***/ if (frame[0] & 0x01) { proto = *frame++; len -= 1; } else { proto = *frame++ << 8; proto |= *frame++; len -= 2; } /*** check for the special START_TIMER ***/ if (proto == PPP_PROT_START_TIMER) { PPPBandwidthTimerStart (); return; } PPPBandwidthTimerStop (len); /*** search the cb for the protocol ***/ for (i=0; i<CB_LIST; i++) if (cbList[i].proto == proto) break; if (i >= CB_LIST) { #ifdef _AIX fprintf (stderr, "p[%04x,%d]", proto, len); fflush (stderr); #endif return; } (cbList[i].cb) (frame, len, cbList[i].data); } /* PPPReceive */ /*-------------------------------------------------------------------------*/ void PPPSend (u8bit *data, int len, u16bit proto) { u8bit frame[PPP_MTU]; int n = 0;
/*** send the START_TIMER frame first ***/ n = 0; frame[n++] = (PPP_PROT_START_TIMER >> 8) & 0xFF; frame[n++] = (PPP_PROT_START_TIMER >> 0) & 0xFF; HDLCSend (frame, n); n = 0; /*** build the real frame ***/ if (len > PPP_MTU -2) return; if (proto <= 0xff) { frame[n++] = proto; } else { frame[n++] = (proto >> 8) & 0xFF; frame[n++] = (proto >> 0) & 0xFF; } while (len-- > 0) frame[n++] = *data++; HDLCSend (frame, n); } /* PPPSend */ /*-------------------------------------------------------------------------*/
/* * COPYRIGHT BY OERTEL & ZAHL SOFTWAREENTWICKLUNG GbR * file: ipudprtpcomrpe.h * written by: Christian Zahl * description: ... * * Id * * Log */#ifndef INCL_IP_UDP_RTP_COMPRESS_H #define INCL_IP_UDP_RTP_COMPRESS_H
/*----- standard includefiles ------------------------------------------------*/
/*----- local includefiles ---------------------------------------------------*/
/*----- defines --------------------------------------------------------------*/ #define TYPE_FULL_HEADERS 1 #define TYPE_COMPRESSED_UDP 3 #define TYPE_COMPRESSED_RTP 4 #define TYPE_CONTEXT_STATE 5
/*----- type definitions -----------------------------------------------------*/
/*----- global functions -----------------------------------------------------*/
/*----- global variables -----------------------------------------------------*/
#endif /* INCL_IP_UDP_RTP_COMPRESS_H */
/* * file: ipUdpRtpCompr.c * written by: Christian Zahl * description: Compressing of IP/UDP/RTP packets * * Id * * Log */ static char rcsid[] = "Id\n";/*----- standard includefiles ----------------------------------------------*/ #include <stdio.h> #include <sys/types.h> #include <netinet/in_systm.h> #include <netinet/in.h> #include <netinet/ip.h> #include <netinet/udp.h>
/*----- user includefiles --------------------------------------------------*/ #include "misc.h" #include "rtp.h" #include "ipUdpRtpCompr.h"
/*----- defines ------------------------------------------------------------*/ #define MAX_CXT 256 #define TRACE printf ("##########%s:%d\n", __FILE__, __LINE__); #ifdef _AIX #define DEBUG(xxx) xxx #else #define DEBUG(xxx) #endif
/*----- type definitions ---------------------------------------------------*/ typedef struct { u32bit srcAddr; /* IP src */ u32bit dstAddr; /* IP dst */ u16bit srcPort; /* UDP src */ u16bit dstPort; /* UDP dst */ u32bit ssrc; /* RTP ssrc */ } t_Ident; typedef struct { int valid; t_Ident ident; int cxtId; u32bit timestamp; /* when this cxt was touched last */ struct ip *ip; u8bit ipHdr[60]; int ipHdrLen; struct udphdr *udp; u8bit udpHdr[8]; int udpHdrLen; struct rtp *rtp; u8bit rtpHdr[12+15*4+32]; int rtpHdrLen; int fullHeaderReq; /* pending req to send FULL_HEADER */ int seqNo; /* next sequence number */ int deltaI; int deltaT; int X; int XLen; } t_Cxt;
/*----- local functions ----------------------------------------------------*/
/*----- global functions ---------------------------------------------------*/
/*----- local variables ----------------------------------------------------*/ static u32bit timestamp = 0; static t_Cxt compressCxt[MAX_CXT]; static t_Cxt decompressCxt[MAX_CXT];
/*----- global variables ---------------------------------------------------*/
/*-------------------------------------------------------------------------*/ static void SaveHeaders (t_Cxt *cxt, const u8bit *p) /* * Saves the IP, UDP and RTP headers in the context. */ { /*** save IP header ***/ cxt->ipHdrLen = IP_HDR_BYTES ((struct ip*)p); memcpy (cxt->ipHdr, p, cxt->ipHdrLen); p += cxt->ipHdrLen; /*** save UDP header ***/ cxt->udpHdrLen = UDP_HDR_BYTES ((struct udphdr*)p); memcpy (cxt->udpHdr, p, cxt->udpHdrLen); p += cxt->udpHdrLen; /*** save RTP header ***/ cxt->rtpHdrLen = RTP_HDR_BYTES ((struct rtp*)p); memcpy (cxt->rtpHdr, p, cxt->rtpHdrLen); } /* SaveHeaders */ /*-------------------------------------------------------------------------*/ static void GetIdent (const u8bit *in, t_Ident *ident) /* * Generates an identifier for the connection out of the IP/UDP/RTP packet */ { struct ip *ip = (struct ip*)in; struct udphdr *udp = (struct udphdr*)IP_DATA (ip); struct rtp *rtp = (struct rtp*)UDP_DATA (udp);
ident->dstAddr = ip->ip_dst.s_addr; ident->srcAddr = ip->ip_src.s_addr; ident->dstPort = udp->uh_dport; ident->srcPort = udp->uh_sport; ident->ssrc = rtp->ssrc; } /* GetIdent */ /*-------------------------------------------------------------------------*/ static CompIdent (const t_Ident *ident1, const t_Ident *ident2) { return memcmp (ident1, ident2, sizeof (t_Ident)); } /* CompIdent */ /*-------------------------------------------------------------------------*/ static void InitCxt (t_Cxt *cxt) /* * Initializes the context. */ { memset (&cxt->ident, '\0', sizeof (cxt->ident)); cxt->fullHeaderReq = 1; cxt->seqNo = 0; cxt->deltaI = 1; cxt->deltaT = 0; cxt->X = 0; cxt->ip = (struct ip*)cxt->ipHdr; cxt->udp = (struct udphdr*)cxt->udpHdr; cxt->rtp = (struct rtp*)cxt->rtpHdr; cxt->valid = 0; } /* InitCxt */ /*-------------------------------------------------------------------------*/ static int NewSeqNo (t_Cxt *cxt) /* * Generates a new sequence no for the given context. */ { int seqNo;
seqNo = cxt->seqNo++; if (cxt->seqNo >= 0x0f) cxt->seqNo = 0; return seqNo; } /* NewSeqNo */ /*-------------------------------------------------------------------------*/ static t_Cxt *GetCompressCxt (const t_Ident *ident) /* * Gets the context for this connection identifier. If it is a new one, * get a new context for the array by removing the oldest one. * This is for the compression context only. */ { int oldest = 0; int i;
for (i=0; i<MAX_CXT; i++) if (CompIdent (&compressCxt[i].ident, ident) == 0) return &compressCxt[i]; else if (compressCxt[i].timestamp < compressCxt[oldest].timestamp) oldest = i; InitCxt (&compressCxt[oldest]); compressCxt[oldest].ident = *ident; compressCxt[oldest].cxtId = oldest; return &compressCxt[oldest]; } /* GetCompressCxt */ /*-------------------------------------------------------------------------*/ static int CompressValue (u8bit *buf, u32bit val) /* * Compresses the delta-values for the compressed IP/UDP/RTP header. * Returns the # of occupied bytes. */ { if (val <= 0x7f) { *buf = val; return 1; } else if (val <= 0x3fff) { *buf++ = ((val >> 8) & 0x3f) | 0x80; *buf = val & 0xff; return 2; } else if (val <= 0x3fffff) { *buf++ = ((val >> 16) & 0x3f) | 0xC0; *buf++ = ((val >> 8) & 0xff); *buf = val & 0xff; return 3; } else return -1; } /* CompressValue */ /*-------------------------------------------------------------------------*/ static int DecompressValue (u8bit *buf, u32bit *val) /* * Decompresses the value from an compressed IP/UDP/RTP header. * Returns the # of occupied bytes. */ { if ((buf[0] & 0x80) == 0x00) { /* 1 byte */ *val = buf[0] & 0x7f; return 1; } if ((buf[0] & 0xC0) == 0x80) { /* 2 bytes */ *val = ((buf[0] & 0x3f) <<8) | buf[1]; return 2; } if ((buf[0] & 0xC0) == 0xC0) { /* 3 bytes */ *val = ((buf[0] & 0x3f) <<16) | (buf[1]<<8) | buf[2]; return 3; } } /* CompressValue */ /*-------------------------------------------------------------------------*/ static int GenerateFullHeader (t_Cxt *cxt, const u8bit *in, int inLen, u8bit *out, int *type) /* * Generates a FULL_HEADER packet in out, sets the type and returns the # of * bytes of the new packet. */ { struct ip *ip = (struct ip*)out;
/*** set the type of this new package ***/ *type = TYPE_FULL_HEADERS; /*** place the input package in the new paket ***/ memcpy (out, in, inLen); /*** place the sequence-no ***/ IP_DATA (ip) [5] = NewSeqNo (cxt); /* low byte of UDP length */ /*** place the context-id ***/ ip->ip_len = (ip->ip_len & 0xff00) | cxt->cxtId; /* cxtId into low byte of IP-len */ /*** reset delta values to default ***/ cxt->deltaI = 1; cxt->deltaT = 0; cxt->valid = 1; /*** return the length of the new packet ***/ return inLen; } /* GenerateFullHeader */ /*-------------------------------------------------------------------------*/ static int GenerateCompressedUdp (t_Cxt *cxt, const u8bit *in, int inLen, u8bit *out, int *type) /* * Generates a COMPRESSED_UDP packet in out, sets the type, and returns the # * of bytes of the new packet. */ { struct ip *ip = (struct ip*)in; struct udphdr *udp = (struct udphdr*) IP_DATA (ip); struct rtp *rtp = (struct rtp*) UDP_DATA (udp); int deltaI; int n; int outLen = 0;
/*** set the type of this new package ***/ *type = TYPE_COMPRESSED_UDP; /*** place context-id and sequence-no ***/ out[outLen++] = cxt->cxtId; out[outLen++] = NewSeqNo (cxt); /*** place UDP checksum, if necessarry ***/ if (udp->uh_sum) { if (!(cxt->udp->uh_sum)) return GenerateFullHeader (cxt, in, inLen, out, type); out[outLen++] = (udp->uh_sum >> 8) & 0xff; out[outLen++] = (udp->uh_sum >> 0) & 0xff; } else if (cxt->udp->uh_sum) return GenerateFullHeader (cxt, in, inLen, out, type); /*** place IP identifier delta, if ncessarry ***/ if ((deltaI = ip->ip_id - cxt->ip->ip_id) != cxt->deltaI) { out[1] |= 0x10; outLen += CompressValue (out+outLen, deltaI); cxt->deltaI = deltaI; } /*** place RTP header and payload ***/ n = inLen -IP_HDR_BYTES (ip) -UDP_HDR_BYTES (udp); memcpy (out+outLen, (u8bit*)rtp, n); /*** reset the timestamp delta in the cxt ***/ cxt->deltaT = 0; /*** return size of generated package ***/ return outLen +n; } /* GenerateCompressedUdp */ /*-------------------------------------------------------------------------*/ static int GenerateCompressedRtp (t_Cxt *cxt, const u8bit *in, int inLen, u8bit *out, int *type) /* * Generates a COMPRESSED_RTP packet in out, sets the type and returns the * # of bytes of the new packet. */ { int outLen = 0; struct ip *ip = (struct ip*)in; struct udphdr *udp = (struct udphdr*)IP_DATA (ip); struct rtp *rtp = (struct rtp*)UDP_DATA (udp); int M = 0; int S = 0; int T = 0; int I = 0; int deltaS; int deltaT; int deltaI; int MSTI = 0; int MSTIOff; int i, j, n;
/*** set the type of this new package ***/ *type = TYPE_COMPRESSED_RTP; /*** place context-id and sequence-no ***/ out[outLen++] = cxt->cxtId; MSTIOff = outLen; out[outLen++] = NewSeqNo (cxt); /*** place UDP checksum ***/ if (udp->uh_sum) { if (!cxt->udp->uh_sum) return GenerateFullHeader (cxt, in, inLen, out, type); out[outLen++] = (udp->uh_sum >> 8) & 0xff; out[outLen++] = (udp->uh_sum >> 0) & 0xff; } else if (cxt->udp->uh_sum) return GenerateFullHeader (cxt, in, inLen, out, type); /*** get some indications and deltas ***/ M = rtp->m; if ((deltaS = rtp->seq -cxt->rtp->seq) < 0) deltaS += 0x10000; if (deltaS != 1) S = 1; if ((deltaT = rtp->timestamp -cxt->rtp->timestamp) != cxt->deltaT) T = 1; if ((deltaI = ip->ip_id - cxt->ip->ip_id) != cxt->deltaI) I = 1; /*** check for changes in CSRC ***/ n = 0; for (i=0; i<rtp->cc; i++) for (j=0; j<cxt->rtp->cc; j++) if (RTP_CSRC(rtp)[i].csrc == RTP_CSRC(cxt->rtp)[j].csrc) { n++; break; } /*** check for the need of special MSTI setting ***/ if ((rtp->cc != cxt->rtp->cc) || (rtp->cc != n) || (M & S & T & I)) { out[1] |= 0xf0; /* set MSTI */ MSTIOff = outLen; out[outLen++] = rtp->cc; /* CC */ MSTI = 1; } /*** place M bit ***/ if (M) out[MSTIOff] |= 0x80; /*** place I bit and IP identification delta ***/ if (I) { out[MSTIOff] |= 0x10; outLen += CompressValue (out+outLen, deltaI); cxt->deltaI = deltaI; } /*** place S bit and RTP sequence-no delta ***/ if (S) { out[MSTIOff] |= 0x40; outLen += CompressValue (out+outLen, deltaS); } /*** place T bit and RTP timestamp delta ***/ if (T) { out[MSTIOff] |= 0x20; outLen += CompressValue (out+outLen, deltaT); cxt->deltaT = deltaT; } /*** place RTP CC count and RTP CC list ***/ if (MSTI) { u32bit csrc;
for (i=0; i<rtp->cc; i++) { csrc = RTP_CSRC (rtp)[i].csrc; out[outLen++] = (csrc >> 24) & 0xff; out[outLen++] = (csrc >> 16) & 0xff; out[outLen++] = (csrc >> 8) & 0xff; out[outLen++] = (csrc >> 0) & 0xff; } } /*** place RTP header extension ***/ if (rtp->x) { u8bit *p;
p = RTP_EXT_DATA (rtp); for (i=0; i<RTP_EXT_BYTES (rtp); i++) out[outLen++] = *p++; } /*** place RTP payload ***/ n = inLen; n -= IP_HDR_BYTES (ip); n -= UDP_HDR_BYTES (udp); n -= RTP_HDR_BYTES (rtp); memcpy (out+outLen, RTP_DATA (rtp), n); /*** return size of generated package ***/ return outLen +n; } /* GenerateCompressedRtp */ /*-------------------------------------------------------------------------*/ IpUdpRtpCompress (const u8bit *in, int inLen, u8bit *out, int *type) /* * Performs the IP/UDP/RTP compression * Returns the # of byte of the resulting package to be send and the type */ { t_Ident ident; struct ip *ip = (struct ip*)in; struct udphdr *udp = (struct udphdr*)IP_DATA (ip); struct rtp *rtp = (struct rtp*)UDP_DATA (udp); int outLen; t_Cxt *cxt;
GetIdent ((u8bit*)ip, &ident); cxt = GetCompressCxt (&ident); cxt->timestamp = timestamp++; /*** FULL_HEADER if reqested or uncompressable IP hdr field changed ***/ if ((cxt->fullHeaderReq) || (ip->ip_hl != cxt->ip->ip_hl) || (ip->ip_tos != cxt->ip->ip_tos) || (ip->ip_off != cxt->ip->ip_off) || (ip->ip_ttl != cxt->ip->ip_ttl) || (ip->ip_p != cxt->ip->ip_p)) outLen = GenerateFullHeader (cxt, in, inLen, out, type); /*** COMPRESSED_UDP if uncompressable RTP field changes ***/ else if ((rtp->x != cxt->rtp->x) || (rtp->pt != cxt->rtp->pt) || (rtp->seq - cxt->rtp->seq > 0x3fffff) || (rtp->timestamp - cxt->rtp->timestamp > 0x3fffff)) outLen = GenerateCompressedUdp (cxt, in, inLen, out, type); /*** COMPRESSED_RTP ***/ else outLen = GenerateCompressedRtp (cxt, in, inLen, out, type); /*** save the current headers in the context ***/ SaveHeaders (cxt, in); cxt->fullHeaderReq = 0; return outLen; } /* IpUdpRtpCompress */ /*-------------------------------------------------------------------------*/ static int GenerateContextState (t_Cxt *cxt, u8bit *out) /* * Generates a CONTEXT_STATE packet for the gicen context. Return the * length of the new packet in bytes. */ { int n = 0;
out[n++] = 0x01; out[n++] = 0x01; /* only one context state */ out[n++] = cxt->cxtId; out[n++] = 0x80 | cxt->seqNo; out[n++] = 0x00; /* currently no support for gen-id */ return n; } /* GenerateContextState */ /*-------------------------------------------------------------------------*/ static int DecompressFullHeaders (u8bit *_in, int inLen, u8bit *out) /* * Decompresses a FULL_HEADER compressed frame and updates the context for * this session. * RC > 0 len of uncompressed frame */ { u8bit tmp[1500]; u8bit *in = tmp; int cxtId; t_Cxt *cxt; int outLen = inLen; struct ip *ip = (struct ip*)in; struct udphdr *udp; struct rtp *rtp;
/*** copy to make sure that the IP header is word alligned (needed for SPARC) ***/ memcpy (tmp, _in, inLen); /*** it's IP, so handle and save the IP header ***/ cxtId = ip->ip_len & 0xff; /* get the encoded context id */ cxt = &decompressCxt[cxtId]; InitCxt (cxt); cxt->cxtId = cxtId; cxt->ipHdrLen = IP_HDR_BYTES (ip); memcpy (cxt->ipHdr, in, cxt->ipHdrLen); cxt->ip->ip_len = inLen; /* set the real IP len */ memcpy (out, cxt->ipHdr, cxt->ipHdrLen); out += cxt->ipHdrLen; in += cxt->ipHdrLen; inLen -= cxt->ipHdrLen; /*** if it's UDP, handle UDP header ***/ if (ip->ip_p == IPPROTO_UDP) { udp = (struct udphdr*)in; cxt->udpHdrLen = UDP_HDR_BYTES (udp); memcpy (cxt->udpHdr, udp, cxt->udpHdrLen); cxt->seqNo = udp->uh_ulen & 0xff; /* encoded sequence no */ NewSeqNo (cxt); /* generate the next sequence no to expect */ cxt->udp->uh_ulen = inLen; /* set the original length */ memcpy (out, cxt->udpHdr, cxt->udpHdrLen); out += cxt->udpHdrLen; in += cxt->udpHdrLen; inLen -= cxt->udpHdrLen; /*** if it seems to be RTP version 2, handle it ***/ rtp = (struct rtp*)in; if (rtp->v == 2) { cxt->rtpHdrLen = RTP_HDR_BYTES (rtp); memcpy (cxt->rtpHdr, in, cxt->rtpHdrLen); memcpy (out, cxt->rtpHdr, cxt->rtpHdrLen); out += cxt->rtpHdrLen; in += cxt->rtpHdrLen; inLen -= cxt->rtpHdrLen; } else { cxt->rtpHdrLen = 0; memset (cxt->rtpHdr, '\0', sizeof (cxt->rtpHdr)); } } else { cxt->udpHdrLen = 0; memset (cxt->udpHdr, '\0', sizeof (cxt->udpHdr)); } /*** update some context fields ***/ cxt->fullHeaderReq = 0; /* no pending FULL_HEADER */ cxt->deltaT = 0; cxt->deltaI = 1; cxt->X = 0; cxt->valid = 1; /*** place the remaining data ***/ memcpy (out, in, inLen); return outLen; } /* DecompressFullHeaders */ /*-------------------------------------------------------------------------*/ static short IpChksum (u16bit *buf, int words) /* * Generates the IP header checksum, according to Comer. */ { u32bit sum;
for (sum=0; words>0; words--) sum += *buf++; sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); return ~sum; } /* IpChnksum */ /*-------------------------------------------------------------------------*/ static int DecompressCompressedUdp (u8bit *in, int inLen, u8bit *out) { int outLen = 0; int n = 0; int s; int cxtId; t_Cxt *cxt; u16bit chks; struct rtp *rtp;
cxtId = in[n++]; cxt = &decompressCxt[cxtId]; if (!cxt->valid) return -2; s = NewSeqNo (cxt) - in[n++] & 0x0F; /*** check for pending FULL_HEADER request (i.e. context invalid) ***/ if (cxt->fullHeaderReq) { DEBUG (fprintf (stderr, "s");) return -GenerateContextState (cxt, out); return 0; } /*** check the sequence no ***/ if (s) { cxt->fullHeaderReq = 1; DEBUG (fprintf (stderr, "S");) return -GenerateContextState (cxt, out); return -1; } /*** get the UDP checksum, if present ***/ if (cxt->udp->uh_sum) { chks = (in[n++] << 8); chks |= in[n++]; cxt->udp->uh_sum = chks; } /*** check if I bit is set ***/ if (in[1] & 0x10) n += DecompressValue (in+n, &cxt->deltaI); /*** update the saved headers ***/ cxt->ip->ip_id += cxt->deltaI; cxt->ip->ip_len = inLen -n +cxt->ipHdrLen +cxt->udpHdrLen +cxt->rtpHdrLen; cxt->udp->uh_ulen = cxt->ip->ip_len -cxt->ipHdrLen; /*** place the original IP header ***/ memcpy (out +outLen, cxt->ipHdr, cxt->ipHdrLen); outLen += cxt->ipHdrLen; /*** place the original UDP header ***/ memcpy (out +outLen, cxt->udpHdr, cxt->udpHdrLen); outLen += cxt->udpHdrLen; /*** save the RTP header ***/ in += n; inLen -= n; rtp = (struct rtp*) in; if (rtp->v == 2 && RTP_HDR_BYTES (rtp) <= sizeof (cxt->rtpHdr)) { cxt->rtpHdrLen = RTP_HDR_BYTES (rtp); memcpy (cxt->rtpHdr, in, cxt->rtpHdrLen); } else ; /*** place the RTP header and data ***/ memcpy (out +outLen, in, inLen); outLen += inLen; return outLen; } /* DecompressCompressedUdp */ /*-------------------------------------------------------------------------*/ static int DecompressCompressedRtp (u8bit *in, int inLen, u8bit *out) { int n = 0; int outLen = 0; int cxtId; t_Cxt *cxt; int CC; u8bit MSTI; int i; u32bit deltaS; u32bit s; u32bit chks; u32bit csrc;
cxtId = in[n++]; cxt = &decompressCxt[cxtId]; if (!cxt->valid) return -2; MSTI = in[n] & 0xf0; s = NewSeqNo (cxt) - (in[n++] & 0x0F); /* delta expected and received sequence-no */ /*** check for pending FULL_HEADER request (i.e. context invalid) ***/ if (cxt->fullHeaderReq) { DEBUG (fprintf (stderr, "s");) return -GenerateContextState (cxt, out); return 0; } /*** check the sequence no ***/ if (s) { cxt->fullHeaderReq = 1; DEBUG (fprintf (stderr, "S");) return -GenerateContextState (cxt, out); return -1; } /*** get the UDP checksum, if present ***/ if (cxt->udp->uh_sum) { chks = (in[n++] << 8); chks |= in[n++]; cxt->udp->uh_sum = chks; } /*** ***/ if (MSTI == 0xf0) { /* MSTI = 1111 */ MSTI = in[n]; CC = in[n++] & 0x0f; /* CC */ } else CC = 0; /*** delta IPv4 identifier ***/ if (MSTI & 0x10) /* I */ n += DecompressValue (in+n, &cxt->deltaI); /*** delta RTP sequence ***/ if (MSTI & 0x40) /* S */ n += DecompressValue (in+n, &deltaS); else deltaS = 1; /*** delta RTP timestamp ***/ if (MSTI & 0x20) /* T */ n += DecompressValue (in+n, &cxt->deltaT); /*** get the RTP CSRC list ***/ for (i=0; i<CC; i++) { csrc = (in[n+0]<<24) | (in[n+1]<<16) | (in[n+2]<<8) | (in[n+3]); RTP_CSRC(cxt->rtp)[i].csrc = csrc; n += 4; } /*** get the RTP header extension ***/ if (cxt->X) { /* currently not supported */ n += cxt->XLen; } /*** update the header fields ***/ cxt->ip->ip_id += cxt->deltaI; cxt->ip->ip_len = inLen -n +IP_HDR_BYTES (cxt->ip) +UDP_HDR_BYTES (cxt->udp) +RTP_HDR_BYTES (cxt->rtp); cxt->udp->uh_ulen = cxt->ip->ip_len -IP_HDR_BYTES (cxt->ip); cxt->rtp->seq += deltaS; cxt->rtp->timestamp += +cxt->deltaT; cxt->rtp->m = (MSTI & 0x80) >>7; if (CC) cxt->rtp->cc = CC; cxt->rtpHdrLen = RTP_HDR_BYTES (cxt->rtp); cxt->ip->ip_sum = 0; cxt->ip->ip_sum = IpChksum ((u16bit*)cxt->ip, cxt->ipHdrLen /2); /*** place the original IP header ***/ memcpy (out +outLen, cxt->ipHdr, cxt->ipHdrLen); outLen += cxt->ipHdrLen; /*** place the original UDP header ***/ memcpy (out +outLen, cxt->udpHdr, cxt->udpHdrLen); outLen += cxt->udpHdrLen; /*** place the original RTP header ***/ memcpy (out +outLen, cxt->rtpHdr, cxt->rtpHdrLen); outLen += cxt->rtpHdrLen; /*** place the recevied RTP data ***/ memcpy (out +outLen, in+n, inLen -n); outLen += inLen -n; return outLen; } /* DecompressCompressedRtp */ /*-------------------------------------------------------------------------*/ static int DecompressContextState (u8bit *in, int inLen, u8bit *out) /* * Handles the received CONTEXT_STATE packet */ { int n = 0; int cxtId; t_Cxt *cxt;
if (in[n++] != 0x01) return 0; if (in[n++] != 0x01) /* we can handle only one context */ return 0; cxtId = in[n++]; cxt = &compressCxt[cxtId]; if (!cxt->valid) { DEBUG (fprintf (stderr, "(CS%d not valid)", cxtId);) return 0; } if (in[n++] & 0x80) { /* FULL_HEADER request ? */ cxt->fullHeaderReq = 1; } return 0; } /* DecompressContextState */ /*-------------------------------------------------------------------------*/ IpUdpRtpDecompress (u8bit *in, int inLen, int packetType, u8bit *out) /* * Uncompresses the packet in with inLen bytes into out. The packetType * defines, which kind of packet we have. * RC > 0 # byte of out * 0 # error */ { int n;
if (packetType == TYPE_FULL_HEADERS) { DEBUG (fprintf (stderr, "F");) n = DecompressFullHeaders (in, inLen, out); } else if (packetType == TYPE_COMPRESSED_UDP) { DEBUG (fprintf (stderr, "U");) n = DecompressCompressedUdp (in, inLen, out); } else if (packetType == TYPE_COMPRESSED_RTP) { /* DEBUG (fprintf (stderr, "R");) */ n = DecompressCompressedRtp (in, inLen, out); } else if (packetType == TYPE_CONTEXT_STATE) { DEBUG (fprintf (stderr, "C");) n = DecompressContextState (in, inLen, out); } return n; } /* IpUdpRtpUncompress */ /*-------------------------------------------------------------------------*/
#include "dump.c"
/* * file: rtpTranslator.c * written by: Christian Zahl * description: Implements an RTP translator with payload compression * * Id * * Log */ static char rcsid[] = "Id\n";/*----- standard includefiles ----------------------------------------------*/ #include <stdio.h> #include <sys/time.h>
/*----- user includefiles --------------------------------------------------*/ #include "misc.h" #include "gsm.h" #include "rtp.h" #include "tabxlaw.h" #include "lpc.h"
/*----- defines ------------------------------------------------------------*/ #define CXT_LIST 10 /* # of contexts available */
/*----- type definitions ---------------------------------------------------*/ typedef struct { gsm gsmHandle; int lpcInit; int dstPt; /* dest. payload type */ u32bit ssrc; u32bit csrc[15]; u16bit seq; u32bit timestamp; u8bit data[8000]; int dataLen; /* current len in buf */ int pt; /* current pt in buf */ int m; /* marker bit */ int cc; /* # CSRC */ } t_Cxt;
/*----- local functions ----------------------------------------------------*/
/*----- global functions ---------------------------------------------------*/
/*----- local variables ----------------------------------------------------*/ static t_Cxt cxtList[CXT_LIST];
/*----- global variables ---------------------------------------------------*/
/*-------------------------------------------------------------------------*/ void RtpTranslatorInit () /* * Initializes the RTP translator. */ { int i;
for (i=0; i<CXT_LIST; i++) { cxtList[i].gsmHandle = NULL; cxtList[i].dstPt = RTP_PT_LPC; cxtList[i].dstPt = RTP_PT_GSM; } } /* RtpTranslatorInit */ /*-------------------------------------------------------------------------*/ void RtpTranslatorFini () { } /* RtpTranslatorFini */ /*-------------------------------------------------------------------------*/ static int ConvertPcmuGsm (t_Cxt *cxt, u8bit *in, int inLen, u8bit *out) /* * Converts len bytes in buf from PCMU to GSM. * Return # of bytes */ { short frame[160]; int n = 0; int i;
/*** create the GSM handle, if not done so ***/ if (!cxt->gsmHandle) cxt->gsmHandle = gsm_create (); /*** convert each frame of 160 bytes (20ms) to GSM ***/ while (inLen >= 160) { for (i=0; i<160; i++) frame[i] = ULAW_TO_LIN (*in++); gsm_encode (cxt->gsmHandle, frame, out+n); n += 33; inLen -= 160; } return n; } /* ConvertPcmuGsm */ /*-------------------------------------------------------------------------*/ static int ConvertPcmaGsm (t_Cxt *cxt, u8bit *in, int inLen, u8bit *out) /* * Converts len bytes in buf from PCMU to GSM. * Return # of bytes */ { short frame[160]; int n = 0; int i;
if (!cxt->gsmHandle) cxt->gsmHandle = gsm_create (); while (inLen >= 160) { for (i=0; i<160; i++) frame[i] = ALAW_TO_LIN (*in++); gsm_encode (cxt->gsmHandle, frame, out+n); n += 33; inLen -= 160; } return n; } /* ConvertPcmaGsm */ /*-------------------------------------------------------------------------*/ static int ConvertPcmuLpc (t_Cxt *cxt, u8bit *in, int inLen, u8bit *out) /* * Converts len bytes in buf from PCMU to LPC. * Return # of bytes */ { int n = 0;
/*** init LPC context if necessarry ***/ if (!cxt->lpcInit) { lpc_init (160); cxt->lpcInit = 1; } /*** convert each frame of 160 bytes (20ms) to LPC ***/ while (inLen >= 160) { lpc_analyze (in, out+n); n += 14; inLen -= 160; in += 160; } return n; } /* ConvertPcmuLpc */ /*-------------------------------------------------------------------------*/ static int RtpCompressPt (t_Cxt *cxt, u8bit *out) /* * Compresses the payload of the RTP data for the given cxt. */ { /*** convert to GSM ***/ if (cxt->dstPt == RTP_PT_GSM) { switch (cxt->pt) { case RTP_PT_PCMU: cxt->pt = RTP_PT_GSM; return ConvertPcmuGsm (cxt, cxt->data, cxt->dataLen, out); case RTP_PT_PCMA: cxt->pt = RTP_PT_GSM; return ConvertPcmaGsm (cxt, cxt->data, cxt->dataLen, out); case RTP_PT_GSM: cxt->pt = RTP_PT_GSM; memcpy (out, cxt->data, cxt->dataLen); return cxt->dataLen; case RTP_PT_LPC: cxt->pt = RTP_PT_LPC; memcpy (out, cxt->data, cxt->dataLen); return cxt->dataLen; default: return 0; } } else if (cxt->dstPt == RTP_PT_LPC) { switch (cxt->pt) { case RTP_PT_PCMU: cxt->pt = RTP_PT_LPC; return ConvertPcmuLpc (cxt, cxt->data, cxt->dataLen, out); case RTP_PT_LPC: cxt->pt = RTP_PT_LPC; memcpy (out, cxt->data, cxt->dataLen); return cxt->dataLen; default: return 0; } /*** unsoported conversion... ***/ } else { return 0; } } /* RtpCompressPt */ /*-------------------------------------------------------------------------*/ int RtpTranslator (struct sockaddr_in *dst, struct rtp *in, int inLen, struct rtp *out) /* * Generiert ein eigenes neues RTP paket, aufsetzend auf den empfangenen * und cxt. Komprimiert die Payload des RPT Paketes. * IN * cxt Context der session * rtp dst buffer fr rtp paket * * RC = -1 skip * >= 0 len */ { t_Cxt *cxt; u8bit *buf; int len;
/*** search the context of the session ***/ cxt = &cxtList[0]; /* simulated for now... */ /*** translate the packet ***/ cxt->pt = in->pt; cxt->m = in->m; cxt->timestamp = in->timestamp; cxt->seq = in->seq; cxt->dataLen = inLen -RTP_HDR_BYTES (in); memcpy (cxt->data, RTP_DATA (in), cxt->dataLen); /*** generate a new output packet, if data available ***/ out->v = 2; out->p = 0; out->x = 0; out->cc = 0; out->m = cxt->m; out->pt = cxt->dstPt; out->seq = cxt->seq; out->timestamp = cxt->timestamp; out->ssrc = cxt->ssrc; /*** RTP data ***/ buf = RTP_DATA (out); len = RtpCompressPt (cxt, buf); out->pt = cxt->pt; return len +RTP_HDR_BYTES (out); } /* RtpTranslator */ /*-------------------------------------------------------------------------*/
/* * file: csap.c * written by: Christian Zahl * description: Implements the cSAP (compressed session announcement * protocol) to be used over PPP * * Id * * Log */ static char rcsid[] = "Id\n";/*----- standard includefiles ----------------------------------------------*/ #include <stdio.h>
/*----- user includefiles --------------------------------------------------*/ #include "misc.h"
/*----- defines ------------------------------------------------------------*/ #define OP_ASSIGN 0x00 #define OP_RETRANSMIT 0x01 #define OP_DELETED 0x02 #define OP_RESET 0x03 #define GLOBAL_CONTEXT_ID 0xffffffff #define STATE_FREE 0 #define STATE_INUSE 1 #define DEF_TIMEOUT 3600 #define CONTEXTS 256 #define SAP_TRANSPARENT 0 #define SDP_TRANSPARENT 0
/*----- type definitions ---------------------------------------------------*/ typedef struct { u32bit srcAddr; u32bit dstAddr; u16bit srcPort; u16bit dstPort; u8bit sapSdp; } t_Assign;
typedef struct _t_Cxt { int state; int genId; u32bit srcAddr; u32bit dstAddr; u16bit srcPort; u16bit dstPort; int sap; int sdp; int timeout; int announcementLen; u8bit *announcement; } t_Cxt;
/*----- local functions ----------------------------------------------------*/
/*----- global functions ---------------------------------------------------*/
/*----- local variables ----------------------------------------------------*/ static t_Cxt serverCache[CONTEXTS]; static t_Cxt clientCache[CONTEXTS];
/*----- global variables ---------------------------------------------------*/
/*-------------------------------------------------------------------------*/ static void FlushCxt (t_Cxt *cxt) { if (cxt->state == STATE_INUSE) free (cxt->announcement); cxt->announcement = NULL; cxt->state = STATE_FREE; } /* FlushCxt */ /*-------------------------------------------------------------------------*/ static void FlushClientCache () { int i;
for (i=0; i<CONTEXTS; i++) FlushCxt (&clientCache[i]); } /* FlushClientCache */ /*-------------------------------------------------------------------------*/ static void FlushServerCache () { int i;
for (i=0; i<CONTEXTS; i++) FlushCxt (&serverCache[i]); } /* FluchServerCache */ /*-------------------------------------------------------------------------*/ static void SendAnnouncement (t_Cxt *cxt) /* * Sends the announcement in the given context, if we are able to handle * it. */ { if (cxt->sap == SAP_TRANSPARENT && cxt->sdp == SDP_TRANSPARENT) { ; /* ... send out the announcement */ } else { ; } } /* SendAnnouncement */ /*-------------------------------------------------------------------------*/ static void SendAssignMsg (t_Cxt *cxt, u32bit cxtLen) { } /* SendAssignMsg */ /*-------------------------------------------------------------------------*/ static void SendRetransmitMsg (t_Cxt *cxt, u32bit cxtLen) { } /* SendRetransmitMsg */ /*-------------------------------------------------------------------------*/ static void SendDeleteMsg (t_Cxt *cxt, u32bit cxtLen) { int i; u8bit msg[2048]; int n = 0;
msg[n] = cxt->genId << 5; ....... } /* SendDeleteMsg */ /*-------------------------------------------------------------------------*/ static void HandleAssignMsg (u8bit *msg, int msgLen, int genId, u32bit cxtId) /* * Assigns the announcement and all the other related data in the clients * given context. Also transmit the announcement, if we are able to handle * it. */ { u8bit buf[2048]; t_Assign *assign = (t_Assign*) buf; t_Cxt *cxt; int i; int now;
/*** check the context-id ***/ if (cxtId == GLOBAL_CONTEXT_ID) return; /*** save the announcement data in the cache ***/ time (&now); memcpy (buf, msg, msgLen); /* don't get a problem on a SUN */ cxt = &clientCache[cxtId]; FlushCxt (cxt); cxt->state = STATE_INUSE; cxt->genId = genId; cxt->srcAddr = assign->srcAddr; cxt->dstAddr = assign->dstAddr; cxt->srcPort = assign->srcPort; cxt->dstPort = assign->dstPort; cxt->sap = (assign->sapSdp >> 4) &0x0f; cxt->sdp = (assign->sapSdp >> 0) &0x0f; cxt->timeout = now + DEF_TIMEOUT; msgLen -= sizeof (t_Assign); msg += sizeof (t_Assign); cxt->announcementLen = msgLen; cxt->announcement = malloc (msgLen); memcpy (cxt->announcement, msg, msgLen); /*** transmit the announcement, if possible ***/ SendAnnouncement (cxt); /*** check the cache for any timouts ***/ for (i=0; i<CONTEXTS; i++) if (clientCache[i].timeout < now); FlushCxt (&clientCache[i]); } /* HandleAssignMsg */ /*-------------------------------------------------------------------------*/ static void HandleRetransmitMsg (u8bit *msg, int msgLen, int genId, u32bit cxtId) { t_Cxt *cxt;
/*** check the context-id ***/ if (cxtId == GLOBAL_CONTEXT_ID) return; /*** search the context ***/ cxt = &clientCache[cxtId]; /*** send DELETE if context unknown or genId out of band ***/ if (!cxt || genId != cxt->genId) { if (cxt) FlushCxt (cxt); SendDeleteMsg (cxt, cxtId); return; } /*** transmit the announcement, if possible ***/ SendAnnouncement (cxt); } /* HandleRetransmitMsg */ /*-------------------------------------------------------------------------*/ static void HandleDeletedMsg (u8bit *msg, int msgLen, int genId, u32bit cxtId) /* * Deletes the context of cxtId from the server cache. When the cxtId is the * global context-ID, we delete the whole server cache. */ { int i; t_Cxt *cxt;
/*** check the context-id ***/ if (cxtId == GLOBAL_CONTEXT_ID) { FlushServerCache (); return; } /*** search the context ***/ cxt = &serverCache[cxtId]; if (cxt->state == STATE_FREE) return; /*** reassign the announcement on the client side ***/ SendAssignMsg (cxt, cxtId); } /* HandleDeletedMsg */ /*-------------------------------------------------------------------------*/ void CSAPIRecv (u8bit *msg, int msgLen) { int op; int genId; u32bit cxtId;
op = *msg & 0x0F; genId = (*msg >> 5) & 0x07; /*** get the context-ID ***/ if (*msg++ & 0x10) { if (msgLen < 3) return; cxtId = *msg++ << 8; cxtId |= *msg++; if (cxtId == 0xffff) cxtId = GLOBAL_CONTEXT_ID; msgLen -= 3; } else { cxtId = *msg++; if (cxtId == 0xff) cxtId = GLOBAL_CONTEXT_ID; msgLen -= 2; } /*** ignore context-ID values too high ***/ if (cxtId != GLOBAL_CONTEXT_ID && cxtId >= CONTEXTS) return; /*** handle the packet */ switch (op) { case OP_ASSIGN: HandleAssignMsg (msg, msgLen, genId, cxtId); break; case OP_RETRANSMIT: HandleRetransmitMsg (msg, msgLen, genId, cxtId); break; case OP_DELETED: HandleDeletedMsg (msg, msgLen, genId, cxtId); break; default: break; } } /* CSAPIRecv */ /*-------------------------------------------------------------------------*/ void CSAPInit () { FlushServerCache (); FlushClientCache (); } /* CSAPInit */ /*-------------------------------------------------------------------------*/ void CSAPIFini () { } /* CSAPIFini */ /*-------------------------------------------------------------------------*/
/* * file: csap.c * written by: Christian Zahl * description: Implements the cSAP (compressed session announcement * protocol) to be used over PPP * * Id * * Log */ static char rcsid[] = "Id\n";/*----- standard includefiles ----------------------------------------------*/ #include <stdio.h>
/*----- user includefiles --------------------------------------------------*/ #include "misc.h"
/*----- defines ------------------------------------------------------------*/ #define OP_ASSIGN 0x00 #define OP_RETRANSMIT 0x01 #define OP_DELETED 0x02 #define OP_RESET 0x03 #define GLOBAL_CONTEXT_ID 0xffffffff #define STATE_FREE 0 #define STATE_INUSE 1 #define DEF_TIMEOUT 3600 #define CONTEXTS 256 #define SAP_TRANSPARENT 0 #define SDP_TRANSPARENT 0
/*----- type definitions ---------------------------------------------------*/ typedef struct { u32bit srcAddr; u32bit dstAddr; u16bit srcPort; u16bit dstPort; u8bit sapSdp; } t_Assign;
typedef struct _t_Cxt { int state; int genId; u32bit srcAddr; u32bit dstAddr; u16bit srcPort; u16bit dstPort; int sap; int sdp; int timeout; int announcementLen; u8bit *announcement; } t_Cxt;
/*----- local functions ----------------------------------------------------*/
/*----- global functions ---------------------------------------------------*/
/*----- local variables ----------------------------------------------------*/ static t_Cxt serverCache[CONTEXTS]; static t_Cxt clientCache[CONTEXTS];
/*----- global variables ---------------------------------------------------*/
/*-------------------------------------------------------------------------*/ static void FlushCxt (t_Cxt *cxt) { if (cxt->state == STATE_INUSE) free (cxt->announcement); cxt->announcement = NULL; cxt->state = STATE_FREE; } /* FlushCxt */ /*-------------------------------------------------------------------------*/ static void FlushClientCache () { int i;
for (i=0; i<CONTEXTS; i++) FlushCxt (&clientCache[i]); } /* FlushClientCache */ /*-------------------------------------------------------------------------*/ static void FlushServerCache () { int i;
for (i=0; i<CONTEXTS; i++) FlushCxt (&serverCache[i]); } /* FluchServerCache */ /*-------------------------------------------------------------------------*/ static void SendAnnouncement (t_Cxt *cxt) /* * Sends the announcement in the given context, if we are able to handle * it. */ { if (cxt->sap == SAP_TRANSPARENT && cxt->sdp == SDP_TRANSPARENT) { ; /* ... send out the announcement */ } else { ; } } /* SendAnnouncement */ /*-------------------------------------------------------------------------*/ static void SendAssignMsg (t_Cxt *cxt, u32bit cxtLen) { } /* SendAssignMsg */ /*-------------------------------------------------------------------------*/ static void SendRetransmitMsg (t_Cxt *cxt, u32bit cxtLen) { } /* SendRetransmitMsg */ /*-------------------------------------------------------------------------*/ static void SendDeleteMsg (t_Cxt *cxt, u32bit cxtLen) { int i; u8bit msg[2048]; int n = 0;
msg[n] = cxt->genId << 5; ....... } /* SendDeleteMsg */ /*-------------------------------------------------------------------------*/ static void HandleAssignMsg (u8bit *msg, int msgLen, int genId, u32bit cxtId) /* * Assigns the announcement and all the other related data in the clients * given context. Also transmit the announcement, if we are able to handle * it. */ { u8bit buf[2048]; t_Assign *assign = (t_Assign*) buf; t_Cxt *cxt; int i; int now;
/*** check the context-id ***/ if (cxtId == GLOBAL_CONTEXT_ID) return; /*** save the announcement data in the cache ***/ time (&now); memcpy (buf, msg, msgLen); /* don't get a problem on a SUN */ cxt = &clientCache[cxtId]; FlushCxt (cxt); cxt->state = STATE_INUSE; cxt->genId = genId; cxt->srcAddr = assign->srcAddr; cxt->dstAddr = assign->dstAddr; cxt->srcPort = assign->srcPort; cxt->dstPort = assign->dstPort; cxt->sap = (assign->sapSdp >> 4) &0x0f; cxt->sdp = (assign->sapSdp >> 0) &0x0f; cxt->timeout = now + DEF_TIMEOUT; msgLen -= sizeof (t_Assign); msg += sizeof (t_Assign); cxt->announcementLen = msgLen; cxt->announcement = malloc (msgLen); memcpy (cxt->announcement, msg, msgLen); /*** transmit the announcement, if possible ***/ SendAnnouncement (cxt); /*** check the cache for any timouts ***/ for (i=0; i<CONTEXTS; i++) if (clientCache[i].timeout < now); FlushCxt (&clientCache[i]); } /* HandleAssignMsg */ /*-------------------------------------------------------------------------*/ static void HandleRetransmitMsg (u8bit *msg, int msgLen, int genId, u32bit cxtId) { t_Cxt *cxt;
/*** check the context-id ***/ if (cxtId == GLOBAL_CONTEXT_ID) return; /*** search the context ***/ cxt = &clientCache[cxtId]; /*** send DELETE if context unknown or genId out of band ***/ if (!cxt || genId != cxt->genId) { if (cxt) FlushCxt (cxt); SendDeleteMsg (cxt, cxtId); return; } /*** transmit the announcement, if possible ***/ SendAnnouncement (cxt); } /* HandleRetransmitMsg */ /*-------------------------------------------------------------------------*/ static void HandleDeletedMsg (u8bit *msg, int msgLen, int genId, u32bit cxtId) /* * Deletes the context of cxtId from the server cache. When the cxtId is the * global context-ID, we delete the whole server cache. */ { int i; t_Cxt *cxt;
/*** check the context-id ***/ if (cxtId == GLOBAL_CONTEXT_ID) { FlushServerCache (); return; } /*** search the context ***/ cxt = &serverCache[cxtId]; if (cxt->state == STATE_FREE) return; /*** reassign the announcement on the client side ***/ SendAssignMsg (cxt, cxtId); } /* HandleDeletedMsg */ /*-------------------------------------------------------------------------*/ void CSAPIRecv (u8bit *msg, int msgLen) { int op; int genId; u32bit cxtId;
op = *msg & 0x0F; genId = (*msg >> 5) & 0x07; /*** get the context-ID ***/ if (*msg++ & 0x10) { if (msgLen < 3) return; cxtId = *msg++ << 8; cxtId |= *msg++; if (cxtId == 0xffff) cxtId = GLOBAL_CONTEXT_ID; msgLen -= 3; } else { cxtId = *msg++; if (cxtId == 0xff) cxtId = GLOBAL_CONTEXT_ID; msgLen -= 2; } /*** ignore context-ID values too high ***/ if (cxtId != GLOBAL_CONTEXT_ID && cxtId >= CONTEXTS) return; /*** handle the packet */ switch (op) { case OP_ASSIGN: HandleAssignMsg (msg, msgLen, genId, cxtId); break; case OP_RETRANSMIT: HandleRetransmitMsg (msg, msgLen, genId, cxtId); break; case OP_DELETED: HandleDeletedMsg (msg, msgLen, genId, cxtId); break; default: break; } } /* CSAPIRecv */ /*-------------------------------------------------------------------------*/ void CSAPInit () { FlushServerCache (); FlushClientCache (); } /* CSAPInit */ /*-------------------------------------------------------------------------*/ void CSAPIFini () { } /* CSAPIFini */ /*-------------------------------------------------------------------------*/
/* * file: filehandler.h * written by: Christian Zahl * description: ... * * Id * * Log */#ifndef INCL_FILEHANDLER_H #define INCL_FILEHANDLER_H
/*----- standard includefiles ------------------------------------------------*/
/*----- local includefiles ---------------------------------------------------*/
/*----- defines --------------------------------------------------------------*/ #define FILEHANDLER_READ 1 #define FILEHANDLER_WRITE 2 #define FILEHANDLER_EXCEPTION 4
/*----- type definitions -----------------------------------------------------*/
/*----- global functions -----------------------------------------------------*/
/*----- global variables -----------------------------------------------------*/
#endif /* INCL_FILEHANDLER */
/* * file: filehandler.c * written by: Christian Zahl * description: Impelements a filehander concept * * Id * * Log */ static char rcsid[] = "Id\n";/*----- standard includefiles ----------------------------------------------*/ #include <stdio.h> #include <errno.h> #include <sys/select.h>
/*----- user includefiles --------------------------------------------------*/ #include "filehandler.h"
/*----- defines ------------------------------------------------------------*/ #define CB_LIST 32
/*----- type definitions ---------------------------------------------------*/ typedef struct { void (*cb)(); void *data; int mode; } t_Cb;
/*----- local functions ----------------------------------------------------*/
/*----- global functions ---------------------------------------------------*/
/*----- local variables ----------------------------------------------------*/ static int stop = 0; static t_Cb cbList[CB_LIST]; static fd_set readSet;
/*----- global variables ---------------------------------------------------*/
/*-------------------------------------------------------------------------*/ void FileHandlerFdSet () { int i;
FD_ZERO (&readSet); for (i=0; i<CB_LIST; i++) if (cbList[i].cb) if (cbList[i].mode & FILEHANDLER_READ) FD_SET (i, &readSet); } /* FileHandlerFdSet */ /*-------------------------------------------------------------------------*/ void FileHandlerInit () { int i;
for (i=0; i<CB_LIST; i++) { cbList[i].cb = NULL; cbList[i].data = NULL; cbList[i].mode = 0; } FileHandlerFdSet (); stop = 0; } /* FileHandlerInit */ /*-------------------------------------------------------------------------*/ void FileHandlerStop () { stop = 1; } /* FileHandlerStop */ /*-------------------------------------------------------------------------*/ void FileHandlerFini () { FileHandlerStop (); } /* FileHandlerFini */ /*-------------------------------------------------------------------------*/ FileHandlerCreate (int fd, int mode, void (*cb)(), void *data) { if (fd < 0) return; if (fd >= CB_LIST) return; if (mode == FILEHANDLER_READ) { cbList[fd].cb = cb; cbList[fd].data = data; cbList[fd].mode = mode; FileHandlerFdSet (); } } /* FileHandlerCreate */ /*-------------------------------------------------------------------------*/ FileHandlerDelete (int fd) { if (fd < 0) return; if (fd >= CB_LIST) return; cbList[fd].cb = NULL; FileHandlerFdSet (); } /* FileHandlerDelete */ /*-------------------------------------------------------------------------*/ void FileHandler () { fd_set tmpReadSet; int i;
stop = 0; while (!stop) { memcpy (&tmpReadSet, &readSet, sizeof (tmpReadSet)); i = select (CB_LIST, &tmpReadSet, NULL, NULL, NULL); if (i == -1 && errno == EINTR) continue; for (i=0; i<CB_LIST; i++) if (FD_ISSET (i, &tmpReadSet)) (cbList[i].cb) (i, 0, cbList[i].data); } /* while */ } /* FileHandler */ /*-------------------------------------------------------------------------*/
/* * file: misc.h * written by: Christian Zahl * description: Defines for accessing IP, UDP and RTP headers * * Id * * Log */#ifndef INCL_MISC #define INCL_MISC
/*----- standard includefiles ------------------------------------------------*/
/*----- local includefiles ---------------------------------------------------*/
/*----- defines --------------------------------------------------------------*/ #define IP_HDR_BYTES(xxx) ((xxx)->ip_hl*4) #define IP_DATA(xxx) (((unsigned char*)(xxx))+(xxx)->ip_hl*4)
#define UDP_HDR_BYTES(xxx) (8) #define UDP_DATA(xxx) (((unsigned char*)xxx)+UDP_HDR_BYTES(xxx)) /*** handling of RTP header fields ***/ #define RTP_CSRC_BYTES(xxx) ((xxx)->cc*4) #define RTP_CSRC(xxx) ((struct rtpCsrc*)(((unsigned char*)xxx)+12)) #define RTP_EXT(xxx) ((struct rtpExt*)(((unsigned char*)xxx)+12+RTP_CSRC_BYTES(xxx))) #define RTP_EXT_DATA(xxx) ((((unsigned char*)xxx)+12+RTP_CSRC_BYTES(xxx))) #define RTP_EXT_BYTES(xxx) ((xxx)->x?RTP_EXT(xxx)->xlen:0) #define RTP_HDR_BYTES(xxx) (12+(xxx)->cc*4+RTP_EXT_BYTES(xxx)) #define RTP_DATA(xxx) (((unsigned char*)xxx)+RTP_HDR_BYTES(xxx))
#define RTP_CSRC_SET(rtp,csrc,ii) \ {rtp[12+ii*4]=(csrc)>>24;rtp[13+ii*4]=(csrc)>>16;\ rtp[14+ii*4]=(csrc)>>8;rtp[15+ii*4]=(csrc)>>0;}
/*----- type definitions -----------------------------------------------------*/ typedef unsigned char u8bit; typedef unsigned short u16bit; typedef unsigned int u32bit;
/*----- global functions -----------------------------------------------------*/
/*----- global variables -----------------------------------------------------*/
#endif /* INCL_MISC */
/* * COPYRIGHT BY OERTEL & ZAHL SOFTWAREENTWICKLUNG GbR * file: rtp.h * written by: Christian Zahl * description: Definition of RTP header * * Id * * Log */#ifndef INCL_RTP_H #define INCL_RTP_H
/*----- standard includefiles ------------------------------------------------*/
/*----- local includefiles ---------------------------------------------------*/
/*----- defines --------------------------------------------------------------*/ #define RTP_PT_PCMU 0 #define RTP_PT_GSM 3 #define RTP_PT_LPC 7 #define RTP_PT_PCMA 8
/*----- type definitions -----------------------------------------------------*/ struct rtp { unsigned int v:2; unsigned int p:1; unsigned int x:1; unsigned int cc:4; unsigned int m:1; unsigned int pt:7; unsigned int seq:16; unsigned int timestamp; unsigned int ssrc; }; struct rtpCsrc { unsigned int csrc; };
struct rtpExt { unsigned short type; unsigned short xlen; };
/*----- global functions -----------------------------------------------------*/
/*----- global variables -----------------------------------------------------*/
#endif /* INCL_RTP_H */
/* * COPYRIGHT BY OERTEL & ZAHL SOFTWAREENTWICKLUNG GbR * file: tabxlaw.h * written by: Christian Zahl * description: Defines four tables and some macros for converting * alaw and ulaw to linear and vice versa. * * Id * * Log */#ifndef INCL_TABXLAW #define INCL_TABXLAW
/*----- standard includefiles ------------------------------------------------*/
/*----- local includefiles ---------------------------------------------------*/
/*----- defines --------------------------------------------------------------*/ #define ULAW_TO_LIN(x) (tabulaw2lin[(x)]) #define LIN_TO_ULAW(x) (tablin2ulaw[(int)(x)+32767]) #define ALAW_TO_LIN(x) (tabalaw2lin[(x)]) #define LIN_TO_ALAW(x) (tablin2alaw[(int)(x)+32767])
/*----- type definitions -----------------------------------------------------*/
/*----- global functions -----------------------------------------------------*/
/*----- global variables -----------------------------------------------------*/ extern const short tabulaw2lin[256]; extern const unsigned char tablin2ulaw[65536]; extern const short tabalaw2lin[256]; extern const unsigned char tablin2alaw[65536];
#endif /* INCL_TABXLAW */
CFLAGS=-O2 -g -I/usr/local/include.SUFFIXES: .DEFAULT:
OBJ_DIR=(ARCH)
OBJ= (OBJ_DIR)/server.o \ (OBJ DIR)/hdlc.o \ (OBJ_DIR)/ppp.o \ (OBJ DIR)/filehandler.o \ (OBJ_DIR)/ipUdpRtpCompr.o \ (OBJÿDIR)/rtpTranslator.o \ (OBJ_DIR)/tabxlaw.o \ (OBJÿDIR)/lpc.o \ (NULL)
server: (OBJÿDIR)/server
sun5/server: (OBJ) (CC) -g (OBJ) -o(OBJÿDIR)/server -L. -L/usr/local/lib -lgsm -lnsl -lsocket -lm
aix4/server: (OBJ) (OBJÿDIR)/modem.o (CC) -g (OBJ) (OBJ_DIR)/modem.o -o(OBJÿDIR)/server -L/usr/local/lib -lgsm -lm
test: (OBJ_DIR)/test
aix4/test: (OBJÿDIR)/test.o (OBJ_DIR)/ipUdpRtpCompr.o (CC) -g (OBJ_DIR)/test.o (OBJÿDIR)/ipUdpRtpCompr.o -o (OBJ_DIR)/test
sun5/test: (OBJÿDIR)/test.o (OBJ_DIR)/ipUdpRtpCompr.o (CC) -g (OBJ_DIR)/test.o (OBJÿDIR)/ipUdpRtpCompr.o -o (OBJ_DIR)/test
############################################################################ (OBJÿDIR)/server.o: server.c (CC) -c (CFLAGS) ? -o @
(OBJ_DIR)/hdlc.o: hdlc.c (CC) -c (CFLAGS) ? -o @
(OBJÿDIR)/ppp.o: ppp.c (CC) -c (CFLAGS) ? -o @
(OBJ_DIR)/filehandler.o: filehandler.c (CC) -c (CFLAGS) ? -o @
(OBJÿDIR)/ipUdpRtpCompr.o: ipUdpRtpCompr.c (CC) -c (CFLAGS) ? -o @
(OBJ_DIR)/rtpMixer.o: rtpMixer.c (CC) -c (CFLAGS) ? -o @
(OBJÿDIR)/rtpTranslator.o: rtpTranslator.c (CC) -c (CFLAGS) ? -o @
(OBJ_DIR)/tabxlaw.o: tabxlaw.c (CC) -c (CFLAGS) ? -o @
(OBJÿDIR)/modem.o: modem.c (CC) -c (CFLAGS) ? -o @
(OBJ_DIR)/test.o: test.c (CC) -c (CFLAGS) ? -o @
(OBJÿDIR)/lpc.o: lpc.c (CC) -c (CFLAGS) ? -o @