home *** CD-ROM | disk | FTP | other *** search
- /* RTP_SUBR . C
- #
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- This software is copyright (C) by the Lawrence Berkeley Laboratory.
- Permission is granted to reproduce this software for non-commercial
- purposes provided that this notice is left intact.
-
- It is acknowledged that the U.S. Government has rights to this software
- under Contract DE-AC03-765F00098 between the U.S. Department of Energy
- and the University of California.
-
- This software is provided as a professional and academic contribution
- for joint exchange. Thus, it is experimental, and is provided ``as is'',
- with no warranties of any kind whatsoever, no support, no promise of
- updates, or printed documentation. By using this software, you
- acknowledge that the Lawrence Berkeley Laboratory and Regents of the
- University of California shall have no liability with respect to the
- infringement of other copyrights by any part of this software.
-
- For further information about this notice, contact William Johnston,
- Bld. 50B, Rm. 2239, Lawrence Berkeley Laboratory, Berkeley, CA, 94720.
- (wejohnston@lbl.gov)
-
- For further information about this software, contact:
- Jin Guojun
- Bld. 50B, Rm. 2275, Lawrence Berkeley Laboratory, Berkeley, CA, 94720.
- g_jin@lbl.gov
-
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %
- % Author: Jin Guojun - LBL 3/1/93
- */
-
- #define KERNEL
- #include "net_need.h"
-
- #ifndef RTP_MARGIN
- #define RTP_MARGIN 16
- #endif
-
- #define RTP_OPT_LEN ((sizeof(rtcpsdeschdr_t) + sizeof(rtcp_movie_t)) >> 2)
- #define RTCP_MOVIEHDR_LEN (sizeof(rtphdr_t) >> 2)
- #define TOTAL_HEADER_BYTES TOTAL_RTP_MOVIE_HEADER_BYTES
-
- #ifndef Max_FRAGMENTS
- #define Max_FRAGMENTS 144
- #endif
-
- #ifndef MaxRTPchannel
- #define MaxRTPchannel 64
- #endif
-
- #ifdef RTP_READ_ACCURACY
- #define DEFAULT_TOLERANCE 85
- #else
- #define DEFAULT_TOLERANCE 106
- #endif
-
-
- static rtp_flow_ctrl *rtp_resource[MaxRTPchannel][2];
- static int mislist[256]; /* shared resource, so get it right way */
- extern struct sockaddr_in *get_soaddr();
-
-
- /* called at open RTP channel */
- rtp_request_port(int flow_id, int port, int mode, int flags)
- {
- register int i=flow_id;
- if (i < 0 || i >= MaxRTPchannel) return -1;
- {
- register rtp_flow_ctrl **rrp = rtp_resource[i];
- int use_ip = flags & RTP_OVERIP ? IP_HDR_MINLEN : 0;
- int n=sizeof(n), packet_size;
- rtphdr_t *rtphdrp;
- rtcp_movie_t *rtcp_mhp;
- rtcpsdeschdr_t *rtcp_sdp;
- if (mode < 0 || mode) { /* transmittor */
- rrp[1] = (rtp_flow_ctrl*) ZALLOC(sizeof(rtp_flow_ctrl), 1, "flow_ctrl");
- rrp[1]->flag = flags;
- rrp[1]->len = 0;
- /* rrp[1]->port = port; */
-
- if ((i=getsockopt(i, SOL_SOCKET, SO_SNDBUF, &packet_size, &n)) < 0)
- return i;
- if (!(rrp[1]->buf=NZALLOC(packet_size, 1, "rtp"))) return -1;
-
- rrp[1]->aux = packet_size - use_ip - TOTAL_HEADER_BYTES - RTP_MARGIN;
- get_soaddr(1, &rrp[1]->soaddr);
- if (use_ip) init_ip_header(rrp[1]->buf, flow_id, 5);
- rtphdrp = rrp[1]->rtphdrp= (rtphdr_t *) (rrp[1]->buf + use_ip);
- rtcp_sdp = (rtcpsdeschdr_t*)(rtphdrp + 1);
- rtcp_mhp = (rtcp_movie_t *)(rtcp_sdp + 1);
-
- rtphdrp->rh_vers = RTP_VERSION;
- rtphdrp->rh_flow = flow_id;
- rtphdrp->rh_opts = True;
- rtphdrp->rh_content = RTPCONT_MOVIE;
- rtcp_sdp->rtsh_fin = 1;
- rtcp_sdp->rtsh_type = RTPOPT_SDES;
- rtcp_sdp->rtsh_optlen = RTP_OPT_LEN;
- rtcp_sdp->rtsh_class = 0;
- rtcp_sdp->rtsh_msglen = RTCP_MOVIEHDR_LEN;
- rtcp_mhp->group_id = kludgeGID;
- rtcp_mhp->ttl = 33; /* 33 ms */
- rtcp_mhp->linewidth = 0;
- rtcp_mhp->size = packet_size;
- }
- if (mode <= 0) { /* reciever */
- rrp[0] = (rtp_flow_ctrl*) ZALLOC(1, sizeof(rtp_flow_ctrl), "flow_ctrl");
- rrp[0]->flag = flags;
- rrp[0]->len = 0;
- rrp[0]->list = mislist;
- rrp[0]->port = port;
- rrp[0]->group_id = kludgeGID;
-
- if ((i=getsockopt(i, SOL_SOCKET, SO_RCVBUF, &packet_size, &n)) < 0)
- return i;
- if (!(rrp[0]->buf=NZALLOC(packet_size,
- flags&RTP_LOCALBUF ? Max_FRAGMENTS : 1, "rtp")))
- return -1;
- get_soaddr(0, &rrp[0]->soaddr);
- rrp[0]->aux = packet_size;
- rrp[0]->rtphdrp = (rtphdr_t *) (rrp[0]->buf + use_ip);
- }
-
- i = flow_id;
- #ifdef AUTO_CONNECT
- if (flags & RTP_OVERTCP) {
- #ifdef LWP
- lwpcreate
- #else
- switch (fork()) {
- case -1:
- case 0: /* parent */
- default: /* child */
- exit (0);
- }
- #endif
- }
- #endif
- return i; /* should be port # ? */
- }
- }
-
- void /* used for close RTP descriptot */
- rtp_release_port(register int fd)
- {
- register rtp_flow_ctrl **rrp = rtp_resource[fd];
- if (fd < 0 || fd >= MaxRTPchannel)
- prgmerr(0, "RTP port %d is out of range", fd);
- else {
- if (rrp[0])
- free(rrp[0]->buf), free(rrp[0]);
- if (rrp[1])
- free(rrp[1]->buf), free(rrp[1]);
- }
- }
-
-
- rtp_write(int s, VType* data, int datalen)
- {
- if (s < 0 || s >= MaxRTPchannel) return -1;
- {
- rtp_flow_ctrl* rrp = rtp_resource[s][1];
- char *vp=rrp->buf;
- rtphdr_t *rtphdrp=rrp->rtphdrp;
- rtcpsdeschdr_t *rtcp_sdp=(rtcpsdeschdr_t *)(rtphdrp+1);
- rtcp_movie_t *rtcp_mhp=(rtcp_movie_t *)(rtcp_sdp+1);
- int hdrlen = (char*)(rtcp_mhp + 1) - vp,
- i=sizeof(i), n, linewidth=rtcp_mhp->linewidth, packet_size=rrp->aux;
- bool use_ip = rrp->flag & RTP_OVERIP;
-
- rtcp_mhp->total_len = datalen;
- rtcp_mhp->fragment = datalen / packet_size;
- #ifndef OLD_RTP
- rrp->rtpmsg.msg_name = (caddr_t)&rrp->soaddr;
- rrp->rtpmsg.msg_namelen = sizeof(rrp->soaddr);
- rrp->rtpmsg.msg_iov = rrp->rtpiov;
- rrp->rtpmsg.msg_iovlen = 2; /* rtphdr & data */
- rrp->rtpiov[0].iov_base = (caddr_t)vp;
- rrp->rtpiov[0].iov_len = hdrlen;
- #endif
- time((time_t*)&rtphdrp->rh_ts);
-
- if (rrp->flag & RTP_OVERTCP) {
- if (write(s, vp, hdrlen) != hdrlen) return -1;
- return write(s, data, datalen);
- }
- if (use_ip) set_ip_dsize(vp, hdrlen + packet_size, 0);
-
- for (rtcp_mhp->fin_p=i=0; datalen > 0; i++) {
- rtcp_mhp->pkt_id = i;
- n = packet_size * i;
- if (linewidth) {
- register int y = n / linewidth;
- rtcp_mhp->offset.cord.y = y;
- rtcp_mhp->offset.cord.x = n - y * linewidth;
- } else rtcp_mhp->offset.pos = n;
- #ifdef _DEBUG_
- message("GID %d : offset.pos = %d\n",
- rtcp_mhp->group_id, rtcp_mhp->offset.pos);
- #endif
- if (datalen < packet_size) {
- packet_size = datalen;
- rtphdrp->rh_sync = rtcp_mhp->fin_p = 1;
- if (use_ip)
- set_ip_dsize(vp, hdrlen + packet_size, 0);
- }
- datalen -= packet_size;
- #ifdef OLD_RTP
- memcpy(vp + hdrlen, (byte*)data + n, packet_size);
- /*
- if (write(s, vp, packet_size) < 0)
- */
- rtp_retry: if (sendto(s, vp, packet_size, 0, &rrp->soaddr, sizeof(rrp->soaddr)) < 0)
- #else
- rrp->rtpiov[1].iov_base = (caddr_t)data + n;
- rrp->rtpiov[1].iov_len = packet_size;
- rtp_retry: if (sendmsg(s, &rrp->rtpmsg, 0) < 0)
- #endif
- if (errno == ENOBUFS) {
- udelay(0, -1); goto rtp_retry;
- } else return prgmerr(0, "rtp gwrite");
- if (n=rrp->udelay) {
- n >>= 4; /* call cost factor */
- for (n += !n; n--;)
- time((time_t*)&rtphdrp->rh_ts);
- }
- }
- datalen = rtcp_mhp->total_len;
- rtcp_mhp->total_len = 0;
- if (use_ip) set_ip_dsize(vp, hdrlen, 0);
- for (n=hdrlen, i=2; i--;)
- sendto(s, vp, n, 0, &rrp->soaddr, sizeof(rrp->soaddr));
- rtcp_mhp->group_id++;
- return datalen;
- }
- }
-
- rtp_read(int s, char *data, int tolerance)
- {
- static char* lastbuf;
- rtp_flow_ctrl* rrp = rtp_resource[s][0];
- rtphdr_t *rtphdrp = rrp->rtphdrp;
- bool video = lastbuf==data && rrp->flag & RTP_SLOWVIDEO;
- int l, packet_size = rrp->aux, nrcv=rrp->miss=0, slen=sizeof(rrp->soaddr),
- gid, total_recv=0,
- use_ip=(char*)rtphdrp - rrp->buf, hdrlen=TOTAL_HEADER_BYTES + use_ip;
- register int n = rrp->flag & RTP_LOCALBUF;
- char *buf, /* working area and data pointer */
- *dp = buf = n | video ? rrp->buf + hdrlen : data,
- *localbuf = n ? dp : 0; /* data assembling area */
-
- #ifdef RTP_CAN_USETCP
- if (rrp->flag & RTP_OVERTCP) {
- if (read(s=rrp->tcp, rrp->buf, hdrlen) < hdrlen)
- return -1;
- rtcp_sdp = 0;
- rtcp_getoptions(rtphdrp, 1, RTPOPT_SDES, &rtcp_sdp);
- if (!rtcp_sdp) return -1;
- rmopt = (rtcp_movie_t *)(rtcp_sdp + 1);
- return read(s, data, rmopt->total_len);
- }
- #endif
- /* require at least one buffer */
- if (!((int)localbuf | (int)data)) {
- errno = ENOBUFS; return -1;
- }
-
- #ifndef OLD_RTP
- rrp->rtpmsg.msg_name = (caddr_t)&rrp->soaddr;
- rrp->rtpmsg.msg_namelen = sizeof(rrp->soaddr);
- rrp->rtpmsg.msg_iov = rrp->rtpiov;
- rrp->rtpmsg.msg_iovlen = 2; /* rtphdr & data */
- rrp->rtpiov[0].iov_base = (caddr_t)rtphdrp;
- rrp->rtpiov[0].iov_len = hdrlen;
- #endif
- if (tolerance < 25 || tolerance > 100) /* ? rrp->ignore_err */
- tolerance = DEFAULT_TOLERANCE;
- #ifndef RTP_READ_ACCURACY
- else tolerance += tolerance >> 2; /* 1.25 / 1.28 */
- #endif
- if (rrp->len) {
- if (!video && !localbuf) /* move out small saving area */
- /* message("move out %d from %x to %x\n",
- rrp->len, rrp->buf + hdrlen, dp), */
- memcpy(dp, rrp->buf + hdrlen, rrp->len);
- goto addata;
- }
-
- Loop {
- rtcpsdeschdr_t *rtcp_sdp;
- rtcp_movie_t *rmopt;
- #define dsp rrp->header_len
- /*
- l = read(s, rtphdrp, packet_size);
- */
- #if defined OLD_RTP | defined MAYBE_FAST
- l = recvfrom(s, rtphdrp, packet_size, 0, &rrp->soaddr, &slen);
- #else
- rrp->rtpiov[1].iov_base = (caddr_t)dp;
- rrp->rtpiov[1].iov_len = packet_size;
- l = recvmsg(s, &rrp->rtpmsg, 0);
- #endif
- if (l < 1) return l;
-
- addata: rtcp_sdp = 0;
- dsp = rtcp_getoptions(rtphdrp, 1, RTPOPT_SDES, &rtcp_sdp);
- if (!rtcp_sdp) {
- message("strange RTP movie packet");
- continue;
- }
- rmopt = (rtcp_movie_t *)(rtcp_sdp + 1);
- gid = n = rmopt->group_id;
- #ifdef _DEBUG_
- message("GID %d : rev = %d, dsp = %d\n", n, l, dsp);
- #endif
- if (n && n < rrp->group_id) /* n=0 is next gid loop */
- continue;
- if (!rmopt->total_len) goto rend;
-
- l -= dsp; /* data length */
- if (n > rrp->group_id) { /* new group coming in */
- rrp->group_id = n; /* == rmopt->group_id; */
- rrp->len = l;
- if (!video && localbuf && dp != buf) /* not buffered */
- /* save first packet in small buffer for next frame */
- /* message("save first packet %d from %x to %x\n",
- l, dp, rrp->buf + hdrlen), */
- memcpy(rrp->buf + hdrlen, dp, l);
- exam: n = total_recv -
- #ifdef RTP_READ_ACCURACY
- rmopt->total_len * tolerance / 100;
- #else
- (rmopt->total_len * tolerance >> 7);
- #endif
- if (n >= 0 || data == lastbuf) {
- lastbuf = data;
- if (localbuf && data) /* require extra copy */{
- /* message("extra copy "); */
- memcpy(data, localbuf, rmopt->total_len);
- }
- return total_recv;
- }
- #ifdef NO_ERROR_RERURN
- nrcv = 0; /* discard old group */
- #else
- return n;
- #endif
- }
- if (n=rmopt->linewidth)
- n = rmopt->offset.cord.y * n + rmopt->offset.cord.x;
- else n = rmopt->offset.pos;
- total_recv += l;
-
- if (!video) {
- if (n != dp - buf && tolerance < DEFAULT_TOLERANCE)
- /* message("move lost packet %d from %x to %x+%d\n",
- l, dp, buf, n), */
- memcpy(buf + n, dp, l); /* lossing packet, so */
- /* we are in the loosing area, and to be moved to the right place */
- /* else discard frame anyway */
-
- if (n+l > rmopt->total_len && !localbuf)
- dp = buf; /* let last packet go to small local area */
- else if (n >= dp - buf)
- dp = buf + n + l; /* point to next block */
- /* otherwise, don't move the data pointer */
- } else memcpy(data + n, dp, l);
-
- #ifdef _DEBUG_
- message("receive %d : total %d (%d) (pos %d)\n",
- l, total_recv, rmopt->fin_p, n);
- #endif
-
- { register int w = rmopt->pkt_id - nrcv;
- /* ignore case k < 0 which indicates retransmission */
- if (w > 0) { /* missing packet, and packet arrives in order */
- #ifdef RTP_INTERPOLATION
- if (rrp->flag & RTP_NOINPOLA)
- while (w--) mislist[rrp->miss++] = nrcv++;
- else if (localbuf) { /* not true anymore */
- while (w--) nrcv++,
- memcpy(data + n - w*l, localbuf + n - w*l, l);
- } else if (data != lastbuf) {
- while (w--) nrcv++,
- memcpy(data + n - w*l, lastbuf + n - w*l, l);
- }
- /* otherwise, treat it as video which uses same buf */
- #else
- while (w--) mislist[rrp->miss++] = nrcv++;
- #endif
- } else nrcv++;
- }
-
- if (n=rmopt->size > packet_size) { /* should be in connection */
- /* and should not happen at last packet !!! */
- packet_size = rrp->aux = n;
- if (!localbuf) {
- verify_buffer_size(&rrp->buf, n, 1, No);
- if (!rrp->buf)
- return -1;
- rtphdrp = (rtphdr_t*)(rrp->buf + use_ip);
- if (video) buf = rrp->buf + hdrlen;
- }
- if ((rrp=rtp_resource[s][1]) && n < rrp->aux)
- rrp->aux = n;
- rrp = rtp_resource[s][0];
- } /* end initializing buffer agreement */
-
- n = rmopt->total_len + hdrlen;
- if (localbuf && n > pointer_buffer_size(rrp->buf)) {
- if (!(rrp->buf = realloc(rrp->buf, n)))
- return -1;
- buf = localbuf = rrp->buf + hdrlen;
- } /* end resizing local buffer */
-
- rend: if (rmopt->fin_p) {
- rrp->group_id = ++gid;
- rrp->len = 0;
- goto exam;
- }
- }
- }
-
-
- #ifndef MIN_RCVBUF
- #define MIN_RCVBUF 1024
- #endif
-
- rtp_open(char *host, char *port, int carrier, int mode, int buf_size)
- {
- int s, rev = !(mode && ~mode), flag = RTP_LOCALBUF;
-
- if (!host && mode)
- return prgmerr(0, "no host name for transmission");
-
- if (carrier != SOCK_RAW && carrier != SOCK_STREAM)
- carrier = SOCK_DGRAM; /* deafult carrieer */
- if (!port) port = "1920";
-
- if (buf_size < MIN_RCVBUF && rev)
- buf_size = Max_WINDOW_SIZE, flag = No;
- else if (buf_size < 512 + TOTAL_HEADER_BYTES ||
- buf_size > UDP_BUF_LIMIT && carrier != SOCK_STREAM)
- buf_size = FRAGMENT_SIZE << rev;
-
- s = build_socket(host, port, carrier, mode, &buf_size, No, NULL);
-
- if (carrier == SOCK_STREAM) flag = RTP_OVERTCP;
- else if (carrier == SOCK_RAW) flag |= RTP_OVERIP;
- return rtp_request_port(s, get_soaddr(1, NULL)->sin_port, mode, flag);
- }
-
- void
- rtp_close(int fd)
- {
- rtp_release_port(fd);
- close(fd);
- }
-
- rtp_setoption(int s, int option, int op1, int op2)
- {
- if (s < 0 || s >= MaxRTPchannel) return -1;
- {
- rtp_flow_ctrl* rrp = rtp_resource[s][1]; /* transmittor */
-
- switch (option) {
- case RTP_OPT_UDELAY:
- rrp->udelay = op1; break;
- case RTP_OPT_HDRLEN: /* user data header need to be repeated in each packet */
- rrp->header_len = op1; break;
- case RTP_OPT_GROUPID:
- rrp->group_id = op1; break;
- case RTP_OPT_FLAGS:
- rrp->flag = op1; break;
- case RTP_OPT_ADDFLAG:
- rrp->flag |= op1; break;
- case RTP_OPT_QOS: {
- rtcp_movie_t* opthdt = (rtcp_movie_t*)(rrp->buf + sizeof(rtphdr_t) +
- sizeof(rtcpsdeschdr_t));
- opthdt->fin_p = False; break; /* not right now !!! */
- }
- }
-
- }
- return 0;
- }
-
- rtp_flow_ctrl *
- get_rtp_control(int fd, int rw /* 0=r */)
- {
- if (fd < 0 || fd >= MaxRTPchannel) return NULL;
- return rtp_resource[fd][rw];
- }
-
- rtp_receive_cmd(int s, rtcp_movie_t *rmp)
- {
- if (s < 0 || s >= MaxRTPchannel) return 0;
- {
- register rtcp_movie_t* romp = (rtcp_movie_t*)( (char*)
- (rtp_resource[s][0]->rtphdrp + 1) + sizeof(rtcpsdeschdr_t) );
- if (rmp) *rmp = *romp;
- else rmp = romp;
- return rmp->command;
- }
- }
-
-