~ubuntu-branches/ubuntu/maverick/sflphone/maverick

« back to all changes in this revision

Viewing changes to sflphone-common/libs/pjproject/third_party/srtp/test/rtpw.c

  • Committer: Bazaar Package Importer
  • Author(s): Francois Marier
  • Date: 2010-06-03 15:59:46 UTC
  • Revision ID: james.westby@ubuntu.com-20100603155946-ybe8d8o8zx8lp0m8
Tags: upstream-0.9.8.3
ImportĀ upstreamĀ versionĀ 0.9.8.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * rtpw.c
 
3
 *
 
4
 * rtp word sender/receiver
 
5
 *
 
6
 * David A. McGrew
 
7
 * Cisco Systems, Inc.
 
8
 *
 
9
 * This app is a simple RTP application intended only for testing
 
10
 * libsrtp.  It reads one word at a time from /usr/dict/words (or
 
11
 * whatever file is specified as DICT_FILE), and sends one word out
 
12
 * each USEC_RATE microseconds.  Secure RTP protections can be
 
13
 * applied.  See the usage() function for more details.
 
14
 *
 
15
 */
 
16
 
 
17
/*
 
18
 *      
 
19
 * Copyright (c) 2001-2006, Cisco Systems, Inc.
 
20
 * All rights reserved.
 
21
 * 
 
22
 * Redistribution and use in source and binary forms, with or without
 
23
 * modification, are permitted provided that the following conditions
 
24
 * are met:
 
25
 * 
 
26
 *   Redistributions of source code must retain the above copyright
 
27
 *   notice, this list of conditions and the following disclaimer.
 
28
 * 
 
29
 *   Redistributions in binary form must reproduce the above
 
30
 *   copyright notice, this list of conditions and the following
 
31
 *   disclaimer in the documentation and/or other materials provided
 
32
 *   with the distribution.
 
33
 * 
 
34
 *   Neither the name of the Cisco Systems, Inc. nor the names of its
 
35
 *   contributors may be used to endorse or promote products derived
 
36
 *   from this software without specific prior written permission.
 
37
 * 
 
38
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 
39
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 
40
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 
41
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 
42
 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 
43
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 
44
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 
45
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
46
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 
47
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 
48
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 
49
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 
50
 *
 
51
 */
 
52
 
 
53
 
 
54
#include "datatypes.h"
 
55
#include "getopt_s.h"       /* for local getopt()  */
 
56
 
 
57
#include <stdio.h>          /* for printf, fprintf */
 
58
#include <stdlib.h>         /* for atoi()          */
 
59
#include <errno.h>
 
60
#include <unistd.h>         /* for close()         */
 
61
 
 
62
#include <string.h>         /* for strncpy()       */
 
63
#include <time.h>           /* for usleep()        */
 
64
#ifdef HAVE_SYS_SOCKET_H
 
65
# include <sys/socket.h>
 
66
#endif
 
67
#ifdef HAVE_NETINET_IN_H
 
68
# include <netinet/in.h>
 
69
#elif defined HAVE_WINSOCK2_H
 
70
# include <winsock2.h>
 
71
# include <ws2tcpip.h>
 
72
# define RTPW_USE_WINSOCK2      1
 
73
#endif
 
74
#ifdef HAVE_ARPA_INET_H
 
75
# include <arpa/inet.h>
 
76
#endif
 
77
 
 
78
#include "srtp.h"           
 
79
#include "rtp.h"
 
80
 
 
81
#ifdef RTPW_USE_WINSOCK2
 
82
# define DICT_FILE        "words.txt"
 
83
#else
 
84
# define DICT_FILE        "/usr/share/dict/words"
 
85
#endif
 
86
#define USEC_RATE        (5e5)
 
87
#define MAX_WORD_LEN     128  
 
88
#define ADDR_IS_MULTICAST(a) IN_MULTICAST(htonl(a))
 
89
#define MAX_KEY_LEN      64
 
90
#define MASTER_KEY_LEN   30
 
91
 
 
92
 
 
93
#ifndef HAVE_USLEEP
 
94
# ifdef HAVE_WINDOWS_H
 
95
#  define usleep(us)    Sleep((us)/1000)
 
96
# else
 
97
#  define usleep(us)    sleep((us)/1000000)
 
98
# endif
 
99
#endif
 
100
 
 
101
 
 
102
/*
 
103
 * the function usage() prints an error message describing how this
 
104
 * program should be called, then calls exit()
 
105
 */
 
106
 
 
107
void
 
108
usage(char *prog_name);
 
109
 
 
110
/*
 
111
 * leave_group(...) de-registers from a multicast group
 
112
 */
 
113
 
 
114
void
 
115
leave_group(int sock, struct ip_mreq mreq, char *name);
 
116
 
 
117
 
 
118
/*
 
119
 * program_type distinguishes the [s]rtp sender and receiver cases
 
120
 */
 
121
 
 
122
typedef enum { sender, receiver, unknown } program_type;
 
123
 
 
124
int
 
125
main (int argc, char *argv[]) {
 
126
  char *dictfile = DICT_FILE;
 
127
  FILE *dict;
 
128
  char word[MAX_WORD_LEN];
 
129
  int sock, ret;
 
130
  struct in_addr rcvr_addr;
 
131
  struct sockaddr_in name;
 
132
  struct ip_mreq mreq;
 
133
#if BEW
 
134
  struct sockaddr_in local;
 
135
#endif 
 
136
  program_type prog_type = unknown;
 
137
  sec_serv_t sec_servs = sec_serv_none;
 
138
  unsigned char ttl = 5;
 
139
  int c;
 
140
  char *input_key = NULL;
 
141
  char *address = NULL;
 
142
  char key[MAX_KEY_LEN];
 
143
  unsigned short port = 0;
 
144
  rtp_sender_t snd;
 
145
  srtp_policy_t policy;
 
146
  err_status_t status;
 
147
  int len;
 
148
  int do_list_mods = 0;
 
149
  uint32_t ssrc = 0xdeadbeef; /* ssrc value hardcoded for now */
 
150
#ifdef RTPW_USE_WINSOCK2
 
151
  WORD wVersionRequested = MAKEWORD(2, 0);
 
152
  WSADATA wsaData;
 
153
 
 
154
  ret = WSAStartup(wVersionRequested, &wsaData);
 
155
  if (ret != 0) {
 
156
    fprintf(stderr, "error: WSAStartup() failed: %d\n", ret);
 
157
    exit(1);
 
158
  }
 
159
#endif
 
160
 
 
161
  /* initialize srtp library */
 
162
  status = srtp_init();
 
163
  if (status) {
 
164
    printf("error: srtp initialization failed with error code %d\n", status);
 
165
    exit(1);
 
166
  }
 
167
 
 
168
  /* check args */
 
169
  while (1) {
 
170
    c = getopt_s(argc, argv, "k:rsaeld:");
 
171
    if (c == -1) {
 
172
      break;
 
173
    }
 
174
    switch (c) {
 
175
    case 'k':
 
176
      input_key = optarg_s;
 
177
      break;
 
178
    case 'e':
 
179
      sec_servs |= sec_serv_conf;
 
180
      break;
 
181
    case 'a':
 
182
      sec_servs |= sec_serv_auth;
 
183
      break;
 
184
    case 'r':
 
185
      prog_type = receiver;
 
186
      break;
 
187
    case 's':
 
188
      prog_type = sender;
 
189
      break;
 
190
    case 'd':
 
191
      status = crypto_kernel_set_debug_module(optarg_s, 1);
 
192
      if (status) {
 
193
        printf("error: set debug module (%s) failed\n", optarg_s);
 
194
        exit(1);
 
195
      }
 
196
      break;
 
197
    case 'l':
 
198
      do_list_mods = 1;
 
199
      break;
 
200
    default:
 
201
      usage(argv[0]);
 
202
    }
 
203
  }
 
204
 
 
205
  if (prog_type == unknown) {
 
206
    if (do_list_mods) {
 
207
      status = crypto_kernel_list_debug_modules();
 
208
      if (status) {
 
209
        printf("error: list of debug modules failed\n");
 
210
        exit(1);
 
211
      }
 
212
      return 0;
 
213
    } else {
 
214
      printf("error: neither sender [-s] nor receiver [-r] specified\n");
 
215
      usage(argv[0]);
 
216
    }
 
217
  }
 
218
   
 
219
  if ((sec_servs && !input_key) || (!sec_servs && input_key)) {
 
220
    /* 
 
221
     * a key must be provided if and only if security services have
 
222
     * been requested 
 
223
     */
 
224
    usage(argv[0]);
 
225
  }
 
226
    
 
227
  if (argc != optind_s + 2) {
 
228
    /* wrong number of arguments */
 
229
    usage(argv[0]);
 
230
  }
 
231
 
 
232
  /* get address from arg */
 
233
  address = argv[optind_s++];
 
234
 
 
235
  /* get port from arg */
 
236
  port = atoi(argv[optind_s++]);
 
237
 
 
238
  /* set address */
 
239
#ifdef HAVE_INET_ATON
 
240
  if (0 == inet_aton(address, &rcvr_addr)) {
 
241
    fprintf(stderr, "%s: cannot parse IP v4 address %s\n", argv[0], address);
 
242
    exit(1);
 
243
  }
 
244
  if (rcvr_addr.s_addr == INADDR_NONE) {
 
245
    fprintf(stderr, "%s: address error", argv[0]);
 
246
    exit(1);
 
247
  }
 
248
#else
 
249
  rcvr_addr.s_addr = inet_addr(address);
 
250
  if (0xffffffff == rcvr_addr.s_addr) {
 
251
    fprintf(stderr, "%s: cannot parse IP v4 address %s\n", argv[0], address);
 
252
    exit(1);
 
253
  }
 
254
#endif
 
255
 
 
256
  /* open socket */
 
257
  sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
 
258
  if (sock < 0) {
 
259
    int err;
 
260
#ifdef RTPW_USE_WINSOCK2
 
261
    err = WSAGetLastError();
 
262
#else
 
263
    err = errno;
 
264
#endif
 
265
    fprintf(stderr, "%s: couldn't open socket: %d\n", argv[0], err);
 
266
    exit(1);
 
267
  }
 
268
 
 
269
  name.sin_addr   = rcvr_addr;    
 
270
  name.sin_family = PF_INET;
 
271
  name.sin_port   = htons(port);
 
272
 
 
273
  if (ADDR_IS_MULTICAST(rcvr_addr.s_addr)) {
 
274
    if (prog_type == sender) {
 
275
      ret = setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, 
 
276
                       sizeof(ttl));
 
277
      if (ret < 0) {
 
278
        fprintf(stderr, "%s: Failed to set TTL for multicast group", argv[0]);
 
279
        perror("");
 
280
        exit(1);
 
281
      }
 
282
    }
 
283
 
 
284
    mreq.imr_multiaddr.s_addr = rcvr_addr.s_addr;
 
285
    mreq.imr_interface.s_addr = htonl(INADDR_ANY);
 
286
    ret = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void*)&mreq,
 
287
                     sizeof(mreq));
 
288
    if (ret < 0) {
 
289
      fprintf(stderr, "%s: Failed to join multicast group", argv[0]);
 
290
      perror("");
 
291
      exit(1);
 
292
    }
 
293
  }
 
294
 
 
295
  /* report security services selected on the command line */
 
296
  printf("security services: ");
 
297
  if (sec_servs & sec_serv_conf)
 
298
    printf("confidentiality ");
 
299
  if (sec_servs & sec_serv_auth)
 
300
    printf("message authentication");
 
301
  if (sec_servs == sec_serv_none)
 
302
    printf("none");
 
303
  printf("\n");
 
304
  
 
305
  /* set up the srtp policy and master key */    
 
306
  if (sec_servs) {
 
307
    /* 
 
308
     * create policy structure, using the default mechanisms but 
 
309
     * with only the security services requested on the command line,
 
310
     * using the right SSRC value
 
311
     */
 
312
    switch (sec_servs) {
 
313
    case sec_serv_conf_and_auth:
 
314
      crypto_policy_set_rtp_default(&policy.rtp);
 
315
      crypto_policy_set_rtcp_default(&policy.rtcp);
 
316
      break;
 
317
    case sec_serv_conf:
 
318
      crypto_policy_set_aes_cm_128_null_auth(&policy.rtp);
 
319
      crypto_policy_set_rtcp_default(&policy.rtcp);      
 
320
      break;
 
321
    case sec_serv_auth:
 
322
      crypto_policy_set_null_cipher_hmac_sha1_80(&policy.rtp);
 
323
      crypto_policy_set_rtcp_default(&policy.rtcp);
 
324
      break;
 
325
    default:
 
326
      printf("error: unknown security service requested\n");
 
327
      return -1;
 
328
    } 
 
329
    policy.ssrc.type  = ssrc_specific;
 
330
    policy.ssrc.value = ssrc;
 
331
    policy.key  = (uint8_t *) key;
 
332
    policy.next = NULL;
 
333
    policy.rtp.sec_serv = sec_servs;
 
334
    policy.rtcp.sec_serv = sec_serv_none;  /* we don't do RTCP anyway */
 
335
 
 
336
    /*
 
337
     * read key from hexadecimal on command line into an octet string
 
338
     */
 
339
    len = hex_string_to_octet_string(key, input_key, MASTER_KEY_LEN*2);
 
340
    
 
341
    /* check that hex string is the right length */
 
342
    if (len < MASTER_KEY_LEN*2) {
 
343
      fprintf(stderr, 
 
344
              "error: too few digits in key/salt "
 
345
              "(should be %d hexadecimal digits, found %d)\n",
 
346
              MASTER_KEY_LEN*2, len);
 
347
      exit(1);    
 
348
    } 
 
349
    if (strlen(input_key) > MASTER_KEY_LEN*2) {
 
350
      fprintf(stderr, 
 
351
              "error: too many digits in key/salt "
 
352
              "(should be %d hexadecimal digits, found %u)\n",
 
353
              MASTER_KEY_LEN*2, (unsigned)strlen(input_key));
 
354
      exit(1);    
 
355
    }
 
356
    
 
357
    printf("set master key/salt to %s/", octet_string_hex_string(key, 16));
 
358
    printf("%s\n", octet_string_hex_string(key+16, 14));
 
359
  
 
360
  } else {
 
361
    /*
 
362
     * we're not providing security services, so set the policy to the
 
363
     * null policy
 
364
     *
 
365
     * Note that this policy does not conform to the SRTP
 
366
     * specification, since RTCP authentication is required.  However,
 
367
     * the effect of this policy is to turn off SRTP, so that this
 
368
     * application is now a vanilla-flavored RTP application.
 
369
     */
 
370
    policy.key                 = (uint8_t *)key;
 
371
    policy.ssrc.type           = ssrc_specific;
 
372
    policy.ssrc.value          = ssrc;
 
373
    policy.rtp.cipher_type     = NULL_CIPHER;
 
374
    policy.rtp.cipher_key_len  = 0; 
 
375
    policy.rtp.auth_type       = NULL_AUTH;
 
376
    policy.rtp.auth_key_len    = 0;
 
377
    policy.rtp.auth_tag_len    = 0;
 
378
    policy.rtp.sec_serv        = sec_serv_none;   
 
379
    policy.rtcp.cipher_type    = NULL_CIPHER;
 
380
    policy.rtcp.cipher_key_len = 0; 
 
381
    policy.rtcp.auth_type      = NULL_AUTH;
 
382
    policy.rtcp.auth_key_len   = 0;
 
383
    policy.rtcp.auth_tag_len   = 0;
 
384
    policy.rtcp.sec_serv       = sec_serv_none;   
 
385
    policy.next                = NULL;
 
386
  }
 
387
 
 
388
  if (prog_type == sender) {
 
389
 
 
390
#if BEW
 
391
    /* bind to local socket (to match crypto policy, if need be) */
 
392
    memset(&local, 0, sizeof(struct sockaddr_in));
 
393
    local.sin_addr.s_addr = htonl(INADDR_ANY);
 
394
    local.sin_port = htons(port);
 
395
    ret = bind(sock, (struct sockaddr *) &local, sizeof(struct sockaddr_in));
 
396
    if (ret < 0) {
 
397
      fprintf(stderr, "%s: bind failed\n", argv[0]);
 
398
      perror("");
 
399
      exit(1); 
 
400
    }
 
401
#endif /* BEW */
 
402
 
 
403
    /* initialize sender's rtp and srtp contexts */
 
404
    snd = rtp_sender_alloc();
 
405
    if (snd == NULL) {
 
406
      fprintf(stderr, "error: malloc() failed\n");
 
407
      exit(1);
 
408
    }
 
409
    rtp_sender_init(snd, sock, name, ssrc); 
 
410
    status = rtp_sender_init_srtp(snd, &policy);
 
411
    if (status) {
 
412
      fprintf(stderr, 
 
413
              "error: srtp_create() failed with code %d\n", 
 
414
              status);
 
415
      exit(1);
 
416
    }
 
417
 
 
418
    /* open dictionary */
 
419
    dict = fopen (dictfile, "r");
 
420
    if (dict == NULL) {
 
421
      fprintf(stderr, "%s: couldn't open file %s\n", argv[0], dictfile);
 
422
      if (ADDR_IS_MULTICAST(rcvr_addr.s_addr)) {
 
423
        leave_group(sock, mreq, argv[0]);
 
424
      }
 
425
      exit(1);
 
426
    }
 
427
          
 
428
    /* read words from dictionary, then send them off */
 
429
    while (fgets(word, MAX_WORD_LEN, dict) != NULL) { 
 
430
      len = strlen(word) + 1;  /* plus one for null */
 
431
      
 
432
      if (len > MAX_WORD_LEN) 
 
433
        printf("error: word %s too large to send\n", word);
 
434
      else {
 
435
        rtp_sendto(snd, word, len);
 
436
        printf("sending word: %s", word);
 
437
      }
 
438
      usleep(USEC_RATE);
 
439
    }
 
440
    
 
441
  } else  { /* prog_type == receiver */
 
442
    rtp_receiver_t rcvr;
 
443
        
 
444
    if (bind(sock, (struct sockaddr *)&name, sizeof(name)) < 0) {
 
445
      close(sock);
 
446
      fprintf(stderr, "%s: socket bind error\n", argv[0]);
 
447
      perror(NULL);
 
448
      if (ADDR_IS_MULTICAST(rcvr_addr.s_addr)) {
 
449
        leave_group(sock, mreq, argv[0]);
 
450
      }
 
451
      exit(1);
 
452
    }
 
453
 
 
454
    rcvr = rtp_receiver_alloc();
 
455
    if (rcvr == NULL) {
 
456
      fprintf(stderr, "error: malloc() failed\n");
 
457
      exit(1);
 
458
    }
 
459
    rtp_receiver_init(rcvr, sock, name, ssrc);
 
460
    status = rtp_receiver_init_srtp(rcvr, &policy);
 
461
    if (status) {
 
462
      fprintf(stderr, 
 
463
              "error: srtp_create() failed with code %d\n", 
 
464
              status);
 
465
      exit(1);
 
466
    }
 
467
 
 
468
    /* get next word and loop */
 
469
    while (1) {
 
470
      len = MAX_WORD_LEN;
 
471
      if (rtp_recvfrom(rcvr, word, &len) > -1)
 
472
        printf("\tword: %s", word);
 
473
    }
 
474
      
 
475
  } 
 
476
 
 
477
  if (ADDR_IS_MULTICAST(rcvr_addr.s_addr)) {
 
478
    leave_group(sock, mreq, argv[0]);
 
479
  }
 
480
 
 
481
#ifdef RTPW_USE_WINSOCK2
 
482
  WSACleanup();
 
483
#endif
 
484
 
 
485
  return 0;
 
486
}
 
487
 
 
488
 
 
489
void
 
490
usage(char *string) {
 
491
 
 
492
  printf("usage: %s [-d <debug>]* [-k <key> [-a][-e]] "
 
493
         "[-s | -r] dest_ip dest_port\n"
 
494
         "or     %s -l\n"
 
495
         "where  -a use message authentication\n"
 
496
         "       -e use encryption\n"
 
497
         "       -k <key>  sets the srtp master key\n"
 
498
         "       -s act as rtp sender\n"
 
499
         "       -r act as rtp receiver\n"
 
500
         "       -l list debug modules\n"
 
501
         "       -d <debug> turn on debugging for module <debug>\n",
 
502
         string, string);
 
503
  exit(1);
 
504
  
 
505
}
 
506
 
 
507
 
 
508
void
 
509
leave_group(int sock, struct ip_mreq mreq, char *name) {
 
510
  int ret;
 
511
 
 
512
  ret = setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, (void*)&mreq,
 
513
                   sizeof(mreq));
 
514
  if (ret < 0) {
 
515
        fprintf(stderr, "%s: Failed to leave multicast group", name);
 
516
        perror("");
 
517
  }
 
518
}
 
519