blob: 7a1b62a60adc7df1780d3fbbc60464a6ef2949be [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#include "private.h"
40#include <ccrtp/queuebase.h>
41#include <ccrtp/ioqueue.h>
42#include <cstdio>
43#include <cstring>
44
Alexandre Lisionddd731e2014-01-31 11:50:08 -050045#ifndef _MSWINDOWS_
46#include <fcntl.h>
Emeric Vigier2f625822012-08-06 11:09:52 -040047#endif
48
Alexandre Lisionddd731e2014-01-31 11:50:08 -050049NAMESPACE_COMMONCPP
50using namespace std;
51
Emeric Vigier2f625822012-08-06 11:09:52 -040052// The first part of this file includes a copy of the MD5Digest class
53// of Common C++. This may seem weird, but it would be the only
54// dependency on libccext, so we prefer to reduce the library
55// footprint.
56
Emeric Vigier2f625822012-08-06 11:09:52 -040057/**
58 * The digest base class is used for implementing and deriving one way
59 * hashing functions.
60 *
61 * @author David Sugar <dyfet@ostel.com>
62 * @short base class for hashing services.
63 */
64class Digest : protected streambuf, public ostream
65{
66protected:
67 Digest();
68
69 /**
70 * Get the size of a digest in octets.
71 *
72 * @return number of bytes in digest.
73 */
74 virtual unsigned getSize(void) = 0;
75
76 /**
77 * Copy the binary digest buffer to user memory.
78 *
79 * @return number of bytes in digest.
80 * @param buffer to write into.
81 */
82 virtual unsigned getDigest(unsigned char *buffer) = 0;
83
84 /**
85 * Put data into the digest bypassing the stream subsystem.
86 *
87 * @param buffer to read from.
88 * @param length of data.
89 */
90 virtual void putDigest(const unsigned char *buffer, unsigned length) = 0;
91
92 /**
93 * print a digest string for export.
94 *
95 * @return string representation of digest.
96 */
97 virtual std::ostream &strDigest(std::ostream &os) = 0;
98
99 friend std::ostream &operator<<(std::ostream &os, Digest &ia)
100 {return ia.strDigest(os);}
101
102public:
103 /**
104 * Reset the digest table to an initial default value.
105 */
106 virtual void initDigest(void) = 0;
107};
108
109Digest::Digest() :
110streambuf()
111#ifdef HAVE_OLD_IOSTREAM
112,ostream()
113#else
114,ostream((streambuf *)this)
115#endif
116{
117#ifdef HAVE_OLD_IOSTREAM
118 init((streambuf *)this);
119#endif
120}
121
122/**
123 * A md5 collection/computation accululator class.
124 *
125 * @author David Sugar <dyfet@ostel.com>
126 * @short md5 hash accumulation.
127 */
128class MD5Digest : public Digest
129{
130private:
131 unsigned long state[4];
132 unsigned long count[2];
133 unsigned char buf[64];
134 unsigned bpos;
135 unsigned char md5[16];
136 bool updated;
137
138protected:
139 int overflow(int c);
140
141 void update(void);
142
143 void commit(void);
144
145 std::ostream &strDigest(std::ostream &os);
146
147public:
148 MD5Digest();
149
150 void initDigest(void);
151
152 inline unsigned getSize(void)
153 {return 16;}
154
155 unsigned getDigest(unsigned char *buffer);
156
157 void putDigest(const unsigned char *buffer, unsigned len);
158};
159
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500160#ifdef _MSWINDOWS_
Emeric Vigier2f625822012-08-06 11:09:52 -0400161#include <io.h>
162#endif
163
164#define S11 7
165#define S12 12
166#define S13 17
167#define S14 22
168#define S21 5
169#define S22 9
170#define S23 14
171#define S24 20
172#define S31 4
173#define S32 11
174#define S33 16
175#define S34 23
176#define S41 6
177#define S42 10
178#define S43 15
179#define S44 21
180
181static inline unsigned long rotate_left(unsigned long x, unsigned long n)
182{
183 // is unsigned long > 32 bit mask
184#if ~0lu != 0xfffffffflu
185 return (x << n) | ((x & 0xffffffffu) >> (32-n));
186#else
187 return (x << n) | (x >> (32-n));
188#endif
189}
190
191static inline unsigned long F(unsigned long x, unsigned long y, unsigned long z)
192{
193 return (x & y) | (~x & z);
194}
195
196static inline unsigned long G(unsigned long x, unsigned long y, unsigned long z)
197{
198 return (x & z) | (y & ~z);
199}
200
201static inline unsigned long H(unsigned long x, unsigned long y, unsigned long z)
202{
203 return x ^ y ^ z;
204}
205
206static inline unsigned long md5I(unsigned long x, unsigned long y, unsigned long z)
207{
208 return y ^ (x | ~z);
209}
210
211
212static void FF(unsigned long &a, unsigned long b, unsigned long c, unsigned long d, unsigned long x, unsigned long s, unsigned long ac)
213{
214 a += F(b, c, d) + x + ac;
215 a = rotate_left(a, s) + b;
216}
217
218static void GG(unsigned long &a, unsigned long b, unsigned long c, unsigned long d, unsigned long x, unsigned long s, unsigned long ac)
219{
220 a += G(b, c, d) + x + ac;
221 a = rotate_left(a, s) + b;
222}
223
224static void HH(unsigned long &a, unsigned long b, unsigned long c, unsigned long d, unsigned long x, unsigned long s, unsigned long ac)
225{
226 a += H(b, c, d) + x + ac;
227 a = rotate_left(a, s) + b;
228}
229
230static void II(unsigned long &a, unsigned long b, unsigned long c, unsigned long d, unsigned long x, unsigned long s, unsigned long ac)
231{
232 a += md5I(b, c, d) + x + ac;
233 a = rotate_left(a, s) + b;
234}
235
236MD5Digest::MD5Digest() :
237Digest()
238{
239 initDigest();
240 updated = true;
241}
242
243void MD5Digest::initDigest(void)
244{
245 count[0] = count[1] = 0;
246 state[0] = 0x67452301;
247 state[1] = 0xefcdab89;
248 state[2] = 0x98badcfe;
249 state[3] = 0x10325476;
250 bpos = 0;
251 updated = true; // CCY Added
252 setp((char*)buf,(char*)buf+64);
253}
254
255int MD5Digest::overflow(int c)
256{
257 updated = true;
258 bpos = (unsigned char*)pptr()-buf;
259 if(bpos >= 64)
260 update();
261 if (c != EOF)
262 buf[bpos++] = (unsigned char)c;
263 setp((char*)buf+bpos,(char*)buf+64);
264
265 return c;
266}
267
268void MD5Digest::update(void)
269{
270 unsigned long x[16], a, b, c, d;
271 int i;
272
273 if(!bpos)
274 return;
275
276 while(bpos < 64)
277 buf[bpos++] = 0;
278 bpos = 0;
279
280 if((count[0] += 512) < 512)
281 ++count[1];
282
283 a = state[0];
284 b = state[1];
285 c = state[2];
286 d = state[3];
287
288 for(i = 0; i < 16; ++i)
289 x[i] = (unsigned long)(buf[i * 4]) |
290 (unsigned long)(buf[i * 4 + 1] << 8) |
291 (unsigned long)(buf[i * 4 + 2] << 16) |
292 (unsigned long)(buf[i * 4 + 3] << 24);
293
294 FF(a, b, c, d, x[ 0], S11, 0xd76aa478);
295 FF(d, a, b, c, x[ 1], S12, 0xe8c7b756);
296 FF(c, d, a, b, x[ 2], S13, 0x242070db);
297 FF(b, c, d, a, x[ 3], S14, 0xc1bdceee);
298 FF(a, b, c, d, x[ 4], S11, 0xf57c0faf);
299 FF(d, a, b, c, x[ 5], S12, 0x4787c62a);
300 FF(c, d, a, b, x[ 6], S13, 0xa8304613);
301 FF(b, c, d, a, x[ 7], S14, 0xfd469501);
302 FF(a, b, c, d, x[ 8], S11, 0x698098d8);
303 FF(d, a, b, c, x[ 9], S12, 0x8b44f7af);
304 FF(c, d, a, b, x[10], S13, 0xffff5bb1);
305 FF(b, c, d, a, x[11], S14, 0x895cd7be);
306 FF(a, b, c, d, x[12], S11, 0x6b901122);
307 FF(d, a, b, c, x[13], S12, 0xfd987193);
308 FF(c, d, a, b, x[14], S13, 0xa679438e);
309 FF(b, c, d, a, x[15], S14, 0x49b40821);
310
311 GG(a, b, c, d, x[ 1], S21, 0xf61e2562);
312 GG(d, a, b, c, x[ 6], S22, 0xc040b340);
313 GG(c, d, a, b, x[11], S23, 0x265e5a51);
314 GG(b, c, d, a, x[ 0], S24, 0xe9b6c7aa);
315 GG(a, b, c, d, x[ 5], S21, 0xd62f105d);
316 GG(d, a, b, c, x[10], S22, 0x2441453);
317 GG(c, d, a, b, x[15], S23, 0xd8a1e681);
318 GG(b, c, d, a, x[ 4], S24, 0xe7d3fbc8);
319 GG(a, b, c, d, x[ 9], S21, 0x21e1cde6);
320 GG(d, a, b, c, x[14], S22, 0xc33707d6);
321 GG(c, d, a, b, x[ 3], S23, 0xf4d50d87);
322 GG(b, c, d, a, x[ 8], S24, 0x455a14ed);
323 GG(a, b, c, d, x[13], S21, 0xa9e3e905);
324 GG(d, a, b, c, x[ 2], S22, 0xfcefa3f8);
325 GG(c, d, a, b, x[ 7], S23, 0x676f02d9);
326 GG(b, c, d, a, x[12], S24, 0x8d2a4c8a);
327
328 HH(a, b, c, d, x[ 5], S31, 0xfffa3942);
329 HH(d, a, b, c, x[ 8], S32, 0x8771f681);
330 HH(c, d, a, b, x[11], S33, 0x6d9d6122);
331 HH(b, c, d, a, x[14], S34, 0xfde5380c);
332 HH(a, b, c, d, x[ 1], S31, 0xa4beea44);
333 HH(d, a, b, c, x[ 4], S32, 0x4bdecfa9);
334 HH(c, d, a, b, x[ 7], S33, 0xf6bb4b60);
335 HH(b, c, d, a, x[10], S34, 0xbebfbc70);
336 HH(a, b, c, d, x[13], S31, 0x289b7ec6);
337 HH(d, a, b, c, x[ 0], S32, 0xeaa127fa);
338 HH(c, d, a, b, x[ 3], S33, 0xd4ef3085);
339 HH(b, c, d, a, x[ 6], S34, 0x4881d05);
340 HH(a, b, c, d, x[ 9], S31, 0xd9d4d039);
341 HH(d, a, b, c, x[12], S32, 0xe6db99e5);
342 HH(c, d, a, b, x[15], S33, 0x1fa27cf8);
343 HH(b, c, d, a, x[ 2], S34, 0xc4ac5665);
344
345 II(a, b, c, d, x[ 0], S41, 0xf4292244);
346 II(d, a, b, c, x[ 7], S42, 0x432aff97);
347 II(c, d, a, b, x[14], S43, 0xab9423a7);
348 II(b, c, d, a, x[ 5], S44, 0xfc93a039);
349 II(a, b, c, d, x[12], S41, 0x655b59c3);
350 II(d, a, b, c, x[ 3], S42, 0x8f0ccc92);
351 II(c, d, a, b, x[10], S43, 0xffeff47d);
352 II(b, c, d, a, x[ 1], S44, 0x85845dd1);
353 II(a, b, c, d, x[ 8], S41, 0x6fa87e4f);
354 II(d, a, b, c, x[15], S42, 0xfe2ce6e0);
355 II(c, d, a, b, x[ 6], S43, 0xa3014314);
356 II(b, c, d, a, x[13], S44, 0x4e0811a1);
357 II(a, b, c, d, x[ 4], S41, 0xf7537e82);
358 II(d, a, b, c, x[11], S42, 0xbd3af235);
359 II(c, d, a, b, x[ 2], S43, 0x2ad7d2bb);
360 II(b, c, d, a, x[ 9], S44, 0xeb86d391);
361
362 state[0] += a;
363 state[1] += b;
364 state[2] += c;
365 state[3] += d;
366 updated = true;
367}
368
369void MD5Digest::commit(void)
370{
371 unsigned char cbuf[8];
372 unsigned long i, len;
373
374 static unsigned char pad[64]={
375 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
376 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
377 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
378
379 bpos = (unsigned char*)pptr()-buf;
380 if(!updated && !bpos)
381 return;
382
383 count[0] += (unsigned long)(bpos << 3);
384 if(count[0] < (unsigned long)(bpos << 3))
385 ++count[1];
386
387 for(i = 0; i < 2; ++i) {
388 cbuf[i * 4] = (unsigned char)count[i] & 0xff;
389 cbuf[i * 4 + 1] = (unsigned char)((count[i] >> 8) & 0xff);
390 cbuf[i * 4 + 2] = (unsigned char)((count[i] >> 16) & 0xff);
391 cbuf[i * 4 + 3] = (unsigned char)((count[i] >> 24) & 0xff);
392 }
393
394 i = (unsigned) ((count[0] >> 3) & 0x3f);
395 len = (i < 56) ? (56 - i) : (120 - i);
396 if(len)
397 putDigest(pad, len);
398
399 putDigest(cbuf, 8);
400
401 for(i = 0; i < 4; ++i) {
402 md5[i * 4] = (unsigned char)state[i] & 0xff;
403 md5[i * 4 + 1] = (unsigned char)((state[i] >> 8) & 0xff);
404 md5[i * 4 + 2] = (unsigned char)((state[i] >> 16) & 0xff);
405 md5[i * 4 + 3] = (unsigned char)((state[i] >> 24) & 0xff);
406 }
407 initDigest();
408}
409
410unsigned MD5Digest::getDigest(unsigned char *buffer)
411{
412 commit();
413
414 memcpy(buffer, md5, 16);
415 return 16;
416}
417
418void MD5Digest::putDigest(const unsigned char *buffer, unsigned len)
419{
420 bpos = (unsigned char*)pptr()-buf;
421 if(bpos >= 64)
422 update();
423 while(len--) {
424 buf[bpos++] = *(buffer++);
425 if(bpos >= 64)
426 update();
427 }
428 setp((char*)buf+bpos,(char*)buf+64);
429}
430
431std::ostream &MD5Digest::strDigest(std::ostream &os)
432{
433 char dbuf[36];
434 int i;
435
436 commit();
437
438 for(i = 0; i < 16; ++i)
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500439#ifdef _MSWINDOWS_
Emeric Vigier2f625822012-08-06 11:09:52 -0400440 sprintf(dbuf + 2 * i, "%02x", md5[i]);
441#else
442 std::sprintf(dbuf + 2 * i, "%02x", md5[i]);
443#endif
444 os << dbuf;
445 return os;
446}
447
Emeric Vigier2f625822012-08-06 11:09:52 -0400448static uint32 MD5BasedRandom32()
449{
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500450 // for bizzare gcc wierdness with type visibility
451 typedef timeval md5time_t;
452
Emeric Vigier2f625822012-08-06 11:09:52 -0400453 // This is the input to the MD5 algorithm.
454 union {
455 uint8 array[1];
456 struct {
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500457 md5time_t time;
Emeric Vigier2f625822012-08-06 11:09:52 -0400458 void *address;
459 uint8 cname[10];
460 } data;
461 } message;
462
463 // the output from the MD5 algorithm will be put here.
464 union {
465 uint32 buf32[4];
466 uint8 buf8[16];
467 } digest;
468
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500469 SysTime::gettimeofday(&(message.data.time),NULL);
Emeric Vigier2f625822012-08-06 11:09:52 -0400470 message.array[0] =
471 static_cast<uint8>(message.data.time.tv_sec *
472 message.data.time.tv_usec);
473
474 message.data.address = &message;
475 memcpy(message.data.cname,
476 defaultApplication().getSDESItem(SDESItemTypeCNAME).c_str(),10);
477
478 // compute MD5.
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500479 MD5Digest md5;
Emeric Vigier2f625822012-08-06 11:09:52 -0400480 md5.putDigest(reinterpret_cast<unsigned char*>(message.array),
481 sizeof(message));
482 md5.getDigest(reinterpret_cast<unsigned char*>(digest.buf8));
483
484 // Get result as xor of the four 32-bit words from the MD5 algorithm.
485 uint32 result = 0;
486 for ( int i = 0; i < 4; i ++ )
487 result ^= digest.buf32[i];
488 return result;
489}
490
491uint32 random32()
492{
493 // If /dev/urandom fails, default to the MD5 based algorithm
494 // given in the RTP specification.
495 uint32 number;
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500496#ifndef _MSWINDOWS_
Emeric Vigier2f625822012-08-06 11:09:52 -0400497 bool success = true;
498 int fd = open("/dev/urandom",O_RDONLY);
499 if (fd == -1) {
500 success = false;
501 } else {
502 if ( read(fd,&number,sizeof(number)) != sizeof(number) ) {
503 success = false;
504 }
505 }
506 close(fd);
507 if ( !success )
508#endif
509 number = MD5BasedRandom32();
510 return number;
511}
512
513uint16 random16()
514{
515 uint32 r32 = random32();
516 uint16 r16 = r32 & (r32 >> 16);
517 return r16;
518}
519
520RTPQueueBase::RTPQueueBase(uint32 *ssrc)
521{
522 if ( NULL == ssrc )
523 setLocalSSRC(random32());
524 else
525 setLocalSSRC(*ssrc);
526
527 // assume a default rate and payload type.
528 setPayloadFormat(StaticPayloadFormat(sptPCMU));
529 // queue/session creation time
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500530 SysTime::gettimeofday(&initialTime,NULL);
Emeric Vigier2f625822012-08-06 11:09:52 -0400531}
532
533const uint32 RTPDataQueue::defaultSessionBw = 64000;
534
535RTPDataQueue::RTPDataQueue(uint32 size) :
536IncomingDataQueue(size), OutgoingDataQueue()
537{
538 initQueue();
539}
540
541RTPDataQueue::RTPDataQueue(uint32* ssrc, uint32 size):
542RTPQueueBase(ssrc), IncomingDataQueue(size), OutgoingDataQueue(), timeclock()
543{
544 initQueue();
545 setLocalSSRC(*ssrc); // TODO - Strange - ssrc should be initialized via RTPQueueBase constructor
546}
547
548// Initialize everything
549void RTPDataQueue::initQueue()
550{
551 dataServiceActive = false;
552 typeOfService = tosBestEffort; // assume a best effort network
553 sessionBw = getDefaultSessionBandwidth();
554}
555
556void RTPDataQueue::endQueue(void)
557{
558 // stop executing the data service.
559 dataServiceActive = false;
560
561 // purge both sending and receiving queues.
562#ifdef CCXX_EXCEPTIONS
563 try {
564#endif
565 purgeOutgoingQueue();
566 purgeIncomingQueue();
567#ifdef CCXX_EXCEPTIONS
568 } catch (...) { }
569#endif
570 removeOutQueueCryptoContext(NULL); // remove the outgoing crypto context
571 removeInQueueCryptoContext(NULL); // Remove any incoming crypto contexts
572}
573
574uint32
575RTPDataQueue::getCurrentTimestamp() const
576{
577 // translate from current time to timestamp
578 timeval now;
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500579 SysTime::gettimeofday(&now,NULL);
Emeric Vigier2f625822012-08-06 11:09:52 -0400580
581 int32 result = now.tv_usec - getInitialTime().tv_usec;
582 result *= (getCurrentRTPClockRate()/1000);
583 result /= 1000;
584 result += (now.tv_sec - getInitialTime().tv_sec) * getCurrentRTPClockRate();
585
586 //result -= initialTimestamp;
587 return result;
588}
589
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500590END_NAMESPACE
Emeric Vigier2f625822012-08-06 11:09:52 -0400591
592/** EMACS **
593 * Local variables:
594 * mode: c++
595 * c-basic-offset: 4
596 * End:
597 */
598