[Pkg-voip-commits] r6613 - in /sip-tester: ./ branches/ branches/upstream/ branches/upstream/current/ branches/upstream/current/Makefile branches/upstream/current/call.cpp branches/upstream/current/sipp.hpp
msp at alioth.debian.org
msp at alioth.debian.org
Sun Jan 4 00:34:05 UTC 2009
Author: msp
Date: Sun Jan 4 00:34:05 2009
New Revision: 6613
URL: http://svn.debian.org/wsvn/pkg-voip/?sc=1&rev=6613
Log:
[svn-inject] Installing original source of sip-tester
Added:
sip-tester/
sip-tester/branches/
sip-tester/branches/upstream/
sip-tester/branches/upstream/current/
sip-tester/branches/upstream/current/Makefile
sip-tester/branches/upstream/current/call.cpp
sip-tester/branches/upstream/current/sipp.hpp
Added: sip-tester/branches/upstream/current/Makefile
URL: http://svn.debian.org/wsvn/pkg-voip/sip-tester/branches/upstream/current/Makefile?rev=6613&op=file
==============================================================================
--- sip-tester/branches/upstream/current/Makefile (added)
+++ sip-tester/branches/upstream/current/Makefile Sun Jan 4 00:34:05 2009
@@ -1,0 +1,225 @@
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# Copyright (C) 2003 - The Authors
+#
+# Author : Richard GAYRAUD - 04 Nov 2003
+# From Hewlett Packard Company.
+#
+
+-include local.mk
+
+# 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
+
+# Libraries directories
+LIBDIR_linux=
+LIBDIR_FreeBSD=
+LIBDIR_hpux=
+LIBDIR_tru64=
+LIBDIR_SunOS=
+LIBDIR_Cygwin=
+LIBDIR_Darwin=
+
+# Archive file created in your home directory when building the archive target
+# ARCHIVE= $(HOME)/$(OUTPUT).tgz
+ARCHIVE= $(OUTPUT).tgz
+
+# Files to be erased by 'make clean' in addition to the output
+# binaries and object files:
+TOCLEAN= *.log $(ARCHIVE) \
+ *.csv *.exe
+
+###################################################################
+# Generic Rules
+
+#OSNAME=`uname`
+#MODELNAME=`uname -m`
+
+# SYSTEM nickname
+SYSTEM_HP-UX=hpux
+SYSTEM_Linux=linux
+SYSTEM_FreeBSD=freebsd
+SYSTEM_OSF1=tru64
+SYSTEM_SunOS=SunOS
+SYSTEM_CYGWIN=Cygwin
+SYSTEM_Darwin=Darwin
+SYSTEM=$(SYSTEM_$(OSNAME))
+
+# C compiler
+CC_hpux=aCC
+CC_linux=cc
+CC_freebsd=cc
+CC_tru64=cc
+CC_SunOS=gcc
+CC_Cygwin=cc
+CC_Darwin=cc
+CC=$(CC_$(SYSTEM))
+
+# C++ compiler mapping
+CPP_hpux=aCC
+CPP_linux=gcc
+CPP_freebsd=g++
+CPP_tru64=cxx
+CPP_SunOS=g++
+CPP_Cygwin=g++
+CPP_Darwin=g++
+CPP=$(CPP_$(SYSTEM))
+
+#Model specific flags
+MFLAGS_ia64=+DD64
+MFLAGS_9000/800=+DAportable
+MFLAGS_9000/785=+DAportable
+MFLAGS_i686=
+MFLAGS_i586=
+MFLAGS_i486=
+MFLAGS_i386=
+MFLAGS_ppc=
+MFLAGS=$(MFLAGS_$(MODELNAME))
+
+#C Compiler Flags
+# supress warning #829 (Implicit conversion of string literal to
+#'char *' is deprecated) since this is both common and harmless
+CFLAGS_hpux=-D__HPUX -DPROTOTYPES +W829
+CFLAGS_linux=-D__LINUX -pthread
+CFLAGS_freebsd=-D__LINUX -pthread
+CFLAGS_tru64=-D__OSF1 -pthread
+CFLAGS_SunOS=-g -D__SUNOS
+CFLAGS_Cygwin=-D__CYGWIN -Dsocklen_t=int
+CFLAGS_Darwin=-D__DARWIN
+CFLAGS=$(CFLAGS_$(SYSTEM)) -D__3PCC__ $(TLS) $(PCAPPLAY) $(EXTRACFLAGS)
+
+#C++ Compiler Flags
+CPPFLAGS_hpux=-AA -mt -D__HPUX +W829
+CPPFLAGS_linux=-D__LINUX -pthread
+CPPFLAGS_freebsd=-D__LINUX -pthread
+CPPFLAGS_tru64=-D__OSF1 -pthread
+CPPFLAGS_SunOS=-g -D__SUNOS
+CPPFLAGS_Cygwin=-D__CYGWIN -Dsocklen_t=int
+CPPFLAGS_Darwin=-D__DARWIN
+CPPFLAGS=$(CPPFLAGS_$(SYSTEM)) -D__3PCC__ $(TLS) $(PCAPPLAY) $(EXTRACPPFLAGS)
+
+#Linker mapping
+CCLINK_hpux=aCC
+CCLINK_linux=gcc
+CCLINK_freebsd=g++
+CCLINK_tru64=cxx
+CCLINK_SunOS=gcc
+CCLINK_Cygwin=g++
+CCLINK_Darwin=g++
+CCLINK=$(CCLINK_$(SYSTEM))
+
+#Linker Flags
+LFLAGS_hpux=-AA -mt
+LFLAGS_linux=
+LFLAGS_freebsd=
+LFLAGS_tru64=
+LFLAGS_SunOS=
+LFLAGS_Cygwin=
+LFLAGS_Darwin=
+LFLAGS=$(LFLAGS_$(SYSTEM)) $(EXTRALFLAGS)
+
+#Link Libraries
+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_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_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/
+INCDIR_Cygwin=-I. -I/usr/include/openssl -I/usr/include -I/usr/lib/WpdPack/Include
+INCDIR_Darwin=-I. -I/usr/local/ssl/include
+INCDIR=$(INCDIR_$(SYSTEM))
+
+-include local.mk
+
+# Building without TLS and authentication (no openssl pre-requisite)
+all:
+ make OSNAME=`uname|sed -e "s/CYGWIN.*/CYGWIN/"` MODELNAME=`uname -m|sed "s/Power Macintosh/ppc/"` $(OUTPUT)
+
+# Building with TLS and authentication
+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" $(OUTPUT)
+
+#Building with PCAP play
+pcapplay:
+ 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)
+
+pcapplay_hp_li_ia:
+ @_HPUX_LI_FLAG=-D_HPUX_LI ; export _HPUX_LI_FLAG ; make pcapplay
+
+pcapplay_ossl_hp_li_ia:
+ @_HPUX_LI_FLAG=-D_HPUX_LI ; export _HPUX_LI_FLAG ; make pcapplay_ossl
+
+pcapplay_cygwin:
+ 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="-lwpcap" PCAPPLAY="-DPCAPPLAY" $(OUTPUT)
+
+pcapplay_ossl_cygwin:
+ 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="-lwpcap" PCAPPLAY="-DPCAPPLAY" $(OUTPUT)
+
+$(OUTPUT): $(OBJ_TLS) $(OBJ_PCAPPLAY) $(OBJ)
+ $(CCLINK) $(LFLAGS) $(MFLAGS) $(LIBDIR_$(SYSTEM)) \
+ $(DEBUG_FLAGS) -o $@ $(OBJ_TLS) $(OBJ_PCAPPLAY) $(OBJ) $(LIBS) $(TLS_LIBS) $(PCAPPLAY_LIBS) $(EXTRAENDLIBS)
+
+debug:
+ DEBUG_FLAGS="-g -pg" ; export DEBUG_FLAGS ; make all
+
+debug_tls:
+ @DEBUG_FLAGS=-g ; export DEBUG_FLAGS ; make tls
+
+debug_pcap_cygwin:
+ @DEBUG_FLAGS=-g ; export DEBUG_FLAGS ; make pcapplay_ossl_cygwin
+
+clean:
+ rm -f *.o $(OUTPUT) *~ $(TOCLEAN)
+ rm -rf cxx_repository
+
+archive:
+ rm -f TMP_TAR_FILE.* $(ARCHIVE)
+ make clean
+ tar cf TMP_TAR_FILE.tar .
+ gzip TMP_TAR_FILE.tar
+ cp TMP_TAR_FILE.tar.gz $(ARCHIVE)
+ rm -f TMP_TAR_FILE.*
+
+
+# Files types rules
+.SUFFIXES: .o .cpp .c .h .hpp
+
+*.o: *.h *.hpp
+
+.C.o:
+ $(CPP) $(CPPFLAGS) $(MFLAGS) $(DEBUG_FLAGS) $(_HPUX_LI_FLAG) $(INCDIR) -c -o $*.o $<
+
+.cpp.o:
+ $(CPP) $(CPPFLAGS) $(MFLAGS) $(DEBUG_FLAGS) $(_HPUX_LI_FLAG) $(INCDIR) -c -o $*.o $<
+
+.c.o:
+ $(CC) $(CFLAGS) $(MFLAGS) $(DEBUG_FLAGS) $(_HPUX_LI_FLAG) $(INCDIR) -c -o $*.o $<
+
Added: sip-tester/branches/upstream/current/call.cpp
URL: http://svn.debian.org/wsvn/pkg-voip/sip-tester/branches/upstream/current/call.cpp?rev=6613&op=file
==============================================================================
--- sip-tester/branches/upstream/current/call.cpp (added)
+++ sip-tester/branches/upstream/current/call.cpp Sun Jan 4 00:34:05 2009
@@ -1,0 +1,3687 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author : Richard GAYRAUD - 04 Nov 2003
+ * Olivier Jacques
+ * From Hewlett Packard Company.
+ * Shriram Natarajan
+ * Peter Higginson
+ * Eric Miller
+ * Venkatesh
+ * Enrico Hartung
+ * Nasir Khan
+ * Lee Ballard
+ * Guillaume Teissier from FTR&D
+ * Wolfgang Beck
+ * Venkatesh
+ * Vlad Troyanker
+ * Charles P Wright from IBM Research
+ * Amit On from Followap
+ * Jan Andres from Freenet
+ * Ben Evans from Open Cloud
+ * Marc Van Diest from Belgacom
+ * Michael Dwyer from Cibation
+ */
+
+#include <iterator>
+#include <algorithm>
+#include <fstream>
+#include <iostream>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#ifdef PCAPPLAY
+#include "send_packets.h"
+#endif
+#include "sipp.hpp"
+#include "assert.h"
+
+#define KEYWORD_SIZE 256
+
+#ifdef _USE_OPENSSL
+extern SSL *ssl_list[];
+extern struct pollfd pollfiles[];
+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;
+
+#ifdef PCAPPLAY
+/* send_packets pthread wrapper */
+void *send_wrapper(void *);
+#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 nb = 0;
+ unsigned int i=0;
+ unsigned int interval=0;
+ unsigned int random=0;
+ bool found = false;
+
+ /* Find a number in the tdm_map which is not in use */
+ interval = (tdm_map_a+1) * (tdm_map_b+1) * (tdm_map_c+1);
+ random = rand() % interval;
+ while ((i<interval) && (!found)) {
+ if (tdm_map[(random + i - 1) % interval] == false) {
+ nb = (random + i - 1) % interval;
+ found = true;
+ }
+ i++;
+ }
+
+ if (!found) {
+ return 0;
+ } else {
+ return nb+1;
+ }
+}
+
+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;
+ } 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;
+}
+#endif
+
+
+call * add_call(bool ipv6)
+{
+ 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;
+ switch(*src++) {
+ case 'u':
+ count += snprintf(&call_id[count], MAX_HEADER_LEN-count-1,"%u", next_number);
+ break;
+ case 'p':
+ count += snprintf(&call_id[count], MAX_HEADER_LEN-count-1,"%u", pid);
+ break;
+ case 's':
+ count += snprintf(&call_id[count], MAX_HEADER_LEN-count-1,"%s", local_ip);
+ break;
+ default: // treat all unknown sequences as %%
+ call_id[count++] = '%';
+ break;
+ }
+ } else {
+ call_id[count++] = *src++;
+ }
+ }
+ 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);
+ 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;
+
+#ifdef _USE_OPENSSL
+ m_ctx_ssl = NULL ;
+ m_bio = NULL ;
+#endif
+
+ pollset_index = 0 ;
+ poll_flag_write = false ;
+
+ call_remote_socket = 0;
+
+ // 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;
+ }
+ }
+
+ // If not updated by a message we use the start time
+ // information to compute rtd information
+ for (i = 0; i < MAX_RTD_INFO_LENGTH; i++) {
+ start_time_rtd[i] = getmicroseconds();
+ rtd_done[i] = false;
+ }
+
+ // by default, last action result is NO_ERROR
+ last_action_result = call::E_AR_NO_ERROR;
+
+ if (InputFileRandomOrder == m_usage) {
+ m_localLineNumber = rand() % numLinesInFile;
+ } else {
+ m_localLineNumber = m_counter++;
+ if (m_counter >= numLinesInFile) {
+ m_counter = 0;
+ }
+
+ }
+
+#ifdef PCAPPLAY
+ memset(&(play_args_a.to), 0, sizeof(struct sockaddr_storage));
+ memset(&(play_args_v.to), 0, sizeof(struct sockaddr_storage));
+ memset(&(play_args_a.from), 0, sizeof(struct sockaddr_storage));
+ memset(&(play_args_v.from), 0, sizeof(struct sockaddr_storage));
+ hasMediaInformation = 0;
+ media_thread = 0;
+#endif
+
+ peer_tag = NULL;
+ recv_timeout = 0;
+}
+
+call::~call()
+{
+ deleted += 1;
+
+ 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(last_recv_msg) { free(last_recv_msg); }
+ if(last_send_msg) { free(last_send_msg); }
+ if(peer_tag) { free(peer_tag); }
+
+ if(dialog_route_set) {
+ free(dialog_route_set);
+ }
+
+ if(next_req_url) {
+ 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(transport == T_UDP) {
+ struct sockaddr_storage saddr;
+ sipp_socklen_t len;
+
+ int L_status = 0 ; // no new socket
+
+ if(toolMode != MODE_CLIENT) return;
+
+ 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) {
+ memset(&saddr, 0, sizeof(struct sockaddr_storage));
+
+ memcpy(&saddr,
+ local_addr_storage->ai_addr,
+ SOCK_ADDR_SIZE(
+ _RCAST(struct sockaddr_storage *,local_addr_storage->ai_addr)));
+
+ if (use_ipv6) {
+ saddr.ss_family = AF_INET6;
+ } else {
+ saddr.ss_family = AF_INET;
+ }
+
+ if (peripsocket) {
+ struct addrinfo * h ;
+ struct addrinfo hints;
+ memset((char*)&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = PF_UNSPEC;
+ getaddrinfo(peripaddr,
+ NULL,
+ &hints,
+ &h);
+ memcpy(&saddr,
+ h->ai_addr,
+ SOCK_ADDR_SIZE(
+ _RCAST(struct sockaddr_storage *,h->ai_addr)));
+
+ if (use_ipv6) {
+ (_RCAST(struct sockaddr_in6 *, &saddr))->sin6_port = htons(local_port);
+ } else {
+ (_RCAST(struct sockaddr_in *, &saddr))->sin_port = htons(local_port);
+ }
+ }
+
+ if(bind(call_socket,
+ (sockaddr *)(void *)&saddr,
+ use_ipv6 ? sizeof(struct sockaddr_in6) :
+ sizeof(struct sockaddr_in))) {
+ ERROR_NO("Unable to bind UDP socket");
+ }
+ }
+
+ 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) {
+ 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;
+ } 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)
+{
+ static int inited = 0;
+ double percent = global_lost;
+
+ if(!lose_packets) return false;
+
+ if (scenario[index]->lost >= 0) {
+ percent = scenario[index]->lost;
+ }
+
+ if (percent == 0) {
+ return false;
+ }
+
+ if(!inited) {
+ srand((unsigned int) time(NULL));
+ inited = 1;
+ }
+
+ return (((double)rand() / (double)RAND_MAX) < (percent / 100.0));
+}
+
+int call::send_raw(char * msg, int index)
+{
+ void ** state;
+ int 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((index!=-1) && (lost(index))) {
+ TRACE_MSG((s, "%s message voluntary lost (while sending).", TRANSPORT_TO_STRING(transport)));
+
+ if(comp_state) { comp_free(&comp_state); }
+ scenario[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");
+ }
+ 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);
+ }
+
+ 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;
+
+ /* call send_raw but with a special scenario index */
+ rc=send_raw(msg, -1);
+
+ return rc;
+}
+
+
+char * call::compute_cseq(char * src)
+{
+ static char cseq[MAX_HEADER_LEN];
+
+ /* If we find a CSeq in incoming msg */
+ char * last_header = get_last_header("CSeq:");
+ if(last_header) {
+ int i;
+ /* Extract the integer value of the last CSeq */
+ last_header = strstr(last_header, ":");
+ last_header++;
+ while(isspace(*last_header)) last_header++;
+ sscanf(last_header,"%d", &i);
+ /* Add 1 to the last CSeq value */
+ sprintf(cseq, "%s%d", "CSeq: ", (i+1));
+ } else {
+ sprintf(cseq, "%s", "CSeq: 2");
+ }
+ return cseq;
+}
+
+char * call::get_header_field_code(char *msg, char * name)
+{
+ static char code[MAX_HEADER_LEN];
+ char * last_header;
+ int i;
+
+ last_header = NULL;
+ i = 0;
+ /* If we find the field in msg */
+ last_header = get_header_content(msg, name);
+ if(last_header) {
+ /* Extract the integer value of the field */
+ while(isspace(*last_header)) last_header++;
+ sscanf(last_header,"%d", &i);
+ sprintf(code, "%s %d", name, i);
+ }
+ return code;
+}
+
+char * call::get_last_header(char * name)
+{
+ int len;
+
+ if((!last_recv_msg) || (!strlen(last_recv_msg))) {
+ return NULL;
+ }
+
+ len = strlen(name);
+
+ /* 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));
+ }
+
+ if (name[len - 1] == ':') {
+ return get_header(last_recv_msg, name, false);
+ } else {
+ char with_colon[MAX_HEADER_LEN];
+ sprintf(with_colon, "%s:", name);
+ return get_header(last_recv_msg, with_colon, false);
+ }
+}
+
+char * call::get_header_content(char* message, char * name)
+{
+ return get_header(message, name, true);
+}
+
+/* If content is true, we only return the header's contents. */
+char * call::get_header(char* message, char * name, bool content)
+{
+ /* non reentrant. consider accepting char buffer as param */
+ static char last_header[MAX_HEADER_LEN * 10];
+ char * src, *dest, *start, *ptr;
+ /* Are we searching for a short form header? */
+ bool short_form = false;
+ char src_tmp[MAX_HEADER_LEN + 1];
+
+ /* returns empty string in case of error */
+ last_header[0] = '\0';
+
+ if((!message) || (!strlen(message))) {
+ return last_header;
+ }
+
+ /* for safety's sake */
+ if (NULL == name || NULL == strrchr(name, ':')) {
+ WARNING_P1("Can not searching for header (no colon): %s", name ? name : "(null)");
+ return last_header;
+ }
+
+ do
+ {
+ snprintf(src_tmp, MAX_HEADER_LEN, "\n%s", name);
+ src = message;
+ dest = last_header;
+
+ while(src = strcasestr2(src, src_tmp)) {
+ if (content) {
+ /* just want the header's content */
+ src += strlen(name) + 1;
+ } else {
+ src++;
+ }
+ ptr = strchr(src, '\n');
+
+ /* Multiline headers always begin with a tab or a space
+ * on the subsequent lines */
+ while((ptr) &&
+ ((*(ptr+1) == ' ' ) ||
+ (*(ptr+1) == '\t') )) {
+ ptr = strchr(ptr + 1, '\n');
+ }
+
+ if(ptr) { *ptr = 0; }
+ // 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 += 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'; }
+
+ src++;
+ }
+ /* We found the header. */
+ if(dest != last_header) {
+ break;
+ }
+ /* We didn't find the header, even in its short form. */
+ if (short_form) {
+ return last_header;
+ }
+
+ /* We should retry with the short form. */
+ short_form = true;
+ if (!strcasecmp(name, "call-id:")) {
+ name = "i:";
+ } else if (!strcasecmp(name, "contact:")) {
+ name = "m:";
+ } else if (!strcasecmp(name, "content-encoding:")) {
+ name = "e:";
+ } else if (!strcasecmp(name, "content-length:")) {
+ name = "l:";
+ } else if (!strcasecmp(name, "content-type:")) {
+ name = "c:";
+ } else if (!strcasecmp(name, "from:")) {
+ name = "f:";
+ } else if (!strcasecmp(name, "to:")) {
+ name = "t:";
+ } else if (!strcasecmp(name, "via:")) {
+ name = "v:";
+ } else {
+ /* There is no short form to try. */
+ return last_header;
+ }
+ }
+ while (1);
+
+ *(dest--) = 0;
+
+ /* Remove trailing whitespaces, tabs, and CRs */
+ while ((dest > last_header) &&
+ ((*dest == ' ') || (*dest == '\r')|| (*dest == '\t'))) {
+ *(dest--) = 0;
+ }
+
+ /* Remove leading whitespaces */
+ for (start = last_header; *start == ' '; start++);
+
+ /* remove enclosed CRs in multilines */
+ /* don't remove enclosed CRs for multiple headers (e.g. Via) (Rhys) */
+ while((ptr = strstr(last_header, "\r\n")) != NULL
+ && ( *(ptr + 2) == ' '
+ || *(ptr + 2) == '\r'
+ || *(ptr + 2) == '\t') ) {
+ /* Use strlen(ptr) to include trailing zero */
+ memmove(ptr, ptr+1, strlen(ptr));
+ }
+
+ /* Remove illegal double CR characters */
+ while((ptr = strstr(last_header, "\r\r")) != NULL) {
+ memmove(ptr, ptr+1, strlen(ptr));
+ }
+ /* Remove illegal double Newline characters */
+ while((ptr = strstr(last_header, "\n\n")) != NULL) {
+ memmove(ptr, ptr+1, strlen(ptr));
+ }
+
+ return start;
+}
+
+char * call::send_scene(int index, int *send_status)
+{
+ static char msg_buffer[SIPP_MAX_MSG_SIZE];
+
+#define MAX_MSG_NAME_SIZE 30
+ static char msg_name[MAX_MSG_NAME_SIZE];
+ char *L_ptr1 ;
+ 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);
+ }
+ } else {
+ ERROR("Unsupported 'send' message in scenario");
+ }
+
+ return msg_buffer;
+}
+
+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 this message can be used to compute RTD, do it now */
+ if(int rtd = scenario[index] -> start_rtd) {
+ start_time_rtd[rtd - 1] = getmicroseconds();
+ }
+
+ if(int rtd = scenario[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,
+ (end - start) / 1000, rtd - 1);
+
+ if (!scenario[index] -> repeat_rtd) {
+ rtd_done[rtd - 1] = true;
+ }
+ }
+ }
+}
+
+bool call::next()
+{
+ int test = scenario[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()))
+ ) {
+ /* Branching possible, check the probability */
+ int chance = scenario[msg_index]->chance;
+ if ((chance <= 0) || (rand() > chance )) {
+ /* Branch == overwrite with the 'next' attribute value */
+ new_msg_index = labelArray[scenario[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);
+ return false;
+ }
+
+ return run();
+}
+
+bool call::run()
+{
+ bool bInviteTransaction = false;
+ int actionResult = 0;
+
+ assert(running);
+
+ clock_tick = getmilliseconds();
+
+ if(msg_index >= scenario_len) {
+ ERROR_P3("Scenario overrun for call %s (%p) (index = %d)\n",
+ id, this, msg_index);
+ }
+
+ /* Manages retransmissions or delete if max retrans reached */
+ if(next_retrans && (next_retrans < clock_tick)) {
+ nb_retrans++;
+
+ if ( (0 == strncmp (last_send_msg, "INVITE", 6)) )
+ {
+ bInviteTransaction = true;
+ }
+
+ 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];
+ next_retrans = 0;
+ recv_timeout = 0;
+ if (msg_index < scenario_len) 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) {
+ // Abort the call by sending proper SIP message
+ return(abortCall());
+ } else {
+ // Just delete existing call
+ delete_call(id);
+ return false;
+ }
+ }
+ CStat::instance()->computeStat(CStat::E_CALL_FAILED);
+ CStat::instance()->computeStat(CStat::E_FAILED_MAX_UDP_RETRANS);
+ if (default_behavior) {
+ // Abort the call by sending proper SIP message
+ WARNING_P1("Aborting call on UDP retransmission timeout for Call-ID '%s'", id);
+ return(abortCall());
+ } else {
+ // Just delete existing call
+ delete_call(id);
+ return false;
+ }
+ } else {
+ nb_last_delay *= 2;
+ if (DEFAULT_T2_TIMER_VALUE < nb_last_delay)
+ {
+ if (!bInviteTransaction)
+ {
+ nb_last_delay = DEFAULT_T2_TIMER_VALUE;
+ }
+ }
+ 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);
+ next_retrans = clock_tick + nb_last_delay;
+ }
+ }
+
+ 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);
+ return true;
+ }
+ /* Our pause is over. */
+ paused_until = 0;
+ return next();
+ } else if(scenario[msg_index] -> pause_function) {
+ unsigned int pause;
+ pause = scenario[msg_index] -> pause_function(scenario[msg_index]);
+ if (pause > INT_MAX) {
+ pause = INT_MAX;
+ }
+ paused_until = clock_tick + pause;
+
+ /* Increment the number of sessions in pause state */
+ ++scenario[msg_index]->sessions;
+ return run(); /* In case delay is 0 */
+ }
+#ifdef __3PCC__
+ else if(scenario[msg_index] -> M_type == MSG_TYPE_SENDCMD) {
+ int send_status;
+
+ if(next_retrans) {
+ return true;
+ }
+
+ send_status = sendCmdMessage(msg_index);
+
+ if(send_status != 0) { /* Send error */
+ return false; /* call deleted */
+ }
+ scenario[msg_index] -> 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) {
+ char * msg_snd;
+ int send_status;
+
+ /* Do not send a new message until the previous one which had
+ * 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);
+ return true;
+ }
+
+ /* Handle counters and RTDs for this message. */
+ do_bookkeeping(msg_index);
+
+ /* decide whether to increment cseq or not
+ * basically increment for anything except response, ACK or CANCEL
+ * Note that cseq is only used by the [cseq] keyword, and
+ * not by default
+ */
+
+ 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)) {
+ ++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 (incr_cseq) --cseq;
+ return true; /* No step, nothing done, retry later */
+ } else if(send_status <-1) { /* Send error */
+ return false; /* call deleted */
+ }
+
+ 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) {
+ /* 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((transport == T_UDP) && (retrans_enabled)) {
+ next_retrans = clock_tick + scenario[msg_index] -> retrans_delay;
+ nb_retrans = 0;
+ nb_last_delay = scenario[msg_index]->retrans_delay;
+ }
+ } else {
+ next_retrans = 0;
+ }
+
+#ifdef PCAPPLAY
+ actionResult = executeAction(msg_snd, msg_index);
+#endif
+
+ /* Update scenario statistics */
+ scenario[msg_index] -> 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
+ ) {
+ 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);
+ return true;
+ }
+ recv_timeout = 0;
+ ++scenario[msg_index]->nb_timeout;
+ if (scenario[msg_index]->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",
+ id, msg_index);
+ CStat::instance()->computeStat(CStat::E_CALL_FAILED);
+ CStat::instance()->computeStat(CStat::E_FAILED_TIMEOUT_ON_RECV);
+ if (default_behavior) {
+ return (abortCall());
+ } else {
+ delete_call(id);
+ 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];
+ recv_timeout = 0;
+ if (msg_index < scenario_len) 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) {
+ return (abortCall());
+ } else {
+ delete_call(id);
+ return false;
+ }
+ } else if ((scenario[msg_index]->retrans_delay) || (defl_recv_timeout)) {
+ if (scenario[msg_index]->retrans_delay)
+ // If timeout is specified on message receive, use it
+ recv_timeout = getmilliseconds() + scenario[msg_index]->retrans_delay;
+ else
+ // Else use the default timeout if specified
+ recv_timeout = getmilliseconds() + defl_recv_timeout;
+ 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);
+ }
+ }
+ return true;
+}
+
+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);
+ } else {
+ WARNING_P3("Continuing call on unexpected message for Call-ID '%s': while expecting '%s', received '%s' ",
+ id, scenario[msg_index] -> recv_request, msg);
+ }
+ } 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"
+ "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());
+ } else {
+ // Do not abort call nor send anything in reply if default behavior is disabled
+ return false;
+ }
+}
+
+bool call::abortCall()
+{
+ int res ;
+ int is_inv;
+
+ char * src_send = NULL ;
+ char * src_recv = NULL ;
+
+ if (last_send_msg != NULL) {
+ is_inv = !strncmp(last_send_msg, "INVITE", 6);
+ } else {
+ is_inv = false;
+ }
+ if ((toolMode != MODE_SERVER) && (msg_index > 0)) {
+ if ((call_established == false) && (is_inv)) {
+ src_recv = last_recv_msg ;
+ char L_msg_buffer[SIPP_MAX_MSG_SIZE];
+ L_msg_buffer[0] = '\0';
+ char * L_param = L_msg_buffer;
+
+ // 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));
+
+ } else if (src_recv) {
+ /* Call is not established and the reply is not a 4XX, 5XX */
+ /* And we already received a message. */
+ if (ack_is_pending == true) {
+ char * cseq = NULL;
+
+ /* If an ACK is expected from the other side, send it
+ * 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));
+
+ /* 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));
+ } 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));
+ }
+ } else {
+ /* Call is not established and the reply is not a 4XX, 5XX */
+ /* and we didn't received any message. This is the case when */
+ /* we are aborting after having send an INVITE and not received */
+ /* any answer. */
+ /* Do nothing ! */
+ }
+ } else {
+ /* Call is established */
+ 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);
+ return false;
+}
+
+bool call::rejectCall()
+{
+ CStat::instance()->computeStat(CStat::E_CALL_FAILED);
+ CStat::instance()->computeStat(CStat::E_FAILED_CALL_REJECTED);
+ delete_call(id);
+ return false;
+}
+
+
+#ifdef __3PCC__
+int call::sendCmdMessage(int index)
+{
+ char * dest;
+ char delimitor[2];
+ delimitor[0]=27;
+ delimitor[1]=0;
+
+ /* 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);
+ strcat(dest, delimitor);
+ //WARNING_P1("---SEND_TWIN_CMD---%s---", dest);
+
+ int rc;
+
+ /* 3pcc extended mode */
+ peer_dest = scenario[index]->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);
+ }
+ if(rc < 0) {
+ CStat::instance()->computeStat(CStat::E_CALL_FAILED);
+ CStat::instance()->computeStat(CStat::E_FAILED_CMD_NOT_SENT);
+ delete_call(id);
+ return(-1);
+ }
+
+ return(0);
+ }
+ else
+ return(-1);
+}
+
+int call::sendCmdBuffer(char* cmd)
+{
+ char * dest;
+ char delimitor[2];
+ int rc;
+
+ delimitor[0]=27;
+ delimitor[1]=0;
+
+ dest = cmd ;
+
+ strcat(dest, delimitor);
+
+
+ rc = send(twinSippSocket,
+ dest,
+ strlen(dest),
+ 0);
+ if(rc < 0) {
+ CStat::instance()->computeStat(CStat::E_CALL_FAILED);
+ CStat::instance()->computeStat(CStat::E_FAILED_CMD_NOT_SENT);
+ delete_call(id);
+ return(-1);
+ }
+
+ return(0);
+}
+
+#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;
+ } 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);
+#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__
+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);
+ }
+
+ if (checkInternalCmd(msg) == false) {
+
+ for(search_index = msg_index;
+ search_index < scenario_len;
+ 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();
+ } else {
+ if(extendedTwinSippMode){ // 3pcc extended mode
+ if(check_peer_src(msg, search_index)){
+ found = true;
+ break;
+ } else{
+ WARNING_P1("Unexpected sender for the received peer message \n%s\n", msg);
+ return rejectCall();
+ }
+ }
+ else {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (found) {
+ scenario[search_index]->M_nbCmdRecv ++;
+
+ // variable treatment
+ // Remove \r, \n at the end of a received command
+ // (necessary for transport, to be removed for usage)
+ while ( (msg[strlen(msg)-1] == '\n') &&
+ (msg[strlen(msg)-2] == '\r') ) {
+ 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
+ call::last_action_result = actionResult;
+ if (actionResult == E_AR_STOP_CALL) {
+ return rejectCall();
+ }
+ }
+ } else {
+ return rejectCall();
+ }
+ msg_index = search_index; //update the state machine
+ return(next());
+
+ } else {
+ return (false);
+ }
+}
+
+bool call::checkInternalCmd(char * cmd)
+{
+
+ char * L_ptr1, * L_ptr2, L_backup;
+
+ L_ptr1 = strstr(cmd, "internal-cmd:");
+ if (!L_ptr1) {return (false);}
+ L_ptr1 += 13 ;
+ while((*L_ptr1 == ' ') || (*L_ptr1 == '\t')) { L_ptr1++; }
+ if (!(*L_ptr1)) {return (false);}
+ L_ptr2 = L_ptr1;
+ while((*L_ptr2) &&
+ (*L_ptr2 != ' ') &&
+ (*L_ptr2 != '\t') &&
+ (*L_ptr2 != '\r') &&
+ (*L_ptr2 != '\n')) {
+ L_ptr2 ++;
+ }
+ if(!*L_ptr2) { return (false); }
+ L_backup = *L_ptr2;
+ *L_ptr2 = 0;
+
+ if (strcmp(L_ptr1, "abort_call") == 0) {
+ *L_ptr2 = L_backup;
+ abortCall();
+ CStat::instance()->computeStat(CStat::E_CALL_FAILED);
+ return (true);
+ }
+
+ *L_ptr2 = L_backup;
+ return (false);
+}
+
+bool call::check_peer_src(char * msg, int search_index)
+{
+ char * L_ptr1, * L_ptr2, L_backup ;
+
+ L_ptr1 = strstr(msg, "From:");
+ if (!L_ptr1) {return (false);}
+ L_ptr1 += 5 ;
+ while((*L_ptr1 == ' ') || (*L_ptr1 == '\t')) { L_ptr1++; }
+ if (!(*L_ptr1)) {return (false);}
+ L_ptr2 = L_ptr1;
+ while((*L_ptr2) &&
+ (*L_ptr2 != ' ') &&
+ (*L_ptr2 != '\t') &&
+ (*L_ptr2 != '\r') &&
+ (*L_ptr2 != '\n')) {
+ L_ptr2 ++;
+ }
+ if(!*L_ptr2) { return (false); }
+ L_backup = *L_ptr2;
+ *L_ptr2 = 0;
+ if (strcmp(L_ptr1, scenario[search_index] -> peer_src) == 0) {
+ *L_ptr2 = L_backup;
+ return(true);
+ }
+
+ *L_ptr2 = L_backup;
+ return (false);
+}
+#endif
+
+
+void call::extract_cseq_method (char* method, char* msg)
+{
+ char* cseq ;
+ if (cseq = strstr (msg, "CSeq"))
+ {
+ char * value ;
+ if ( value = strchr (cseq, ':'))
+ {
+ value++;
+ while ( isspace(*value)) value++; // ignore any white spaces after the :
+ while ( !isspace(*value)) value++; // ignore the CSEQ numnber
+ value++;
+ char *end = value;
+ int nbytes = 0;
+ /* A '\r' terminates the line, so we want to catch that too. */
+ while ((*end != '\r') && (*end != '\n')) { end++; nbytes++; }
+ if (nbytes > 0) strncpy (method, value, nbytes);
+ method[nbytes] = '\0';
+ }
+ }
+}
+
+void call::formatNextReqUrl (char* next_req_url)
+{
+
+ /* clean up the next_req_url -- Record routes may have extra gunk
+ that needs to be removed
+ */
+ char* actual_req_url = strchr(next_req_url, '<');
+ if (actual_req_url)
+ {
+ /* using a temporary buffer */
+ char tempBuffer[MAX_HEADER_LEN];
+ strcpy(tempBuffer, actual_req_url + 1);
+ actual_req_url = strrchr(tempBuffer, '>');
+ *actual_req_url = '\0';
+ strcpy(next_req_url, tempBuffer);
+ }
+
+}
+
+void call::computeRouteSetAndRemoteTargetUri (char* rr, char* contact, bool bRequestIncoming)
+{
+ if (0 >=strlen (rr))
+ {
+ //
+ // there are no RR headers. Simply set up the contact as our target uri
+ //
+ if (0 < strlen(contact))
+ {
+ strcpy (next_req_url, contact);
+ }
+
+ formatNextReqUrl(next_req_url);
+
+ return;
+ }
+
+ char actual_rr[MAX_HEADER_LEN];
+ char targetURI[MAX_HEADER_LEN];
+ memset(actual_rr, 0, sizeof(actual_rr));
+
+ bool isFirst = true;
+ bool bCopyContactToRR = false;
+
+ while (1)
+ {
+ char* pointer = NULL;
+ if (bRequestIncoming)
+ {
+ pointer = strchr (rr, ',');
+ }
+ else
+ {
+ pointer = strrchr(rr, ',');
+ }
+
+ if (pointer)
+ {
+ if (!isFirst)
+ {
+ if (strlen(actual_rr) )
+ {
+ strcat(actual_rr, pointer + 1);
+ }
+ else
+ {
+ strcpy(actual_rr, pointer + 1);
+ }
+ strcat(actual_rr, ",");
+ }
+ else
+ {
+ isFirst = false;
+ if (NULL == strstr (pointer, ";lr"))
+ {
+ /* bottom most RR is the next_req_url */
+ strcpy (targetURI, pointer + 1);
+ bCopyContactToRR = true;
+ }
+ else
+ {
+ /* the hop is a loose router. Thus, the target URI should be the
+ * contact
+ */
+ strcpy (targetURI, contact);
+ strcpy(actual_rr, pointer + 1);
+ strcat(actual_rr, ",");
+ }
+ }
+ }
+ else
+ {
+ if (!isFirst)
+ {
+ strcat(actual_rr, rr);
+ }
+ //
+ // this is the *only* RR header that was found
+ //
+ else
+ {
+ if (NULL == strstr (rr, ";lr"))
+ {
+ /* bottom most RR is the next_req_url */
+ strcpy (targetURI, rr);
+ bCopyContactToRR = true;
+ }
+ else
+ {
+ /* the hop is a loose router. Thus, the target URI should be the
+ * contact
+ */
+ strcpy (actual_rr, rr);
+ strcpy (targetURI, contact);
+ }
+ }
+ break;
+ }
+ *pointer = '\0';
+ }
+
+ if (bCopyContactToRR)
+ {
+ if (0 < strlen (actual_rr))
+ {
+ strcat(actual_rr, ",");
+ strcat(actual_rr, contact);
+ }
+ else
+ {
+ strcpy(actual_rr, contact);
+ }
+ }
+
+ if (strlen(actual_rr))
+ {
+ dialog_route_set = (char *)
+ calloc(1, strlen(actual_rr) + 2);
+ sprintf(dialog_route_set, "%s", actual_rr);
+ }
+
+ if (strlen (targetURI))
+ {
+ strcpy (next_req_url, targetURI);
+ formatNextReqUrl (next_req_url);
+ }
+}
+
+bool call::matches_scenario(unsigned int index, int reply_code, char * request, char * responsecseqmethod)
+{
+ 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;
+ }
+
+ return false;
+}
+
+bool call::process_incoming(char * msg)
+{
+ int reply_code;
+ static char request[65];
+ char responsecseqmethod[65];
+ 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);
+
+ /* 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();
+ }
+ responsecseqmethod[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) {
+
+ int status;
+
+ if(lost(recv_retrans_recv_index)) {
+ TRACE_MSG((s, "%s message (retrans) lost (recv).",
+ TRANSPORT_TO_STRING(transport)));
+
+ if(comp_state) { comp_free(&comp_state); }
+ scenario[recv_retrans_recv_index] -> nb_lost++;
+ return true;
+ }
+
+ scenario[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) {
+ return false;
+ }
+
+ return true;
+ }
+
+ if(last_recv_hash == cookie) {
+ /* This one has already been received, but not processed
+ * yet => (has not triggered something yet) so we can discard.
+ *
+ * This case appears when the UAS has send a 200 but not received
+ * a ACK yet. Thus, the UAS retransmit the 200 (invite transaction)
+ * until it receives a ACK. In this case, it nevers sends the 200
+ * from the BYE, until it has reveiced the previous 200. Thus,
+ * the UAC retransmit the BYE, and this BYE is considered as an
+ * unexpected.
+ *
+ * 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++;
+ return true;
+ }
+ }
+
+ /* Is it a response ? */
+ if((msg[0] == 'S') &&
+ (msg[1] == 'I') &&
+ (msg[2] == 'P') &&
+ (msg[3] == '/') &&
+ (msg[4] == '2') &&
+ (msg[5] == '.') &&
+ (msg[6] == '0') ) {
+
+ reply_code = get_reply_code(msg);
+ if(!reply_code) {
+ if (!process_unexpected(msg)) {
+ return false; // Call aborted by unexpected message handling
+ }
+#ifdef PCAPPLAY
+ } else if ((hasMedia == 1) && *(strstr(msg, "\r\n\r\n")+4) != '\0') {
+ /* Get media info if we find something like an SDP */
+ get_remote_media_addr(msg);
+#endif
+ }
+ /* It is a response: update peer_tag */
+ ptr = get_peer_tag(msg);
+ if (ptr) {
+ if(strlen(ptr) > (MAX_HEADER_LEN - 1)) {
+ ERROR("Peer tag too long. Change MAX_HEADER_LEN and recompile sipp");
+ }
+ if(peer_tag) { free(peer_tag); }
+ peer_tag = strdup(ptr);
+ if (!peer_tag) {
+ ERROR("Out of memory allocating peer tag.");
+ }
+ }
+ request[0]=0;
+ // extract the cseq method from the response
+ extract_cseq_method (responsecseqmethod, msg);
+ } else if(ptr = strchr(msg, ' ')) {
+ if((ptr - msg) < 64) {
+ memcpy(request, msg, ptr - msg);
+ request[ptr - msg] = 0;
+ // Check if we received an ACK => call established
+ if (strcmp(request,"ACK")==0) {
+ call_established=true;
+ }
+#ifdef PCAPPLAY
+ /* In case of INVITE or re-INVITE, ACK or PRACK
+ get the media info if needed (= we got a pcap
+ play action) */
+ if ((strncmp(request, "INVITE", 6) == 0)
+ || (strncmp(request, "ACK", 3) == 0)
+ || (strncmp(request, "PRACK", 5) == 0)
+ && (hasMedia == 1))
+ get_remote_media_addr(msg);
+#endif
+
+ reply_code = 0;
+ } else {
+ ERROR_P1("SIP method too long in received message '%s'",
+ msg);
+ }
+ } else {
+ ERROR_P1("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++) {
+ if(!matches_scenario(search_index, reply_code, request, responsecseqmethod)) {
+ if(scenario[search_index] -> optional) {
+ continue;
+ }
+ /* The received message is different for the expected one */
+ break;
+ }
+
+ found = true;
+ /* TODO : this is a little buggy: If a 100 trying from an INVITE
+ * is delayed by the network until the BYE is sent, it may
+ * stop BYE transmission erroneously, if the BYE also expects
+ * a 100 trying. */
+ break;
+ }
+
+ /* Try to find it in the old non-mandatory receptions */
+ if(!found) {
+ bool contig = true;
+ 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) {
+ 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 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
+ }
+ } else {
+ // call aborted by automatic response mode if needed
+ return (automaticResponseMode(L_case, msg));
+ }
+ }
+
+ int test = (!found) ? -1 : scenario[search_index]->test;
+ /* test==0: No branching"
+ * test==-1 branching without testing"
+ * test>0 branching with testing
+ */
+
+ /* Simulate loss of messages */
+ if(lost(search_index)) {
+ TRACE_MSG((s, "%s message lost (recv).",
+ TRANSPORT_TO_STRING(transport)));
+ if(comp_state) { comp_free(&comp_state); }
+ scenario[search_index] -> nb_lost++;
+ return true;
+ }
+
+
+ /* Handle counters and RTDs for this message. */
+ do_bookkeeping(search_index);
+
+ /* Increment the recv counter */
+ scenario[search_index] -> nb_recv++;
+
+ // Action treatment
+ if (found) {
+ //WARNING_P1("---EXECUTE_ACTION_ON_MSG---%s---", msg);
+
+ 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
+ call::last_action_result = actionResult;
+ if (actionResult == E_AR_STOP_CALL) {
+ return rejectCall();
+ }
+ }
+ }
+
+ if (request) { // update [cseq] with received CSeq
+ unsigned long int rcseq = get_cseq_value(msg);
+ if (rcseq > cseq) cseq = rcseq;
+ }
+
+ /* This is an ACK/PRACK or a response, and its index is greater than the
+ * current active retransmission message, so we stop the retrans timer.
+ * True also for CANCEL and BYE that we also want to answer to */
+ if(((reply_code) ||
+ ((!strcmp(request, "ACK")) ||
+ (!strcmp(request, "CANCEL")) || (!strcmp(request, "BYE")) ||
+ (!strcmp(request, "PRACK")))) &&
+ (search_index > last_send_index)) {
+ /*
+ * We should stop any retransmission timers on receipt of a provisional response only for INVITE
+ * transactions. Non INVITE transactions continue to retransmit at T2 until a final response is
+ * received
+ */
+ if ( (0 == reply_code) || // means this is a request.
+ (200 <= reply_code) || // final response
+ ((0 != reply_code) && (0 == strncmp (responsecseqmethod, "INVITE", strlen(responsecseqmethod)))) ) // prov for INVITE
+ {
+ next_retrans = 0;
+ }
+ else
+ {
+ /*
+ * We are here due to a provisional response for non INVITE. Update our next retransmit.
+ */
+ next_retrans = clock_tick + DEFAULT_T2_TIMER_VALUE;
+ nb_last_delay = DEFAULT_T2_TIMER_VALUE;
+
+ }
+ }
+
+ /* This is a response with 200 so set the flag indicating that an
+ * ACK is pending (used to prevent from release a call with CANCEL
+ * when an ACK+BYE should be sent instead) */
+ if (reply_code == 200) {
+ ack_is_pending = true;
+ }
+
+ /* store the route set only once. TODO: does not support target refreshes!! */
+ if (scenario[search_index] -> bShouldRecordRoutes &&
+ NULL == dialog_route_set ) {
+
+ next_req_url = (char*) calloc(1, MAX_HEADER_LEN);
+
+ char rr[MAX_HEADER_LEN];
+ memset(rr, 0, sizeof(rr));
+ strcpy(rr, get_header_content(msg, (char*)"Record-Route:"));
+
+ // WARNING_P1("rr [%s]", rr);
+ char ch[MAX_HEADER_LEN];
+ strcpy(ch, get_header_content(msg, (char*)"Contact:"));
+
+ /* decorate the contact with '<' and '>' if it does not have it */
+ char* contDecorator = strchr(ch, '<');
+ if (NULL == contDecorator) {
+ char tempBuffer[MAX_HEADER_LEN];
+ sprintf(tempBuffer, "<%s>", ch);
+ strcpy(ch, tempBuffer);
+ }
+
+ /* should cache the route set */
+ if (reply_code) {
+ computeRouteSetAndRemoteTargetUri (rr, ch, false);
+ }
+ else
+ {
+ computeRouteSetAndRemoteTargetUri (rr, ch, true);
+ }
+ // WARNING_P1("next_req_url is [%s]", next_req_url);
+ }
+
+#ifdef _USE_OPENSSL
+ /* store the authentication info */
+ if ((scenario[search_index] -> bShouldAuthenticate) &&
+ (reply_code == 401 || reply_code == 407)) {
+
+ /* is a challenge */
+ char auth[MAX_HEADER_LEN];
+ memset(auth, 0, sizeof(auth));
+ strcpy(auth, get_header_content(msg, (char*)"Proxy-Authenticate:"));
+ if (auth[0] == 0) {
+ strcpy(auth, get_header_content(msg, (char*)"WWW-Authenticate:"));
+ }
+ if (auth[0] == 0) {
+ ERROR("Couldn't find 'Proxy-Authenticate' or 'WWW-Authenticate' in 401 or 407!");
+ }
+
+ dialog_authentication = (char *) calloc(1, 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
+
+ /* Store last received message information for all messages so that we can
+ * correctly identify retransmissions, and use its body for inclusion
+ * in our messages. */
+ last_recv_index = search_index;
+ last_recv_hash = cookie;
+ last_recv_msg = (char *) realloc(last_recv_msg, strlen(msg) + 1);
+ strcpy(last_recv_msg, msg);
+
+ /* 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()))
+ ) {
+ msg_index = search_index;
+ return next();
+ } else {
+ unsigned int timeout = call_wake(this);
+ 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);
+ }
+
+ /* 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;
+ if (candidate == 0) {
+ if (defl_recv_timeout == 0) {
+ continue;
+ }
+ candidate = defl_recv_timeout;
+ }
+ if (!timeout || (clock_tick + candidate < timeout)) {
+ timeout = clock_tick + candidate;
+ }
+ }
+
+ if (!remove_running_call(this)) {
+ ERROR("Tried to remove a running call that wasn't running!\n");
+ }
+ paused_calls.add_paused_call(this, true);
+ }
+ return true;
+}
+
+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;
+ // looking for action to do on this message
+ if(actions != NULL) {
+ for(int i=0; i<actions->getUsedAction(); 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
+ } else /* end action == E_AT_ASSIGN_FROM_REGEXP */
+ if (currentAction->getActionType() == CAction::E_AT_LOG_TO_FILE) {
+ 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) {
+
+ if (currentAction->getCmdLine()) {
+ char* x = createSendingMessage(currentAction->getCmdLine(), -2 /* do not add crlf*/);
+ // TRACE_MSG((s, "Trying to execute [%s]", x));
+ pid_t l_pid;
+ switch(l_pid = fork())
+ {
+ case -1:
+ // error when forking !
+ ERROR("Forking error");
+ break;
+
+ case 0:
+ // first child process - execute the command
+ if((l_pid = fork()) < 0) {
+ ERROR("Forking error");
+ } else {
+ if( l_pid == 0)
+ system(x); // second child runs
+ exit(EXIT_OTHER);
+ }
+ break;
+ default:
+ // parent process continue
+ // reap first child immediately
+ if(waitpid(l_pid, NULL, 0) != l_pid) {
+ ERROR("waitpid error");
+ }
+ break;
+ }
+ }
+ } else /* end action == E_AT_LOG_TO_FILE */
+ if (currentAction->getActionType() == CAction::E_AT_EXEC_INTCMD) {
+ switch (currentAction->getIntCmd())
+ {
+ case CAction::E_INTCMD_STOP_ALL:
+ quitting = 1;
+ break;
+ case CAction::E_INTCMD_STOP_NOW:
+ screen_exit(EXIT_TEST_RES_INTERNAL);
+ break;
+ case CAction::E_INTCMD_STOPCALL:
+ default:
+ return(call::E_AR_STOP_CALL);
+ break;
+ }
+#ifdef PCAPPLAY
+ } else if ((currentAction->getActionType() == CAction::E_AT_PLAY_PCAP_AUDIO) ||
+ (currentAction->getActionType() == CAction::E_AT_PLAY_PCAP_VIDEO)) {
+ play_args_t *play_args;
+ if (currentAction->getActionType() == CAction::E_AT_PLAY_PCAP_AUDIO) {
+ play_args = &(this->play_args_a);
+ } else if (currentAction->getActionType() == CAction::E_AT_PLAY_PCAP_VIDEO) {
+ play_args = &(this->play_args_v);
+ }
+ play_args->pcap = currentAction->getPcapPkts();
+ /* port number is set in [auto_]media_port interpolation */
+ if (media_ip_is_ipv6) {
+ struct sockaddr_in6 *from = (struct sockaddr_in6 *)(void *) &(play_args->from);
+ from->sin6_family = AF_INET6;
+ inet_pton(AF_INET6, media_ip, &(from->sin6_addr));
+ }
+ else {
+ struct sockaddr_in *from = (struct sockaddr_in *)(void *) &(play_args->from);
+ from->sin_family = AF_INET;
+ from->sin_addr.s_addr = inet_addr(media_ip);
+ }
+ /* Create a thread to send RTP packets */
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+#ifndef PTHREAD_STACK_MIN
+#define PTHREAD_STACK_MIN 16384
+#endif
+ //pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN);
+ pthread_attr_setdetachstate(&attr,
+ PTHREAD_CREATE_DETACHED);
+ int ret = pthread_create(&media_thread, &attr, send_wrapper,
+ (void *) play_args);
+ if(ret)
+ ERROR("Can create thread to send RTP packets");
+ pthread_attr_destroy(&attr);
+#endif
+ } else {// end action == E_AT_EXECUTE_CMD
+ ERROR("call::executeAction unknown action");
+ }
+ } // end if current action != null
+ } // end for
+ }
+ return(call::E_AR_NO_ERROR);
+}
+
+void call::extractSubMessage(char * msg, char * matchingString, char* result, bool case_indep, int occurrence, bool headers) {
+
+ char *ptr, *ptr1;
+ int sizeOf;
+ int i = 0;
+ int len = strlen(matchingString);
+ char mat1 = tolower(*matchingString);
+ char mat2 = toupper(*matchingString);
+
+ ptr = msg;
+ while (*ptr) {
+ if (!case_indep) {
+ ptr = strstr(ptr, matchingString);
+ if (ptr == NULL) break;
+ if (headers == true && ptr != msg && *(ptr-1) != '\n') {
+ ++ptr;
+ continue;
+ }
+ } else {
+ if (headers) {
+ if (ptr != msg) {
+ ptr = strchr(ptr, '\n');
+ if (ptr == NULL) break;
+ ++ptr;
+ if (*ptr == 0) break;
+ }
+ } else {
+ ptr1 = strchr(ptr, mat1);
+ ptr = strchr(ptr, mat2);
+ if (ptr == NULL) {
+ if (ptr1 == NULL) break;
+ ptr = ptr1;
+ } else {
+ if (ptr1 != NULL && ptr1 < ptr) ptr = ptr1;
+ }
+ }
+ if (strncasecmp(ptr, matchingString, len) != 0) {
+ ++ptr;
+ continue;
+ }
+ }
+ // here with ptr pointing to a matching string
+ if (occurrence <= 1) break;
+ --occurrence;
+ ++ptr;
+ }
+
+ if(ptr != NULL && *ptr != 0) {
+ strncpy(result, ptr+len, MAX_SUB_MESSAGE_LENGTH);
+ sizeOf = strlen(result);
+ if(sizeOf >= MAX_SUB_MESSAGE_LENGTH)
+ sizeOf = MAX_SUB_MESSAGE_LENGTH-1;
+ while((i<sizeOf) && (result[i] != '\n') && (result[i] != '\r'))
+ i++;
+ result[i] = '\0';
+ } else {
+ result[0] = '\0';
+ }
+}
+
+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 ;
+
+ if (strcmp(P_recv, "BYE")==0) {
+ L_res = 1 ;
+ } else if (strcmp(P_recv, "CANCEL") == 0) {
+ L_res = 2 ;
+ } else if (strcmp(P_recv, "PING") == 0) {
+ L_res = 3 ;
+ } 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)
+{
+
+ int res ;
+ char * old_last_recv_msg = NULL;
+ bool last_recv_msg_saved = false;
+
+ switch (P_case) {
+ case 1: // 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__
+ // 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 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);
+ }
+ break ;
+
+ case 3: // 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)) ;
+ // 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__ */
+
+ CStat::instance()->computeStat(CStat::E_AUTO_ANSWERED);
+ delete_call(id);
+ } else {
+ WARNING_P1("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
+ // store previous last msg if msg is INFO, UPDATE or NOTIFY
+ // restore last_recv_msg to previous one
+ // after sending ok
+ old_last_recv_msg = NULL;
+ if (last_recv_msg != NULL) {
+ last_recv_msg_saved = true;
+ old_last_recv_msg = (char *) malloc(strlen(last_recv_msg)+1);
+ strcpy(old_last_recv_msg,last_recv_msg);
+ }
+ // usage of last_ keywords
+ 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)) ;
+
+ // restore previous last msg
+ if (last_recv_msg_saved == true) {
+ last_recv_msg = (char *) realloc(last_recv_msg, strlen(old_last_recv_msg) + 1);
+ strcpy(last_recv_msg, old_last_recv_msg);
+ if (old_last_recv_msg != NULL) {
+ free(old_last_recv_msg);
+ old_last_recv_msg = NULL;
+ }
+ }
+ CStat::instance()->computeStat(CStat::E_AUTO_ANSWERED);
+ return true;
+ break;
+
+ default:
+ ERROR_P1("Internal error for automaticResponseMode - mode %d is not implemented!", P_case);
+ break ;
+ }
+
+ return false;
+
+}
+
+#ifdef PCAPPLAY
+void *send_wrapper(void *arg)
+{
+ play_args_t *s = (play_args_t *) arg;
+ //struct sched_param param;
+ //int ret;
+ //param.sched_priority = 10;
+ //ret = pthread_setschedparam(pthread_self(), SCHED_RR, ¶m);
+ //if(ret)
+ // ERROR("Can't set RTP play thread realtime parameters");
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+ pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
+ send_packets(s);
+ pthread_exit(NULL);
+ return NULL;
+}
+#endif
Added: sip-tester/branches/upstream/current/sipp.hpp
URL: http://svn.debian.org/wsvn/pkg-voip/sip-tester/branches/upstream/current/sipp.hpp?rev=6613&op=file
==============================================================================
--- sip-tester/branches/upstream/current/sipp.hpp (added)
+++ sip-tester/branches/upstream/current/sipp.hpp Sun Jan 4 00:34:05 2009
@@ -1,0 +1,491 @@
+/*
+
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Author : Richard GAYRAUD - 04 Nov 2003
+ * From Hewlett Packard Company.
+ */
+
+#ifndef __SIPP__
+#define __SIPP__
+
+/* Std C includes */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <sys/time.h>
+#include <sys/poll.h>
+#include <sys/resource.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <signal.h>
+#include <time.h>
+#include <vector>
+#include <string>
+#include <map>
+#include <math.h>
+
+#if defined(__HPUX) || defined(__SUNOS)
+#include <alloca.h>
+#endif
+
+/* Sipp includes */
+
+#include "xp_parser.h"
+#include "scenario.hpp"
+#include "screen.hpp"
+#include "call.hpp"
+#include "comp.h"
+#include "stat.hpp"
+#include "actions.hpp"
+#include "variables.hpp"
+/* Open SSL stuff */
+#ifdef _USE_OPENSSL
+#include "sslcommon.h"
+#endif
+
+
+#ifndef __CYGWIN
+#ifndef FD_SETSIZE
+#define FD_SETSIZE 65000
+#endif
+#else
+#ifndef FD_SETSIZE
+#define FD_SETSIZE 1024
+#endif
+#endif
+
+/*
+ * If this files is included in the Main, then extern definitions
+ * are removed, and the _DEFAULT macro becomes '= value;'. Else
+ * extern definition does not contain default values assignment
+ */
+
+#ifdef GLOBALS_FULL_DEFINITION
+#define extern
+#define _DEFVAL(value) = value
+#else
+#define _DEFVAL(value)
+#endif
+
+/************************** Constants **************************/
+
+#define SIPP_VERSION 20070516
+#define T_UDP 0
+#define T_TCP 1
+#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"))
+
+#define SIPP_MAXFDS 65536
+#define SIPP_MAX_MSG_SIZE 65536
+
+#define MSG_RETRANS_FIRST 0
+#define MSG_RETRANS_RETRANSMISSION 1
+#define MSG_RETRANS_NEVER 2
+
+#define DISPLAY_STAT_SCREEN 1
+#define DISPLAY_REPARTITION_SCREEN 2
+#define DISPLAY_SCENARIO_SCREEN 3
+#define DISPLAY_VARIABLE_SCREEN 4
+#define DISPLAY_TDM_MAP_SCREEN 5
+#define DISPLAY_SECONDARY_REPARTITION_SCREEN 6
+
+#define MAX_RECV_LOOPS_PER_CYCLE 1000
+#define NB_UPDATE_PER_CYCLE 1
+
+#define MAX_PATH 250
+
+#define MAX_PEER_SIZE 4096 /* 3pcc extended mode: max size of peer names */
+#define MAX_LOCAL_TWIN_SOCKETS 10 /*3pcc extended mode:max number of peers from which
+ cmd messages are received */
+
+/******************** Default parameters ***********************/
+
+#define DEFAULT_RATE 10.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
+#define DEFAULT_REPORT_FREQ_DUMP_LOG 60000
+#define DEFAULT_TIMER_RESOLUTION 1
+#define DEFAULT_FREQ_DUMP_RTT 200
+#define DEFAULT_MAX_MULTI_SOCKET 50000
+#define DEFAULT_CTRL_SOCKET_PORT 8888
+
+/************ User controls and command line options ***********/
+
+extern int duration _DEFVAL(0);
+extern double rate _DEFVAL(DEFAULT_RATE);
+extern int rate_increase _DEFVAL(0);
+extern int rate_max _DEFVAL(0);
+extern int users _DEFVAL(0);
+extern int rate_period_ms _DEFVAL(DEFAULT_RATE_PERIOD_MS);
+extern unsigned long defl_recv_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 bool pause_msg_ign _DEFVAL(0);
+extern int auto_answer _DEFVAL(0);
+extern int multisocket _DEFVAL(0);
+extern int compression _DEFVAL(0);
+extern int peripsocket _DEFVAL(0);
+extern int peripfield _DEFVAL(0);
+extern int bind_local _DEFVAL(0);
+extern void * monosocket_comp_state _DEFVAL(0);
+extern char * service _DEFVAL(DEFAULT_SERVICE);
+extern char * auth_password _DEFVAL(DEFAULT_AUTH_PASSWORD);
+extern unsigned long report_freq _DEFVAL(DEFAULT_REPORT_FREQ);
+extern unsigned long report_freq_dumpLog _DEFVAL
+ (DEFAULT_REPORT_FREQ_DUMP_LOG);
+extern char * stat_delimiter _DEFVAL(";");
+
+extern bool timeout_exit _DEFVAL(false);
+
+extern unsigned long report_freq_dumpRtt _DEFVAL
+ (DEFAULT_FREQ_DUMP_RTT);
+
+extern unsigned int max_multi_socket _DEFVAL
+ (DEFAULT_MAX_MULTI_SOCKET);
+
+extern unsigned int timer_resolution _DEFVAL(DEFAULT_TIMER_RESOLUTION);
+extern int max_recv_loops _DEFVAL(MAX_RECV_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 int buff_size _DEFVAL(65535);
+extern int tcp_readsize _DEFVAL(4096);
+#ifdef PCAPPLAY
+extern int hasMedia _DEFVAL(0);
+#endif
+extern bool rtp_echo_enabled _DEFVAL(0);
+extern char media_ip[40];
+extern char media_ip_escaped[42];
+extern int user_media_port _DEFVAL(0);
+extern int media_port _DEFVAL(0);
+extern size_t media_bufsize _DEFVAL(2048);
+extern bool media_ip_is_ipv6;
+extern char remote_ip[40];
+extern char remote_ip_escaped[42];
+extern int remote_port _DEFVAL(DEFAULT_PORT);
+extern unsigned int pid _DEFVAL(0);
+extern int print_all_responses _DEFVAL(0);
+extern unsigned long stop_after _DEFVAL(0xffffffff);
+extern int quitting _DEFVAL(0);
+extern int interrupt _DEFVAL(0);
+extern int paused _DEFVAL(0);
+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;
+extern char * slave_number;
+extern int twinSippPort _DEFVAL(DEFAULT_3PCC_PORT);
+extern bool twinSippMode _DEFVAL(false);
+extern bool extendedTwinSippMode _DEFVAL(false);
+#endif
+
+extern bool backgroundMode _DEFVAL(false);
+extern bool signalDump _DEFVAL(false);
+
+extern bool ctrlEW _DEFVAL(false);
+
+extern int currentScreenToDisplay _DEFVAL
+ (DISPLAY_SCENARIO_SCREEN);
+extern int currentRepartitionToDisplay _DEFVAL(1);
+extern unsigned int base_cseq _DEFVAL(0);
+extern char * auth_uri _DEFVAL(0);
+extern char * call_id_string _DEFVAL("%u-%p@%s");
+extern char **generic[100];
+
+/* TDM map */
+extern bool use_tdmmap _DEFVAL(false);
+extern unsigned int tdm_map_a _DEFVAL(0);
+extern unsigned int tdm_map_b _DEFVAL(0);
+extern unsigned int tdm_map_c _DEFVAL(0);
+extern unsigned int tdm_map_x _DEFVAL(0);
+extern unsigned int tdm_map_y _DEFVAL(0);
+extern unsigned int tdm_map_z _DEFVAL(0);
+extern unsigned int tdm_map_h _DEFVAL(0);
+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) ;
+extern char *tls_key_name _DEFVAL(DEFAULT_TLS_KEY) ;
+extern char *tls_crl_name _DEFVAL(DEFAULT_TLS_CRL) ;
+
+#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);
+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);
+extern unsigned long rtp_bytes _DEFVAL(0);
+extern unsigned long rtp_pckts_pcap _DEFVAL(0);
+extern unsigned long rtp_bytes_pcap _DEFVAL(0);
+extern unsigned long rtp2_pckts _DEFVAL(0);
+extern unsigned long rtp2_bytes _DEFVAL(0);
+extern unsigned long rtp2_pckts_pcap _DEFVAL(0);
+extern unsigned long rtp2_bytes_pcap _DEFVAL(0);
+
+/************* 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);
+extern unsigned int open_calls_allowed _DEFVAL(0);
+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 ***********************/
+
+extern unsigned long clock_tick _DEFVAL(0);
+extern unsigned long scheduling_loops _DEFVAL(0);
+extern unsigned long last_timer_cycle _DEFVAL(0);
+
+#define GET_TIME(clock) \
+{ \
+ struct timezone tzp; \
+ gettimeofday (clock, &tzp); \
+}
+
+/*********************** Global Sockets **********************/
+
+extern int main_socket _DEFVAL(0);
+extern int tcp_multiplex _DEFVAL(0);
+extern int media_socket _DEFVAL(0);
+extern int media_socket_video _DEFVAL(0);
+
+extern struct sockaddr_storage local_sockaddr;
+extern struct sockaddr_storage localTwin_sockaddr;
+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_close _DEFVAL(1);
+extern int reset_sleep _DEFVAL(1000);
+
+extern struct addrinfo * local_addr_storage;
+
+#ifdef __3PCC__
+extern int twinSippSocket _DEFVAL(0);
+extern int localTwinSippSocket _DEFVAL(0);
+extern struct sockaddr_storage twinSipp_sockaddr;
+
+/* 3pcc extended mode */
+typedef struct _T_peer_infos {
+ char peer_host[40];
+ int peer_port;
+ struct sockaddr_storage peer_sockaddr;
+ char peer_ip[40];
+ int 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;
+extern peer_socket_map peer_sockets;
+extern int 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 short use_remote_sending_addr _DEFVAL(0);
+extern struct sockaddr_storage remote_sending_sockaddr;
+
+enum E_Alter_YesNo
+ {
+ E_ALTER_YES=0,
+ E_ALTER_NO
+ };
+
+/************************** Trace Files ***********************/
+
+extern FILE * screenf _DEFVAL(0);
+extern FILE * logfile _DEFVAL(0);
+extern FILE * messagef _DEFVAL(0);
+extern FILE * timeoutf _DEFVAL(0);
+extern bool useMessagef _DEFVAL(0);
+extern bool useScreenf _DEFVAL(0);
+extern bool useLogf _DEFVAL(0);
+extern bool useTimeoutf _DEFVAL(0);
+extern bool dumpInFile _DEFVAL(0);
+extern bool dumpInRtt _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); \
+ } \
+}
+
+/********************* Mini-Parser Routines *******************/
+
+int get_method(char *msg);
+char * get_peer_tag(char *msg);
+unsigned long int get_cseq_value(char *msg);
+unsigned long get_reply_code(char *msg);
+
+/********************** 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);
+
+#if defined (__hpux) || defined (__alpha) && !defined (__FreeBSD__)
+#define sipp_socklen_t int
+#else
+#define sipp_socklen_t socklen_t
+#endif
+
+#define SOCK_ADDR_SIZE(a) \
+ (((a)->ss_family == AF_INET) ? sizeof(struct sockaddr_in) \
+ : sizeof(struct sockaddr_in6))
+
+#if defined(__cplusplus) && defined (__hpux)
+#define _RCAST(type, val) (reinterpret_cast<type> (val))
+#else
+#define _RCAST(type, val) ((type)(val))
+#endif
+
+/********************* Utilities functions *******************/
+
+char *strcasestr2 ( char *__haystack, char *__needle);
+char *get_peer_addr(char *);
+int get_decimal_from_hex(char hex);
+
+int reset_connections() ;
+int close_calls();
+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 *);
+void connect_to_all_peers ();
+void connect_local_twin_socket(char *);
+void close_peer_sockets();
+void close_local_sockets();
+void free_peer_addr_map();
+
+/********************* Reset global kludge *******************/
+
+#ifdef GLOBALS_FULL_DEFINITION
+#undef extern
+#endif
+
+#endif // __SIPP__
More information about the Pkg-voip-commits
mailing list