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