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