]> sjero.net Git - linphone/blob - linphone/oRTP/src/rtcpparse.c
64df2c7762b4810fe9a82b423d816320ff2539b0
[linphone] / linphone / oRTP / src / rtcpparse.c
1 /*
2   The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack.
3   Copyright (C) 2001  Simon MORLAT simon.morlat@linphone.org
4
5   This library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License as published by the Free Software Foundation; either
8   version 2.1 of the License, or (at your option) any later version.
9
10   This library is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   Lesser General Public License for more details.
14
15   You should have received a copy of the GNU Lesser General Public
16   License along with this library; if not, write to the Free Software
17   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19
20
21 #include "ortp/ortp.h"
22 #include "utils.h"
23
24
25 /*in case of coumpound packet, set read pointer of m to the beginning of the next RTCP
26 packet */
27 bool_t rtcp_next_packet(mblk_t *m){
28         const rtcp_common_header_t *ch=rtcp_get_common_header(m);
29         if (ch){
30                 int nextlen=sizeof(rtcp_common_header_t)+
31                         (rtcp_common_header_get_length(ch)*4);
32                 if (m->b_rptr+nextlen<m->b_wptr){
33                         m->b_rptr+=nextlen;
34                         return TRUE;
35                 }
36         }
37         return FALSE;
38 }
39
40 void rtcp_rewind(mblk_t *m){
41         m->b_rptr=m->b_datap->db_base;
42 }
43
44 /* get common header; this function will also check the sanity of the packet*/
45 const rtcp_common_header_t * rtcp_get_common_header(const mblk_t *m){
46         int size=msgdsize(m);
47         rtcp_common_header_t *ch;
48         if (m->b_cont!=NULL){
49                 ortp_fatal("RTCP parser does not work on fragmented mblk_t. Use msgpullup() before to re-assemble the packet.");
50                 return NULL;
51         }
52         if (size<sizeof(rtcp_common_header_t)){
53                 ortp_warning("Bad RTCP packet, too short.");
54                 return NULL;
55         }
56         ch=(rtcp_common_header_t*)m->b_rptr;
57         return ch;
58 }
59
60 bool_t rtcp_is_SR(const mblk_t *m){
61         const rtcp_common_header_t *ch=rtcp_get_common_header(m);
62         if (ch!=NULL && rtcp_common_header_get_packet_type(ch)==RTCP_SR){
63                 if (msgdsize(m)<sizeof(rtcp_sr_t)){
64                         ortp_warning("Too short RTCP SR packet.");
65                         return FALSE;
66                 }
67                 return TRUE;
68         }
69         return FALSE;
70 }
71
72 /*Sender Report accessors */
73 uint32_t rtcp_SR_get_ssrc(const mblk_t *m){
74         rtcp_sr_t *sr=(rtcp_sr_t*)m->b_rptr;
75         return ntohl(sr->ssrc);
76 }
77
78 const sender_info_t * rtcp_SR_get_sender_info(const mblk_t *m){
79         rtcp_sr_t *sr=(rtcp_sr_t*)m->b_rptr;
80         return &sr->si;
81 }
82
83 const report_block_t * rtcp_SR_get_report_block(const mblk_t *m, int idx){
84         rtcp_sr_t *sr=(rtcp_sr_t*)m->b_rptr;
85         report_block_t *rb=&sr->rb[idx];
86         int size=sizeof(rtcp_common_header_t)+(4*rtcp_common_header_get_length(&sr->ch));
87         if ( ( (uint8_t*)rb)+sizeof(report_block_t) <= m->b_rptr + size ) {
88                 return rb;
89         }else{
90                 if (idx<rtcp_common_header_get_rc(&sr->ch)){
91                         ortp_warning("RTCP packet should include a report_block_t at pos %i but has no space for it.",idx);
92                 }
93         }
94         return NULL;
95 }
96
97 /*Receiver report accessors*/
98 bool_t rtcp_is_RR(const mblk_t *m){
99         const rtcp_common_header_t *ch=rtcp_get_common_header(m);
100         if (ch!=NULL && rtcp_common_header_get_packet_type(ch)==RTCP_RR){
101                 if (msgdsize(m)<sizeof(rtcp_rr_t)){
102                         ortp_warning("Too short RTCP RR packet.");
103                         return FALSE;
104                 }
105                 return TRUE;
106         }
107         return FALSE;
108 }
109
110 uint32_t rtcp_RR_get_ssrc(const mblk_t *m){
111         rtcp_rr_t *rr=(rtcp_rr_t*)m->b_rptr;
112         return ntohl(rr->ssrc);
113 }
114
115 const report_block_t * rtcp_RR_get_report_block(const mblk_t *m,int idx){
116         rtcp_rr_t *rr=(rtcp_rr_t*)m->b_rptr;
117         report_block_t *rb=&rr->rb[idx];
118         int size=sizeof(rtcp_common_header_t)+(4*rtcp_common_header_get_length(&rr->ch));
119         if ( ( (uint8_t*)rb)+sizeof(report_block_t) <= (m->b_rptr + size ) ){
120                 return rb;
121         }else{
122                 if (idx<rtcp_common_header_get_rc(&rr->ch)){
123                         ortp_warning("RTCP packet should include a report_block_t at pos %i but has no space for it.",idx);
124                 }
125         }
126         return NULL;
127 }
128
129 /*SDES accessors */
130 bool_t rtcp_is_SDES(const mblk_t *m){
131         const rtcp_common_header_t *ch=rtcp_get_common_header(m);
132         if (ch && rtcp_common_header_get_packet_type(ch)==RTCP_SDES){
133                 if (msgdsize(m)<sizeof(rtcp_common_header_t)+
134                         (4*rtcp_common_header_get_length(ch))){
135                         ortp_warning("Too short RTCP SDES packet.");
136                         return FALSE;
137                 }
138                 return TRUE;
139         }
140         return FALSE;
141 }
142
143 void rtcp_sdes_parse(const mblk_t *m, SdesItemFoundCallback cb, void *user_data){
144         uint8_t *rptr=(uint8_t*)m->b_rptr+sizeof(rtcp_common_header_t);
145         const rtcp_common_header_t *ch=(rtcp_common_header_t*)m->b_rptr;
146         uint8_t *end=rptr+sizeof(rtcp_common_header_t)+
147                         (4*rtcp_common_header_get_length(ch));
148         uint32_t ssrc=0;
149         int nchunk=0;
150         bool_t chunk_start=TRUE;
151
152         if (end>(uint8_t*)m->b_wptr) end=(uint8_t*)m->b_wptr;
153
154         while(rptr<end){
155                 if (chunk_start){
156                         if (rptr+4<=end){
157                                 ssrc=ntohl(*(uint32_t*)rptr);
158                                 rptr+=4;
159                         }else{
160                                 ortp_warning("incorrect chunk start in RTCP SDES");
161                                 break;
162                         }
163                         chunk_start=FALSE;
164                 }else{
165                         if (rptr+2<=end){
166                                 uint8_t type=rptr[0];
167                                 uint8_t len=rptr[1];
168
169                                 if (type==RTCP_SDES_END){
170                                         /* pad to next 32bit boundary*/
171                                         rptr=(uint8_t*)(((unsigned long)rptr+4) & ~0x3);
172                                         nchunk++;
173                                         if (nchunk<rtcp_common_header_get_rc(ch)){
174                                                 chunk_start=TRUE;
175                                                 continue;
176                                         }else break;
177                                 }
178                                 rptr+=2;
179                                 if (rptr+len<=end){
180                                         cb(user_data,ssrc,type,(char*)rptr,len);
181                                         rptr+=len;
182                                 }else{
183                                         ortp_warning("bad item length in RTCP SDES");
184                                         break;
185                                 }
186                         }else{
187                                 /*end of packet */
188                                 break;
189                         }
190                 }
191         }
192 }
193
194 /*BYE accessors */
195 bool_t rtcp_is_BYE(const mblk_t *m){
196         const rtcp_common_header_t *ch=rtcp_get_common_header(m);
197         if (ch && rtcp_common_header_get_packet_type(ch)==RTCP_BYE){
198                 if (msgdsize(m)<sizeof(rtcp_common_header_t)+
199                         rtcp_common_header_get_length(ch)){
200                         ortp_warning("Too short RTCP BYE packet.");
201                         return FALSE;
202                 }
203                 return TRUE;
204         }
205         return FALSE;
206 }
207
208 bool_t rtcp_BYE_get_ssrc(const mblk_t *m, int idx, uint32_t *ssrc){
209         rtcp_bye_t *bye=(rtcp_bye_t*)m->b_rptr;
210         int rc=rtcp_common_header_get_rc(&bye->ch);
211         int len=rtcp_common_header_get_length(&bye->ch);
212         if (idx<rc){
213                 if ((uint8_t*)&bye->ssrc[idx]<=(m->b_rptr
214                                 +sizeof(rtcp_common_header_t)+len-4)) {
215                         *ssrc=ntohl(bye->ssrc[idx]);
216                         return TRUE;
217                 }else{
218                         ortp_warning("RTCP BYE should contain %i ssrc, but there is not enough room for it.");
219                 }
220         }
221         return FALSE;
222 }
223
224 bool_t rtcp_BYE_get_reason(const mblk_t *m, const char **reason, int *reason_len){
225         rtcp_bye_t *bye=(rtcp_bye_t*)m->b_rptr;
226         int rc=rtcp_common_header_get_rc(&bye->ch);
227         int len=rtcp_common_header_get_length(&bye->ch);
228         uint8_t *rptr=(uint8_t*)m->b_rptr+sizeof(rtcp_common_header_t)+rc*4;
229         uint8_t *end=(uint8_t*)(m->b_rptr+sizeof(rtcp_common_header_t)+len);
230         if (rptr<end){
231                 uint8_t content_len=rptr[0];
232                 if (rptr+1+content_len<=end){
233                         *reason=(char*)rptr+1;
234                         *reason_len=content_len;
235                         return TRUE;
236                 }else{
237                         ortp_warning("RTCP BYE has not enough space for reason phrase.");
238                         return FALSE;
239                 }
240         }
241         return FALSE;
242 }
243
244 /*APP accessors */
245 bool_t rtcp_is_APP(const mblk_t *m){
246         const rtcp_common_header_t *ch=rtcp_get_common_header(m);
247         if (ch!=NULL && rtcp_common_header_get_packet_type(ch)==RTCP_APP){
248                 if (msgdsize(m)<sizeof(rtcp_common_header_t)+
249                         rtcp_common_header_get_length(ch)){
250                         ortp_warning("Too short RTCP APP packet.");
251                         return FALSE;
252                 }
253                 if (sizeof(rtcp_common_header_t)+rtcp_common_header_get_length(ch)
254                         < sizeof(rtcp_app_t)){
255                         ortp_warning("Bad RTCP APP packet.");
256                         return FALSE;
257                 }
258                 return TRUE;
259         }
260         return FALSE;
261 }
262
263 int rtcp_APP_get_subtype(const mblk_t *m){
264         rtcp_app_t *app=(rtcp_app_t*)m->b_rptr;
265         return rtcp_common_header_get_rc(&app->ch);
266 }
267
268 uint32_t rtcp_APP_get_ssrc(const mblk_t *m){
269         rtcp_app_t *app=(rtcp_app_t*)m->b_rptr;
270         return ntohl(app->ssrc);
271 }
272 /* name argument is supposed to be at least 4 characters (note: no '\0' written)*/
273 void rtcp_APP_get_name(const mblk_t *m, char *name){
274         rtcp_app_t *app=(rtcp_app_t*)m->b_rptr;
275         memcpy(name,app->name,4);
276 }
277 /* retrieve the data. when returning, data points directly into the mblk_t */
278 void rtcp_APP_get_data(const mblk_t *m, uint8_t **data, int *len){
279         rtcp_app_t *app=(rtcp_app_t*)m->b_rptr;
280         int datalen=sizeof(rtcp_common_header_t)+rtcp_common_header_get_length(&app->ch)-8;
281         if (datalen>0){
282                 *data=(uint8_t*)m->b_rptr+sizeof(rtcp_app_t);
283                 *len=datalen;
284         }else{
285                 *len=0;
286                 *data=NULL;
287         }
288 }
289
290 /*old functions: deprecated, but some useful code parts can be reused */
291 /* Start from now this source code file was written by Nicola Baldo as an extension of 
292   the oRTP library. Copyright (C) 2005 Nicola Baldo nicola@baldo.biz*/
293
294 void report_block_parse(RtpSession *session, report_block_t *rb, struct timeval rcv_time_tv)
295 {               
296   rb->ssrc = ntohl(rb->ssrc);
297
298   if ( rb->ssrc != session->snd.ssrc )
299
300     {
301       ortp_debug("Received rtcp report block related to unknown ssrc (not from us)... discarded");
302       return;
303     }       
304
305   else
306
307     {
308       uint32_t rcv_time_msw;       
309       uint32_t rcv_time_lsw;
310       uint32_t rcv_time;
311       double rtt;
312
313       rcv_time_msw = rcv_time_tv.tv_sec;
314 #if defined(_WIN32_WCE)
315       rcv_time_lsw = (uint32_t) ((double)rcv_time_tv.tv_usec*(double)(((uint64_t)1)<<32)*1.0e-6);
316 #else
317       rcv_time_lsw = (uint32_t) ((double)rcv_time_tv.tv_usec*(double)(1LL<<32)*1.0e-6);
318 #endif
319       rcv_time = (rcv_time_msw<<16) | (rcv_time_lsw >> 16);
320
321 /*
322       rb->cum_num_packet_lost = ntoh24(rb->cum_num_packet_lost);
323       rb->ext_high_seq_num_rec = ntohl(rb->ext_high_seq_num_rec);
324       rb->interarrival_jitter = ntohl(rb->interarrival_jitter);
325       rb->lsr = ntohl(rb->lsr);
326       rb->delay_snc_last_sr = ntohl(rb->delay_snc_last_sr);
327 */
328                   
329       /* calculating Round Trip Time*/ 
330       if (rb->lsr != 0)
331         {
332           rtt = (double) (rcv_time - rb->delay_snc_last_sr - rb->lsr);
333           rtt = rtt/65536;        
334           //printf("RTT = %f s\n",rtt);
335         }
336
337     }
338
339 }
340
341 void rtp_session_rtcp_parse(RtpSession *session, mblk_t *mp)
342 {
343   rtcp_common_header_t *rtcp;
344   int msgsize;
345   int rtcp_pk_size;
346   RtpStream *rtpstream=&session->rtp;
347   struct timeval rcv_time_tv;
348
349   
350   gettimeofday(&rcv_time_tv,NULL);
351
352   return_if_fail(mp!=NULL);
353
354   msgsize=(int) (mp->b_wptr-mp->b_rptr);
355
356   if (msgsize < RTCP_COMMON_HEADER_SIZE)
357     {
358       ortp_debug("Receiving too short rtcp packet... discarded");
359       return;
360     }
361
362   rtcp=(rtcp_common_header_t *)mp->b_rptr;
363
364   /* compound rtcp packet can be composed by more than one rtcp message */
365   while (msgsize >= RTCP_COMMON_HEADER_SIZE)
366     {
367
368       if (rtcp->version!=2)
369         {
370           ortp_debug("Receiving rtcp packet with version number !=2...discarded");
371           return;
372         }
373
374       /* convert header data from network order to host order */
375       rtcp->length = ntohs(rtcp->length);
376
377       /* compute length */
378       rtcp_pk_size = (rtcp->length + 1) * 4;
379       /* Sanity check of simple RTCP packet length. */
380       if (rtcp_pk_size > msgsize)
381         {
382           ortp_debug("Receiving rtcp packet shorter than the specified length.. discared");
383           return;
384         }
385
386       switch (rtcp->packet_type)   
387
388         {
389
390         case RTCP_SR:
391
392           {
393             rtcp_sr_t *sr = (rtcp_sr_t *) rtcp;
394             report_block_t *rb;
395             int i;
396
397             if ( ntohl(sr->ssrc) != session->rcv.ssrc )
398               {
399                 ortp_debug("Receiving rtcp sr packet from unknown ssrc.. discarded");           
400                 return;
401               }     
402
403             if (msgsize < RTCP_COMMON_HEADER_SIZE + RTCP_SSRC_FIELD_SIZE + RTCP_SENDER_INFO_SIZE + (RTCP_REPORT_BLOCK_SIZE*sr->ch.rc))
404               {
405                 ortp_debug("Receiving too short rtcp sr packet... discarded");
406                 return;
407               }     
408
409             /* parsing RTCP Sender Info */ 
410             sr->si.ntp_timestamp_msw = ntohl(sr->si.ntp_timestamp_msw);
411             sr->si.ntp_timestamp_lsw = ntohl(sr->si.ntp_timestamp_lsw);
412             sr->si.rtp_timestamp = ntohl(sr->si.rtp_timestamp);
413             sr->si.senders_packet_count = ntohl(sr->si.senders_packet_count);
414             sr->si.senders_octet_count = ntohl(sr->si.senders_octet_count);         
415
416             /* saving data to fill LSR and DLSR field in next RTCP report to be transmitted  */
417             rtpstream->last_rcv_SR_ts = (sr->si.ntp_timestamp_msw << 16) | (sr->si.ntp_timestamp_lsw >> 16);  
418             rtpstream->last_rcv_SR_time.tv_usec = rcv_time_tv.tv_usec;
419             rtpstream->last_rcv_SR_time.tv_sec = rcv_time_tv.tv_sec;                
420
421
422             /* parsing all RTCP report blocks */          
423             for (i=0; i<sr->ch.rc; i++)
424               { 
425                 rb = &(sr->rb[i]);              
426                 report_block_parse(session, rb, rcv_time_tv);           
427               }
428
429           }
430           break;
431
432
433
434         case RTCP_RR:
435
436           {
437             rtcp_rr_t *rr = (rtcp_rr_t *) rtcp;
438             report_block_t *rb;
439             int i;
440
441         if (session->rcv.ssrc == 0)
442           {
443             /* rcv.ssrc is not set, so we adopt the incoming one */
444             session->rcv.ssrc = ntohl(rr->ssrc);
445           }
446             else if ( ntohl(rr->ssrc) != session->rcv.ssrc )
447           {
448             ortp_debug("Receiving rtcp rr packet from unknown ssrc.. discarded");
449             return;
450           }
451
452             if (msgsize < RTCP_COMMON_HEADER_SIZE + RTCP_SSRC_FIELD_SIZE + (RTCP_REPORT_BLOCK_SIZE*rr->ch.rc))
453               {
454                 ortp_debug("Receiving too short rtcp sr packet... discarded");
455                 return;
456               }     
457
458             /* parsing all RTCP report blocks */          
459             for (i=0; i<rr->ch.rc; i++)
460               { 
461                 rb = &(rr->rb[i]);              
462                 report_block_parse(session, rb, rcv_time_tv);           
463               }
464   
465           }
466           break;
467           
468           
469         case RTCP_SDES: 
470           /* to be implemented */
471           break;
472                   
473           
474         case RTCP_BYE:
475       {
476         rtcp_bye_t *bye = (rtcp_bye_t *) rtcp;
477         unsigned sclen = bye->ch.rc * 4;
478         int reason_space_len = rtcp_pk_size
479                                - sizeof (rtcp_common_header_t)
480                                - sclen;
481         int i;
482         char *reason = NULL;
483         bool_t rcv_ssrc_match = FALSE;
484
485         if (reason_space_len < 0) {
486             ortp_debug("Receiving too short RTCP BYE packet... discarded");
487             return;
488         }
489         for (i = 0; i < bye->ch.rc; i++) {
490             if (ntohl(bye->ssrc[i]) == session->rcv.ssrc) {
491                 rcv_ssrc_match = TRUE;
492                 break;
493             }
494         }
495         if (rcv_ssrc_match) {
496             if (session->on_rtcp_bye.count > 0) {
497                 /* Get reason. */
498                 if (reason_space_len > 1) {
499                     uint8_t *reasonbuf = (uint8_t *) rtcp
500                                         + sizeof (rtcp_common_header_t)
501                                         + sclen;
502                     if (reasonbuf[0] <= reason_space_len-1)
503                         reason = ortp_strndup((char *)(reasonbuf+1), reasonbuf[0]);
504                     else
505                         ortp_debug("Incorrect RTCP BYE reason length");
506                 }
507                 rtp_signal_table_emit2(&session->on_rtcp_bye,
508                     (long)reason);
509                 if (reason)
510                     ortp_free(reason);
511             } else {
512                 ortp_debug("Got RTCP BYE without RTCP BYE handler");
513             }
514         } else {
515             ortp_debug("No SSRC in the BYE packet matched our rcv.ssrc.");
516         }
517             break;
518       }
519
520         case RTCP_APP:
521           /* to be implemented */
522           break;
523
524           
525         default:
526
527           ortp_debug("Receiving unknown rtcp packet type... discarded");
528           return;
529
530         }
531
532       
533       msgsize -= rtcp_pk_size;              /* size of unparsed portion of UDP packet, in octets */
534       rtcp = (rtcp_common_header_t *) (rtcp_pk_size + (char *) rtcp);  /* pointer to next RTCP packet in current UDP packet */
535
536     }
537
538     /* The function did not failed sanity checks, write down the RTPC/RTCP
539        reception time. */
540     session->last_recv_time = rcv_time_tv;
541 }