⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtpsend.c

📁 RTP 实现的工具
💻 C
字号:
/** Send RTP packet stream with configurable parameters.* Intended to test RTP features.* Reads RTP/RTCP headers from ASCII file, possibly generated by rtpdump.* Format (in any order, without white space around =, lines continued*    with initial white space, comment lines start with #, strings*    enclosed in quotation marks):* <time> RTP v=<version> m=<marker> pt=<payload type> ts=<time stamp>*    seq=<sequence number> cc=<CSRC count> data=<hex payload>* <time> RTCP (SDES v=<version> *               (src=<source> cname="..." name="...")*               (src=<source> ...)*             )*             (RR v=<version>*             )*** (c) 1995 Henning Schulzrinne, GMD Fokus*/#include <stdio.h>#include <ctype.h>#include <sys/types.h>#include <sys/time.h>    /* gettimeofday() */#include <sys/socket.h>  /* struct sockaddr */#include <netinet/in.h>#include <arpa/inet.h>   /* inet_ntoa() */#include <time.h>#include <stdio.h>       /* stderr, printf() */#include <string.h>#include <stdlib.h>      /* perror(), calloc() */#include <unistd.h>      /* write() */#include "notify.h"      /* notify_start(), ... */#include "rtp.h"         /* RTP headers */#include "multimer.h"    /* timer_set() */#include "ansi.h"static char rcsid[] = "$Id$";static int verbose = 0;static FILE *in = stdin;static int sock[2];  /* output sockets *//** Node either has a parameter or a non-zero pointer to list.*/typedef struct node {  struct node *next, *list;  /* parameter in list, level down */   char *type;    /* parameter type */  int num;       /* numeric value */  char *string;  /* string value */} node_t;static void usage(char *argv0){  fprintf(stderr, "Usage: %s [-l] [-f file] destination/port/ttl\n",    argv0);  exit(1);} /* usage *//** Convert hexadecimal numbers in 'text' to binary in 'buffer'.* Ignore embedded whitespace.* Return length in bytes.*/static int hex(char *text, char *buffer){  char *s;  char byte[3];  int nibble = 0;  int len = 0;  byte[2] = '\0';  for (s = text; *s; s++) {    if (isspace(*s)) continue;    else {      byte[nibble++] = *s;      if (nibble == 2) {        nibble = 0;        buffer[len++] = strtol(byte, (char **)NULL, 16);      }    }  }  return len;} /* hex *//** Convert textual description into parse tree.* (SDES (ssrc=<ssrc> cname=<cname> ...) (ssrc=<ssrc> ...))* Return pointer to first node.*/static node_t *parse(char *text){  int string = 0;  int level = 0;  char tmp[1024];  int c = 0;  node_t *n;  node_t *first = (node_t *)NULL, *last = (node_t *)NULL;  char *s;  /* convert to tree */  for (s = text; *s; s++) {    if (string) {      tmp[c++] = *s;      if (*s == '"') string = 0;    }    else if (*s == '(') {      if (level > 0) tmp[c++] = *s;      else c = 0;      level++;    }    else if (*s == ')') {      level--;      if (level == 0) {        n = calloc(1, sizeof(node_t));        /* append node to list */        if (!first) first = n;        if (last) last->next = n;        last = n;        tmp[c] = 0;        c = 0;        /* attach list */        n->list = parse(tmp);      }      else {        tmp[c++] = *s;      }    }    else if (*s == '"') {      tmp[c++] = *s;      string = 1;    }    else if (level >= 1) {      tmp[c++] = *s;    }    /* end of parameter/value pair */    else if (isspace(*s)) {      char *e;      tmp[c] = '\0';      if (c > 0) {        c = 0;        n = calloc(1, sizeof(node_t));        if (!first) first = n;        if (last) last->next = n;        last = n;        e = strchr(tmp, '=');        if (e) {          char *v = e+1;          *e = '\0';          if (isdigit(*v)) n->num = strtol(v, (char **)NULL, 0);          else {            n->string = malloc(strlen(v+1) + 1);            /* strip quotation marks */            v[strlen(v)-1] = '\0';            strcpy(n->string, v+1);          }        }        n->type = malloc(strlen(tmp) + 1);        strcpy(n->type, tmp);            }    }    /* parameters, separated by white space */    else {      tmp[c++] = *s;    }  }   return first;} /* parse *//** Parse parameter=value. Return value, word becomes parameter.* Value must be integer.*/static u_int32 parse_int(char *word){  char *s;  u_int32 value;  if ((s = strchr(word, '='))) {    value = strtol(s+1, (char **)NULL, 0);        *s = '\0';  }  else {    *word = '\0';  }  return value;} /* parse_int *//** Free nodes recursively.*/static void node_free(node_t *list){  node_t *n, *n_next;  for (n = list; n; n = n_next) {    if (n->type) {      free(n->type);      n->type = 0;    }    if (n->string) {      free(n->string);      n->string = 0;    }    n->num = 0;    if (n->list) node_free(n->list);    n_next = n->next;    free(n);  }} /* node_free */static int rtcp_sdes_item(char *type, char *string, char *packet){  struct {    char *name;    rtcp_sdes_type_t type;   } map[] = {    {"end",   RTCP_SDES_END},    {"cname", RTCP_SDES_CNAME},    {"name",  RTCP_SDES_NAME},    {"email", RTCP_SDES_EMAIL},    {"phone", RTCP_SDES_PHONE},    {"loc",   RTCP_SDES_LOC},    {"tool",  RTCP_SDES_TOOL},    {"note",  RTCP_SDES_NOTE},     {"priv",  RTCP_SDES_PRIV},     {0,0}  };  int i;  rtcp_sdes_item_t *item = (rtcp_sdes_item_t *)packet;  for (i = 0; map[i].name; i++) {    if (strcasecmp(type, map[i].name) == 0) break;  }  item->type = map[i].type;  item->length = strlen(string);  strcpy(item->data, string);  return item->length + 2;} /* rtcp_sdes_item *//** Create SDES entries for single source.* Return length.*/static int rtcp_sdes(node_t *list, char *packet){  node_t *n;  int len = 0, total = 4;  struct rtcp_sdes *sdes = (struct rtcp_sdes *)packet;  packet += 4; /* skip SRC */  for (n = list; n; n = n->next) {    if (n->type) {      if (strcmp(n->type, "src") == 0) {        sdes->src = n->num;      }      else {        len = rtcp_sdes_item(n->type, n->string, packet);        packet += len;        total += len;      }    }  }  /* end marker */  *packet = RTCP_SDES_END;  total++;  /* pad length to next multiple of 32 bits */  len = (total + 3) & 0xfffc;  memset(packet, 0, len - total);  return len;} /* rtcp_sdes */static int rtcp_sr(node_t *n, char *packet){  int length = 0;  return length;} /* rtcp_sr */static int rtcp_rr(node_t *n, char *packet){  int length = 0;  return length;} /* rtcp_rr */static int rtcp_bye(node_t *n, char *packet){  int length = 0;  return length;} /* rtcp_bye *//** Based on list of parameters in 'n', assemble RTCP packet.*/static int rtcp_packet(node_t *list, char *packet){  node_t *n;  int len = 0, total = 4, count = 0;  rtcp_t *r = (rtcp_t *)packet;  int (*f)(node_t *list, char *packet);    r->common.length  = 0;  r->common.count   = 0;  r->common.version = RTP_VERSION;  r->common.p       = 0;  packet += 4; /* skip common header */  for (n = list; n; n = n->next) {    if (n->type) {      if (strcmp(n->type, "SDES") == 0) {        f = rtcp_sdes;        r->common.pt = RTCP_SDES;      }      else if (strcmp(n->type, "RR") == 0) {        f = rtcp_rr;        r->common.pt = RTCP_RR;      }      else if (strcmp(n->type, "SR") == 0) {        f = rtcp_sr;        r->common.pt = RTCP_SR;      }      else if (strcmp(n->type, "BYE") == 0) {        f = rtcp_bye;        r->common.pt = RTCP_BYE;      }      else if (strcmp(n->type, "pt") == 0) {        r->common.pt = n->num;      }      else if (strcmp(n->type, "v") == 0) {        r->common.version = n->num;      }      else if (strcmp(n->type, "p") == 0) {        r->common.p = n->num;      }      else if (strcmp(n->type, "count") == 0) {        r->common.count = n->num;      }      else if (strcmp(n->type, "len") == 0) {        r->common.length = n->num;      }    }    /* list: type-specific parts */    else {      len = (*f)(n->list, packet);      packet += len;      total += len;      count++;    }  }  /* if no length or count given, fill in */  if (r->common.length == 0) {    r->common.length = (total - 4) / 4;  }  if (r->common.count == 0) r->common.count = count;  return total;} /* rtcp_packet *//** Generate RTCP packet based on textual description.*/static int rtcp(char *text, char *packet){  node_t *node_list, *n;  int len;  int total = 0;  node_list = parse(text);  for (n = node_list; n; n = n->next) {    if (n->list) {      len = rtcp_packet(n->list, packet);      packet += len;      total += len;    }  }   node_free(node_list);  return total;} /* rtcp *//** Generate RTP data packet.*/static int rtp(char *text, char *packet){  char *word;  int pl = 0;  /* payload length */  int wc = 0;  int cc = 0;  int pad = 0;  rtp_hdr_t *h = (rtp_hdr_t *)packet;  int length = 0;  u_int32 value;  /* defaults */  memset(packet, 0, sizeof(rtp_hdr_t));  h->version = RTP_VERSION;  while ((word = strtok(wc ? 0 : text, " "))) {    value = parse_int(word);    if (strcmp(word, "ts") == 0) {      h->ts = htonl(value);    }    else if (strcmp(word, "seq") == 0) {      h->seq = htonl(value);    }    else if (strcmp(word, "pt") == 0) {      h->pt = value;    }    else if (strcmp(word, "ssrc") == 0) {      h->ssrc = htonl(value);    }    else if (strcmp(word, "p") == 0) {      h->p = (value != 0);      pad = value;    }    else if (strcmp(word, "m") == 0) {      h->m = value;    }    else if (strcmp(word, "v") == 0) {      h->version = value;    }    else if (strcmp(word, "cc") == 0) {      h->cc = value;    }    else if (strncmp(word, "csrc", 4) == 0) {      int k = atoi(&word[5]);      h->csrc[k] = value;      if (k > cc) cc = k;    }     /* data is in hex; words may be separated by spaces */    else if (strcmp(word, "data") == 0) {      pl = hex(&word[5], packet + 12 + h->cc*4);    }    else if (strcmp(word, "len") == 0) {      length = value;    }    wc++;  }  /* fill in default values if not set */  if (h->cc == 0) h->cc = cc;  if (length == 0) length = 12 + h->cc * 4 + pl;  /* insert padding */  return length;} /* rtp *//** Generate a packet based on description in 'text'. Return length.* Set generation time.*/static int generate(char *text, char *data, double *time, int *type){  int length;  char type_name[100];  if (verbose) printf("%s", text);  sscanf(text, "%lf %s", time, type_name);  if (strcmp(type_name, "RTP") == 0) {    length = rtp(strstr(text, "RTP") + 3, data);    *type = 0;  }  else if (strcmp(type_name, "RTCP") == 0) {    length = rtcp(strstr(text, "RTCP") + 4, data);    *type = 1;  }  return length;} /* generate *//** Timer handler; sends any pending packets and parses next one.* First packet is played out immediately.*/static Notify_value send_handler(Notify_client client){  static struct {    int length;    double time;    int type;    char data[1024];   } packet = { 0, -1, 0};  FILE *in = (FILE *)client;  static char line[2048];       /* last line read (may be next packet) */  char text[2048];  double this;                  /* time this packet is being sent */  struct timeval delta;         /* next packet generation time */  char *s;  /* send any pending packet */  if (packet.length && write(sock[packet.type], packet.data, packet.length) < 0) {    perror("write");  }   /* read line; continuation lines start with white space */  if (feof(in)) {    notify_stop();    exit(0);    return NOTIFY_DONE;  }  s = text;  if (line[0]) {    strcpy(text, line);    s += strlen(text);  }  while (fgets(line, sizeof(line), in)) {    if (line[0] == '#') continue;    else if (s != text && !isspace(line[0])) break;    else {      strcpy(s, line);      s += strlen(line);    }  }  this = packet.time;  packet.length = generate(text, packet.data, &packet.time, &packet.type);  /* very first packet: send immediately */  if (this < 0.) this = packet.time;  else if (this > packet.time) {    fprintf(stderr, "Non-monotonic time %f - sent immediately.\n", packet.time);    this = packet.time;  }  /* compute next playout time */  delta.tv_sec = packet.time - this;  delta.tv_usec = ((packet.time - this) - delta.tv_sec) * 1e6;  timer_set(&delta, send_handler, (Notify_client)in, 1);  return NOTIFY_DONE;} /* send_handler */int main(int argc, char *argv[]){  char ttl = 16;  static struct sockaddr_in sin;  int i;  int c;  int loop = 0;   /* play file indefinitely */  char *filename = 0;  extern char *optarg;  extern int optind;  extern int hpt(char *h, struct sockaddr *sa, unsigned char *ttl);  /* parse command line arguments */  while ((c = getopt(argc, argv, "f:lt:v")) != EOF) {    switch(c) {    case 'f':      filename = optarg;      break;    case 'l':      loop = 1;      break;    case 'v':      verbose = 1;      break;    case '?':    case 'h':      usage(argv[0]);      break;    }  }  if (filename) {    in = fopen(filename, "r");    if (!in) {      perror(filename);      exit(1);    }  }  else {    in = stdin;    loop = 0;  }  if (optind < argc) {    if (hpt(argv[optind], (struct sockaddr *)&sin, &ttl) < 0) usage(argv[0]);  }  /* create/connect sockets */  for (i = 0; i < 2; i++) {    sock[i] = socket(PF_INET, SOCK_DGRAM, 0);    if (sock[i] < 0) {      perror("socket");      exit(1);    }    sin.sin_port = htons(ntohs(sin.sin_port) + i);    if (connect(sock[i], (struct sockaddr *)&sin, sizeof(sin)) < 0) {      perror("connect");      exit(1);    }    if (IN_CLASSD(sin.sin_addr.s_addr) &&         (setsockopt(sock[i], IPPROTO_IP, IP_MULTICAST_TTL, &ttl,                   sizeof(ttl)) < 0)) {      perror("IP_MULTICAST_TTL");      exit(1);    }  }  send_handler((Notify_client)in);  notify_start();  return 0;} /* main */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -