shithub: opus-tools

Download patch

ref: 79b256df5c397a83037909a9a62a0ebc008d66a4
parent: bbcc1334e0b4d1b58b7ee679b296a8e8eb1bf8fd
author: Ralph Giles <giles@mozilla.com>
date: Mon Aug 27 11:44:49 EDT 2012

Move some of the header parsing logic into functions.

The code is a little cleaner now.

Also fixes a new warning created by the previous warning fix.

--- a/src/opusrtp.c
+++ b/src/opusrtp.c
@@ -4,11 +4,17 @@
  *
  */
 
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
+#ifdef HAVE_PCAP
 #include <pcap.h>
+#endif
 #include <ogg/ogg.h>
 
 /* state struct for passing around our handles */
@@ -141,12 +147,12 @@
 
   while (ogg_stream_pageout(params->stream, &page)) {
     written = fwrite(page.header, 1, page.header_len, params->out);
-    if (written != page.header_len) {
+    if (written != (size_t)page.header_len) {
       fprintf(stderr, "Error writing Ogg page header\n");
       return -2;
     }
     written = fwrite(page.body, 1, page.body_len, params->out);
-    if (written != page.body_len) {
+    if (written != (size_t)page.body_len) {
       fprintf(stderr, "Error writing Ogg page body\n");
       return -3;
     }
@@ -167,12 +173,12 @@
 
   while (ogg_stream_flush(params->stream, &page)) {
     written = fwrite(page.header, 1, page.header_len, params->out);
-    if (written != page.header_len) {
+    if (written != (size_t)page.header_len) {
       fprintf(stderr, "Error writing Ogg page header\n");
       return -2;
     }
     written = fwrite(page.body, 1, page.body_len, params->out);
-    if (written != page.body_len) {
+    if (written != (size_t)page.body_len) {
       fprintf(stderr, "Error writing Ogg page body\n");
       return -3;
     }
@@ -181,11 +187,13 @@
   return 0;
 }
 
+#define ETH_HEADER_LEN 14
 typedef struct {
   unsigned char src[6], dst[6]; /* ethernet MACs */
   int type;
 } eth_header;
 
+#define IP_HEADER_MIN 20
 typedef struct {
   int version;
   int header_size;
@@ -193,11 +201,13 @@
   int protocol;
 } ip_header;
 
+#define UDP_HEADER_LEN 8
 typedef struct {
   int src, dst; /* ports */
   int size, checksum;
 } udp_header;
 
+#define RTP_HEADER_MIN 12
 typedef struct {
   int version;
   int type;
@@ -204,15 +214,127 @@
   int pad, ext, cc, mark;
   int seq, time;
   int ssrc;
+  int *csrc;
   int header_size;
   int payload_size;
 } rtp_header;
 
+/* helper, read a big-endian 16 bit int from memory */
+static int rbe16(const unsigned char *p)
+{
+  int v = p[0] << 8 | p[1];
+  return v;
+}
+
+/* helper, read a big-endian 32 bit int from memory */
+static int rbe32(const unsigned char *p)
+{
+  int v = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
+  return v;
+}
+
+int parse_eth_header(const unsigned char *packet, int size, eth_header *eth)
+{
+  if (!packet || !eth) {
+    return -2;
+  }
+  if (size < ETH_HEADER_LEN) {
+    fprintf(stderr, "Packet too short for eth\n");
+    return -1;
+  }
+  memcpy(eth->src, packet + 0, 6);
+  memcpy(eth->dst, packet + 6, 6);
+  eth->type = rbe16(packet + 12);
+
+  return 0;
+}
+
+int parse_ip_header(const unsigned char *packet, int size, ip_header *ip)
+{
+  if (!packet || !ip) {
+    return -2;
+  }
+  if (size < IP_HEADER_MIN) {
+    fprintf(stderr, "Packet too short for ip\n");
+    return -1;
+  }
+
+  ip->version = (packet[0] >> 4) & 0x0f;
+  if (ip->version != 4) {
+    fprintf(stderr, "unhandled ip version %d\n", ip->version);
+    return 1;
+  }
+
+  /* ipv4 header */
+  ip->header_size = 4 * (packet[0] & 0x0f);
+  ip->protocol = packet[9];
+  memcpy(ip->src, packet + 12, 4);
+  memcpy(ip->dst, packet + 16, 4);
+
+  if (size < ip->header_size) {
+    fprintf(stderr, "Packet too short for ipv4 with options\n");
+    return -1;
+  }
+
+  return 0;
+}
+
+int parse_udp_header(const unsigned char *packet, int size, udp_header *udp)
+{
+  if (!packet || !udp) {
+    return -2;
+  }
+  if (size < UDP_HEADER_LEN) {
+    fprintf(stderr, "Packet too short for udp\n");
+    return -1;
+  }
+
+  udp->src = rbe16(packet);
+  udp->dst = rbe16(packet + 2);
+  udp->size = rbe16(packet + 4);
+  udp->checksum = rbe16(packet + 6);
+
+  return 0;
+}
+
+
+int parse_rtp_header(const unsigned char *packet, int size, rtp_header *rtp)
+{
+  if (!packet || !rtp) {
+    return -2;
+  }
+  if (size < RTP_HEADER_MIN) {
+    fprintf(stderr, "Packet too short for rtp\n");
+    return -1;
+  }
+  rtp->version = (packet[0] >> 6) & 3;
+  rtp->pad = (packet[0] >> 5) & 1;
+  rtp->ext = (packet[0] >> 4) & 1;
+  rtp->cc = packet[0] & 7;
+  rtp->header_size = 12 + 4 * rtp->cc;
+  rtp->payload_size = size - rtp->header_size;
+
+  rtp->mark = (packet[1] >> 7) & 1;
+  rtp->type = (packet[1]) & 127;
+  rtp->seq  = rbe16(packet + 2);
+  rtp->time = rbe32(packet + 4);
+  rtp->ssrc = rbe32(packet + 8);
+  rtp->csrc = NULL;
+  if (size < rtp->header_size) {
+    fprintf(stderr, "Packet too short for RTP header\n");
+    return -1;
+  }
+
+  return 0;
+}
+
 /* pcap 'got_packet' callback */
 void write_packet(u_char *args, const struct pcap_pkthdr *header,
-                  const u_char *packet)
+                  const u_char *data)
 {
   state *params = (state *)args;
+  const unsigned char *packet;
+  int size;
   eth_header eth;
   ip_header ip;
   udp_header udp;
@@ -220,16 +342,13 @@
 
   fprintf(stderr, "Got %d byte packet (%d bytes captured)\n",
           header->len, header->caplen);
+  packet = data;
+  size = header->caplen;
 
-  /* eth header is always 14 bytes */
-  if (header->caplen < 14) {
-    fprintf(stderr, "Packet too short for eth\n");
+  if (parse_eth_header(packet, size, &eth)) {
+    fprintf(stderr, "error parsing eth header\n");
     return;
   }
-  memcpy(eth.src, packet, 6);
-  memcpy(eth.dst, packet + 6, 6);
-  eth.type = packet[12] << 8 | packet[13];
-
   fprintf(stderr, "  eth 0x%04x", eth.type);
   fprintf(stderr, " %02x:%02x:%02x:%02x:%02x:%02x ->",
           eth.src[0], eth.src[1], eth.src[2],
@@ -237,18 +356,13 @@
   fprintf(stderr, " %02x:%02x:%02x:%02x:%02x:%02x\n",
           eth.dst[0], eth.dst[1], eth.dst[2],
           eth.dst[3], eth.dst[4], eth.dst[5]);
+  packet += ETH_HEADER_LEN;
+  size -= ETH_HEADER_LEN;
 
-  /* ipv4 header */
-  if (header->caplen < 14 + 20) {
-    fprintf(stderr, "Packet too short for ipv4\n");
+  if (parse_ip_header(packet, size, &ip)) {
+    fprintf(stderr, "error parsing ip header\n");
     return;
   }
-  ip.version = (packet[14+0] >> 4) & 0x0f;
-  ip.header_size = 4 * (packet[14+0] & 0x0f);
-  ip.protocol = packet[14 + 9];
-  memcpy(ip.src, packet + 14 + 12, 4);
-  memcpy(ip.dst, packet + 14 + 16, 4);
-
   fprintf(stderr, " ipv%d protocol %d", ip.version, ip.protocol);
   fprintf(stderr, " %d.%d.%d.%d ->",
           ip.src[0], ip.src[1], ip.src[2], ip.src[3]);
@@ -255,49 +369,22 @@
   fprintf(stderr, " %d.%d.%d.%d",
           ip.dst[0], ip.dst[1], ip.dst[2], ip.dst[3]);
   fprintf(stderr, " header %d bytes\n", ip.header_size);
-  if (header->caplen < 14 + ip.header_size) {
-    fprintf(stderr, "Packet too short for ipv4 with options\n");
-    return;
-  }
+  packet += ip.header_size;
+  size -= ip.header_size;
 
-  if (header->caplen < 14 + ip.header_size + 8) {
-    fprintf(stderr, "Packet too short for udp\n");
+  if (parse_udp_header(packet, size, &udp)) {
+    fprintf(stderr, "error parsing udp header\n");
     return;
   }
-  udp.src = packet[14+ip.header_size] << 8 |
-            packet[14+ip.header_size + 1];
-  udp.dst = packet[14+ip.header_size + 2] << 8 |
-            packet[14+ip.header_size + 3];
-  udp.size = packet[14+ip.header_size + 4] << 8 |
-             packet[14+ip.header_size + 5];
-  udp.checksum = packet[14+ip.header_size + 6] << 8 |
-                 packet[14+ip.header_size + 7];
   fprintf(stderr, "  udp %d bytes %d -> %d crc 0x%04x\n",
           udp.size, udp.src, udp.dst, udp.checksum);
-  if (header->caplen < 14 + ip.header_size + 8 + 12) {
-    fprintf(stderr, "Packet too short for rtp\n");
+  packet += UDP_HEADER_LEN;
+  size -= UDP_HEADER_LEN;
+
+  if (parse_rtp_header(packet, size, &rtp)) {
+    fprintf(stderr, "error parsing rtp header\n");
     return;
   }
-  rtp.version = (packet[14+ip.header_size+8 + 0] >> 6) & 3;
-  rtp.pad = (packet[14+ip.header_size+8] >> 5) & 1;
-  rtp.ext = (packet[14+ip.header_size+8] >> 4) & 1;
-  rtp.cc = packet[14+ip.header_size+8] & 7;
-  rtp.header_size = 12 + 4 * rtp.cc;
-  rtp.payload_size = udp.size - 8 - rtp.header_size;
-
-  rtp.mark = (packet[14+ip.header_size+8 + 1] >> 7) & 1;
-  rtp.type = (packet[14+ip.header_size+8 + 1]) & 127;
-  rtp.seq = packet[14+ip.header_size+8 + 2] << 8 |
-            packet[14+ip.header_size+8 + 3];
-  rtp.time = packet[14+ip.header_size+8 + 4] << 24 |
-             packet[14+ip.header_size+8 + 5] << 16 |
-             packet[14+ip.header_size+8 + 6] << 8 |
-             packet[14+ip.header_size+8 + 7];
-  rtp.ssrc = packet[14+ip.header_size+8 + 8] << 24 |
-             packet[14+ip.header_size+8 + 9] << 16 |
-             packet[14+ip.header_size+8 + 10] << 8 |
-             packet[14+ip.header_size+8 + 11];
-
   fprintf(stderr, "  rtp 0x%08x %d %d %d",
           rtp.ssrc, rtp.type, rtp.seq, rtp.time);
   fprintf(stderr, "  v%d %s%s%s CC %d", rtp.version,
@@ -305,7 +392,10 @@
           rtp.mark ? "M":".", rtp.cc);
   fprintf(stderr, " %5d bytes\n", rtp.payload_size);
 
-  if (header->caplen < 14 + ip.header_size + 8 + rtp.header_size) {
+  packet += rtp.header_size;
+  size -= rtp.header_size;
+
+  if (size < 0) {
     fprintf(stderr, "skipping short packet\n");
     return;
   }
@@ -322,10 +412,8 @@
   }
 
   /* write the payload to our opus file */
-  int size = header->caplen - 14 - ip.header_size - 8 - rtp.header_size;
-  unsigned char *data = packet + 14+ip.header_size+8 + rtp.header_size;
-  ogg_packet *op = op_from_pkt(data, size);
-  op->granulepos = 960*rtp.seq;
+  ogg_packet *op = op_from_pkt(packet, size);
+  op->granulepos = 960*rtp.seq; // FIXME: get this from the toc byte
   ogg_stream_packetin(params->stream, op);
   free(op);
   ogg_write(params);