err_status_t hash_test_case_add(hash_test_case_t **list_ptr, char *hex_data, unsigned data_len, char *hex_hash, unsigned hash_len) { hash_test_case_t *list_head = *list_ptr; hash_test_case_t *test_case; unsigned tmp_len; test_case = malloc(sizeof(hash_test_case_t)); if (test_case == NULL) return err_status_alloc_fail; tmp_len = hex_string_to_octet_string((char *)test_case->data, hex_data, data_len*2); if (tmp_len != data_len*2) return err_status_parse_err; tmp_len = hex_string_to_octet_string((char *)test_case->hash, hex_hash, hash_len*2); if (tmp_len != hash_len*2) return err_status_parse_err; test_case->data_len = data_len; test_case->hash_len = hash_len; /* add the new test case to the head of the list */ test_case->next_test_case = list_head; *list_ptr = test_case; return err_status_ok; }
// int main(int argc, char *argv[]) { int aes_calc(char *key8, char *phrase8, char *cipher8) { v128_t data, key; aes_expanded_key_t exp_key; int len; int verbose = 0; /* read in key, checking length */ if (strlen(key8) > AES_KEY_LEN * 2) { fprintf(stderr, "error: too many digits in key " "(should be %d hexadecimal digits, found %u)\n", AES_KEY_LEN * 2, (unsigned) strlen(key8)); return(1); } len = hex_string_to_octet_string((char *) &key, key8, AES_KEY_LEN*2); /* check that hex string is the right length */ if (len < AES_KEY_LEN * 2) { fprintf(stderr, "error: too few digits in key " "(should be %d hexadecimal digits, found %d)\n", AES_KEY_LEN * 2, len); return(1); } /* read in plaintext, checking length */ if (strlen(phrase8) > 16 * 2) { fprintf(stderr, "error: too many digits in plaintext " "(should be %d hexadecimal digits, found %u)\n", 16 * 2, (unsigned) strlen(phrase8)); return(1); } len = hex_string_to_octet_string((char *) (&data), phrase8, 16 * 2); /* check that hex string is the right length */ if (len < 16 * 2) { fprintf(stderr, "error: too few digits in plaintext " "(should be %d hexadecimal digits, found %d)\n", 16 * 2, len); return(1); } if (verbose) { /* print out plaintext */ printf("plaintext:\t%s\n", octet_string_hex_string((uint8_t *) &data, 16)); } /* encrypt plaintext */ aes_expand_encryption_key(&key, exp_key); aes_encrypt(&data, exp_key); /* write ciphertext to output */ if (verbose) { printf("key:\t\t%s\n", v128_hex_string(&key)); printf("ciphertext:\t"); } printf("%s\n", v128_hex_string(&data)); return strcmp(v128_hex_string(&data), cipher8); }
srtpw_err_status_t srtpw_validate_key(unsigned char *input_key) { char key[SRTP_MAX_KEY_LEN]; int len; /* * read key from hexadecimal into an octet string */ len = hex_string_to_octet_string((char *)key, (char *)input_key, SRTP_MASTER_KEY_LEN*2); /* check that hex string is the right length */ if (len < SRTP_MASTER_KEY_LEN*2) { srtpw_log(err_level_error, "error: too few digits in key/salt " "(should be %d hexadecimal digits, found %d)\n", SRTP_MASTER_KEY_LEN*2, len); return srtpw_err_status_bad_param; } if (strlen((const char *)input_key) > SRTP_MASTER_KEY_LEN*2) { srtpw_log(err_level_error, "error: too many digits in key/salt " "(should be %d hexadecimal digits, found %u)\n", SRTP_MASTER_KEY_LEN*2, (unsigned)strlen((const char *)input_key)); return srtpw_err_status_bad_param; } srtpw_log(err_level_info,"set master key/salt to %s/", octet_string_hex_string(key, SRTP_MASTERKEY_LEN)); srtpw_log(err_level_info,"%s\n", octet_string_hex_string(key+SRTP_MASTERKEY_LEN, SRTP_MASTERSALT_LEN)); return srtpw_err_status_ok; }
void test_hex_string_funcs(void) { char hex1[] = "abadcafe"; char hex2[] = "0123456789abcdefqqqqq"; char raw[10]; int len; len = hex_string_to_octet_string(raw, hex1, strlen(hex1)); printf("computed length: %d\tstring: %s\n", len, octet_string_hex_string(raw, len/2)); printf("expected length: %u\tstring: %s\n", (unsigned)strlen(hex1), hex1); len = hex_string_to_octet_string(raw, hex2, strlen(hex2)); printf("computed length: %d\tstring: %s\n", len, octet_string_hex_string(raw, len/2)); printf("expected length: %d\tstring: %s\n", 16, "0123456789abcdef"); }
int main (int argc, char *argv[]) { char *dictfile = DICT_FILE; FILE *dict; char word[MAX_WORD_LEN]; int sock, ret; struct in_addr rcvr_addr; struct sockaddr_in name; struct ip_mreq mreq; #if BEW struct sockaddr_in local; #endif program_type prog_type = unknown; sec_serv_t sec_servs = sec_serv_none; unsigned char ttl = 5; int c; int key_size = 128; int tag_size = 8; int gcm_on = 0; char *input_key = NULL; char *address = NULL; char key[MAX_KEY_LEN]; unsigned short port = 0; rtp_sender_t snd; srtp_policy_t policy; err_status_t status; int len; int do_list_mods = 0; uint32_t ssrc = 0xdeadbeef; /* ssrc value hardcoded for now */ #ifdef RTPW_USE_WINSOCK2 WORD wVersionRequested = MAKEWORD(2, 0); WSADATA wsaData; ret = WSAStartup(wVersionRequested, &wsaData); if (ret != 0) { fprintf(stderr, "error: WSAStartup() failed: %d\n", ret); exit(1); } #endif if (setup_signal_handler(argv[0]) != 0) { exit(1); } /* initialize srtp library */ status = srtp_init(); if (status) { printf("error: srtp initialization failed with error code %d\n", status); exit(1); } /* check args */ while (1) { c = getopt_s(argc, argv, "k:rsgt:ae:ld:"); if (c == -1) { break; } switch (c) { case 'k': input_key = optarg_s; break; case 'e': key_size = atoi(optarg_s); if (key_size != 128 && key_size != 256) { printf("error: encryption key size must be 128 or 256 (%d)\n", key_size); exit(1); } sec_servs |= sec_serv_conf; break; case 't': tag_size = atoi(optarg_s); if (tag_size != 8 && tag_size != 16) { printf("error: GCM tag size must be 8 or 16 (%d)\n", tag_size); exit(1); } break; case 'a': sec_servs |= sec_serv_auth; break; case 'g': gcm_on = 1; sec_servs |= sec_serv_auth; break; case 'r': prog_type = receiver; break; case 's': prog_type = sender; break; case 'd': status = crypto_kernel_set_debug_module(optarg_s, 1); if (status) { printf("error: set debug module (%s) failed\n", optarg_s); exit(1); } break; case 'l': do_list_mods = 1; break; default: usage(argv[0]); } } if (prog_type == unknown) { if (do_list_mods) { status = crypto_kernel_list_debug_modules(); if (status) { printf("error: list of debug modules failed\n"); exit(1); } return 0; } else { printf("error: neither sender [-s] nor receiver [-r] specified\n"); usage(argv[0]); } } if ((sec_servs && !input_key) || (!sec_servs && input_key)) { /* * a key must be provided if and only if security services have * been requested */ usage(argv[0]); } if (argc != optind_s + 2) { /* wrong number of arguments */ usage(argv[0]); } /* get address from arg */ address = argv[optind_s++]; /* get port from arg */ port = atoi(argv[optind_s++]); /* set address */ #ifdef HAVE_INET_ATON if (0 == inet_aton(address, &rcvr_addr)) { fprintf(stderr, "%s: cannot parse IP v4 address %s\n", argv[0], address); exit(1); } if (rcvr_addr.s_addr == INADDR_NONE) { fprintf(stderr, "%s: address error", argv[0]); exit(1); } #else rcvr_addr.s_addr = inet_addr(address); if (0xffffffff == rcvr_addr.s_addr) { fprintf(stderr, "%s: cannot parse IP v4 address %s\n", argv[0], address); exit(1); } #endif /* open socket */ sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (sock < 0) { int err; #ifdef RTPW_USE_WINSOCK2 err = WSAGetLastError(); #else err = errno; #endif fprintf(stderr, "%s: couldn't open socket: %d\n", argv[0], err); exit(1); } name.sin_addr = rcvr_addr; name.sin_family = PF_INET; name.sin_port = htons(port); if (ADDR_IS_MULTICAST(rcvr_addr.s_addr)) { if (prog_type == sender) { ret = setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)); if (ret < 0) { fprintf(stderr, "%s: Failed to set TTL for multicast group", argv[0]); perror(""); exit(1); } } mreq.imr_multiaddr.s_addr = rcvr_addr.s_addr; mreq.imr_interface.s_addr = htonl(INADDR_ANY); ret = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void*)&mreq, sizeof(mreq)); if (ret < 0) { fprintf(stderr, "%s: Failed to join multicast group", argv[0]); perror(""); exit(1); } } /* report security services selected on the command line */ printf("security services: "); if (sec_servs & sec_serv_conf) printf("confidentiality "); if (sec_servs & sec_serv_auth) printf("message authentication"); if (sec_servs == sec_serv_none) printf("none"); printf("\n"); /* set up the srtp policy and master key */ if (sec_servs) { /* * create policy structure, using the default mechanisms but * with only the security services requested on the command line, * using the right SSRC value */ switch (sec_servs) { case sec_serv_conf_and_auth: if (gcm_on) { #ifdef OPENSSL switch (key_size) { case 128: crypto_policy_set_aes_gcm_128_8_auth(&policy.rtp); crypto_policy_set_aes_gcm_128_8_auth(&policy.rtcp); break; case 256: crypto_policy_set_aes_gcm_256_8_auth(&policy.rtp); crypto_policy_set_aes_gcm_256_8_auth(&policy.rtcp); break; } #else printf("error: GCM mode only supported when using the OpenSSL crypto engine.\n"); return 0; #endif } else { switch (key_size) { case 128: crypto_policy_set_rtp_default(&policy.rtp); crypto_policy_set_rtcp_default(&policy.rtcp); break; case 256: crypto_policy_set_aes_cm_256_hmac_sha1_80(&policy.rtp); crypto_policy_set_rtcp_default(&policy.rtcp); break; } } break; case sec_serv_conf: if (gcm_on) { printf("error: GCM mode must always be used with auth enabled\n"); return -1; } else { switch (key_size) { case 128: crypto_policy_set_aes_cm_128_null_auth(&policy.rtp); crypto_policy_set_rtcp_default(&policy.rtcp); break; case 256: crypto_policy_set_aes_cm_256_null_auth(&policy.rtp); crypto_policy_set_rtcp_default(&policy.rtcp); break; } } break; case sec_serv_auth: if (gcm_on) { #ifdef OPENSSL switch (key_size) { case 128: crypto_policy_set_aes_gcm_128_8_only_auth(&policy.rtp); crypto_policy_set_aes_gcm_128_8_only_auth(&policy.rtcp); break; case 256: crypto_policy_set_aes_gcm_256_8_only_auth(&policy.rtp); crypto_policy_set_aes_gcm_256_8_only_auth(&policy.rtcp); break; } #else printf("error: GCM mode only supported when using the OpenSSL crypto engine.\n"); return 0; #endif } else { crypto_policy_set_null_cipher_hmac_sha1_80(&policy.rtp); crypto_policy_set_rtcp_default(&policy.rtcp); } break; default: printf("error: unknown security service requested\n"); return -1; } policy.ssrc.type = ssrc_specific; policy.ssrc.value = ssrc; policy.key = (uint8_t *) key; policy.ekt = NULL; policy.next = NULL; policy.window_size = 128; policy.allow_repeat_tx = 0; policy.rtp.sec_serv = sec_servs; policy.rtcp.sec_serv = sec_serv_none; /* we don't do RTCP anyway */ if (gcm_on && tag_size != 8) { policy.rtp.auth_tag_len = tag_size; } /* * read key from hexadecimal on command line into an octet string */ len = hex_string_to_octet_string(key, input_key, policy.rtp.cipher_key_len*2); /* check that hex string is the right length */ if (len < policy.rtp.cipher_key_len*2) { fprintf(stderr, "error: too few digits in key/salt " "(should be %d hexadecimal digits, found %d)\n", policy.rtp.cipher_key_len*2, len); exit(1); } if (strlen(input_key) > policy.rtp.cipher_key_len*2) { fprintf(stderr, "error: too many digits in key/salt " "(should be %d hexadecimal digits, found %u)\n", policy.rtp.cipher_key_len*2, (unsigned)strlen(input_key)); exit(1); } printf("set master key/salt to %s/", octet_string_hex_string(key, 16)); printf("%s\n", octet_string_hex_string(key+16, 14)); } else { /* * we're not providing security services, so set the policy to the * null policy * * Note that this policy does not conform to the SRTP * specification, since RTCP authentication is required. However, * the effect of this policy is to turn off SRTP, so that this * application is now a vanilla-flavored RTP application. */ policy.key = (uint8_t *)key; policy.ssrc.type = ssrc_specific; policy.ssrc.value = ssrc; policy.rtp.cipher_type = NULL_CIPHER; policy.rtp.cipher_key_len = 0; policy.rtp.auth_type = NULL_AUTH; policy.rtp.auth_key_len = 0; policy.rtp.auth_tag_len = 0; policy.rtp.sec_serv = sec_serv_none; policy.rtcp.cipher_type = NULL_CIPHER; policy.rtcp.cipher_key_len = 0; policy.rtcp.auth_type = NULL_AUTH; policy.rtcp.auth_key_len = 0; policy.rtcp.auth_tag_len = 0; policy.rtcp.sec_serv = sec_serv_none; policy.window_size = 0; policy.allow_repeat_tx = 0; policy.ekt = NULL; policy.next = NULL; } if (prog_type == sender) { #if BEW /* bind to local socket (to match crypto policy, if need be) */ memset(&local, 0, sizeof(struct sockaddr_in)); local.sin_addr.s_addr = htonl(INADDR_ANY); local.sin_port = htons(port); ret = bind(sock, (struct sockaddr *) &local, sizeof(struct sockaddr_in)); if (ret < 0) { fprintf(stderr, "%s: bind failed\n", argv[0]); perror(""); exit(1); } #endif /* BEW */ /* initialize sender's rtp and srtp contexts */ snd = rtp_sender_alloc(); if (snd == NULL) { fprintf(stderr, "error: malloc() failed\n"); exit(1); } rtp_sender_init(snd, sock, name, ssrc); status = rtp_sender_init_srtp(snd, &policy); if (status) { fprintf(stderr, "error: srtp_create() failed with code %d\n", status); exit(1); } /* open dictionary */ dict = fopen (dictfile, "r"); if (dict == NULL) { fprintf(stderr, "%s: couldn't open file %s\n", argv[0], dictfile); if (ADDR_IS_MULTICAST(rcvr_addr.s_addr)) { leave_group(sock, mreq, argv[0]); } exit(1); } /* read words from dictionary, then send them off */ while (!interrupted && fgets(word, MAX_WORD_LEN, dict) != NULL) { len = strlen(word) + 1; /* plus one for null */ if (len > MAX_WORD_LEN) printf("error: word %s too large to send\n", word); else { rtp_sendto(snd, word, len); printf("sending word: %s", word); } usleep(USEC_RATE); } rtp_sender_deinit_srtp(snd); rtp_sender_dealloc(snd); fclose(dict); } else { /* prog_type == receiver */ rtp_receiver_t rcvr; if (bind(sock, (struct sockaddr *)&name, sizeof(name)) < 0) { close(sock); fprintf(stderr, "%s: socket bind error\n", argv[0]); perror(NULL); if (ADDR_IS_MULTICAST(rcvr_addr.s_addr)) { leave_group(sock, mreq, argv[0]); } exit(1); } rcvr = rtp_receiver_alloc(); if (rcvr == NULL) { fprintf(stderr, "error: malloc() failed\n"); exit(1); } rtp_receiver_init(rcvr, sock, name, ssrc); status = rtp_receiver_init_srtp(rcvr, &policy); if (status) { fprintf(stderr, "error: srtp_create() failed with code %d\n", status); exit(1); } /* get next word and loop */ while (!interrupted) { len = MAX_WORD_LEN; if (rtp_recvfrom(rcvr, word, &len) > -1) printf("\tword: %s\n", word); } rtp_receiver_deinit_srtp(rcvr); rtp_receiver_dealloc(rcvr); } if (ADDR_IS_MULTICAST(rcvr_addr.s_addr)) { leave_group(sock, mreq, argv[0]); } #ifdef RTPW_USE_WINSOCK2 ret = closesocket(sock); #else ret = close(sock); #endif if (ret < 0) { fprintf(stderr, "%s: Failed to close socket", argv[0]); perror(""); } status = srtp_shutdown(); if (status) { printf("error: srtp shutdown failed with error code %d\n", status); exit(1); } #ifdef RTPW_USE_WINSOCK2 WSACleanup(); #endif return 0; }
int main (int argc, char *argv[]) { struct rtp *session; int rx_port, tx_port, fd; uint32_t read_size, packet_size, number_of_packet; uint8_t buff[BUFFSIZE]; off_t cur_pos; char *ip_addr; char filename[1024]; int c; struct hostent *h; struct utsname myname; #ifdef HAVE_SRTP #else void *srtp_data; #endif unsigned int extra_len; int do_auth = 1, do_encrypt = 1; ssize_t readit; ssize_t sendit; int do_rtcp = false; // Setting of default session if(uname(&myname) < 0){ fprintf(stderr,"uname\n"); exit(1); } if((h = gethostbyname(myname.nodename)) == NULL) { herror("gethostbyname"); exit(1); } ip_addr = strdup(inet_ntoa(*((struct in_addr *)h->h_addr))); rx_port = 15002; tx_port = 15000; // Option opterr = 0; while((c = getopt(argc, argv, "acdehi:r:t:f:")) != -1){ switch (c) { case 'a': do_auth = 0; break; case 'c': do_rtcp = 1; break; case 'd': dump_pak = true; break; case 'e': do_encrypt = 0; break; case 'h': printf("Usage: ./test_rtp_client -i <IP_Addr> -r <rx_port> -t <tx_port> -f <filename>\n"); printf("Default values are as follows...\n"); printf("ip_addr = %s\n", ip_addr); printf("rx_port = %d\n", rx_port); printf("tx_port = %d\n", tx_port); printf("Filename = %s\n", filename); exit(-1); case 'i': strcpy(ip_addr, optarg); break; case 'r': rx_port = atoi(optarg); break; case 't': tx_port = atoi(optarg); break; case 'f': strcpy(filename,optarg); break; case '?': printf("usage: ./test_rtp_client -i <IP_Addr> -r <rx_port> -t <tx_port> -f <filename>\n"); exit(1); } } if (optind < argc) { for(; optind < argc; optind++) { printf("error->%s(#%d): put -[i|r|t|f] \n", argv[optind],optind-1); } exit(1); } // display session information printf("\n-Session Information-\n"); printf(" ip_addr = %s\n", ip_addr); printf(" rx_port = %d\n", rx_port); printf(" tx_port = %d\n", tx_port); printf(" filename = %s\n", filename); printf("Press Return key..."); // getchar(); // Open Original File to compare with received file if((fd = open(filename, O_RDONLY)) == -1){ perror(filename); exit(1); } rtp_stream_params_t rsp; rtp_default_params(&rsp); rsp.rtp_addr = ip_addr; rsp.rtp_rx_port = rx_port; rsp.rtp_tx_port = tx_port; rsp.rtp_ttl = TTL; rsp.rtcp_bandwidth = RTCP_BW; rsp.rtp_callback = c_rtp_callback; rsp.transmit_initial_rtcp = 1; if ( (session = rtp_init_stream(&rsp) ) == NULL){ exit(-1); } rtp_set_my_ssrc(session,OUR_SSRC); #ifdef HAVE_SRTP /////////// start will //set NULL security services //uint32_t ssrc = 0xdeadbeef; /* ssrc value hardcoded for now */ srtp_policy_t policy; char key[64]; char keystr[128]; uint ix; #if 1 strcpy(keystr, "c1eec3717da76195bb878578790af71c4ee9f859e197a414a78d5abc7451"); hex_string_to_octet_string(key, keystr, 60); #else memset(key, 0, sizeof(key)); #endif for (ix = 0; ix < 30; ix++) { printf("%02x ", key[ix]); } printf("\n"); #if 0 // NULL cipher policy.key = (uint8_t *) key; policy.ssrc.type = ssrc_any_outbound; //ssrc_specific; policy.ssrc.value = 0x96;//OUR_SSRC; policy.rtp.cipher_type = NULL_CIPHER; policy.rtp.cipher_key_len = 0; policy.rtp.auth_type = NULL_AUTH; policy.rtp.auth_key_len = 0; policy.rtp.auth_tag_len = 0; policy.rtp.sec_serv = sec_serv_none; policy.rtcp.cipher_type = NULL_CIPHER; policy.rtcp.cipher_key_len = 0; policy.rtcp.auth_type = NULL_AUTH; policy.rtcp.auth_key_len = 0; policy.rtcp.auth_tag_len = 0; policy.rtcp.sec_serv = sec_serv_none; policy.next = NULL; #else //confidentiality only, no auth crypto_policy_set_aes_cm_128_null_auth(&policy.rtp); crypto_policy_set_rtcp_default(&policy.rtcp); policy.ssrc.type = ssrc_any_outbound; policy.key = (uint8_t *) key; policy.next = NULL; policy.rtp.sec_serv = sec_serv_conf;//sec_servs; policy.rtcp.sec_serv = sec_serv_none; /* we don't do RTCP anyway */ #endif err_status_t status; printf("ABOUT TO SRTP_INIT\n"); status = srtp_init(); if (status) { printf("error: srtp initialization failed with error code %d\n", status); exit(1); } printf("ABOUT TO SRTP_CREAT\n"); srtp_ctx_t *srtp_ctx = NULL; status = srtp_create(&srtp_ctx, &policy); if (status) { printf("error: srtp_create() failed with code %d\n", status); exit(1); } printf("DONE WITH SRTP_CREATE\n"); extra_len = 0; #else extra_len = 0; srtp_data = NULL; #endif rtp_encryption_params_t params; params.rtp_encrypt = ENCRYPT_FUNCTION; params.rtcp_encrypt = RTCP_ENCRYPT_FUNCTION; params.rtp_decrypt = DECRYPT_FUNCTION; params.rtcp_decrypt = RTCP_DECRYPT_FUNCTION; params.userdata = srtp_data; params.rtp_auth_alloc_extra = params.rtcp_auth_alloc_extra = 0; rtp_set_encryption_params(session, ¶ms); if (do_rtcp) { rtcp_file = fopen("server.rtcp", FOPEN_WRITE_BINARY); } cur_pos = 0; packet_size = 64; number_of_packet = 0; while(1) { // change BUFFSIZE to be an incrementing value from 64 to 1450 if(packet_size > 1450) packet_size = 725; readit = read(fd, buff, packet_size); if (readit < 0) { perror("file read"); exit(1); } read_size = readit; //int buflen = readit; if (read_size == 0) break; //printf("about to protect\n"); #if 0 sendit = rtp_send_data(session, cur_pos, 97,//pt 0,//m 0,//cc NULL, //csrc[], buff,//data read_size,//data_len NULL,//*extn 0, 0); #else { struct iovec iov[2]; iov[0].iov_len = read_size % 48; if (iov[0].iov_len == 0) iov[0].iov_len = 1; iov[0].iov_base = buff; iov[1].iov_len = read_size - iov[0].iov_len; iov[1].iov_base = buff + iov[0].iov_len; sendit = rtp_send_data_iov(session, cur_pos, 97, 0, 0, NULL, iov, read_size > iov[0].iov_len ? 2 : 1, NULL, 0, 0, 0); } #endif if (sendit < 0) { printf("rtp_send_data error\n"); exit(1); } if (do_rtcp) rtp_send_ctrl(session, cur_pos, NULL); printf("set timestamp = "U64", size %u\n", cur_pos, read_size); cur_pos += read_size; packet_size++; number_of_packet++; //rtp_periodic(); //rtp_send_ctrl(session,cur_pos,NULL); rtp_update(session); // Some sort of sleep here... usleep(2 * 1000); } printf("I've sent %d RTP packets!\n\n", number_of_packet); close(fd); if (rtcp_file != NULL) fclose(rtcp_file); rtp_done(session); return 0; }
/* * main() */ int main(int argc, char *argv[]) { pj_caching_pool cp; pjmedia_endpt *med_endpt; pj_pool_t *pool; pjmedia_vid_stream *stream = NULL; pjmedia_port *enc_port, *dec_port; pj_status_t status; pjmedia_vid_port *capture=NULL, *renderer=NULL; pjmedia_vid_port_param vpp; #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) /* SRTP variables */ pj_bool_t use_srtp = PJ_FALSE; char tmp_tx_key[64]; char tmp_rx_key[64]; pj_str_t srtp_tx_key = {NULL, 0}; pj_str_t srtp_rx_key = {NULL, 0}; pj_str_t srtp_crypto_suite = {NULL, 0}; int tmp_key_len; #endif /* Default values */ const pjmedia_vid_codec_info *codec_info; pjmedia_vid_codec_param codec_param; pjmedia_dir dir = PJMEDIA_DIR_DECODING; pj_sockaddr_in remote_addr; pj_uint16_t local_port = 4000; char *codec_id = NULL; pjmedia_rect_size tx_size = {0}; pj_int8_t rx_pt = -1, tx_pt = -1; play_file_data play_file = { NULL }; pjmedia_port *play_port = NULL; pjmedia_vid_codec *play_decoder = NULL; pjmedia_clock *play_clock = NULL; enum { OPT_CODEC = 'c', OPT_LOCAL_PORT = 'p', OPT_REMOTE = 'r', OPT_PLAY_FILE = 'f', OPT_SEND_RECV = 'b', OPT_SEND_ONLY = 's', OPT_RECV_ONLY = 'i', OPT_SEND_WIDTH = 'W', OPT_SEND_HEIGHT = 'H', OPT_RECV_PT = 't', OPT_SEND_PT = 'T', #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) OPT_USE_SRTP = 'S', #endif OPT_SRTP_TX_KEY = 'x', OPT_SRTP_RX_KEY = 'y', OPT_HELP = 'h', }; struct pj_getopt_option long_options[] = { { "codec", 1, 0, OPT_CODEC }, { "local-port", 1, 0, OPT_LOCAL_PORT }, { "remote", 1, 0, OPT_REMOTE }, { "play-file", 1, 0, OPT_PLAY_FILE }, { "send-recv", 0, 0, OPT_SEND_RECV }, { "send-only", 0, 0, OPT_SEND_ONLY }, { "recv-only", 0, 0, OPT_RECV_ONLY }, { "send-width", 1, 0, OPT_SEND_WIDTH }, { "send-height", 1, 0, OPT_SEND_HEIGHT }, { "recv-pt", 1, 0, OPT_RECV_PT }, { "send-pt", 1, 0, OPT_SEND_PT }, #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) { "use-srtp", 2, 0, OPT_USE_SRTP }, { "srtp-tx-key", 1, 0, OPT_SRTP_TX_KEY }, { "srtp-rx-key", 1, 0, OPT_SRTP_RX_KEY }, #endif { "help", 0, 0, OPT_HELP }, { NULL, 0, 0, 0 }, }; int c; int option_index; pj_bzero(&remote_addr, sizeof(remote_addr)); /* init PJLIB : */ status = pj_init(); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* Parse arguments */ pj_optind = 0; while((c=pj_getopt_long(argc,argv, "h", long_options, &option_index))!=-1) { switch (c) { case OPT_CODEC: codec_id = pj_optarg; break; case OPT_LOCAL_PORT: local_port = (pj_uint16_t) atoi(pj_optarg); if (local_port < 1) { printf("Error: invalid local port %s\n", pj_optarg); return 1; } break; case OPT_REMOTE: { pj_str_t ip = pj_str(strtok(pj_optarg, ":")); pj_uint16_t port = (pj_uint16_t) atoi(strtok(NULL, ":")); status = pj_sockaddr_in_init(&remote_addr, &ip, port); if (status != PJ_SUCCESS) { app_perror(THIS_FILE, "Invalid remote address", status); return 1; } } break; case OPT_PLAY_FILE: play_file.file_name = pj_optarg; break; case OPT_SEND_RECV: dir = PJMEDIA_DIR_ENCODING_DECODING; break; case OPT_SEND_ONLY: dir = PJMEDIA_DIR_ENCODING; break; case OPT_RECV_ONLY: dir = PJMEDIA_DIR_DECODING; break; case OPT_SEND_WIDTH: tx_size.w = (unsigned)atoi(pj_optarg); break; case OPT_SEND_HEIGHT: tx_size.h = (unsigned)atoi(pj_optarg); break; case OPT_RECV_PT: rx_pt = (pj_int8_t)atoi(pj_optarg); break; case OPT_SEND_PT: tx_pt = (pj_int8_t)atoi(pj_optarg); break; #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) case OPT_USE_SRTP: use_srtp = PJ_TRUE; if (pj_optarg) { pj_strset(&srtp_crypto_suite, pj_optarg, strlen(pj_optarg)); } else { srtp_crypto_suite = pj_str("AES_CM_128_HMAC_SHA1_80"); } break; case OPT_SRTP_TX_KEY: tmp_key_len = hex_string_to_octet_string(tmp_tx_key, pj_optarg, strlen(pj_optarg)); pj_strset(&srtp_tx_key, tmp_tx_key, tmp_key_len/2); break; case OPT_SRTP_RX_KEY: tmp_key_len = hex_string_to_octet_string(tmp_rx_key, pj_optarg, strlen(pj_optarg)); pj_strset(&srtp_rx_key, tmp_rx_key, tmp_key_len/2); break; #endif case OPT_HELP: usage(); return 1; default: printf("Invalid options %s\n", argv[pj_optind]); return 1; } } /* Verify arguments. */ if (dir & PJMEDIA_DIR_ENCODING) { if (remote_addr.sin_addr.s_addr == 0) { printf("Error: remote address must be set\n"); return 1; } } if (play_file.file_name != NULL && dir != PJMEDIA_DIR_ENCODING) { printf("Direction is set to --send-only because of --play-file\n"); dir = PJMEDIA_DIR_ENCODING; } #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) /* SRTP validation */ if (use_srtp) { if (!srtp_tx_key.slen || !srtp_rx_key.slen) { printf("Error: Key for each SRTP stream direction must be set\n"); return 1; } } #endif /* Must create a pool factory before we can allocate any memory. */ pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0); /* * Initialize media endpoint. * This will implicitly initialize PJMEDIA too. */ status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* Create memory pool for application purpose */ pool = pj_pool_create( &cp.factory, /* pool factory */ "app", /* pool name. */ 4000, /* init size */ 4000, /* increment size */ NULL /* callback on error */ ); /* Init video format manager */ pjmedia_video_format_mgr_create(pool, 64, 0, NULL); /* Init video converter manager */ pjmedia_converter_mgr_create(pool, NULL); /* Init event manager */ pjmedia_event_mgr_create(pool, 0, NULL); /* Init video codec manager */ pjmedia_vid_codec_mgr_create(pool, NULL); /* Init video subsystem */ pjmedia_vid_dev_subsys_init(&cp.factory); /* Register all supported codecs */ status = init_codecs(&cp.factory); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* Find which codec to use. */ if (codec_id) { unsigned count = 1; pj_str_t str_codec_id = pj_str(codec_id); status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL, &str_codec_id, &count, &codec_info, NULL); if (status != PJ_SUCCESS) { printf("Error: unable to find codec %s\n", codec_id); return 1; } } else { static pjmedia_vid_codec_info info[1]; unsigned count = PJ_ARRAY_SIZE(info); /* Default to first codec */ pjmedia_vid_codec_mgr_enum_codecs(NULL, &count, info, NULL); codec_info = &info[0]; } /* Get codec default param for info */ status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info, &codec_param); pj_assert(status == PJ_SUCCESS); /* Set outgoing video size */ if (tx_size.w && tx_size.h) codec_param.enc_fmt.det.vid.size = tx_size; #if DEF_RENDERER_WIDTH && DEF_RENDERER_HEIGHT /* Set incoming video size */ if (DEF_RENDERER_WIDTH > codec_param.dec_fmt.det.vid.size.w) codec_param.dec_fmt.det.vid.size.w = DEF_RENDERER_WIDTH; if (DEF_RENDERER_HEIGHT > codec_param.dec_fmt.det.vid.size.h) codec_param.dec_fmt.det.vid.size.h = DEF_RENDERER_HEIGHT; #endif if (play_file.file_name) { pjmedia_video_format_detail *file_vfd; pjmedia_clock_param clock_param; char fmt_name[5]; /* Create file player */ status = create_file_player(pool, play_file.file_name, &play_port); if (status != PJ_SUCCESS) goto on_exit; /* Collect format info */ file_vfd = pjmedia_format_get_video_format_detail(&play_port->info.fmt, PJ_TRUE); PJ_LOG(2, (THIS_FILE, "Reading video stream %dx%d %s @%.2ffps", file_vfd->size.w, file_vfd->size.h, pjmedia_fourcc_name(play_port->info.fmt.id, fmt_name), (1.0*file_vfd->fps.num/file_vfd->fps.denum))); /* Allocate file read buffer */ play_file.read_buf_size = PJMEDIA_MAX_VIDEO_ENC_FRAME_SIZE; play_file.read_buf = pj_pool_zalloc(pool, play_file.read_buf_size); /* Create decoder, if the file and the stream uses different codec */ if (codec_info->fmt_id != (pjmedia_format_id)play_port->info.fmt.id) { const pjmedia_video_format_info *dec_vfi; pjmedia_video_apply_fmt_param dec_vafp = {0}; const pjmedia_vid_codec_info *codec_info2; pjmedia_vid_codec_param codec_param2; /* Find decoder */ status = pjmedia_vid_codec_mgr_get_codec_info2(NULL, play_port->info.fmt.id, &codec_info2); if (status != PJ_SUCCESS) goto on_exit; /* Init decoder */ status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info2, &play_decoder); if (status != PJ_SUCCESS) goto on_exit; status = play_decoder->op->init(play_decoder, pool); if (status != PJ_SUCCESS) goto on_exit; /* Open decoder */ status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info2, &codec_param2); if (status != PJ_SUCCESS) goto on_exit; codec_param2.dir = PJMEDIA_DIR_DECODING; status = play_decoder->op->open(play_decoder, &codec_param2); if (status != PJ_SUCCESS) goto on_exit; /* Get decoder format info and apply param */ dec_vfi = pjmedia_get_video_format_info(NULL, codec_info2->dec_fmt_id[0]); if (!dec_vfi || !dec_vfi->apply_fmt) { status = PJ_ENOTSUP; goto on_exit; } dec_vafp.size = file_vfd->size; (*dec_vfi->apply_fmt)(dec_vfi, &dec_vafp); /* Allocate buffer to receive decoder output */ play_file.dec_buf_size = dec_vafp.framebytes; play_file.dec_buf = pj_pool_zalloc(pool, play_file.dec_buf_size); } /* Create player clock */ clock_param.usec_interval = PJMEDIA_PTIME(&file_vfd->fps); clock_param.clock_rate = codec_info->clock_rate; status = pjmedia_clock_create2(pool, &clock_param, PJMEDIA_CLOCK_NO_HIGHEST_PRIO, &clock_cb, &play_file, &play_clock); if (status != PJ_SUCCESS) goto on_exit; /* Override stream codec param for encoding direction */ codec_param.enc_fmt.det.vid.size = file_vfd->size; codec_param.enc_fmt.det.vid.fps = file_vfd->fps; } else { pjmedia_vid_port_param_default(&vpp); /* Set as active for all video devices */ vpp.active = PJ_TRUE; /* Create video device port. */ if (dir & PJMEDIA_DIR_ENCODING) { /* Create capture */ status = pjmedia_vid_dev_default_param( pool, PJMEDIA_VID_DEFAULT_CAPTURE_DEV, &vpp.vidparam); if (status != PJ_SUCCESS) goto on_exit; pjmedia_format_copy(&vpp.vidparam.fmt, &codec_param.enc_fmt); vpp.vidparam.fmt.id = codec_param.dec_fmt.id; vpp.vidparam.dir = PJMEDIA_DIR_CAPTURE; status = pjmedia_vid_port_create(pool, &vpp, &capture); if (status != PJ_SUCCESS) goto on_exit; } if (dir & PJMEDIA_DIR_DECODING) { /* Create renderer */ status = pjmedia_vid_dev_default_param( pool, PJMEDIA_VID_DEFAULT_RENDER_DEV, &vpp.vidparam); if (status != PJ_SUCCESS) goto on_exit; pjmedia_format_copy(&vpp.vidparam.fmt, &codec_param.dec_fmt); vpp.vidparam.dir = PJMEDIA_DIR_RENDER; vpp.vidparam.disp_size = vpp.vidparam.fmt.det.vid.size; vpp.vidparam.flags |= PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW_FLAGS; vpp.vidparam.window_flags = PJMEDIA_VID_DEV_WND_BORDER | PJMEDIA_VID_DEV_WND_RESIZABLE; status = pjmedia_vid_port_create(pool, &vpp, &renderer); if (status != PJ_SUCCESS) goto on_exit; } } /* Set to ignore fmtp */ codec_param.ignore_fmtp = PJ_TRUE; /* Create stream based on program arguments */ status = create_stream(pool, med_endpt, codec_info, &codec_param, dir, rx_pt, tx_pt, local_port, &remote_addr, #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) use_srtp, &srtp_crypto_suite, &srtp_tx_key, &srtp_rx_key, #endif &stream); if (status != PJ_SUCCESS) goto on_exit; /* Get the port interface of the stream */ status = pjmedia_vid_stream_get_port(stream, PJMEDIA_DIR_ENCODING, &enc_port); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); status = pjmedia_vid_stream_get_port(stream, PJMEDIA_DIR_DECODING, &dec_port); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* Start streaming */ status = pjmedia_vid_stream_start(stream); if (status != PJ_SUCCESS) goto on_exit; /* Start renderer */ if (renderer) { status = pjmedia_vid_port_connect(renderer, dec_port, PJ_FALSE); if (status != PJ_SUCCESS) goto on_exit; status = pjmedia_vid_port_start(renderer); if (status != PJ_SUCCESS) goto on_exit; } /* Start capture */ if (capture) { status = pjmedia_vid_port_connect(capture, enc_port, PJ_FALSE); if (status != PJ_SUCCESS) goto on_exit; status = pjmedia_vid_port_start(capture); if (status != PJ_SUCCESS) goto on_exit; } /* Start playing file */ if (play_file.file_name) { #if HAS_LOCAL_RENDERER_FOR_PLAY_FILE /* Create local renderer */ pjmedia_vid_port_param_default(&vpp); vpp.active = PJ_FALSE; status = pjmedia_vid_dev_default_param( pool, PJMEDIA_VID_DEFAULT_RENDER_DEV, &vpp.vidparam); if (status != PJ_SUCCESS) goto on_exit; vpp.vidparam.dir = PJMEDIA_DIR_RENDER; pjmedia_format_copy(&vpp.vidparam.fmt, &codec_param.dec_fmt); vpp.vidparam.fmt.det.vid.size = play_port->info.fmt.det.vid.size; vpp.vidparam.fmt.det.vid.fps = play_port->info.fmt.det.vid.fps; vpp.vidparam.disp_size = vpp.vidparam.fmt.det.vid.size; status = pjmedia_vid_port_create(pool, &vpp, &renderer); if (status != PJ_SUCCESS) goto on_exit; status = pjmedia_vid_port_start(renderer); if (status != PJ_SUCCESS) goto on_exit; #endif /* Init play file data */ play_file.play_port = play_port; play_file.stream_port = enc_port; play_file.decoder = play_decoder; if (renderer) { play_file.renderer = pjmedia_vid_port_get_passive_port(renderer); } status = pjmedia_clock_start(play_clock); if (status != PJ_SUCCESS) goto on_exit; } /* Done */ if (dir == PJMEDIA_DIR_DECODING) printf("Stream is active, dir is recv-only, local port is %d\n", local_port); else if (dir == PJMEDIA_DIR_ENCODING) printf("Stream is active, dir is send-only, sending to %s:%d\n", pj_inet_ntoa(remote_addr.sin_addr), pj_ntohs(remote_addr.sin_port)); else printf("Stream is active, send/recv, local port is %d, " "sending to %s:%d\n", local_port, pj_inet_ntoa(remote_addr.sin_addr), pj_ntohs(remote_addr.sin_port)); if (dir & PJMEDIA_DIR_ENCODING) PJ_LOG(2, (THIS_FILE, "Sending %dx%d %.*s @%.2ffps", codec_param.enc_fmt.det.vid.size.w, codec_param.enc_fmt.det.vid.size.h, codec_info->encoding_name.slen, codec_info->encoding_name.ptr, (1.0*codec_param.enc_fmt.det.vid.fps.num/ codec_param.enc_fmt.det.vid.fps.denum))); for (;;) { char tmp[10]; puts(""); puts("Commands:"); puts(" q Quit"); puts(""); printf("Command: "); fflush(stdout); if (fgets(tmp, sizeof(tmp), stdin) == NULL) { puts("EOF while reading stdin, will quit now.."); break; } if (tmp[0] == 'q') break; } /* Start deinitialization: */ on_exit: /* Stop and destroy file clock */ if (play_clock) { pjmedia_clock_stop(play_clock); pjmedia_clock_destroy(play_clock); } /* Destroy file reader/player */ if (play_port) pjmedia_port_destroy(play_port); /* Destroy file decoder */ if (play_decoder) { play_decoder->op->close(play_decoder); pjmedia_vid_codec_mgr_dealloc_codec(NULL, play_decoder); } /* Destroy video devices */ if (capture) pjmedia_vid_port_destroy(capture); if (renderer) pjmedia_vid_port_destroy(renderer); /* Destroy stream */ if (stream) { pjmedia_transport *tp; tp = pjmedia_vid_stream_get_transport(stream); pjmedia_vid_stream_destroy(stream); pjmedia_transport_close(tp); } /* Deinit codecs */ deinit_codecs(); /* Shutdown video subsystem */ pjmedia_vid_dev_subsys_shutdown(); /* Destroy event manager */ pjmedia_event_mgr_destroy(NULL); /* Release application pool */ pj_pool_release( pool ); /* Destroy media endpoint. */ pjmedia_endpt_destroy( med_endpt ); /* Destroy pool factory */ pj_caching_pool_destroy( &cp ); /* Shutdown PJLIB */ pj_shutdown(); return (status == PJ_SUCCESS) ? 0 : 1; }
/* * main() */ int main(int argc, char *argv[]) { pj_caching_pool cp; pjmedia_endpt *med_endpt; pj_pool_t *pool; pjmedia_port *rec_file_port = NULL, *play_file_port = NULL; pjmedia_master_port *master_port = NULL; pjmedia_snd_port *snd_port = NULL; pjmedia_stream *stream = NULL; pjmedia_port *stream_port; char tmp[10]; pj_status_t status; #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) /* SRTP variables */ pj_bool_t use_srtp = PJ_FALSE; char tmp_tx_key[64]; char tmp_rx_key[64]; pj_str_t srtp_tx_key = {NULL, 0}; pj_str_t srtp_rx_key = {NULL, 0}; pj_str_t srtp_crypto_suite = {NULL, 0}; int tmp_key_len; #endif /* Default values */ const pjmedia_codec_info *codec_info; pjmedia_codec_param codec_param; pjmedia_dir dir = PJMEDIA_DIR_DECODING; pj_sockaddr_in remote_addr; pj_uint16_t local_port = 4000; char *codec_id = NULL; char *rec_file = NULL; char *play_file = NULL; enum { OPT_CODEC = 'c', OPT_LOCAL_PORT = 'p', OPT_REMOTE = 'r', OPT_PLAY_FILE = 'w', OPT_RECORD_FILE = 'R', OPT_SEND_RECV = 'b', OPT_SEND_ONLY = 's', OPT_RECV_ONLY = 'i', #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) OPT_USE_SRTP = 'S', #endif OPT_SRTP_TX_KEY = 'x', OPT_SRTP_RX_KEY = 'y', OPT_HELP = 'h', }; struct pj_getopt_option long_options[] = { { "codec", 1, 0, OPT_CODEC }, { "local-port", 1, 0, OPT_LOCAL_PORT }, { "remote", 1, 0, OPT_REMOTE }, { "play-file", 1, 0, OPT_PLAY_FILE }, { "record-file", 1, 0, OPT_RECORD_FILE }, { "send-recv", 0, 0, OPT_SEND_RECV }, { "send-only", 0, 0, OPT_SEND_ONLY }, { "recv-only", 0, 0, OPT_RECV_ONLY }, #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) { "use-srtp", 2, 0, OPT_USE_SRTP }, { "srtp-tx-key", 1, 0, OPT_SRTP_TX_KEY }, { "srtp-rx-key", 1, 0, OPT_SRTP_RX_KEY }, #endif { "help", 0, 0, OPT_HELP }, { NULL, 0, 0, 0 }, }; int c; int option_index; pj_bzero(&remote_addr, sizeof(remote_addr)); /* init PJLIB : */ status = pj_init(); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* Parse arguments */ pj_optind = 0; while((c=pj_getopt_long(argc,argv, "h", long_options, &option_index))!=-1) { switch (c) { case OPT_CODEC: codec_id = pj_optarg; break; case OPT_LOCAL_PORT: local_port = (pj_uint16_t) atoi(pj_optarg); if (local_port < 1) { printf("Error: invalid local port %s\n", pj_optarg); return 1; } break; case OPT_REMOTE: { pj_str_t ip = pj_str(strtok(pj_optarg, ":")); pj_uint16_t port = (pj_uint16_t) atoi(strtok(NULL, ":")); status = pj_sockaddr_in_init(&remote_addr, &ip, port); if (status != PJ_SUCCESS) { app_perror(THIS_FILE, "Invalid remote address", status); return 1; } } break; case OPT_PLAY_FILE: play_file = pj_optarg; break; case OPT_RECORD_FILE: rec_file = pj_optarg; break; case OPT_SEND_RECV: dir = PJMEDIA_DIR_ENCODING_DECODING; break; case OPT_SEND_ONLY: dir = PJMEDIA_DIR_ENCODING; break; case OPT_RECV_ONLY: dir = PJMEDIA_DIR_DECODING; break; #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) case OPT_USE_SRTP: use_srtp = PJ_TRUE; if (pj_optarg) { pj_strset(&srtp_crypto_suite, pj_optarg, strlen(pj_optarg)); } else { srtp_crypto_suite = pj_str("AES_CM_128_HMAC_SHA1_80"); } break; case OPT_SRTP_TX_KEY: tmp_key_len = hex_string_to_octet_string(tmp_tx_key, pj_optarg, (int)strlen(pj_optarg)); pj_strset(&srtp_tx_key, tmp_tx_key, tmp_key_len/2); break; case OPT_SRTP_RX_KEY: tmp_key_len = hex_string_to_octet_string(tmp_rx_key, pj_optarg, (int)strlen(pj_optarg)); pj_strset(&srtp_rx_key, tmp_rx_key, tmp_key_len/2); break; #endif case OPT_HELP: usage(); return 1; default: printf("Invalid options %s\n", argv[pj_optind]); return 1; } } /* Verify arguments. */ if (dir & PJMEDIA_DIR_ENCODING) { if (remote_addr.sin_addr.s_addr == 0) { printf("Error: remote address must be set\n"); return 1; } } if (play_file != NULL && dir != PJMEDIA_DIR_ENCODING) { printf("Direction is set to --send-only because of --play-file\n"); dir = PJMEDIA_DIR_ENCODING; } #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) /* SRTP validation */ if (use_srtp) { if (!srtp_tx_key.slen || !srtp_rx_key.slen) { printf("Error: Key for each SRTP stream direction must be set\n"); return 1; } } #endif /* Must create a pool factory before we can allocate any memory. */ pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0); /* * Initialize media endpoint. * This will implicitly initialize PJMEDIA too. */ status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* Create memory pool for application purpose */ pool = pj_pool_create( &cp.factory, /* pool factory */ "app", /* pool name. */ 4000, /* init size */ 4000, /* increment size */ NULL /* callback on error */ ); /* Register all supported codecs */ status = init_codecs(med_endpt); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* Find which codec to use. */ if (codec_id) { unsigned count = 1; pj_str_t str_codec_id = pj_str(codec_id); pjmedia_codec_mgr *codec_mgr = pjmedia_endpt_get_codec_mgr(med_endpt); status = pjmedia_codec_mgr_find_codecs_by_id( codec_mgr, &str_codec_id, &count, &codec_info, NULL); if (status != PJ_SUCCESS) { printf("Error: unable to find codec %s\n", codec_id); return 1; } } else { /* Default to pcmu */ pjmedia_codec_mgr_get_codec_info( pjmedia_endpt_get_codec_mgr(med_endpt), 0, &codec_info); } /* Create stream based on program arguments */ status = create_stream(pool, med_endpt, codec_info, dir, local_port, &remote_addr, #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) use_srtp, &srtp_crypto_suite, &srtp_tx_key, &srtp_rx_key, #endif &stream); if (status != PJ_SUCCESS) goto on_exit; /* Get codec default param for info */ status = pjmedia_codec_mgr_get_default_param( pjmedia_endpt_get_codec_mgr(med_endpt), codec_info, &codec_param); /* Should be ok, as create_stream() above succeeded */ pj_assert(status == PJ_SUCCESS); /* Get the port interface of the stream */ status = pjmedia_stream_get_port( stream, &stream_port); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); if (play_file) { unsigned wav_ptime; wav_ptime = PJMEDIA_PIA_PTIME(&stream_port->info); status = pjmedia_wav_player_port_create(pool, play_file, wav_ptime, 0, -1, &play_file_port); if (status != PJ_SUCCESS) { app_perror(THIS_FILE, "Unable to use file", status); goto on_exit; } status = pjmedia_master_port_create(pool, play_file_port, stream_port, 0, &master_port); if (status != PJ_SUCCESS) { app_perror(THIS_FILE, "Unable to create master port", status); goto on_exit; } status = pjmedia_master_port_start(master_port); if (status != PJ_SUCCESS) { app_perror(THIS_FILE, "Error starting master port", status); goto on_exit; } printf("Playing from WAV file %s..\n", play_file); } else if (rec_file) { status = pjmedia_wav_writer_port_create(pool, rec_file, PJMEDIA_PIA_SRATE(&stream_port->info), PJMEDIA_PIA_CCNT(&stream_port->info), PJMEDIA_PIA_SPF(&stream_port->info), PJMEDIA_PIA_BITS(&stream_port->info), 0, 0, &rec_file_port); if (status != PJ_SUCCESS) { app_perror(THIS_FILE, "Unable to use file", status); goto on_exit; } status = pjmedia_master_port_create(pool, stream_port, rec_file_port, 0, &master_port); if (status != PJ_SUCCESS) { app_perror(THIS_FILE, "Unable to create master port", status); goto on_exit; } status = pjmedia_master_port_start(master_port); if (status != PJ_SUCCESS) { app_perror(THIS_FILE, "Error starting master port", status); goto on_exit; } printf("Recording to WAV file %s..\n", rec_file); } else { /* Create sound device port. */ if (dir == PJMEDIA_DIR_ENCODING_DECODING) status = pjmedia_snd_port_create(pool, -1, -1, PJMEDIA_PIA_SRATE(&stream_port->info), PJMEDIA_PIA_CCNT(&stream_port->info), PJMEDIA_PIA_SPF(&stream_port->info), PJMEDIA_PIA_BITS(&stream_port->info), 0, &snd_port); else if (dir == PJMEDIA_DIR_ENCODING) status = pjmedia_snd_port_create_rec(pool, -1, PJMEDIA_PIA_SRATE(&stream_port->info), PJMEDIA_PIA_CCNT(&stream_port->info), PJMEDIA_PIA_SPF(&stream_port->info), PJMEDIA_PIA_BITS(&stream_port->info), 0, &snd_port); else status = pjmedia_snd_port_create_player(pool, -1, PJMEDIA_PIA_SRATE(&stream_port->info), PJMEDIA_PIA_CCNT(&stream_port->info), PJMEDIA_PIA_SPF(&stream_port->info), PJMEDIA_PIA_BITS(&stream_port->info), 0, &snd_port); if (status != PJ_SUCCESS) { app_perror(THIS_FILE, "Unable to create sound port", status); goto on_exit; } /* Connect sound port to stream */ status = pjmedia_snd_port_connect( snd_port, stream_port ); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); } /* Start streaming */ pjmedia_stream_start(stream); /* Done */ if (dir == PJMEDIA_DIR_DECODING) printf("Stream is active, dir is recv-only, local port is %d\n", local_port); else if (dir == PJMEDIA_DIR_ENCODING) printf("Stream is active, dir is send-only, sending to %s:%d\n", pj_inet_ntoa(remote_addr.sin_addr), pj_ntohs(remote_addr.sin_port)); else printf("Stream is active, send/recv, local port is %d, " "sending to %s:%d\n", local_port, pj_inet_ntoa(remote_addr.sin_addr), pj_ntohs(remote_addr.sin_port)); for (;;) { puts(""); puts("Commands:"); puts(" s Display media statistics"); puts(" q Quit"); puts(""); printf("Command: "); fflush(stdout); if (fgets(tmp, sizeof(tmp), stdin) == NULL) { puts("EOF while reading stdin, will quit now.."); break; } if (tmp[0] == 's') print_stream_stat(stream, &codec_param); else if (tmp[0] == 'q') break; } /* Start deinitialization: */ on_exit: /* Destroy sound device */ if (snd_port) { pjmedia_snd_port_destroy( snd_port ); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); } /* If there is master port, then we just need to destroy master port * (it will recursively destroy upstream and downstream ports, which * in this case are file_port and stream_port). */ if (master_port) { pjmedia_master_port_destroy(master_port, PJ_TRUE); play_file_port = NULL; stream = NULL; } /* Destroy stream */ if (stream) { pjmedia_transport *tp; tp = pjmedia_stream_get_transport(stream); pjmedia_stream_destroy(stream); pjmedia_transport_close(tp); } /* Destroy file ports */ if (play_file_port) pjmedia_port_destroy( play_file_port ); if (rec_file_port) pjmedia_port_destroy( rec_file_port ); /* Release application pool */ pj_pool_release( pool ); /* Destroy media endpoint. */ pjmedia_endpt_destroy( med_endpt ); /* Destroy pool factory */ pj_caching_pool_destroy( &cp ); /* Shutdown PJLIB */ pj_shutdown(); return (status == PJ_SUCCESS) ? 0 : 1; }
int main (int argc, char *argv[]) { char errbuf[PCAP_ERRBUF_SIZE]; bpf_u_int32 pcap_net = 0; pcap_t *pcap_handle; #if BEW struct sockaddr_in local; #endif srtp_sec_serv_t sec_servs = sec_serv_none; int c; int key_size = 128; int tag_size = 8; int gcm_on = 0; char *input_key = NULL; int b64_input = 0; char key[MAX_KEY_LEN]; struct bpf_program fp; char filter_exp[MAX_FILTER] = ""; rtp_decoder_t dec; srtp_policy_t policy; srtp_err_status_t status; int len; int expected_len; int do_list_mods = 0; fprintf(stderr, "Using %s [0x%x]\n", srtp_get_version_string(), srtp_get_version()); /* initialize srtp library */ status = srtp_init(); if (status) { fprintf(stderr, "error: srtp initialization failed with error code %d\n", status); exit(1); } /* check args */ while (1) { c = getopt_s(argc, argv, "b:k:gt:ae:ld:f:"); if (c == -1) { break; } switch (c) { case 'b': b64_input = 1; /* fall thru */ case 'k': input_key = optarg_s; break; case 'e': key_size = atoi(optarg_s); if (key_size != 128 && key_size != 256) { fprintf(stderr, "error: encryption key size must be 128 or 256 (%d)\n", key_size); exit(1); } input_key = malloc(key_size); sec_servs |= sec_serv_conf; break; case 't': tag_size = atoi(optarg_s); if (tag_size != 8 && tag_size != 16) { fprintf(stderr, "error: GCM tag size must be 8 or 16 (%d)\n", tag_size); //exit(1); } break; case 'a': sec_servs |= sec_serv_auth; break; case 'g': gcm_on = 1; sec_servs |= sec_serv_auth; break; case 'd': status = srtp_crypto_kernel_set_debug_module(optarg_s, 1); if (status) { fprintf(stderr, "error: set debug module (%s) failed\n", optarg_s); exit(1); } break; case 'f': if(strlen(optarg_s) > MAX_FILTER){ fprintf(stderr, "error: filter bigger than %d characters\n", MAX_FILTER); exit(1); } fprintf(stderr, "Setting filter as %s\n", optarg_s); strcpy(filter_exp, optarg_s); break; case 'l': do_list_mods = 1; break; default: usage(argv[0]); } } if (do_list_mods) { status = srtp_crypto_kernel_list_debug_modules(); if (status) { fprintf(stderr, "error: list of debug modules failed\n"); exit(1); } return 0; } if ((sec_servs && !input_key) || (!sec_servs && input_key)) { /* * a key must be provided if and only if security services have * been requested */ if(input_key == NULL){ fprintf(stderr, "key not provided\n"); } if(!sec_servs){ fprintf(stderr, "no secservs\n"); } fprintf(stderr, "provided\n"); usage(argv[0]); } /* report security services selected on the command line */ fprintf(stderr, "security services: "); if (sec_servs & sec_serv_conf) fprintf(stderr, "confidentiality "); if (sec_servs & sec_serv_auth) fprintf(stderr, "message authentication"); if (sec_servs == sec_serv_none) fprintf(stderr, "none"); fprintf(stderr, "\n"); /* set up the srtp policy and master key */ if (sec_servs) { /* * create policy structure, using the default mechanisms but * with only the security services requested on the command line, * using the right SSRC value */ switch (sec_servs) { case sec_serv_conf_and_auth: if (gcm_on) { #ifdef OPENSSL switch (key_size) { case 128: srtp_crypto_policy_set_aes_gcm_128_8_auth(&policy.rtp); srtp_crypto_policy_set_aes_gcm_128_8_auth(&policy.rtcp); break; case 256: srtp_crypto_policy_set_aes_gcm_256_8_auth(&policy.rtp); srtp_crypto_policy_set_aes_gcm_256_8_auth(&policy.rtcp); break; } #else fprintf(stderr, "error: GCM mode only supported when using the OpenSSL crypto engine.\n"); return 0; #endif } else { switch (key_size) { case 128: srtp_crypto_policy_set_rtp_default(&policy.rtp); srtp_crypto_policy_set_rtcp_default(&policy.rtcp); break; case 256: srtp_crypto_policy_set_aes_cm_256_hmac_sha1_80(&policy.rtp); srtp_crypto_policy_set_rtcp_default(&policy.rtcp); break; } } break; case sec_serv_conf: if (gcm_on) { fprintf(stderr, "error: GCM mode must always be used with auth enabled\n"); return -1; } else { switch (key_size) { case 128: srtp_crypto_policy_set_aes_cm_128_null_auth(&policy.rtp); srtp_crypto_policy_set_rtcp_default(&policy.rtcp); break; case 256: srtp_crypto_policy_set_aes_cm_256_null_auth(&policy.rtp); srtp_crypto_policy_set_rtcp_default(&policy.rtcp); break; } } break; case sec_serv_auth: if (gcm_on) { #ifdef OPENSSL switch (key_size) { case 128: srtp_crypto_policy_set_aes_gcm_128_8_only_auth(&policy.rtp); srtp_crypto_policy_set_aes_gcm_128_8_only_auth(&policy.rtcp); break; case 256: srtp_crypto_policy_set_aes_gcm_256_8_only_auth(&policy.rtp); srtp_crypto_policy_set_aes_gcm_256_8_only_auth(&policy.rtcp); break; } #else printf("error: GCM mode only supported when using the OpenSSL crypto engine.\n"); return 0; #endif } else { srtp_crypto_policy_set_null_cipher_hmac_sha1_80(&policy.rtp); srtp_crypto_policy_set_rtcp_default(&policy.rtcp); } break; default: fprintf(stderr, "error: unknown security service requested\n"); return -1; } policy.key = (uint8_t *) key; policy.ekt = NULL; policy.next = NULL; policy.window_size = 128; policy.allow_repeat_tx = 0; policy.rtp.sec_serv = sec_servs; policy.rtcp.sec_serv = sec_servs; //sec_serv_none; /* we don't do RTCP anyway */ fprintf(stderr, "setting tag len %d\n", tag_size); policy.rtp.auth_tag_len = tag_size; if (gcm_on && tag_size != 8) { fprintf(stderr, "setted tag len %d\n", tag_size); policy.rtp.auth_tag_len = tag_size; } /* * read key from hexadecimal or base64 on command line into an octet string */ if (b64_input) { int pad; expected_len = policy.rtp.cipher_key_len*4/3; len = base64_string_to_octet_string(key, &pad, input_key, expected_len); if (pad != 0) { fprintf(stderr, "error: padding in base64 unexpected\n"); exit(1); } } else { expected_len = policy.rtp.cipher_key_len*2; len = hex_string_to_octet_string(key, input_key, expected_len); } /* check that hex string is the right length */ if (len < expected_len) { fprintf(stderr, "error: too few digits in key/salt " "(should be %d digits, found %d)\n", expected_len, len); exit(1); } if (strlen(input_key) > policy.rtp.cipher_key_len*2) { fprintf(stderr, "error: too many digits in key/salt " "(should be %d hexadecimal digits, found %u)\n", policy.rtp.cipher_key_len*2, (unsigned)strlen(input_key)); exit(1); } fprintf(stderr, "set master key/salt to %s/", octet_string_hex_string(key, 16)); fprintf(stderr, "%s\n", octet_string_hex_string(key+16, 14)); } else { fprintf(stderr, "error: neither encryption or authentication were selected"); exit(1); } pcap_handle = pcap_open_offline("-", errbuf); if (!pcap_handle) { fprintf(stderr, "libpcap failed to open file '%s'\n", errbuf); exit(1); } assert(pcap_handle != NULL); if ((pcap_compile(pcap_handle, &fp, filter_exp, 1, pcap_net)) == -1){ fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(pcap_handle)); return (2); } if (pcap_setfilter(pcap_handle, &fp) == -1){ fprintf(stderr, "couldn't install filter %s: %s\n", filter_exp, pcap_geterr(pcap_handle)); return (2); } dec = rtp_decoder_alloc(); if (dec == NULL) { fprintf(stderr, "error: malloc() failed\n"); exit(1); } fprintf(stderr, "Starting decoder\n"); rtp_decoder_init(dec, policy); pcap_loop(pcap_handle, 0, rtp_decoder_handle_pkt, (u_char *)dec); rtp_decoder_deinit_srtp(dec); rtp_decoder_dealloc(dec); status = srtp_shutdown(); if (status) { fprintf(stderr, "error: srtp shutdown failed with error code %d\n", status); exit(1); } return 0; }
/* * Here's the entry point */ int main (int argc, char *argv[]) { int sock; char *filenm = NULL; struct in_addr rcvr_addr; program_type prog_type = unknown; sec_serv_t sec_servs = sec_serv_conf | sec_serv_auth; int num_threads = 1; int c; char *input_key = NULL; char *address = NULL; char key[MAX_KEY_LEN]; unsigned short start_port = 0; srtp_policy_t *policy; err_status_t status; thread_parms_t *tplist[MAX_THREADS_SUPPORTED]; thread_parms_t *tp; int i; pthread_attr_t t_attr; struct sched_param sp1 = { 11 }; int len; int rc; /* initialize srtp library */ status = srtp_init(); if (status) { printf("error: srtp initialization failed with error code %d\n", status); exit(1); } /* check args */ while (1) { c = getopt(argc, argv, "k:n:o:rs"); if (c == -1) { break; } switch (c) { case 'n': num_threads = atoi(optarg); if (num_threads > MAX_THREADS_SUPPORTED) { printf("error: maximum number of threads supported is %d\n", MAX_THREADS_SUPPORTED); exit(1); } printf("Running %d threads\n", num_threads); break; case 'k': input_key = optarg; printf("Using key\n"); break; case 'o': filenm = optarg; printf("Using output file: %s\n", filenm); break; case 'r': prog_type = receiver; break; case 's': prog_type = sender; break; default: usage(argv[0]); } } if (prog_type == unknown) { printf("error: neither sender [-s] nor receiver [-r] specified\n"); usage(argv[0]); } if (!input_key) { /* * a key must be provided if and only if security services have * been requested */ usage(argv[0]); } if (argc != optind + 2) { /* wrong number of arguments */ usage(argv[0]); } /* get IP address from arg */ address = argv[optind++]; /* * read key from hexadecimal on command line into an octet string */ len = hex_string_to_octet_string(key, input_key, MASTER_KEY_LEN * 2); /* check that hex string is the right length */ if (len < MASTER_KEY_LEN * 2) { fprintf(stderr, "error: too few digits in key/salt " "(should be %d hexadecimal digits, found %d)\n", MASTER_KEY_LEN * 2, len); exit(1); } if (strlen(input_key) > MASTER_KEY_LEN * 2) { fprintf(stderr, "error: too many digits in key/salt " "(should be %d hexadecimal digits, found %u)\n", MASTER_KEY_LEN * 2, (unsigned)strlen(input_key)); exit(1); } printf("set master key/salt to %s/", octet_string_hex_string(key, 16)); printf("%s\n", octet_string_hex_string(key + 16, 14)); /* get starting port from arg */ start_port = atoi(argv[optind++]); /* set address */ rcvr_addr.s_addr = inet_addr(address); if (0xffffffff == rcvr_addr.s_addr) { fprintf(stderr, "%s: cannot parse IP v4 address %s\n", argv[0], address); exit(1); } if (ADDR_IS_MULTICAST(rcvr_addr.s_addr)) { printf("\nMulticast addresses not supported\n"); exit(1); } if (prog_type == receiver && filenm != NULL) { output = fopen(filenm, "wa"); if (output == NULL) { printf("\nUnable to open output file.\n"); exit(1); } } else { output = stdout; } /* * Setup and kick-off each thread. Each thread will be either * a receiver or a sender, depending on the arguments passed to us */ for (i = 0; i < num_threads; i++) { /* open socket */ sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (sock < 0) { int err; err = errno; fprintf(stderr, "%s: couldn't open socket: %d\n", argv[0], err); exit(1); } /* * Create an SRTP policy */ policy = malloc(sizeof(srtp_policy_t)); if (policy == NULL) { fprintf(stderr, "Unable to malloc\n"); exit(1); } crypto_policy_set_rtp_default(&policy->rtp); crypto_policy_set_rtcp_default(&policy->rtcp); policy->ssrc.type = ssrc_specific; policy->ssrc.value = SSRC_BASE; policy->key = (uint8_t*)key; policy->next = NULL; policy->rtp.sec_serv = sec_servs; policy->rtcp.sec_serv = sec_serv_none; /* we don't do RTCP anyway */ /* * Create a thread_parms_t instance to manage this thread */ tplist[i] = malloc(sizeof(thread_parms_t)); if (tplist[i] == NULL) { fprintf(stderr, "Unable to malloc\n"); exit(1); } tp = tplist[i]; tp->thread_num = i; tp->sock = sock; tp->port = start_port + i; tp->policy = policy; tp->name.sin_addr = rcvr_addr; tp->name.sin_family = PF_INET; tp->name.sin_port = htons(start_port + i); tp->ssrc = SSRC_BASE; tp->stream_cnt = NUM_SSRC_PER_THREAD; //Number of streams to create for the session /* * Setup the pthread attributes */ pthread_attr_init(&t_attr); pthread_attr_setschedparam(&t_attr, &sp1); pthread_attr_setschedpolicy(&t_attr, SCHED_RR); if (prog_type == sender) { /* * Start a sender thread */ rc = pthread_create(&tp->thread_id, &t_attr, sender_thread, tp); if (rc) { fprintf(stderr, "Unable to create thread\n"); exit(1); } } else { /* prog_type == receiver */ /* * Start a receiver thread */ rc = pthread_create(&tp->thread_id, &t_attr, receiver_thread, tp); if (rc) { fprintf(stderr, "Unable to create thread\n"); exit(1); } } /* * Clean-up the attributes */ pthread_attr_destroy(&t_attr); } /* * Wait for all threads to finish */ for (i = 0; i < num_threads; i++) { void *res; tp = tplist[i]; pthread_join(tp->thread_id, &res); close(tplist[i]->sock); free(tplist[i]->policy); free(tplist[i]); } /* * If we don't call this, we get a memory leak in the * libsrtp libary */ status = srtp_shutdown(); if (status) { printf("error: srtp shutdown failed with error code %d\n", status); exit(1); } return (0); }