From 46095ef7264f4ca17a936a2f822fbedf8b33a008 Mon Sep 17 00:00:00 2001 From: Walter Doekes Date: Tue, 5 May 2015 14:29:42 +0200 Subject: [PATCH] Allow m=image in SDP to pcap_play faxes/images. Taken from https://code.osso.nl/projects/sipp/changeset/c939d058337f/ and adapted. (Still root-only pcap_play.) --- include/actions.hpp | 1 + include/call.hpp | 1 + include/rtpstream.hpp | 3 +- src/actions.cpp | 4 +- src/call.cpp | 101 ++++++++++++++++++++++++++++-------------- src/prepare_pcap.c | 3 +- src/rtpstream.cpp | 7 ++- src/scenario.cpp | 5 +++ src/send_packets.c | 4 +- 9 files changed, 88 insertions(+), 41 deletions(-) diff --git a/include/actions.hpp b/include/actions.hpp index fc46067a..c52a4aea 100644 --- a/include/actions.hpp +++ b/include/actions.hpp @@ -71,6 +71,7 @@ class CAction E_AT_CLOSE_CON, #ifdef PCAPPLAY E_AT_PLAY_PCAP_AUDIO, + E_AT_PLAY_PCAP_IMAGE, E_AT_PLAY_PCAP_VIDEO, #endif #ifdef RTP_STREAM diff --git a/include/call.hpp b/include/call.hpp index 0391f286..461e5260 100644 --- a/include/call.hpp +++ b/include/call.hpp @@ -168,6 +168,7 @@ class call : virtual public task, virtual public listener, public virtual socket int hasMediaInformation; pthread_t media_thread; play_args_t play_args_a; + play_args_t play_args_i; play_args_t play_args_v; #endif diff --git a/include/rtpstream.hpp b/include/rtpstream.hpp index 2fcb3beb..aeb2c519 100644 --- a/include/rtpstream.hpp +++ b/include/rtpstream.hpp @@ -47,7 +47,8 @@ void rtpstream_shutdown (void); int rtpstream_get_audioport (rtpstream_callinfo_t *callinfo); int rtpstream_get_videoport (rtpstream_callinfo_t *callinfo); -void rtpstream_set_remote (rtpstream_callinfo_t *callinfo, int ip_ver, char *ip_addr, int audio_port, int video_port); +void rtpstream_set_remote (rtpstream_callinfo_t *callinfo, int ip_ver, char *ip_addr, + int audio_port, int image_port, int video_port); int rtpstream_cache_file (char *filename); void rtpstream_play (rtpstream_callinfo_t *callinfo, rtpstream_actinfo_t *actioninfo); diff --git a/src/actions.cpp b/src/actions.cpp index f58dc46c..c6296b88 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -147,7 +147,7 @@ void CAction::afficheInfo() } else if (M_action == E_AT_VAR_TO_DOUBLE) { printf("Type[%d] - toDouble varId[%s]", M_action, display_scenario->allocVars->getName(M_varId)); #ifdef PCAPPLAY - } else if ((M_action == E_AT_PLAY_PCAP_AUDIO) || (M_action == E_AT_PLAY_PCAP_VIDEO)) { + } else if ((M_action == E_AT_PLAY_PCAP_AUDIO) || (M_action == E_AT_PLAY_PCAP_IMAGE) || (M_action == E_AT_PLAY_PCAP_VIDEO)) { printf("Type[%d] - file[%s]", M_action, M_pcapArgs->file); #endif @@ -635,7 +635,7 @@ CAction::CAction(scenario *scenario) #endif #ifdef RTP_STREAM - memset (&M_rtpstream_actinfo,0,sizeof(M_rtpstream_actinfo)); + memset(&M_rtpstream_actinfo, 0, sizeof(M_rtpstream_actinfo)); #endif M_scenario = scenario; diff --git a/src/call.cpp b/src/call.cpp index 401cf407..bdc83a45 100644 --- a/src/call.cpp +++ b/src/call.cpp @@ -195,12 +195,15 @@ uint8_t get_remote_ipv6_media(char *msg, struct in6_addr *addr) } /* - * Look for "m=audio " or "m=video " pattern in the message and extract the - * following value which should be port number + * Look for "m=audio ", "m=image " or "m=video " pattern in the message + * and extract the following value which should be port number. */ -#define PAT_AUDIO 1 -#define PAT_VIDEO 2 -uint16_t get_remote_port_media(const char *msg, int pattype) +enum media_ptn { + PAT_AUDIO, + PAT_IMAGE, + PAT_VIDEO +}; +uint16_t get_remote_port_media(const char *msg, enum media_ptn pattype) { const char *pattern; char *begin, *end; @@ -208,6 +211,8 @@ uint16_t get_remote_port_media(const char *msg, int pattype) if (pattype == PAT_AUDIO) { pattern = "m=audio "; + } else if (pattype == PAT_IMAGE) { + pattern = "m=image "; } else if (pattype == PAT_VIDEO) { pattern = "m=video "; } else { @@ -244,7 +249,7 @@ uint16_t get_remote_port_media(const char *msg, int pattype) */ void call::get_remote_media_addr(char *msg) { - uint16_t video_port, audio_port; + uint16_t audio_port, image_port, video_port; if (media_ip_is_ipv6) { struct in6_addr ip_media; if (get_remote_ipv6_media(msg, &ip_media)) { @@ -254,16 +259,25 @@ 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; } + image_port = get_remote_port_media(msg, PAT_IMAGE); + if (image_port) { + /* We have image in the SDP: set the to_image addr */ + (_RCAST(struct sockaddr_in6 *, &(play_args_i.to)))->sin6_flowinfo = 0; + (_RCAST(struct sockaddr_in6 *, &(play_args_i.to)))->sin6_scope_id = 0; + (_RCAST(struct sockaddr_in6 *, &(play_args_i.to)))->sin6_family = AF_INET6; + (_RCAST(struct sockaddr_in6 *, &(play_args_i.to)))->sin6_port = htons(image_port); + (_RCAST(struct sockaddr_in6 *, &(play_args_i.to)))->sin6_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_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; @@ -276,14 +290,21 @@ 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; } + image_port = get_remote_port_media(msg, PAT_IMAGE); + if (image_port) { + /* We have image in the SDP: set the to_image addr */ + (_RCAST(struct sockaddr_in *, &(play_args_i.to)))->sin_family = AF_INET; + (_RCAST(struct sockaddr_in *, &(play_args_i.to)))->sin_port = htons(image_port); + (_RCAST(struct sockaddr_in *, &(play_args_i.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; @@ -299,6 +320,7 @@ void call::get_remote_media_addr(char *msg) #define SDP_IPADDR_PREFIX "\nc=IN IP" #define SDP_AUDIOPORT_PREFIX "\nm=audio" +#define SDP_IMAGEPORT_PREFIX "\nm=image" #define SDP_VIDEOPORT_PREFIX "\nm=video" void call::extract_rtp_remote_addr (char * msg) { @@ -306,8 +328,9 @@ void call::extract_rtp_remote_addr (char * msg) char *copy; char ip_addr[128]; int ip_ver; - int audio_port= 0; - int video_port= 0; + int audio_port = 0; + int image_port = 0; + int video_port = 0; /* Look for start of message body */ search= strstr(msg,"\r\n\r\n"); @@ -349,6 +372,15 @@ void call::extract_rtp_remote_addr (char * msg) } sscanf (search,"%d",&audio_port); } + /* And find the port number for the image stream */ + search= strstr(msg,SDP_IMAGEPORT_PREFIX); + if (search) { + search+= strlen(SDP_IMAGEPORT_PREFIX); + while ( (*search==' ') || (*search=='\t') ) { + search++; + } + sscanf (search,"%d",&image_port); + } /* And find the port number for the video stream */ search= strstr(msg,SDP_VIDEOPORT_PREFIX); if (search) { @@ -358,10 +390,10 @@ void call::extract_rtp_remote_addr (char * msg) } sscanf (search,"%d",&video_port); } - if ((audio_port==0)&&(video_port==0)) { - ERROR("extract_rtp_remote_addr: no m=audio or m=video line found in SDP message body"); + if (audio_port == 0 && image_port == 0 && video_port == 0) { + ERROR("extract_rtp_remote_addr: no m=audio, m=image or m=video line found in SDP message body"); } - rtpstream_set_remote (&rtpstream_callinfo,ip_ver,ip_addr,audio_port,video_port); + rtpstream_set_remote(&rtpstream_callinfo, ip_ver, ip_addr, audio_port, image_port, video_port); } #endif @@ -612,8 +644,10 @@ void call::init(scenario * call_scenario, struct sipp_socket *socket, struct soc #ifdef PCAPPLAY memset(&(play_args_a.to), 0, sizeof(struct sockaddr_storage)); + memset(&(play_args_i.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)); + memset(&(play_args_i.from), 0, sizeof(struct sockaddr_storage)); memset(&(play_args_v.from), 0, sizeof(struct sockaddr_storage)); hasMediaInformation = 0; media_thread = 0; @@ -2105,9 +2139,8 @@ char* call::createSendingMessage(SendingMessage *src, int P_index, char *msg_buf (sockaddr *)(void *)&server_sockaddr, &len); if (server_sockaddr.ss_family == AF_INET6) { - char * temp_dest; - temp_dest = (char *) malloc(INET6_ADDRSTRLEN); - memset(temp_dest,0,INET6_ADDRSTRLEN); + char temp_dest[INET6_ADDRSTRLEN]; /* fits both INET and INET6 */ + temp_dest[0] = temp_dest[INET6_ADDRSTRLEN - 1] = '\0'; inet_ntop(AF_INET6, &((_RCAST(struct sockaddr_in6 *,&server_sockaddr))->sin6_addr), temp_dest, @@ -2139,21 +2172,21 @@ char* call::createSendingMessage(SendingMessage *src, int P_index, char *msg_buf if (begin == msg_buffer) { ERROR("Can not find beginning of a line for the media port!\n"); } + play_args_t *play_args = NULL; if (strstr(begin, "audio")) { - if (media_ip_is_ipv6) { - (_RCAST(struct sockaddr_in6 *, &(play_args_a.from)))->sin6_port = port; - } else { - (_RCAST(struct sockaddr_in *, &(play_args_a.from)))->sin_port = port; - } + play_args = &play_args_a; + } else if (strstr(begin, "image")) { + play_args = &play_args_i; } else if (strstr(begin, "video")) { - if (media_ip_is_ipv6) { - (_RCAST(struct sockaddr_in6 *, &(play_args_v.from)))->sin6_port = port; - } else { - (_RCAST(struct sockaddr_in *, &(play_args_v.from)))->sin_port = port; - } + play_args = &play_args_v; } else { ERROR("media_port keyword with no audio or video on the current line (%s)", begin); } + if (media_ip_is_ipv6) { + (_RCAST(struct sockaddr_in6 *, &(play_args->from)))->sin6_port = htons(port); + } else { + (_RCAST(struct sockaddr_in *, &(play_args->from)))->sin_port = htons(port); + } #endif dest += sprintf(dest, "%u", port); break; @@ -3835,16 +3868,18 @@ call::T_ActionResult call::executeAction(char * msg, message *curmsg) } #ifdef PCAPPLAY } else if ((currentAction->getActionType() == CAction::E_AT_PLAY_PCAP_AUDIO) || + (currentAction->getActionType() == CAction::E_AT_PLAY_PCAP_IMAGE) || (currentAction->getActionType() == CAction::E_AT_PLAY_PCAP_VIDEO)) { - play_args_t *play_args = NULL; + play_args_t *play_args; if (currentAction->getActionType() == CAction::E_AT_PLAY_PCAP_AUDIO) { play_args = &(this->play_args_a); + } else if (currentAction->getActionType() == CAction::E_AT_PLAY_PCAP_IMAGE) { + play_args = &(this->play_args_i); } else if (currentAction->getActionType() == CAction::E_AT_PLAY_PCAP_VIDEO) { play_args = &(this->play_args_v); - } - - if (!play_args) + } else { ERROR("Can't find pcap data to play"); + } play_args->pcap = currentAction->getPcapPkts(); /* port number is set in [auto_]media_port interpolation */ @@ -3857,7 +3892,7 @@ 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 */ + /* Create a thread to send RTP or UDPTL packets */ pthread_attr_t attr; pthread_attr_init(&attr); #ifndef PTHREAD_STACK_MIN diff --git a/src/prepare_pcap.c b/src/prepare_pcap.c index 0f92f83f..a525642a 100644 --- a/src/prepare_pcap.c +++ b/src/prepare_pcap.c @@ -141,7 +141,8 @@ int prepare_pkts(char *file, pcap_pkts *pkts) ethhdr = (ether_type_hdr *)(pktdata + ether_type_offset); if (ntohs(ethhdr->ether_type) != 0x0800 /* IPv4 */ && ntohs(ethhdr->ether_type) != 0x86dd) { /* IPv6 */ - fprintf(stderr, "Ignoring non IP{4,6} packet!\n"); + fprintf(stderr, "Ignoring non IP{4,6} packet, got ether_type %hu!\n", + ntohs(ethhdr->ether_type)); continue; } iphdr = (struct iphdr *)((char *)ethhdr + sizeof(*ethhdr)); diff --git a/src/rtpstream.cpp b/src/rtpstream.cpp index 06cffbbb..ce9132c9 100644 --- a/src/rtpstream.cpp +++ b/src/rtpstream.cpp @@ -886,8 +886,10 @@ int rtpstream_get_videoport (rtpstream_callinfo_t *callinfo) } /* code checked */ -void rtpstream_set_remote (rtpstream_callinfo_t *callinfo, int ip_ver, char *ip_addr, int audio_port, int video_port) +void rtpstream_set_remote (rtpstream_callinfo_t *callinfo, int ip_ver, char *ip_addr, + int audio_port, int image_port, int video_port) { + // TODO: we don't do anything with image_port right now.. struct sockaddr_storage address; struct in_addr *ip4_addr; struct in6_addr *ip6_addr; @@ -895,7 +897,8 @@ void rtpstream_set_remote (rtpstream_callinfo_t *callinfo, int ip_ver, char *ip_ unsigned count; int nonzero_ip; - debugprint ("rtpstream_set_remote callinfo=%p, ip_ver %d ip_addr %s audio %d video %d\n",callinfo,ip_ver,ip_addr,audio_port,video_port); + debugprint("rtpstream_set_remote callinfo=%p, ip_ver %d ip_addr %s audio %d image %d video %d\n", + callinfo, ip_ver, ip_addr, audio_port, image_port, video_port); taskinfo= callinfo->taskinfo; if (!taskinfo) { diff --git a/src/scenario.cpp b/src/scenario.cpp index 83f1bb98..d69ca213 100644 --- a/src/scenario.cpp +++ b/src/scenario.cpp @@ -1608,6 +1608,9 @@ void scenario::parseAction(CActions *actions) } else if ((ptr = xp_get_value((char *) "play_pcap_audio"))) { tmpAction->setPcapArgs(ptr); tmpAction->setActionType(CAction::E_AT_PLAY_PCAP_AUDIO); + } else if ((ptr = xp_get_value((char *) "play_pcap_image"))) { + tmpAction->setPcapArgs(ptr); + tmpAction->setActionType(CAction::E_AT_PLAY_PCAP_IMAGE); hasMedia = 1; } else if ((ptr = xp_get_value((char *) "play_pcap_video"))) { tmpAction->setPcapArgs(ptr); @@ -1616,6 +1619,8 @@ void scenario::parseAction(CActions *actions) #else } else if ((ptr = xp_get_value((char *) "play_pcap_audio"))) { ERROR("Scenario specifies a play_pcap_audio action, but this version of SIPp does not have PCAP support"); + } else if ((ptr = xp_get_value((char *) "play_pcap_image"))) { + ERROR("Scenario specifies a play_pcap_image action, but this version of SIPp does not have PCAP support"); } else if ((ptr = xp_get_value((char *) "play_pcap_video"))) { ERROR("Scenario specifies a play_pcap_video action, but this version of SIPp does not have PCAP support"); #endif diff --git a/src/send_packets.c b/src/send_packets.c index 3113decf..9dafa075 100644 --- a/src/send_packets.c +++ b/src/send_packets.c @@ -199,8 +199,8 @@ int send_packets (play_args_t * play_args) 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); + udp->uh_sport = htons(port_diff + ntohs(*from_port)); + udp->uh_dport = htons(port_diff + ntohs(*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));