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