[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 (&currentTime);
+  TRACE_MSG((s, "----------------------------------------------- %s\n"
+             "%s message sent:\n\n%s\n",
+             CStat::instance()->formatTime(&currentTime),
+             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, &param);
+  //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