1 // test ccRTP functionality
2 // Copyright (C) 2004 Federico Montesino Pouzols <fedemp@altern.org>
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 #include <cstdlib>
19 #include <cstring>
20 #include <ccrtp/rtp.h>
21 #include <ccrtp/rtppkt.h>
22 #include <ccrtp/crypto/SrtpSymCrypto.h>
23 #include <ccrtp/CryptoContext.h>
24 #include <ccrtp/CryptoContextCtrl.h>
25 
26 #ifdef  CCXX_NAMESPACES
27 using namespace ost;
28 using namespace std;
29 #endif
30 
31 // Select one of SrtpEncryptionAESF8, SrtpEncryptionAESCM, SrtpEncryptionTWOCM, SrtpEncryptionTWOF8
32 // per RFC 3711 standard is: SrtpEncryptionAESCM
33 static int cryptoAlgo = SrtpEncryptionAESCM;
34 
hex_char_to_nibble(uint8_t c)35 inline int hex_char_to_nibble(uint8_t c)
36 {
37     switch(c) {
38     case ('0'): return 0x0;
39     case ('1'): return 0x1;
40     case ('2'): return 0x2;
41     case ('3'): return 0x3;
42     case ('4'): return 0x4;
43     case ('5'): return 0x5;
44     case ('6'): return 0x6;
45     case ('7'): return 0x7;
46     case ('8'): return 0x8;
47     case ('9'): return 0x9;
48     case ('a'): return 0xa;
49     case ('A'): return 0xa;
50     case ('b'): return 0xb;
51     case ('B'): return 0xb;
52     case ('c'): return 0xc;
53     case ('C'): return 0xc;
54     case ('d'): return 0xd;
55     case ('D'): return 0xd;
56     case ('e'): return 0xe;
57     case ('E'): return 0xe;
58     case ('f'): return 0xf;
59     case ('F'): return 0xf;
60     default: return -1;   /* this flags an error */
61     }
62     /* NOTREACHED */
63     return -1;  /* this keeps compilers from complaining */
64 }
65 
66 /*
67  * hex_string_to_octet_string converts a hexadecimal string
68  * of length 2 * len to a raw octet string of length len
69  */
70 
hex_string_to_octet_string(char * raw,char * hex,int len)71 int hex_string_to_octet_string(char *raw, char *hex, int len)
72 {
73     uint8 x;
74     int tmp;
75     int hex_len;
76 
77     hex_len = 0;
78     while (hex_len < len) {
79         tmp = hex_char_to_nibble(hex[0]);
80         if (tmp == -1)
81             return hex_len;
82         x = (tmp << 4);
83         hex_len++;
84         tmp = hex_char_to_nibble(hex[1]);
85         if (tmp == -1)
86             return hex_len;
87         x |= (tmp & 0xff);
88         hex_len++;
89         *raw++ = x;
90         hex += 2;
91     }
92     return hex_len;
93 }
94 
95 class PacketsPattern
96 {
97 public:
getDestinationAddress() const98     inline const InetHostAddress& getDestinationAddress() const
99         { return destinationAddress; }
100 
getDestinationPort() const101     inline const tpport_t getDestinationPort() const
102         { return destinationPort; }
103 
getPacketsNumber() const104     uint32 getPacketsNumber() const
105         { return packetsNumber; }
106 
getSsrc() const107     uint32 getSsrc() const
108         { return 0xdeadbeef; }
109 
getPacketData(uint32 i)110     const unsigned char* getPacketData(uint32 i)
111         { return data; }
112 
getPacketSize(uint32 i)113     const size_t getPacketSize(uint32 i)
114         { return packetsSize; }
115 
116 private:
117     static const InetHostAddress destinationAddress;
118     static const uint16 destinationPort = 5002;
119     static const uint32 packetsNumber = 10;
120     static const uint32 packetsSize = 12;
121     static unsigned char data[];
122 };
123 
124 const InetHostAddress PacketsPattern::destinationAddress =
125     InetHostAddress("localhost");
126 
127 unsigned char PacketsPattern::data[] = {
128     "0123456789\n"
129 };
130 
131 PacketsPattern pattern;
132 
133 static char* fixKey = (char *)"c2479f224b21c2008deea6ef0e5dbd4a761aef98e7ebf8eed405986c4687";
134 
135 // static uint8* masterKey =  (uint8*)"masterKeymasterKeymasterKeymaster";
136 // static uint8* masterSalt = (uint8*)"NaClNaClNaClNa";
137 
138 uint8 masterKey[] = {   0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
139                         0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
140 
141 uint8 masterSalt[] = {  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
142                         0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d };
143 
144 static uint8 binKeys[60];
145 
146 class SendPacketTransmissionTest: public Thread, public TimerPort
147 {
148 public:
run()149     void run() {
150         doTest();
151     }
152 
doTest()153     int doTest()
154     {
155         // should be valid?
156         //RTPSession tx();
157         RTPSession tx(pattern.getSsrc(), InetHostAddress("localhost"));
158         tx.setSchedulingTimeout(10000);
159         tx.setExpireTimeout(1000000);
160 
161         CryptoContext* txCryptoCtx =
162             new CryptoContext(pattern.getSsrc(),
163                   0,                           // roc,
164                   0L,                          // keydr << 48,
165                   cryptoAlgo,         // encryption algo
166                   SrtpAuthenticationSha1Hmac,  // authtication algo
167                   masterKey,                   // Master Key
168                   128 / 8,                     // Master Key length
169                   masterSalt,                  // Master Salt
170                   112 / 8,                     // Master Salt length
171                   128 / 8,                     // encryption keyl
172                   160 / 8,                     // authentication key len (SHA1))
173                   112 / 8,                     // session salt len
174                   80 / 8);                     // authentication tag len
175         txCryptoCtx->deriveSrtpKeys(0);
176 
177         tx.setOutQueueCryptoContext(txCryptoCtx);
178 
179         CryptoContextCtrl* txCryptoCtxCtrl = new CryptoContextCtrl(0,
180                   cryptoAlgo,         // encryption algo
181                   SrtpAuthenticationSha1Hmac,  // authtication algo
182                   masterKey,                   // Master Key
183                   128 / 8,                     // Master Key length
184                   masterSalt,                  // Master Salt
185                   112 / 8,                     // Master Salt length
186                   128 / 8,                     // encryption keyl
187                   160 / 8,                     // authentication key len (SHA1))
188                   112 / 8,                     // session salt len
189                   80 / 8);                     // authentication tag len
190         tx.setOutQueueCryptoContextCtrl(txCryptoCtxCtrl);
191 
192         tx.startRunning();
193 
194         tx.setPayloadFormat(StaticPayloadFormat(sptPCMU));
195         if (!tx.addDestination(pattern.getDestinationAddress(), pattern.getDestinationPort()) ) {
196             return 1;
197         }
198 
199         // 50 packets per second (packet duration of 20ms)
200         uint32 period = 20;
201         uint16 inc = tx.getCurrentRTPClockRate()/50;
202         TimerPort::setTimer(period);
203         for ( uint32 i = 0; i < pattern.getPacketsNumber(); i++ ) {
204             tx.putData(i*inc, pattern.getPacketData(i), pattern.getPacketSize(i));
205             cout << "Sent some data: " << i << endl;
206             Thread::sleep(TimerPort::getTimer());
207             TimerPort::incTimer(period);
208         }
209         return 0;
210     }
211 };
212 
213 
214 class RecvPacketTransmissionTest: public Thread
215 {
216 public:
run()217     void run() {
218         doTest();
219     }
220 
doTest()221     int doTest()
222     {
223         RTPSession rx(pattern.getSsrc(), pattern.getDestinationAddress(),
224             pattern.getDestinationPort());
225 
226         rx.setSchedulingTimeout(10000);
227         rx.setExpireTimeout(1000000);
228 
229         CryptoContext* rxCryptoCtx =
230             new CryptoContext(0,                // SSRC == 0 -> Context template
231                     0,                          // roc,
232                     0L,                         // keydr << 48,
233                     cryptoAlgo,        // encryption algo
234                     SrtpAuthenticationSha1Hmac, // authtication algo
235                     masterKey,                  // Master Key
236                     128 / 8,                    // Master Key length
237                     masterSalt,                 // Master Salt
238                     112 / 8,                    // Master Salt length
239                     128 / 8,                    // encryption keyl
240                     160 / 8,                    // authentication keylen (SHA1))
241                     112 / 8,                    // session salt len
242                     80 / 8);                    // authentication tag len
243         rx.setInQueueCryptoContext(rxCryptoCtx);
244 
245         CryptoContextCtrl* rxCryptoCtxCtrl = new CryptoContextCtrl(0,
246                   cryptoAlgo,         // encryption algo
247                   SrtpAuthenticationSha1Hmac,  // authtication algo
248                   masterKey,                   // Master Key
249                   128 / 8,                     // Master Key length
250                   masterSalt,                  // Master Salt
251                   112 / 8,                     // Master Salt length
252                   128 / 8,                     // encryption keyl
253                   160 / 8,                     // authentication key len (SHA1))
254                   112 / 8,                     // session salt len
255                   80 / 8);                     // authentication tag len
256 
257         rx.setInQueueCryptoContextCtrl(rxCryptoCtxCtrl);
258 
259         rx.startRunning();
260         rx.setPayloadFormat(StaticPayloadFormat(sptPCMU));
261         // arbitrary number of loops
262         for ( int i = 0; i < 500 ; i++ ) {
263             const AppDataUnit* adu;
264             while ( (adu = rx.getData(rx.getFirstTimestamp())) ) {
265                 cerr << "got some data: " << adu->getData() << endl;
266                 delete adu;
267             }
268             Thread::sleep(70);
269         }
270         return 0;
271     }
272 };
273 
main(int argc,char * argv[])274 int main(int argc, char *argv[])
275 {
276     int result = 0;
277     bool send = false;
278     bool recv = false;
279     bool f8Test = false;
280 
281     char* inputKey = NULL;
282     char *args = *argv++;
283 
284     while(NULL != (args = *argv++)) {
285         if(*args == '-')
286             ++args;
287         if(!strcmp(args, "r") || !strcmp(args, "recv"))
288             recv = true;
289         else if(!strcmp(args, "s") || !strcmp(args, "send"))
290             send = true;
291         else if(!strcmp(args, "8") || !strcmp(args, "8test"))
292             f8Test = true;
293         else if(!strcmp(args, "k") || !strcmp(args, "key"))
294             inputKey = *argv++;
295         else
296             fprintf(stderr, "*** ccsrtptest: %s: unknown option\n", args);
297     }
298 
299     if (inputKey == NULL) {
300         inputKey = fixKey;
301     }
302     hex_string_to_octet_string((char*)binKeys, inputKey, 60);
303 
304     if (send || recv) {
305         if (send) {
306             cout << "Running as sender" << endl;
307         }
308         else {
309             cout << "Running as receiver" << endl;
310         }
311     }
312     else if (f8Test) {
313         cout << "Running F8 test: ";
314         int ret = testF8();
315         cout << ret << endl;
316         exit(ret);
317     }
318     RecvPacketTransmissionTest *rx;
319     SendPacketTransmissionTest *tx;
320 
321     // accept as parameter if must run as -s, -r, -8
322 
323     // run several tests in parallel threads
324     if (send) {
325         tx = new SendPacketTransmissionTest();
326         tx->start();
327         tx->join();
328     } else if (recv) {
329         rx = new RecvPacketTransmissionTest();
330         rx->start();
331         rx->join();
332     }
333     exit(result);
334 }
335 
336 /** EMACS **
337  * Local variables:
338  * mode: c++
339  * c-basic-offset: 4
340  * End:
341  */
342 
343