[Pkg-voip-commits] r6624 - in /sip-tester/trunk: Makefile call.cpp debian/changelog debian/watch sipp.hpp
msp at alioth.debian.org
msp at alioth.debian.org
Sun Jan 4 03:39:23 UTC 2009
Author: msp
Date: Sun Jan 4 03:39:23 2009
New Revision: 6624
URL: http://svn.debian.org/wsvn/pkg-voip/?sc=1&rev=6624
Log:
* (NOT RELEASED YET) New upstream release
* Update debian/watch
Modified:
sip-tester/trunk/Makefile
sip-tester/trunk/call.cpp
sip-tester/trunk/debian/changelog
sip-tester/trunk/debian/watch
sip-tester/trunk/sipp.hpp
Modified: sip-tester/trunk/Makefile
URL: http://svn.debian.org/wsvn/pkg-voip/sip-tester/trunk/Makefile?rev=6624&op=diff
==============================================================================
--- sip-tester/trunk/Makefile (original)
+++ sip-tester/trunk/Makefile Sun Jan 4 03:39:23 2009
@@ -19,13 +19,15 @@
#
-include local.mk
+SVN_VERSION=$(shell if test -d .svn ; then svnversion . | sed -e 's/^/svn/;' ; else echo unknown ; fi)
+VERINFO=-DSVN_VERSION="\"$(SVN_VERSION)\""
# Output binary to be built
OUTPUT=sipp
# C & C++ object files to be built
-OBJ= xp_parser.o scenario.o screen.o call.o comp.o sipp.o stat.o \
- actions.o variables.o
+OBJ= xp_parser.o message.o scenario.o screen.o call.o comp.o sipp.o stat.o \
+ actions.o variables.o infile.o deadcall.o task.o socketowner.o listener.o
# Libraries directories
LIBDIR_linux=
@@ -63,7 +65,7 @@
# C compiler
CC_hpux=aCC
-CC_linux=cc
+CC_linux=gcc
CC_freebsd=cc
CC_tru64=cc
CC_SunOS=gcc
@@ -73,7 +75,7 @@
# C++ compiler mapping
CPP_hpux=aCC
-CPP_linux=gcc
+CPP_linux=g++
CPP_freebsd=g++
CPP_tru64=cxx
CPP_SunOS=g++
@@ -99,20 +101,20 @@
CFLAGS_linux=-D__LINUX -pthread
CFLAGS_freebsd=-D__LINUX -pthread
CFLAGS_tru64=-D__OSF1 -pthread
-CFLAGS_SunOS=-g -D__SUNOS
+CFLAGS_SunOS=${DEBUG_FLAGS} -D__SUNOS
CFLAGS_Cygwin=-D__CYGWIN -Dsocklen_t=int
CFLAGS_Darwin=-D__DARWIN
-CFLAGS=$(CFLAGS_$(SYSTEM)) -D__3PCC__ $(TLS) $(PCAPPLAY) $(EXTRACFLAGS)
+CFLAGS=$(CFLAGS_$(SYSTEM)) $(VERINFO) $(TLS) $(PCAPPLAY) $(EXTRACFLAGS)
#C++ Compiler Flags
-CPPFLAGS_hpux=-AA -mt -D__HPUX +W829
+CPPFLAGS_hpux=-AA -mt -D__HPUX -D_INCLUDE_LONGLONG -DNOMACROS +W829
CPPFLAGS_linux=-D__LINUX -pthread
CPPFLAGS_freebsd=-D__LINUX -pthread
CPPFLAGS_tru64=-D__OSF1 -pthread
-CPPFLAGS_SunOS=-g -D__SUNOS
+CPPFLAGS_SunOS=${DEBUG_FLAGS} -D__SUNOS
CPPFLAGS_Cygwin=-D__CYGWIN -Dsocklen_t=int
CPPFLAGS_Darwin=-D__DARWIN
-CPPFLAGS=$(CPPFLAGS_$(SYSTEM)) -D__3PCC__ $(TLS) $(PCAPPLAY) $(EXTRACPPFLAGS)
+CPPFLAGS=$(CPPFLAGS_$(SYSTEM)) $(VERINFO) $(TLS) $(PCAPPLAY) $(EXTRACPPFLAGS)
#Linker mapping
CCLINK_hpux=aCC
@@ -129,7 +131,7 @@
LFLAGS_linux=
LFLAGS_freebsd=
LFLAGS_tru64=
-LFLAGS_SunOS=
+LFLAGS_SunOS=-mt ${DEBUG_FLAGS}
LFLAGS_Cygwin=
LFLAGS_Darwin=
LFLAGS=$(LFLAGS_$(SYSTEM)) $(EXTRALFLAGS)
@@ -138,15 +140,15 @@
LIBS_linux= -ldl -lpthread -lncurses -lstdc++ -lm -L /usr/local/lib -L /usr/lib -L /usr/lib64
LIBS_hpux= -lcurses -lpthread -L /opt/openssl/lib -L /usr/local/lib
LIBS_tru64= -lcurses -lpthread
-LIBS_freebsd= -lcurses -pthread
-LIBS_SunOS= -lcurses -lpthread -lnsl -lsocket -lstdc++ -lm -ldl -L /usr/local/ssl/lib/
+LIBS_freebsd= -lcurses -pthread -L /usr/local/lib
+LIBS_SunOS= -lcurses -lpthread -lnsl -lsocket -Wl,-Bstatic -lstdc++ -Wl,-Bdynamic -lm -ldl -L /usr/local/ssl/lib/
LIBS_Cygwin= -lcurses -lpthread -lstdc++ -L /usr/lib/WpdPack/Lib
LIBS_Darwin= -lcurses
LIBS=$(LIBS_$(SYSTEM)) $(EXTRALIBS)
# Include directories
-INCDIR_linux=-I. -I/opt/openssl/include
-INCDIR_freebsd=-I. -I/opt/openssl/include
+INCDIR_linux=-I. -I/usr/include/openssl
+INCDIR_freebsd=-I. -I/usr/local/include
INCDIR_hpux=-I. -I/usr/local/include -I/opt/openssl/include
INCDIR_tru64=-I. -I/opt/openssl/include
INCDIR_SunOS=-I. -I/usr/local/ssl/include/
@@ -169,7 +171,7 @@
make OSNAME=`uname|sed -e "s/CYGWIN.*/CYGWIN/"` MODELNAME=`uname -m|sed "s/Power Macintosh/ppc/"` OBJ_PCAPPLAY="send_packets.o prepare_pcap.o" PCAPPLAY_LIBS="-lpcap" PCAPPLAY="-DPCAPPLAY" $(OUTPUT)
pcapplay_ossl:
- make OSNAME=`uname|sed -e "s/CYGWIN.*/CYGWIN/"` MODELNAME=`uname -m|sed "s/Power Macintosh/ppc/"` OBJ_TLS="auth.o sslinit.o sslthreadsafe.o milenage.o rijndael.o" TLS_LIBS="-lssl -lcrypto" TLS="-D_USE_OPENSSL -DOPENSSL_NO_KRB5" OBJ_PCAPPLAY="send_packets.o prepare_pcap.o" PCAPPLAY_LIBS="-lpcap -L`if test -f /usr/lib/libpcap.a; then echo /usr; else echo ./ext; fi;`/lib" PCAPPLAY="-DPCAPPLAY -I`if test -f /usr/lib/libpcap.a; then echo /usr; else echo ./ext; fi;`/include" $(OUTPUT)
+ make OSNAME=`uname|sed -e "s/CYGWIN.*/CYGWIN/"` MODELNAME=`uname -m|sed "s/Power Macintosh/ppc/"` OBJ_TLS="auth.o sslinit.o sslthreadsafe.o milenage.o rijndael.o" TLS_LIBS="-lssl -lcrypto" TLS="-D_USE_OPENSSL -DOPENSSL_NO_KRB5" OBJ_PCAPPLAY="send_packets.o prepare_pcap.o" PCAPPLAY_LIBS="-lpcap `if test -f ./ext; then echo -L./ext/lib; fi;`" PCAPPLAY="-DPCAPPLAY `if test -f ./ext; then echo -I./ext/include; fi;`" $(OUTPUT)
pcapplay_hp_li_ia:
@_HPUX_LI_FLAG=-D_HPUX_LI ; export _HPUX_LI_FLAG ; make pcapplay
@@ -190,8 +192,8 @@
debug:
DEBUG_FLAGS="-g -pg" ; export DEBUG_FLAGS ; make all
-debug_tls:
- @DEBUG_FLAGS=-g ; export DEBUG_FLAGS ; make tls
+debug_ossl:
+ @DEBUG_FLAGS=-g ; export DEBUG_FLAGS ; make ossl
debug_pcap_cygwin:
@DEBUG_FLAGS=-g ; export DEBUG_FLAGS ; make pcapplay_ossl_cygwin
@@ -222,4 +224,3 @@
.c.o:
$(CC) $(CFLAGS) $(MFLAGS) $(DEBUG_FLAGS) $(_HPUX_LI_FLAG) $(INCDIR) -c -o $*.o $<
-
Modified: sip-tester/trunk/call.cpp
URL: http://svn.debian.org/wsvn/pkg-voip/sip-tester/trunk/call.cpp?rev=6624&op=diff
==============================================================================
--- sip-tester/trunk/call.cpp (original)
+++ sip-tester/trunk/call.cpp Sun Jan 4 03:39:23 2009
@@ -46,9 +46,8 @@
#include "send_packets.h"
#endif
#include "sipp.hpp"
+#include "deadcall.hpp"
#include "assert.h"
-
-#define KEYWORD_SIZE 256
#ifdef _USE_OPENSSL
extern SSL *ssl_list[];
@@ -56,11 +55,7 @@
extern SSL_CTX *sip_trp_ssl_ctx;
#endif
-extern map<string, int> map_perip_fd;
-
-call_map calls;
-call_list running_calls;
-timewheel paused_calls;
+extern map<string, struct sipp_socket *> map_perip_fd;
#ifdef PCAPPLAY
/* send_packets pthread wrapper */
@@ -68,14 +63,9 @@
#endif
/************** Call map and management routines **************/
-call_map * get_calls()
-{
- return & calls;
-}
-
static unsigned int next_number = 1;
-unsigned int get_tdm_map_number(unsigned int number) {
+unsigned int get_tdm_map_number() {
unsigned int nb = 0;
unsigned int i=0;
unsigned int interval=0;
@@ -100,73 +90,205 @@
}
}
-call * add_call(char * call_id, bool ipv6)
-{
- call * new_call;
- unsigned int nb;
-
- if(!next_number) { next_number ++; }
-
- if (use_tdmmap) {
- nb = get_tdm_map_number(next_number);
- if (nb != 0) {
- /* Mark the entry in the list as busy */
- tdm_map[nb - 1] = true;
+/* When should this call wake up? */
+unsigned int call::wake() {
+ unsigned int wake = 0;
+
+ if (zombie) {
+ return wake;
+ }
+
+ if (paused_until) {
+ wake = paused_until;
+ }
+
+ if (next_retrans && (!wake || (next_retrans < wake))) {
+ wake = next_retrans;
+ }
+
+ if (recv_timeout && (!wake || (recv_timeout < wake))) {
+ wake = recv_timeout;
+ }
+
+ return wake;
+}
+
+#ifdef PCAPPLAY
+/******* Media information management *************************/
+/*
+ * Look for "c=IN IP4 " pattern in the message and extract the following value
+ * which should be IP address
+ */
+uint32_t get_remote_ip_media(char *msg)
+{
+ char pattern[] = "c=IN IP4 ";
+ char *begin, *end;
+ char ip[32];
+ begin = strstr(msg, pattern);
+ if (!begin) {
+ /* Can't find what we're looking at -> return no address */
+ return INADDR_NONE;
+ }
+ begin += sizeof("c=IN IP4 ") - 1;
+ end = strstr(begin, "\r\n");
+ if (!end)
+ return INADDR_NONE;
+ memset(ip, 0, 32);
+ strncpy(ip, begin, end - begin);
+ return inet_addr(ip);
+}
+
+/*
+ * Look for "c=IN IP6 " pattern in the message and extract the following value
+ * which should be IPv6 address
+ */
+uint8_t get_remote_ipv6_media(char *msg, struct in6_addr addr)
+{
+ char pattern[] = "c=IN IP6 ";
+ char *begin, *end;
+ char ip[128];
+
+ memset(&addr, 0, sizeof(addr));
+ memset(ip, 0, 128);
+
+ begin = strstr(msg, pattern);
+ if (!begin) {
+ /* Can't find what we're looking at -> return no address */
+ return 0;
+ }
+ begin += sizeof("c=IN IP6 ") - 1;
+ end = strstr(begin, "\r\n");
+ if (!end)
+ return 0;
+ strncpy(ip, begin, end - begin);
+ if (!inet_pton(AF_INET6, ip, &addr)) {
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * Look for "m=audio " 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(char *msg, int pattype)
+{
+ char *pattern;
+ char *begin, *end;
+ char number[6];
+
+ if (pattype == PAT_AUDIO) {
+ pattern = "m=audio ";
+ } else if (pattype == PAT_VIDEO) {
+ pattern = "m=video ";
} else {
- /* Can't create the new call */
- WARNING("Can't create new outgoing call: all tdm_map circuits busy");
- return NULL;
- }
- }
-
- new_call = new call(call_id, ipv6);
-
- if(!new_call) {
- ERROR("Memory Overflow");
- }
-
- /* All calls must exist in the map. */
- calls[std::string(call_id)] = new_call;
- /* All calls start off in the running state. */
- add_running_call(new_call);
-
- new_call -> number = next_number;
- new_call -> tdm_map_number = nb - 1;
-
- /* Vital counters update */
- next_number++;
- open_calls++;
-
- /* Statistics update */
- calls_since_last_rate_change++;
- total_calls ++;
-
- if(open_calls > open_calls_peak) {
- open_calls_peak = open_calls;
- open_calls_peak_time = clock_tick / 1000;
- }
- return new_call;
-}
-
-#ifdef _USE_OPENSSL
-call * add_call(char * call_id , int P_pollset_indx, bool ipv6)
-{
- call * new_call = add_call(call_id, ipv6);
- new_call -> pollset_index = P_pollset_indx;
- return new_call;
-}
+ ERROR("Internal error: Undefined media pattern %d\n", 3);
+ }
+
+ begin = strstr(msg, pattern);
+ if (!begin) {
+ /* m=audio not found */
+ return 0;
+ }
+ begin += strlen(pattern) - 1;
+ end = strstr(begin, "\r\n");
+ if (!end)
+ ERROR("get_remote_port_media: no CRLF found");
+ memset(number, 0, sizeof(number));
+ strncpy(number, begin, sizeof(number) - 1);
+ return atoi(number);
+}
+
+/*
+ * IPv{4,6} compliant
+ */
+void call::get_remote_media_addr(char *msg) {
+ uint16_t video_port, audio_port;
+ if (media_ip_is_ipv6) {
+ struct in6_addr ip_media;
+ if (get_remote_ipv6_media(msg, ip_media)) {
+ audio_port = get_remote_port_media(msg, PAT_AUDIO);
+ if (audio_port) {
+ /* We have audio in the SDP: set the to_audio addr */
+ (_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_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_addr = ip_media;
+ }
+ hasMediaInformation = 1;
+ }
+ }
+ else {
+ uint32_t ip_media;
+ ip_media = get_remote_ip_media(msg);
+ if (ip_media != INADDR_NONE) {
+ audio_port = get_remote_port_media(msg, PAT_AUDIO);
+ 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_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_addr.s_addr = ip_media;
+ }
+ hasMediaInformation = 1;
+ }
+ }
+}
+
#endif
-
-call * add_call(bool ipv6)
+/******* Very simple hash for retransmission detection *******/
+
+unsigned long hash(char * msg) {
+ unsigned long hash = 0;
+ int c;
+
+ while (c = *msg++)
+ hash = c + (hash << 6) + (hash << 16) - hash;
+
+ return hash;
+}
+
+/******************* Call class implementation ****************/
+call::call(char *p_id, bool use_ipv6, int userId, struct sockaddr_storage *dest) : listener(p_id, true) {
+ init(main_scenario, NULL, dest, p_id, userId, use_ipv6, false);
+}
+
+call::call(char *p_id, struct sipp_socket *socket, struct sockaddr_storage *dest) : listener(p_id, true) {
+ init(main_scenario, socket, dest, p_id, 0 /* No User. */, socket->ss_ipv6, false /* Not Auto. */);
+}
+
+call::call(scenario * call_scenario, struct sipp_socket *socket, struct sockaddr_storage *dest, char * p_id, int userId, bool ipv6, bool isAutomatic) : listener(p_id, true) {
+ init(call_scenario, socket, dest, p_id, userId, ipv6, isAutomatic);
+}
+
+call *call::add_call(int userId, bool ipv6, struct sockaddr_storage *dest)
{
static char call_id[MAX_HEADER_LEN];
-
+
char * src = call_id_string;
int count = 0;
-
+
if(!next_number) { next_number ++; }
-
+
while (*src && count < MAX_HEADER_LEN-1) {
if (*src == '%') {
++src;
@@ -190,429 +312,112 @@
}
call_id[count] = 0;
- return add_call(call_id, ipv6);
-}
-
-call * get_call(char * call_id)
-{
-
- call * call_ptr;
-
- call_map::iterator call_it ;
- call_it = calls.find(call_map::key_type(call_id));
- call_ptr = (call_it != calls.end()) ? call_it->second : NULL ;
-
- return call_ptr;
-}
-
-void delete_call(char * call_id)
-{
- call * call_ptr;
- call_map::iterator call_it ;
- call_it = calls.find(call_map::key_type(call_id));
- call_ptr = (call_it != calls.end()) ? call_it->second : NULL ;
-
- if(call_ptr) {
- if (use_tdmmap)
- tdm_map[call_ptr->tdm_map_number] = false;
- calls.erase(call_it);
-
- if (call_ptr->running) {
- remove_running_call(call_ptr);
- } else {
- paused_calls.remove_paused_call(call_ptr);
- }
-
- delete call_ptr;
- open_calls--;
- } else {
- if (start_calls == 0) {
- ERROR("Call not found");
- }
- }
-}
-
-void delete_calls(void)
-{
- call * call_ptr;
-
- call_map::iterator call_it ;
- call_it = calls.begin();
- while (call_it != calls.end()) {
- call_ptr = (call_it != calls.end()) ? call_it->second : NULL ;
- WARNING_P1("Aborting call with Call-Id '%s'", call_ptr->id);
- call_ptr->abortCall();
- call_it = calls.begin();
- }
-
-}
-
-/* Routines for running calls. */
-
-/* Get the overall list of running calls. */
-call_list * get_running_calls()
-{
- return & running_calls;
-}
-
-/* Put this call in the run queue. */
-void add_running_call(call *call) {
- call->runit = running_calls.insert(running_calls.end(), call);
- call->running = true;
-}
-
-/* Remove this call from the run queue. */
-bool remove_running_call(call *call) {
- if (!call->running) {
- return false;
- }
- running_calls.erase(call->runit);
- call->running = false;
- return true;
-}
-
-/* When should this call wake up? */
-unsigned int call_wake(call *call) {
- unsigned int wake = 0;
-
- if (call->paused_until) {
- wake = call->paused_until;
- }
-
- if (call->next_retrans && (!wake || (call->next_retrans < wake))) {
- wake = call->next_retrans;
- }
-
- if (call->recv_timeout && (!wake || (call->recv_timeout < wake))) {
- wake = call->recv_timeout;
- }
-
- return wake;
-}
-
-call_list *timewheel::call2list(call *call) {
- unsigned int wake = call_wake(call);
- unsigned int wake_sigbits = wake;
- unsigned int base_sigbits = wheel_base;
-
- if (wake == 0) {
- return &forever_list;
- }
-
- wake_sigbits /= LEVEL_ONE_SLOTS;
- base_sigbits /= LEVEL_ONE_SLOTS;
- if (wake_sigbits == base_sigbits) {
- return &wheel_one[wake % LEVEL_ONE_SLOTS];
- }
- wake_sigbits /= LEVEL_TWO_SLOTS;
- base_sigbits /= LEVEL_TWO_SLOTS;
- if (wake_sigbits == base_sigbits) {
- return &wheel_two[(wake / LEVEL_ONE_SLOTS) % LEVEL_TWO_SLOTS];
- }
- assert(wake_sigbits < LEVEL_THREE_SLOTS);
- return &wheel_three[wake_sigbits];
-}
-
-int expire_paused_calls() {
- return paused_calls.expire_paused_calls();
-}
-int paused_calls_count() {
- return paused_calls.size();
-}
-void remove_paused_call(call *call) {
- assert(!call->running);
- paused_calls.remove_paused_call(call);
-}
-
-/* Iterate through our sorted set of paused calls, removing those that
- * should no longer be paused, and adding them to the run queue. */
-int timewheel::expire_paused_calls() {
- int found = 0;
-
- while (wheel_base < clock_tick) {
- int slot1 = wheel_base % LEVEL_ONE_SLOTS;
-
- /* Migrate calls from slot2 when we hit 0. */
- if (slot1 == 0) {
- int slot2 = (wheel_base / LEVEL_ONE_SLOTS) % LEVEL_TWO_SLOTS;
-
- /* If slot2 is also zero, we must migrate calls from slot3 into slot2. */
- if (slot2 == 0) {
- int slot3 = ((wheel_base / LEVEL_ONE_SLOTS) / LEVEL_TWO_SLOTS);
- assert(slot3 < LEVEL_THREE_SLOTS);
-
- for (call_list::iterator l3it = wheel_three[slot3].begin();
- l3it != wheel_three[slot3].end();
- l3it++) {
- /* Migrate this call to wheel two. */
- add_paused_call(*l3it, false);
- }
-
- wheel_three[slot3].clear();
- }
-
- for (call_list::iterator l2it = wheel_two[slot2].begin();
- l2it != wheel_two[slot2].end();
- l2it++) {
- /* Migrate this call to wheel one. */
- add_paused_call(*l2it, false);
- }
-
- wheel_two[slot2].clear();
- }
-
- found += wheel_one[slot1].size();
- for(call_list::iterator it = wheel_one[slot1].begin();
- it != wheel_one[slot1].end(); it++) {
- add_running_call(*it);
- count--;
- }
- wheel_one[slot1].clear();
-
- wheel_base++;
- }
-
- return found;
-}
-
-void timewheel::add_paused_call(call *call, bool increment) {
- call_list *list = call2list(call);
- call->pauseit = list->insert(list->end(), call);
- if (increment) {
- count++;
- }
-}
-
-void timewheel::remove_paused_call(call *call) {
- call_list *list = call2list(call);
- list->erase(call->pauseit);
- count--;
-}
-
-timewheel::timewheel() {
- count = 0;
- wheel_base = clock_tick;
-}
-
-int timewheel::size() {
- return count;
-}
-
-#ifdef PCAPPLAY
-/******* Media information management *************************/
-/*
- * Look for "c=IN IP4 " pattern in the message and extract the following value
- * which should be IP address
- */
-uint32_t get_remote_ip_media(char *msg)
-{
- char pattern[] = "c=IN IP4 ";
- char *begin, *end;
- char ip[32];
- begin = strstr(msg, pattern);
- if (!begin) {
- /* Can't find what we're looking at -> return no address */
- return INADDR_NONE;
- }
- begin += sizeof("c=IN IP4 ") - 1;
- end = strstr(begin, "\r\n");
- if (!end)
- return INADDR_NONE;
- memset(ip, 0, 32);
- strncpy(ip, begin, end - begin);
- return inet_addr(ip);
-}
-
-/*
- * Look for "c=IN IP6 " pattern in the message and extract the following value
- * which should be IPv6 address
- */
-uint8_t get_remote_ipv6_media(char *msg, struct in6_addr addr)
-{
- char pattern[] = "c=IN IP6 ";
- char *begin, *end;
- char ip[128];
-
- memset(&addr, 0, sizeof(addr));
- memset(ip, 0, 128);
-
- begin = strstr(msg, pattern);
- if (!begin) {
- /* Can't find what we're looking at -> return no address */
- return 0;
- }
- begin += sizeof("c=IN IP6 ") - 1;
- end = strstr(begin, "\r\n");
- if (!end)
- return 0;
- strncpy(ip, begin, end - begin);
- if (!inet_pton(AF_INET6, ip, &addr)) {
- return 0;
- }
- return 1;
-}
-
-/*
- * Look for "m=audio " pattern in the message and extract the following value
- * which should be port number
- */
-uint16_t get_remote_audio_port_media(char *msg)
-{
- char pattern[] = "m=audio ";
- char *begin, *end;
- char number[6];
- begin = strstr(msg, pattern);
- if (!begin) {
- /* m=audio not found */
- return 0;
- }
- begin += sizeof("m=audio ") - 1;
- end = strstr(begin, "\r\n");
- if (!end)
- ERROR("get_remote_audio_port_media: no CRLF found");
- memset(number, 0, sizeof(number));
- strncpy(number, begin, sizeof(number) - 1);
- return atoi(number);
-}
-
-/*
- * Look for "m=video " pattern in the message and extract the following value
- * which should be port number
- */
-uint16_t get_remote_video_port_media(char *msg)
-{
- char pattern[] = "m=video ";
- char *begin, *end;
- char number[5];
- begin = strstr(msg, pattern);
- if (!begin) {
- /* m=video not found */
- return 0;
- }
- begin += sizeof("m=video ") - 1;
- end = strstr(begin, "\r\n");
- if (!end)
- ERROR("get_remote_video_port_media: no CRLF found");
- memset(number, 0, 5);
- strncpy(number, begin, end - begin);
- return atoi(number);
-}
-
-/*
- * IPv{4,6} compliant
- */
-void call::get_remote_media_addr(char *msg) {
- uint16_t video_port, audio_port;
- if (media_ip_is_ipv6) {
- struct in6_addr ip_media;
- if (get_remote_ipv6_media(msg, ip_media)) {
- audio_port = get_remote_audio_port_media(msg);
- if (audio_port) {
- /* We have audio in the SDP: set the to_audio addr */
- (_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_addr = ip_media;
- }
- video_port = get_remote_video_port_media(msg);
- 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_addr = ip_media;
- }
- hasMediaInformation = 1;
- }
- }
- else {
- uint32_t ip_media;
- ip_media = get_remote_ip_media(msg);
- if (ip_media != INADDR_NONE) {
- audio_port = get_remote_audio_port_media(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_addr.s_addr = ip_media;
- }
- video_port = get_remote_video_port_media(msg);
- 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_addr.s_addr = ip_media;
- }
- hasMediaInformation = 1;
- }
- }
-}
-
-#endif
-
-/******* Very simple hash for retransmission detection *******/
-
-unsigned long hash(char * msg) {
- unsigned long hash = 0;
- int c;
-
- while (c = *msg++)
- hash = c + (hash << 6) + (hash << 16) - hash;
-
- return hash;
-}
-
-/******************* Call class implementation ****************/
-
-call::InputFileUsage call::m_usage = call::InputFileSequentialOrder;
-int call::m_counter = 0;
-
-call::call(char * p_id, bool ipv6) : use_ipv6(ipv6)
-{
- memset(this, 0, sizeof(call));
- id = strdup(p_id);
+ return new call(main_scenario, NULL, dest, call_id, userId, ipv6, false /* Not Auto. */);
+}
+
+
+void call::init(scenario * call_scenario, struct sipp_socket *socket, struct sockaddr_storage *dest, char * p_id, int userId, bool ipv6, bool isAutomatic)
+{
+ this->call_scenario = call_scenario;
+ zombie = false;
+ msg_index = 0;
+ last_send_index = 0;
+ last_send_msg = NULL;
+
+ last_recv_hash = 0;
+ last_recv_index = -1;
+ last_recv_msg = NULL;
+
+ recv_retrans_hash = 0;
+ recv_retrans_recv_index = -1;
+ recv_retrans_send_index = -1;
+
+ dialog_route_set = NULL;
+ next_req_url = NULL;
+
+ cseq = 0;
+
+ next_retrans = 0;
+ nb_retrans = 0;
+ nb_last_delay = 0;
+
+ paused_until = 0;
+
+ call_port = 0;
+ comp_state = NULL;
+
start_time = clock_tick;
call_established=false ;
- count_in_stats=true ;
ack_is_pending=false ;
last_recv_msg = NULL;
cseq = base_cseq;
nb_last_delay = 0;
- tdm_map_number = 0;
+ use_ipv6 = ipv6;
+ queued_msg = NULL;
#ifdef _USE_OPENSSL
+ dialog_authentication = NULL;
+ dialog_challenge_type = 0;
+
m_ctx_ssl = NULL ;
m_bio = NULL ;
#endif
- pollset_index = 0 ;
- poll_flag_write = false ;
-
- call_remote_socket = 0;
+#ifdef PCAPPLAY
+ hasMediaInformation = 0;
+#endif
+
+ call_remote_socket = NULL;
+ if (socket) {
+ associate_socket(socket);
+ socket->ss_count++;
+ } else {
+ call_socket = NULL;
+ }
+ if (dest) {
+ memcpy(&call_peer, dest, SOCK_ADDR_SIZE(dest));
+ } else {
+ memset(&call_peer, 0, sizeof(call_peer));
+ }
// initialising the CallVariable with the Scenario variable
- bool test_var=false;
- int i,j;
- for(i=0; i<SCEN_VARIABLE_SIZE; i++)
- {
- for (j=0; j<SCEN_MAX_MESSAGES; j++)
- {
- if(scenVariableTable[i][j] != NULL) {
- test_var=true;
- break;
- }
- }
- if (test_var) {
- M_callVariableTable[i] = new CCallVariable();
- if (M_callVariableTable[i] == NULL) {
- ERROR ("call variable allocation failed");
- }
- } else {
- M_callVariableTable[i] = NULL;
- }
- }
+ int i;
+ VariableTable *userVars = NULL;
+ bool putUserVars = false;
+ if (userId) {
+ int_vt_map::iterator it = userVarMap.find(userId);
+ if (it != userVarMap.end()) {
+ userVars = it->second;
+ }
+ } else {
+ userVars = new VariableTable(userVariables);
+ /* Creating this table creates a reference to it, but if it is really used,
+ * then the refcount will be increased. */
+ putUserVars = true;
+ }
+ if (call_scenario->allocVars->size > 0) {
+ if (userVars) {
+ M_callVariableTable = new VariableTable(userVars, call_scenario->allocVars->size);
+ } else {
+ M_callVariableTable = new VariableTable(userVars, call_scenario->allocVars->size);
+ }
+ } else if (userVars->size > 0) {
+ M_callVariableTable = userVars->getTable();
+ } else if (globalVariables->size > 0) {
+ M_callVariableTable = globalVariables->getTable();
+ } else {
+ M_callVariableTable = NULL;
+ }
+ if (putUserVars) {
+ userVars->putTable();
+ }
+
+ if (call_scenario->maxTxnUsed > 0) {
+ txnID = (char **)malloc(sizeof(char *) * call_scenario->maxTxnUsed);
+ memset(txnID, 0, sizeof(char *) * call_scenario->maxTxnUsed);
+ } else {
+ txnID = NULL;
+ }
// If not updated by a message we use the start time
// information to compute rtd information
@@ -624,14 +429,21 @@
// by default, last action result is NO_ERROR
last_action_result = call::E_AR_NO_ERROR;
- if (InputFileRandomOrder == m_usage) {
- m_localLineNumber = rand() % numLinesInFile;
+ this->userId = userId;
+
+ /* For automatic answer calls to an out of call request, we must not */
+ /* increment the input files line numbers to not disturb */
+ /* the input files read mechanism (otherwise some lines risk */
+ /* to be systematically skipped */
+ if (!isAutomatic) {
+ m_lineNumber = new file_line_map();
+ for (file_map::iterator file_it = inFiles.begin();
+ file_it != inFiles.end();
+ file_it++) {
+ (*m_lineNumber)[file_it->first] = file_it->second->nextLine(userId);
+ }
} else {
- m_localLineNumber = m_counter++;
- if (m_counter >= numLinesInFile) {
- m_counter = 0;
- }
-
+ m_lineNumber = NULL;
}
#ifdef PCAPPLAY
@@ -645,72 +457,68 @@
peer_tag = NULL;
recv_timeout = 0;
+ send_timeout = 0;
+ timewait = false;
+
+ if (!isAutomatic) {
+ /* Not advancing the number is safe, because for automatic calls we do not
+ * assign the identifier, the only other place it is used is for the auto
+ * media port. */
+ number = next_number++;
+
+ if (use_tdmmap) {
+ tdm_map_number = get_tdm_map_number();
+ if (tdm_map_number == 0) {
+ /* Can't create the new call */
+ WARNING("Can't create new outgoing call: all tdm_map circuits busy");
+ computeStat(CStat::E_CALL_FAILED);
+ computeStat(CStat::E_FAILED_OUTBOUND_CONGESTION);
+ this->zombie = true;
+ return;
+ }
+ /* Mark the entry in the list as busy */
+ tdm_map[tdm_map_number - 1] = true;
+ } else {
+ tdm_map_number = 0;
+ }
+ }
+
+ setRunning();
}
call::~call()
{
- deleted += 1;
+ computeStat(CStat::E_ADD_CALL_DURATION, clock_tick - start_time);
if(comp_state) { comp_free(&comp_state); }
- if(count_in_stats) {
- CStat::instance()->computeStat(CStat::E_ADD_CALL_DURATION,
- clock_tick - start_time);
- }
-
-#ifdef _USE_OPENSSL
-
- if ((toolMode == MODE_SERVER) && (multisocket)) {
- if (ssl_list[call_socket] != NULL) {
- if((pollset_index) && (pollfiles[pollset_index].fd == call_socket)) {
- SSL_set_shutdown(ssl_list[call_socket],SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
- SSL_free(ssl_list[call_socket]);
- ssl_list[call_socket] = NULL ;
- pollset_remove(pollset_index);
- shutdown(call_socket, SHUT_RDWR);
- close(call_socket);
- }
- }
- }
-
- if ((toolMode != MODE_SERVER) && (multisocket)) {
- if(pollset_index ) {
- if (ssl_list[call_socket] != NULL) {
- // SSL_shutdown(ssl_list[call_socket]);
- SSL_set_shutdown(ssl_list[call_socket],SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
- SSL_free(ssl_list[call_socket]);
- // BIO_free(m_bio);
- // m_bio = NULL ;
- m_ctx_ssl = NULL ;
- }
- }
- }
-#endif
-
- if (toolMode != MODE_SERVER) {
- // TRACE_MSG((s,"socket close %d at idx = %d\n", socket_close, pollset_index));
- if(pollset_index) {
- if (socket_close) {
- pollset_remove(pollset_index);
- shutdown(call_socket, SHUT_RDWR);
- close(call_socket);
- }
- }
- } else {
- if (call_remote_socket) {
- close(call_remote_socket);
- }
- }
-
- /* Deletion of the call variable */
- for(int i=0; i<SCEN_VARIABLE_SIZE; i++) {
- if(M_callVariableTable[i] != NULL) {
- delete M_callVariableTable[i] ;
- M_callVariableTable[i] = NULL;
- }
- }
-
- if(id) { free(id); }
+
+ if (call_remote_socket) {
+ sipp_close_socket(call_remote_socket);
+ }
+
+ /* Deletion of the call variable */
+ if(M_callVariableTable) {
+ M_callVariableTable->putTable();
+ }
+ if (m_lineNumber) {
+ delete m_lineNumber;
+ }
+ if (userId) {
+ if (call_scenario->stats->GetStat(CStat::CPT_C_CurrentCall) >= open_calls_allowed) {
+ retiredUsers.push_front(userId);
+ } else {
+ freeUsers.push_front(userId);
+ }
+ }
+
+ if (txnID) {
+ for (int i = 0; i < call_scenario->maxTxnUsed; i++) {
+ free(txnID[i]);
+ }
+ free(txnID);
+ }
+
if(last_recv_msg) { free(last_recv_msg); }
if(last_send_msg) { free(last_send_msg); }
if(peer_tag) { free(peer_tag); }
@@ -723,56 +531,92 @@
free(next_req_url);
}
+
#ifdef _USE_OPENSSL
if(dialog_authentication) {
free(dialog_authentication);
}
#endif
- call_established= false ;
-}
-
-void call::connect_socket_if_needed()
-{
-#ifdef _USE_OPENSSL
- int err;
- SSL *L_ssl_tcp_multiplex=NULL ;
-#endif
-
- if(call_socket) return;
- if(!multisocket) return;
+
+ if (use_tdmmap) {
+ tdm_map[tdm_map_number] = false;
+ }
+}
+
+void call::computeStat (CStat::E_Action P_action) {
+ call_scenario->stats->computeStat(P_action);
+}
+
+void call::computeStat (CStat::E_Action P_action, unsigned long P_value) {
+ call_scenario->stats->computeStat(P_action, P_value);
+}
+
+void call::computeStat (CStat::E_Action P_action, unsigned long P_value, int which) {
+ call_scenario->stats->computeStat(P_action, P_value, which);
+}
+
+/* Dump call info to error log. */
+void call::dump() {
+ char s[MAX_HEADER_LEN];
+ sprintf(s, "%s: State %d", id, msg_index);
+ if (next_retrans) {
+ sprintf(s, "%s (next retrans %ld)", s, next_retrans);
+ }
+ if (paused_until) {
+ sprintf(s, "%s (paused until %ld)", s, paused_until);
+ }
+ if (recv_timeout) {
+ sprintf(s, "%s (recv timeout %ld)", s, recv_timeout);
+ }
+ if (send_timeout) {
+ sprintf(s, "%s (send timeout %ld)", s, send_timeout);
+ }
+ WARNING("%s", s);
+}
+
+bool call::connect_socket_if_needed()
+{
+ bool existing;
+
+ if(call_socket) return true;
+ if(!multisocket) return true;
if(transport == T_UDP) {
struct sockaddr_storage saddr;
- sipp_socklen_t len;
-
- int L_status = 0 ; // no new socket
-
- if(toolMode != MODE_CLIENT) return;
+
+ if(toolMode != MODE_CLIENT)
+ return true;
char peripaddr[256];
if (!peripsocket) {
- if ((call_socket = new_socket(use_ipv6, SOCK_DGRAM, &L_status)) == -1) {
- ERROR_NO("Unable to get a UDP socket");
- }
- } else {
- getIpFieldFromInputFile(peripfield, m_localLineNumber, peripaddr);
- map<string, int>::iterator i;
- i = map_perip_fd.find(peripaddr);
- if (i == map_perip_fd.end()) {
- // Socket does not exist
- if ((call_socket = new_socket(use_ipv6, SOCK_DGRAM, &L_status)) == -1) {
- ERROR_NO("Unable to get a UDP socket");
- } else {
- map_perip_fd[peripaddr] = call_socket;
- }
- } else {
- // Socket exists already
- call_socket = i->second;
- }
- }
-
-
- if (L_status) {
+ if ((associate_socket(new_sipp_call_socket(use_ipv6, transport, &existing))) == NULL) {
+ ERROR_NO("Unable to get a UDP socket");
+ }
+ } else {
+ char *tmp = peripaddr;
+ getFieldFromInputFile(ip_file, peripfield, NULL, tmp);
+ map<string, struct sipp_socket *>::iterator i;
+ i = map_perip_fd.find(peripaddr);
+ if (i == map_perip_fd.end()) {
+ // Socket does not exist
+ if ((associate_socket(new_sipp_call_socket(use_ipv6, transport, &existing))) == NULL) {
+ ERROR_NO("Unable to get a UDP socket");
+ } else {
+ /* Ensure that it stays persistent, because it is recorded in the map. */
+ call_socket->ss_count++;
+ map_perip_fd[peripaddr] = call_socket;
+ }
+ } else {
+ // Socket exists already
+ associate_socket(i->second);
+ existing = true;
+ i->second->ss_count++;
+ }
+ }
+ if (existing) {
+ return true;
+ }
+
memset(&saddr, 0, sizeof(struct sockaddr_storage));
memcpy(&saddr,
@@ -808,119 +652,69 @@
}
}
- if(bind(call_socket,
- (sockaddr *)(void *)&saddr,
- use_ipv6 ? sizeof(struct sockaddr_in6) :
- sizeof(struct sockaddr_in))) {
+ if (sipp_bind_socket(call_socket, &saddr, &call_port)) {
ERROR_NO("Unable to bind UDP socket");
}
+ } else { /* TCP or TLS. */
+ struct sockaddr_storage *L_dest = &remote_sockaddr;
+
+ if ((associate_socket(new_sipp_call_socket(use_ipv6, transport, &existing))) == NULL) {
+ ERROR_NO("Unable to get a TCP socket");
+ }
+
+ if (existing) {
+ return true;
}
- if (use_ipv6) {
- len = sizeof(struct sockaddr_in6);
- } else {
- len = sizeof(struct sockaddr_in);
- }
-
- getsockname(call_socket,
- (sockaddr *)(void *)&saddr,
- &len);
-
- if (use_ipv6) {
- call_port =
- ntohs((short)((_RCAST(struct sockaddr_in6 *, &saddr))->sin6_port));
- } else {
- call_port
- = ntohs((short)((_RCAST(struct sockaddr_in *, &saddr))->sin_port));
- }
- /* Asks to receive incoming messages */
- if (L_status) {
- pollset_index = pollset_add(this, call_socket);
- }
-
- } else { /* TCP */
-
- int L_status = 0 ; // no new socket
- struct sockaddr_storage *L_dest = &remote_sockaddr;
-
- if ((call_socket = new_socket(use_ipv6, SOCK_STREAM, &L_status)) == -1) {
- ERROR_NO("Unable to get a TCP socket");
- }
-
- if (L_status) {
- sipp_customize_socket(call_socket);
-
- if (use_remote_sending_addr) {
- L_dest = &remote_sending_sockaddr;
- }
-
- if(connect(call_socket,
- (struct sockaddr *)(void *)L_dest,
- SOCK_ADDR_SIZE(&remote_sockaddr))) {
-
- if (reset_number > 0) {
+ sipp_customize_socket(call_socket);
+
+ if (use_remote_sending_addr) {
+ L_dest = &remote_sending_sockaddr;
+ }
+
+ if (sipp_connect_socket(call_socket, L_dest)) {
+ if (reconnect_allowed()) {
if(errno == EINVAL){
/* This occurs sometime on HPUX but is not a true INVAL */
WARNING("Unable to connect a TCP socket, remote peer error");
} else {
WARNING("Unable to connect a TCP socket");
}
- start_calls = 1;
+ /* This connection failed. We must be in multisocket mode, because
+ * otherwise we would already have a call_socket. This call can not
+ * succeed, but does not affect any of our other calls. We do decrement
+ * the reconnection counter however. */
+ if (reset_number != -1) {
+ reset_number--;
+ }
+
+ computeStat(CStat::E_CALL_FAILED);
+ computeStat(CStat::E_FAILED_TCP_CONNECT);
+ delete this;
+
+ return false;
} else {
- if(errno == EINVAL){
- /* This occurs sometime on HPUX but is not a true INVAL */
- ERROR("Unable to connect a TCP socket, remote peer error");
- } else {
- ERROR_NO("Unable to connect a TCP socket");
- }
- }
- } else {
-#ifdef _USE_OPENSSL
- if ( transport == T_TLS ) {
- m_ctx_ssl = sip_trp_ssl_ctx ;
-
-
- if (!(L_ssl_tcp_multiplex = SSL_new(m_ctx_ssl))){
- ERROR("Unable to create SSL object : Problem with SSL_new() \n");
- }
-
- // if ( (m_bio = BIO_new_socket(call_socket,BIO_NOCLOSE)) == NULL) {
-
- if ( (m_bio = BIO_new_socket(call_socket,BIO_CLOSE)) == NULL) {
- ERROR("Unable to create BIO object:Problem with BIO_new_socket()\n");
- }
-
-
- // SSL_set_fd(L_ssl_tcp_multiplex, call_socket);
- SSL_set_bio(L_ssl_tcp_multiplex,m_bio,m_bio);
- // SSL_set_bio(L_ssl_tcp_multiplex,bio,bio);
-
- if ( (err = SSL_connect(L_ssl_tcp_multiplex)) < 0 ) {
- ERROR("Error in SSL connection \n");
- }
- ssl_list[call_socket] = L_ssl_tcp_multiplex;
-
-
- }
-#endif
-
-
- /* Asks to receive incoming messages */
- pollset_index = pollset_add(this, call_socket);
- }
- }
- }
-}
-
-bool lost(int index)
+ if(errno == EINVAL){
+ /* This occurs sometime on HPUX but is not a true INVAL */
+ ERROR("Unable to connect a TCP socket, remote peer error");
+ } else {
+ ERROR_NO("Unable to connect a TCP socket");
+ }
+ }
+ }
+ }
+ return true;
+}
+
+bool call::lost(int index)
{
static int inited = 0;
double percent = global_lost;
if(!lose_packets) return false;
- if (scenario[index]->lost >= 0) {
- percent = scenario[index]->lost;
+ if (call_scenario->messages[index]->lost >= 0) {
+ percent = call_scenario->messages[index]->lost;
}
if (percent == 0) {
@@ -937,120 +731,77 @@
int call::send_raw(char * msg, int index)
{
- void ** state;
- int sock;
+ struct sipp_socket *sock;
int rc;
-#ifdef _USE_OPENSSL
- SSL *ssl;
- // extern SSL *ssl_list[];
-#endif
- if (useMessagef == 1) {
- struct timeval currentTime;
- GET_TIME (¤tTime);
- TRACE_MSG((s, "----------------------------------------------- %s\n"
- "%s message sent:\n\n%s\n",
- CStat::instance()->formatTime(¤tTime),
- TRANSPORT_TO_STRING(transport),
- msg));
- }
-
+
+ if (useShortMessagef == 1) {
+ struct timeval currentTime;
+ GET_TIME (¤tTime);
+ char* cs=get_header_content(msg,"CSeq:");
+ TRACE_SHORTMSG("%s\tS\t%s\tCSeq:%s\t%s\n",
+ CStat::formatTime(¤tTime),id, cs, get_first_line(msg));
+ }
+
if((index!=-1) && (lost(index))) {
- TRACE_MSG((s, "%s message voluntary lost (while sending).", TRANSPORT_TO_STRING(transport)));
+ TRACE_MSG("%s message voluntary lost (while sending).", TRANSPORT_TO_STRING(transport));
if(comp_state) { comp_free(&comp_state); }
- scenario[index] -> nb_lost++;
+ call_scenario->messages[index] -> nb_lost++;
return 0;
}
- if(call_socket) {
- state = &comp_state;
- sock = call_socket;
-
- if ((use_remote_sending_addr) && (toolMode == MODE_SERVER)) {
- if (!call_remote_socket) {
- struct sockaddr_storage *L_dest = &remote_sending_sockaddr;
-
- if(transport == T_UDP) {
- if((call_remote_socket= socket(use_ipv6 ? AF_INET6 : AF_INET,
- SOCK_DGRAM,
- 0))== -1) {
- ERROR_NO("Unable to get a socket for rsa option");
- }
- if(bind(call_remote_socket,
- (sockaddr *)(void *)L_dest,
- use_ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))) {
- ERROR_NO("Unable to bind UDP socket for rsa option");
- }
- } else {
- if((call_remote_socket= socket(use_ipv6 ? AF_INET6 : AF_INET,
- SOCK_STREAM,
- 0))== -1) {
- ERROR_NO("Unable to get a socket for rsa option");
+ sock = call_socket;
+
+ if ((use_remote_sending_addr) && (toolMode == MODE_SERVER)) {
+ if (!call_remote_socket) {
+ struct sockaddr_storage *L_dest = &remote_sending_sockaddr;
+
+ if((call_remote_socket= new_sipp_socket(use_ipv6, transport)) == NULL) {
+ ERROR_NO("Unable to get a socket for rsa option");
+ }
+
+ sipp_customize_socket(call_remote_socket);
+
+ if(transport != T_UDP) {
+ if (sipp_connect_socket(call_remote_socket, L_dest)) {
+ if(errno == EINVAL){
+ /* This occurs sometime on HPUX but is not a true INVAL */
+ ERROR("Unable to connect a %s socket for rsa option, remote peer error", TRANSPORT_TO_STRING(transport));
+ } else {
+ ERROR_NO("Unable to connect a socket for rsa option");
}
- sipp_customize_socket(call_remote_socket);
-
- if(connect(call_remote_socket,
- (struct sockaddr *)(void *)L_dest,
- SOCK_ADDR_SIZE(&remote_sockaddr))) {
- if(errno == EINVAL){
- /* This occurs sometime on HPUX but is not a true INVAL */
- ERROR_P1("Unable to connect a %s socket for rsa option, remote peer error", TRANSPORT_TO_STRING(transport));
- } else {
- ERROR_NO("Unable to connect a socket for rsa option");
- }
- }
- }
- }
- sock=call_remote_socket ;
- }
-
-#ifdef _USE_OPENSSL
- ssl = ssl_list[sock];
- // ssl = m_ssl;
-#endif
- } else {
- state = &monosocket_comp_state;
- if(transport == T_UDP) {
- sock = main_socket;
- } else {
- sock = tcp_multiplex;
-#ifdef _USE_OPENSSL
- ssl = ssl_tcp_multiplex;
-#endif
- }
- }
-
-#ifdef _USE_OPENSSL
- if ( transport == T_TLS ) {
- rc = send_message_tls(ssl, state, msg);
- } else {
-#endif
- rc = send_message(sock, state, msg);
-#ifdef _USE_OPENSSL
- }
-#endif
-
- if(rc == -1) return -1;
-
- if(rc < -1) {
- CStat::instance()->computeStat(CStat::E_CALL_FAILED);
- CStat::instance()->computeStat(CStat::E_FAILED_CANNOT_SEND_MSG);
- delete_call(id);
- }
-
+ }
+ }
+ }
+ sock=call_remote_socket ;
+ }
+
+ rc = write_socket(sock, msg, strlen(msg), WS_BUFFER, &call_peer);
+ if(rc == -1 && errno == EWOULDBLOCK) {
+ return -1;
+ }
+
+ if(rc < 0) {
+ computeStat(CStat::E_CALL_FAILED);
+ computeStat(CStat::E_FAILED_CANNOT_SEND_MSG);
+ delete this;
+ }
+
return rc; /* OK */
}
/* This method is used to send messages that are not */
/* part of the XML scenario */
-int call::sendBuffer(char * msg)
-{
- int rc;
-
+void call::sendBuffer(char * msg)
+{
/* call send_raw but with a special scenario index */
- rc=send_raw(msg, -1);
-
- return rc;
+ if (send_raw(msg, -1) < 0) {
+ if (sendbuffer_warn) {
+ ERROR_NO("Error sending raw message");
+ } else {
+ WARNING_NO("Error sending raw message");
+ }
+ }
}
@@ -1107,7 +858,7 @@
/* Ideally this check should be moved to the XML parser so that it is not
* along a critical path. We could also handle lowercasing there. */
if (len > MAX_HEADER_LEN) {
- ERROR_P2("call::get_last_header: Header to parse bigger than %d (%zu)", MAX_HEADER_LEN, strlen(name));
+ ERROR("call::get_last_header: Header to parse bigger than %d (%zu)", MAX_HEADER_LEN, strlen(name));
}
if (name[len - 1] == ':') {
@@ -1132,6 +883,7 @@
char * src, *dest, *start, *ptr;
/* Are we searching for a short form header? */
bool short_form = false;
+ bool first_time = true;
char src_tmp[MAX_HEADER_LEN + 1];
/* returns empty string in case of error */
@@ -1143,7 +895,7 @@
/* for safety's sake */
if (NULL == name || NULL == strrchr(name, ':')) {
- WARNING_P1("Can not searching for header (no colon): %s", name ? name : "(null)");
+ WARNING("Can not searching for header (no colon): %s", name ? name : "(null)");
return last_header;
}
@@ -1154,12 +906,13 @@
dest = last_header;
while(src = strcasestr2(src, src_tmp)) {
- if (content) {
+ if (content || !first_time) {
/* just want the header's content */
src += strlen(name) + 1;
} else {
- src++;
- }
+ src++;
+ }
+ first_time = false;
ptr = strchr(src, '\n');
/* Multiline headers always begin with a tab or a space
@@ -1174,19 +927,12 @@
// Add "," when several headers are present
if (dest != last_header) {
/* Remove trailing whitespaces, tabs, and CRs */
- *(dest--) = 0;
while ((dest > last_header) &&
- ((*dest == ' ') || (*dest == '\r')|| (*dest == '\t'))) {
- *(dest--) = 0;
+ ((*(dest-1) == ' ') || (*(dest-1) == '\r') || (*(dest-1) == '\n') || (*(dest-1) == '\t'))) {
+ *(--dest) = 0;
}
dest += sprintf(dest, ",");
-
- /* We only want to append the contents of the header, not its name for
- * the second value. */
- if (!content) {
- src += strlen(name);
- }
}
dest += sprintf(dest, "%s", src);
if(ptr) { *ptr = '\n'; }
@@ -1260,6 +1006,78 @@
return start;
}
+char * call::get_first_line(char * message)
+{
+ /* non reentrant. consider accepting char buffer as param */
+ static char last_header[MAX_HEADER_LEN * 10];
+ char * src, *dest;
+
+ /* returns empty string in case of error */
+ memset(last_header, 0, sizeof(last_header));
+
+ if((!message) || (!strlen(message))) {
+ return last_header;
+ }
+
+ src = message;
+ dest = last_header;
+
+ int i=0;
+ while (*src){
+ if((*src=='\n')||(*src=='\r')){
+ break;
+ }
+ else
+ {
+ last_header[i]=*src;
+ }
+ i++;
+ src++;
+ }
+
+ return last_header;
+}
+
+/* Return the last request URI from the To header. On any error returns the
+ * empty string. The caller must free the result. */
+char * call::get_last_request_uri ()
+{
+ char * tmp;
+ char * tmp2;
+ char * last_request_uri;
+ int tmp_len;
+
+ char * last_To = get_last_header("To:");
+ if (!last_To) {
+ return strdup("");
+ }
+
+ tmp = strchr(last_To, '<');
+ if (!tmp) {
+ return strdup("");
+ }
+ tmp++;
+
+ tmp2 = strchr(last_To, '>');
+ if (!tmp2) {
+ return strdup("");
+ }
+
+ tmp_len = strlen(tmp) - strlen(tmp2);
+ if (tmp_len < 0) {
+ return strdup("");
+ }
+
+ if(!(last_request_uri = (char *) malloc(tmp_len+1))) ERROR("Cannot allocate !\n");
+ memset(last_request_uri, 0, sizeof(last_request_uri));
+ if(tmp && (tmp_len > 0)){
+ strncpy(last_request_uri, tmp, tmp_len);
+ }
+ last_request_uri[tmp_len] = '\0';
+ return last_request_uri;
+
+}
+
char * call::send_scene(int index, int *send_status)
{
static char msg_buffer[SIPP_MAX_MSG_SIZE];
@@ -1270,37 +1088,44 @@
char *L_ptr2 ;
/* Socket port must be known before string substitution */
- connect_socket_if_needed();
-
- if(scenario[index] -> send_scheme) {
- char * dest;
- dest = createSendingMessage(scenario[index] -> send_scheme, index);
- strcpy(msg_buffer, dest);
-
- if (dest) {
- L_ptr1=msg_name ;
- L_ptr2=msg_buffer ;
- while ((*L_ptr2 != ' ') && (*L_ptr2 != '\n') && (*L_ptr2 != '\t')) {
- *L_ptr1 = *L_ptr2;
- L_ptr1 ++;
- L_ptr2 ++;
- }
- *L_ptr1 = '\0' ;
- }
-
- if (strcmp(msg_name,"ACK") == 0) {
- call_established = true ;
- ack_is_pending = false ;
- }
-
- if(send_status) {
- *send_status =
- send_raw(msg_buffer, index);
- } else {
- send_raw(msg_buffer, index);
- }
+ if (!connect_socket_if_needed()) {
+ *send_status = -2;
+ return NULL;
+ }
+
+ assert(call_socket);
+
+ if (call_socket->ss_congested) {
+ *send_status = -1;
+ return NULL;
+ }
+
+ assert(call_scenario->messages[index]->send_scheme);
+
+ char * dest;
+ dest = createSendingMessage(call_scenario->messages[index] -> send_scheme, index);
+ strcpy(msg_buffer, dest);
+
+ if (dest) {
+ L_ptr1=msg_name ;
+ L_ptr2=msg_buffer ;
+ while ((*L_ptr2 != ' ') && (*L_ptr2 != '\n') && (*L_ptr2 != '\t')) {
+ *L_ptr1 = *L_ptr2;
+ L_ptr1 ++;
+ L_ptr2 ++;
+ }
+ *L_ptr1 = '\0' ;
+ }
+
+ if (strcmp(msg_name,"ACK") == 0) {
+ call_established = true ;
+ ack_is_pending = false ;
+ }
+
+ if(send_status) {
+ *send_status = send_raw(msg_buffer, index);
} else {
- ERROR("Unsupported 'send' message in scenario");
+ send_raw(msg_buffer, index);
}
return msg_buffer;
@@ -1308,75 +1133,108 @@
void call::do_bookkeeping(int index) {
/* If this message increments a counter, do it now. */
- if(int counter = scenario[index] -> counter) {
- CStat::instance()->computeStat(CStat::E_ADD_GENERIC_COUNTER, 1, counter - 1);
+ if(int counter = call_scenario->messages[index] -> counter) {
+ computeStat(CStat::E_ADD_GENERIC_COUNTER, 1, counter - 1);
}
/* If this message can be used to compute RTD, do it now */
- if(int rtd = scenario[index] -> start_rtd) {
+ if(int rtd = call_scenario->messages[index] -> start_rtd) {
start_time_rtd[rtd - 1] = getmicroseconds();
}
- if(int rtd = scenario[index] -> stop_rtd) {
+ if(int rtd = call_scenario->messages[index] -> stop_rtd) {
if (!rtd_done[rtd - 1]) {
unsigned long long start = start_time_rtd[rtd - 1];
unsigned long long end = getmicroseconds();
if(dumpInRtt) {
- CStat::instance()->computeRtt(start, end, rtd);
- }
-
- CStat::instance()->computeStat(CStat::E_ADD_RESPONSE_TIME_DURATION,
+ call_scenario->stats->computeRtt(start, end, rtd);
+ }
+
+ computeStat(CStat::E_ADD_RESPONSE_TIME_DURATION,
(end - start) / 1000, rtd - 1);
- if (!scenario[index] -> repeat_rtd) {
+ if (!call_scenario->messages[index] -> repeat_rtd) {
rtd_done[rtd - 1] = true;
}
}
}
}
+void call::tcpClose() {
+ terminate(CStat::E_FAILED_TCP_CLOSED);
+}
+
+bool call::terminate(CStat::E_Action reason) {
+ char reason_str[100];
+
+ stopListening();
+
+ // Call end -> was it successful?
+ if(call::last_action_result != call::E_AR_NO_ERROR) {
+ switch(call::last_action_result) {
+ case call::E_AR_REGEXP_DOESNT_MATCH:
+ computeStat(CStat::E_CALL_FAILED);
+ computeStat(CStat::E_FAILED_REGEXP_DOESNT_MATCH);
+ if (deadcall_wait) {
+ sprintf(reason_str, "regexp match failure at index %d", msg_index);
+ new deadcall(id, reason_str);
+ }
+ break;
+ case call::E_AR_HDR_NOT_FOUND:
+ computeStat(CStat::E_CALL_FAILED);
+ computeStat(CStat::E_FAILED_REGEXP_HDR_NOT_FOUND);
+ if (deadcall_wait) {
+ sprintf(reason_str, "regexp header not found at index %d", msg_index);
+ new deadcall(id, reason_str);
+ }
+ break;
+ case call::E_AR_NO_ERROR:
+ case call::E_AR_STOP_CALL:
+ /* Do nothing. */
+ break;
+ }
+ } else {
+ if (reason == CStat::E_CALL_SUCCESSFULLY_ENDED || timewait) {
+ computeStat(CStat::E_CALL_SUCCESSFULLY_ENDED);
+ if (deadcall_wait) {
+ new deadcall(id, "successful");
+ }
+ } else {
+ computeStat(CStat::E_CALL_FAILED);
+ if (reason != CStat::E_NO_ACTION) {
+ computeStat(reason);
+ }
+ if (deadcall_wait) {
+ sprintf(reason_str, "failed at index %d", msg_index);
+ new deadcall(id, reason_str);
+ }
+ }
+ }
+ delete this;
+}
+
bool call::next()
{
- int test = scenario[msg_index]->test;
+ int test = call_scenario->messages[msg_index]->test;
/* What is the next message index? */
/* Default without branching: use the next message */
int new_msg_index = msg_index+1;
/* If branch needed, overwrite this default */
- if ( scenario[msg_index]->next &&
- ((test == -1) ||
- (test < SCEN_VARIABLE_SIZE && M_callVariableTable[test] != NULL && M_callVariableTable[test]->isSet()))
+ if ( (call_scenario->messages[msg_index]->next >= 0) &&
+ ((test == -1) || M_callVariableTable->getVar(test)->isSet())
) {
/* Branching possible, check the probability */
- int chance = scenario[msg_index]->chance;
+ int chance = call_scenario->messages[msg_index]->chance;
if ((chance <= 0) || (rand() > chance )) {
/* Branch == overwrite with the 'next' attribute value */
- new_msg_index = labelArray[scenario[msg_index]->next];
+ new_msg_index = call_scenario->messages[msg_index]->next;
}
}
msg_index=new_msg_index;
recv_timeout = 0;
- if(msg_index >= scenario_len) {
- // Call end -> was it successful?
- if(call::last_action_result != call::E_AR_NO_ERROR) {
- switch(call::last_action_result) {
- case call::E_AR_REGEXP_DOESNT_MATCH:
- CStat::instance()->computeStat(CStat::E_CALL_FAILED);
- CStat::instance()->computeStat(CStat::E_FAILED_REGEXP_DOESNT_MATCH);
- break;
- case call::E_AR_HDR_NOT_FOUND:
- CStat::instance()->computeStat(CStat::E_CALL_FAILED);
- CStat::instance()->computeStat(CStat::E_FAILED_REGEXP_HDR_NOT_FOUND);
- break;
- case call::E_AR_NO_ERROR:
- case call::E_AR_STOP_CALL:
- /* Do nothing. */
- break;
- }
- } else {
- CStat::instance()->computeStat(CStat::E_CALL_SUCCESSFULLY_ENDED);
- }
- delete_call(id);
+ if(msg_index >= call_scenario->length) {
+ terminate(CStat::E_CALL_SUCCESSFULLY_ENDED);
return false;
}
@@ -1390,12 +1248,19 @@
assert(running);
+ if (zombie) {
+ delete this;
+ return false;
+ }
+
clock_tick = getmilliseconds();
- if(msg_index >= scenario_len) {
- ERROR_P3("Scenario overrun for call %s (%p) (index = %d)\n",
+ if(msg_index >= call_scenario->length) {
+ ERROR("Scenario overrun for call %s (%p) (index = %d)\n",
id, this, msg_index);
}
+
+ message *curmsg = call_scenario->messages[msg_index];
/* Manages retransmissions or delete if max retrans reached */
if(next_retrans && (next_retrans < clock_tick)) {
@@ -1408,36 +1273,38 @@
if((nb_retrans > (bInviteTransaction ? max_invite_retrans : max_non_invite_retrans)) ||
(nb_retrans > max_udp_retrans)) {
- scenario[last_send_index] -> nb_timeout ++;
- if (scenario[last_send_index]->on_timeout) { // action on timeout
- WARNING_P3("Call-Id: %s, timeout on max UDP retrans for message %d, jumping to label %d ",
- id, msg_index, scenario[last_send_index]->on_timeout);
- msg_index = labelArray[scenario[last_send_index]->on_timeout];
+ call_scenario->messages[last_send_index] -> nb_timeout ++;
+ if (call_scenario->messages[last_send_index]->on_timeout >= 0) { // action on timeout
+ WARNING("Call-Id: %s, timeout on max UDP retrans for message %d, jumping to label %d ",
+ id, msg_index, call_scenario->messages[last_send_index]->on_timeout);
+ msg_index = call_scenario->messages[last_send_index]->on_timeout;
next_retrans = 0;
recv_timeout = 0;
- if (msg_index < scenario_len) return true;
+ if (msg_index < call_scenario->length) {
+ return true;
+ }
// here if asked to go to the last label delete the call
- CStat::instance()->computeStat(CStat::E_CALL_FAILED);
- CStat::instance()->computeStat(CStat::E_FAILED_MAX_UDP_RETRANS);
- if (default_behavior) {
+ computeStat(CStat::E_CALL_FAILED);
+ computeStat(CStat::E_FAILED_MAX_UDP_RETRANS);
+ if (default_behaviors & DEFAULT_BEHAVIOR_BYE) {
// Abort the call by sending proper SIP message
return(abortCall());
} else {
// Just delete existing call
- delete_call(id);
+ delete this;
return false;
}
}
- CStat::instance()->computeStat(CStat::E_CALL_FAILED);
- CStat::instance()->computeStat(CStat::E_FAILED_MAX_UDP_RETRANS);
- if (default_behavior) {
+ computeStat(CStat::E_CALL_FAILED);
+ computeStat(CStat::E_FAILED_MAX_UDP_RETRANS);
+ if (default_behaviors & DEFAULT_BEHAVIOR_BYE) {
// Abort the call by sending proper SIP message
- WARNING_P1("Aborting call on UDP retransmission timeout for Call-ID '%s'", id);
+ WARNING("Aborting call on UDP retransmission timeout for Call-ID '%s'", id);
return(abortCall());
} else {
// Just delete existing call
- delete_call(id);
+ delete this;
return false;
}
} else {
@@ -1452,8 +1319,8 @@
if(send_raw(last_send_msg, last_send_index) < -1) {
return false;
}
- scenario[last_send_index] -> nb_sent_retrans++;
- CStat::instance()->computeStat(CStat::E_RETRANSMISSION);
+ call_scenario->messages[last_send_index] -> nb_sent_retrans++;
+ computeStat(CStat::E_RETRANSMISSION);
next_retrans = clock_tick + nb_last_delay;
}
}
@@ -1461,29 +1328,40 @@
if(paused_until) {
/* Process a pending pause instruction until delay expiration */
if(paused_until > clock_tick) {
- if (!remove_running_call(this)) {
- ERROR("Tried to remove a running call that wasn't running!\n");
- }
- paused_calls.add_paused_call(this, true);
+ setPaused();
return true;
}
/* Our pause is over. */
paused_until = 0;
return next();
- } else if(scenario[msg_index] -> pause_function) {
+ } else if(curmsg -> pause_distribution || curmsg->pause_variable != -1) {
unsigned int pause;
- pause = scenario[msg_index] -> pause_function(scenario[msg_index]);
+ if (curmsg->pause_distribution) {
+ pause = (int)(curmsg -> pause_distribution -> sample());
+ } else {
+ int varId = curmsg->pause_variable;
+ pause = (int) M_callVariableTable->getVar(varId)->getDouble();
+ }
+ if (pause < 0) {
+ pause = 0;
+ }
if (pause > INT_MAX) {
pause = INT_MAX;
}
paused_until = clock_tick + pause;
+ /* This state is used as the last message of a scenario, just for handling
+ * final retransmissions. If the connection closes, we do not mark it is
+ * failed. */
+ this->timewait = curmsg->timewait;
+
/* Increment the number of sessions in pause state */
- ++scenario[msg_index]->sessions;
+ curmsg->sessions++;
+ do_bookkeeping(msg_index);
+ actionResult = executeAction(NULL, msg_index);
return run(); /* In case delay is 0 */
- }
-#ifdef __3PCC__
- else if(scenario[msg_index] -> M_type == MSG_TYPE_SENDCMD) {
+ }
+ else if(curmsg -> M_type == MSG_TYPE_SENDCMD) {
int send_status;
if(next_retrans) {
@@ -1495,18 +1373,20 @@
if(send_status != 0) { /* Send error */
return false; /* call deleted */
}
- scenario[msg_index] -> M_nbCmdSent++;
+ curmsg -> M_nbCmdSent++;
next_retrans = 0;
- return(next());
- }
-#endif
- else if(scenario[msg_index] -> M_type == MSG_TYPE_NOP) {
+
do_bookkeeping(msg_index);
actionResult = executeAction(NULL, msg_index);
return(next());
}
-
- else if(scenario[msg_index] -> send_scheme) {
+ else if(curmsg -> M_type == MSG_TYPE_NOP) {
+ do_bookkeeping(msg_index);
+ actionResult = executeAction(NULL, msg_index);
+ return(next());
+ }
+
+ else if(curmsg -> send_scheme) {
char * msg_snd;
int send_status;
@@ -1514,10 +1394,7 @@
* retransmission enabled is acknowledged */
if(next_retrans) {
- if (!remove_running_call(this)) {
- ERROR("Tried to remove a running call that wasn't running!\n");
- }
- paused_calls.add_paused_call(this, true);
+ setPaused();
return true;
}
@@ -1531,175 +1408,324 @@
*/
int incr_cseq = 0;
- if (strncmp(::scenario[msg_index]->send_scheme,"ACK",3) &&
- strncmp(::scenario[msg_index]->send_scheme,"CANCEL",6) &&
- strncmp(::scenario[msg_index]->send_scheme,"SIP/2.0",7)) {
+ if (!curmsg->send_scheme->isAck() &&
+ !curmsg->send_scheme->isCancel() &&
+ !curmsg->send_scheme->isResponse()) {
++cseq;
incr_cseq = 1;
}
- if ((ctrlEW) || (poll_flag_write)) {
- send_status = -1;
- } else {
msg_snd = send_scene(msg_index, &send_status);
- }
-
- if(send_status == -1) { /* Would Block on TCP */
+ if(send_status == -1 && errno == EWOULDBLOCK) {
if (incr_cseq) --cseq;
+ /* Have we set the timeout yet? */
+ if (send_timeout) {
+ /* If we have actually timed out. */
+ if (clock_tick > send_timeout) {
+ WARNING("Call-Id: %s, send timeout on message %d: aborting call",
+ id, msg_index);
+ computeStat(CStat::E_CALL_FAILED);
+ computeStat(CStat::E_FAILED_TIMEOUT_ON_SEND);
+ if (default_behaviors & DEFAULT_BEHAVIOR_BYE) {
+ return (abortCall());
+ } else {
+ delete this;
+ return false;
+ }
+ }
+ } else if (curmsg->timeout) {
+ /* Initialize the send timeout to the per message timeout. */
+ send_timeout = clock_tick + curmsg->timeout;
+ } else if (defl_send_timeout) {
+ /* Initialize the send timeout to the global timeout. */
+ send_timeout = clock_tick + defl_send_timeout;
+ }
return true; /* No step, nothing done, retry later */
- } else if(send_status <-1) { /* Send error */
- return false; /* call deleted */
- }
-
+ } else if(send_status < 0) { /* Send error */
+ /* The timeout will not be sent, so the timeout is no longer needed. */
+ send_timeout = 0;
+ /* The call was already deleted by connect_socket_if_needed or send_raw. */
+ return false;
+ }
+ /* We have sent the message, so the timeout is no longer needed. */
+ send_timeout = 0;
+
last_send_index = msg_index;
last_send_msg = (char *) realloc(last_send_msg, strlen(msg_snd) + 1);
strcpy(last_send_msg, msg_snd);
- if(last_recv_hash) {
+ if (curmsg->start_txn) {
+ txnID[curmsg->start_txn - 1] = (char *)realloc(txnID[curmsg->start_txn - 1], MAX_HEADER_LEN);
+ extract_transaction(txnID[curmsg->start_txn - 1], last_send_msg);
+ }
+
+ if(last_recv_index >= 0) {
/* We are sending just after msg reception. There is a great
* chance that we will be asked to retransmit this message */
recv_retrans_hash = last_recv_hash;
recv_retrans_recv_index = last_recv_index;
recv_retrans_send_index = msg_index;
-
+
/* Prevent from detecting the cause relation between send and recv
* in the next valid send */
last_recv_hash = 0;
}
/* Update retransmission information */
- if(scenario[msg_index] -> retrans_delay) {
+ if(curmsg -> retrans_delay) {
if((transport == T_UDP) && (retrans_enabled)) {
- next_retrans = clock_tick + scenario[msg_index] -> retrans_delay;
+ next_retrans = clock_tick + curmsg -> retrans_delay;
nb_retrans = 0;
- nb_last_delay = scenario[msg_index]->retrans_delay;
+ nb_last_delay = curmsg->retrans_delay;
}
} else {
next_retrans = 0;
}
-
-#ifdef PCAPPLAY
+
actionResult = executeAction(msg_snd, msg_index);
-#endif
-
+
/* Update scenario statistics */
- scenario[msg_index] -> nb_sent++;
+ curmsg -> nb_sent++;
return next();
- } else if (scenario[msg_index]->M_type == MSG_TYPE_RECV
-#ifdef __3PCC__
- || scenario[msg_index]->M_type == MSG_TYPE_RECVCMD
-#endif
+ } else if (curmsg->M_type == MSG_TYPE_RECV
+ || curmsg->M_type == MSG_TYPE_RECVCMD
) {
- if (recv_timeout) {
+ if (queued_msg) {
+ char *msg = queued_msg;
+ queued_msg = NULL;
+ bool ret = process_incoming(msg);
+ free(msg);
+ return ret;
+ } else if (recv_timeout) {
if(recv_timeout > clock_tick || recv_timeout > getmilliseconds()) {
- if (!remove_running_call(this)) {
- ERROR("Tried to remove a running call that wasn't running!\n");
- }
- paused_calls.add_paused_call(this, true);
+ setPaused();
return true;
}
recv_timeout = 0;
- ++scenario[msg_index]->nb_timeout;
- if (scenario[msg_index]->on_timeout == 0) {
+ curmsg->nb_timeout++;
+ if (curmsg->on_timeout < 0) {
// if you set a timeout but not a label, the call is aborted
- WARNING_P2("Call-Id: %s, receive timeout on message %d without label to jump to (ontimeout attribute): aborting call",
+ WARNING("Call-Id: %s, receive timeout on message %d without label to jump to (ontimeout attribute): aborting call",
id, msg_index);
- CStat::instance()->computeStat(CStat::E_CALL_FAILED);
- CStat::instance()->computeStat(CStat::E_FAILED_TIMEOUT_ON_RECV);
- if (default_behavior) {
+ computeStat(CStat::E_CALL_FAILED);
+ computeStat(CStat::E_FAILED_TIMEOUT_ON_RECV);
+ if (default_behaviors & DEFAULT_BEHAVIOR_BYE) {
return (abortCall());
} else {
- delete_call(id);
+ delete this;
return false;
}
}
- WARNING_P3("Call-Id: %s, receive timeout on message %d, jumping to label %d",
- id, msg_index, scenario[msg_index]->on_timeout);
- msg_index = labelArray[scenario[msg_index]->on_timeout];
+ WARNING("Call-Id: %s, receive timeout on message %d, jumping to label %d",
+ id, msg_index, curmsg->on_timeout);
+ msg_index = curmsg->on_timeout;
recv_timeout = 0;
- if (msg_index < scenario_len) return true;
+ if (msg_index < call_scenario->length) return true;
// special case - the label points to the end - finish the call
- CStat::instance()->computeStat(CStat::E_CALL_FAILED);
- CStat::instance()->computeStat(CStat::E_FAILED_TIMEOUT_ON_RECV);
- if (default_behavior) {
+ computeStat(CStat::E_CALL_FAILED);
+ computeStat(CStat::E_FAILED_TIMEOUT_ON_RECV);
+ if (default_behaviors & DEFAULT_BEHAVIOR_BYE) {
return (abortCall());
} else {
- delete_call(id);
+ delete this;
return false;
}
- } else if ((scenario[msg_index]->retrans_delay) || (defl_recv_timeout)) {
- if (scenario[msg_index]->retrans_delay)
+ } else if (curmsg->timeout || defl_recv_timeout) {
+ if (curmsg->timeout)
// If timeout is specified on message receive, use it
- recv_timeout = getmilliseconds() + scenario[msg_index]->retrans_delay;
+ recv_timeout = getmilliseconds() + curmsg->timeout;
else
// Else use the default timeout if specified
recv_timeout = getmilliseconds() + defl_recv_timeout;
- return true;
+ return true;
} else {
/* We are going to wait forever. */
- if (!remove_running_call(this)) {
- ERROR("Tried to remove a running call that wasn't running!\n");
- }
- paused_calls.add_paused_call(this, true);
+ setPaused();
}
}
return true;
}
+char *default_message_names[] = {
+ "3pcc_abort",
+ "ack",
+ "ack2",
+ "bye",
+ "cancel",
+ "200",
+};
+char *default_message_strings[] = {
+ /* 3pcc_abort */
+ "call-id: [call_id]\ninternal-cmd: abort_call\n\n",
+ /* ack */
+ "ACK [last_Request_URI] SIP/2.0\n"
+ "[last_Via]\n"
+ "[last_From]\n"
+ "[last_To]\n"
+ "Call-ID: [call_id]\n"
+ "CSeq: [last_cseq_number] ACK\n"
+ "Contact: <sip:sipp@[local_ip]:[local_port];transport=[transport]>\n"
+ "Max-Forwards: 70\n"
+ "Subject: Performance Test\n"
+ "Content-Length: 0\n\n",
+ /* ack2, the only difference is Via, I don't quite know why. */
+ "ACK [last_Request_URI] SIP/2.0\n"
+ "Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n"
+ "[last_From]\n"
+ "[last_To]\n"
+ "Call-ID: [call_id]\n"
+ "CSeq: [last_cseq_number] ACK\n"
+ "Contact: <sip:sipp@[local_ip]:[local_port];transport=[transport]>\n"
+ "Max-Forwards: 70\n"
+ "Subject: Performance Test\n"
+ "Content-Length: 0\n\n",
+ /* bye */
+ "BYE [last_Request_URI] SIP/2.0\n"
+ "Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n"
+ "[last_From]\n"
+ "[last_To]\n"
+ "Call-ID: [call_id]\n"
+ "CSeq: [last_cseq_number+1] BYE\n"
+ "Max-Forwards: 70\n"
+ "Contact: <sip:sipp@[local_ip]:[local_port];transport=[transport]>\n"
+ "Content-Length: 0\n\n",
+ /* cancel */
+ "CANCEL [last_Request_URI] SIP/2.0\n"
+ "[last_Via]\n"
+ "[last_From]\n"
+ "[last_To]\n"
+ "Call-ID: [call_id]\n"
+ "CSeq: [last_cseq_number] CANCEL\n"
+ "Max-Forwards: 70\n"
+ "Contact: <sip:sipp@[local_ip]:[local_port];transport=[transport]>\n"
+ "Content-Length: 0\n\n",
+ /* 200 */
+ "SIP/2.0 200 OK\n"
+ "[last_Via:]\n"
+ "[last_From:]\n"
+ "[last_To:]\n"
+ "[last_Call-ID:]\n"
+ "[last_CSeq:]\n"
+ "Contact: <sip:[local_ip]:[local_port];transport=[transport]>\n"
+ "Content-Length: 0\n\n"
+};
+
+SendingMessage **default_messages;
+
+void init_default_messages() {
+ int messages = sizeof(default_message_strings)/sizeof(default_message_strings[0]);
+ default_messages = new SendingMessage* [messages];
+ for (int i = 0; i < messages; i++) {
+ default_messages[i] = new SendingMessage(main_scenario, default_message_strings[i]);
+ }
+}
+
+void free_default_messages() {
+ int messages = sizeof(default_message_strings)/sizeof(default_message_strings[0]);
+ if (!default_messages) {
+ return;
+ }
+ for (int i = 0; i < messages; i++) {
+ delete default_messages[i];
+ }
+ delete [] default_messages;
+}
+
+SendingMessage *get_default_message(const char *which) {
+ int messages = sizeof(default_message_names)/sizeof(default_message_names[0]);
+ for (int i = 0; i < messages; i++) {
+ if (!strcmp(which, default_message_names[i])) {
+ return default_messages[i];
+ }
+ }
+ ERROR("Internal Error: Unknown default message: %s!", which);
+}
+
+void set_default_message(const char *which, char *msg) {
+ int messages = sizeof(default_message_names)/sizeof(default_message_names[0]);
+ for (int i = 0; i < messages; i++) {
+ if (!strcmp(which, default_message_names[i])) {
+ default_message_strings[i] = msg;
+ return;
+ }
+ }
+ ERROR("Internal Error: Unknown default message: %s!", which);
+}
+
bool call::process_unexpected(char * msg)
{
- scenario[msg_index] -> nb_unexp++;
-
- if (scenario[msg_index] -> recv_request) {
- if (default_behavior) {
- WARNING_P3("Aborting call on unexpected message for Call-ID '%s': while expecting '%s', received '%s' ",
- id, scenario[msg_index] -> recv_request, msg);
+ char buffer[MAX_HEADER_LEN];
+ char *desc = buffer;
+
+ message *curmsg = call_scenario->messages[msg_index];
+
+ curmsg->nb_unexp++;
+
+ if (default_behaviors & DEFAULT_BEHAVIOR_ABORTUNEXP) {
+ desc += snprintf(desc, MAX_HEADER_LEN - (desc - buffer), "Aborting ");
} else {
- WARNING_P3("Continuing call on unexpected message for Call-ID '%s': while expecting '%s', received '%s' ",
- id, scenario[msg_index] -> recv_request, msg);
- }
+ desc += snprintf(desc, MAX_HEADER_LEN - (desc - buffer), "Continuing ");
+ }
+ desc += snprintf(desc, MAX_HEADER_LEN - (desc - buffer), "call on unexpected message for Call-Id '%s': ", id);
+
+ if (curmsg -> M_type == MSG_TYPE_RECV) {
+ if (curmsg -> recv_request) {
+ desc += snprintf(desc, MAX_HEADER_LEN - (desc - buffer), "while expecting '%s' ", curmsg -> recv_request);
+ } else {
+ desc += snprintf(desc, MAX_HEADER_LEN - (desc - buffer), "while expecting '%d' ", curmsg -> recv_response);
+ }
+ } else if (curmsg -> M_type == MSG_TYPE_SEND) {
+ desc += snprintf(desc, MAX_HEADER_LEN - (desc - buffer), "while sending ");
+ } else if (curmsg -> M_type == MSG_TYPE_PAUSE) {
+ desc += snprintf(desc, MAX_HEADER_LEN - (desc - buffer), "while pausing ");
+ } else if (curmsg -> M_type == MSG_TYPE_SENDCMD) {
+ desc += snprintf(desc, MAX_HEADER_LEN - (desc - buffer), "while sending command ");
+ } else if (curmsg -> M_type == MSG_TYPE_RECVCMD) {
+ desc += snprintf(desc, MAX_HEADER_LEN - (desc - buffer), "while expecting command ");
} else {
- if (default_behavior) {
- WARNING_P3("Aborting call on unexpected message for Call-ID '%s': while expecting '%d' response, received '%s' ",
- id, scenario[msg_index] -> recv_response, msg);
- } else {
- WARNING_P3("Continuing call on unexpected message for Call-ID '%s': while expecting '%d' response, received '%s' ",
- id, scenario[msg_index] -> recv_response, msg);
- }
- }
-
- TRACE_MSG((s, "-----------------------------------------------\n"
+ desc += snprintf(desc, MAX_HEADER_LEN - (desc - buffer), "while in message type %d ", curmsg->M_type);
+ }
+ desc += snprintf(desc, MAX_HEADER_LEN - (desc - buffer), "(index %d)", msg_index);
+
+ WARNING("%s, received '%s'", buffer, msg);
+
+ TRACE_MSG("-----------------------------------------------\n"
"Unexpected %s message received:\n\n%s\n",
TRANSPORT_TO_STRING(transport),
- msg));
-
- if (default_behavior) {
-#ifdef __3PCC__
- // if twin socket call => reset the other part here
- if (twinSippSocket && (msg_index > 0)) {
- //WARNING_P2("call-ID '%s', internal-cmd: abort_call %s",id, "");
- sendCmdBuffer
- (createSendingMessage((char*)"call-id: [call_id]\ninternal-cmd: abort_call\n", -1));
- }
-#endif /* __3PCC__ */
-
- // usage of last_ keywords => for call aborting
- last_recv_msg = (char *) realloc(last_recv_msg, strlen(msg) + 1);
- strcpy(last_recv_msg, msg);
-
- CStat::instance()->computeStat(CStat::E_CALL_FAILED);
- CStat::instance()->computeStat(CStat::E_FAILED_UNEXPECTED_MSG);
- return (abortCall());
+ msg);
+
+ if (default_behaviors & DEFAULT_BEHAVIOR_ABORTUNEXP) {
+ // if twin socket call => reset the other part here
+ if (twinSippSocket && (msg_index > 0)) {
+ sendCmdBuffer(createSendingMessage(get_default_message("3pcc_abort"), -1));
+ }
+
+ // usage of last_ keywords => for call aborting
+ last_recv_msg = (char *) realloc(last_recv_msg, strlen(msg) + 1);
+ strcpy(last_recv_msg, msg);
+
+ computeStat(CStat::E_CALL_FAILED);
+ computeStat(CStat::E_FAILED_UNEXPECTED_MSG);
+ if (default_behaviors & DEFAULT_BEHAVIOR_BYE) {
+ return (abortCall());
+ } else {
+ delete this;
+ return false;
+ }
} else {
// Do not abort call nor send anything in reply if default behavior is disabled
return false;
}
}
+void call::abort() {
+ WARNING("Aborted call with Call-ID '%s'", id);
+ abortCall();
+}
+
bool call::abortCall()
{
- int res ;
int is_inv;
char * src_send = NULL ;
@@ -1720,24 +1746,7 @@
// Answer unexpected errors (4XX, 5XX and beyond) with an ACK
// Contributed by F. Tarek Rogers
if((src_recv) && (get_reply_code(src_recv) >= 400)) {
-
- strcpy(L_param, "ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0\n");
- sprintf(L_param, "%s%s", L_param, "Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n");
- sprintf(L_param, "%s%s", L_param, "From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]\n");
- sprintf(L_param, "%s%s", L_param, "To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]\n");
- sprintf(L_param, "%s%s", L_param, "Call-ID: [call_id]\n");
- char * cseq;
- cseq = get_header_field_code(src_recv,(char *) "CSeq:");
- if (cseq != NULL) {
- sprintf(L_param, "%s%s ACK\n", L_param, cseq);
- }
- sprintf(L_param, "%s%s", L_param, "Contact: <sip:sipp@[local_ip]:[local_port];transport=[transport]>\n");
- sprintf(L_param, "%s%s", L_param, "Max-Forwards: 70\n");
- sprintf(L_param, "%s%s", L_param, "Subject: Performance Test\n");
- sprintf(L_param, "%s%s", L_param, "Content-Length: 0\n");
-
- res = sendBuffer(createSendingMessage((char*)(L_param), -2));
-
+ sendBuffer(createSendingMessage(get_default_message("ack"), -2));
} else if (src_recv) {
/* Call is not established and the reply is not a 4XX, 5XX */
/* And we already received a message. */
@@ -1748,45 +1757,13 @@
* and send a BYE afterwards */
ack_is_pending = false;
/* Send an ACK */
- strcpy(L_param, "ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0\n");
- sprintf(L_param, "%s%s", L_param, "Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n");
- sprintf(L_param, "%s%s", L_param, "From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]\n");
- sprintf(L_param, "%s%s", L_param, "To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]\n");
- sprintf(L_param, "%s%s", L_param, "Call-ID: [call_id]\n");
- src_send = last_send_msg ;
- cseq = get_header_field_code(src_recv,"CSeq:");
- if (cseq != NULL) {
- sprintf(L_param, "%s%s ACK\n", L_param, cseq);
- }
- sprintf(L_param, "%s%s", L_param, "Contact: <sip:[local_ip]:[local_port];transport=[transport]>\n");
- sprintf(L_param, "%s%s", L_param, "Content-Length: 0\n");
- res = sendBuffer(createSendingMessage((char*)(L_param),-1));
-
+ sendBuffer(createSendingMessage(get_default_message("ack"), -1));
+
/* Send the BYE */
- cseq = NULL;
- strcpy(L_param, "BYE sip:[service]@[remote_ip]:[remote_port] SIP/2.0\n");
- sprintf(L_param, "%s%s", L_param, "Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n");
- sprintf(L_param, "%s%s", L_param, "From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]\n");
- sprintf(L_param, "%s%s", L_param, "To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]\n");
- sprintf(L_param, "%s%s", L_param, "Call-ID: [call_id]\n");
- cseq = compute_cseq(src_recv);
- if (cseq != NULL) {
- sprintf(L_param, "%s%s BYE\n", L_param, compute_cseq(src_recv));
- }
- sprintf(L_param, "%s%s", L_param, "Contact: <sip:[local_ip]:[local_port];transport=[transport]>\n");
- sprintf(L_param, "%s%s", L_param, "Content-Length: 0\n");
- res = sendBuffer(createSendingMessage((char*)(L_param),-1));
+ sendBuffer(createSendingMessage(get_default_message("bye"), -1));
} else {
/* Send a CANCEL */
- strcpy(L_param, "CANCEL sip:[service]@[remote_ip]:[remote_port] SIP/2.0\n");
- sprintf(L_param, "%s%s", L_param, "Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n");
- sprintf(L_param, "%s%s", L_param, "From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]\n");
- sprintf(L_param, "%s%s", L_param, "To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]\n");
- sprintf(L_param, "%s%s", L_param, "Call-ID: [call_id]\n");
- sprintf(L_param, "%sCSeq: 1 CANCEL\n", L_param);
- sprintf(L_param, "%s%s", L_param, "Contact: <sip:[local_ip]:[local_port];transport=[transport]>\n");
- sprintf(L_param, "%s%s", L_param, "Content-Length: 0\n");
- res = sendBuffer(createSendingMessage((char*)(L_param),-2));
+ sendBuffer(createSendingMessage(get_default_message("cancel"), -1));
}
} else {
/* Call is not established and the reply is not a 4XX, 5XX */
@@ -1795,42 +1772,40 @@
/* any answer. */
/* Do nothing ! */
}
- } else {
- /* Call is established */
+ } else if (last_recv_msg) {
+ /* The call may not be established, if we haven't yet received a message,
+ * because the earlier check depends on the first message being an INVITE
+ * (although it could be something like a message message, therefore we
+ * check that we received a message. */
char * src_recv = last_recv_msg ;
char L_msg_buffer[SIPP_MAX_MSG_SIZE];
L_msg_buffer[0] = '\0';
char * L_param = L_msg_buffer;
- strcpy(L_param, "BYE sip:[service]@[remote_ip]:[remote_port] SIP/2.0\n");
- sprintf(L_param, "%s%s", L_param, "Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n");
- sprintf(L_param, "%s%s", L_param, "From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]\n");
- sprintf(L_param, "%s%s", L_param, "To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]\n");
- sprintf(L_param, "%s%s", L_param, "Call-ID: [call_id]\n");
- char * cseq;
- cseq = compute_cseq(src_recv);
- if (cseq != NULL) {
- sprintf(L_param, "%s%s BYE\n", L_param, compute_cseq(src_recv));
- }
- sprintf(L_param, "%s%s", L_param, "Contact: <sip:[local_ip]:[local_port];transport=[transport]>\n");
- sprintf(L_param, "%s%s", L_param, "Content-Length: 0\n");
- res = sendBuffer(createSendingMessage((char*)(L_param),-1));
- }
- }
-
- delete_call(id);
+ sendBuffer(createSendingMessage(get_default_message("bye"), -1));
+ }
+ }
+
+ stopListening();
+ deadcall *deadcall_ptr = NULL;
+ if (deadcall_wait) {
+ char reason[100];
+ sprintf(reason, "aborted at index %d", msg_index);
+ deadcall_ptr = new deadcall(id, reason);
+ }
+ delete this;
+
return false;
}
bool call::rejectCall()
{
- CStat::instance()->computeStat(CStat::E_CALL_FAILED);
- CStat::instance()->computeStat(CStat::E_FAILED_CALL_REJECTED);
- delete_call(id);
+ computeStat(CStat::E_CALL_FAILED);
+ computeStat(CStat::E_FAILED_CALL_REJECTED);
+ delete this;
return false;
}
-#ifdef __3PCC__
int call::sendCmdMessage(int index)
{
char * dest;
@@ -1840,35 +1815,30 @@
/* 3pcc extended mode */
char * peer_dest;
- int * peer_socket;
-
- if(scenario[index] -> M_sendCmdData) {
- // WARNING_P1("---PREPARING_TWIN_CMD---%s---", scenario[index] -> M_sendCmdData);
- dest = createSendingMessage(scenario[index] -> M_sendCmdData, -1);
+ struct sipp_socket **peer_socket;
+
+ message *curmsg = call_scenario->messages[index];
+
+ if(curmsg -> M_sendCmdData) {
+ // WARNING("---PREPARING_TWIN_CMD---%s---", scenario[index] -> M_sendCmdData);
+ dest = createSendingMessage(curmsg -> M_sendCmdData, -1);
strcat(dest, delimitor);
- //WARNING_P1("---SEND_TWIN_CMD---%s---", dest);
+ //WARNING("---SEND_TWIN_CMD---%s---", dest);
int rc;
/* 3pcc extended mode */
- peer_dest = scenario[index]->peer_dest;
- if(peer_dest){
+ peer_dest = curmsg->peer_dest;
+ if(peer_dest){
peer_socket = get_peer_socket(peer_dest);
- rc = send(* peer_socket,
- dest,
- strlen(dest),
- 0);
-
- }else {
- rc = send(twinSippSocket,
- dest,
- strlen(dest),
- 0);
- }
+ rc = write_socket(*peer_socket, dest, strlen(dest), WS_BUFFER, &call_peer);
+ }else {
+ rc = write_socket(twinSippSocket, dest, strlen(dest), WS_BUFFER, &call_peer);
+ }
if(rc < 0) {
- CStat::instance()->computeStat(CStat::E_CALL_FAILED);
- CStat::instance()->computeStat(CStat::E_FAILED_CMD_NOT_SENT);
- delete_call(id);
+ computeStat(CStat::E_CALL_FAILED);
+ computeStat(CStat::E_FAILED_CMD_NOT_SENT);
+ delete this;
return(-1);
}
@@ -1877,6 +1847,7 @@
else
return(-1);
}
+
int call::sendCmdBuffer(char* cmd)
{
@@ -1891,554 +1862,459 @@
strcat(dest, delimitor);
-
- rc = send(twinSippSocket,
- dest,
- strlen(dest),
- 0);
+ rc = write_socket(twinSippSocket, dest, strlen(dest), WS_BUFFER, &twinSippSocket->ss_remote_sockaddr);
if(rc < 0) {
- CStat::instance()->computeStat(CStat::E_CALL_FAILED);
- CStat::instance()->computeStat(CStat::E_FAILED_CMD_NOT_SENT);
- delete_call(id);
+ computeStat(CStat::E_CALL_FAILED);
+ computeStat(CStat::E_FAILED_CMD_NOT_SENT);
+ delete this;
return(-1);
}
return(0);
}
+
+char* call::createSendingMessage(SendingMessage *src, int P_index) {
+ static char msg_buffer[SIPP_MAX_MSG_SIZE+2];
+ return createSendingMessage(src, P_index, msg_buffer, sizeof(msg_buffer));
+}
+
+char* call::createSendingMessage(SendingMessage *src, int P_index, char *msg_buffer, int buf_len)
+{
+ char * length_marker = NULL;
+ char * auth_marker = NULL;
+ MessageComponent *auth_comp = NULL;
+ bool auth_comp_allocated = false;
+ int len_offset = 0;
+ char *dest = msg_buffer;
+ bool supresscrlf = false;
+
+ *dest = '\0';
+
+ for (int i = 0; i < src->numComponents(); i++) {
+ MessageComponent *comp = src->getComponent(i);
+ int left = buf_len - (dest - msg_buffer);
+ switch(comp->type) {
+ case E_Message_Literal:
+ if (supresscrlf) {
+ char *ptr = comp->literal;
+ while (isspace(*ptr)) ptr++;
+ dest += snprintf(dest, left, "%s", ptr);
+ supresscrlf = false;
+ } else {
+ dest += snprintf(dest, left, "%s", comp->literal);
+ }
+ break;
+ case E_Message_Remote_IP:
+ dest += snprintf(dest, left, "%s", remote_ip_escaped);
+ break;
+ case E_Message_Remote_Host:
+ dest += snprintf(dest, left, "%s", remote_host);
+ break;
+ case E_Message_Remote_Port:
+ dest += snprintf(dest, left, "%d", remote_port + comp->offset);
+ break;
+ case E_Message_Local_IP:
+ dest += snprintf(dest, left, "%s", local_ip_escaped);
+ break;
+ case E_Message_Local_Port:
+ int port;
+ if((transport == T_UDP) && (multisocket) && (toolMode != MODE_SERVER)) {
+ port = call_port;
+ } else {
+ port = local_port;
+ }
+ dest += snprintf(dest, left, "%d", port + comp->offset);
+ break;
+ case E_Message_Transport:
+ dest += snprintf(dest, left, "%s", TRANSPORT_TO_STRING(transport));
+ break;
+ case E_Message_Local_IP_Type:
+ dest += snprintf(dest, left, "%s", (local_ip_is_ipv6 ? "6" : "4"));
+ break;
+ case E_Message_Server_IP: {
+ /* We should do this conversion once per socket creation, rather than
+ * repeating it every single time. */
+ struct sockaddr_storage server_sockaddr;
+
+ sipp_socklen_t len = SOCK_ADDR_SIZE(&server_sockaddr);
+ getsockname(call_socket->ss_fd,
+ (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);
+ inet_ntop(AF_INET6,
+ &((_RCAST(struct sockaddr_in6 *,&server_sockaddr))->sin6_addr),
+ temp_dest,
+ INET6_ADDRSTRLEN);
+ dest += snprintf(dest, left, "%s",temp_dest);
+ } else {
+ dest += snprintf(dest, left, "%s",
+ inet_ntoa((_RCAST(struct sockaddr_in *,&server_sockaddr))->sin_addr));
+ }
+ }
+ break;
+ case E_Message_Media_IP:
+ dest += snprintf(dest, left, "%s", media_ip_escaped);
+ break;
+ case E_Message_Media_Port:
+ case E_Message_Auto_Media_Port: {
+ int port = media_port + comp->offset;
+ if (comp->type == E_Message_Auto_Media_Port) {
+ port = media_port + (4 * (number - 1)) % 10000 + comp->offset;
+ }
+#ifdef PCAPPLAY
+ char *begin = dest;
+ while (begin > msg_buffer) {
+ if (*begin == '\n') {
+ break;
+ }
+ begin--;
+ }
+ if (begin == msg_buffer) {
+ ERROR("Can not find beginning of a line for the media port!\n");
+ }
+ 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;
+ }
+ } 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;
+ }
+ } else {
+ ERROR("media_port keyword with no audio or video on the current line (%s)", begin);
+ }
#endif
-
-void call::getHexStringParam(char * dest, char * src, int * len)
-{
- *len=0;
- /* Allows any hex coded string like '0x5B07F6' */
- while (isxdigit(*src)) {
- int val = get_decimal_from_hex(*src);
- src++;
- if (isxdigit(*src)) {
- val = (val << 4) + get_decimal_from_hex(*src);
- src++;
- }
- *dest++ = val & 0xff;
- (*len)++;
- }
-}
-
-char* call::getKeywordParam(char * src, char * param, char * output)
-{
- char *key, *tmp;
- int len;
-
- len = 0;
- key = NULL;
- if(tmp = strstr(src, param)) {
- tmp += strlen(param);
- key = tmp;
- if ((*key == '0') && (*(key+1) == 'x')) {
- key += 2;
- getHexStringParam(output, key, &len);
- key += len * 2;
+ dest += sprintf(dest, "%u", port);
+ break;
+ }
+ case E_Message_Media_IP_Type:
+ dest += snprintf(dest, left, "%s", (media_ip_is_ipv6 ? "6" : "4"));
+ break;
+ case E_Message_Call_Number:
+ dest += snprintf(dest, left, "%u", number);
+ break;
+ case E_Message_Call_ID:
+ dest += snprintf(dest, left, "%s", id);
+ break;
+ case E_Message_CSEQ:
+ dest += snprintf(dest, left, "%u", cseq + comp->offset);
+ break;
+ case E_Message_PID:
+ dest += snprintf(dest, left, "%d", pid);
+ break;
+ case E_Message_Service:
+ dest += snprintf(dest, left, "%s", service);
+ break;
+ case E_Message_Branch:
+ /* Branch is magic cookie + call number + message index in scenario */
+ if(P_index == -2){
+ dest += snprintf(dest, left, "z9hG4bK-%u-%u-%d", pid, number, msg_index-1 + comp->offset);
+ } else {
+ dest += snprintf(dest, left, "z9hG4bK-%u-%u-%d", pid, number, P_index + comp->offset);
+ }
+ break;
+ case E_Message_Index:
+ dest += snprintf(dest, left, "%d", P_index);
+ break;
+ case E_Message_Next_Url:
+ if (next_req_url) {
+ dest += sprintf(dest, "%s", next_req_url);
+ }
+ break;
+ case E_Message_Len:
+ length_marker = dest;
+ dest += snprintf(dest, left, " ");
+ len_offset = comp->offset;
+ break;
+ case E_Message_Authentication:
+ if (auth_marker) {
+ ERROR("Only one [authentication] keyword is currently supported!\n");
+ }
+ auth_marker = dest;
+ dest += snprintf(dest, left, "[authentication place holder]");
+ auth_comp = comp;
+ break;
+ case E_Message_Peer_Tag_Param:
+ if(peer_tag) {
+ dest += snprintf(dest, left, ";tag=%s", peer_tag);
+ }
+ break;
+ case E_Message_Routes:
+ if (dialog_route_set) {
+ dest += sprintf(dest, "Route: %s", dialog_route_set);
+ } else if (*(dest - 1) == '\n') {
+ supresscrlf = true;
+ }
+ break;
+ case E_Message_ClockTick:
+ dest += snprintf(dest, left, "%lu", clock_tick);
+ break;
+ case E_Message_Timestamp:
+ struct timeval currentTime;
+ gettimeofday(¤tTime, NULL);
+ dest += snprintf(dest, left, "%s", CStat::formatTime(¤tTime));
+ break;
+ case E_Message_Users:
+ dest += snprintf(dest, left, "%d", users);
+ break;
+ case E_Message_UserID:
+ dest += snprintf(dest, left, "%d", userId);
+ break;
+ case E_Message_Variable: {
+ int varId = comp->varId;
+ CCallVariable *var = M_callVariableTable->getVar(varId);
+ if(var->isSet()) {
+ if (var->isRegExp()) {
+ dest += sprintf(dest, "%s", var->getMatchingValue());
+ } else if (var->isDouble()) {
+ dest += sprintf(dest, "%lf", var->getDouble());
+ } else if (var->isString()) {
+ dest += sprintf(dest, "%s", var->getString());
+ } else if (var->isBool()) {
+ dest += sprintf(dest, "true");
+ }
+ } else if (var->isBool()) {
+ dest += sprintf(dest, "false");
+ }
+ break;
+ }
+ case E_Message_Fill: {
+ int varId = comp->varId;
+ int length = (int) M_callVariableTable->getVar(varId)->getDouble();
+ if (length < 0) {
+ length = 0;
+ }
+ char *filltext = comp->literal;
+ int filllen = strlen(filltext);
+ if (filllen == 0) {
+ ERROR("Internal error: [fill] keyword has zero-length text.");
+ }
+ for (int i = 0, j = 0; i < length; i++, j++) {
+ *dest++ = filltext[j % filllen];
+ }
+ *dest = '\0';
+ break;
+ }
+ case E_Message_Injection: {
+ char *orig_dest = dest;
+ getFieldFromInputFile(comp->comp_param.field_param.filename, comp->comp_param.field_param.field, comp->comp_param.field_param.line, dest);
+ /* We are injecting an authentication line. */
+ if (char *tmp = strstr(orig_dest, "[authentication")) {
+ if (auth_marker) {
+ ERROR("Only one [authentication] keyword is currently supported!\n");
+ }
+ auth_marker = tmp;
+ auth_comp = (struct MessageComponent *)calloc(1, sizeof(struct MessageComponent));
+ if (!auth_comp) { ERROR("Out of memory!"); }
+ auth_comp_allocated = true;
+
+ tmp = strchr(auth_marker, ']');
+ char c = *tmp;
+ *tmp = '\0';
+ SendingMessage::parseAuthenticationKeyword(call_scenario, auth_comp, auth_marker);
+ *tmp = c;
+ }
+ if (*(dest - 1) == '\n') {
+ supresscrlf = true;
+ }
+ break;
+ }
+ case E_Message_Last_Header: {
+ char * last_header = get_last_header(comp->literal);
+ if(last_header) {
+ dest += sprintf(dest, "%s", last_header);
+ }
+ if (*(dest - 1) == '\n') {
+ supresscrlf = true;
+ }
+ break;
+ }
+ case E_Message_Last_Message:
+ if(last_recv_msg && strlen(last_recv_msg)) {
+ dest += sprintf(dest, "%s", last_recv_msg);
+ }
+ break;
+ case E_Message_Last_Request_URI: {
+ char * last_request_uri = get_last_request_uri();
+ dest += sprintf(dest, "%s", last_request_uri);
+ free(last_request_uri);
+ break;
+ }
+ case E_Message_Last_CSeq_Number: {
+ int last_cseq = 0;
+
+ char *last_header = get_last_header("CSeq:");
+ if(last_header) {
+ last_header += 5;
+ /* Extract the integer value of the field */
+ while(isspace(*last_header)) last_header++;
+ sscanf(last_header,"%d", &last_cseq);
+ }
+ dest += sprintf(dest, "%d", last_cseq + comp->offset);
+ break;
+ }
+ case E_Message_TDM_Map:
+ if (!use_tdmmap)
+ ERROR("[tdmmap] keyword without -tdmmap parameter on command line");
+ dest += snprintf(dest, left, "%d.%d.%d/%d",
+ tdm_map_x+(int((tdm_map_number)/((tdm_map_b+1)*(tdm_map_c+1))))%(tdm_map_a+1),
+ tdm_map_h,
+ tdm_map_y+(int((tdm_map_number)/(tdm_map_c+1)))%(tdm_map_b+1),
+ tdm_map_z+(tdm_map_number)%(tdm_map_c+1)
+ );
+ break;
+ }
+ }
+ /* Need the body for length and auth-int calculation */
+ char *body;
+ if (length_marker || auth_marker) {
+ body = strstr(msg_buffer, "\r\n\r\n");
+ }
+
+ /* Fix up the length. */
+ if (length_marker) {
+ if (auth_marker > body) {
+ ERROR("The authentication keyword should appear in the message header, not the body!");
+ }
+
+ if (body && dest - body > 4 && dest - body < 100004) {
+ char tmp = length_marker[5];
+ sprintf(length_marker, "%5u", dest - body - 4 + len_offset);
+ length_marker[5] = tmp;
} else {
- while (*key) {
- if (((key - src) > KEYWORD_SIZE) || (!(key - src))) {
- ERROR_P1("Syntax error parsing '%s' parameter", param);
- } else if (*key == ']' || *key < 33 || *key > 126) {
- strncpy(output, tmp, key-tmp);
- output[key-tmp] = '\0';
- break;
- }
- key++;
- }
- }
- } else {
- output[0] = '\0';
- }
- return key;
-}
-
-char* call::createSendingMessage(char * src, int P_index)
-{
- static char msg_buffer[SIPP_MAX_MSG_SIZE+2];
-
- if(src != NULL) {
- char * dest = msg_buffer;
- char * key;
- char * length_marker = NULL;
- int offset = 0;
- int len_offset = 0;
- char current_line[MAX_HEADER_LEN];
- char * line_mark = NULL;
- char * tsrc;
-
- current_line[0] = '\0';
- while(*src) {
- if (current_line[0] == '\0') {
- line_mark = NULL;
- line_mark = strchr(src, '\n');
- if (line_mark) {
- memcpy(current_line, src, line_mark - src);
- current_line[line_mark-src] = '\0';
- }
- }
- /* This hex encoding could be done in XML parsing, allowing us to skip
- * these conditionals and branches. */
- if ((*src == '\\') && (*(src+1) == 'x')) {
- /* Allows any hex coded char like '\x5B' ([) */
- src += 2;
- if (isxdigit(*src)) {
- int val = get_decimal_from_hex(*src);
- src++;
- if (isxdigit(*src)) {
- val = (val << 4) + get_decimal_from_hex(*src);
- }
- *dest++ = val & 0xff;
- }
- src++;
- } else if(*src == '[') {
- char keyword [KEYWORD_SIZE+1];
- src++;
-
- tsrc=strchr(src, '[');
- key = strchr(src, ']');
- if ((tsrc) && (tsrc<key)){
- memcpy(keyword, src-1, tsrc - src + 1);
- keyword[tsrc - src + 1] = 0;
- src=tsrc+1;
- dest += sprintf(dest, "%s", keyword);
- }
-
- if((!key) || ((key - src) > KEYWORD_SIZE) || (!(key - src))){
- ERROR_P1("Syntax error or invalid [keyword] in scenario while parsing '%s'", current_line);
- }
- memcpy(keyword, src, key - src);
-
- keyword[key - src] = 0;
- src = key + 1;
- // allow +/-n for numeric variables
- if (!strstr(keyword, "authentication") && !strstr(keyword, "map") && ((key = strchr(keyword,'+')) || (key = strchr(keyword,'-'))) && isdigit(*(key+1))) {
- offset = atoi(key);
- *key = 0;
- } else offset = 0;
-
- if(!strcmp(keyword, "remote_ip")) {
- dest += sprintf(dest, "%s", remote_ip_escaped);
- } else if(!strcmp(keyword, "remote_port")) {
- dest += sprintf(dest, "%u", remote_port + offset);
- } else if(!strcmp(keyword, "transport")) {
- dest += sprintf(dest, "%s", TRANSPORT_TO_STRING(transport));
- } else if(!strcmp(keyword, "local_ip")) {
- dest += sprintf(dest, "%s", local_ip_escaped);
- } else if(!strcmp(keyword, "local_ip_type")) {
- dest += sprintf(dest, "%s", (local_ip_is_ipv6 ? "6" : "4"));
- } else if(!strcmp(keyword, "local_port")) {
- if((transport == T_UDP) && (multisocket) && (toolMode != MODE_SERVER)) {
- dest += sprintf(dest, "%u", call_port + offset);
- } else {
- dest += sprintf(dest, "%u", local_port + offset);
- }
- } else if(!strcmp(keyword, "server_ip")) {
- struct sockaddr_storage server_sockaddr;
- sipp_socklen_t len = SOCK_ADDR_SIZE(&server_sockaddr);
- getsockname(call_socket,
- (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);
- inet_ntop(AF_INET6,
- &((_RCAST(struct sockaddr_in6 *,&server_sockaddr))->sin6_addr),
- temp_dest,
- INET6_ADDRSTRLEN);
- dest += sprintf(dest, "%s",temp_dest);
- } else {
- dest += sprintf(dest, "%s",
- inet_ntoa((_RCAST(struct sockaddr_in *,&server_sockaddr))->sin_addr));
- }
- } else if(!strcmp(keyword, "media_ip")) {
- dest += sprintf(dest, "%s", media_ip_escaped);
-#ifdef PCAPPLAY
- } else if (!strcmp(keyword, "auto_media_port")) {
- /* to make media ports begin from true media_port exported from sipp.cpp, as number begins to 1
- * * 4 to allow video (audio+rtcp+video+rtcp)
- * Modulo 10000 to limit the port number
- * -> Max 10000 concurrent RTP sessions for pcap_play
- */
- int port = media_port + (4 * (number - 1)) % 10000 + offset;
- if (strstr(current_line, "m=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;
- }
- } else if (strstr(current_line, "m=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;
- }
- } else {
- ERROR_P1("auto_media_port keyword with no audio or video on the current line (%s)", current_line);
- }
- dest += sprintf(dest, "%u", port);
+ // Other cases: Content-Length is 0
+ sprintf(length_marker, " 0\r\n\r\n");
+ }
+ }
+
+ /*
+ * The authentication substitution must be done outside the above
+ * loop because auth-int will use the body (which must have already
+ * been keyword substituted) to build the md5 hash
+ */
+ if (auth_marker) {
+#ifndef _USE_OPENSSL
+ ERROR("Authentication requires OpenSSL!");
+#else
+ if (!dialog_authentication) {
+ ERROR("Authentication keyword without dialog_authentication!");
+ }
+
+ int auth_marker_len;
+ char * tmp;
+ int authlen;
+
+ auth_marker_len = (strchr(auth_marker, ']') + 1) - auth_marker;
+
+ /* Need the Method name from the CSeq of the Challenge */
+ char method[MAX_HEADER_LEN];
+ tmp = get_last_header("CSeq:");
+ if(!tmp) {
+ ERROR("Could not extract method from cseq of challenge");
+ }
+ tmp += 5;
+ while(isspace(*tmp) || isdigit(*tmp)) tmp++;
+ sscanf(tmp,"%s", method);
+
+ if (!body) {
+ body = "";
+ }
+
+ /* Determine the type of credentials. */
+ char result[MAX_HEADER_LEN];
+ if (dialog_challenge_type == 401) {
+ /* Registrars use Authorization */
+ authlen = sprintf(result, "Authorization: ");
+ } else {
+ /* Proxies use Proxy-Authorization */
+ authlen = sprintf(result, "Proxy-Authorization: ");
+ }
+
+ /* Build the auth credenticals */
+ char uri[MAX_HEADER_LEN];
+ sprintf (uri, "%s:%d", remote_ip, remote_port);
+ /* These cause this function to not be reentrant. */
+ static char my_auth_user[MAX_HEADER_LEN + 2];
+ static char my_auth_pass[MAX_HEADER_LEN + 2];
+ static char my_aka_OP[MAX_HEADER_LEN + 2];
+ static char my_aka_AMF[MAX_HEADER_LEN + 2];
+ static char my_aka_K[MAX_HEADER_LEN + 2];
+
+ createSendingMessage(auth_comp->comp_param.auth_param.auth_user, -2, my_auth_user, sizeof(my_auth_user));
+ createSendingMessage(auth_comp->comp_param.auth_param.auth_pass, -2, my_auth_pass, sizeof(my_auth_pass));
+ createSendingMessage(auth_comp->comp_param.auth_param.aka_K, -2, my_aka_K, sizeof(my_aka_K));
+ createSendingMessage(auth_comp->comp_param.auth_param.aka_AMF, -2, my_aka_AMF, sizeof(my_aka_AMF));
+ createSendingMessage(auth_comp->comp_param.auth_param.aka_OP, -2, my_aka_OP, sizeof(my_aka_OP));
+
+ if (createAuthHeader(my_auth_user, my_auth_pass, method, uri, body, dialog_authentication,
+ my_aka_OP, my_aka_AMF, my_aka_K, result + authlen) == 0) {
+ ERROR("%s", result + authlen);
+ }
+ authlen = strlen(result);
+
+ /* Shift the end of the message to its rightful place. */
+ memmove(auth_marker + authlen, auth_marker + auth_marker_len, strlen(auth_marker + auth_marker_len) + 1);
+ /* Copy our result into the hole. */
+ memcpy(auth_marker, result, authlen);
#endif
- } else if(!strcmp(keyword, "media_port")) {
- int port = media_port + offset;
-#ifdef PCAPPLAY
- if (strstr(current_line, "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;
- }
- } else if (strstr(current_line, "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;
- }
- } else {
- ERROR_P1("media_port keyword with no audio or video on the current line (%s)", current_line);
- }
-#endif
- dest += sprintf(dest, "%u", port);
- } else if(!strcmp(keyword, "media_ip_type")) {
- dest += sprintf(dest, "%s", (media_ip_is_ipv6 ? "6" : "4"));
- } else if(!strcmp(keyword, "call_number")) {
- dest += sprintf(dest, "%u", number);
- } else if(!strcmp(keyword, "call_id")) {
- dest += sprintf(dest, "%s", id);
- } else if(!strcmp(keyword, "cseq")) {
- dest += sprintf(dest, "%u", cseq +offset);
- } else if(!strcmp(keyword, "pid")) {
- dest += sprintf(dest, "%u", pid);
- } else if(!strcmp(keyword, "service")) {
- dest += sprintf(dest, "%s", service);
- } else if(!strncmp(keyword, "field", 5)) {
- char* local_dest = dest;
- getFieldFromInputFile(keyword, m_localLineNumber, dest);
- if (dest == local_dest && ('\r' == *(local_dest-1) || '\n' == *(local_dest-1))) {
- /* If the line begins with a field value and there
- * is nothing to add for this field,
- * Jump to the end of line in scenario. SN
- */
- while((*src) && (*src != '\n')) {
- src++;
- }
- if(*src == '\n') {
- src++;
- }
- }
- } else if(!strcmp(keyword, "peer_tag_param")) {
- if(peer_tag) {
- dest += sprintf(dest, ";tag=%s", peer_tag);
- }
- } else if(strstr(keyword, "tdmmap")) {
- /* keyword to generate c= line for TDM
- * format: g.h.i/j
- * g: varies in interval a, offset x
- * h: fix value
- * i: varies in interval b, offset y
- * j: varies in interval c, offset z
- * Format: tdmmap{1-3}{0}{0-27}{1-24}
- */
- if (!use_tdmmap)
- ERROR("[tdmmap] keyword without -tdmmap parameter on command line");
- dest += sprintf(dest, "%d.%d.%d/%d",
- tdm_map_x+(int((tdm_map_number)/((tdm_map_b+1)*(tdm_map_c+1))))%(tdm_map_a+1),
- tdm_map_h,
- tdm_map_y+(int((tdm_map_number)/(tdm_map_c+1)))%(tdm_map_b+1),
- tdm_map_z+(tdm_map_number)%(tdm_map_c+1)
- );
- } else if(strstr(keyword, "$")) {
- int varId = atoi(keyword+1);
- if(varId < SCEN_VARIABLE_SIZE) {
- if(M_callVariableTable[varId] != NULL) {
- if(M_callVariableTable[varId]->isSet()) {
- dest += sprintf(dest, "%s",
- M_callVariableTable[varId]->
- getMatchingValue());
- // WARNING_P1("VARIABLE --%s--", M_callVariableTable[varId]->getMatchingValue());
- } else {
- dest += sprintf(dest, "%s", "");
- }
- }
- }
- } else if(strstr(keyword, "last_")) {
- char * last_header = get_last_header(keyword+5);
- if(last_header) {
- dest += sprintf(dest, "%s", last_header);
- } else {
- /* Jump to the end of line in scenario if nothing
- * to insert in place of this header. */
- while((*src) && (*src != '\n')) {
- src++;
- }
- if(*src == '\n') {
- src++;
- }
- }
- } else if(strstr(keyword, "routes")) {
- if (dialog_route_set) {
- dest += sprintf(dest, "Route: %s", dialog_route_set);
- } else {
- // Skip to end of line
- while((*src) && (*src != '\n')) src++;
- if (*src == '\n') src++;
- }
-#ifdef _USE_OPENSSL
- } else if(strstr(keyword, "authentication")) {
- /* This keyword is substituted below */
- dest += sprintf(dest, "[%s]", keyword);
-#endif
- } else if(strstr(keyword, "branch")) {
- /* Branch is magic cookie + call number + message index in scenario */
- if(P_index == -2){
- dest += sprintf(dest, "z9hG4bK-%u-%u-%d", pid, number, msg_index-1);
- } else {
- dest += sprintf(dest, "z9hG4bK-%u-%u-%d", pid, number, P_index);
- }
- } else if(strstr(keyword, "msg_index")) {
- /* Message index in scenario */
- dest += sprintf(dest, "%d", P_index);
- } else if(strstr(keyword, "next_url")) {
- if (next_req_url) {
- dest += sprintf(dest, "%s", next_req_url);
- }
- } else if(strstr(keyword, "len")) {
- length_marker = dest;
- dest += sprintf(dest, " ");
- len_offset = offset;
- } else { // scan for the generic parameters - must be last test
- int i = 0;
- while (generic[i]) {
- char *msg1 = *generic[i];
- char *msg2 = *(generic[i] + 1);
- if(!strcmp(keyword, msg1)) {
- dest += sprintf(dest, "%s", msg2);
- break;
- }
- ++i;
- }
- if (!generic[i]) {
- ERROR_P1("Unsupported keyword '%s' in xml scenario file",
- keyword);
- }
- }
- /* This could also be done at XML parsing time. */
- } else if (*src == '\n') {
- *dest++ = '\r';
- *dest++ = *src++;
- current_line[0] = '\0';
- } else {
- *dest++ = *src++;
- }
- }
- *dest = 0;
-
-#ifdef _USE_OPENSSL
- /*
- * The authentication substitution must be done outside the above
- * loop because auth-int will use the body (which must have already
- * been keyword substituted) to build the md5 hash
- */
-
- if(dialog_authentication && (src = strstr(msg_buffer, "[authentication"))) {
- char * auth_marker;
- int auth_marker_len;
-
- char my_auth_user[KEYWORD_SIZE];
- char my_auth_pass[KEYWORD_SIZE];
- char my_aka_OP[KEYWORD_SIZE];
- char my_aka_AMF[KEYWORD_SIZE];
- char my_aka_K[KEYWORD_SIZE];
- char * tmp;
- int authlen;
-
- auth_marker = src;
- auth_marker_len = strchr(src, ']') - src;
- strcpy(my_auth_user, service);
- strcpy(my_auth_pass, auth_password);
- /* Look for optional username and password parameters */
- /* add aka_OP, aka_AMF, aka_K */
- key = getKeywordParam(src, "username=", my_auth_user);
- memset(my_auth_pass,0,KEYWORD_SIZE);
- key = getKeywordParam(src, "password=", my_auth_pass);
- memset(my_aka_OP,0,KEYWORD_SIZE);
- key = getKeywordParam(src, "aka_OP=", my_aka_OP);
- memset(my_aka_AMF,0,KEYWORD_SIZE);
- key = getKeywordParam(src, "aka_AMF=", my_aka_AMF);
- memset(my_aka_K,0,KEYWORD_SIZE);
- key = getKeywordParam(src, "aka_K=", my_aka_K);
- if (my_aka_K[0]==0){
- memcpy(my_aka_K,my_auth_pass,16);
- my_aka_K[16]=0;
- }
-
- /* Need the Method name from the CSeq of the Challenge */
- char method[MAX_HEADER_LEN];
- tmp = get_last_header("CSeq") + 5;
- if(!tmp) {
- ERROR("Could not extract method from cseq of challenge");
- }
- while(isspace(*tmp) || isdigit(*tmp)) tmp++;
- /* This looks like it could have been be a bug, shouldn't it be method instead of &method. */
- sscanf(tmp,"%s", method);
-
- /* Need the body for auth-int calculation */
- char body[SIPP_MAX_MSG_SIZE];
- memset(body, 0, sizeof(body));
- tmp = msg_buffer;
- while(*(tmp+4)) {
- if (*tmp == '\r' && *(tmp + 1) == '\n' &&
- *(tmp + 2) == '\r' && *(tmp + 3) == '\n') {
- sprintf(body, "%s", tmp+4);
- break;
- }
- tmp++;
- }
-
- /* Build the auth credenticals */
- char result[MAX_HEADER_LEN];
- char uri[MAX_HEADER_LEN];
- sprintf (uri, "%s:%d", remote_ip, remote_port);
- if (createAuthHeader(my_auth_user, my_auth_pass, method, uri,
- body, dialog_authentication,
- my_aka_OP,
- my_aka_AMF,
- my_aka_K,
- result) == 0) {
- ERROR_P1("%s", result);
- }
-
- char tmp_buffer[SIPP_MAX_MSG_SIZE];
- dest = strncpy(tmp_buffer, msg_buffer, src - msg_buffer);
- dest += src - msg_buffer;
- key = strchr(src, ']');
- src += key - src + 1;
-
- if (dialog_challenge_type == 401) {
- /* Registrars use Authorization */
- authlen = sprintf(dest, "Authorization: %s", result);
- } else {
- /* Proxies use Proxy-Authorization */
- authlen = sprintf(dest, "Proxy-Authorization: %s", result);
- }
- dest += authlen;
- if (length_marker > auth_marker) {
- length_marker = length_marker - 1 - auth_marker_len + authlen;
- }
- dest += sprintf(dest, "%s", src);
- strcpy(msg_buffer, tmp_buffer);
- dest = msg_buffer + strlen(msg_buffer);
- }
-#endif
-
- // Remove all \r, \n but 1 at the end of a message to send
- int len = strlen(msg_buffer);
- while ( (msg_buffer[len-1] == '\n') &&
- (msg_buffer[len-2] == '\r') &&
- (msg_buffer[len-3] == '\n') &&
- (msg_buffer[len-4] == '\r')) {
- msg_buffer[len-2] = 0;
- len -= 2;
- }
-
- int L_flag_crlf = 0 ; // don't need add crlf
- int L_content_length = 0;
-
- if(P_index < 0 ) {
- L_flag_crlf = 1 ; // Add crlf
- } else {
- message::ContentLengthFlag L_flag_content = scenario[P_index] -> content_length_flag ;
- switch (L_flag_content) {
- case message::ContentLengthValueZero :
- L_flag_crlf = 1;
- break ;
- case message::ContentLengthValueNoZero :
- // the msg contains content-length field and his value is greater than 0
- break ;
- default :
- // the msg does not contain content-length field
- // control the crlf
- L_content_length = xp_get_content_length(msg_buffer) ;
- if( L_content_length == 0) {
- L_flag_crlf = 1;
- } else if (L_content_length == -1 ) {
- // The content_length is not present: its a [len] keyword
- }
- break;
- }
- }
-
- if(L_flag_crlf) {
- // Add crlf
- msg_buffer[len] ='\r';
- msg_buffer[len+1] ='\n';
- msg_buffer[len+2] =0;
- }
-
- if (length_marker) {
- key = strstr(length_marker,"\r\n\r\n");
- if (key && dest - key > 4 && dest - key < 10004) {
- char tmp = length_marker[4];
- sprintf(length_marker, "%4u", dest - key - 4 + len_offset);
- length_marker[4] = tmp;
- } else {
- // Other cases: Content-Length is 0
- sprintf(length_marker, " 0\r\n\r\n");
- }
- }
- } else {
- ERROR("Unsupported 'send' message in scenario");
- }
- return(msg_buffer);
-}
-
-
-#ifdef __3PCC__
+ }
+
+ if (auth_comp_allocated) {
+ SendingMessage::freeMessageComponent(auth_comp);
+ }
+
+ return msg_buffer;
+}
+
bool call::process_twinSippCom(char * msg)
{
int search_index;
bool found = false;
T_ActionResult actionResult;
- if (!running) {
- paused_calls.remove_paused_call(this);
- add_running_call(this);
- }
+ setRunning();
if (checkInternalCmd(msg) == false) {
for(search_index = msg_index;
- search_index < scenario_len;
+ search_index < call_scenario->length;
search_index++) {
- if(scenario[search_index] -> M_type != MSG_TYPE_RECVCMD) {
- if(scenario[search_index] -> optional) {
- continue;
- }
- /* The received message is different from the expected one */
- return rejectCall();
+ if(call_scenario->messages[search_index] -> M_type != MSG_TYPE_RECVCMD) {
+ if(call_scenario->messages[search_index] -> optional) {
+ continue;
+ }
+ /* The received message is different from the expected one */
+ TRACE_MSG("Unexpected control message received (I was expecting a different type of message):\n%s\n", msg);
+ return rejectCall();
} else {
- if(extendedTwinSippMode){ // 3pcc extended mode
+ if(extendedTwinSippMode){ // 3pcc extended mode
if(check_peer_src(msg, search_index)){
- found = true;
- break;
+ found = true;
+ break;
} else{
- WARNING_P1("Unexpected sender for the received peer message \n%s\n", msg);
+ WARNING("Unexpected sender for the received peer message \n%s\n", msg);
return rejectCall();
- }
- }
- else {
- found = true;
- break;
- }
- }
- }
-
+ }
+ }
+ else {
+ found = true;
+ break;
+ }
+ }
+ }
+
if (found) {
- scenario[search_index]->M_nbCmdRecv ++;
-
+ call_scenario->messages[search_index]->M_nbCmdRecv ++;
+ do_bookkeeping(search_index);
+
// variable treatment
// Remove \r, \n at the end of a received command
// (necessary for transport, to be removed for usage)
@@ -2447,7 +2323,7 @@
msg[strlen(msg)-2] = 0;
}
actionResult = executeAction(msg, search_index);
-
+
if(actionResult != call::E_AR_NO_ERROR) {
// Store last action result if it is an error
// and go on with the scenario
@@ -2457,11 +2333,11 @@
}
}
} else {
+ TRACE_MSG("Unexpected control message received (no such message found):\n%s\n", msg);
return rejectCall();
}
msg_index = search_index; //update the state machine
return(next());
-
} else {
return (false);
}
@@ -2492,7 +2368,7 @@
if (strcmp(L_ptr1, "abort_call") == 0) {
*L_ptr2 = L_backup;
abortCall();
- CStat::instance()->computeStat(CStat::E_CALL_FAILED);
+ computeStat(CStat::E_CALL_FAILED);
return (true);
}
@@ -2520,7 +2396,7 @@
if(!*L_ptr2) { return (false); }
L_backup = *L_ptr2;
*L_ptr2 = 0;
- if (strcmp(L_ptr1, scenario[search_index] -> peer_src) == 0) {
+ if (strcmp(L_ptr1, call_scenario->messages[search_index] -> peer_src) == 0) {
*L_ptr2 = L_backup;
return(true);
}
@@ -2528,7 +2404,6 @@
*L_ptr2 = L_backup;
return (false);
}
-#endif
void call::extract_cseq_method (char* method, char* msg)
@@ -2551,6 +2426,28 @@
method[nbytes] = '\0';
}
}
+}
+
+void call::extract_transaction (char* txn, char* msg)
+{
+ char *otxn = txn;
+ char *via = get_header_content(msg, "via:");
+ if (!via) {
+ txn[0] = '\0';
+ return;
+ }
+
+ char *branch = strstr(via, ";branch=");
+ if (!branch) {
+ txn[0] = '\0';
+ return;
+ }
+
+ branch += strlen(";branch=");
+ while (*branch && *branch != ';' && *branch != ',' && !isspace(*branch)) {
+ *txn++ = *branch++;
+ }
+ *txn = '\0';
}
void call::formatNextReqUrl (char* next_req_url)
@@ -2700,39 +2597,50 @@
}
}
-bool call::matches_scenario(unsigned int index, int reply_code, char * request, char * responsecseqmethod)
-{
+bool call::matches_scenario(unsigned int index, int reply_code, char * request, char * responsecseqmethod, char *txn)
+{
int result;
-
- if ((reply_code) && ((scenario[index] -> recv_response) == reply_code) && \
- (scenario[index]->recv_response_for_cseq_method_list) && \
- (strstr(scenario[index]->recv_response_for_cseq_method_list, responsecseqmethod))) {
- return true;
- }
-
- if ((scenario[index] -> recv_request) && \
- (!strcmp(scenario[index] -> recv_request, request))) {
- return true;
- }
-
- if ((scenario[index] -> recv_request) && (scenario[index] -> regexp_match)) {
-
- if (scenario[index] -> regexp_compile == NULL) {
- regex_t *re = new regex_t;
- if (regcomp(re, scenario[index] -> recv_request, REG_EXTENDED|REG_NOSUB)) {
- // regexp is not well formed
- scenario[index] -> regexp_match = 0;
- free(re);
- return false;
- }
- scenario[index] -> regexp_compile = re;
- }
-
- result = regexec(scenario[index] -> regexp_compile, request, (size_t)0, NULL, 0);
- if (!result) return true;
+ message *curmsg = call_scenario->messages[index];
+
+ if ((curmsg -> recv_request)) {
+ if (curmsg->regexp_match) {
+ if (curmsg -> regexp_compile == NULL) {
+ regex_t *re = new regex_t;
+ if (regcomp(re, curmsg -> recv_request, REG_EXTENDED|REG_NOSUB)) {
+ ERROR("Invalid regular expression for index %d: %s", curmsg->recv_request);
+ }
+ curmsg -> regexp_compile = re;
+ }
+ return !regexec(curmsg -> regexp_compile, request, (size_t)0, NULL, 0);
+ } else {
+ return !strcmp(curmsg -> recv_request, request);
+ }
+ } else if (curmsg->recv_response && (curmsg->recv_response == reply_code)) {
+ /* This is a potential candidate, we need to match transactions. */
+ if (curmsg->response_txn) {
+ if (txnID[curmsg->response_txn - 1] && !strcmp(txnID[curmsg->response_txn - 1], txn)) {
+ return true;
+ } else {
+ return false;
+ }
+ } else if (index == 0) {
+ /* Always true for the first message. */
+ return true;
+ } else if (curmsg->recv_response_for_cseq_method_list &&
+ strstr(curmsg->recv_response_for_cseq_method_list, responsecseqmethod)) {
+ /* If we do not have a transaction defined, we just check the CSEQ method. */
+ return true;
+ } else {
+ return false;
+ }
}
return false;
+}
+
+void call::queue_up(char *msg) {
+ free(queued_msg);
+ queued_msg = strdup(msg);
}
bool call::process_incoming(char * msg)
@@ -2740,60 +2648,59 @@
int reply_code;
static char request[65];
char responsecseqmethod[65];
+ char txn[MAX_HEADER_LEN];
unsigned long cookie;
char * ptr;
int search_index;
bool found = false;
T_ActionResult actionResult;
- int L_case = 0 ;
-
- if (!running) {
- paused_calls.remove_paused_call(this);
- add_running_call(this);
- }
-
- /* Ignore the messages received during a pause if -pause_msg_ign is set */
- if(scenario[msg_index] -> M_type == MSG_TYPE_PAUSE && pause_msg_ign) return(true);
+ setRunning();
+
+ /* Ignore the messages received during a pause if -pause_msg_ign is set */
+ if(call_scenario->messages[msg_index] -> M_type == MSG_TYPE_PAUSE && pause_msg_ign) return(true);
/* Authorize nop as a first command, even in server mode */
- if((msg_index == 0) && (scenario[msg_index] -> M_type == MSG_TYPE_NOP)) {
- actionResult = executeAction(NULL, msg_index);
- return next();
+ if((msg_index == 0) && (call_scenario->messages[msg_index] -> M_type == MSG_TYPE_NOP)) {
+ queue_up (msg);
+ paused_until = 0;
+ return run();
}
responsecseqmethod[0] = '\0';
+ txn[0] = '\0';
if((transport == T_UDP) && (retrans_enabled)) {
/* Detects retransmissions from peer and retransmit the
* message which was sent just after this one was received */
cookie = hash(msg);
- if(recv_retrans_hash == cookie) {
+ if((recv_retrans_recv_index >= 0) && (recv_retrans_hash == cookie)) {
int status;
if(lost(recv_retrans_recv_index)) {
- TRACE_MSG((s, "%s message (retrans) lost (recv).",
- TRANSPORT_TO_STRING(transport)));
+ TRACE_MSG("%s message (retrans) lost (recv).",
+ TRANSPORT_TO_STRING(transport));
if(comp_state) { comp_free(&comp_state); }
- scenario[recv_retrans_recv_index] -> nb_lost++;
+ call_scenario->messages[recv_retrans_recv_index] -> nb_lost++;
return true;
}
- scenario[recv_retrans_recv_index] -> nb_recv_retrans++;
+ call_scenario->messages[recv_retrans_recv_index] -> nb_recv_retrans++;
send_scene(recv_retrans_send_index, &status);
if(status == 0) {
- scenario[recv_retrans_send_index] -> nb_sent_retrans++;
- } else if(status < -1) {
+ call_scenario->messages[recv_retrans_send_index] -> nb_sent_retrans++;
+ computeStat(CStat::E_RETRANSMISSION);
+ } else if(status < 0) {
return false;
}
return true;
}
- if(last_recv_hash == cookie) {
+ if((last_recv_index >= 0) && (last_recv_hash == cookie)) {
/* This one has already been received, but not processed
* yet => (has not triggered something yet) so we can discard.
*
@@ -2807,7 +2714,7 @@
* This case can also appear in case of message duplication by
* the network. This should not be considered as an unexpected.
*/
- scenario[last_recv_index]->nb_recv_retrans++;
+ call_scenario->messages[last_recv_index]->nb_recv_retrans++;
return true;
}
}
@@ -2847,6 +2754,7 @@
request[0]=0;
// extract the cseq method from the response
extract_cseq_method (responsecseqmethod, msg);
+ extract_transaction (txn, msg);
} else if(ptr = strchr(msg, ' ')) {
if((ptr - msg) < 64) {
memcpy(request, msg, ptr - msg);
@@ -2868,21 +2776,21 @@
reply_code = 0;
} else {
- ERROR_P1("SIP method too long in received message '%s'",
+ ERROR("SIP method too long in received message '%s'",
msg);
}
} else {
- ERROR_P1("Invalid sip message received '%s'",
+ ERROR("Invalid sip message received '%s'",
msg);
}
-
+
/* Try to find it in the expected non mandatory responses
* until the first mandatory response in the scenario */
for(search_index = msg_index;
- search_index < scenario_len;
+ search_index < call_scenario->length;
search_index++) {
- if(!matches_scenario(search_index, reply_code, request, responsecseqmethod)) {
- if(scenario[search_index] -> optional) {
+ if(!matches_scenario(search_index, reply_code, request, responsecseqmethod, txn)) {
+ if(call_scenario->messages[search_index] -> optional) {
continue;
}
/* The received message is different for the expected one */
@@ -2903,23 +2811,44 @@
for(search_index = msg_index - 1;
search_index >= 0;
search_index--) {
- if (scenario[search_index]->optional == OPTIONAL_FALSE) contig = false;
- if(matches_scenario(search_index, reply_code, request, responsecseqmethod)) {
- if (contig || scenario[search_index]->optional == OPTIONAL_GLOBAL) {
+ if (call_scenario->messages[search_index]->optional == OPTIONAL_FALSE) contig = false;
+ if(matches_scenario(search_index, reply_code, request, responsecseqmethod, txn)) {
+ if (contig || call_scenario->messages[search_index]->optional == OPTIONAL_GLOBAL) {
found = true;
break;
} else {
- /*
- * we received a non mandatory msg for an old transaction (this could be due to a retransmit.
- * If this response is for an INVITE transaction, retransmit the ACK to quench retransmits.
- */
- if ( (reply_code) &&
- (0 == strncmp (responsecseqmethod, "INVITE", strlen(responsecseqmethod)) ) &&
- (scenario[search_index+1]->M_type == MSG_TYPE_SEND) &&
- (0 == strncmp(scenario[search_index+1]->send_scheme, "ACK", 3)) ) {
- sendBuffer(createSendingMessage(scenario[search_index+1] -> send_scheme, (search_index+1)));
- return true;
- }
+ if (int checkTxn = call_scenario->messages[search_index]->response_txn) {
+ /* This is a reply to an old transaction. */
+ if (!strcmp(txnID[checkTxn - 1], txn)) {
+ /* This reply is provisional, so it should have no effect if we recieve it out-of-order. */
+ if (reply_code >= 100 && reply_code <= 199) {
+ TRACE_MSG("-----------------------------------------------\n"
+ "Ignoring provisional %s message for transaction %s:\n\n%s\n",
+ TRANSPORT_TO_STRING(transport), call_scenario->txnRevMap[checkTxn - 1], msg);
+ return true;
+ } else if (call_scenario->messages[search_index + 1]->M_type == MSG_TYPE_SEND && call_scenario->messages[search_index + 1]->send_scheme->isAck()) {
+ /* This is the message before an ACK, so verify that this is an invite transaction. */
+ if (!strcmp(responsecseqmethod, "INVITE")) {
+ sendBuffer(createSendingMessage(call_scenario->messages[search_index+1] -> send_scheme, (search_index+1)));
+ return true;
+ }
+ }
+ /* This is a non-provisional message for the transaction, and
+ * we have already gotten our allowable response. */
+ }
+ } else {
+ /*
+ * we received a non mandatory msg for an old transaction (this could be due to a retransmit.
+ * If this response is for an INVITE transaction, retransmit the ACK to quench retransmits.
+ */
+ if ( (reply_code) &&
+ (0 == strncmp (responsecseqmethod, "INVITE", strlen(responsecseqmethod)) ) &&
+ (call_scenario->messages[search_index+1]->M_type == MSG_TYPE_SEND) &&
+ (call_scenario->messages[search_index+1]->send_scheme->isAck()) ) {
+ sendBuffer(createSendingMessage(call_scenario->messages[search_index+1] -> send_scheme, (search_index+1)));
+ return true;
+ }
+ }
}
}
}
@@ -2927,17 +2856,43 @@
/* If it is still not found, process an unexpected message */
if(!found) {
- if ((L_case = checkAutomaticResponseMode(request)) == 0) {
- if (!process_unexpected(msg)) {
- return false; // Call aborted by unexpected message handling
+ if (call_scenario->unexpected_jump >= 0) {
+ bool recursive = false;
+ if (call_scenario->retaddr >= 0) {
+ if (M_callVariableTable->getVar(call_scenario->retaddr)->getDouble() != 0) {
+ /* We are already in a jump! */
+ recursive = true;
+ } else {
+ M_callVariableTable->getVar(call_scenario->retaddr)->setDouble(msg_index);
+ }
+ }
+ if (!recursive) {
+ if (call_scenario->pausedaddr >= 0) {
+ M_callVariableTable->getVar(call_scenario->pausedaddr)->setDouble(paused_until);
+ }
+ msg_index = call_scenario->unexpected_jump;
+ queue_up(msg);
+ paused_until = 0;
+ return run();
+ } else {
+ if (!process_unexpected(msg)) {
+ return false; // Call aborted by unexpected message handling
+ }
}
} else {
- // call aborted by automatic response mode if needed
- return (automaticResponseMode(L_case, msg));
- }
- }
-
- int test = (!found) ? -1 : scenario[search_index]->test;
+ T_AutoMode L_case;
+ if ((L_case = checkAutomaticResponseMode(request)) == 0) {
+ if (!process_unexpected(msg)) {
+ return false; // Call aborted by unexpected message handling
+ }
+ } else {
+ // call aborted by automatic response mode if needed
+ return automaticResponseMode(L_case, msg);
+ }
+ }
+ }
+
+ int test = (!found) ? -1 : call_scenario->messages[search_index]->test;
/* test==0: No branching"
* test==-1 branching without testing"
* test>0 branching with testing
@@ -2945,10 +2900,10 @@
/* Simulate loss of messages */
if(lost(search_index)) {
- TRACE_MSG((s, "%s message lost (recv).",
- TRANSPORT_TO_STRING(transport)));
+ TRACE_MSG("%s message lost (recv).",
+ TRANSPORT_TO_STRING(transport));
if(comp_state) { comp_free(&comp_state); }
- scenario[search_index] -> nb_lost++;
+ call_scenario->messages[search_index] -> nb_lost++;
return true;
}
@@ -2957,12 +2912,12 @@
do_bookkeeping(search_index);
/* Increment the recv counter */
- scenario[search_index] -> nb_recv++;
+ call_scenario->messages[search_index] -> nb_recv++;
// Action treatment
if (found) {
- //WARNING_P1("---EXECUTE_ACTION_ON_MSG---%s---", msg);
-
+ //WARNING("---EXECUTE_ACTION_ON_MSG---%s---", msg);
+
actionResult = executeAction(msg, search_index);
if(actionResult != call::E_AR_NO_ERROR) {
@@ -2974,7 +2929,7 @@
}
}
}
-
+
if (request) { // update [cseq] with received CSeq
unsigned long int rcseq = get_cseq_value(msg);
if (rcseq > cseq) cseq = rcseq;
@@ -3018,7 +2973,7 @@
}
/* store the route set only once. TODO: does not support target refreshes!! */
- if (scenario[search_index] -> bShouldRecordRoutes &&
+ if (call_scenario->messages[search_index] -> bShouldRecordRoutes &&
NULL == dialog_route_set ) {
next_req_url = (char*) calloc(1, MAX_HEADER_LEN);
@@ -3027,7 +2982,7 @@
memset(rr, 0, sizeof(rr));
strcpy(rr, get_header_content(msg, (char*)"Record-Route:"));
- // WARNING_P1("rr [%s]", rr);
+ // WARNING("rr [%s]", rr);
char ch[MAX_HEADER_LEN];
strcpy(ch, get_header_content(msg, (char*)"Contact:"));
@@ -3047,12 +3002,12 @@
{
computeRouteSetAndRemoteTargetUri (rr, ch, true);
}
- // WARNING_P1("next_req_url is [%s]", next_req_url);
+ // WARNING("next_req_url is [%s]", next_req_url);
}
#ifdef _USE_OPENSSL
/* store the authentication info */
- if ((scenario[search_index] -> bShouldAuthenticate) &&
+ if ((call_scenario->messages[search_index] -> bShouldAuthenticate) &&
(reply_code == 401 || reply_code == 407)) {
/* is a challenge */
@@ -3066,13 +3021,18 @@
ERROR("Couldn't find 'Proxy-Authenticate' or 'WWW-Authenticate' in 401 or 407!");
}
- dialog_authentication = (char *) calloc(1, strlen(auth) + 2);
+ dialog_authentication = (char *) realloc(dialog_authentication, strlen(auth) + 2);
sprintf(dialog_authentication, "%s", auth);
/* Store the code of the challenge for building the proper header */
dialog_challenge_type = reply_code;
}
#endif
+
+ /* If we are not advancing state, we should quite before we change this stuff. */
+ if (!call_scenario->messages[search_index]->advance_state) {
+ return true;
+ }
/* Store last received message information for all messages so that we can
* correctly identify retransmissions, and use its body for inclusion
@@ -3084,29 +3044,30 @@
/* If this was a mandatory message, or if there is an explicit next label set
* we must update our state machine. */
- if (!(scenario[search_index] -> optional) ||
- scenario[search_index]->next &&
- ((test == -1) ||
- (test < SCEN_VARIABLE_SIZE && M_callVariableTable[test] != NULL && M_callVariableTable[test]->isSet()))
+ if (!(call_scenario->messages[search_index] -> optional) ||
+ call_scenario->messages[search_index]->next &&
+ ((test == -1) || (M_callVariableTable->getVar(test)->isSet()))
) {
+ /* If we are paused, then we need to wake up so that we properly go through the state machine. */
+ paused_until = 0;
msg_index = search_index;
return next();
} else {
- unsigned int timeout = call_wake(this);
+ unsigned int timeout = wake();
unsigned int candidate;
- if (test < SCEN_VARIABLE_SIZE && M_callVariableTable[test] != NULL && M_callVariableTable[test]->isSet()) {
- WARNING_P1("Last message generates an error and will not be used for next sends (for last_ variables):\r\n%s",msg);
+ if (call_scenario->messages[search_index]->next && M_callVariableTable->getVar(test)->isSet()) {
+ WARNING("Last message generates an error and will not be used for next sends (for last_ variables):\r\n%s",msg);
}
/* We are just waiting for a message to be received, if any of the
* potential messages have a timeout we set it as our timeout. We
* start from the next message and go until any non-receives. */
- for(search_index++; search_index < scenario_len; search_index++) {
- if(scenario[search_index] -> M_type != MSG_TYPE_RECV) {
- break;
- }
- candidate = scenario[search_index] -> retrans_delay;
+ for(search_index++; search_index < call_scenario->length; search_index++) {
+ if(call_scenario->messages[search_index] -> M_type != MSG_TYPE_RECV) {
+ break;
+ }
+ candidate = call_scenario->messages[search_index] -> timeout;
if (candidate == 0) {
if (defl_recv_timeout == 0) {
continue;
@@ -3118,131 +3079,232 @@
}
}
- if (!remove_running_call(this)) {
- ERROR("Tried to remove a running call that wasn't running!\n");
- }
- paused_calls.add_paused_call(this, true);
+ setPaused();
}
return true;
+}
+
+double call::get_rhs(CAction *currentAction) {
+ if (currentAction->getVarInId()) {
+ return M_callVariableTable->getVar(currentAction->getVarInId())->getDouble();
+ } else {
+ return currentAction->getDoubleValue();
+ }
}
call::T_ActionResult call::executeAction(char * msg, int scenarioIndex)
{
CActions* actions;
CAction* currentAction;
- CVariable* scenVariable;
- char msgPart[MAX_SUB_MESSAGE_LENGTH];
- int currentId;
-
- actions = scenario[scenarioIndex]->M_actions;
+
+ actions = call_scenario->messages[scenarioIndex]->M_actions;
// looking for action to do on this message
if(actions != NULL) {
- for(int i=0; i<actions->getUsedAction(); i++) {
+ for(int i=0; i<actions->getActionSize(); i++) {
currentAction = actions->getAction(i);
if(currentAction != NULL) {
if(currentAction->getActionType() == CAction::E_AT_ASSIGN_FROM_REGEXP) {
- currentId = currentAction->getVarId();
- scenVariable = scenVariableTable[currentId][scenarioIndex];
- if(scenVariable != NULL) {
- if(currentAction->getLookingPlace() == CAction::E_LP_HDR) {
- extractSubMessage
- (msg,
- currentAction->getLookingChar(),
- msgPart,
- currentAction->getCaseIndep(),
- currentAction->getOccurence(),
- currentAction->getHeadersOnly());
-
- if(strlen(msgPart) > 0) {
-
- scenVariable->executeRegExp(msgPart,
- M_callVariableTable,
- currentId,
- currentAction->getNbSubVarId(),
- currentAction->getSubVarId());
-
- if( (!(M_callVariableTable[currentId]->isSet()))
- && (currentAction->getCheckIt() == true) ) {
- // the message doesn't match and the checkit
- // action say it MUST match
- // Allow easier regexp debugging
- WARNING_P2("Failed regexp match: looking "
- "in '%s', with regexp '%s'",
- msgPart,
- scenVariable->
- getRegularExpression());
- // --> Call will be marked as failed
- return(call::E_AR_REGEXP_DOESNT_MATCH);
- }
- } else {// sub part of message not found
- if( currentAction->getCheckIt() == true ) {
- // the sub message is not found and the
- // checking action say it MUST match
- // --> Call will be marked as failed but
- // will go on
- WARNING_P2("Failed regexp match: header %s not found in message %s\n", currentAction->getLookingChar(), msg);
- return(call::E_AR_HDR_NOT_FOUND);
- }
- }
- } else {// we must look in the entire message
- // WARNING_P1("LOOKING IN MSG -%s-", msg);
- scenVariable->executeRegExp(msg,
- M_callVariableTable,
- currentId,
- currentAction->getNbSubVarId(),
- currentAction->getSubVarId());
- if((!(M_callVariableTable[currentId]->isSet()))
- && (currentAction->getCheckIt() == true) ) {
- // the message doesn't match and the checkit
- // action say it MUST match
- // Allow easier regexp debugging
- WARNING_P2("Failed regexp match: looking in '%s'"
- ", with regexp '%s'",
- msg,
- scenVariable->getRegularExpression());
- // --> rejecting the call
- return(call::E_AR_REGEXP_DOESNT_MATCH);
- }
- }
- } // end if scen variable != null
+ char msgPart[MAX_SUB_MESSAGE_LENGTH];
+
+ /* Where to look. */
+ char *haystack;
+
+ if(currentAction->getLookingPlace() == CAction::E_LP_HDR) {
+ extractSubMessage (msg,
+ currentAction->getLookingChar(),
+ msgPart,
+ currentAction->getCaseIndep(),
+ currentAction->getOccurence(),
+ currentAction->getHeadersOnly());
+ if(currentAction->getCheckIt() == true && (strlen(msgPart) < 0)) {
+ // the sub message is not found and the checking action say it
+ // MUST match --> Call will be marked as failed but will go on
+ WARNING("Failed regexp match: header %s not found in message %s\n", currentAction->getLookingChar(), msg);
+ return(call::E_AR_HDR_NOT_FOUND);
+ }
+ haystack = msgPart;
+ } else {
+ haystack = msg;
+ }
+ currentAction->executeRegExp(haystack, M_callVariableTable);
+
+ if( (!(M_callVariableTable->getVar(currentAction->getVarId())->isSet())) && (currentAction->getCheckIt() == true) ) {
+ // the message doesn't match and the checkit action say it MUST match
+ // Allow easier regexp debugging
+ WARNING("Failed regexp match: looking in '%s', with regexp '%s'",
+ haystack, currentAction->getRegularExpression());
+ return(call::E_AR_REGEXP_DOESNT_MATCH);
+ }
} else /* end action == E_AT_ASSIGN_FROM_REGEXP */
- if (currentAction->getActionType() == CAction::E_AT_LOG_TO_FILE) {
+ if (currentAction->getActionType() == CAction::E_AT_ASSIGN_FROM_VALUE) {
+ double operand = get_rhs(currentAction);
+ M_callVariableTable->getVar(currentAction->getVarId())->setDouble(operand);
+ } else if (currentAction->getActionType() == CAction::E_AT_ASSIGN_FROM_INDEX) {
+ M_callVariableTable->getVar(currentAction->getVarId())->setDouble(msg_index);
+ } else if (currentAction->getActionType() == CAction::E_AT_ASSIGN_FROM_GETTIMEOFDAY) {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ M_callVariableTable->getVar(currentAction->getVarId())->setDouble((double)tv.tv_sec);
+ M_callVariableTable->getVar(currentAction->getSubVarId(0))->setDouble((double)tv.tv_usec);
+ } else if (currentAction->getActionType() == CAction::E_AT_LOOKUP) {
+ /* Create strings from the sending messages. */
+ char *file = strdup(createSendingMessage(currentAction->getMessage(0), -2));
+ char *key = strdup(createSendingMessage(currentAction->getMessage(1), -2));
+ double value = -1;
+
+ str_int_map::iterator index_it = infIndex[file]->find(key);
+ if (index_it != infIndex[file]->end()) {
+ value = index_it->second;
+ }
+ M_callVariableTable->getVar(currentAction->getVarId())->setDouble(value);
+ free(file);
+ free(key);
+#ifdef _USE_OPENSSL
+ } else if (currentAction->getActionType() == CAction::E_AT_VERIFY_AUTH) {
+ bool result;
+ char *lf;
+ char *end;
+
+ lf = strchr(msg, '\n');
+ end = strchr(msg, ' ');
+
+ if (!lf || !end) {
+ result = false;
+ } else if (lf < end) {
+ result = false;
+ } else {
+ char *auth = get_header(msg, "Authorization:", true);
+ char *method = (char *)malloc(end - msg + 1);
+ strncpy(method, msg, end - msg);
+ method[end - msg] = '\0';
+
+ /* Generate the username to verify it against. */
+ char *tmp = createSendingMessage(currentAction->getMessage(0), -2 /* do not add crlf*/);
+ char *username = strdup(tmp);
+ /* Generate the password to verify it against. */
+ tmp= createSendingMessage(currentAction->getMessage(1), -2 /* do not add crlf*/);
+ char *password = strdup(tmp);
+
+ result = verifyAuthHeader(username, password, method, auth);
+
+ free(username);
+ free(password);
+ }
+
+ M_callVariableTable->getVar(currentAction->getVarId())->setBool(result);
+#endif
+ } else if (currentAction->getActionType() == CAction::E_AT_JUMP) {
+ double operand = get_rhs(currentAction);
+ msg_index = (int)operand - 1;
+ } else if (currentAction->getActionType() == CAction::E_AT_PAUSE_RESTORE) {
+ double operand = get_rhs(currentAction);
+ paused_until = (int)operand;
+ } else if (currentAction->getActionType() == CAction::E_AT_VAR_ADD) {
+ double value = M_callVariableTable->getVar(currentAction->getVarId())->getDouble();
+ double operand = get_rhs(currentAction);
+ M_callVariableTable->getVar(currentAction->getVarId())->setDouble(value + operand);
+ } else if (currentAction->getActionType() == CAction::E_AT_VAR_SUBTRACT) {
+ double value = M_callVariableTable->getVar(currentAction->getVarId())->getDouble();
+ double operand = get_rhs(currentAction);
+ M_callVariableTable->getVar(currentAction->getVarId())->setDouble(value - operand);
+ } else if (currentAction->getActionType() == CAction::E_AT_VAR_MULTIPLY) {
+ double value = M_callVariableTable->getVar(currentAction->getVarId())->getDouble();
+ double operand = get_rhs(currentAction);
+ M_callVariableTable->getVar(currentAction->getVarId())->setDouble(value * operand);
+ } else if (currentAction->getActionType() == CAction::E_AT_VAR_DIVIDE) {
+ double value = M_callVariableTable->getVar(currentAction->getVarId())->getDouble();
+ double operand = get_rhs(currentAction);
+ if (operand == 0) {
+ WARNING("Action failure: Can not divide by zero ($%d/$%d)!\n", currentAction->getVarId(), currentAction->getVarInId());
+ } else {
+ M_callVariableTable->getVar(currentAction->getVarId())->setDouble(value / operand);
+ }
+ } else if (currentAction->getActionType() == CAction::E_AT_VAR_TEST) {
+ double value = currentAction->compare(M_callVariableTable);
+ M_callVariableTable->getVar(currentAction->getVarId())->setBool(value);
+ } else if (currentAction->getActionType() == CAction::E_AT_VAR_STRCMP) {
+ char *rhs = M_callVariableTable->getVar(currentAction->getVarInId())->getString();
+ char *lhs = currentAction->getStringValue();
+ int value = strcmp(rhs, lhs);
+ M_callVariableTable->getVar(currentAction->getVarId())->setDouble((double)value);
+ } else if (currentAction->getActionType() == CAction::E_AT_VAR_TRIM) {
+ CCallVariable *var = M_callVariableTable->getVar(currentAction->getVarId());
+ char *in = var->getString();
+ char *p = in;
+ while (isspace(*p)) {
+ p++;
+ }
+ char *q = strdup(p);
+ var->setString(q);
+ int l = strlen(q);
+ for (int i = l - 1; i >= 0 & isspace(q[i]); i--) {
+ q[i] = '\0';
+ }
+ } else if (currentAction->getActionType() == CAction::E_AT_VAR_TO_DOUBLE) {
+ double value;
+
+ if (M_callVariableTable->getVar(currentAction->getVarInId())->toDouble(&value)) {
+ M_callVariableTable->getVar(currentAction->getVarId())->setDouble(value);
+ } else {
+ WARNING("Invalid double conversion from $%d to $%d", currentAction->getVarInId(), currentAction->getVarId());
+ }
+ } else if (currentAction->getActionType() == CAction::E_AT_ASSIGN_FROM_SAMPLE) {
+ double value = currentAction->getDistribution()->sample();
+ M_callVariableTable->getVar(currentAction->getVarId())->setDouble(value);
+ } else if (currentAction->getActionType() == CAction::E_AT_ASSIGN_FROM_STRING) {
char* x = createSendingMessage(currentAction->getMessage(), -2 /* do not add crlf*/);
- LOG_MSG((s, "%s\n", x));
- } else /* end action == E_AT_LOG_TO_FILE */
- if (currentAction->getActionType() == CAction::E_AT_EXECUTE_CMD) {
+ char *str = strdup(x);
+ if (!str) {
+ ERROR("Out of memory duplicating string for assignment!");
+ }
+ M_callVariableTable->getVar(currentAction->getVarId())->setString(str);
+ } else if (currentAction->getActionType() == CAction::E_AT_LOG_TO_FILE) {
+ char* x = createSendingMessage(currentAction->getMessage(), -2 /* do not add crlf*/);
+ LOG_MSG("%s\n", x);
+ } else if (currentAction->getActionType() == CAction::E_AT_LOG_WARNING) {
+ char* x = createSendingMessage(currentAction->getMessage(), -2 /* do not add crlf*/);
+ WARNING("%s", x);
+ } else if (currentAction->getActionType() == CAction::E_AT_EXECUTE_CMD) {
if (currentAction->getCmdLine()) {
- char* x = createSendingMessage(currentAction->getCmdLine(), -2 /* do not add crlf*/);
- // TRACE_MSG((s, "Trying to execute [%s]", x));
+ char* x = createSendingMessage(currentAction->getMessage(), -2 /* do not add crlf*/);
+ // TRACE_MSG("Trying to execute [%s]", x);
pid_t l_pid;
switch(l_pid = fork())
{
case -1:
// error when forking !
- ERROR("Forking error");
+ ERROR_NO("Forking error main");
break;
case 0:
- // first child process - execute the command
+ // first child process - execute the command
if((l_pid = fork()) < 0) {
- ERROR("Forking error");
+ ERROR_NO("Forking error child");
} else {
- if( l_pid == 0)
- system(x); // second child runs
- exit(EXIT_OTHER);
+ if( l_pid == 0){
+ int ret;
+ ret = system(x); // second child runs
+ if(ret == -1) {
+ WARNING("system call error for %s",x);
+ }
+ }
+ exit(EXIT_OTHER);
}
break;
default:
// parent process continue
// reap first child immediately
- if(waitpid(l_pid, NULL, 0) != l_pid) {
- ERROR("waitpid error");
+ pid_t ret;
+ while ((ret=waitpid(l_pid, NULL, 0)) != l_pid) {
+ if (ret != -1) {
+ ERROR("waitpid returns %1d for child %1d",ret,l_pid);
+ }
}
break;
}
}
- } else /* end action == E_AT_LOG_TO_FILE */
+ } else /* end action == E_AT_EXECUTE_CMD */
if (currentAction->getActionType() == CAction::E_AT_EXEC_INTCMD) {
switch (currentAction->getIntCmd())
{
@@ -3293,7 +3355,7 @@
ERROR("Can create thread to send RTP packets");
pthread_attr_destroy(&attr);
#endif
- } else {// end action == E_AT_EXECUTE_CMD
+ } else {
ERROR("call::executeAction unknown action");
}
} // end if current action != null
@@ -3362,151 +3424,54 @@
}
}
-void call::dumpFileContents(void)
-{
- WARNING_P3("Line choosing strategy is [%s]. m_counter [%d] numLinesInFile [%d]",
- m_usage == InputFileSequentialOrder ? "SEQUENTIAL" : "RANDOM",
- m_counter, numLinesInFile);
-
- for (int i(0); i < numLinesInFile && fileContents[i][0]; ++i) {
- WARNING_P2("%dth line reads [%s]", i, fileContents[i].c_str());
- }
-}
-
-/* Read MAX_CHAR_BUFFER_SIZE size lines from the
- * "fileName" and populate it in the fileContents
- * vector. The file should not be more than
- * MAX_LINES_IN_FILE lines long and each line
- * should be terminated with a '\n'
- */
-
-void call::readInputFileContents(const char* fileName)
-{
- ifstream *inFile = new ifstream(fileName);
- ifstream &inFileObj = *inFile;
- char line[MAX_CHAR_BUFFER_SIZE];
-
- if (!inFile->good()) {
- ERROR_P1("Unable to open file %s", fileName);
- return ;
- }
-
- numLinesInFile = 0;
- call::m_counter = 0;
- line[0] = '\0';
- inFileObj.getline(line, MAX_CHAR_BUFFER_SIZE);
-
- if (NULL != strstr(line, "RANDOM")) {
- call::m_usage = InputFileRandomOrder;
- } else if (NULL != strstr(line, "SEQUENTIAL")) {
- call::m_usage = InputFileSequentialOrder;
- } else {
- // default
- call::m_usage = InputFileSequentialOrder;
- }
-
- while (!inFileObj.eof()) {
- line[0] = '\0';
- inFileObj.getline(line, MAX_CHAR_BUFFER_SIZE);
- if (line[0]) {
- if ('#' != line[0]) {
- fileContents.push_back(line);
- numLinesInFile++; /* this counts number of valid data lines */
- }
- } else {
- break;
- }
- }
- // call::dumpFileContents();
- delete inFile;
-}
-
-void call::getFieldFromInputFile(const char* keyword, unsigned int lineNum, char*& dest)
-{
- int nthField = atoi(keyword+5 /*strlen("field")*/);
- int origNth = nthField;
-
- if (fileContents.size() > lineNum) {
- const string& line = fileContents[lineNum];
-
- // WARNING_P3("lineNum [%d] nthField [%d] line [%s]",
- // lineNum, nthField, line.c_str());
-
- size_t pos(0), oldpos(0);
- do {
- oldpos = pos;
- size_t localpos = line.find(';', oldpos);
-
- if (localpos != string::npos) {
- pos = localpos + 1;
- } else {
- pos = localpos;
- break;
- }
-
- //string x = line.substr(oldpos, pos - oldpos);
- // WARNING_P3("pos [%d] oldpos [%d] is [%s]", pos, oldpos, x.c_str());
-
- if (nthField) {
- --nthField;
- } else {
- break;
- }
-
- } while (oldpos != string::npos);
-
- if (nthField) {
- WARNING_P1("Field %d not found in the file", origNth);
- // field not found in line
- } else {
- if (string::npos != oldpos) {
- if (string::npos != pos) {
- // should not be decremented for fieldN
- pos -= (oldpos + 1);
- }
-
- string x = line.substr(oldpos, pos);
- if (x.length()) {
- dest += sprintf(dest, "%s", x.c_str());
- }
-
- // WARNING_P2("nthField [%d] is [%s]", origNth, x.c_str());
- }
- }
- } else {
- // WARNING_P1("Field %d definition not found", nthField);
- }
-}
-
-void call::getIpFieldFromInputFile(int fieldNr, int lineNum, char *dest)
-{
- char keyword[10];
- sprintf(keyword, "field%d", fieldNr);
- char *p = dest;
- getFieldFromInputFile(keyword, lineNum, p);
-}
-
-int call::checkAutomaticResponseMode(char * P_recv) {
-
- int L_res = 0 ;
+void call::getFieldFromInputFile(const char *fileName, int field, SendingMessage *lineMsg, char*& dest)
+{
+ if (inFiles.find(fileName) == inFiles.end()) {
+ ERROR("Invalid injection file: %s", fileName);
+ }
+ int line = (*m_lineNumber)[fileName];
+ if (lineMsg) {
+ char lineBuffer[20];
+ char *endptr;
+ createSendingMessage(lineMsg, -2, lineBuffer, sizeof(lineBuffer));
+ line = (int) strtod(lineBuffer, &endptr);
+ if (*endptr != 0) {
+ ERROR("Invalid line number generated: '%s'", lineBuffer);
+ }
+ if (line > inFiles[fileName]->numLines()) {
+ line = -1;
+ }
+ }
+ if (line < 0) {
+ return;
+ }
+ dest += inFiles[fileName]->getField(line, field, dest, SIPP_MAX_MSG_SIZE);
+}
+
+call::T_AutoMode call::checkAutomaticResponseMode(char * P_recv) {
+
+ int L_res = E_AM_DEFAULT ;
if (strcmp(P_recv, "BYE")==0) {
- L_res = 1 ;
+ return E_AM_UNEXP_BYE;
} else if (strcmp(P_recv, "CANCEL") == 0) {
- L_res = 2 ;
+ return E_AM_UNEXP_CANCEL;
} else if (strcmp(P_recv, "PING") == 0) {
- L_res = 3 ;
+ return E_AM_PING;
} else if (((strcmp(P_recv, "INFO") == 0) || (strcmp(P_recv, "NOTIFY") == 0) || (strcmp(P_recv, "UPDATE") == 0))
&& (auto_answer == true)){
- L_res = 4 ;
- }
-
- return (L_res) ;
-
-}
-
-
-bool call::automaticResponseMode(int P_case, char * P_recv)
+ return E_AM_AA;
+ } else {
+ return E_AM_DEFAULT;
+ }
+}
+
+void call::setLastMsg(const char *msg) {
+ last_recv_msg = (char *) realloc(last_recv_msg, strlen(msg) + 1);
+ strcpy(last_recv_msg, msg);
+}
+
+bool call::automaticResponseMode(T_AutoMode P_case, char * P_recv)
{
int res ;
@@ -3514,113 +3479,81 @@
bool last_recv_msg_saved = false;
switch (P_case) {
- case 1: // response for an unexpected BYE
+ case E_AM_UNEXP_BYE: // response for an unexpected BYE
// usage of last_ keywords
last_recv_msg = (char *) realloc(last_recv_msg, strlen(P_recv) + 1);
strcpy(last_recv_msg, P_recv);
// The BYE is unexpected, count it
- scenario[msg_index] -> nb_unexp++;
- if (default_behavior) {
- WARNING_P1("Aborting call on an unexpected BYE for call: %s", (id==NULL)?"none":id);
- res = sendBuffer(createSendingMessage(
- (char*)"SIP/2.0 200 OK\n"
- "[last_Via:]\n"
- "[last_From:]\n"
- "[last_To:]\n"
- "[last_Call-ID:]\n"
- "[last_CSeq:]\n"
- "Contact: <sip:[local_ip]:[local_port];transport=[transport]>\n"
- "Content-Length: 0\n"
- , -1)) ;
-
-#ifdef __3PCC__
+ call_scenario->messages[msg_index] -> nb_unexp++;
+ if (default_behaviors & DEFAULT_BEHAVIOR_ABORTUNEXP) {
+ WARNING("Aborting call on an unexpected BYE for call: %s", (id==NULL)?"none":id);
+ if (default_behaviors & DEFAULT_BEHAVIOR_BYE) {
+ sendBuffer(createSendingMessage(get_default_message("200"), -1));
+ }
+
+ // if twin socket call => reset the other part here
+ if (twinSippSocket && (msg_index > 0)) {
+ res = sendCmdBuffer(createSendingMessage(get_default_message("3pcc_abort"), -1));
+ }
+ computeStat(CStat::E_CALL_FAILED);
+ computeStat(CStat::E_FAILED_UNEXPECTED_MSG);
+ delete this;
+ } else {
+ WARNING("Continuing call on an unexpected BYE for call: %s", (id==NULL)?"none":id);
+ }
+ break ;
+
+ case E_AM_UNEXP_CANCEL: // response for an unexpected cancel
+ // usage of last_ keywords
+ last_recv_msg = (char *) realloc(last_recv_msg, strlen(P_recv) + 1);
+ strcpy(last_recv_msg, P_recv);
+
+ // The CANCEL is unexpected, count it
+ call_scenario->messages[msg_index] -> nb_unexp++;
+ if (default_behaviors & DEFAULT_BEHAVIOR_ABORTUNEXP) {
+ WARNING("Aborting call on an unexpected CANCEL for call: %s", (id==NULL)?"none":id);
+ if (default_behaviors & DEFAULT_BEHAVIOR_BYE) {
+ sendBuffer(createSendingMessage(get_default_message("200"), -1));
+ }
+
// if twin socket call => reset the other part here
if (twinSippSocket && (msg_index > 0)) {
res = sendCmdBuffer
- (createSendingMessage((char*)"call-id: [call_id]\ninternal-cmd: abort_call\n", -1));
- }
-#endif /* __3PCC__ */
- CStat::instance()->computeStat(CStat::E_CALL_FAILED);
- CStat::instance()->computeStat(CStat::E_FAILED_UNEXPECTED_MSG);
- delete_call(id);
+ (createSendingMessage(get_default_message("3pcc_abort"), -1));
+ }
+
+ computeStat(CStat::E_CALL_FAILED);
+ computeStat(CStat::E_FAILED_UNEXPECTED_MSG);
+ delete this;
} else {
- WARNING_P1("Continuing call on an unexpected BYE for call: %s", (id==NULL)?"none":id);
- }
- break ;
-
- case 2: // response for an unexpected cancel
- // usage of last_ keywords
- last_recv_msg = (char *) realloc(last_recv_msg, strlen(P_recv) + 1);
- strcpy(last_recv_msg, P_recv);
-
- // The CANCEL is unexpected, count it
- scenario[msg_index] -> nb_unexp++;
- if (default_behavior) {
- WARNING_P1("Aborting call on an unexpected CANCEL for call: %s", (id==NULL)?"none":id);
- res = sendBuffer(createSendingMessage(
- (char*)"SIP/2.0 200 OK\n"
- "[last_Via:]\n"
- "[last_From:]\n"
- "[last_To:]\n"
- "[last_Call-ID:]\n"
- "[last_CSeq:]\n"
- "Contact: sip:sipp@[local_ip]:[local_port]\n"
- "Content-Length: 0\n"
- , -1)) ;
-
-#ifdef __3PCC__
- // if twin socket call => reset the other part here
- if (twinSippSocket && (msg_index > 0)) {
- res = sendCmdBuffer
- (createSendingMessage((char*)"call-id: [call_id]\ninternal-cmd: abort_call\n", -1));
- }
-#endif /* __3PCC__ */
-
- CStat::instance()->computeStat(CStat::E_CALL_FAILED);
- CStat::instance()->computeStat(CStat::E_FAILED_UNEXPECTED_MSG);
- delete_call(id);
- } else {
- WARNING_P1("Continuing call on unexpected CANCEL for call: %s", (id==NULL)?"none":id);
+ WARNING("Continuing call on unexpected CANCEL for call: %s", (id==NULL)?"none":id);
}
break ;
- case 3: // response for a random ping
+ case E_AM_PING: // response for a random ping
// usage of last_ keywords
last_recv_msg = (char *) realloc(last_recv_msg, strlen(P_recv) + 1);
strcpy(last_recv_msg, P_recv);
- if (default_behavior) {
- WARNING_P1("Automatic response mode for an unexpected PING for call: %s", (id==NULL)?"none":id);
- count_in_stats = false; // Call must not be counted in statistics
- res = sendBuffer(createSendingMessage(
- (char*)"SIP/2.0 200 OK\n"
- "[last_Via:]\n"
- "[last_Call-ID:]\n"
- "[last_To:]\n"
- "[last_From:]\n"
- "[last_CSeq:]\n"
- "Contact: sip:sipp@[local_ip]:[local_port]\n"
- "Content-Length: 0\n"
- , -1)) ;
+ if (default_behaviors & DEFAULT_BEHAVIOR_PINGREPLY) {
+ WARNING("Automatic response mode for an unexpected PING for call: %s", (id==NULL)?"none":id);
+ sendBuffer(createSendingMessage(get_default_message("200"), -1));
// Note: the call ends here but it is not marked as bad. PING is a
// normal message.
-#ifdef __3PCC__
// if twin socket call => reset the other part here
if (twinSippSocket && (msg_index > 0)) {
- res = sendCmdBuffer
- (createSendingMessage((char*)"call-id: [call_id]\ninternal-cmd: abort_call\n",-1));
- }
-#endif /* __3PCC__ */
+ res = sendCmdBuffer(createSendingMessage(get_default_message("3pcc_abort"), -1));
+ }
- CStat::instance()->computeStat(CStat::E_AUTO_ANSWERED);
- delete_call(id);
+ CStat::globalStat(CStat::E_AUTO_ANSWERED);
+ delete this;
} else {
- WARNING_P1("Do not answer on an unexpected PING for call: %s", (id==NULL)?"none":id);
+ WARNING("Do not answer on an unexpected PING for call: %s", (id==NULL)?"none":id);
}
break ;
- case 4: // response for a random INFO, UPDATE or NOTIFY
+ case E_AM_AA: // response for a random INFO, UPDATE or NOTIFY
// store previous last msg if msg is INFO, UPDATE or NOTIFY
// restore last_recv_msg to previous one
// after sending ok
@@ -3634,17 +3567,8 @@
last_recv_msg = (char *) realloc(last_recv_msg, strlen(P_recv) + 1);
strcpy(last_recv_msg, P_recv);
- WARNING_P1("Automatic response mode for an unexpected INFO, UPDATE or NOTIFY for call: %s", (id==NULL)?"none":id);
- res = sendBuffer(createSendingMessage(
- (char*)"SIP/2.0 200 OK\n"
- "[last_Via:]\n"
- "[last_Call-ID:]\n"
- "[last_To:]\n"
- "[last_From:]\n"
- "[last_CSeq:]\n"
- "Contact: sip:sipp@[local_ip]:[local_port]\n"
- "Content-Length: 0\n"
- , -1)) ;
+ WARNING("Automatic response mode for an unexpected INFO, UPDATE or NOTIFY for call: %s", (id==NULL)?"none":id);
+ sendBuffer(createSendingMessage(get_default_message("200"), -1));
// restore previous last msg
if (last_recv_msg_saved == true) {
@@ -3655,17 +3579,16 @@
old_last_recv_msg = NULL;
}
}
- CStat::instance()->computeStat(CStat::E_AUTO_ANSWERED);
+ CStat::globalStat(CStat::E_AUTO_ANSWERED);
return true;
break;
default:
- ERROR_P1("Internal error for automaticResponseMode - mode %d is not implemented!", P_case);
+ ERROR("Internal error for automaticResponseMode - mode %d is not implemented!", P_case);
break ;
}
return false;
-
}
#ifdef PCAPPLAY
Modified: sip-tester/trunk/debian/changelog
URL: http://svn.debian.org/wsvn/pkg-voip/sip-tester/trunk/debian/changelog?rev=6624&op=diff
==============================================================================
--- sip-tester/trunk/debian/changelog (original)
+++ sip-tester/trunk/debian/changelog Sun Jan 4 03:39:23 2009
@@ -1,3 +1,10 @@
+sip-tester (3.1-1) UNRELEASED; urgency=low
+
+ * (NOT RELEASED YET) New upstream release
+ * Update debian/watch
+
+ -- Mark Purcell <msp at debian.org> Sun, 04 Jan 2009 13:50:05 +1100
+
sip-tester (2.0.1-1.2) unstable; urgency=high
* Non-maintainer upload by the Security Team.
Modified: sip-tester/trunk/debian/watch
URL: http://svn.debian.org/wsvn/pkg-voip/sip-tester/trunk/debian/watch?rev=6624&op=diff
==============================================================================
--- sip-tester/trunk/debian/watch (original)
+++ sip-tester/trunk/debian/watch Sun Jan 4 03:39:23 2009
@@ -1,6 +1,2 @@
-# Example watch control file for uscan
-# Rename this file to "watch" and then you can run the "uscan" command
-# to check for upstream updates and more.
-# Site Directory Pattern Version Script
-version=2
-http://jaist.dl.sourceforge.net/sourceforge/sipp/sipp-(.*).tar.gz
+version=3
+http://sf.net/sipp/sipp.(.+)\.src\.tar\.gz debian svn-upgrade
Modified: sip-tester/trunk/sipp.hpp
URL: http://svn.debian.org/wsvn/pkg-voip/sip-tester/trunk/sipp.hpp?rev=6624&op=diff
==============================================================================
--- sip-tester/trunk/sipp.hpp (original)
+++ sip-tester/trunk/sipp.hpp Sun Jan 4 03:39:23 2009
@@ -45,7 +45,13 @@
#include <vector>
#include <string>
#include <map>
+#include <set>
#include <math.h>
+#ifndef __SUNOS
+#include <curses.h>
+#else
+#include <stdarg.h>
+#endif
#if defined(__HPUX) || defined(__SUNOS)
#include <alloca.h>
@@ -56,11 +62,15 @@
#include "xp_parser.h"
#include "scenario.hpp"
#include "screen.hpp"
+#include "task.hpp"
+#include "listener.hpp"
+#include "socketowner.hpp"
#include "call.hpp"
#include "comp.h"
#include "stat.hpp"
#include "actions.hpp"
#include "variables.hpp"
+#include "infile.hpp"
/* Open SSL stuff */
#ifdef _USE_OPENSSL
#include "sslcommon.h"
@@ -92,17 +102,27 @@
/************************** Constants **************************/
-#define SIPP_VERSION 20070516
+#ifdef SVN_VERSION
+# ifdef LOCAL_VERSION_EXTRA
+# define SIPP_VERSION SVN_VERSION LOCAL_VERSION_EXTRA
+# else
+# define SIPP_VERSION SVN_VERSION
+# endif
+#else
+# define SIPP_VERSION "unknown"
+#endif
+
#define T_UDP 0
#define T_TCP 1
+#define T_TLS 2
+
#ifdef _USE_OPENSSL
-#define T_TLS 2
#define DEFAULT_TLS_CERT ((char *)"cacert.pem")
#define DEFAULT_TLS_KEY ((char *)"cakey.pem")
#define DEFAULT_TLS_CRL ((char *)"")
-
-#endif
-#define TRANSPORT_TO_STRING(p) ((p==1) ? "TCP" : ((p==2)? "TLS" :"UDP"))
+#endif
+
+#define TRANSPORT_TO_STRING(p) ((p==T_TCP) ? "TCP" : ((p==T_TLS)? "TLS" :"UDP"))
#define SIPP_MAXFDS 65536
#define SIPP_MAX_MSG_SIZE 65536
@@ -119,6 +139,7 @@
#define DISPLAY_SECONDARY_REPARTITION_SCREEN 6
#define MAX_RECV_LOOPS_PER_CYCLE 1000
+#define MAX_SCHED_LOOPS_PER_CYCLE 1000
#define NB_UPDATE_PER_CYCLE 1
#define MAX_PATH 250
@@ -130,13 +151,12 @@
/******************** Default parameters ***********************/
#define DEFAULT_RATE 10.0
+#define DEFAULT_RATE_SCALE 1.0
#define DEFAULT_RATE_PERIOD_MS 1000
#define DEFAULT_TRANSPORT T_UDP
#define DEFAULT_PORT 5060
#define DEFAULT_MEDIA_PORT 6000
-#ifdef __3PCC__
#define DEFAULT_3PCC_PORT 6060
-#endif
#define DEFAULT_SERVICE ((char *)"service")
#define DEFAULT_AUTH_PASSWORD ((char *)"password")
#define DEFAULT_REPORT_FREQ 1000
@@ -145,23 +165,35 @@
#define DEFAULT_FREQ_DUMP_RTT 200
#define DEFAULT_MAX_MULTI_SOCKET 50000
#define DEFAULT_CTRL_SOCKET_PORT 8888
+#define DEFAULT_DEADCALL_WAIT 33000
+
+#define DEFAULT_BEHAVIOR_NONE 0
+#define DEFAULT_BEHAVIOR_BYE 1
+#define DEFAULT_BEHAVIOR_ABORTUNEXP 2
+#define DEFAULT_BEHAVIOR_PINGREPLY 4
+
+#define DEFAULT_BEHAVIOR_ALL (DEFAULT_BEHAVIOR_BYE | DEFAULT_BEHAVIOR_ABORTUNEXP | DEFAULT_BEHAVIOR_PINGREPLY)
/************ User controls and command line options ***********/
extern int duration _DEFVAL(0);
extern double rate _DEFVAL(DEFAULT_RATE);
+extern double rate_scale _DEFVAL(DEFAULT_RATE_SCALE);
extern int rate_increase _DEFVAL(0);
extern int rate_max _DEFVAL(0);
-extern int users _DEFVAL(0);
+extern bool rate_quit _DEFVAL(true);
+extern int users _DEFVAL(-1);
extern int rate_period_ms _DEFVAL(DEFAULT_RATE_PERIOD_MS);
extern unsigned long defl_recv_timeout _DEFVAL(0);
+extern unsigned long defl_send_timeout _DEFVAL(0);
extern unsigned long global_timeout _DEFVAL(0);
extern int transport _DEFVAL(DEFAULT_TRANSPORT);
extern bool retrans_enabled _DEFVAL(1);
extern int max_udp_retrans _DEFVAL(UDP_MAX_RETRANS);
extern int max_invite_retrans _DEFVAL(UDP_MAX_RETRANS_INVITE_TRANSACTION);
extern int max_non_invite_retrans _DEFVAL(UDP_MAX_RETRANS_NON_INVITE_TRANSACTION);
-extern bool default_behavior _DEFVAL(1);
+extern unsigned long default_behaviors _DEFVAL(DEFAULT_BEHAVIOR_ALL);
+extern unsigned long deadcall_wait _DEFVAL(DEFAULT_DEADCALL_WAIT);
extern bool pause_msg_ign _DEFVAL(0);
extern int auto_answer _DEFVAL(0);
extern int multisocket _DEFVAL(0);
@@ -175,6 +207,7 @@
extern unsigned long report_freq _DEFVAL(DEFAULT_REPORT_FREQ);
extern unsigned long report_freq_dumpLog _DEFVAL
(DEFAULT_REPORT_FREQ_DUMP_LOG);
+extern bool periodic_rtd _DEFVAL(false);
extern char * stat_delimiter _DEFVAL(";");
extern bool timeout_exit _DEFVAL(false);
@@ -184,16 +217,20 @@
extern unsigned int max_multi_socket _DEFVAL
(DEFAULT_MAX_MULTI_SOCKET);
+extern bool skip_rlimit _DEFVAL(false);
extern unsigned int timer_resolution _DEFVAL(DEFAULT_TIMER_RESOLUTION);
extern int max_recv_loops _DEFVAL(MAX_RECV_LOOPS_PER_CYCLE);
+extern int max_sched_loops _DEFVAL(MAX_SCHED_LOOPS_PER_CYCLE);
extern char local_ip[40];
extern char local_ip_escaped[42];
extern bool local_ip_is_ipv6;
extern int local_port _DEFVAL(0);
+extern char control_ip[40];
+extern int control_port _DEFVAL(0);
extern int buff_size _DEFVAL(65535);
-extern int tcp_readsize _DEFVAL(4096);
+extern int tcp_readsize _DEFVAL(65535);
#ifdef PCAPPLAY
extern int hasMedia _DEFVAL(0);
#endif
@@ -216,7 +253,6 @@
extern int lose_packets _DEFVAL(0);
extern double global_lost _DEFVAL(0.0);
extern char remote_host[255];
-#ifdef __3PCC__
extern char twinSippHost[255];
extern char twinSippIp[40];
extern char * master_name;
@@ -224,12 +260,10 @@
extern int twinSippPort _DEFVAL(DEFAULT_3PCC_PORT);
extern bool twinSippMode _DEFVAL(false);
extern bool extendedTwinSippMode _DEFVAL(false);
-#endif
-
+
+extern bool nostdin _DEFVAL(false);
extern bool backgroundMode _DEFVAL(false);
extern bool signalDump _DEFVAL(false);
-
-extern bool ctrlEW _DEFVAL(false);
extern int currentScreenToDisplay _DEFVAL
(DISPLAY_SCENARIO_SCREEN);
@@ -251,8 +285,6 @@
extern bool tdm_map[1024];
#ifdef _USE_OPENSSL
-extern BIO *bio ;
-extern SSL *ssl_tcp_multiplex ;
extern BIO *twinSipp_bio ;
extern SSL *twinSipp_ssl ;
extern char *tls_cert_name _DEFVAL(DEFAULT_TLS_CERT) ;
@@ -262,36 +294,48 @@
#endif
// extern field file management
-typedef std::vector<std::string> IN_FILE_CONTENTS;
-extern IN_FILE_CONTENTS fileContents;
-extern int numLinesInFile _DEFVAL(0);
-
-extern int new_socket(bool P_use_ipv6, int P_type_socket, int * P_status);
+typedef std::map<string, FileContents *> file_map;
+extern file_map inFiles;
+typedef std::map<string, str_int_map *> file_index;
+extern file_index infIndex;
+extern char *ip_file _DEFVAL(NULL);
+extern char *default_file _DEFVAL(NULL);
+
+// free user id list
+extern list<int> freeUsers;
+extern list<int> retiredUsers;
+extern AllocVariableTable *globalVariables _DEFVAL(NULL);
+extern AllocVariableTable *userVariables _DEFVAL(NULL);
+typedef std::map<int, VariableTable *> int_vt_map;
+extern int_vt_map userVarMap;
+
+//extern int new_socket(bool P_use_ipv6, int P_type_socket, int * P_status);
+extern struct sipp_socket *new_sipp_socket(bool use_ipv6, int transport);
+struct sipp_socket *new_sipp_call_socket(bool use_ipv6, int transport, bool *existing);
+struct sipp_socket *sipp_accept_socket(struct sipp_socket *accept_socket);
+extern int sipp_bind_socket(struct sipp_socket *socket, struct sockaddr_storage *saddr, int *port);
+extern int sipp_connect_socket(struct sipp_socket *socket, struct sockaddr_storage *dest);
+extern int sipp_reconnect_socket(struct sipp_socket *socket);
+extern void sipp_customize_socket(struct sipp_socket *socket);
extern int delete_socket(int P_socket);
extern int min_socket _DEFVAL(65535);
extern int select_socket _DEFVAL(0);
extern bool socket_close _DEFVAL(true);
extern bool test_socket _DEFVAL(true);
-extern bool socket_open _DEFVAL(true);
extern bool maxSocketPresent _DEFVAL(false);
-extern int *tab_multi_socket;
extern unsigned long getmilliseconds();
extern unsigned long long getmicroseconds();
/************************ Statistics **************************/
-extern unsigned long total_calls _DEFVAL(0);
extern unsigned long last_report_calls _DEFVAL(0);
extern unsigned long nb_net_send_errors _DEFVAL(0);
extern unsigned long nb_net_cong _DEFVAL(0);
extern unsigned long nb_net_recv_errors _DEFVAL(0);
extern bool cpu_max _DEFVAL(false);
extern bool outbound_congestion _DEFVAL(false);
-extern unsigned int open_calls_peak _DEFVAL(0);
-extern unsigned long open_calls_peak_time _DEFVAL(0);
extern int open_calls_user_setting _DEFVAL(0);
-extern int nb_out_of_the_blue _DEFVAL(0);
extern int resynch_send _DEFVAL(0);
extern int resynch_recv _DEFVAL(0);
extern unsigned long rtp_pckts _DEFVAL(0);
@@ -305,7 +349,6 @@
/************* Rate Control & Contexts variables **************/
-extern unsigned int open_calls _DEFVAL(0);
extern int last_running_calls _DEFVAL(0);
extern int last_woken_calls _DEFVAL(0);
extern int last_paused_calls _DEFVAL(0);
@@ -313,7 +356,6 @@
extern unsigned long last_rate_change_time _DEFVAL(0);
extern unsigned long last_report_time _DEFVAL(0);
extern unsigned long last_dump_time _DEFVAL(0);
-extern unsigned long calls_since_last_rate_change _DEFVAL(0);
/********************** Clock variables ***********************/
@@ -329,8 +371,8 @@
/*********************** Global Sockets **********************/
-extern int main_socket _DEFVAL(0);
-extern int tcp_multiplex _DEFVAL(0);
+extern struct sipp_socket *main_socket _DEFVAL(0);
+extern struct sipp_socket *tcp_multiplex _DEFVAL(0);
extern int media_socket _DEFVAL(0);
extern int media_socket_video _DEFVAL(0);
@@ -339,17 +381,19 @@
extern int user_port _DEFVAL(0);
extern char hostname[80];
extern bool is_ipv6 _DEFVAL(false);
-extern int start_calls _DEFVAL(0);
-extern double reset_number _DEFVAL(0);
+
+extern int reset_number _DEFVAL(0);
extern int reset_close _DEFVAL(1);
extern int reset_sleep _DEFVAL(1000);
+extern bool sendbuffer_warn _DEFVAL(false);
+/* A list of sockets pending reset. */
+extern set<struct sipp_socket *> sockets_pending_reset;
extern struct addrinfo * local_addr_storage;
-#ifdef __3PCC__
-extern int twinSippSocket _DEFVAL(0);
-extern int localTwinSippSocket _DEFVAL(0);
-extern struct sockaddr_storage twinSipp_sockaddr;
+extern struct sipp_socket *twinSippSocket _DEFVAL(NULL);
+extern struct sipp_socket *localTwinSippSocket _DEFVAL(NULL);
+extern struct sockaddr_storage twinSipp_sockaddr;
/* 3pcc extended mode */
typedef struct _T_peer_infos {
@@ -357,22 +401,20 @@
int peer_port;
struct sockaddr_storage peer_sockaddr;
char peer_ip[40];
- int peer_socket ;
+ struct sipp_socket *peer_socket ;
} T_peer_infos;
typedef std::map<std::string, char * > peer_addr_map;
extern peer_addr_map peer_addrs;
typedef std::map<std::string, T_peer_infos> peer_map;
extern peer_map peers;
-typedef std::map<int, std::string > peer_socket_map;
+typedef std::map<struct sipp_socket *, std::string > peer_socket_map;
extern peer_socket_map peer_sockets;
-extern int local_sockets[MAX_LOCAL_TWIN_SOCKETS];
+extern struct sipp_socket *local_sockets[MAX_LOCAL_TWIN_SOCKETS];
extern int local_nb _DEFVAL(0);
extern int peers_connected _DEFVAL(0);
-#endif
-
-extern struct sockaddr_storage remote_sockaddr;
-
+
+extern struct sockaddr_storage remote_sockaddr;
extern short use_remote_sending_addr _DEFVAL(0);
extern struct sockaddr_storage remote_sending_sockaddr;
@@ -387,42 +429,37 @@
extern FILE * screenf _DEFVAL(0);
extern FILE * logfile _DEFVAL(0);
extern FILE * messagef _DEFVAL(0);
-extern FILE * timeoutf _DEFVAL(0);
+extern FILE * shortmessagef _DEFVAL(0);
+extern FILE * countf _DEFVAL(0);
+// extern FILE * timeoutf _DEFVAL(0);
extern bool useMessagef _DEFVAL(0);
+extern bool useShortMessagef _DEFVAL(0);
extern bool useScreenf _DEFVAL(0);
extern bool useLogf _DEFVAL(0);
-extern bool useTimeoutf _DEFVAL(0);
+// should we overwrite the existing files?
+extern bool messagef_overwrite _DEFVAL(true);
+extern bool shortmessagef_overwrite _DEFVAL(true);
+extern bool errorf_overwrite _DEFVAL(true);
+extern bool logfile_overwrite _DEFVAL(true);
+//extern bool useTimeoutf _DEFVAL(0);
extern bool dumpInFile _DEFVAL(0);
extern bool dumpInRtt _DEFVAL(0);
+extern bool useCountf _DEFVAL(0);
extern char * scenario_file;
extern char * slave_cfg_file;
-#define TRACE_MSG(arg) \
-{ \
- if(messagef) { \
- FILE * s = messagef; \
- fprintf arg; \
- fflush(messagef); \
- } \
-}
-
-#define LOG_MSG(arg) \
-{ \
- if(logfile) { \
- FILE * s = logfile; \
- fprintf arg; \
- fflush(logfile); \
- } \
-}
-
-#define TRACE_TIMEOUT(arg) \
-{ \
- if(timeoutf) { \
- FILE * s = timeoutf; \
- fprintf arg; \
- fflush(timeoutf); \
- } \
-}
+extern unsigned long long max_log_size _DEFVAL(0);
+extern unsigned long long ringbuffer_size _DEFVAL(0);
+extern int ringbuffer_files _DEFVAL(0);
+
+extern char screen_last_error[32768];
+extern char screen_logfile[MAX_PATH] _DEFVAL("");
+extern FILE * screen_errorf _DEFVAL(NULL);
+
+void rotate_messagef();
+void rotate_shortmessagef();
+void rotate_logfile();
+void rotate_errorf();
/********************* Mini-Parser Routines *******************/
@@ -433,15 +470,67 @@
/********************** Network Interfaces ********************/
-void sipp_customize_socket(int socket);
int send_message(int s, void ** comp_state, char * msg);
#ifdef _USE_OPENSSL
int send_message_tls(SSL *s, void ** comp_state, char * msg);
#endif
-void pollset_remove(int idx);
-void remove_from_pollfiles(int sock);
-int pollset_add(call * p_call, int socket);
+/* Socket Buffer Management. */
+#define NO_COPY 0
+#define DO_COPY 1
+struct socketbuf *alloc_socketbuf(char *buffer, size_t size, int copy);
+void free_socketbuf(struct socketbuf *socketbuf);
+
+/* These buffers lets us read past the end of the message, and then split it if
+ * required. This eliminates the need for reading a message octet by octet and
+ * performing a second read for the content length. */
+struct socketbuf {
+ char *buf;
+ size_t len;
+ size_t offset;
+ struct sockaddr_storage addr;
+ struct socketbuf *next;
+};
+
+/* This is an abstraction of a socket, which provides buffers for input and
+ * output. */
+struct sipp_socket {
+ int ss_count; /* How many users are there of this socket? */
+
+ int ss_transport; /* T_TCP, T_UDP, or T_TLS. */
+ bool ss_ipv6;
+ bool ss_control; /* Is this a control socket? */
+ bool ss_call_socket; /* Is this a call socket? */
+
+ int ss_fd; /* The underlying file descriptor for this socket. */
+ void *ss_comp_state; /* The compression state. */
+#ifdef _USE_OPENSSL
+ SSL *ss_ssl; /* The underlying SSL descriptor for this socket. */
+ BIO *ss_bio; /* The underlying BIO descriptor for this socket. */
+#endif
+ struct sockaddr_storage ss_remote_sockaddr; /* Who we are talking to. */
+ struct sockaddr_storage ss_dest; /* Who we are talking to. */
+
+
+ int ss_pollidx; /* The index of this socket in our poll structures. */
+ bool ss_congested; /* Is this socket congested? */
+ bool ss_invalid; /* Has this socket been closed remotely? */
+
+ struct socketbuf *ss_in; /* Buffered input. */
+ size_t ss_msglen; /* Is there a complete SIP message waiting, and if so how big? */
+ struct socketbuf *ss_out; /* Buffered output. */
+};
+
+/* Write data to a socket. */
+int write_socket(struct sipp_socket *socket, char *buffer, ssize_t len, int flags, struct sockaddr_storage *dest);
+/* Mark a socket as "bad". */
+void sipp_socket_invalidate(struct sipp_socket *socket);
+/* Actually free the socket. */
+void sipp_close_socket(struct sipp_socket *socket);
+
+#define WS_EAGAIN 1 /* Return EAGAIN if there is no room for writing the message. */
+#define WS_BUFFER 2 /* Buffer the message if there is no room for writing the message. */
+
#if defined (__hpux) || defined (__alpha) && !defined (__FreeBSD__)
#define sipp_socklen_t int
@@ -465,17 +554,18 @@
char *get_peer_addr(char *);
int get_decimal_from_hex(char hex);
-int reset_connections() ;
-int close_calls();
+bool reconnect_allowed();
+void reset_connection(struct sipp_socket *);
+void close_calls(struct sipp_socket *);
int close_connections();
int open_connections();
void timeout_alarm(int);
/* extended 3PCC mode */
-int * get_peer_socket(char *);
-bool is_a_peer_socket(int);
-bool is_a_local_socket(int);
-void connect_to_peer (char *, int *, sockaddr_storage *, char *, int *);
+struct sipp_socket **get_peer_socket(char *);
+bool is_a_peer_socket(struct sipp_socket *);
+bool is_a_local_socket(struct sipp_socket *);
+void connect_to_peer (char *, int , sockaddr_storage *, char *, struct sipp_socket **);
void connect_to_all_peers ();
void connect_local_twin_socket(char *);
void close_peer_sockets();
@@ -488,4 +578,15 @@
#undef extern
#endif
+/* THis must go after the GLOBALS_FULL_DEFINITION, because we need the extern keyword. */
+#ifdef __cplusplus
+extern "C" {
+#endif
+int TRACE_MSG(char *fmt, ...);
+int TRACE_SHORTMSG(char *fmt, ...);
+int LOG_MSG(char *fmt, ...);
+#ifdef __cplusplus
+}
+#endif
+
#endif // __SIPP__
More information about the Pkg-voip-commits
mailing list