1 /*
2  * Copyright (c) 2007-2008 Sippy Software, Inc., http://www.sippysoft.com
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  */
27 
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <netinet/in.h>
32 #include <assert.h>
33 #include <stddef.h>
34 
35 #include "rtp.h"
36 #include "rtp_info.h"
37 #include "rtp_packet.h"
38 #include "rtpp_mallocs.h"
39 
40 #include "rtpp_wi.h"
41 #include "rtpp_wi_private.h"
42 
43 #define RTP_PROFILE_AUDIO(s, nc) {.ts_rate = (s), .sample_rate = (s), \
44   .pt_kind = RTP_PTK_AUDIO, .nchannels = (nc)}
45 
46 const struct rtp_profile rtp_profiles[128] = {
47     RTP_PROFILE_AUDIO(8000,  1), /* RTP_PCMU */
48     {.pt_kind = RTP_PTK_RES},    /* Reserved */
49     {.pt_kind = RTP_PTK_RES},    /* Reserved */
50     RTP_PROFILE_AUDIO(8000,  1), /* RTP_GSM */
51     RTP_PROFILE_AUDIO(8000,  1), /* RTP_G723 */
52     RTP_PROFILE_AUDIO(8000,  1), /* RTP_DVI4_8000 */
53     RTP_PROFILE_AUDIO(16000, 1), /* RTP_DVI4_16000 */
54     RTP_PROFILE_AUDIO(8000,  1), /* RTP_LPC */
55     RTP_PROFILE_AUDIO(8000,  1), /* RTP_PCMA */
56     RTP_PROFILE_AUDIO(8000,  1), /* RTP_G722 */
57     RTP_PROFILE_AUDIO(44100, 1), /* RTP_L16_MONO */
58     RTP_PROFILE_AUDIO(44100, 2), /* RTP_L16_STEREO */
59     RTP_PROFILE_AUDIO(8000,  1), /* RTP_QCELP */
60     RTP_PROFILE_AUDIO(8000,  1), /* RTP_CN */
61     RTP_PROFILE_AUDIO(90000, 2), /* RTP_MPA */
62     RTP_PROFILE_AUDIO(8000,  1), /* RTP_G728 */
63     RTP_PROFILE_AUDIO(11025, 1), /* RTP_DVI4_11025 */
64     RTP_PROFILE_AUDIO(22050, 1), /* RTP_DVI4_22050 */
65     RTP_PROFILE_AUDIO(8000,  1)  /* RTP_G729 */
66 };
67 
68 struct rtp_packet_full;
69 
70 struct rtp_packet_priv {
71     struct rtp_info rinfo;
72     struct rtpp_wi wi;
73 };
74 
75 struct rtp_packet_full {
76     struct rtp_packet pub;
77     struct rtp_packet_priv pvt;
78 };
79 
80 static int
g723_len(unsigned char ch)81 g723_len(unsigned char ch)
82 {
83 
84     switch (ch & 3) {
85     case 2:
86 	/* Silence Insertion Descriptor (SID) frame */
87 	return 4;
88 
89     case 0:
90 	/* 6.3 kbit/s frame */
91 	return 24;
92 
93     case 1:
94 	/* 5.3 kbit/s frame */
95 	return 20;
96 
97     default:
98 	return RTP_NSAMPLES_UNKNOWN;
99     }
100 }
101 
102 static int
g723_samples(const unsigned char * buf,int maxlen)103 g723_samples(const unsigned char *buf, int maxlen)
104 {
105     int pos, samples, n;
106 
107     for (pos = 0, samples = 0; pos < maxlen; pos += n) {
108 	samples += 240;
109 	n = g723_len(buf[pos]);
110 	if (n == RTP_NSAMPLES_UNKNOWN)
111 	    return RTP_NSAMPLES_UNKNOWN;
112     }
113     return samples;
114 }
115 
116 static int
rtp_calc_samples(int codec_id,size_t nbytes,const unsigned char * data)117 rtp_calc_samples(int codec_id, size_t nbytes, const unsigned char *data)
118 {
119 
120     switch (codec_id) {
121 	case RTP_PCMU:
122 	case RTP_PCMA:
123 	    return nbytes;
124 
125 	case RTP_G729:
126 	    return (nbytes / 10) * 80 + (nbytes % 10 == 0 ? 0 : 80);
127 
128 	case RTP_GSM:
129 	    return 160 * (nbytes / 33);
130 
131 	case RTP_G723:
132 	    return g723_samples(data, nbytes);
133 
134 	case RTP_G722:
135 	    return nbytes;
136 
137 	default:
138 	    return RTP_NSAMPLES_UNKNOWN;
139     }
140 }
141 
142 static void
rtp_packet_chunk_find_g711(struct rtp_packet * pkt,struct rtp_packet_chunk * ret,int min_nsamples)143 rtp_packet_chunk_find_g711(struct rtp_packet *pkt, struct rtp_packet_chunk *ret, int min_nsamples)
144 {
145 
146     ret->nsamples = min_nsamples;
147     ret->bytes = min_nsamples;
148 }
149 
150 static void
rtp_packet_chunk_find_g729(struct rtp_packet * pkt,struct rtp_packet_chunk * ret,int min_nsamples)151 rtp_packet_chunk_find_g729(struct rtp_packet *pkt, struct rtp_packet_chunk *ret, int min_nsamples)
152 {
153     int frames, samples;
154 
155     frames = min_nsamples / 80 + ((min_nsamples % 80) == 0 ? 0 : 1);
156     samples = frames * 80;
157 
158     if (samples >= pkt->parsed->nsamples) {
159 	ret->whole_packet_matched = 1;
160 	return;
161     }
162     ret->nsamples = samples;
163     ret->bytes = frames * 10;
164 }
165 
166 static void
rtp_packet_chunk_find_gsm(struct rtp_packet * pkt,struct rtp_packet_chunk * ret,int min_nsamples)167 rtp_packet_chunk_find_gsm(struct rtp_packet *pkt, struct rtp_packet_chunk *ret, int min_nsamples)
168 {
169     int frames, samples;
170 
171     frames = min_nsamples / 160 + ((min_nsamples % 160) == 0 ? 0 : 1);
172     samples = frames * 160;
173 
174     if (samples >= pkt->parsed->nsamples) {
175 	ret->whole_packet_matched = 1;
176 	return;
177     }
178     ret->nsamples = samples;
179     ret->bytes = frames * 33;
180 }
181 
182 static void
rtp_packet_chunk_find_g723(struct rtp_packet * pkt,struct rtp_packet_chunk * ret,int min_nsamples)183 rtp_packet_chunk_find_g723(struct rtp_packet *pkt, struct rtp_packet_chunk *ret, int min_nsamples)
184 {
185     int frames, samples, pos, found_samples, n;
186     unsigned char *buf;
187 
188     frames = min_nsamples / 240 + ((min_nsamples % 240) == 0 ? 0 : 1);
189     samples = frames * 240;
190 
191     pos = 0;
192     found_samples = 0;
193     if (samples >= pkt->parsed->nsamples) {
194 	ret->whole_packet_matched = 1;
195 	return;
196     }
197 
198     buf = &pkt->data.buf[pkt->parsed->data_offset];
199     while (pos < pkt->parsed->data_size && samples > found_samples) {
200 	found_samples += 240;
201 	n = g723_len(buf[pos]);
202 	assert(n != RTP_NSAMPLES_UNKNOWN);
203 	pos += n;
204     }
205     ret->nsamples = found_samples;
206     ret->bytes = (pos < pkt->parsed->data_size ? pos : pkt->parsed->data_size);
207 }
208 
209 static void
rtp_packet_chunk_find_g722(struct rtp_packet * pkt,struct rtp_packet_chunk * ret,int min_nsamples)210 rtp_packet_chunk_find_g722(struct rtp_packet *pkt, struct rtp_packet_chunk *ret, int min_nsamples)
211 {
212     ret->nsamples = min_nsamples;
213     ret->bytes = min_nsamples / 2;
214 }
215 
216 
217 /*
218  * Find the head of the packet with the length at least
219  * of min_nsamples.
220  *
221  * Warning! When whole packet has been matched the chunk can be uninitialized.
222  */
223 void
rtp_packet_first_chunk_find(struct rtp_packet * pkt,struct rtp_packet_chunk * ret,int min_nsamples)224 rtp_packet_first_chunk_find(struct rtp_packet *pkt, struct rtp_packet_chunk *ret, int min_nsamples)
225 {
226 
227     assert(pkt->parsed->nsamples > min_nsamples);
228     ret->whole_packet_matched = 0;
229 
230     switch (pkt->data.header.pt) {
231     case RTP_PCMU:
232     case RTP_PCMA:
233 	rtp_packet_chunk_find_g711(pkt, ret, min_nsamples);
234 	break;
235 
236     case RTP_G729:
237 	rtp_packet_chunk_find_g729(pkt, ret, min_nsamples);
238 	break;
239 
240     case RTP_GSM:
241 	rtp_packet_chunk_find_gsm(pkt, ret, min_nsamples);
242 	break;
243 
244     case RTP_G723:
245 	rtp_packet_chunk_find_g723(pkt, ret, min_nsamples);
246 	break;
247 
248     case RTP_G722:
249 	rtp_packet_chunk_find_g722(pkt, ret, min_nsamples);
250 	break;
251 
252     default:
253 	ret->whole_packet_matched = 1;
254 	break;
255     }
256 }
257 
258 const char *
rtp_packet_parse_errstr(rtp_parser_err_t ecode)259 rtp_packet_parse_errstr(rtp_parser_err_t ecode)
260 {
261     switch (ecode) {
262     case RTP_PARSER_OK:
263        return "no error";
264 
265     case RTP_PARSER_PTOOSHRT:
266        return "packet is too short for RTP header";
267 
268     case RTP_PARSER_IHDRVER:
269        return "incorrect RTP header version";
270 
271     case RTP_PARSER_PTOOSHRTXS:
272        return "packet is too short for extended RTP header size";
273 
274     case RTP_PARSER_PTOOSHRTXH:
275        return "packet is too short for extended RTP header";
276 
277     case RTP_PARSER_PTOOSHRTPS:
278         return "packet is too short for RTP padding size";
279 
280     case RTP_PARSER_PTOOSHRTP:
281        return "packet is too short for RTP padding";
282 
283     case RTP_PARSER_IPS:
284        return "invalid RTP padding size";
285 
286     default:
287        abort();
288     }
289 
290     /* NOTREACHED */
291     return NULL;
292 }
293 
294 rtp_parser_err_t
rtp_packet_parse_raw(unsigned char * buf,size_t size,struct rtp_info * rinfo)295 rtp_packet_parse_raw(unsigned char *buf, size_t size, struct rtp_info *rinfo)
296 {
297     int padding_size;
298     rtp_hdr_ext_t *hdr_ext_ptr;
299     rtp_hdr_t *header;
300 
301     header = (rtp_hdr_t *)buf;
302 
303     padding_size = 0;
304 
305     rinfo->data_size = 0;
306     rinfo->data_offset = 0;
307     rinfo->appendable = 1;
308     rinfo->nsamples = RTP_NSAMPLES_UNKNOWN;
309 
310     if (size < sizeof(*header))
311         return RTP_PARSER_PTOOSHRT;
312 
313     if (header->version != 2)
314         return RTP_PARSER_IHDRVER;
315 
316     rinfo->data_offset = RTP_HDR_LEN(header);
317 
318     if (header->x != 0) {
319         if (size < rinfo->data_offset + sizeof(*hdr_ext_ptr))
320             return RTP_PARSER_PTOOSHRTXS;
321         hdr_ext_ptr = (rtp_hdr_ext_t *)&buf[rinfo->data_offset];
322         rinfo->data_offset += sizeof(rtp_hdr_ext_t) +
323           (ntohs(hdr_ext_ptr->length) * sizeof(hdr_ext_ptr->extension[0]));
324     }
325 
326     if (size < rinfo->data_offset)
327         return RTP_PARSER_PTOOSHRTXH;
328 
329     if (header->p != 0) {
330         if (rinfo->data_offset == size)
331             return RTP_PARSER_PTOOSHRTPS;
332         padding_size = buf[size - 1];
333         if (padding_size == 0)
334             return RTP_PARSER_IPS;
335     }
336 
337     if (size < rinfo->data_offset + padding_size)
338         return RTP_PARSER_PTOOSHRTP;
339 
340     rinfo->data_size = size - rinfo->data_offset - padding_size;
341     rinfo->ts = ntohl(header->ts);
342     rinfo->seq = ntohs(header->seq);
343     rinfo->ssrc = ntohl(header->ssrc);
344     rinfo->rtp_profile = &rtp_profiles[header->pt];
345 
346     if (rinfo->data_size == 0)
347         return RTP_PARSER_OK;
348 
349     rinfo->nsamples = rtp_calc_samples(header->pt, rinfo->data_size,
350       &buf[rinfo->data_offset]);
351     /*
352      * G.729 comfort noise frame as the last frame causes
353      * packet to be non-appendable
354      */
355     if (header->pt == RTP_G729 && (rinfo->data_size % 10) != 0)
356         rinfo->appendable = 0;
357     return RTP_PARSER_OK;
358 }
359 
360 rtp_parser_err_t
rtp_packet_parse(struct rtp_packet * pkt)361 rtp_packet_parse(struct rtp_packet *pkt)
362 {
363     struct rtp_packet_full *pkt_full;
364     struct rtp_info *rinfo;
365 
366     if (pkt->parse_result != RTP_PARSER_NOTPARSED) {
367         return (pkt->parse_result);
368     }
369     assert(pkt->parsed == NULL);
370     pkt_full = (void *)pkt;
371     rinfo = &(pkt_full->pvt.rinfo);
372     pkt->parse_result = rtp_packet_parse_raw(pkt->data.buf, pkt->size, rinfo);
373     if (pkt->parse_result == RTP_PARSER_OK) {
374         pkt->parsed = rinfo;
375     }
376     return (pkt->parse_result);
377 }
378 
379 void
rtp_packet_dup(struct rtp_packet * dpkt,struct rtp_packet * spkt,int flags)380 rtp_packet_dup(struct rtp_packet *dpkt, struct rtp_packet *spkt, int flags)
381 {
382     int csize;
383     struct rtp_packet_full *dpkt_full, *spkt_full;
384     struct rtp_info *drinfo, *srinfo;
385 
386     csize = offsetof(struct rtp_packet, data.buf) + spkt->size;
387     if ((flags & RTPP_DUP_HDRONLY) != 0) {
388         assert(spkt->parse_result == RTP_PARSER_OK);
389         csize -= spkt->parsed->data_size;
390     }
391     memcpy(dpkt, spkt, csize);
392     dpkt_full = (struct rtp_packet_full *)dpkt;
393     dpkt->wi = &(dpkt_full->pvt.wi);
394     if (dpkt->parsed == NULL) {
395         return;
396     }
397     drinfo = &(dpkt_full->pvt.rinfo);
398     spkt_full = (struct rtp_packet_full *)spkt;
399     srinfo = &(spkt_full->pvt.rinfo);
400     memcpy(drinfo, srinfo, sizeof(struct rtp_info));
401     dpkt->parsed = drinfo;
402     if ((flags & RTPP_DUP_HDRONLY) != 0) {
403         dpkt->size -= dpkt->parsed->data_size;
404         dpkt->parsed->data_size = 0;
405         dpkt->parsed->nsamples = 0;
406     }
407 }
408 
409 struct rtp_packet *
rtp_packet_alloc()410 rtp_packet_alloc()
411 {
412     struct rtp_packet_full *pkt;
413 
414     pkt = rtpp_zmalloc(sizeof(*pkt));
415     if (pkt == NULL) {
416         return (NULL);
417     }
418     pkt->pub.wi = &pkt->pvt.wi;
419 
420     return &(pkt->pub);
421 }
422 
423 void
rtp_packet_free(struct rtp_packet * pkt)424 rtp_packet_free(struct rtp_packet *pkt)
425 {
426 
427     free(pkt);
428 }
429 
430 void
rtp_packet_set_seq(struct rtp_packet * p,uint16_t seq)431 rtp_packet_set_seq(struct rtp_packet *p, uint16_t seq)
432 {
433 
434     p->parsed->seq = seq;
435     p->data.header.seq = htons(seq);
436 }
437 
438 void
rtp_packet_set_ts(struct rtp_packet * p,uint32_t ts)439 rtp_packet_set_ts(struct rtp_packet *p, uint32_t ts)
440 {
441 
442     p->parsed->ts = ts;
443     p->data.header.ts = htonl(ts);
444 }
445