src/rtcpparse.c

00001 /*
00002   The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack.
00003   Copyright (C) 2001  Simon MORLAT simon.morlat@linphone.org
00004 
00005   This library is free software; you can redistribute it and/or
00006   modify it under the terms of the GNU Lesser General Public
00007   License as published by the Free Software Foundation; either
00008   version 2.1 of the License, or (at your option) any later version.
00009 
00010   This library is distributed in the hope that it will be useful,
00011   but WITHOUT ANY WARRANTY; without even the implied warranty of
00012   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013   Lesser General Public License for more details.
00014 
00015   You should have received a copy of the GNU Lesser General Public
00016   License along with this library; if not, write to the Free Software
00017   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 */
00019 
00020 
00021 #include "ortp/ortp.h"
00022 #include "utils.h"
00023 
00024 
00025 /*in case of coumpound packet, set read pointer of m to the beginning of the next RTCP
00026 packet */
00027 bool_t rtcp_next_packet(mblk_t *m){
00028         const rtcp_common_header_t *ch=rtcp_get_common_header(m);
00029         if (ch){
00030                 int nextlen=sizeof(rtcp_common_header_t)+
00031                         (rtcp_common_header_get_length(ch)*4);
00032                 if (m->b_rptr+nextlen<m->b_wptr){
00033                         m->b_rptr+=nextlen;
00034                         return TRUE;
00035                 }
00036         }
00037         return FALSE;
00038 }
00039 
00040 void rtcp_rewind(mblk_t *m){
00041         m->b_rptr=m->b_datap->db_base;
00042 }
00043 
00044 /* get common header; this function will also check the sanity of the packet*/
00045 const rtcp_common_header_t * rtcp_get_common_header(const mblk_t *m){
00046         int size=msgdsize(m);
00047         rtcp_common_header_t *ch;
00048         if (m->b_cont!=NULL){
00049                 ortp_fatal("RTCP parser does not work on fragmented mblk_t. Use msgpullup() before to re-assemble the packet.");
00050                 return NULL;
00051         }
00052         if (size<sizeof(rtcp_common_header_t)){
00053                 ortp_warning("Bad RTCP packet, too short.");
00054                 return NULL;
00055         }
00056         ch=(rtcp_common_header_t*)m->b_rptr;
00057         return ch;
00058 }
00059 
00060 bool_t rtcp_is_SR(const mblk_t *m){
00061         const rtcp_common_header_t *ch=rtcp_get_common_header(m);
00062         if (ch!=NULL && rtcp_common_header_get_packet_type(ch)==RTCP_SR){
00063                 if (msgdsize(m)<sizeof(rtcp_sr_t)){
00064                         ortp_warning("Too short RTCP SR packet.");
00065                         return FALSE;
00066                 }
00067                 return TRUE;
00068         }
00069         return FALSE;
00070 }
00071 
00072 /*Sender Report accessors */
00073 uint32_t rtcp_SR_get_ssrc(const mblk_t *m){
00074         rtcp_sr_t *sr=(rtcp_sr_t*)m->b_rptr;
00075         return ntohl(sr->ssrc);
00076 }
00077 
00078 const sender_info_t * rtcp_SR_get_sender_info(const mblk_t *m){
00079         rtcp_sr_t *sr=(rtcp_sr_t*)m->b_rptr;
00080         return &sr->si;
00081 }
00082 
00083 const report_block_t * rtcp_SR_get_report_block(const mblk_t *m, int idx){
00084         rtcp_sr_t *sr=(rtcp_sr_t*)m->b_rptr;
00085         report_block_t *rb=&sr->rb[idx];
00086         int size=sizeof(rtcp_common_header_t)+(4*rtcp_common_header_get_length(&sr->ch));
00087         if ( ( (uint8_t*)rb)+sizeof(report_block_t) <= m->b_rptr + size ) {
00088                 return rb;
00089         }else{
00090                 if (idx<rtcp_common_header_get_rc(&sr->ch)){
00091                         ortp_warning("RTCP packet should include a report_block_t at pos %i but has no space for it.",idx);
00092                 }
00093         }
00094         return NULL;
00095 }
00096 
00097 /*Receiver report accessors*/
00098 bool_t rtcp_is_RR(const mblk_t *m){
00099         const rtcp_common_header_t *ch=rtcp_get_common_header(m);
00100         if (ch!=NULL && rtcp_common_header_get_packet_type(ch)==RTCP_RR){
00101                 if (msgdsize(m)<sizeof(rtcp_rr_t)){
00102                         ortp_warning("Too short RTCP RR packet.");
00103                         return FALSE;
00104                 }
00105                 return TRUE;
00106         }
00107         return FALSE;
00108 }
00109 
00110 uint32_t rtcp_RR_get_ssrc(const mblk_t *m){
00111         rtcp_rr_t *rr=(rtcp_rr_t*)m->b_rptr;
00112         return ntohl(rr->ssrc);
00113 }
00114 
00115 const report_block_t * rtcp_RR_get_report_block(const mblk_t *m,int idx){
00116         rtcp_rr_t *rr=(rtcp_rr_t*)m->b_rptr;
00117         report_block_t *rb=&rr->rb[idx];
00118         int size=sizeof(rtcp_common_header_t)+(4*rtcp_common_header_get_length(&rr->ch));
00119         if ( ( (uint8_t*)rb)+sizeof(report_block_t) <= (m->b_rptr + size ) ){
00120                 return rb;
00121         }else{
00122                 if (idx<rtcp_common_header_get_rc(&rr->ch)){
00123                         ortp_warning("RTCP packet should include a report_block_t at pos %i but has no space for it.",idx);
00124                 }
00125         }
00126         return NULL;
00127 }
00128 
00129 /*SDES accessors */
00130 bool_t rtcp_is_SDES(const mblk_t *m){
00131         const rtcp_common_header_t *ch=rtcp_get_common_header(m);
00132         if (ch && rtcp_common_header_get_packet_type(ch)==RTCP_SDES){
00133                 if (msgdsize(m)<sizeof(rtcp_common_header_t)+
00134                         (4*rtcp_common_header_get_length(ch))){
00135                         ortp_warning("Too short RTCP SDES packet.");
00136                         return FALSE;
00137                 }
00138                 return TRUE;
00139         }
00140         return FALSE;
00141 }
00142 
00143 void rtcp_sdes_parse(const mblk_t *m, SdesItemFoundCallback cb, void *user_data){
00144         uint8_t *rptr=(uint8_t*)m->b_rptr+sizeof(rtcp_common_header_t);
00145         const rtcp_common_header_t *ch=(rtcp_common_header_t*)m->b_rptr;
00146         uint8_t *end=rptr+sizeof(rtcp_common_header_t)+
00147                         (4*rtcp_common_header_get_length(ch));
00148         uint32_t ssrc=0;
00149         int nchunk=0;
00150         bool_t chunk_start=TRUE;
00151 
00152         if (end>(uint8_t*)m->b_wptr) end=(uint8_t*)m->b_wptr;
00153 
00154         while(rptr<end){
00155                 if (chunk_start){
00156                         if (rptr+4<=end){
00157                                 ssrc=ntohl(*(uint32_t*)rptr);
00158                                 rptr+=4;
00159                         }else{
00160                                 ortp_warning("incorrect chunk start in RTCP SDES");
00161                                 break;
00162                         }
00163                         chunk_start=FALSE;
00164                 }else{
00165                         if (rptr+2<=end){
00166                                 uint8_t type=rptr[0];
00167                                 uint8_t len=rptr[1];
00168 
00169                                 if (type==RTCP_SDES_END){
00170                                         /* pad to next 32bit boundary*/
00171                                         rptr=(uint8_t*)(((unsigned long)rptr+4) & ~0x3);
00172                                         nchunk++;
00173                                         if (nchunk<rtcp_common_header_get_rc(ch)){
00174                                                 chunk_start=TRUE;
00175                                                 continue;
00176                                         }else break;
00177                                 }
00178                                 rptr+=2;
00179                                 if (rptr+len<=end){
00180                                         cb(user_data,ssrc,type,(char*)rptr,len);
00181                                         rptr+=len;
00182                                 }else{
00183                                         ortp_warning("bad item length in RTCP SDES");
00184                                         break;
00185                                 }
00186                         }else{
00187                                 /*end of packet */
00188                                 break;
00189                         }
00190                 }
00191         }
00192 }
00193 
00194 /*BYE accessors */
00195 bool_t rtcp_is_BYE(const mblk_t *m){
00196         const rtcp_common_header_t *ch=rtcp_get_common_header(m);
00197         if (ch && rtcp_common_header_get_packet_type(ch)==RTCP_BYE){
00198                 if (msgdsize(m)<sizeof(rtcp_common_header_t)+
00199                         rtcp_common_header_get_length(ch)){
00200                         ortp_warning("Too short RTCP BYE packet.");
00201                         return FALSE;
00202                 }
00203                 return TRUE;
00204         }
00205         return FALSE;
00206 }
00207 
00208 bool_t rtcp_BYE_get_ssrc(const mblk_t *m, int idx, uint32_t *ssrc){
00209         rtcp_bye_t *bye=(rtcp_bye_t*)m->b_rptr;
00210         int rc=rtcp_common_header_get_rc(&bye->ch);
00211         int len=rtcp_common_header_get_length(&bye->ch);
00212         if (idx<rc){
00213                 if ((uint8_t*)&bye->ssrc[idx]<=(m->b_rptr
00214                                 +sizeof(rtcp_common_header_t)+len-4)) {
00215                         *ssrc=ntohl(bye->ssrc[idx]);
00216                         return TRUE;
00217                 }else{
00218                         ortp_warning("RTCP BYE should contain %i ssrc, but there is not enough room for it.");
00219                 }
00220         }
00221         return FALSE;
00222 }
00223 
00224 bool_t rtcp_BYE_get_reason(const mblk_t *m, const char **reason, int *reason_len){
00225         rtcp_bye_t *bye=(rtcp_bye_t*)m->b_rptr;
00226         int rc=rtcp_common_header_get_rc(&bye->ch);
00227         int len=rtcp_common_header_get_length(&bye->ch);
00228         uint8_t *rptr=(uint8_t*)m->b_rptr+sizeof(rtcp_common_header_t)+rc*4;
00229         uint8_t *end=(uint8_t*)(m->b_rptr+sizeof(rtcp_common_header_t)+len);
00230         if (rptr<end){
00231                 uint8_t content_len=rptr[0];
00232                 if (rptr+1+content_len<=end){
00233                         *reason=(char*)rptr+1;
00234                         *reason_len=content_len;
00235                         return TRUE;
00236                 }else{
00237                         ortp_warning("RTCP BYE has not enough space for reason phrase.");
00238                         return FALSE;
00239                 }
00240         }
00241         return FALSE;
00242 }
00243 
00244 /*APP accessors */
00245 bool_t rtcp_is_APP(const mblk_t *m){
00246         const rtcp_common_header_t *ch=rtcp_get_common_header(m);
00247         if (ch!=NULL && rtcp_common_header_get_packet_type(ch)==RTCP_APP){
00248                 if (msgdsize(m)<sizeof(rtcp_common_header_t)+
00249                         rtcp_common_header_get_length(ch)){
00250                         ortp_warning("Too short RTCP APP packet.");
00251                         return FALSE;
00252                 }
00253                 if (sizeof(rtcp_common_header_t)+rtcp_common_header_get_length(ch)
00254                         < sizeof(rtcp_app_t)){
00255                         ortp_warning("Bad RTCP APP packet.");
00256                         return FALSE;
00257                 }
00258                 return TRUE;
00259         }
00260         return FALSE;
00261 }
00262 
00263 int rtcp_APP_get_subtype(const mblk_t *m){
00264         rtcp_app_t *app=(rtcp_app_t*)m->b_rptr;
00265         return rtcp_common_header_get_rc(&app->ch);
00266 }
00267 
00268 uint32_t rtcp_APP_get_ssrc(const mblk_t *m){
00269         rtcp_app_t *app=(rtcp_app_t*)m->b_rptr;
00270         return ntohl(app->ssrc);
00271 }
00272 /* name argument is supposed to be at least 4 characters (note: no '\0' written)*/
00273 void rtcp_APP_get_name(const mblk_t *m, char *name){
00274         rtcp_app_t *app=(rtcp_app_t*)m->b_rptr;
00275         memcpy(name,app->name,4);
00276 }
00277 /* retrieve the data. when returning, data points directly into the mblk_t */
00278 void rtcp_APP_get_data(const mblk_t *m, uint8_t **data, int *len){
00279         rtcp_app_t *app=(rtcp_app_t*)m->b_rptr;
00280         int datalen=sizeof(rtcp_common_header_t)+rtcp_common_header_get_length(&app->ch)-8;
00281         if (datalen>0){
00282                 *data=(uint8_t*)m->b_rptr+sizeof(rtcp_app_t);
00283                 *len=datalen;
00284         }else{
00285                 *len=0;
00286                 *data=NULL;
00287         }
00288 }
00289 
00290 /*old functions: deprecated, but some useful code parts can be reused */
00291 /* Start from now this source code file was written by Nicola Baldo as an extension of 
00292   the oRTP library. Copyright (C) 2005 Nicola Baldo nicola@baldo.biz*/
00293 
00294 void report_block_parse(RtpSession *session, report_block_t *rb, struct timeval rcv_time_tv)
00295 {               
00296   rb->ssrc = ntohl(rb->ssrc);
00297 
00298   if ( rb->ssrc != session->snd.ssrc )
00299 
00300     {
00301       ortp_debug("Received rtcp report block related to unknown ssrc (not from us)... discarded");
00302       return;
00303     }       
00304 
00305   else
00306 
00307     {
00308       uint32_t rcv_time_msw;       
00309       uint32_t rcv_time_lsw;
00310       uint32_t rcv_time;
00311       double rtt;
00312 
00313       rcv_time_msw = rcv_time_tv.tv_sec;
00314 #if defined(_WIN32_WCE)
00315       rcv_time_lsw = (uint32_t) ((double)rcv_time_tv.tv_usec*(double)(((uint64_t)1)<<32)*1.0e-6);
00316 #else
00317       rcv_time_lsw = (uint32_t) ((double)rcv_time_tv.tv_usec*(double)(1LL<<32)*1.0e-6);
00318 #endif
00319       rcv_time = (rcv_time_msw<<16) | (rcv_time_lsw >> 16);
00320 
00321 /*
00322       rb->cum_num_packet_lost = ntoh24(rb->cum_num_packet_lost);
00323       rb->ext_high_seq_num_rec = ntohl(rb->ext_high_seq_num_rec);
00324       rb->interarrival_jitter = ntohl(rb->interarrival_jitter);
00325       rb->lsr = ntohl(rb->lsr);
00326       rb->delay_snc_last_sr = ntohl(rb->delay_snc_last_sr);
00327 */
00328                   
00329       /* calculating Round Trip Time*/ 
00330       if (rb->lsr != 0)
00331         {
00332           rtt = (double) (rcv_time - rb->delay_snc_last_sr - rb->lsr);
00333           rtt = rtt/65536;        
00334           //printf("RTT = %f s\n",rtt);
00335         }
00336 
00337     }
00338 
00339 }
00340 
00341 void rtp_session_rtcp_parse(RtpSession *session, mblk_t *mp)
00342 {
00343   rtcp_common_header_t *rtcp;
00344   int msgsize;
00345   int rtcp_pk_size;
00346   RtpStream *rtpstream=&session->rtp;
00347   struct timeval rcv_time_tv;
00348 
00349   
00350   gettimeofday(&rcv_time_tv,NULL);
00351 
00352   return_if_fail(mp!=NULL);
00353 
00354   msgsize=(int) (mp->b_wptr-mp->b_rptr);
00355 
00356   if (msgsize < RTCP_COMMON_HEADER_SIZE)
00357     {
00358       ortp_debug("Receiving too short rtcp packet... discarded");
00359       return;
00360     }
00361 
00362   rtcp=(rtcp_common_header_t *)mp->b_rptr;
00363 
00364   /* compound rtcp packet can be composed by more than one rtcp message */
00365   while (msgsize >= RTCP_COMMON_HEADER_SIZE)
00366     {
00367 
00368       if (rtcp->version!=2)
00369         {
00370           ortp_debug("Receiving rtcp packet with version number !=2...discarded");
00371           return;
00372         }
00373 
00374       /* convert header data from network order to host order */
00375       rtcp->length = ntohs(rtcp->length);
00376 
00377       /* compute length */
00378       rtcp_pk_size = (rtcp->length + 1) * 4;
00379       /* Sanity check of simple RTCP packet length. */
00380       if (rtcp_pk_size > msgsize)
00381         {
00382           ortp_debug("Receiving rtcp packet shorter than the specified length.. discared");
00383           return;
00384         }
00385 
00386       switch (rtcp->packet_type)   
00387 
00388         {
00389 
00390         case RTCP_SR:
00391 
00392           {
00393             rtcp_sr_t *sr = (rtcp_sr_t *) rtcp;
00394             report_block_t *rb;
00395             int i;
00396 
00397             if ( ntohl(sr->ssrc) != session->rcv.ssrc )
00398               {
00399                 ortp_debug("Receiving rtcp sr packet from unknown ssrc.. discarded");           
00400                 return;
00401               }     
00402 
00403             if (msgsize < RTCP_COMMON_HEADER_SIZE + RTCP_SSRC_FIELD_SIZE + RTCP_SENDER_INFO_SIZE + (RTCP_REPORT_BLOCK_SIZE*sr->ch.rc))
00404               {
00405                 ortp_debug("Receiving too short rtcp sr packet... discarded");
00406                 return;
00407               }     
00408 
00409             /* parsing RTCP Sender Info */ 
00410             sr->si.ntp_timestamp_msw = ntohl(sr->si.ntp_timestamp_msw);
00411             sr->si.ntp_timestamp_lsw = ntohl(sr->si.ntp_timestamp_lsw);
00412             sr->si.rtp_timestamp = ntohl(sr->si.rtp_timestamp);
00413             sr->si.senders_packet_count = ntohl(sr->si.senders_packet_count);
00414             sr->si.senders_octet_count = ntohl(sr->si.senders_octet_count);         
00415 
00416             /* saving data to fill LSR and DLSR field in next RTCP report to be transmitted  */
00417             rtpstream->last_rcv_SR_ts = (sr->si.ntp_timestamp_msw << 16) | (sr->si.ntp_timestamp_lsw >> 16);  
00418             rtpstream->last_rcv_SR_time.tv_usec = rcv_time_tv.tv_usec;
00419             rtpstream->last_rcv_SR_time.tv_sec = rcv_time_tv.tv_sec;                
00420 
00421 
00422             /* parsing all RTCP report blocks */          
00423             for (i=0; i<sr->ch.rc; i++)
00424               { 
00425                 rb = &(sr->rb[i]);              
00426                 report_block_parse(session, rb, rcv_time_tv);           
00427               }
00428 
00429           }
00430           break;
00431 
00432 
00433 
00434         case RTCP_RR:
00435 
00436           {
00437             rtcp_rr_t *rr = (rtcp_rr_t *) rtcp;
00438             report_block_t *rb;
00439             int i;
00440 
00441         if (session->rcv.ssrc == 0)
00442           {
00443             /* rcv.ssrc is not set, so we adopt the incoming one */
00444             session->rcv.ssrc = ntohl(rr->ssrc);
00445           }
00446             else if ( ntohl(rr->ssrc) != session->rcv.ssrc )
00447           {
00448             ortp_debug("Receiving rtcp rr packet from unknown ssrc.. discarded");
00449             return;
00450           }
00451 
00452             if (msgsize < RTCP_COMMON_HEADER_SIZE + RTCP_SSRC_FIELD_SIZE + (RTCP_REPORT_BLOCK_SIZE*rr->ch.rc))
00453               {
00454                 ortp_debug("Receiving too short rtcp sr packet... discarded");
00455                 return;
00456               }     
00457 
00458             /* parsing all RTCP report blocks */          
00459             for (i=0; i<rr->ch.rc; i++)
00460               { 
00461                 rb = &(rr->rb[i]);              
00462                 report_block_parse(session, rb, rcv_time_tv);           
00463               }
00464   
00465           }
00466           break;
00467           
00468           
00469         case RTCP_SDES: 
00470           /* to be implemented */
00471           break;
00472                   
00473           
00474         case RTCP_BYE:
00475       {
00476         rtcp_bye_t *bye = (rtcp_bye_t *) rtcp;
00477         unsigned sclen = bye->ch.rc * 4;
00478         int reason_space_len = rtcp_pk_size
00479                                - sizeof (rtcp_common_header_t)
00480                                - sclen;
00481         int i;
00482         char *reason = NULL;
00483         bool_t rcv_ssrc_match = FALSE;
00484 
00485         if (reason_space_len < 0) {
00486             ortp_debug("Receiving too short RTCP BYE packet... discarded");
00487             return;
00488         }
00489         for (i = 0; i < bye->ch.rc; i++) {
00490             if (ntohl(bye->ssrc[i]) == session->rcv.ssrc) {
00491                 rcv_ssrc_match = TRUE;
00492                 break;
00493             }
00494         }
00495         if (rcv_ssrc_match) {
00496             if (session->on_rtcp_bye.count > 0) {
00497                 /* Get reason. */
00498                 if (reason_space_len > 1) {
00499                     uint8_t *reasonbuf = (uint8_t *) rtcp
00500                                         + sizeof (rtcp_common_header_t)
00501                                         + sclen;
00502                     if (reasonbuf[0] <= reason_space_len-1)
00503                         reason = ortp_strndup((char *)(reasonbuf+1), reasonbuf[0]);
00504                     else
00505                         ortp_debug("Incorrect RTCP BYE reason length");
00506                 }
00507                 rtp_signal_table_emit2(&session->on_rtcp_bye,
00508                     (long)reason);
00509                 if (reason)
00510                     ortp_free(reason);
00511             } else {
00512                 ortp_debug("Got RTCP BYE without RTCP BYE handler");
00513             }
00514         } else {
00515             ortp_debug("No SSRC in the BYE packet matched our rcv.ssrc.");
00516         }
00517             break;
00518       }
00519 
00520         case RTCP_APP:
00521           /* to be implemented */
00522           break;
00523 
00524           
00525         default:
00526 
00527           ortp_debug("Receiving unknown rtcp packet type... discarded");
00528           return;
00529 
00530         }
00531 
00532       
00533       msgsize -= rtcp_pk_size;              /* size of unparsed portion of UDP packet, in octets */
00534       rtcp = (rtcp_common_header_t *) (rtcp_pk_size + (char *) rtcp);  /* pointer to next RTCP packet in current UDP packet */
00535 
00536     }
00537 
00538     /* The function did not failed sanity checks, write down the RTPC/RTCP
00539        reception time. */
00540     session->last_recv_time = rcv_time_tv;
00541 }

Generated on Mon Apr 23 10:09:13 2007 for oRTP by  doxygen 1.5.2