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