Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add fax/t38 support #129

Merged
merged 2 commits into from
May 8, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/actions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions include/call.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
3 changes: 2 additions & 1 deletion include/rtpstream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 video_port);

int rtpstream_cache_file (char *filename);
void rtpstream_play (rtpstream_callinfo_t *callinfo, rtpstream_actinfo_t *actioninfo);
Expand Down
4 changes: 2 additions & 2 deletions src/actions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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;
Expand Down
104 changes: 71 additions & 33 deletions src/call.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,19 +195,24 @@ 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;
char number[6];

if (pattype == PAT_AUDIO) {
pattern = "m=audio ";
} else if (pattype == PAT_IMAGE) {
pattern = "m=image ";
} else if (pattype == PAT_VIDEO) {
pattern = "m=video ";
} else {
Expand Down Expand Up @@ -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)) {
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -299,15 +320,17 @@ 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)
{
char *search;
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");
Expand Down Expand Up @@ -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) {
Expand All @@ -358,10 +390,13 @@ 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);
/* If we get an image_port only, we won't set anything useful.
* We cannot use rtpstream for udptl/t38 data because it has
* non-linear timing and data size. */
rtpstream_set_remote(&rtpstream_callinfo, ip_ver, ip_addr, audio_port, video_port);
}
#endif

Expand Down Expand Up @@ -612,8 +647,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;
Expand Down Expand Up @@ -2105,9 +2142,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,
Expand Down Expand Up @@ -2139,21 +2175,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;
Expand Down Expand Up @@ -3835,16 +3871,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 */
Expand All @@ -3857,7 +3895,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
Expand Down
31 changes: 24 additions & 7 deletions src/prepare_pcap.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,9 @@
* made available by the platform, as we had no problems to get them on all supported platforms.
*/

typedef struct _ether_hdr {
char ether_dst[6];
char ether_src[6];
typedef struct _ether_type_hdr {
u_int16_t ether_type; /* we only need the type, so we can determine, if the next header is IPv4 or IPv6 */
} ether_hdr;
} ether_type_hdr;

typedef struct _ipv6_hdr {
char dontcare[6];
Expand Down Expand Up @@ -99,7 +97,9 @@ int prepare_pkts(char *file, pcap_pkts *pkts)
u_int16_t base = 0xffff;
u_long pktlen;
pcap_pkt *pkt_index;
ether_hdr *ethhdr;
size_t ether_type_offset;
ether_type_hdr *ethhdr;

struct iphdr *iphdr;
ipv6_hdr *ip6hdr;
struct udphdr *udphdr;
Expand All @@ -110,6 +110,19 @@ int prepare_pkts(char *file, pcap_pkts *pkts)
if (!pcap)
ERROR("Can't open PCAP file '%s'", file);

switch (pcap_datalink(pcap)) {
case DLT_EN10MB:
/* srcmac[6], dstmac[6], ethertype[2] */
ether_type_offset = 12;
break;
case DLT_LINUX_SLL:
/* some_stuff[14], ethertype[2] */
ether_type_offset = 14;
break;
default:
ERROR("Unsupported link-type %d", pcap_datalink(pcap));
}

#if HAVE_PCAP_NEXT_EX
while (pcap_next_ex (pcap, &pkthdr, (const u_char **) &pktdata) == 1) {
#else
Expand All @@ -122,10 +135,14 @@ int prepare_pkts(char *file, pcap_pkts *pkts)
ERROR("Can't allocate memory for pcap pkthdr");
while ((pktdata = (u_char *) pcap_next (pcap, pkthdr)) != NULL) {
#endif
ethhdr = (ether_hdr *)pktdata;
if (pkthdr->len != pkthdr->caplen) {
ERROR("You got truncated packets. Please create a new dump with -s0");
}
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));
Expand Down
6 changes: 4 additions & 2 deletions src/rtpstream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -886,7 +886,8 @@ 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 video_port)
{
struct sockaddr_storage address;
struct in_addr *ip4_addr;
Expand All @@ -895,7 +896,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 video %d\n",
callinfo, ip_ver, ip_addr, audio_port, video_port);

taskinfo= callinfo->taskinfo;
if (!taskinfo) {
Expand Down
5 changes: 5 additions & 0 deletions src/scenario.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/send_packets.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down