diff --git a/CHANGELOG.TXT b/CHANGELOG.TXT index ff7ed11..e3ff3a2 100644 --- a/CHANGELOG.TXT +++ b/CHANGELOG.TXT @@ -1,10 +1,18 @@ This file tracks changes responsible for version number updates. 3.2.18 xx-xx-xx -Fix .xml stripping from scenario file parameter (-sf) -Set deadcall_time to 0 with -mc by default -Improved error/trace/debug logs associated with exec and raw socket failure -Support RTP playback from cooked format (in prepare_pcap) -Optimize load of SIPp with large files (strstr replaced) +- Add many SSL enhancements +- When there is a nop SIPp is forced into client mode, for TLS default to server mode. Also default to port 5061 for TLS. +- Make SIPp able to use the certificates in the directory in which sipp is being run from by using "SIPPED" environment variable to check direction sipp is in, as well as continuing to support certificates in the current directory. +- Add -force_client_mode and -fcm to force client mode. Also added -force_server_mode/-fsm to force server mode. +- Better error message when recieves response while expecting request. +- Fix 'assertion failure when aa in forced client mode' bug [happens when incoming TCP connection is established, handled with auto-answer, but the code 'expects' to be in server mode.] If sipp trys to autorespond without a socket set up for the current call (like in the case above), sipp tries sending back on the last socket open (which should be the port opened to send the unexpected message in the first place). +- Fix RTP playback from correct IP on multi-homed machiens (bind rtp socket to media_ip). +- Fix crash when no scenario is specified (ie neither -sf nor -sn) +- Fix .xml stripping from scenario file parameter (-sf) +- Set deadcall_time to 0 with -mc by default +- Improved error/trace/debug logs associated with exec and raw socket failure +- Support RTP playback from cooked format (in prepare_pcap) +- Optimize load of SIPp with large files (strstr replaced) 3.2.17 09-09-2011 - Encoding attribute for DialogSpecific keywords diff --git a/call.cpp b/call.cpp index ecf50b2..6b42eeb 100644 --- a/call.cpp +++ b/call.cpp @@ -230,7 +230,7 @@ void call::get_remote_media_addr(char *msg) { (_RCAST(struct sockaddr_in6 *, &(play_args_a.to)))->sin6_flowinfo = 0; (_RCAST(struct sockaddr_in6 *, &(play_args_a.to)))->sin6_scope_id = 0; (_RCAST(struct sockaddr_in6 *, &(play_args_a.to)))->sin6_family = AF_INET6; - (_RCAST(struct sockaddr_in6 *, &(play_args_a.to)))->sin6_port = audio_port; + (_RCAST(struct sockaddr_in6 *, &(play_args_a.to)))->sin6_port = htons(audio_port); (_RCAST(struct sockaddr_in6 *, &(play_args_a.to)))->sin6_addr = ip_media; } video_port = get_remote_port_media(msg, PAT_VIDEO); @@ -239,7 +239,7 @@ void call::get_remote_media_addr(char *msg) { (_RCAST(struct sockaddr_in6 *, &(play_args_v.to)))->sin6_flowinfo = 0; (_RCAST(struct sockaddr_in6 *, &(play_args_v.to)))->sin6_scope_id = 0; (_RCAST(struct sockaddr_in6 *, &(play_args_v.to)))->sin6_family = AF_INET6; - (_RCAST(struct sockaddr_in6 *, &(play_args_v.to)))->sin6_port = video_port; + (_RCAST(struct sockaddr_in6 *, &(play_args_v.to)))->sin6_port = htons(video_port); (_RCAST(struct sockaddr_in6 *, &(play_args_v.to)))->sin6_addr = ip_media; } hasMediaInformation = 1; @@ -253,14 +253,14 @@ void call::get_remote_media_addr(char *msg) { if (audio_port) { /* We have audio in the SDP: set the to_audio addr */ (_RCAST(struct sockaddr_in *, &(play_args_a.to)))->sin_family = AF_INET; - (_RCAST(struct sockaddr_in *, &(play_args_a.to)))->sin_port = audio_port; + (_RCAST(struct sockaddr_in *, &(play_args_a.to)))->sin_port = htons(audio_port); (_RCAST(struct sockaddr_in *, &(play_args_a.to)))->sin_addr.s_addr = ip_media; } video_port = get_remote_port_media(msg, PAT_VIDEO); if (video_port) { /* We have video in the SDP: set the to_video addr */ (_RCAST(struct sockaddr_in *, &(play_args_v.to)))->sin_family = AF_INET; - (_RCAST(struct sockaddr_in *, &(play_args_v.to)))->sin_port = video_port; + (_RCAST(struct sockaddr_in *, &(play_args_v.to)))->sin_port = htons(video_port); (_RCAST(struct sockaddr_in *, &(play_args_v.to)))->sin_addr.s_addr = ip_media; } hasMediaInformation = 1; @@ -512,17 +512,19 @@ void call::init(scenario * call_scenario, struct sipp_socket *socket, struct soc memset(&(play_args_a.to), 0, sizeof(struct sockaddr_storage)); memset(&(play_args_v.to), 0, sizeof(struct sockaddr_storage)); memset(&(play_args_a.from), 0, sizeof(struct sockaddr_storage)); - if (media_ip_is_ipv6) { - inet_pton(AF_INET, local_ip, (void *)&(_RCAST(struct sockaddr_in6 *, &(play_args_a.from)))->sin6_addr); - } else { - (_RCAST(struct sockaddr_in *, &(play_args_a.from)))->sin_addr.s_addr = inet_addr(local_ip); - } memset(&(play_args_v.from), 0, sizeof(struct sockaddr_storage)); + + // Store IP in audio and video structure from for use in send_packets: if (media_ip_is_ipv6) { - inet_pton(AF_INET, local_ip, (void *)&(_RCAST(struct sockaddr_in6 *, &(play_args_a.from)))->sin6_addr); + inet_pton(AF_INET, media_ip, (void *)&(_RCAST(struct sockaddr_in6 *, &(play_args_a.from)))->sin6_addr); + inet_pton(AF_INET, media_ip, (void *)&(_RCAST(struct sockaddr_in6 *, &(play_args_v.from)))->sin6_addr); } else { - (_RCAST(struct sockaddr_in *, &(play_args_v.from)))->sin_addr.s_addr = inet_addr(local_ip); + (_RCAST(struct sockaddr_in *, &(play_args_a.from)))->sin_addr.s_addr = inet_addr(media_ip); + (_RCAST(struct sockaddr_in *, &(play_args_v.from)))->sin_addr.s_addr = inet_addr(media_ip); + (_RCAST(struct sockaddr_in *, &(play_args_a.from)))->sin_family = AF_INET; + (_RCAST(struct sockaddr_in *, &(play_args_v.from)))->sin_family = AF_INET; } + hasMediaInformation = 0; for (int i=0; igetActionType() == CAction::E_AT_PLAY_PCAP_AUDIO) { DEBUG("getActionType() is E_AT_PLAY_PCAP_AUDIO"); play_args = &(this->play_args_a); - if (currentAction->getMediaPortOffset()) this->set_audio_port(media_port + currentAction->getMediaPortOffset()); + if (currentAction->getMediaPortOffset()) { + this->set_audio_from_port(media_port + currentAction->getMediaPortOffset()); + } } else if (currentAction->getActionType() == CAction::E_AT_PLAY_PCAP_VIDEO) { DEBUG("getActionType() is E_AT_PLAY_PCAP_VIDEO"); play_args = &(this->play_args_v); - if (currentAction->getMediaPortOffset()) this->set_video_port(media_port + currentAction->getMediaPortOffset()); + if (currentAction->getMediaPortOffset()) { + this->set_video_from_port(media_port + currentAction->getMediaPortOffset()); + } } play_args->pcap = currentAction->getPcapPkts(); /* port number is set in [auto_]media_port interpolation*/ @@ -4431,14 +4437,16 @@ call::T_ActionResult call::executeAction(char * msg, message *curmsg) from->sin_family = AF_INET; from->sin_addr.s_addr = inet_addr(media_ip); } + /* Create a thread to send RTP packets */ pthread_attr_t attr; pthread_attr_init(&attr); #ifndef PTHREAD_STACK_MIN #define PTHREAD_STACK_MIN 16384 #endif - if (number_of_active_rtp_threads >= MAXIMUM_NUMBER_OF_RTP_MEDIA_THREADS-1) + if (number_of_active_rtp_threads >= MAXIMUM_NUMBER_OF_RTP_MEDIA_THREADS-1) { ERROR("Trying to play too many concurrent media threads. Current maximum is %d.", MAXIMUM_NUMBER_OF_RTP_MEDIA_THREADS); + } int ret = pthread_create(&media_threads[number_of_active_rtp_threads++], &attr, send_wrapper, (void *) play_args); if(ret) @@ -4738,21 +4746,21 @@ void call::free_dialogState() { } #ifdef PCAPPLAY -void call::set_audio_port(int port){ +void call::set_audio_from_port(int port){ DEBUG("Setting audio port to %d", port); if (media_ip_is_ipv6) { - (_RCAST(struct sockaddr_in6 *, &(play_args_a.from)))->sin6_port = port; + (_RCAST(struct sockaddr_in6 *, &(play_args_a.from)))->sin6_port = htons(port); } else { - (_RCAST(struct sockaddr_in *, &(play_args_a.from)))->sin_port = port; + (_RCAST(struct sockaddr_in *, &(play_args_a.from)))->sin_port = htons(port); } } -void call::set_video_port(int port){ +void call::set_video_from_port(int port){ DEBUG("Setting video port to %d", port); if (media_ip_is_ipv6) { - (_RCAST(struct sockaddr_in6 *, &(play_args_v.from)))->sin6_port = port; + (_RCAST(struct sockaddr_in6 *, &(play_args_v.from)))->sin6_port = htons(port); } else { - (_RCAST(struct sockaddr_in *, &(play_args_v.from)))->sin_port = port; + (_RCAST(struct sockaddr_in *, &(play_args_v.from)))->sin_port = htons(port); } } #endif diff --git a/call.hpp b/call.hpp index 74ea0a7..1047a32 100644 --- a/call.hpp +++ b/call.hpp @@ -181,8 +181,8 @@ class call : virtual public task, virtual public listener, public virtual socket int number_of_active_rtp_threads; play_args_t play_args_a; play_args_t play_args_v; - void set_audio_port(int port); - void set_video_port(int port); + void set_audio_from_port(int port); + void set_video_from_port(int port); #endif @@ -249,7 +249,7 @@ class call : virtual public task, virtual public listener, public virtual socket double get_rhs(CAction *currentAction); -// *** meothods that operate on default or specfied msg_index *** +// *** methods that operate on default or specfied msg_index *** // Return true if use_txn specified for currently indexed message bool use_txn(int index=-1); diff --git a/prepare_pcap.c b/prepare_pcap.c index f1066f2..5658d67 100644 --- a/prepare_pcap.c +++ b/prepare_pcap.c @@ -190,7 +190,7 @@ int prepare_pkts(char *file, pcap_pkts *pkts) { pktlen = (u_long) pkthdr->len - sizeof(*ethhdr) - sizeof(*iphdr); #else udphdr = (struct udphdr *)((char *)iphdr + (iphdr->ihl << 2)); - pktlen = (u_long)(ntohs(udphdr->len)); + pktlen = (u_long)(ntohs(udphdr->len)-(sizeof(struct udphdr))); #endif } if (pktlen > PCAP_MAXPACKET) { @@ -205,7 +205,8 @@ int prepare_pkts(char *file, pcap_pkts *pkts) { pkt_index->data = (unsigned char *) malloc(pktlen); if (!pkt_index->data) ERROR("Can't allocate memory for pcap pkt data"); - memcpy(pkt_index->data, udphdr, pktlen); + // copy data, skipping over udp header itself + memcpy(pkt_index->data, (char *)udphdr+(sizeof(struct udphdr)), pktlen); #if defined(__HPUX) || defined(__DARWIN) || (defined __CYGWIN) || defined(__FreeBSD__) udphdr->uh_sum = 0 ; diff --git a/send_packets.c b/send_packets.c index f1fa9d1..e169a7f 100644 --- a/send_packets.c +++ b/send_packets.c @@ -118,19 +118,19 @@ send_packets (play_args_t * play_args) { int ret, sock, port_diff; pcap_pkt *pkt_index, *pkt_max; - uint16_t *from_port, *to_port; struct timeval didsleep = { 0, 0 }; struct timeval start = { 0, 0 }; struct timeval last = { 0, 0 }; pcap_pkts *pkts = play_args->pcap; int allow_ports_to_change = 0; /* may be exposed at later date */ struct sockaddr_storage *to, *from, to_struct, from_struct; - struct udphdr *udp; struct sockaddr_in6 to6, from6; char buffer[PCAP_MAXPACKET]; int temp_sum; + int result = 0; if(allow_ports_to_change) { + // For now, never possible. to = &play_args -> to; from = &play_args -> from; } else { @@ -142,30 +142,55 @@ send_packets (play_args_t * play_args) #ifndef MSG_DONTWAIT int fd_flags; #endif + DEBUG_IN(); if (media_ip_is_ipv6) { - sock = socket(PF_INET6, SOCK_RAW, IPPROTO_UDP); + sock = socket(PF_INET6, SOCK_DGRAM, 0); if (sock < 0) { - ERROR("Can't create raw socket (need to run as root/Administrator and/or lower your Windows 7 User Account Settings?)"); + ERROR_NO("Can't create raw socket (need to run as root/Administrator and/or lower your Windows 7 User Account Settings?)"); } - from_port = &(((struct sockaddr_in6 *)(void *) from )->sin6_port); - to_port = &(((struct sockaddr_in6 *)(void *) to )->sin6_port); + DEBUG("IPv6 from_port = %hu, from_addr = 0x%x, to_port = %hu, to_addr = 0x%x", + ntohs(((struct sockaddr_in6 *)(void *) from )->sin6_port), + ((struct sockaddr_in6 *)(void *) from )->sin6_addr.s6_addr, + ntohs(((struct sockaddr_in6 *)(void *) to )->sin6_port), + ((struct sockaddr_in6 *)(void *) to )->sin6_addr.s6_addr); } else { - sock = socket(PF_INET, SOCK_RAW, IPPROTO_UDP); + sock = socket(PF_INET, SOCK_DGRAM, 0); if (sock < 0) { - ERROR("Can't create raw socket (need to run as root/Administrator and/or lower your Windows 7 User Account Settings?)"); + ERROR_NO("Can't create raw socket (need to run as root/Administrator and/or lower your Windows 7 User Account Settings?)"); } - from_port = &(((struct sockaddr_in *)(void *) from )->sin_port); - to_port = &(((struct sockaddr_in *)(void *) to )->sin_port); + DEBUG("IPv4 from_port = %hu, from_addr = 0x%x, to_port = %hu, to_addr = 0x%x", + ntohs(((struct sockaddr_in *)(void *) from )->sin_port), + ((struct sockaddr_in *)(void *) from )->sin_addr.s_addr, + ntohs(((struct sockaddr_in *)(void *) to )->sin_port), + ((struct sockaddr_in *)(void *) to )->sin_addr.s_addr); + } + int sock_opt = 1; + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&sock_opt, sizeof (sock_opt)) == -1) { + ERROR_NO("setsockopt(sock, SO_REUSEADDR) failed"); } + if (!media_ip_is_ipv6) { + if (bind(sock, (struct sockaddr *) from, sizeof(struct sockaddr_in)) < 0){ + char ip[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &(((struct sockaddr_in *) from)->sin_addr), ip, INET_ADDRSTRLEN); + ERROR_NO("Could not bind RTP traffic socket to %s:%hu", ip, ntohs(((struct sockaddr_in *) from)->sin_port)); + } + } + else { + if(bind(sock, (struct sockaddr *) from, sizeof(struct sockaddr_in6)) < 0){ + char ip[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &(((struct sockaddr_in6 *) from)->sin6_addr), ip, INET_ADDRSTRLEN); + ERROR_NO("Could not bind socket to send RTP traffic %s:%hu", ip, ntohs(((struct sockaddr_in6 *)from )->sin6_port)); + } + } + #ifndef MSG_DONTWAIT fd_flags = fcntl(sock, F_GETFL , NULL); fd_flags |= O_NONBLOCK; fcntl(sock, F_SETFL , fd_flags); #endif - udp = (struct udphdr *)buffer; pkt_index = pkts->pkts; pkt_max = pkts->max; @@ -178,51 +203,18 @@ send_packets (play_args_t * play_args) memcpy(&(to6.sin6_addr.s6_addr), &(((struct sockaddr_in6 *)(void *) to)->sin6_addr.s6_addr), sizeof(to6.sin6_addr.s6_addr)); memcpy(&(from6.sin6_addr.s6_addr), &(((struct sockaddr_in6 *)(void *) from)->sin6_addr.s6_addr), sizeof(from6.sin6_addr.s6_addr)); } - + /* Ensure the sender socket is closed when the thread exits - this * allows the thread to be cancelled cleanly. */ pthread_cleanup_push(send_packets_cleanup, ((void *) sock)); - while (pkt_index < pkt_max) { - memcpy(udp, pkt_index->data, pkt_index->pktlen); - port_diff = ntohs (udp->uh_dport) - pkts->base; - // modify UDP ports - udp->uh_sport = htons(port_diff + *from_port); - udp->uh_dport = htons(port_diff + *to_port); - - if (!media_ip_is_ipv6) { - temp_sum = checksum_carry(pkt_index->partial_check + check((u_int16_t *) &(((struct sockaddr_in *)(void *) from)->sin_addr.s_addr), 4) + check((u_int16_t *) &(((struct sockaddr_in *)(void *) to)->sin_addr.s_addr), 4) + check((u_int16_t *) &udp->uh_sport, 4)); - } - else { - temp_sum = checksum_carry(pkt_index->partial_check + check((u_int16_t *) &(from6.sin6_addr.s6_addr), 16) + check((u_int16_t *) &(to6.sin6_addr.s6_addr), 16) + check((u_int16_t *) &udp->uh_sport, 4)); - } - -#ifndef _HPUX_LI -#ifdef __HPUX - udp->uh_sum = (temp_sum>>16)+((temp_sum & 0xffff)<<16); -#else - udp->uh_sum = temp_sum; -#endif -#else - udp->uh_sum = temp_sum; -#endif + memcpy(buffer, pkt_index->data, pkt_index->pktlen); do_sleep ((struct timeval *) &pkt_index->ts, &last, &didsleep, &start); - if (!media_ip_is_ipv6) { - if(bind(sock, (struct sockaddr *) from, sizeof(struct sockaddr_in)) < 0){ - ERROR("Could not bind local port to send RTP traffic."); - } - ret = sendto(sock, buffer, pkt_index->pktlen, 0, (struct sockaddr *)(void *) to, sizeof(struct sockaddr_in)); - } - else { - if(bind(sock, (struct sockaddr *) from, sizeof(struct sockaddr_in6)) < 0){ - ERROR("Could not bind local port to send RTP traffic."); - } - ret = sendto(sock, buffer, pkt_index->pktlen, 0, (struct sockaddr *)(void *) &to6, sizeof(struct sockaddr_in6)); - } + #ifdef MSG_DONTWAIT if (!media_ip_is_ipv6) { ret = sendto(sock, buffer, pkt_index->pktlen, MSG_DONTWAIT, (struct sockaddr *)(void *) to, sizeof(struct sockaddr_in)); @@ -239,20 +231,21 @@ send_packets (play_args_t * play_args) } #endif if (ret < 0) { - close(sock); - WARNING("send_packets.c: sendto failed with error: %s", strerror(errno)); - return( -1); + WARNING("send_packets.c: sendto failed with error: %s (sock = %d)", strerror(errno), sock); + result = -1; + break; // Can not return directly because of pthread_cleanup_push/pop's use of { and } } rtp_pckts_pcap++; - rtp_bytes_pcap += pkt_index->pktlen - sizeof(*udp); + rtp_bytes_pcap += pkt_index->pktlen; memcpy (&last, &(pkt_index->ts), sizeof (struct timeval)); pkt_index++; } /* Closing the socket is handled by pthread_cleanup_push()/pthread_cleanup_pop() */ pthread_cleanup_pop(1); - return 0; + DEBUG_OUT(); + return result; } /* diff --git a/sipp.cpp b/sipp.cpp index 728a20f..d911e73 100644 --- a/sipp.cpp +++ b/sipp.cpp @@ -4100,17 +4100,26 @@ struct sipp_socket *sipp_accept_socket(struct sipp_socket *accept_socket) { int sipp_bind_socket(struct sipp_socket *socket, struct sockaddr_storage *saddr, int *port) { int ret; int len; + char ip_and_port[INET6_ADDRSTRLEN+10]; DEBUG_IN(); if (socket->ss_ipv6) { len = sizeof(struct sockaddr_in6); + char ip[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &(((struct sockaddr_in6 *) saddr)->sin6_addr), ip, INET_ADDRSTRLEN); + sprintf(ip_and_port, "%s:%hu", ip, ntohs(((struct sockaddr_in6 *)saddr )->sin6_port)); } else { len = sizeof(struct sockaddr_in); + char ip[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &(((struct sockaddr_in *) saddr)->sin_addr), ip, INET_ADDRSTRLEN); + sprintf(ip_and_port, "%s:%hu", ip, ntohs(((struct sockaddr_in *) saddr)->sin_port)); } if((ret = bind(socket->ss_fd, (sockaddr *)saddr, len))) { + DEBUG("Could not bind socket to %s (%d: %s)", ip_and_port, errno, strerror(errno)); return ret; } + DEBUG("Bound socket to %s", ip_and_port); if (!port) { return 0; @@ -4268,7 +4277,7 @@ int main(int argc, char *argv[]) "Use 'sipp -h' for details", argv[argi - 1]); } #define CHECK_PASS() if (option->pass != pass) { break; } - int default_scenario_to_use; // -1 indicates non-default scenario + int default_scenario_to_use = -2; // -1 indicates non-default scenario ; -2 indicates none specified for (int pass = 0; pass <= 3; pass++) { for(argi = 1; argi < argc; argi++) { @@ -4579,22 +4588,22 @@ int main(int argc, char *argv[]) strcpy(twinSippHost, argv[argi]); get_host_and_port(twinSippHost, twinSippHost, &twinSippPort); break; - case SIPP_OPTION_SCENARIO: - REQUIRE_ARG(); - CHECK_PASS(); - if (!strcmp(argv[argi - 1], "-sf")) { - scenario_file = new char [strlen(argv[argi])+1] ; - sprintf(scenario_file,"%s", argv[argi]); - if (useLogf == 1) { - rotate_logfile(); - } - default_scenario_to_use = -1; - } else if (!strcmp(argv[argi - 1], "-sn")) { - int i = find_scenario(argv[argi]); + case SIPP_OPTION_SCENARIO: + REQUIRE_ARG(); + CHECK_PASS(); + if (!strcmp(argv[argi - 1], "-sf")) { + scenario_file = new char [strlen(argv[argi])+1] ; + sprintf(scenario_file,"%s", argv[argi]); + if (useLogf == 1) { + rotate_logfile(); + } + default_scenario_to_use = -1; + } else if (!strcmp(argv[argi - 1], "-sn")) { + int i = find_scenario(argv[argi]); - scenario_file = new char [strlen(argv[argi])+1] ; - sprintf(scenario_file,"%s", argv[argi]); - default_scenario_to_use = i; + scenario_file = new char [strlen(argv[argi])+1] ; + sprintf(scenario_file,"%s", argv[argi]); + default_scenario_to_use = i; } else if (!strcmp(argv[argi - 1], "-sd")) { int i = find_scenario(argv[argi]); fprintf(stdout, "%s", default_scenario[i]); @@ -4831,6 +4840,10 @@ int main(int argc, char *argv[]) lose_packets = 1; } + if (default_scenario_to_use == -2) { + ERROR("You must specify a scenario (for example with -sf or -sn parameters)"); + } + /* trace file setting */ if (scenario_file == NULL) { scenario_file = new char [ 5 ] ; @@ -5083,41 +5096,57 @@ int main(int argc, char *argv[]) media_ip_is_ipv6 = false; } - /* Always create and Bind RTP socket */ - /* to avoid ICMP */ -// if (1) { - /* retrieve RTP local addr */ - struct addrinfo hints; - struct addrinfo * local_addr; + /* retrieve RTP local addr */ + struct addrinfo hints; + struct addrinfo * local_addr; - memset((char*)&hints, 0, sizeof(hints)); - hints.ai_flags = AI_PASSIVE; - hints.ai_family = PF_UNSPEC; + memset((char*)&hints, 0, sizeof(hints)); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = PF_UNSPEC; - /* Resolving local IP */ - if (getaddrinfo(media_ip, - NULL, - &hints, - &local_addr) != 0) { - ERROR("Unknown RTP address '%s'.\n" - "Use 'sipp -h' for details", media_ip); - } - - memset(&media_sockaddr,0,sizeof(struct sockaddr_storage)); - media_sockaddr.ss_family = local_addr->ai_addr->sa_family; - - memcpy(&media_sockaddr, - local_addr->ai_addr, - SOCK_ADDR_SIZE( - _RCAST(struct sockaddr_storage *,local_addr->ai_addr))); - freeaddrinfo(local_addr); + /* Resolving local IP */ + if (getaddrinfo(media_ip, + NULL, + &hints, + &local_addr) != 0) { + ERROR("Unknown RTP address '%s'.\n" + "Use 'sipp -h' for details", media_ip); + } + + memset(&media_sockaddr,0,sizeof(struct sockaddr_storage)); + media_sockaddr.ss_family = local_addr->ai_addr->sa_family; + + memcpy(&media_sockaddr, + local_addr->ai_addr, + SOCK_ADDR_SIZE( + _RCAST(struct sockaddr_storage *,local_addr->ai_addr))); + freeaddrinfo(local_addr); + + media_port = user_media_port ? user_media_port : DEFAULT_MEDIA_PORT; + /* Always create and Bind RTP socket */ + /* to avoid ICMP */ + int create_media_socket = 0; + if (!create_media_socket) { + if (media_sockaddr.ss_family == AF_INET) { + (_RCAST(struct sockaddr_in *,&media_sockaddr))->sin_port = htons((short)media_port); + } else { + (_RCAST(struct sockaddr_in6 *,&media_sockaddr))->sin6_port = htons((short)media_port); + media_ip_is_ipv6 = true; + } + } + else { if((media_socket = socket(media_ip_is_ipv6 ? AF_INET6 : AF_INET, SOCK_DGRAM, 0)) == -1) { char msg[512]; sprintf(msg, "Unable to get the audio RTP socket (IP=%s, port=%d)", media_ip, media_port); ERROR_NO(msg); } + int sock_opt = 1; + if (setsockopt(media_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&sock_opt, sizeof (sock_opt)) == -1) { + ERROR_NO("setsockopt(media_socket, SO_REUSEADDR) failed"); + } + /* create a second socket for video */ if((media_socket_video = socket(media_ip_is_ipv6 ? AF_INET6 : AF_INET, SOCK_DGRAM, 0)) == -1) { @@ -5125,27 +5154,30 @@ int main(int argc, char *argv[]) sprintf(msg, "Unable to get the video RTP socket (IP=%s, port=%d)", media_ip, media_port+2); ERROR_NO(msg); } + if (setsockopt(media_socket_video, SOL_SOCKET, SO_REUSEADDR, (void *)&sock_opt, sizeof (sock_opt)) == -1) { + ERROR_NO("setsockopt(media_socket_video, SO_REUSEADDR) failed"); + } int try_counter; int max_tries = user_media_port ? 1 : 100; - media_port = user_media_port ? user_media_port : DEFAULT_MEDIA_PORT; for (try_counter = 0; try_counter < max_tries; try_counter++) { if (media_sockaddr.ss_family == AF_INET) { - (_RCAST(struct sockaddr_in *,&media_sockaddr))->sin_port = - htons((short)media_port); + (_RCAST(struct sockaddr_in *,&media_sockaddr))->sin_port = + htons((short)media_port); } else { - (_RCAST(struct sockaddr_in6 *,&media_sockaddr))->sin6_port = - htons((short)media_port); - media_ip_is_ipv6 = true; + (_RCAST(struct sockaddr_in6 *,&media_sockaddr))->sin6_port = + htons((short)media_port); + media_ip_is_ipv6 = true; } strcpy(media_ip_escaped, media_ip); if(bind(media_socket, (sockaddr *)(void *)&media_sockaddr, SOCK_ADDR_SIZE(&media_sockaddr)) == 0) { - break; + break; } + DEBUG("Unable to bind to audio port %hu, try %d of %d", media_port, try_counter, max_tries); media_port++; } @@ -5155,6 +5187,7 @@ int main(int argc, char *argv[]) sprintf(msg, "Unable to bind audio RTP socket (IP=%s, port=%d)", media_ip, media_port); ERROR_NO(msg); } + DEBUG("Bound audio socket %s:%hu, after %d attempts", media_ip, media_port, try_counter); /*--------------------------------------------------------- Bind the second socket to media_port+2 @@ -5179,8 +5212,9 @@ int main(int argc, char *argv[]) sprintf(msg, "Unable to bind video RTP socket (IP=%s, port=%d)", media_ip, media_port+2); ERROR_NO(msg); } + DEBUG("Bound video socket %s:%hu", media_ip, media_port+2); /* Second socket bound */ -// } + } /* Creating the remote control socket thread */ setup_ctrl_socket(); @@ -5202,6 +5236,7 @@ int main(int argc, char *argv[]) /* Creating second RTP echo thread for video */ if ((media_socket_video > 0) && (rtp_echo_enabled)) { + DEBUG("RTP echo enabled: starting rtp_echo_thread"); if (pthread_create (&pthread3_id, NULL, @@ -5512,7 +5547,12 @@ int open_connections() { = htons((short)user_port); } if(sipp_bind_socket(main_socket, &local_sockaddr, &local_port)) { - ERROR("Unable to bind main socket. This may be caused by an incorrectly specified local IP"); + if (local_ip_is_ipv6) { + ERROR_NO("Unable to bind main socket to IPv6 address, port %d. This may be caused by an incorrectly specified local IP ", user_port); + } + else { + ERROR_NO("Unable to bind main socket to %s:%d. Make sure that the local IP (as specified with -i) is actually an IP address on your computer", inet_ntoa(((struct sockaddr_in *) &local_sockaddr)->sin_addr), user_port); + } } }