Main Page | Modules | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages | Examples

rtppkt.cpp

Go to the documentation of this file.
00001 // Copyright (C) 1999-2007 Open Source Telecom Corporation.
00002 //
00003 // This program is free software; you can redistribute it and/or modify
00004 // it under the terms of the GNU General Public License as published by
00005 // the Free Software Foundation; either version 2 of the License, or
00006 // (at your option) any later version.
00007 //
00008 // This program is distributed in the hope that it will be useful,
00009 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011 // GNU General Public License for more details.
00012 //
00013 // You should have received a copy of the GNU General Public License
00014 // along with this program; if not, write to the Free Software
00015 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00016 //
00017 // As a special exception, you may use this file as part of a free software
00018 // library without restriction.  Specifically, if other files instantiate
00019 // templates or use macros or inline functions from this file, or you compile
00020 // this file and link it with other files to produce an executable, this
00021 // file does not by itself cause the resulting executable to be covered by
00022 // the GNU General Public License.  This exception does not however
00023 // invalidate any other reasons why the executable file might be covered by
00024 // the GNU General Public License.
00025 //
00026 // This exception applies only to the code released under the name GNU
00027 // ccRTP.  If you copy code from other releases into a copy of GNU
00028 // ccRTP, as the General Public License permits, the exception does
00029 // not apply to the code that you add in this way.  To avoid misleading
00030 // anyone as to the status of such modified files, you must delete
00031 // this exception notice from them.
00032 //
00033 // If you write modifications of your own for GNU ccRTP, it is your choice
00034 // whether to permit this exception to apply to your modifications.
00035 // If you do not wish that, delete this exception notice.
00036 //
00037 
00044 #include "private.h"
00045 #include <ccrtp/rtppkt.h>
00046 #include <ccrtp/CryptoContext.h>
00047 
00048 #ifdef  CCXX_NAMESPACES
00049 namespace ost {
00050 #endif
00051 
00052 // Default to 8Khz when no value is specified.
00053 const uint32 PayloadFormat::defaultRTPClockRate = 8000;
00054 
00055 //uint32 PayloadFormat::staticRates[lastStaticPayloadType]
00056 uint32 StaticPayloadFormat::staticAudioTypesRates[] = {
00057         // audio types:
00058         8000,    //  0 - sptPCMU
00059         0,       //  1 - reserved
00060         8000,    //  2 - sptG726_32
00061         8000,    //  3 - sptGSM
00062         8000,    //  4 - sptG723
00063         8000,    //  5 - sptDVI4_8000
00064         16000,   //  6 - sptDVI4_16000
00065         8000,    //  7 - sptLPC
00066         8000,    //  8 - sptPCMA
00067         8000,    //  9 - sptG722
00068         44100,   // 10 - sptL16_DUAL
00069         44100,   // 11 - sptL16_MONO
00070         8000,    // 12 - sptQCELP
00071         0,       // 13 - reserved
00072         90000,   // 14 - sptMPA
00073         8000,    // 15 - sptG728
00074         11015,   // 16 - sptDVI4_11025
00075         22050,   // 17 - sptDVI4_22050
00076         8000     // 18 - sptG729
00077 /*      0,       // reserved
00078         0,       // unassigned
00079         0,       // unassigned
00080         0,       // unassigned
00081         0        // unassigned
00082 */
00083         // All video types have 90000 hz RTP clock rate.
00084         // If sometime in the future a static video payload type is
00085         // defined with a different RTP clock rate (quite
00086         // unprobable). This table and/or the StaticPayloadType
00087         // constructor must be changed.
00088 };
00089 
00090 StaticPayloadFormat::StaticPayloadFormat(StaticPayloadType type)
00091 {
00092         setPayloadType( (type <= lastStaticPayloadType)? type : 0);
00093         if ( type <= sptG729 ) {
00094                 // audio static type
00095                 setRTPClockRate(staticAudioTypesRates[type]);
00096         } else {
00097                 // video static type
00098                 setRTPClockRate(90000);
00099         }
00100 }
00101 
00102 DynamicPayloadFormat::DynamicPayloadFormat(PayloadType type, uint32 rate)
00103 {
00104         PayloadFormat::setPayloadType(type);
00105         setRTPClockRate(rate);
00106 }
00107 
00108 // constructor commonly used for incoming packets
00109 RTPPacket::RTPPacket(const unsigned char* const block, size_t len,
00110                      bool duplicate):
00111         total((uint32)len),
00112         duplicated(duplicate)
00113 {
00114 
00115         const RTPFixedHeader* const header =
00116                 reinterpret_cast<const RTPFixedHeader*>(block);
00117         hdrSize = sizeof(RTPFixedHeader) + (header->cc << 2);
00118         if ( header->extension ){
00119                 RTPHeaderExt *ext = (RTPHeaderExt *)(block + hdrSize);
00120                 hdrSize += sizeof(uint32) + (ntohs(ext->length) * 4);
00121         }
00122         if ( header->padding )
00123                 len -= block[len - 1];
00124         payloadSize = (uint32)(len - hdrSize);
00125 
00126         if ( duplicate ) {
00127                 buffer = new unsigned char[len];
00128                 setbuffer(block,len,0);
00129         } else {
00130                 buffer = const_cast<unsigned char*>(block);
00131         }
00132 }
00133 
00134 // constructor commonly used for outgoing packets
00135 RTPPacket::RTPPacket(size_t hdrlen, size_t plen, uint8 paddinglen, CryptoContext* pcc ) :
00136         payloadSize((uint32)plen),
00137         buffer(NULL),
00138         hdrSize((uint32)hdrlen),
00139         duplicated(false)
00140 {
00141         total = (uint32)(hdrlen + payloadSize);
00142         // compute if there must be padding
00143         uint8 padding = 0;
00144         if ( 0 != paddinglen ) {
00145                 padding = paddinglen - (total % paddinglen);
00146                 total += padding;
00147         }
00148         srtpLength = 0;
00149         srtpDataOffset = 0;
00150         if (pcc != NULL) {
00151                 // compute additional memory for SRTP data
00152                 srtpLength = pcc->getTagLength() + pcc->getMkiLength();
00153                 srtpDataOffset = total; // SRTP data go behind header plus payload plus padding
00154         }
00155 
00156         // now we know the actual total length of the packet, get  some memory
00157         // but take SRTP data into account. Don't change total because some RTP
00158         // functions rely on the fact that total is the overall size (without
00159         // the SRTP data)
00160         buffer = new unsigned char[total + srtpLength];
00161         *(reinterpret_cast<uint32*>(getHeader())) = 0;
00162         getHeader()->version = CCRTP_VERSION;
00163         if ( 0 != padding ) {
00164                 memset(buffer + total - padding,0,padding - 1);
00165                 buffer[total - 1] = padding;
00166                 getHeader()->padding = 1;
00167         } else {
00168                 getHeader()->padding = 0;
00169         }
00170 }
00171 
00172 void
00173 RTPPacket::endPacket()
00174 {
00175 #ifdef  CCXX_EXCEPTIONS
00176         try {
00177 #endif
00178                 delete [] buffer;
00179 #ifdef  CCXX_EXCEPTIONS
00180         } catch (...) { };
00181 #endif
00182 }
00183 
00184 OutgoingRTPPkt::OutgoingRTPPkt(
00185         const uint32* const csrcs, uint16 numcsrc,
00186         const unsigned char* const hdrext, uint32 hdrextlen,
00187         const unsigned char* const data, size_t datalen,
00188         uint8 paddinglen, CryptoContext* pcc) :
00189         RTPPacket((getSizeOfFixedHeader() + sizeof(uint32) * numcsrc
00190                   + hdrextlen),datalen,paddinglen, pcc)
00191 {
00192         uint32 pointer = (uint32)getSizeOfFixedHeader();
00193         // add CSCR identifiers (putting them in network order).
00194         setCSRCArray(csrcs,numcsrc);
00195         pointer += numcsrc * sizeof(uint32);
00196 
00197         // add header extension.
00198         setbuffer(hdrext,hdrextlen,pointer);
00199         setExtension(hdrextlen > 0);
00200         pointer += hdrextlen;
00201 
00202         // add data.
00203         setbuffer(data,datalen,pointer);
00204 }
00205 
00206 OutgoingRTPPkt::OutgoingRTPPkt(
00207         const uint32* const csrcs, uint16 numcsrc,
00208         const unsigned char* data, size_t datalen,
00209         uint8 paddinglen, CryptoContext* pcc) :
00210         RTPPacket((getSizeOfFixedHeader() + sizeof(uint32) *numcsrc),datalen,
00211                   paddinglen, pcc)
00212 {
00213         uint32 pointer = (uint32)getSizeOfFixedHeader();
00214         // add CSCR identifiers (putting them in network order).
00215         setCSRCArray(csrcs,numcsrc);
00216         pointer += numcsrc * sizeof(uint32);
00217 
00218         // not needed, as the RTPPacket constructor sets by default
00219         // the whole fixed header to 0.
00220         // getHeader()->extension = 0;
00221 
00222         // add data.
00223         setbuffer(data,datalen,pointer);
00224 }
00225 
00226 OutgoingRTPPkt::OutgoingRTPPkt(const unsigned char* data, size_t datalen,
00227                                uint8 paddinglen, CryptoContext* pcc) :
00228         RTPPacket(getSizeOfFixedHeader(),datalen,paddinglen, pcc)
00229 {
00230         // not needed, as the RTPPacket constructor sets by default
00231         // the whole fixed header to 0.
00232         //getHeader()->cc = 0;
00233         //getHeader()->extension = 0;
00234 
00235         setbuffer(data,datalen,getSizeOfFixedHeader());
00236 }
00237 
00238 void
00239 OutgoingRTPPkt::setCSRCArray(const uint32* const csrcs, uint16 numcsrc)
00240 {
00241         setbuffer(csrcs, numcsrc * sizeof(uint32),getSizeOfFixedHeader());
00242         uint32* csrc = const_cast<uint32*>(getCSRCs());
00243         for ( int i = 0; i < numcsrc; i++ )
00244                 csrc[i] = htonl(csrc[i]);
00245         getHeader()->cc = numcsrc;
00246 }
00247 
00248 void
00249 OutgoingRTPPkt::protect(uint32 ssrc, CryptoContext* pcc)
00250 {
00251         /* Encrypt the packet */
00252         uint64 index = ((uint64)pcc->getRoc() << 16) | (uint64)getSeqNum();
00253 
00254         pcc->srtpEncrypt(this, index, ssrc);
00255 
00256         // NO MKI support yet - here we assume MKI is zero. To build in MKI
00257         // take MKI length into account when storing the authentication tag.
00258 
00259         /* Compute MAC */
00260         pcc->srtpAuthenticate(this, pcc->getRoc(),
00261                                    const_cast<uint8*>(getRawPacket()+srtpDataOffset) );
00262         /* Update the ROC if necessary */
00263         if (getSeqNum() == 0xFFFF ) {
00264                 pcc->setRoc(pcc->getRoc() + 1);
00265         }
00266 }
00267 
00268 // These masks are valid regardless of endianness.
00269 const uint16 IncomingRTPPkt::RTP_INVALID_PT_MASK = (0x7e);
00270 const uint16 IncomingRTPPkt::RTP_INVALID_PT_VALUE = (0x48);
00271 
00272 IncomingRTPPkt::IncomingRTPPkt(const unsigned char* const block, size_t len) :
00273         RTPPacket(block,len)
00274 {
00275         // first, perform validity check:
00276         // 1) check protocol version
00277         // 2) it is not an SR nor an RR
00278         // 3) consistent length field value (taking CC value and P and
00279         //    X bits into account)
00280         if ( getProtocolVersion() != CCRTP_VERSION
00281              ||
00282              (getPayloadType() & RTP_INVALID_PT_MASK) == RTP_INVALID_PT_VALUE) {
00283             /*
00284              ||
00285              getPayloadSize() <= 0 ) {
00286             */
00287                 headerValid = false;
00288                 return;
00289         }
00290         headerValid = true;
00291         cachedTimestamp = getRawTimestamp();
00292         cachedSeqNum = ntohs(getHeader()->sequence);
00293         cachedSSRC = ntohl(getHeader()->sources[0]);
00294 }
00295 
00296 int32
00297 IncomingRTPPkt::unprotect(CryptoContext* pcc)
00298 {
00299         if (pcc == NULL) {
00300                 return true;
00301         }
00302 
00303         /*
00304          * This is the setting of the packet data when we come to this
00305          * point:
00306          *
00307          * total:       complete length of received data
00308          * buffer:      points to data as received from network
00309          * hdrSize:     length of header including header extension
00310          * payloadSize: length of data excluding hdrSize and padding
00311          *
00312          * Because this is an SRTP packet we need to adjust some values here.
00313          * The SRTP MKI and authentication data is always at the end of a
00314          * packet. Thus compute the position of this data.
00315          */
00316 
00317         uint32 srtpDataIndex = total - (pcc->getTagLength() + pcc->getMkiLength());
00318 
00319         // now adjust total because some RTP functions rely on the fact that
00320         // total is the full length of data without SRTP data.
00321         total -= pcc->getTagLength() + pcc->getMkiLength();
00322 
00323         // recompute payloadSize by subtracting SRTP data
00324         payloadSize -= pcc->getTagLength() + pcc->getMkiLength();
00325 
00326         // unused??
00327         // const uint8* mki = getRawPacket() + srtpDataIndex;
00328         const uint8* tag = getRawPacket() + srtpDataIndex + pcc->getMkiLength();
00329 
00330         /* Replay control */
00331         if (!pcc->checkReplay(cachedSeqNum)) {
00332                 return -2;
00333         }
00334         /* Guess the index */
00335         uint64 guessedIndex = pcc->guessIndex(cachedSeqNum);
00336 
00337         uint32 guessedRoc = guessedIndex >> 16;
00338         uint8* mac = new uint8[pcc->getTagLength()];
00339 
00340         pcc->srtpAuthenticate(this, guessedRoc, mac);
00341         if (memcmp(tag, mac, pcc->getTagLength()) != 0) {
00342             delete[] mac;
00343             return -1;
00344         }
00345         delete[] mac;
00346 
00347         /* Decrypt the content */
00348         pcc->srtpEncrypt( this, guessedIndex, cachedSSRC );
00349 
00350         /* Update the Crypto-context */
00351         pcc->update(cachedSeqNum);
00352 
00353         return 1;
00354 }
00355 
00356 #ifdef  CCXX_NAMESPACES
00357 }
00358 #endif
00359 

© sourcejam.com 2005-2008