blob: 1ab27f91dfff983fc8d0bd9d8869b3f8520fc009 [file] [log] [blame]
Emeric Vigier2f625822012-08-06 11:09:52 -04001// Copyright (C) 1999-2005 Open Source Telecom Corporation.
2// Copyright (C) 2006-2010 David Sugar, Tycho Softworks.
3//
4// This program is free software; you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation; either version 2 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17//
18// As a special exception, you may use this file as part of a free software
19// library without restriction. Specifically, if other files instantiate
20// templates or use macros or inline functions from this file, or you compile
21// this file and link it with other files to produce an executable, this
22// file does not by itself cause the resulting executable to be covered by
23// the GNU General Public License. This exception does not however
24// invalidate any other reasons why the executable file might be covered by
25// the GNU General Public License.
26//
27// This exception applies only to the code released under the name GNU
28// ccRTP. If you copy code from other releases into a copy of GNU
29// ccRTP, as the General Public License permits, the exception does
30// not apply to the code that you add in this way. To avoid misleading
31// anyone as to the status of such modified files, you must delete
32// this exception notice from them.
33//
34// If you write modifications of your own for GNU ccRTP, it is your choice
35// whether to permit this exception to apply to your modifications.
36// If you do not wish that, delete this exception notice.
37//
38
39/**
40 * @file rtppkt.cpp
41 * @short StaticPayloadFormat, DynamicPayloadFormat, RTPPacket,
42 * OutgoingRTPPkt and IncomingRTPPkt classes implementation.
43 **/
44
45#include "private.h"
46#include <ccrtp/rtppkt.h>
47#include <ccrtp/CryptoContext.h>
48
49#ifdef CCXX_NAMESPACES
50namespace ost {
51#endif
52
53// Default to 8Khz when no value is specified.
54const uint32 PayloadFormat::defaultRTPClockRate = 8000;
55
56//uint32 PayloadFormat::staticRates[lastStaticPayloadType]
57uint32 StaticPayloadFormat::staticAudioTypesRates[] = {
58 // audio types:
59 8000, // 0 - sptPCMU
60 0, // 1 - reserved
61 8000, // 2 - sptG726_32
62 8000, // 3 - sptGSM
63 8000, // 4 - sptG723
64 8000, // 5 - sptDVI4_8000
65 16000, // 6 - sptDVI4_16000
66 8000, // 7 - sptLPC
67 8000, // 8 - sptPCMA
68 8000, // 9 - sptG722
69 44100, // 10 - sptL16_DUAL
70 44100, // 11 - sptL16_MONO
71 8000, // 12 - sptQCELP
72 0, // 13 - reserved
73 90000, // 14 - sptMPA
74 8000, // 15 - sptG728
75 11015, // 16 - sptDVI4_11025
76 22050, // 17 - sptDVI4_22050
77 8000 // 18 - sptG729
78/* 0, // reserved
79 0, // unassigned
80 0, // unassigned
81 0, // unassigned
82 0 // unassigned
83*/
84 // All video types have 90000 hz RTP clock rate.
85 // If sometime in the future a static video payload type is
86 // defined with a different RTP clock rate (quite
87 // unprobable). This table and/or the StaticPayloadType
88 // constructor must be changed.
89};
90
91StaticPayloadFormat::StaticPayloadFormat(StaticPayloadType type)
92{
93 setPayloadType( (type <= lastStaticPayloadType)? type : 0);
94 if ( type <= sptG729 ) {
95 // audio static type
96 setRTPClockRate(staticAudioTypesRates[type]);
97 } else {
98 // video static type
99 setRTPClockRate(90000);
100 }
101}
102
103DynamicPayloadFormat::DynamicPayloadFormat(PayloadType type, uint32 rate)
104{
105 PayloadFormat::setPayloadType(type);
106 setRTPClockRate(rate);
107}
108
109// constructor commonly used for incoming packets
110RTPPacket::RTPPacket(const unsigned char* const block, size_t len, bool duplicate) :
111total((uint32)len), duplicated(duplicate)
112{
113 const RTPFixedHeader* const header =
114 reinterpret_cast<const RTPFixedHeader*>(block);
115 hdrSize = sizeof(RTPFixedHeader) + (header->cc << 2);
116 if ( header->extension ){
117 RTPHeaderExt *ext = (RTPHeaderExt *)(block + hdrSize);
118 hdrSize += sizeof(uint32) + (ntohs(ext->length) * 4);
119 }
120 if ( header->padding )
121 len -= block[len - 1];
122 payloadSize = (uint32)(len - hdrSize);
123
124 if ( duplicate ) {
125 buffer = new unsigned char[len];
126 setbuffer(block,len,0);
127 } else {
128 buffer = const_cast<unsigned char*>(block);
129 }
130}
131
132// constructor commonly used for outgoing packets
133RTPPacket::RTPPacket(size_t hdrlen, size_t plen, uint8 paddinglen, CryptoContext* pcc ) :
134payloadSize((uint32)plen), buffer(NULL), hdrSize((uint32)hdrlen),
135duplicated(false)
136{
137 total = (uint32)(hdrlen + payloadSize);
138 // compute if there must be padding
139 uint8 padding = 0;
140 if ( 0 != paddinglen ) {
141 padding = paddinglen - (total % paddinglen);
142 total += padding;
143 }
144 srtpLength = 0;
145 srtpDataOffset = 0;
146 if (pcc != NULL) {
147 // compute additional memory for SRTP data
148 srtpLength = pcc->getTagLength() + pcc->getMkiLength();
149 srtpDataOffset = total; // SRTP data go behind header plus payload plus padding
150 }
151
152 // now we know the actual total length of the packet, get some memory
153 // but take SRTP data into account. Don't change total because some RTP
154 // functions rely on the fact that total is the overall size (without
155 // the SRTP data)
156 buffer = new unsigned char[total + srtpLength];
157 *(reinterpret_cast<uint32*>(getHeader())) = 0;
158 getHeader()->version = CCRTP_VERSION;
159 if ( 0 != padding ) {
160 memset(buffer + total - padding,0,padding - 1);
161 buffer[total - 1] = padding;
162 getHeader()->padding = 1;
163 } else {
164 getHeader()->padding = 0;
165 }
166}
167
168void RTPPacket::endPacket()
169{
170#ifdef CCXX_EXCEPTIONS
171 try {
172#endif
173 delete [] buffer;
174#ifdef CCXX_EXCEPTIONS
175 } catch (...) { };
176#endif
177}
178
179void RTPPacket::reComputePayLength(bool padding)
180{
181 // If payloadsize was computed without padding set then re-compute
182 // payloadSize after the padding bit was set and set padding flag
183 // in RTP header - option for SRTP
184 if (padding) {
185 size_t len = 0;
186 getHeader()->padding = 1;
187 len -= buffer[payloadSize - 1];
188 payloadSize = (uint32)(payloadSize - len);
189 }
190}
191
192OutgoingRTPPkt::OutgoingRTPPkt(const uint32* const csrcs, uint16 numcsrc,
193const unsigned char* const hdrext, uint32 hdrextlen,
194const unsigned char* const data, size_t datalen,
195uint8 paddinglen, CryptoContext* pcc) :
196RTPPacket((getSizeOfFixedHeader() + sizeof(uint32) * numcsrc + hdrextlen),datalen,paddinglen, pcc)
197{
198 uint32 pointer = (uint32)getSizeOfFixedHeader();
199 // add CSCR identifiers (putting them in network order).
200 setCSRCArray(csrcs,numcsrc);
201 pointer += numcsrc * sizeof(uint32);
202
203 // add header extension.
204 setbuffer(hdrext,hdrextlen,pointer);
205 setExtension(hdrextlen > 0);
206 pointer += hdrextlen;
207
208 // add data.
209 setbuffer(data,datalen,pointer);
210}
211
212OutgoingRTPPkt::OutgoingRTPPkt(const uint32* const csrcs, uint16 numcsrc,
213const unsigned char* data, size_t datalen, uint8 paddinglen, CryptoContext* pcc) :
214RTPPacket((getSizeOfFixedHeader() + sizeof(uint32) *numcsrc),datalen, paddinglen, pcc)
215{
216 uint32 pointer = (uint32)getSizeOfFixedHeader();
217 // add CSCR identifiers (putting them in network order).
218 setCSRCArray(csrcs,numcsrc);
219 pointer += numcsrc * sizeof(uint32);
220
221 // not needed, as the RTPPacket constructor sets by default
222 // the whole fixed header to 0.
223 // getHeader()->extension = 0;
224
225 // add data.
226 setbuffer(data,datalen,pointer);
227}
228
229OutgoingRTPPkt::OutgoingRTPPkt(const unsigned char* data, size_t datalen,
230uint8 paddinglen, CryptoContext* pcc) :
231RTPPacket(getSizeOfFixedHeader(),datalen,paddinglen, pcc)
232{
233 // not needed, as the RTPPacket constructor sets by default
234 // the whole fixed header to 0.
235 //getHeader()->cc = 0;
236 //getHeader()->extension = 0;
237
238 setbuffer(data,datalen,getSizeOfFixedHeader());
239}
240
241void OutgoingRTPPkt::setCSRCArray(const uint32* const csrcs, uint16 numcsrc)
242{
243 setbuffer(csrcs, numcsrc * sizeof(uint32),getSizeOfFixedHeader());
244 uint32* csrc = const_cast<uint32*>(getCSRCs());
245 for ( int i = 0; i < numcsrc; i++ )
246 csrc[i] = htonl(csrc[i]);
247 getHeader()->cc = numcsrc;
248}
249
250void OutgoingRTPPkt::protect(uint32 ssrc, CryptoContext* pcc)
251{
252 /* Encrypt the packet */
253 uint64 index = ((uint64)pcc->getRoc() << 16) | (uint64)getSeqNum();
254
255 pcc->srtpEncrypt(this, index, ssrc);
256
257 // NO MKI support yet - here we assume MKI is zero. To build in MKI
258 // take MKI length into account when storing the authentication tag.
259
260 /* Compute MAC */
261 pcc->srtpAuthenticate(this, pcc->getRoc(),
262 const_cast<uint8*>(getRawPacket()+srtpDataOffset) );
263 /* Update the ROC if necessary */
264 if (getSeqNum() == 0xFFFF ) {
265 pcc->setRoc(pcc->getRoc() + 1);
266 }
267}
268
269// These masks are valid regardless of endianness.
270const uint16 IncomingRTPPkt::RTP_INVALID_PT_MASK = (0x7e);
271const uint16 IncomingRTPPkt::RTP_INVALID_PT_VALUE = (0x48);
272
273IncomingRTPPkt::IncomingRTPPkt(const unsigned char* const block, size_t len) :
274RTPPacket(block,len)
275{
276 // first, perform validity check:
277 // 1) check protocol version
278 // 2) it is not an SR nor an RR
279 // 3) consistent length field value (taking CC value and P and
280 // X bits into account)
281 if ( getProtocolVersion() != CCRTP_VERSION || (getPayloadType() & RTP_INVALID_PT_MASK) == RTP_INVALID_PT_VALUE) {
282 /*
283 ||
284 getPayloadSize() <= 0 ) {
285 */
286 headerValid = false;
287 return;
288 }
289 headerValid = true;
290 cachedTimestamp = getRawTimestamp();
291 cachedSeqNum = ntohs(getHeader()->sequence);
292 cachedSSRC = ntohl(getHeader()->sources[0]);
293}
294
295int32 IncomingRTPPkt::unprotect(CryptoContext* pcc)
296{
297 if (pcc == NULL) {
298 return true;
299 }
300
301 /*
302 * This is the setting of the packet data when we come to this
303 * point:
304 *
305 * total: complete length of received data
306 * buffer: points to data as received from network
307 * hdrSize: length of header including header extension
308 * payloadSize: length of data excluding hdrSize and padding
309 *
310 * Because this is an SRTP packet we need to adjust some values here.
311 * The SRTP MKI and authentication data is always at the end of a
312 * packet. Thus compute the position of this data.
313 */
314
315 uint32 srtpDataIndex = total - (pcc->getTagLength() + pcc->getMkiLength());
316
317 // now adjust total because some RTP functions rely on the fact that
318 // total is the full length of data without SRTP data.
319 total -= pcc->getTagLength() + pcc->getMkiLength();
320
321 // recompute payloadSize by subtracting SRTP data
322 payloadSize -= pcc->getTagLength() + pcc->getMkiLength();
323
324 // unused??
325 // const uint8* mki = getRawPacket() + srtpDataIndex;
326 const uint8* tag = getRawPacket() + srtpDataIndex + pcc->getMkiLength();
327
328 /* Replay control */
329 if (!pcc->checkReplay(cachedSeqNum)) {
330 return -2;
331 }
332 /* Guess the index */
333 uint64 guessedIndex = pcc->guessIndex(cachedSeqNum);
334
335 uint32 guessedRoc = guessedIndex >> 16;
336 uint8* mac = new uint8[pcc->getTagLength()];
337
338 pcc->srtpAuthenticate(this, guessedRoc, mac);
339 if (memcmp(tag, mac, pcc->getTagLength()) != 0) {
340 delete[] mac;
341 return -1;
342 }
343 delete[] mac;
344
345 /* Decrypt the content */
346 pcc->srtpEncrypt( this, guessedIndex, cachedSSRC );
347
348 /* Update the Crypto-context */
349 pcc->update(cachedSeqNum);
350
351 return 1;
352}
353
354#ifdef CCXX_NAMESPACES
355}
356#endif
357
358/** EMACS **
359 * Local variables:
360 * mode: c++
361 * c-basic-offset: 4
362 * End:
363 */