Skip to content

Commit

Permalink
BugID(s): VOIP-64473
Browse files Browse the repository at this point in the history
Fix RTP playback so uses correct IP without seg faulting on 64-bit linux and Windows.


git-svn-id: https://subversion.polycom.com/SVN/RepoMisc/TestUtilities/trunk/SIPped/SIPped/src@26549 85c8ee13-dc6b-4ec3-b49e-93a6737f2991
  • Loading branch information
edward_estabrook committed Oct 18, 2011
1 parent 525494a commit e9b1f62
Show file tree
Hide file tree
Showing 6 changed files with 186 additions and 136 deletions.
18 changes: 13 additions & 5 deletions CHANGELOG.TXT
Original file line number Diff line number Diff line change
@@ -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
Expand Down
54 changes: 31 additions & 23 deletions call.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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; i<MAXIMUM_NUMBER_OF_RTP_MEDIA_THREADS; i++) media_threads[i] = 0;
number_of_active_rtp_threads = 0;
Expand Down Expand Up @@ -697,7 +699,7 @@ bool call::connect_socket_if_needed()
char peripaddr[256];
if (!peripsocket) {
if ((associate_socket(new_sipp_call_socket(use_ipv6, transport, &existing))) == NULL) {
ERROR_NO("Unable to get a UDP socket (1)");
ERROR_NO("Unable to get a UDP socket (1)");
}
} else {
char *tmp = peripaddr;
Expand Down Expand Up @@ -2353,9 +2355,9 @@ char* call::createSendingMessage(SendingMessage *src, int P_index, char *msg_buf
ERROR("Can not find beginning of a line for the media port!\n");
}
if (strstr(begin, "audio")) {
set_audio_port(port);
set_audio_from_port(port);
} else if (strstr(begin, "video")) {
set_video_port(port);
set_video_from_port(port);
} else {
ERROR("media_port keyword with no audio or video on the current line (%s)", begin);
}
Expand Down Expand Up @@ -4413,11 +4415,15 @@ call::T_ActionResult call::executeAction(char * msg, message *curmsg)
if (currentAction->getActionType() == 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*/
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions call.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down Expand Up @@ -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);
Expand Down
5 changes: 3 additions & 2 deletions prepare_pcap.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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 ;
Expand Down
97 changes: 45 additions & 52 deletions send_packets.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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;
Expand All @@ -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));
Expand All @@ -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;
}

/*
Expand Down
Loading

0 comments on commit e9b1f62

Please sign in to comment.