#include #include #include #include #include /* struct sockaddr_in */ #include /* inet_ntoa() */ #include /* gettimeofday() */ #include #include #include #include #include /* select(), perror() */ #include "raw_rtp.h" #include "ansi.h" #include "sysdep.h" void member_sdes(source* s, rtcp_sdes_type_t t, char *b, int len); /* * This function builds one SDES chunk into buffer b composed of argc * items supplied in arrays type , value and length b * * * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |V=2|P| SC | PT=SDES=202 | length | header * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * | SSRC/CSRC_1 | chunk * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1 * | SDES items | * | ... | * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * | SSRC/CSRC_2 | chunk * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 2 * | SDES items | * | ... | * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ */ char *rtp_write_sdes(char *b, u_int32 src, int argc, rtcp_sdes_type_t type[], char *value[], int length[]) { /* source description (SDES) * struct rtcp_sdes { * u_int32 src; * rtcp_sdes_item_t item[1]; * } sdes; * * typedef struct rtcp_sdes rtcp_sdes_t; */ rtcp_sdes_t *s = (rtcp_sdes_t *)b; rtcp_sdes_item_t *rsp; int i; int len; int pad; /* SSRC header */ s->src = src; rsp = &s->item[0]; /* SDES items */ for (i = 0; i < argc; i++) { rsp->type = type[i]; len = length[i]; if (len > RTP_MAX_SDES) { /* invalid length, may want to take other action */ len = RTP_MAX_SDES; } rsp->length = len; memcpy(rsp->data, value[i], len); rsp = (rtcp_sdes_item_t *)&rsp->data[len]; } /* terminate with end marker and pad to next 4-octet boundary */ len = ((char *) rsp) - b; pad = 4 - (len & 0x3); b = (char *) rsp; while (pad--) *b++ = RTCP_SDES_END; return b; } /* Parsing RTCP SDES Packets * * This function parses an SDES packet, calling functions find_member() * to find a pointer to the information for a session member given the * SSRC identifier and member_sdes() to store the new SDES information * for that member. This function expects a pointer to the header of the * RTCP packet. */ /* void rtp_read_sdes(rtcp_t *r, source *s) *{ * int count = r->common.count; * rtcp_sdes_t *sd = &r->r.sdes; * rtcp_sdes_item_t *rsp, *rspn; * rtcp_sdes_item_t *end = (rtcp_sdes_item_t *) * * ((u_int32 *)r + r->common.length + 1); * * * while (--count >= 0) { * rsp = &sd->item[0]; * if (rsp >= end) break; * * * for (; rsp->type; rsp = rspn ) { * rspn = (rtcp_sdes_item_t *)((char*)rsp+rsp->length+2); * if (rspn >= end) { * rsp = rspn; * break; * } * member_sdes(s, rsp->type, rsp->data, rsp->length); * } * sd = (rtcp_sdes_t *) * ((u_int32 *)sd + (((char *)rsp - (char *)sd) >> 2)+1); *} * if (count >= 0) { * *} *} */ static char *rtp_read_sdes(char *b, int len) { rtcp_sdes_item_t *rsp; u_int32 src = *(u_int32 *)b; int total_len = 0; len -= 4; /* subtract SSRC from available bytes */ if (len <= 0) { return 0; } rsp = (rtcp_sdes_item_t *)(b + 4); for (; rsp->type; rsp = (rtcp_sdes_item_t *)((char *)rsp + rsp->length + 2)) { member_sdes(src, rsp->type, rsp->data, rsp->length); total_len += rsp->length + 2; } if (total_len >= len) { fprintf(stderr, "Remaining length of %d bytes for SSRC item too short (has %u bytes)\n", len, total_len); return 0; } b = (char *)rsp + 1; /* skip padding */ return b + ((4 - ((int)b & 0x3)) & 0x3); } /* rtp_read_sdes */ void member_sdes(source* s, rtcp_sdes_type_t t, char *b, int len) { static struct { rtcp_sdes_type_t t; char *name; } map[] = { {RTCP_SDES_END, "end"}, {RTCP_SDES_CNAME, "CNAME"}, {RTCP_SDES_NAME, "NAME"}, {RTCP_SDES_EMAIL, "EMAIL"}, {RTCP_SDES_PHONE, "PHONE"}, {RTCP_SDES_LOC, "LOC"}, {RTCP_SDES_TOOL, "TOOL"}, {RTCP_SDES_NOTE, "NOTE"}, {RTCP_SDES_PRIV, "PRIV"}, {11, "SOURCE"}, {0,0} }; int i; char num[10]; sprintf(num, "%d", t); for (i = 0; map[i].name; i++) { if (map[i].t == t) break; } printf("%s=\"%*.*s\" ", map[i].name ? map[i].name : num, len, len, b); } /* member_sdes */ /* * Return length parsed, -1 on error. */ static int parse_control(char *buf, int len) { rtcp_t *r; /* RTCP header */ int i; r = (rtcp_t *)buf; if (r->common.version == RTP_VERSION) { printf("\n"); while (len > 0) { len -= (ntohs(r->common.length) + 1) << 2; if (len < 0) { /* something wrong with packet format */ printf("Illegal RTCP packet length %d words.\n", ntohs(r->common.length)); return -1; } switch (r->common.pt) { case RTCP_SR: printf(" (SR ssrc=0x%lx p=%d count=%d len=%d\n", (unsigned long)ntohl(r->r.rr.ssrc), r->common.p, r->common.count, ntohs(r->common.length)); printf("ntp=%lu.%lu ts=%lu psent=%lu osent=%lu\n", (unsigned long)ntohl(r->r.sr.ntp_sec), (unsigned long)ntohl(r->r.sr.ntp_frac), (unsigned long)ntohl(r->r.sr.rtp_ts), (unsigned long)ntohl(r->r.sr.psent), (unsigned long)ntohl(r->r.sr.osent)); for (i = 0; i < r->common.count; i++) { printf(" (ssrc=%0lx fraction=%g lost=%lu last_seq=%lu jit=%lu lsr=%lu dlsr=%lu)\n", (unsigned long)ntohl(r->r.sr.rr[i].ssrc), r->r.sr.rr[i].fraction / 256., (unsigned long)ntohl(r->r.sr.rr[i].lost), /* XXX I'm pretty sure this is wrong */ (unsigned long)ntohl(r->r.sr.rr[i].last_seq), (unsigned long)ntohl(r->r.sr.rr[i].jitter), (unsigned long)ntohl(r->r.sr.rr[i].lsr), (unsigned long)ntohl(r->r.sr.rr[i].dlsr)); } printf(" )\n"); break; case RTCP_RR: printf(" (RR ssrc=0x%lx p=%d count=%d len=%d\n", (unsigned long)ntohl(r->r.rr.ssrc), r->common.p, r->common.count, ntohs(r->common.length)); for (i = 0; i < r->common.count; i++) { printf("(ssrc=%0lx fraction=%g lost=%lu last_seq=%lu jit=%lu lsr=%lu dlsr=%lu)\n", (unsigned long)ntohl(r->r.rr.rr[i].ssrc), r->r.rr.rr[i].fraction / 256., (unsigned long)ntohl(r->r.rr.rr[i].lost), (unsigned long)ntohl(r->r.rr.rr[i].last_seq), (unsigned long)ntohl(r->r.rr.rr[i].jitter), (unsigned long)ntohl(r->r.rr.rr[i].lsr), (unsigned long)ntohl(r->r.rr.rr[i].dlsr)); } printf(" )\n"); break; case RTCP_SDES: printf(" (SDES p=%d count=%d len=%d\n", r->common.p, r->common.count, ntohs(r->common.length)); buf = (char *)&r->r.sdes; for (i = 0; i < r->common.count; i++) { int remaining = (ntohs(r->common.length) << 2) - (buf - (char *)&r->r.sdes); printf(" (src=0x%lx ", (unsigned long)ntohl(((struct rtcp_sdes *)buf)->src)); if (remaining > 0) { buf = rtp_read_sdes(buf, (ntohs(r->common.length) << 2) - (buf - (char *)&r->r.sdes)); if (!buf) return -1; } else { fprintf(stderr, "Missing at least %d bytes.\n", -remaining); return -1; } printf(")\n"); } printf(" )\n"); break; case RTCP_BYE: printf(" (BYE p=%d count=%d len=%d\n", r->common.p, r->common.count, ntohs(r->common.length)); for (i = 0; i < r->common.count; i++) { printf("ssrc[%d]=%0lx ", i, (unsigned long)ntohl(r->r.bye.src[i])); } if (ntohs(r->common.length) > r->common.count) { buf = (char *)&r->r.bye.src[r->common.count]; printf("reason=\"%*.*s\"", *buf, *buf, buf+1); } printf(")\n"); break; /* invalid type */ default: printf("(? pt=%d src=0x%lx)\n", r->common.pt, (unsigned long)ntohl(r->r.sdes.src)); break; } r = (rtcp_t *)((u_int32 *)r + ntohs(r->common.length) + 1); } } else { printf("invalid version %d\n", r->common.version); } return len; } /* parse_control */