blob: 3d29100369a4ae782d92e7f290a2a8b158fb7e59 [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
Alexandre Lisionddd731e2014-01-31 11:50:08 -050049NAMESPACE_COMMONCPP
Emeric Vigier2f625822012-08-06 11:09:52 -040050
51// Default to 8Khz when no value is specified.
52const uint32 PayloadFormat::defaultRTPClockRate = 8000;
53
54//uint32 PayloadFormat::staticRates[lastStaticPayloadType]
55uint32 StaticPayloadFormat::staticAudioTypesRates[] = {
56 // audio types:
57 8000, // 0 - sptPCMU
58 0, // 1 - reserved
59 8000, // 2 - sptG726_32
60 8000, // 3 - sptGSM
61 8000, // 4 - sptG723
62 8000, // 5 - sptDVI4_8000
63 16000, // 6 - sptDVI4_16000
64 8000, // 7 - sptLPC
65 8000, // 8 - sptPCMA
66 8000, // 9 - sptG722
67 44100, // 10 - sptL16_DUAL
68 44100, // 11 - sptL16_MONO
69 8000, // 12 - sptQCELP
70 0, // 13 - reserved
71 90000, // 14 - sptMPA
72 8000, // 15 - sptG728
73 11015, // 16 - sptDVI4_11025
74 22050, // 17 - sptDVI4_22050
75 8000 // 18 - sptG729
76/* 0, // reserved
77 0, // unassigned
78 0, // unassigned
79 0, // unassigned
80 0 // unassigned
81*/
82 // All video types have 90000 hz RTP clock rate.
83 // If sometime in the future a static video payload type is
84 // defined with a different RTP clock rate (quite
85 // unprobable). This table and/or the StaticPayloadType
86 // constructor must be changed.
87};
88
89StaticPayloadFormat::StaticPayloadFormat(StaticPayloadType type)
90{
91 setPayloadType( (type <= lastStaticPayloadType)? type : 0);
92 if ( type <= sptG729 ) {
93 // audio static type
94 setRTPClockRate(staticAudioTypesRates[type]);
95 } else {
96 // video static type
97 setRTPClockRate(90000);
98 }
99}
100
101DynamicPayloadFormat::DynamicPayloadFormat(PayloadType type, uint32 rate)
102{
103 PayloadFormat::setPayloadType(type);
104 setRTPClockRate(rate);
105}
106
107// constructor commonly used for incoming packets
108RTPPacket::RTPPacket(const unsigned char* const block, size_t len, bool duplicate) :
109total((uint32)len), duplicated(duplicate)
110{
111 const RTPFixedHeader* const header =
112 reinterpret_cast<const RTPFixedHeader*>(block);
113 hdrSize = sizeof(RTPFixedHeader) + (header->cc << 2);
114 if ( header->extension ){
115 RTPHeaderExt *ext = (RTPHeaderExt *)(block + hdrSize);
116 hdrSize += sizeof(uint32) + (ntohs(ext->length) * 4);
117 }
118 if ( header->padding )
119 len -= block[len - 1];
120 payloadSize = (uint32)(len - hdrSize);
121
122 if ( duplicate ) {
123 buffer = new unsigned char[len];
124 setbuffer(block,len,0);
125 } else {
126 buffer = const_cast<unsigned char*>(block);
127 }
128}
129
130// constructor commonly used for outgoing packets
131RTPPacket::RTPPacket(size_t hdrlen, size_t plen, uint8 paddinglen, CryptoContext* pcc ) :
132payloadSize((uint32)plen), buffer(NULL), hdrSize((uint32)hdrlen),
133duplicated(false)
134{
135 total = (uint32)(hdrlen + payloadSize);
136 // compute if there must be padding
137 uint8 padding = 0;
138 if ( 0 != paddinglen ) {
139 padding = paddinglen - (total % paddinglen);
140 total += padding;
141 }
142 srtpLength = 0;
143 srtpDataOffset = 0;
144 if (pcc != NULL) {
145 // compute additional memory for SRTP data
146 srtpLength = pcc->getTagLength() + pcc->getMkiLength();
147 srtpDataOffset = total; // SRTP data go behind header plus payload plus padding
148 }
149
150 // now we know the actual total length of the packet, get some memory
151 // but take SRTP data into account. Don't change total because some RTP
152 // functions rely on the fact that total is the overall size (without
153 // the SRTP data)
154 buffer = new unsigned char[total + srtpLength];
155 *(reinterpret_cast<uint32*>(getHeader())) = 0;
156 getHeader()->version = CCRTP_VERSION;
157 if ( 0 != padding ) {
158 memset(buffer + total - padding,0,padding - 1);
159 buffer[total - 1] = padding;
160 getHeader()->padding = 1;
161 } else {
162 getHeader()->padding = 0;
163 }
164}
165
166void RTPPacket::endPacket()
167{
168#ifdef CCXX_EXCEPTIONS
169 try {
170#endif
171 delete [] buffer;
172#ifdef CCXX_EXCEPTIONS
173 } catch (...) { };
174#endif
175}
176
177void RTPPacket::reComputePayLength(bool padding)
178{
179 // If payloadsize was computed without padding set then re-compute
180 // payloadSize after the padding bit was set and set padding flag
181 // in RTP header - option for SRTP
182 if (padding) {
183 size_t len = 0;
184 getHeader()->padding = 1;
185 len -= buffer[payloadSize - 1];
186 payloadSize = (uint32)(payloadSize - len);
187 }
188}
189
190OutgoingRTPPkt::OutgoingRTPPkt(const uint32* const csrcs, uint16 numcsrc,
191const unsigned char* const hdrext, uint32 hdrextlen,
192const unsigned char* const data, size_t datalen,
193uint8 paddinglen, CryptoContext* pcc) :
194RTPPacket((getSizeOfFixedHeader() + sizeof(uint32) * numcsrc + hdrextlen),datalen,paddinglen, pcc)
195{
196 uint32 pointer = (uint32)getSizeOfFixedHeader();
197 // add CSCR identifiers (putting them in network order).
198 setCSRCArray(csrcs,numcsrc);
199 pointer += numcsrc * sizeof(uint32);
200
201 // add header extension.
202 setbuffer(hdrext,hdrextlen,pointer);
203 setExtension(hdrextlen > 0);
204 pointer += hdrextlen;
205
206 // add data.
207 setbuffer(data,datalen,pointer);
208}
209
210OutgoingRTPPkt::OutgoingRTPPkt(const uint32* const csrcs, uint16 numcsrc,
211const unsigned char* data, size_t datalen, uint8 paddinglen, CryptoContext* pcc) :
212RTPPacket((getSizeOfFixedHeader() + sizeof(uint32) *numcsrc),datalen, paddinglen, pcc)
213{
214 uint32 pointer = (uint32)getSizeOfFixedHeader();
215 // add CSCR identifiers (putting them in network order).
216 setCSRCArray(csrcs,numcsrc);
217 pointer += numcsrc * sizeof(uint32);
218
219 // not needed, as the RTPPacket constructor sets by default
220 // the whole fixed header to 0.
221 // getHeader()->extension = 0;
222
223 // add data.
224 setbuffer(data,datalen,pointer);
225}
226
227OutgoingRTPPkt::OutgoingRTPPkt(const unsigned char* data, size_t datalen,
228uint8 paddinglen, CryptoContext* pcc) :
229RTPPacket(getSizeOfFixedHeader(),datalen,paddinglen, pcc)
230{
231 // not needed, as the RTPPacket constructor sets by default
232 // the whole fixed header to 0.
233 //getHeader()->cc = 0;
234 //getHeader()->extension = 0;
235
236 setbuffer(data,datalen,getSizeOfFixedHeader());
237}
238
239void OutgoingRTPPkt::setCSRCArray(const uint32* const csrcs, uint16 numcsrc)
240{
241 setbuffer(csrcs, numcsrc * sizeof(uint32),getSizeOfFixedHeader());
242 uint32* csrc = const_cast<uint32*>(getCSRCs());
243 for ( int i = 0; i < numcsrc; i++ )
244 csrc[i] = htonl(csrc[i]);
245 getHeader()->cc = numcsrc;
246}
247
248void OutgoingRTPPkt::protect(uint32 ssrc, CryptoContext* pcc)
249{
250 /* Encrypt the packet */
251 uint64 index = ((uint64)pcc->getRoc() << 16) | (uint64)getSeqNum();
252
253 pcc->srtpEncrypt(this, index, ssrc);
254
255 // NO MKI support yet - here we assume MKI is zero. To build in MKI
256 // take MKI length into account when storing the authentication tag.
257
258 /* Compute MAC */
259 pcc->srtpAuthenticate(this, pcc->getRoc(),
260 const_cast<uint8*>(getRawPacket()+srtpDataOffset) );
261 /* Update the ROC if necessary */
262 if (getSeqNum() == 0xFFFF ) {
263 pcc->setRoc(pcc->getRoc() + 1);
264 }
265}
266
267// These masks are valid regardless of endianness.
268const uint16 IncomingRTPPkt::RTP_INVALID_PT_MASK = (0x7e);
269const uint16 IncomingRTPPkt::RTP_INVALID_PT_VALUE = (0x48);
270
271IncomingRTPPkt::IncomingRTPPkt(const unsigned char* const block, size_t len) :
272RTPPacket(block,len)
273{
274 // first, perform validity check:
275 // 1) check protocol version
276 // 2) it is not an SR nor an RR
277 // 3) consistent length field value (taking CC value and P and
278 // X bits into account)
279 if ( getProtocolVersion() != CCRTP_VERSION || (getPayloadType() & RTP_INVALID_PT_MASK) == RTP_INVALID_PT_VALUE) {
280 /*
281 ||
282 getPayloadSize() <= 0 ) {
283 */
284 headerValid = false;
285 return;
286 }
287 headerValid = true;
288 cachedTimestamp = getRawTimestamp();
289 cachedSeqNum = ntohs(getHeader()->sequence);
290 cachedSSRC = ntohl(getHeader()->sources[0]);
291}
292
293int32 IncomingRTPPkt::unprotect(CryptoContext* pcc)
294{
295 if (pcc == NULL) {
296 return true;
297 }
298
299 /*
300 * This is the setting of the packet data when we come to this
301 * point:
302 *
303 * total: complete length of received data
304 * buffer: points to data as received from network
305 * hdrSize: length of header including header extension
306 * payloadSize: length of data excluding hdrSize and padding
307 *
308 * Because this is an SRTP packet we need to adjust some values here.
309 * The SRTP MKI and authentication data is always at the end of a
310 * packet. Thus compute the position of this data.
311 */
312
313 uint32 srtpDataIndex = total - (pcc->getTagLength() + pcc->getMkiLength());
314
315 // now adjust total because some RTP functions rely on the fact that
316 // total is the full length of data without SRTP data.
317 total -= pcc->getTagLength() + pcc->getMkiLength();
318
319 // recompute payloadSize by subtracting SRTP data
320 payloadSize -= pcc->getTagLength() + pcc->getMkiLength();
321
322 // unused??
323 // const uint8* mki = getRawPacket() + srtpDataIndex;
324 const uint8* tag = getRawPacket() + srtpDataIndex + pcc->getMkiLength();
325
326 /* Replay control */
327 if (!pcc->checkReplay(cachedSeqNum)) {
328 return -2;
329 }
330 /* Guess the index */
331 uint64 guessedIndex = pcc->guessIndex(cachedSeqNum);
332
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500333 uint32 guessedRoc = (uint32)(guessedIndex >> 16);
Emeric Vigier2f625822012-08-06 11:09:52 -0400334 uint8* mac = new uint8[pcc->getTagLength()];
335
336 pcc->srtpAuthenticate(this, guessedRoc, mac);
337 if (memcmp(tag, mac, pcc->getTagLength()) != 0) {
338 delete[] mac;
339 return -1;
340 }
341 delete[] mac;
342
343 /* Decrypt the content */
344 pcc->srtpEncrypt( this, guessedIndex, cachedSSRC );
345
346 /* Update the Crypto-context */
347 pcc->update(cachedSeqNum);
348
349 return 1;
350}
351
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500352END_NAMESPACE
Emeric Vigier2f625822012-08-06 11:09:52 -0400353
354/** EMACS **
355 * Local variables:
356 * mode: c++
357 * c-basic-offset: 4
358 * End:
359 */