[Pkg-voip-commits] r6624 - in /sip-tester/trunk: Makefile call.cpp debian/changelog debian/watch sipp.hpp

msp at alioth.debian.org msp at alioth.debian.org
Sun Jan 4 03:39:23 UTC 2009


Author: msp
Date: Sun Jan  4 03:39:23 2009
New Revision: 6624

URL: http://svn.debian.org/wsvn/pkg-voip/?sc=1&rev=6624
Log:
* (NOT RELEASED YET) New upstream release
* Update debian/watch

Modified:
    sip-tester/trunk/Makefile
    sip-tester/trunk/call.cpp
    sip-tester/trunk/debian/changelog
    sip-tester/trunk/debian/watch
    sip-tester/trunk/sipp.hpp

Modified: sip-tester/trunk/Makefile
URL: http://svn.debian.org/wsvn/pkg-voip/sip-tester/trunk/Makefile?rev=6624&op=diff
==============================================================================
--- sip-tester/trunk/Makefile (original)
+++ sip-tester/trunk/Makefile Sun Jan  4 03:39:23 2009
@@ -19,13 +19,15 @@
 #
 
 -include local.mk
+SVN_VERSION=$(shell if test -d .svn ; then svnversion . | sed -e 's/^/svn/;' ;  else echo unknown ; fi)
+VERINFO=-DSVN_VERSION="\"$(SVN_VERSION)\""
 
 # Output binary to be built
 OUTPUT=sipp
 
 # C & C++ object files to be built
-OBJ= xp_parser.o scenario.o screen.o call.o comp.o sipp.o stat.o \
-     actions.o variables.o
+OBJ= xp_parser.o message.o scenario.o screen.o call.o comp.o sipp.o stat.o \
+     actions.o variables.o infile.o deadcall.o task.o socketowner.o listener.o
 
 # Libraries directories
 LIBDIR_linux=
@@ -63,7 +65,7 @@
 
 # C compiler
 CC_hpux=aCC
-CC_linux=cc  
+CC_linux=gcc  
 CC_freebsd=cc  
 CC_tru64=cc  
 CC_SunOS=gcc
@@ -73,7 +75,7 @@
 
 # C++ compiler mapping
 CPP_hpux=aCC  
-CPP_linux=gcc  
+CPP_linux=g++  
 CPP_freebsd=g++  
 CPP_tru64=cxx  
 CPP_SunOS=g++
@@ -99,20 +101,20 @@
 CFLAGS_linux=-D__LINUX -pthread 
 CFLAGS_freebsd=-D__LINUX -pthread
 CFLAGS_tru64=-D__OSF1 -pthread
-CFLAGS_SunOS=-g -D__SUNOS
+CFLAGS_SunOS=${DEBUG_FLAGS} -D__SUNOS
 CFLAGS_Cygwin=-D__CYGWIN -Dsocklen_t=int
 CFLAGS_Darwin=-D__DARWIN
-CFLAGS=$(CFLAGS_$(SYSTEM)) -D__3PCC__ $(TLS) $(PCAPPLAY) $(EXTRACFLAGS)
+CFLAGS=$(CFLAGS_$(SYSTEM)) $(VERINFO) $(TLS) $(PCAPPLAY) $(EXTRACFLAGS)
 
 #C++ Compiler Flags
-CPPFLAGS_hpux=-AA -mt -D__HPUX +W829 
+CPPFLAGS_hpux=-AA -mt -D__HPUX -D_INCLUDE_LONGLONG -DNOMACROS +W829  
 CPPFLAGS_linux=-D__LINUX -pthread 
 CPPFLAGS_freebsd=-D__LINUX -pthread
 CPPFLAGS_tru64=-D__OSF1 -pthread
-CPPFLAGS_SunOS=-g -D__SUNOS
+CPPFLAGS_SunOS=${DEBUG_FLAGS} -D__SUNOS
 CPPFLAGS_Cygwin=-D__CYGWIN -Dsocklen_t=int
 CPPFLAGS_Darwin=-D__DARWIN
-CPPFLAGS=$(CPPFLAGS_$(SYSTEM)) -D__3PCC__ $(TLS) $(PCAPPLAY) $(EXTRACPPFLAGS)
+CPPFLAGS=$(CPPFLAGS_$(SYSTEM)) $(VERINFO) $(TLS) $(PCAPPLAY) $(EXTRACPPFLAGS)
 
 #Linker mapping
 CCLINK_hpux=aCC
@@ -129,7 +131,7 @@
 LFLAGS_linux=
 LFLAGS_freebsd=
 LFLAGS_tru64=
-LFLAGS_SunOS=
+LFLAGS_SunOS=-mt ${DEBUG_FLAGS}
 LFLAGS_Cygwin=
 LFLAGS_Darwin=
 LFLAGS=$(LFLAGS_$(SYSTEM)) $(EXTRALFLAGS)
@@ -138,15 +140,15 @@
 LIBS_linux= -ldl -lpthread -lncurses -lstdc++ -lm -L /usr/local/lib -L /usr/lib -L /usr/lib64
 LIBS_hpux= -lcurses -lpthread -L /opt/openssl/lib -L /usr/local/lib
 LIBS_tru64= -lcurses -lpthread
-LIBS_freebsd= -lcurses -pthread
-LIBS_SunOS= -lcurses -lpthread -lnsl -lsocket -lstdc++ -lm -ldl -L /usr/local/ssl/lib/
+LIBS_freebsd= -lcurses -pthread -L /usr/local/lib
+LIBS_SunOS= -lcurses -lpthread -lnsl -lsocket -Wl,-Bstatic -lstdc++ -Wl,-Bdynamic -lm -ldl -L /usr/local/ssl/lib/
 LIBS_Cygwin= -lcurses -lpthread -lstdc++ -L /usr/lib/WpdPack/Lib
 LIBS_Darwin= -lcurses
 LIBS=$(LIBS_$(SYSTEM)) $(EXTRALIBS)
 
 # Include directories
-INCDIR_linux=-I. -I/opt/openssl/include
-INCDIR_freebsd=-I. -I/opt/openssl/include
+INCDIR_linux=-I. -I/usr/include/openssl
+INCDIR_freebsd=-I. -I/usr/local/include
 INCDIR_hpux=-I. -I/usr/local/include -I/opt/openssl/include
 INCDIR_tru64=-I. -I/opt/openssl/include
 INCDIR_SunOS=-I. -I/usr/local/ssl/include/
@@ -169,7 +171,7 @@
 	make OSNAME=`uname|sed -e "s/CYGWIN.*/CYGWIN/"` MODELNAME=`uname -m|sed "s/Power Macintosh/ppc/"` OBJ_PCAPPLAY="send_packets.o prepare_pcap.o" PCAPPLAY_LIBS="-lpcap" PCAPPLAY="-DPCAPPLAY" $(OUTPUT)
 
 pcapplay_ossl:
-	make OSNAME=`uname|sed -e "s/CYGWIN.*/CYGWIN/"` MODELNAME=`uname -m|sed "s/Power Macintosh/ppc/"` OBJ_TLS="auth.o sslinit.o sslthreadsafe.o  milenage.o rijndael.o" TLS_LIBS="-lssl -lcrypto" TLS="-D_USE_OPENSSL -DOPENSSL_NO_KRB5"  OBJ_PCAPPLAY="send_packets.o prepare_pcap.o" PCAPPLAY_LIBS="-lpcap -L`if test -f /usr/lib/libpcap.a; then echo /usr; else echo ./ext; fi;`/lib" PCAPPLAY="-DPCAPPLAY -I`if test -f /usr/lib/libpcap.a; then echo /usr; else echo ./ext; fi;`/include" $(OUTPUT)
+	make OSNAME=`uname|sed -e "s/CYGWIN.*/CYGWIN/"` MODELNAME=`uname -m|sed "s/Power Macintosh/ppc/"` OBJ_TLS="auth.o sslinit.o sslthreadsafe.o  milenage.o rijndael.o" TLS_LIBS="-lssl -lcrypto" TLS="-D_USE_OPENSSL -DOPENSSL_NO_KRB5"  OBJ_PCAPPLAY="send_packets.o prepare_pcap.o" PCAPPLAY_LIBS="-lpcap `if test -f ./ext; then echo -L./ext/lib; fi;`" PCAPPLAY="-DPCAPPLAY `if test -f ./ext; then echo -I./ext/include; fi;`" $(OUTPUT)
 
 pcapplay_hp_li_ia:
 	@_HPUX_LI_FLAG=-D_HPUX_LI ; export _HPUX_LI_FLAG ; make pcapplay
@@ -190,8 +192,8 @@
 debug:
 	DEBUG_FLAGS="-g -pg" ; export DEBUG_FLAGS ; make all
 
-debug_tls:
-	@DEBUG_FLAGS=-g ; export DEBUG_FLAGS ; make tls
+debug_ossl:
+	@DEBUG_FLAGS=-g ; export DEBUG_FLAGS ; make ossl
 
 debug_pcap_cygwin:
 	@DEBUG_FLAGS=-g ; export DEBUG_FLAGS ; make pcapplay_ossl_cygwin
@@ -222,4 +224,3 @@
 
 .c.o:
 	$(CC) $(CFLAGS) $(MFLAGS) $(DEBUG_FLAGS) $(_HPUX_LI_FLAG) $(INCDIR) -c -o $*.o $<
-

Modified: sip-tester/trunk/call.cpp
URL: http://svn.debian.org/wsvn/pkg-voip/sip-tester/trunk/call.cpp?rev=6624&op=diff
==============================================================================
--- sip-tester/trunk/call.cpp (original)
+++ sip-tester/trunk/call.cpp Sun Jan  4 03:39:23 2009
@@ -46,9 +46,8 @@
 #include "send_packets.h"
 #endif
 #include "sipp.hpp"
+#include "deadcall.hpp"
 #include "assert.h"
-
-#define KEYWORD_SIZE 256
 
 #ifdef _USE_OPENSSL
 extern  SSL                 *ssl_list[];
@@ -56,11 +55,7 @@
 extern  SSL_CTX             *sip_trp_ssl_ctx;
 #endif
 
-extern  map<string, int>     map_perip_fd;
-
-call_map calls;
-call_list running_calls;
-timewheel paused_calls;
+extern  map<string, struct sipp_socket *>     map_perip_fd;
 
 #ifdef PCAPPLAY
 /* send_packets pthread wrapper */
@@ -68,14 +63,9 @@
 #endif
 
 /************** Call map and management routines **************/
-call_map * get_calls()
-{
-  return & calls;
-}
-
 static unsigned int next_number = 1;
 
-unsigned int get_tdm_map_number(unsigned int number) {
+unsigned int get_tdm_map_number() {
   unsigned int nb = 0;
   unsigned int i=0;
   unsigned int interval=0;
@@ -100,73 +90,205 @@
   } 
 }
 
-call * add_call(char * call_id, bool ipv6)
-{
-  call * new_call;
-  unsigned int nb;
-
-  if(!next_number) { next_number ++; }
-
-  if (use_tdmmap) {
-    nb = get_tdm_map_number(next_number);
-    if (nb != 0) {
-      /* Mark the entry in the list as busy */
-      tdm_map[nb - 1] = true;
+/* When should this call wake up? */
+unsigned int call::wake() {
+  unsigned int wake = 0;
+
+  if (zombie) {
+    return wake;
+  }
+
+  if (paused_until) {
+    wake = paused_until;
+  }
+
+  if (next_retrans && (!wake || (next_retrans < wake))) {
+    wake = next_retrans;
+  }
+
+  if (recv_timeout && (!wake || (recv_timeout < wake))) {
+    wake = recv_timeout;
+  }
+
+  return wake;
+}
+
+#ifdef PCAPPLAY
+/******* Media information management *************************/
+/*
+ * Look for "c=IN IP4 " pattern in the message and extract the following value
+ * which should be IP address
+ */
+uint32_t get_remote_ip_media(char *msg)
+{
+    char pattern[] = "c=IN IP4 ";
+    char *begin, *end;
+    char ip[32];
+    begin = strstr(msg, pattern);
+    if (!begin) {
+      /* Can't find what we're looking at -> return no address */
+      return INADDR_NONE;
+    }
+    begin += sizeof("c=IN IP4 ") - 1;
+    end = strstr(begin, "\r\n");
+    if (!end)
+      return INADDR_NONE;
+    memset(ip, 0, 32);
+    strncpy(ip, begin, end - begin);
+    return inet_addr(ip);
+}
+
+/*
+ * Look for "c=IN IP6 " pattern in the message and extract the following value
+ * which should be IPv6 address
+ */
+uint8_t get_remote_ipv6_media(char *msg, struct in6_addr addr)
+{
+    char pattern[] = "c=IN IP6 ";
+    char *begin, *end;
+    char ip[128];
+
+    memset(&addr, 0, sizeof(addr));
+    memset(ip, 0, 128);
+
+    begin = strstr(msg, pattern);
+    if (!begin) {
+      /* Can't find what we're looking at -> return no address */
+      return 0;
+    }
+    begin += sizeof("c=IN IP6 ") - 1;
+    end = strstr(begin, "\r\n");
+    if (!end)
+      return 0;
+    strncpy(ip, begin, end - begin);
+    if (!inet_pton(AF_INET6, ip, &addr)) {
+      return 0;
+    }
+    return 1;
+}
+
+/*
+ * Look for "m=audio " or "m=video " pattern in the message and extract the
+ * following value which should be port number
+ */
+#define PAT_AUDIO 1
+#define PAT_VIDEO 2
+uint16_t get_remote_port_media(char *msg, int pattype)
+{
+    char *pattern;
+    char *begin, *end;
+    char number[6];
+
+    if (pattype == PAT_AUDIO) {
+      pattern = "m=audio ";
+    } else if (pattype == PAT_VIDEO) {
+      pattern = "m=video ";
     } else {
-      /* Can't create the new call */
-      WARNING("Can't create new outgoing call: all tdm_map circuits busy");
-      return NULL;
-    }
-  }
-
-  new_call = new call(call_id, ipv6);
-
-  if(!new_call) {
-    ERROR("Memory Overflow");
-  }
-
-  /* All calls must exist in the map. */
-  calls[std::string(call_id)] = new_call;
-  /* All calls start off in the running state. */
-  add_running_call(new_call);
-
-  new_call -> number = next_number;
-  new_call -> tdm_map_number = nb - 1;
-
-  /* Vital counters update */
-  next_number++;
-  open_calls++;
-
-  /* Statistics update */
-  calls_since_last_rate_change++;
-  total_calls ++;
-
-  if(open_calls > open_calls_peak) { 
-    open_calls_peak = open_calls;
-    open_calls_peak_time = clock_tick / 1000;
-  }
-  return new_call;
-}
-
-#ifdef _USE_OPENSSL
-call * add_call(char * call_id , int P_pollset_indx, bool ipv6)
-{
-  call * new_call = add_call(call_id, ipv6);
-  new_call -> pollset_index = P_pollset_indx;
-  return new_call;
-}
+	ERROR("Internal error: Undefined media pattern %d\n", 3);
+    }
+
+    begin = strstr(msg, pattern);
+    if (!begin) {
+      /* m=audio not found */
+      return 0;
+    }
+    begin += strlen(pattern) - 1;
+    end = strstr(begin, "\r\n");
+    if (!end)
+      ERROR("get_remote_port_media: no CRLF found");
+    memset(number, 0, sizeof(number));
+    strncpy(number, begin, sizeof(number) - 1);
+    return atoi(number);
+}
+
+/*
+ * IPv{4,6} compliant
+ */
+void call::get_remote_media_addr(char *msg) {
+  uint16_t video_port, audio_port;
+  if (media_ip_is_ipv6) {
+  struct in6_addr ip_media;
+    if (get_remote_ipv6_media(msg, ip_media)) {
+      audio_port = get_remote_port_media(msg, PAT_AUDIO);
+      if (audio_port) {
+        /* We have audio in the SDP: set the to_audio addr */
+        (_RCAST(struct sockaddr_in6 *, &(play_args_a.to)))->sin6_flowinfo = 0;
+        (_RCAST(struct sockaddr_in6 *, &(play_args_a.to)))->sin6_scope_id = 0;
+        (_RCAST(struct sockaddr_in6 *, &(play_args_a.to)))->sin6_family = AF_INET6;
+        (_RCAST(struct sockaddr_in6 *, &(play_args_a.to)))->sin6_port = audio_port;
+        (_RCAST(struct sockaddr_in6 *, &(play_args_a.to)))->sin6_addr = ip_media;
+      }
+      video_port = get_remote_port_media(msg, PAT_VIDEO);
+      if (video_port) {
+        /* We have video in the SDP: set the to_video addr */
+        (_RCAST(struct sockaddr_in6 *, &(play_args_v.to)))->sin6_flowinfo = 0;
+        (_RCAST(struct sockaddr_in6 *, &(play_args_v.to)))->sin6_scope_id = 0;
+        (_RCAST(struct sockaddr_in6 *, &(play_args_v.to)))->sin6_family = AF_INET6;
+        (_RCAST(struct sockaddr_in6 *, &(play_args_v.to)))->sin6_port = video_port;
+        (_RCAST(struct sockaddr_in6 *, &(play_args_v.to)))->sin6_addr = ip_media;
+      }
+      hasMediaInformation = 1;
+    }
+  }
+  else {
+    uint32_t ip_media;
+    ip_media = get_remote_ip_media(msg);
+    if (ip_media != INADDR_NONE) {
+      audio_port = get_remote_port_media(msg, PAT_AUDIO);
+      if (audio_port) {
+        /* We have audio in the SDP: set the to_audio addr */
+        (_RCAST(struct sockaddr_in *, &(play_args_a.to)))->sin_family = AF_INET;
+        (_RCAST(struct sockaddr_in *, &(play_args_a.to)))->sin_port = audio_port;
+        (_RCAST(struct sockaddr_in *, &(play_args_a.to)))->sin_addr.s_addr = ip_media;
+      }
+      video_port = get_remote_port_media(msg, PAT_VIDEO);
+      if (video_port) {
+        /* We have video in the SDP: set the to_video addr */
+        (_RCAST(struct sockaddr_in *, &(play_args_v.to)))->sin_family = AF_INET;
+        (_RCAST(struct sockaddr_in *, &(play_args_v.to)))->sin_port = video_port;
+        (_RCAST(struct sockaddr_in *, &(play_args_v.to)))->sin_addr.s_addr = ip_media;
+      }
+      hasMediaInformation = 1;
+    }
+  }
+}
+
 #endif
 
-
-call * add_call(bool ipv6)
+/******* Very simple hash for retransmission detection  *******/
+
+unsigned long hash(char * msg) {
+  unsigned long hash = 0;
+  int c;
+
+  while (c = *msg++)
+    hash = c + (hash << 6) + (hash << 16) - hash;
+
+  return hash;
+}
+
+/******************* Call class implementation ****************/
+call::call(char *p_id, bool use_ipv6, int userId, struct sockaddr_storage *dest) : listener(p_id, true) {
+  init(main_scenario, NULL, dest, p_id, userId, use_ipv6, false);
+}
+
+call::call(char *p_id, struct sipp_socket *socket, struct sockaddr_storage *dest) : listener(p_id, true) {
+  init(main_scenario, socket, dest, p_id, 0 /* No User. */, socket->ss_ipv6, false /* Not Auto. */);
+}
+
+call::call(scenario * call_scenario, struct sipp_socket *socket, struct sockaddr_storage *dest, char * p_id, int userId, bool ipv6, bool isAutomatic) : listener(p_id, true) {
+  init(call_scenario, socket, dest, p_id, userId, ipv6, isAutomatic);
+}
+
+call *call::add_call(int userId, bool ipv6, struct sockaddr_storage *dest)
 {
   static char call_id[MAX_HEADER_LEN];
-  
+
   char * src = call_id_string;
   int count = 0;
-  
+
   if(!next_number) { next_number ++; }
-  
+
   while (*src && count < MAX_HEADER_LEN-1) {
       if (*src == '%') {
           ++src;
@@ -190,429 +312,112 @@
   }
   call_id[count] = 0;
 
-  return add_call(call_id, ipv6);
-}
-
-call * get_call(char * call_id)
-{
-
-  call * call_ptr;
-
-  call_map::iterator call_it ;
-  call_it = calls.find(call_map::key_type(call_id));
-  call_ptr = (call_it != calls.end()) ? call_it->second : NULL ;
-
-  return call_ptr;
-}
-
-void delete_call(char * call_id)
-{
-  call * call_ptr;
-  call_map::iterator call_it ;
-  call_it = calls.find(call_map::key_type(call_id));
-  call_ptr = (call_it != calls.end()) ? call_it->second : NULL ;
-
-  if(call_ptr) {
-    if (use_tdmmap)
-      tdm_map[call_ptr->tdm_map_number] = false;
-    calls.erase(call_it);
-
-    if (call_ptr->running) {
-      remove_running_call(call_ptr);
-    } else {
-      paused_calls.remove_paused_call(call_ptr);
-    }
-
-    delete call_ptr;
-    open_calls--;
-  } else {
-    if (start_calls == 0) {
-      ERROR("Call not found");
-    }
-  }
-}
-
-void delete_calls(void)
-{
-  call * call_ptr;
-  
-  call_map::iterator call_it ;
-  call_it = calls.begin();
-  while (call_it != calls.end()) {
-    call_ptr = (call_it != calls.end()) ? call_it->second : NULL ;
-    WARNING_P1("Aborting call with Call-Id '%s'", call_ptr->id);
-    call_ptr->abortCall();
-    call_it = calls.begin();
-  }
-
-}
-
-/* Routines for running calls. */
-
-/* Get the overall list of running calls. */
-call_list * get_running_calls()
-{
-  return & running_calls;
-}
-
-/* Put this call in the run queue. */
-void add_running_call(call *call) {
-  call->runit = running_calls.insert(running_calls.end(), call);
-  call->running = true;
-}
-
-/* Remove this call from the run queue. */
-bool remove_running_call(call *call) {
-  if (!call->running) {
-    return false;
-    }
-  running_calls.erase(call->runit);
-  call->running = false;
-  return true;
-}
-
-/* When should this call wake up? */
-unsigned int call_wake(call *call) {
-  unsigned int wake = 0;
-
-  if (call->paused_until) {
-    wake = call->paused_until;
-  }
-
-  if (call->next_retrans && (!wake || (call->next_retrans < wake))) {
-    wake = call->next_retrans;
-  }
-
-  if (call->recv_timeout && (!wake || (call->recv_timeout < wake))) {
-    wake = call->recv_timeout;
-  }
-
-  return wake;
-}
-
-call_list *timewheel::call2list(call *call) {
-  unsigned int wake = call_wake(call);
-  unsigned int wake_sigbits = wake;
-  unsigned int base_sigbits = wheel_base;
-
-  if (wake == 0) {
-    return &forever_list;
-  }
-
-  wake_sigbits /= LEVEL_ONE_SLOTS;
-  base_sigbits /= LEVEL_ONE_SLOTS;
-  if (wake_sigbits == base_sigbits) {
-    return &wheel_one[wake % LEVEL_ONE_SLOTS];
-  }
-  wake_sigbits /= LEVEL_TWO_SLOTS;
-  base_sigbits /= LEVEL_TWO_SLOTS;
-  if (wake_sigbits == base_sigbits) {
-    return &wheel_two[(wake / LEVEL_ONE_SLOTS) % LEVEL_TWO_SLOTS];
-  }
-  assert(wake_sigbits < LEVEL_THREE_SLOTS);
-  return &wheel_three[wake_sigbits];
-}
-
-int expire_paused_calls() {
-  return paused_calls.expire_paused_calls();
-}
-int paused_calls_count() {
-  return paused_calls.size();
-}
-void remove_paused_call(call *call) {
-  assert(!call->running);
-  paused_calls.remove_paused_call(call);
-}
-
-/* Iterate through our sorted set of paused calls, removing those that
- * should no longer be paused, and adding them to the run queue. */
-int timewheel::expire_paused_calls() {
-  int found = 0;
-
-  while (wheel_base < clock_tick) {
-    int slot1 = wheel_base % LEVEL_ONE_SLOTS;
-
-    /* Migrate calls from slot2 when we hit 0. */
-    if (slot1 == 0) {
-      int slot2 = (wheel_base / LEVEL_ONE_SLOTS) % LEVEL_TWO_SLOTS;
-
-      /* If slot2 is also zero, we must migrate calls from slot3 into slot2. */
-      if (slot2 == 0) {
-	int slot3 = ((wheel_base / LEVEL_ONE_SLOTS) / LEVEL_TWO_SLOTS);
-	assert(slot3 < LEVEL_THREE_SLOTS);
-
-	for (call_list::iterator l3it = wheel_three[slot3].begin();
-	     l3it != wheel_three[slot3].end();
-	     l3it++) {
-	  /* Migrate this call to wheel two. */
-	  add_paused_call(*l3it, false);
-        }
-
-	wheel_three[slot3].clear();
-      }
-
-      for (call_list::iterator l2it = wheel_two[slot2].begin();
-	  l2it != wheel_two[slot2].end();
-	  l2it++) {
-	/* Migrate this call to wheel one. */
-	add_paused_call(*l2it, false);
-      }
-
-      wheel_two[slot2].clear();
-    }
-
-    found += wheel_one[slot1].size();
-    for(call_list::iterator it = wheel_one[slot1].begin();
-	it != wheel_one[slot1].end(); it++) {
-      add_running_call(*it);
-      count--;
-    }
-    wheel_one[slot1].clear();
-
-    wheel_base++;
-  }
-
-  return found;
-}
-
-void timewheel::add_paused_call(call *call, bool increment) {
-  call_list *list = call2list(call);
-  call->pauseit = list->insert(list->end(), call);
-  if (increment) {
-    count++;
-  }
-}
-
-void timewheel::remove_paused_call(call *call) {
-  call_list *list = call2list(call);
-  list->erase(call->pauseit);
-  count--;
-}
-
-timewheel::timewheel() {
-  count = 0;
-  wheel_base = clock_tick;
-}
-
-int timewheel::size() {
-  return count;
-}
-
-#ifdef PCAPPLAY
-/******* Media information management *************************/
-/*
- * Look for "c=IN IP4 " pattern in the message and extract the following value
- * which should be IP address
- */
-uint32_t get_remote_ip_media(char *msg)
-{
-    char pattern[] = "c=IN IP4 ";
-    char *begin, *end;
-    char ip[32];
-    begin = strstr(msg, pattern);
-    if (!begin) {
-      /* Can't find what we're looking at -> return no address */
-      return INADDR_NONE;
-    }
-    begin += sizeof("c=IN IP4 ") - 1;
-    end = strstr(begin, "\r\n");
-    if (!end)
-      return INADDR_NONE;
-    memset(ip, 0, 32);
-    strncpy(ip, begin, end - begin);
-    return inet_addr(ip);
-}
-
-/*
- * Look for "c=IN IP6 " pattern in the message and extract the following value
- * which should be IPv6 address
- */
-uint8_t get_remote_ipv6_media(char *msg, struct in6_addr addr)
-{
-    char pattern[] = "c=IN IP6 ";
-    char *begin, *end;
-    char ip[128];
-
-    memset(&addr, 0, sizeof(addr));
-    memset(ip, 0, 128);
-
-    begin = strstr(msg, pattern);
-    if (!begin) {
-      /* Can't find what we're looking at -> return no address */
-      return 0;
-    }
-    begin += sizeof("c=IN IP6 ") - 1;
-    end = strstr(begin, "\r\n");
-    if (!end)
-      return 0;
-    strncpy(ip, begin, end - begin);
-    if (!inet_pton(AF_INET6, ip, &addr)) {
-      return 0;
-    }
-    return 1;
-}
-
-/*
- * Look for "m=audio " pattern in the message and extract the following value
- * which should be port number
- */
-uint16_t get_remote_audio_port_media(char *msg)
-{
-    char pattern[] = "m=audio ";
-    char *begin, *end;
-    char number[6];
-    begin = strstr(msg, pattern);
-    if (!begin) {
-      /* m=audio not found */
-      return 0;
-    }
-    begin += sizeof("m=audio ") - 1;
-    end = strstr(begin, "\r\n");
-    if (!end)
-      ERROR("get_remote_audio_port_media: no CRLF found");
-    memset(number, 0, sizeof(number));
-    strncpy(number, begin, sizeof(number) - 1);
-    return atoi(number);
-}
-
-/*
- * Look for "m=video " pattern in the message and extract the following value
- * which should be port number
- */
-uint16_t get_remote_video_port_media(char *msg)
-{
-    char pattern[] = "m=video ";
-    char *begin, *end;
-    char number[5];
-    begin = strstr(msg, pattern);
-    if (!begin) {
-      /* m=video not found */
-      return 0;
-    }
-    begin += sizeof("m=video ") - 1;
-    end = strstr(begin, "\r\n");
-    if (!end)
-      ERROR("get_remote_video_port_media: no CRLF found");
-    memset(number, 0, 5);
-    strncpy(number, begin, end - begin);
-    return atoi(number);
-}
-
-/*
- * IPv{4,6} compliant
- */
-void call::get_remote_media_addr(char *msg) {
-  uint16_t video_port, audio_port;
-  if (media_ip_is_ipv6) {
-  struct in6_addr ip_media;
-    if (get_remote_ipv6_media(msg, ip_media)) {
-      audio_port = get_remote_audio_port_media(msg);
-      if (audio_port) {
-        /* We have audio in the SDP: set the to_audio addr */
-        (_RCAST(struct sockaddr_in6 *, &(play_args_a.to)))->sin6_flowinfo = 0;
-        (_RCAST(struct sockaddr_in6 *, &(play_args_a.to)))->sin6_scope_id = 0;
-        (_RCAST(struct sockaddr_in6 *, &(play_args_a.to)))->sin6_family = AF_INET6;
-        (_RCAST(struct sockaddr_in6 *, &(play_args_a.to)))->sin6_port = audio_port;
-        (_RCAST(struct sockaddr_in6 *, &(play_args_a.to)))->sin6_addr = ip_media;
-      }
-      video_port = get_remote_video_port_media(msg);
-      if (video_port) {
-        /* We have video in the SDP: set the to_video addr */
-        (_RCAST(struct sockaddr_in6 *, &(play_args_v.to)))->sin6_flowinfo = 0;
-        (_RCAST(struct sockaddr_in6 *, &(play_args_v.to)))->sin6_scope_id = 0;
-        (_RCAST(struct sockaddr_in6 *, &(play_args_v.to)))->sin6_family = AF_INET6;
-        (_RCAST(struct sockaddr_in6 *, &(play_args_v.to)))->sin6_port = video_port;
-        (_RCAST(struct sockaddr_in6 *, &(play_args_v.to)))->sin6_addr = ip_media;
-      }
-      hasMediaInformation = 1;
-    }
-  }
-  else {
-    uint32_t ip_media;
-    ip_media = get_remote_ip_media(msg);
-    if (ip_media != INADDR_NONE) {
-      audio_port = get_remote_audio_port_media(msg);
-      if (audio_port) {
-        /* We have audio in the SDP: set the to_audio addr */
-        (_RCAST(struct sockaddr_in *, &(play_args_a.to)))->sin_family = AF_INET;
-        (_RCAST(struct sockaddr_in *, &(play_args_a.to)))->sin_port = audio_port;
-        (_RCAST(struct sockaddr_in *, &(play_args_a.to)))->sin_addr.s_addr = ip_media;
-      }
-      video_port = get_remote_video_port_media(msg);
-      if (video_port) {
-        /* We have video in the SDP: set the to_video addr */
-        (_RCAST(struct sockaddr_in *, &(play_args_v.to)))->sin_family = AF_INET;
-        (_RCAST(struct sockaddr_in *, &(play_args_v.to)))->sin_port = video_port;
-        (_RCAST(struct sockaddr_in *, &(play_args_v.to)))->sin_addr.s_addr = ip_media;
-      }
-      hasMediaInformation = 1;
-    }
-  }
-}
-
-#endif
-
-/******* Very simple hash for retransmission detection  *******/
-
-unsigned long hash(char * msg) {
-  unsigned long hash = 0;
-  int c;
-
-  while (c = *msg++)
-    hash = c + (hash << 6) + (hash << 16) - hash;
-
-  return hash;
-}
-
-/******************* Call class implementation ****************/
-
-call::InputFileUsage call::m_usage   = call::InputFileSequentialOrder;
-int                  call::m_counter = 0;
-
-call::call(char * p_id, bool ipv6) : use_ipv6(ipv6)
-{
-  memset(this, 0, sizeof(call));
-  id = strdup(p_id);
+  return new call(main_scenario, NULL, dest, call_id, userId, ipv6, false /* Not Auto. */);
+}
+
+
+void call::init(scenario * call_scenario, struct sipp_socket *socket, struct sockaddr_storage *dest, char * p_id, int userId, bool ipv6, bool isAutomatic)
+{
+  this->call_scenario = call_scenario;
+  zombie = false;
+  msg_index = 0;
+  last_send_index = 0;
+  last_send_msg = NULL;
+
+  last_recv_hash = 0;
+  last_recv_index = -1;
+  last_recv_msg = NULL;
+
+  recv_retrans_hash = 0;
+  recv_retrans_recv_index = -1;
+  recv_retrans_send_index = -1;
+
+  dialog_route_set = NULL;
+  next_req_url = NULL;
+
+  cseq = 0;
+
+  next_retrans = 0;
+  nb_retrans = 0;
+  nb_last_delay = 0;
+
+  paused_until = 0;
+
+  call_port = 0;
+  comp_state = NULL;
+
   start_time = clock_tick;
   call_established=false ;
-  count_in_stats=true ;
   ack_is_pending=false ;
   last_recv_msg = NULL;
   cseq = base_cseq;
   nb_last_delay = 0;
-  tdm_map_number = 0;
+  use_ipv6 = ipv6;
+  queued_msg = NULL;
   
 #ifdef _USE_OPENSSL
+  dialog_authentication = NULL;
+  dialog_challenge_type = 0;
+
   m_ctx_ssl = NULL ;
   m_bio = NULL ;
 #endif
 
-  pollset_index = 0 ;
-  poll_flag_write = false ;
-
-  call_remote_socket = 0;
+#ifdef PCAPPLAY
+  hasMediaInformation = 0;
+#endif
+
+  call_remote_socket = NULL;
+  if (socket) {
+    associate_socket(socket);
+    socket->ss_count++;
+  } else {
+    call_socket = NULL;
+  }
+  if (dest) {
+    memcpy(&call_peer, dest, SOCK_ADDR_SIZE(dest));
+  } else {
+    memset(&call_peer, 0, sizeof(call_peer));
+  }
   
   // initialising the CallVariable with the Scenario variable
-  bool test_var=false;
-  int i,j;
-  for(i=0; i<SCEN_VARIABLE_SIZE; i++) 
-    {
-      for (j=0; j<SCEN_MAX_MESSAGES; j++)
-      {
-      if(scenVariableTable[i][j] != NULL) {
-                test_var=true;
-                break;
-            }
-        }
-      if (test_var) {
-        M_callVariableTable[i] = new CCallVariable();
-        if (M_callVariableTable[i] == NULL) {
-          ERROR ("call variable allocation failed");
-        }
-      } else {
-        M_callVariableTable[i] = NULL;
-      }
-    }
+  int i;
+  VariableTable *userVars = NULL;
+  bool putUserVars = false;
+  if (userId) {
+    int_vt_map::iterator it = userVarMap.find(userId);
+    if (it != userVarMap.end()) {
+      userVars  = it->second;
+    }
+  } else {
+    userVars = new VariableTable(userVariables);
+    /* Creating this table creates a reference to it, but if it is really used,
+     * then the refcount will be increased. */
+    putUserVars = true;
+  }
+  if (call_scenario->allocVars->size > 0) {
+	if (userVars) {
+	  M_callVariableTable = new VariableTable(userVars, call_scenario->allocVars->size);
+	} else {
+	  M_callVariableTable = new VariableTable(userVars, call_scenario->allocVars->size);
+	}
+  } else if (userVars->size > 0) {
+	M_callVariableTable = userVars->getTable();
+  } else if (globalVariables->size > 0) {
+	M_callVariableTable = globalVariables->getTable();
+  } else {
+	M_callVariableTable = NULL;
+  }
+  if (putUserVars) {
+    userVars->putTable();
+  }
+
+  if (call_scenario->maxTxnUsed > 0) {
+    txnID = (char **)malloc(sizeof(char *) * call_scenario->maxTxnUsed);
+    memset(txnID, 0, sizeof(char *) * call_scenario->maxTxnUsed);
+  } else {
+    txnID = NULL;
+  }
 
   // If not updated by a message we use the start time 
   // information to compute rtd information
@@ -624,14 +429,21 @@
   // by default, last action result is NO_ERROR
   last_action_result = call::E_AR_NO_ERROR;
 
-  if (InputFileRandomOrder == m_usage) {
-      m_localLineNumber = rand() % numLinesInFile;
+  this->userId = userId;
+
+  /* For automatic answer calls to an out of call request, we must not */
+  /* increment the input files line numbers to not disturb */
+  /* the input files read mechanism (otherwise some lines risk */
+  /* to be systematically skipped */
+  if (!isAutomatic) {
+    m_lineNumber = new file_line_map();
+    for (file_map::iterator file_it = inFiles.begin();
+	file_it != inFiles.end();
+	file_it++) {
+      (*m_lineNumber)[file_it->first] = file_it->second->nextLine(userId);
+    }
   } else {
-      m_localLineNumber = m_counter++;
-      if (m_counter >= numLinesInFile) {
-          m_counter = 0;
-      }
-
+    m_lineNumber = NULL;
   }
 
 #ifdef PCAPPLAY
@@ -645,72 +457,68 @@
 
   peer_tag = NULL;
   recv_timeout = 0;
+  send_timeout = 0;
+  timewait = false;
+
+  if (!isAutomatic) {
+    /* Not advancing the number is safe, because for automatic calls we do not
+     * assign the identifier,  the only other place it is used is for the auto
+     * media port. */
+    number = next_number++;
+
+    if (use_tdmmap) {
+      tdm_map_number = get_tdm_map_number();
+      if (tdm_map_number == 0) {
+	/* Can't create the new call */
+	WARNING("Can't create new outgoing call: all tdm_map circuits busy");
+	computeStat(CStat::E_CALL_FAILED);
+	computeStat(CStat::E_FAILED_OUTBOUND_CONGESTION);
+	this->zombie = true;
+	return;
+      }
+      /* Mark the entry in the list as busy */
+      tdm_map[tdm_map_number - 1] = true;
+    } else {
+      tdm_map_number = 0;
+    }
+  }
+
+  setRunning();
 }
 
 call::~call()
 {
-  deleted += 1;
+  computeStat(CStat::E_ADD_CALL_DURATION, clock_tick - start_time);
 
   if(comp_state) { comp_free(&comp_state); }
 
-  if(count_in_stats) {
-    CStat::instance()->computeStat(CStat::E_ADD_CALL_DURATION, 
-                                   clock_tick - start_time);
-  }
-
-#ifdef _USE_OPENSSL
-  
-  if ((toolMode == MODE_SERVER)  && (multisocket))  {
-   if (ssl_list[call_socket] != NULL) {
-    if((pollset_index) &&  (pollfiles[pollset_index].fd == call_socket)) {
-      SSL_set_shutdown(ssl_list[call_socket],SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
-      SSL_free(ssl_list[call_socket]);
-      ssl_list[call_socket] = NULL ;
-      pollset_remove(pollset_index);
-      shutdown(call_socket, SHUT_RDWR);
-      close(call_socket);
-     }
-   }
-  }
-
-  if ((toolMode != MODE_SERVER) && (multisocket))  {
-    if(pollset_index ) {
-     if (ssl_list[call_socket] != NULL) {
-      // SSL_shutdown(ssl_list[call_socket]);
-      SSL_set_shutdown(ssl_list[call_socket],SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
-       SSL_free(ssl_list[call_socket]);
-       // BIO_free(m_bio);
-       // m_bio = NULL ;
-       m_ctx_ssl = NULL ;
-      }
-    }
-  }
-#endif
-  
-  if (toolMode != MODE_SERVER)   {
-  // TRACE_MSG((s,"socket close  %d at idx = %d\n", socket_close, pollset_index));
-  if(pollset_index) {
-      if (socket_close) {
-    pollset_remove(pollset_index);
-    shutdown(call_socket, SHUT_RDWR);
-    close(call_socket);
-  }
-    }
-  } else {
-    if (call_remote_socket) {
-      close(call_remote_socket);
-    }
-  }
-
-  /* Deletion of the call variable */ 
-  for(int i=0; i<SCEN_VARIABLE_SIZE; i++) {
-    if(M_callVariableTable[i] != NULL) {
-      delete M_callVariableTable[i] ;
-      M_callVariableTable[i] = NULL;
-    }
-  }
-
-  if(id) { free(id); }
+
+  if (call_remote_socket) {
+    sipp_close_socket(call_remote_socket);
+  }
+
+  /* Deletion of the call variable */
+  if(M_callVariableTable) {
+    M_callVariableTable->putTable();
+  }
+  if (m_lineNumber) {
+    delete m_lineNumber;
+  }
+  if (userId) {
+    if (call_scenario->stats->GetStat(CStat::CPT_C_CurrentCall) >= open_calls_allowed) {
+      retiredUsers.push_front(userId);
+    } else {
+      freeUsers.push_front(userId);
+    }
+  }
+
+  if (txnID) {
+    for (int i = 0; i < call_scenario->maxTxnUsed; i++) {
+      free(txnID[i]);
+    }
+    free(txnID);
+  }
+
   if(last_recv_msg) { free(last_recv_msg); }
   if(last_send_msg) { free(last_send_msg); }
   if(peer_tag) { free(peer_tag); }
@@ -723,56 +531,92 @@
        free(next_req_url);
   }
 
+
 #ifdef _USE_OPENSSL
   if(dialog_authentication) {
        free(dialog_authentication);
   }
 #endif
-  call_established= false ;
-}
- 
-void call::connect_socket_if_needed()
-{
-#ifdef _USE_OPENSSL
-   int err;
-   SSL      *L_ssl_tcp_multiplex=NULL ;
-#endif
-
-  if(call_socket) return;
-  if(!multisocket) return;
+
+  if (use_tdmmap) {
+    tdm_map[tdm_map_number] = false;
+  }
+}
+
+void call::computeStat (CStat::E_Action P_action) {
+  call_scenario->stats->computeStat(P_action);
+}
+
+void call::computeStat (CStat::E_Action P_action, unsigned long P_value) {
+  call_scenario->stats->computeStat(P_action, P_value);
+}
+
+void call::computeStat (CStat::E_Action P_action, unsigned long P_value, int which) {
+  call_scenario->stats->computeStat(P_action, P_value, which);
+}
+
+/* Dump call info to error log. */
+void call::dump() {
+  char s[MAX_HEADER_LEN];
+  sprintf(s, "%s: State %d", id, msg_index);
+  if (next_retrans) {
+    sprintf(s, "%s (next retrans %ld)", s, next_retrans);
+  }
+  if (paused_until) {
+    sprintf(s, "%s (paused until %ld)", s, paused_until);
+  }
+  if (recv_timeout) {
+    sprintf(s, "%s (recv timeout %ld)", s, recv_timeout);
+  }
+  if (send_timeout) {
+    sprintf(s, "%s (send timeout %ld)", s, send_timeout);
+  }
+  WARNING("%s", s);
+}
+
+bool call::connect_socket_if_needed()
+{
+  bool existing;
+
+  if(call_socket) return true;
+  if(!multisocket) return true;
 
   if(transport == T_UDP) {
     struct sockaddr_storage saddr;
-    sipp_socklen_t len;
-    
-    int L_status = 0 ;	   // no new socket
-
-    if(toolMode != MODE_CLIENT) return;
+
+    if(toolMode != MODE_CLIENT)
+      return true;
 
     char peripaddr[256];
     if (!peripsocket) {
-      if ((call_socket = new_socket(use_ipv6, SOCK_DGRAM, &L_status)) == -1) {
-        ERROR_NO("Unable to get a UDP socket");
-       }
-     } else {
-       getIpFieldFromInputFile(peripfield, m_localLineNumber, peripaddr);
-       map<string, int>::iterator i;
-       i = map_perip_fd.find(peripaddr);
-       if (i == map_perip_fd.end()) {
-         // Socket does not exist
-    if ((call_socket = new_socket(use_ipv6, SOCK_DGRAM, &L_status)) == -1) {
-      ERROR_NO("Unable to get a UDP socket");
-         } else {
-           map_perip_fd[peripaddr] = call_socket;
-         }
-       } else {
-         // Socket exists already
-         call_socket = i->second;
-       }
-    }
-    
-
-    if (L_status) {
+      if ((associate_socket(new_sipp_call_socket(use_ipv6, transport, &existing))) == NULL) {
+	ERROR_NO("Unable to get a UDP socket");
+      }
+    } else {
+      char *tmp = peripaddr;
+      getFieldFromInputFile(ip_file, peripfield, NULL, tmp);
+      map<string, struct sipp_socket *>::iterator i;
+      i = map_perip_fd.find(peripaddr);
+      if (i == map_perip_fd.end()) {
+	// Socket does not exist
+	if ((associate_socket(new_sipp_call_socket(use_ipv6, transport, &existing))) == NULL) {
+	  ERROR_NO("Unable to get a UDP socket");
+	} else {
+	  /* Ensure that it stays persistent, because it is recorded in the map. */
+	  call_socket->ss_count++;
+	  map_perip_fd[peripaddr] = call_socket;
+	}
+      } else {
+	// Socket exists already
+	associate_socket(i->second);
+	existing = true;
+	i->second->ss_count++;
+      }
+    }
+    if (existing) {
+	return true;
+    }
+
     memset(&saddr, 0, sizeof(struct sockaddr_storage));
 
     memcpy(&saddr,
@@ -808,119 +652,69 @@
       }
     }
 
-    if(bind(call_socket,
-            (sockaddr *)(void *)&saddr,
-            use_ipv6 ? sizeof(struct sockaddr_in6) :
-                       sizeof(struct sockaddr_in))) {
+    if (sipp_bind_socket(call_socket, &saddr, &call_port)) {
       ERROR_NO("Unable to bind UDP socket");
     }
+  } else { /* TCP or TLS. */
+    struct sockaddr_storage *L_dest = &remote_sockaddr;
+
+    if ((associate_socket(new_sipp_call_socket(use_ipv6, transport, &existing))) == NULL) {
+      ERROR_NO("Unable to get a TCP socket");
+    }
+
+    if (existing) {
+      return true;
     }
     
-    if (use_ipv6) {
-      len = sizeof(struct sockaddr_in6);
-    } else {
-      len = sizeof(struct sockaddr_in);
-    }
-
-    getsockname(call_socket, 
-                (sockaddr *)(void *)&saddr,
-                &len);
-
-    if (use_ipv6) {
-      call_port =
-        ntohs((short)((_RCAST(struct sockaddr_in6 *, &saddr))->sin6_port));
-    } else {
-      call_port
-        = ntohs((short)((_RCAST(struct sockaddr_in *, &saddr))->sin_port));
-    }
-     /* Asks to receive incoming messages */
-    if (L_status) {
-     pollset_index = pollset_add(this, call_socket);
-    }
-
-  } else { /* TCP */
-
-    int L_status = 0 ;	   // no new socket
-    struct sockaddr_storage *L_dest = &remote_sockaddr;
-
-    if ((call_socket = new_socket(use_ipv6, SOCK_STREAM, &L_status)) == -1) {
-      ERROR_NO("Unable to get a TCP socket");
-    }
-    
-    if (L_status) {
-      sipp_customize_socket(call_socket);
-
-      if (use_remote_sending_addr) {
-        L_dest = &remote_sending_sockaddr;
-      }
-
-    if(connect(call_socket,
-                 (struct sockaddr *)(void *)L_dest,
-	        SOCK_ADDR_SIZE(&remote_sockaddr))) {
-      
-      if (reset_number > 0) {
+    sipp_customize_socket(call_socket);
+
+    if (use_remote_sending_addr) {
+      L_dest = &remote_sending_sockaddr;
+    }
+
+    if (sipp_connect_socket(call_socket, L_dest)) {
+      if (reconnect_allowed()) {
         if(errno == EINVAL){
           /* This occurs sometime on HPUX but is not a true INVAL */
           WARNING("Unable to connect a TCP socket, remote peer error");
         } else {
           WARNING("Unable to connect a TCP socket");
         }
-        start_calls = 1;
+	/* This connection failed.  We must be in multisocket mode, because
+         * otherwise we would already have a call_socket.  This call can not
+         * succeed, but does not affect any of our other calls. We do decrement
+	 * the reconnection counter however. */
+	if (reset_number != -1) {
+	  reset_number--;
+	}
+
+	computeStat(CStat::E_CALL_FAILED);
+	computeStat(CStat::E_FAILED_TCP_CONNECT);
+	delete this;
+
+	return false;
       } else {
-      if(errno == EINVAL){
-        /* This occurs sometime on HPUX but is not a true INVAL */
-        ERROR("Unable to connect a TCP socket, remote peer error");
-      } else {
-        ERROR_NO("Unable to connect a TCP socket");
-      }
-      }
-    } else {
-#ifdef _USE_OPENSSL
-     if ( transport == T_TLS ) {
-       m_ctx_ssl = sip_trp_ssl_ctx ;
-       
-       
-      if (!(L_ssl_tcp_multiplex = SSL_new(m_ctx_ssl))){
-            ERROR("Unable to create SSL object : Problem with SSL_new() \n");
-       }
-
-       // if ( (m_bio = BIO_new_socket(call_socket,BIO_NOCLOSE)) == NULL) {
-        
-       if ( (m_bio = BIO_new_socket(call_socket,BIO_CLOSE)) == NULL) {
-             ERROR("Unable to create BIO object:Problem with BIO_new_socket()\n");
-       }
-        
-
-       // SSL_set_fd(L_ssl_tcp_multiplex, call_socket);
-       SSL_set_bio(L_ssl_tcp_multiplex,m_bio,m_bio);
-       // SSL_set_bio(L_ssl_tcp_multiplex,bio,bio);
-
-      if ( (err = SSL_connect(L_ssl_tcp_multiplex)) < 0 ) {
-           ERROR("Error in SSL connection \n");
-  }
-       ssl_list[call_socket] = L_ssl_tcp_multiplex;
-
-  
-     }
-#endif
-
-
-  /* Asks to receive incoming messages */
-  pollset_index = pollset_add(this, call_socket);
-    }
-  }
-  }
-}
-
-bool lost(int index)
+	if(errno == EINVAL){
+	  /* This occurs sometime on HPUX but is not a true INVAL */
+	  ERROR("Unable to connect a TCP socket, remote peer error");
+	} else {
+	  ERROR_NO("Unable to connect a TCP socket");
+	}
+      }
+    }
+  }
+  return true;
+}
+
+bool call::lost(int index)
 {
   static int inited = 0;
   double percent = global_lost;
 
   if(!lose_packets) return false;
 
-  if (scenario[index]->lost >= 0) {
-    percent = scenario[index]->lost;
+  if (call_scenario->messages[index]->lost >= 0) {
+    percent = call_scenario->messages[index]->lost;
   }
 
   if (percent == 0) {
@@ -937,120 +731,77 @@
 
 int call::send_raw(char * msg, int index) 
 {
-  void ** state;
-  int sock;
+  struct sipp_socket *sock;
   int rc;
-#ifdef _USE_OPENSSL
-  SSL *ssl;
-  // extern SSL *ssl_list[];
-#endif
-  if (useMessagef == 1) { 
-  struct timeval currentTime;
-  GET_TIME (&currentTime);
-  TRACE_MSG((s, "----------------------------------------------- %s\n"
-             "%s message sent:\n\n%s\n",
-             CStat::instance()->formatTime(&currentTime),
-             TRANSPORT_TO_STRING(transport),
-             msg));
-  }
-  
+ 
+  if (useShortMessagef == 1) {
+      struct timeval currentTime;
+      GET_TIME (&currentTime);
+      char* cs=get_header_content(msg,"CSeq:");
+      TRACE_SHORTMSG("%s\tS\t%s\tCSeq:%s\t%s\n",
+             CStat::formatTime(&currentTime),id, cs, get_first_line(msg));
+  }  
+ 
   if((index!=-1) && (lost(index))) {
-    TRACE_MSG((s, "%s message voluntary lost (while sending).", TRANSPORT_TO_STRING(transport)));
+    TRACE_MSG("%s message voluntary lost (while sending).", TRANSPORT_TO_STRING(transport));
     
     if(comp_state) { comp_free(&comp_state); }
-    scenario[index] -> nb_lost++;
+    call_scenario->messages[index] -> nb_lost++;
     return 0;
   }
   
-  if(call_socket) {
-    state = &comp_state;
-    sock = call_socket;
-
-    if ((use_remote_sending_addr) && (toolMode == MODE_SERVER)) {
-      if (!call_remote_socket) {
-        struct sockaddr_storage *L_dest = &remote_sending_sockaddr;
-
-        if(transport == T_UDP) {        
-        if((call_remote_socket= socket(use_ipv6 ? AF_INET6 : AF_INET,
-  				         SOCK_DGRAM,
-                            0))== -1) {
-          ERROR_NO("Unable to get a socket for rsa option");
-        }
-	  if(bind(call_remote_socket,
-                  (sockaddr *)(void *)L_dest,
-                  use_ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))) {
-              ERROR_NO("Unable to bind UDP socket for rsa option");
-          }   
-        } else {
-	  if((call_remote_socket= socket(use_ipv6 ? AF_INET6 : AF_INET,
-		  		          SOCK_STREAM,
-					  0))== -1) {
-            ERROR_NO("Unable to get a socket for rsa option");
+  sock = call_socket;
+
+  if ((use_remote_sending_addr) && (toolMode == MODE_SERVER)) {
+    if (!call_remote_socket) {
+      struct sockaddr_storage *L_dest = &remote_sending_sockaddr;
+
+      if((call_remote_socket= new_sipp_socket(use_ipv6, transport)) == NULL) {
+	ERROR_NO("Unable to get a socket for rsa option");
+      }
+
+      sipp_customize_socket(call_remote_socket);
+
+      if(transport != T_UDP) {
+	if (sipp_connect_socket(call_remote_socket, L_dest)) {
+	  if(errno == EINVAL){
+	    /* This occurs sometime on HPUX but is not a true INVAL */
+	    ERROR("Unable to connect a %s socket for rsa option, remote peer error", TRANSPORT_TO_STRING(transport));
+	  } else {
+	    ERROR_NO("Unable to connect a socket for rsa option");
 	  }
-        sipp_customize_socket(call_remote_socket);
-
-        if(connect(call_remote_socket,
-               (struct sockaddr *)(void *)L_dest,
-	        SOCK_ADDR_SIZE(&remote_sockaddr))) {
-          if(errno == EINVAL){
-            /* This occurs sometime on HPUX but is not a true INVAL */
-            ERROR_P1("Unable to connect a %s socket for rsa option, remote peer error", TRANSPORT_TO_STRING(transport));
-          } else {
-            ERROR_NO("Unable to connect a socket for rsa option");
-            }
-          }
-        }
-      }
-      sock=call_remote_socket ;
-    }
-
-#ifdef _USE_OPENSSL
-    ssl  = ssl_list[sock];
-    // ssl  = m_ssl;
-#endif
-  } else {
-    state = &monosocket_comp_state;
-    if(transport == T_UDP) {
-      sock = main_socket;
-    } else {
-      sock = tcp_multiplex;
-#ifdef _USE_OPENSSL
-      ssl = ssl_tcp_multiplex;
-#endif
-    }
-  }
-
-#ifdef _USE_OPENSSL
-  if ( transport == T_TLS ) {
-    rc = send_message_tls(ssl, state, msg);
-  } else {
-#endif
-  rc = send_message(sock, state, msg);
-#ifdef _USE_OPENSSL
-  }
-#endif
-
-  if(rc == -1) return -1;
-
-  if(rc < -1) {
-    CStat::instance()->computeStat(CStat::E_CALL_FAILED);
-    CStat::instance()->computeStat(CStat::E_FAILED_CANNOT_SEND_MSG);
-    delete_call(id);
-  }
-  
+	}
+      }
+    }
+    sock=call_remote_socket ;
+  }
+
+  rc = write_socket(sock, msg, strlen(msg), WS_BUFFER, &call_peer);
+  if(rc == -1 && errno == EWOULDBLOCK) {
+    return -1;
+  }
+
+  if(rc < 0) {
+    computeStat(CStat::E_CALL_FAILED);
+    computeStat(CStat::E_FAILED_CANNOT_SEND_MSG);
+    delete this;
+  }
+
   return rc; /* OK */
 }
 
 /* This method is used to send messages that are not */
 /* part of the XML scenario                          */
-int call::sendBuffer(char * msg) 
-{
-  int rc;
-
+void call::sendBuffer(char * msg)
+{
   /* call send_raw but with a special scenario index */
-  rc=send_raw(msg, -1);
-
-  return rc;
+  if (send_raw(msg, -1) < 0) {
+    if (sendbuffer_warn) {
+      ERROR_NO("Error sending raw message");
+    } else {
+      WARNING_NO("Error sending raw message");
+    }
+  }
 }
 
 
@@ -1107,7 +858,7 @@
   /* Ideally this check should be moved to the XML parser so that it is not
    * along a critical path.  We could also handle lowercasing there. */
   if (len > MAX_HEADER_LEN) {
-    ERROR_P2("call::get_last_header: Header to parse bigger than %d (%zu)", MAX_HEADER_LEN, strlen(name));
+    ERROR("call::get_last_header: Header to parse bigger than %d (%zu)", MAX_HEADER_LEN, strlen(name));
   }
 
   if (name[len - 1] == ':') {
@@ -1132,6 +883,7 @@
   char * src, *dest, *start, *ptr;
   /* Are we searching for a short form header? */
   bool short_form = false;
+  bool first_time = true;
   char src_tmp[MAX_HEADER_LEN + 1];
 
   /* returns empty string in case of error */
@@ -1143,7 +895,7 @@
 
   /* for safety's sake */
   if (NULL == name || NULL == strrchr(name, ':')) {
-    WARNING_P1("Can not searching for header (no colon): %s", name ? name : "(null)");
+    WARNING("Can not searching for header (no colon): %s", name ? name : "(null)");
     return last_header;
   }
 
@@ -1154,12 +906,13 @@
     dest = last_header;
 
     while(src = strcasestr2(src, src_tmp)) {
-      if (content) {
+      if (content || !first_time) {
         /* just want the header's content */
         src += strlen(name) + 1;
       } else {
-	src++;
-      }
+	     src++;
+      }
+      first_time = false;
       ptr = strchr(src, '\n');
 
       /* Multiline headers always begin with a tab or a space
@@ -1174,19 +927,12 @@
       // Add "," when several headers are present
       if (dest != last_header) {
 	/* Remove trailing whitespaces, tabs, and CRs */
-	*(dest--) = 0;
 	while ((dest > last_header) &&
-	    ((*dest == ' ') || (*dest == '\r')|| (*dest == '\t'))) {
-	  *(dest--) = 0;
+	    ((*(dest-1) == ' ') || (*(dest-1) == '\r') || (*(dest-1) == '\n') || (*(dest-1) == '\t'))) {
+	  *(--dest) = 0;
 	}
 
 	dest += sprintf(dest, ",");
-
-	/* We only want to append the contents of the header, not its name for
-	 * the second value. */
-	if (!content) {
-	  src += strlen(name);
-	}
       }
       dest += sprintf(dest, "%s", src);
       if(ptr) { *ptr = '\n'; }
@@ -1260,6 +1006,78 @@
   return start;
 }
 
+char * call::get_first_line(char * message)
+{
+  /* non reentrant. consider accepting char buffer as param */
+  static char last_header[MAX_HEADER_LEN * 10];
+  char * src, *dest;
+
+  /* returns empty string in case of error */
+  memset(last_header, 0, sizeof(last_header));
+
+  if((!message) || (!strlen(message))) {
+    return last_header;
+  }
+
+  src = message;
+  dest = last_header;
+  
+  int i=0;
+  while (*src){
+    if((*src=='\n')||(*src=='\r')){
+      break;
+    }
+    else
+    {
+      last_header[i]=*src;
+    }
+    i++;
+    src++;
+  }
+  
+  return last_header;
+}
+
+/* Return the last request URI from the To header. On any error returns the
+ * empty string.  The caller must free the result. */
+char * call::get_last_request_uri ()
+{
+     char * tmp;
+     char * tmp2;
+     char * last_request_uri;
+     int tmp_len;
+
+     char * last_To = get_last_header("To:");
+     if (!last_To) {
+	return strdup("");
+     }
+
+     tmp = strchr(last_To, '<');
+     if (!tmp) {
+	return strdup("");
+     }
+     tmp++;
+
+     tmp2 = strchr(last_To, '>');
+     if (!tmp2) {
+	return strdup("");
+     }
+
+     tmp_len = strlen(tmp) - strlen(tmp2);
+     if (tmp_len < 0) {
+	return strdup("");
+     }
+
+     if(!(last_request_uri = (char *) malloc(tmp_len+1))) ERROR("Cannot allocate !\n");
+     memset(last_request_uri, 0, sizeof(last_request_uri));
+     if(tmp && (tmp_len > 0)){
+       strncpy(last_request_uri, tmp, tmp_len);
+     }
+     last_request_uri[tmp_len] = '\0';
+     return last_request_uri;
+  
+}
+
 char * call::send_scene(int index, int *send_status)
 {
   static char msg_buffer[SIPP_MAX_MSG_SIZE];
@@ -1270,37 +1088,44 @@
   char *L_ptr2 ;
 
   /* Socket port must be known before string substitution */
-  connect_socket_if_needed();
-  
-  if(scenario[index] -> send_scheme) {
-    char * dest;
-    dest = createSendingMessage(scenario[index] -> send_scheme, index);
-    strcpy(msg_buffer, dest);
-
-    if (dest) {
-      L_ptr1=msg_name ;
-      L_ptr2=msg_buffer ;
-      while ((*L_ptr2 != ' ') && (*L_ptr2 != '\n') && (*L_ptr2 != '\t'))  {
-        *L_ptr1 = *L_ptr2;
-        L_ptr1 ++;
-        L_ptr2 ++;
-      }
-      *L_ptr1 = '\0' ;
-    }
-
-    if (strcmp(msg_name,"ACK") == 0) {
-      call_established = true ;
-      ack_is_pending = false ;
-    }
-
-    if(send_status) {
-      *send_status = 
-        send_raw(msg_buffer, index);
-    } else {
-      send_raw(msg_buffer, index);
-    }
+  if (!connect_socket_if_needed()) {
+    *send_status = -2;
+    return NULL;
+  }
+
+  assert(call_socket);
+
+  if (call_socket->ss_congested) {
+    *send_status = -1;
+    return NULL;
+  }
+
+  assert(call_scenario->messages[index]->send_scheme);
+
+  char * dest;
+  dest = createSendingMessage(call_scenario->messages[index] -> send_scheme, index);
+  strcpy(msg_buffer, dest);
+
+  if (dest) {
+    L_ptr1=msg_name ;
+    L_ptr2=msg_buffer ;
+    while ((*L_ptr2 != ' ') && (*L_ptr2 != '\n') && (*L_ptr2 != '\t'))  {
+      *L_ptr1 = *L_ptr2;
+      L_ptr1 ++;
+      L_ptr2 ++;
+    }
+    *L_ptr1 = '\0' ;
+  }
+
+  if (strcmp(msg_name,"ACK") == 0) {
+    call_established = true ;
+    ack_is_pending = false ;
+  }
+
+  if(send_status) {
+    *send_status = send_raw(msg_buffer, index);
   } else {
-    ERROR("Unsupported 'send' message in scenario");
+    send_raw(msg_buffer, index);
   }
 
   return msg_buffer;
@@ -1308,75 +1133,108 @@
 
 void call::do_bookkeeping(int index) {
   /* If this message increments a counter, do it now. */
-  if(int counter = scenario[index] -> counter) {
-    CStat::instance()->computeStat(CStat::E_ADD_GENERIC_COUNTER, 1, counter - 1);
+  if(int counter = call_scenario->messages[index] -> counter) {
+    computeStat(CStat::E_ADD_GENERIC_COUNTER, 1, counter - 1);
   }
 
   /* If this message can be used to compute RTD, do it now */
-  if(int rtd = scenario[index] -> start_rtd) {
+  if(int rtd = call_scenario->messages[index] -> start_rtd) {
     start_time_rtd[rtd - 1] = getmicroseconds();
   }
 
-  if(int rtd = scenario[index] -> stop_rtd) {
+  if(int rtd = call_scenario->messages[index] -> stop_rtd) {
     if (!rtd_done[rtd - 1]) {
       unsigned long long start = start_time_rtd[rtd - 1];
       unsigned long long end = getmicroseconds();
 
       if(dumpInRtt) {
-	CStat::instance()->computeRtt(start, end, rtd);
-      }
-
-      CStat::instance()->computeStat(CStat::E_ADD_RESPONSE_TIME_DURATION,
+	call_scenario->stats->computeRtt(start, end, rtd);
+      }
+
+      computeStat(CStat::E_ADD_RESPONSE_TIME_DURATION,
 	  (end - start) / 1000, rtd - 1);
 
-      if (!scenario[index] -> repeat_rtd) {
+      if (!call_scenario->messages[index] -> repeat_rtd) {
 	rtd_done[rtd - 1] = true;
       }
     }
   }
 }
 
+void call::tcpClose() {
+  terminate(CStat::E_FAILED_TCP_CLOSED);
+}
+
+bool call::terminate(CStat::E_Action reason) {
+  char reason_str[100];
+
+  stopListening();
+
+  // Call end -> was it successful?
+  if(call::last_action_result != call::E_AR_NO_ERROR) {
+    switch(call::last_action_result) {
+      case call::E_AR_REGEXP_DOESNT_MATCH:
+	computeStat(CStat::E_CALL_FAILED);
+	computeStat(CStat::E_FAILED_REGEXP_DOESNT_MATCH);
+	if (deadcall_wait) {
+	  sprintf(reason_str, "regexp match failure at index %d", msg_index);
+	  new deadcall(id, reason_str);
+	}
+	break;
+      case call::E_AR_HDR_NOT_FOUND:
+	computeStat(CStat::E_CALL_FAILED);
+	computeStat(CStat::E_FAILED_REGEXP_HDR_NOT_FOUND);
+	if (deadcall_wait) {
+	  sprintf(reason_str, "regexp header not found at index %d", msg_index);
+	  new deadcall(id, reason_str);
+	}
+	break;
+      case call::E_AR_NO_ERROR:
+      case call::E_AR_STOP_CALL:
+	/* Do nothing. */
+	break;
+    }
+  } else {
+    if (reason == CStat::E_CALL_SUCCESSFULLY_ENDED || timewait) {
+      computeStat(CStat::E_CALL_SUCCESSFULLY_ENDED);
+      if (deadcall_wait) {
+	new deadcall(id, "successful");
+      }
+    } else {
+      computeStat(CStat::E_CALL_FAILED);
+      if (reason != CStat::E_NO_ACTION) {
+	computeStat(reason);
+      }
+      if (deadcall_wait) {
+	sprintf(reason_str, "failed at index %d", msg_index);
+	new deadcall(id, reason_str);
+      }
+    }
+  }
+  delete this;
+}
+
 bool call::next()
 {
-  int test = scenario[msg_index]->test;
+  int test = call_scenario->messages[msg_index]->test;
   /* What is the next message index? */
   /* Default without branching: use the next message */
   int new_msg_index = msg_index+1;
   /* If branch needed, overwrite this default */
-  if ( scenario[msg_index]->next && 
-       ((test == -1) ||
-        (test < SCEN_VARIABLE_SIZE && M_callVariableTable[test] != NULL && M_callVariableTable[test]->isSet()))
+  if ( (call_scenario->messages[msg_index]->next >= 0) &&
+       ((test == -1) || M_callVariableTable->getVar(test)->isSet())
      ) {
     /* Branching possible, check the probability */
-    int chance = scenario[msg_index]->chance;
+    int chance = call_scenario->messages[msg_index]->chance;
     if ((chance <= 0) || (rand() > chance )) {
       /* Branch == overwrite with the 'next' attribute value */
-      new_msg_index = labelArray[scenario[msg_index]->next];
+      new_msg_index = call_scenario->messages[msg_index]->next;
     }
   }
   msg_index=new_msg_index;
   recv_timeout = 0;
-  if(msg_index >= scenario_len) {
-    // Call end -> was it successful?
-    if(call::last_action_result != call::E_AR_NO_ERROR) {
-      switch(call::last_action_result) {
-        case call::E_AR_REGEXP_DOESNT_MATCH:
-          CStat::instance()->computeStat(CStat::E_CALL_FAILED);
-          CStat::instance()->computeStat(CStat::E_FAILED_REGEXP_DOESNT_MATCH);
-          break;
-        case call::E_AR_HDR_NOT_FOUND:
-          CStat::instance()->computeStat(CStat::E_CALL_FAILED);
-          CStat::instance()->computeStat(CStat::E_FAILED_REGEXP_HDR_NOT_FOUND);
-          break;
-	case call::E_AR_NO_ERROR:
-	case call::E_AR_STOP_CALL:
-	  /* Do nothing. */
-	  break;
-      }
-    } else {
-      CStat::instance()->computeStat(CStat::E_CALL_SUCCESSFULLY_ENDED);
-    }
-    delete_call(id);
+  if(msg_index >= call_scenario->length) {
+    terminate(CStat::E_CALL_SUCCESSFULLY_ENDED);
     return false;
   }
 
@@ -1390,12 +1248,19 @@
 
   assert(running);
 
+  if (zombie) {
+    delete this;
+    return false;
+  }
+
   clock_tick = getmilliseconds();
 
-  if(msg_index >= scenario_len) {
-    ERROR_P3("Scenario overrun for call %s (%p) (index = %d)\n",
+  if(msg_index >= call_scenario->length) {
+    ERROR("Scenario overrun for call %s (%p) (index = %d)\n",
              id, this, msg_index);
   }
+
+  message *curmsg = call_scenario->messages[msg_index];
 
   /* Manages retransmissions or delete if max retrans reached */
   if(next_retrans && (next_retrans < clock_tick)) {
@@ -1408,36 +1273,38 @@
 
     if((nb_retrans > (bInviteTransaction ? max_invite_retrans : max_non_invite_retrans)) ||
        (nb_retrans > max_udp_retrans)) {
-      scenario[last_send_index] -> nb_timeout ++;
-      if (scenario[last_send_index]->on_timeout) {  // action on timeout
-          WARNING_P3("Call-Id: %s, timeout on max UDP retrans for message %d, jumping to label %d ", 
-                      id, msg_index, scenario[last_send_index]->on_timeout);
-          msg_index = labelArray[scenario[last_send_index]->on_timeout];
+      call_scenario->messages[last_send_index] -> nb_timeout ++;
+      if (call_scenario->messages[last_send_index]->on_timeout >= 0) {  // action on timeout
+          WARNING("Call-Id: %s, timeout on max UDP retrans for message %d, jumping to label %d ",
+                      id, msg_index, call_scenario->messages[last_send_index]->on_timeout);
+          msg_index = call_scenario->messages[last_send_index]->on_timeout;
           next_retrans = 0;
           recv_timeout = 0;
-          if (msg_index < scenario_len) return true;
+          if (msg_index < call_scenario->length) {
+		return true;
+	  }
 
           // here if asked to go to the last label  delete the call
-          CStat::instance()->computeStat(CStat::E_CALL_FAILED);
-          CStat::instance()->computeStat(CStat::E_FAILED_MAX_UDP_RETRANS);
-          if (default_behavior) {
+          computeStat(CStat::E_CALL_FAILED);
+          computeStat(CStat::E_FAILED_MAX_UDP_RETRANS);
+          if (default_behaviors & DEFAULT_BEHAVIOR_BYE) {
             // Abort the call by sending proper SIP message
             return(abortCall());
           } else {
             // Just delete existing call
-            delete_call(id);
+            delete this;
             return false;
           }
       }
-      CStat::instance()->computeStat(CStat::E_CALL_FAILED);
-      CStat::instance()->computeStat(CStat::E_FAILED_MAX_UDP_RETRANS);
-      if (default_behavior) {
+      computeStat(CStat::E_CALL_FAILED);
+      computeStat(CStat::E_FAILED_MAX_UDP_RETRANS);
+      if (default_behaviors & DEFAULT_BEHAVIOR_BYE) {
         // Abort the call by sending proper SIP message
-        WARNING_P1("Aborting call on UDP retransmission timeout for Call-ID '%s'", id);
+        WARNING("Aborting call on UDP retransmission timeout for Call-ID '%s'", id);
         return(abortCall());
       } else {
         // Just delete existing call
-        delete_call(id);
+        delete this;
         return false;
       }
     } else {
@@ -1452,8 +1319,8 @@
       if(send_raw(last_send_msg, last_send_index) < -1) {
         return false;
       }
-      scenario[last_send_index] -> nb_sent_retrans++;
-      CStat::instance()->computeStat(CStat::E_RETRANSMISSION);
+      call_scenario->messages[last_send_index] -> nb_sent_retrans++;
+      computeStat(CStat::E_RETRANSMISSION);
       next_retrans = clock_tick + nb_last_delay;
     }
   }
@@ -1461,29 +1328,40 @@
   if(paused_until) {
     /* Process a pending pause instruction until delay expiration */
     if(paused_until > clock_tick) {
-      if (!remove_running_call(this)) {
-	ERROR("Tried to remove a running call that wasn't running!\n");
-      }
-      paused_calls.add_paused_call(this, true);
+      setPaused();
       return true;
     }
     /* Our pause is over. */
     paused_until = 0;
     return next();
-  } else if(scenario[msg_index] -> pause_function) {
+  } else if(curmsg -> pause_distribution || curmsg->pause_variable != -1) {
     unsigned int pause;
-    pause  = scenario[msg_index] -> pause_function(scenario[msg_index]);
+    if (curmsg->pause_distribution) {
+      pause  = (int)(curmsg -> pause_distribution -> sample());
+    } else {
+      int varId = curmsg->pause_variable;
+      pause = (int) M_callVariableTable->getVar(varId)->getDouble();
+    }
+    if (pause < 0) {
+      pause = 0;
+    }
     if (pause > INT_MAX) {
       pause = INT_MAX;
     }
     paused_until = clock_tick + pause;
 
+    /* This state is used as the last message of a scenario, just for handling
+     * final retransmissions. If the connection closes, we do not mark it is
+     * failed. */
+    this->timewait = curmsg->timewait;
+
     /* Increment the number of sessions in pause state */
-    ++scenario[msg_index]->sessions;
+    curmsg->sessions++;
+    do_bookkeeping(msg_index);
+    actionResult = executeAction(NULL, msg_index);
     return run(); /* In case delay is 0 */
-  } 
-#ifdef __3PCC__
-  else if(scenario[msg_index] -> M_type == MSG_TYPE_SENDCMD) {
+  }
+  else if(curmsg -> M_type == MSG_TYPE_SENDCMD) {
     int send_status;
 
     if(next_retrans) {
@@ -1495,18 +1373,20 @@
     if(send_status != 0) { /* Send error */
       return false; /* call deleted */
     }
-    scenario[msg_index] -> M_nbCmdSent++;
+    curmsg -> M_nbCmdSent++;
     next_retrans = 0;
-    return(next());
-  }
-#endif
-  else if(scenario[msg_index] -> M_type == MSG_TYPE_NOP) {
+
     do_bookkeeping(msg_index);
     actionResult = executeAction(NULL, msg_index);
     return(next());
   }
-
-  else if(scenario[msg_index] -> send_scheme) {
+  else if(curmsg -> M_type == MSG_TYPE_NOP) {
+    do_bookkeeping(msg_index);
+    actionResult = executeAction(NULL, msg_index);
+    return(next());
+  }
+
+  else if(curmsg -> send_scheme) {
     char * msg_snd;
     int send_status;
 
@@ -1514,10 +1394,7 @@
      * retransmission enabled is acknowledged */
 
     if(next_retrans) {
-      if (!remove_running_call(this)) {
-	ERROR("Tried to remove a running call that wasn't running!\n");
-      }
-      paused_calls.add_paused_call(this, true);
+      setPaused();
       return true;
     }
 
@@ -1531,175 +1408,324 @@
      */
 
     int incr_cseq = 0;
-    if (strncmp(::scenario[msg_index]->send_scheme,"ACK",3) &&
-       strncmp(::scenario[msg_index]->send_scheme,"CANCEL",6) &&
-       strncmp(::scenario[msg_index]->send_scheme,"SIP/2.0",7)) {
+    if (!curmsg->send_scheme->isAck() &&
+        !curmsg->send_scheme->isCancel() &&
+        !curmsg->send_scheme->isResponse()) {
           ++cseq;
           incr_cseq = 1;
     }
     
-    if ((ctrlEW) || (poll_flag_write)) {
-      send_status = -1;
-    } else {
     msg_snd = send_scene(msg_index, &send_status);
-    }
-
-    if(send_status == -1) { /* Would Block on TCP */
+    if(send_status == -1 && errno == EWOULDBLOCK) {
       if (incr_cseq) --cseq;
+      /* Have we set the timeout yet? */
+      if (send_timeout) {
+	/* If we have actually timed out. */
+	if (clock_tick > send_timeout) {
+	  WARNING("Call-Id: %s, send timeout on message %d: aborting call",
+	      id, msg_index);
+	  computeStat(CStat::E_CALL_FAILED);
+	  computeStat(CStat::E_FAILED_TIMEOUT_ON_SEND);
+	  if (default_behaviors & DEFAULT_BEHAVIOR_BYE) {
+	    return (abortCall());
+	  } else {
+	    delete this;
+	    return false;
+	  }
+	}
+      } else if (curmsg->timeout) {
+	/* Initialize the send timeout to the per message timeout. */
+	send_timeout = clock_tick + curmsg->timeout;
+      } else if (defl_send_timeout) {
+	/* Initialize the send timeout to the global timeout. */
+	send_timeout = clock_tick + defl_send_timeout;
+      }
       return true; /* No step, nothing done, retry later */
-    } else if(send_status <-1) { /* Send error */
-      return false; /* call deleted */
-    }
-    
+    } else if(send_status < 0) { /* Send error */
+      /* The timeout will not be sent, so the timeout is no longer needed. */
+      send_timeout = 0;
+      /* The call was already deleted by connect_socket_if_needed or send_raw. */
+      return false;
+    }
+    /* We have sent the message, so the timeout is no longer needed. */
+    send_timeout = 0;
+
     last_send_index = msg_index;
     last_send_msg = (char *) realloc(last_send_msg, strlen(msg_snd) + 1);
     strcpy(last_send_msg, msg_snd);
 
-    if(last_recv_hash) {
+    if (curmsg->start_txn) {
+      txnID[curmsg->start_txn - 1] = (char *)realloc(txnID[curmsg->start_txn - 1], MAX_HEADER_LEN);
+      extract_transaction(txnID[curmsg->start_txn - 1], last_send_msg);
+    }
+
+    if(last_recv_index >= 0) {
       /* We are sending just after msg reception. There is a great
        * chance that we will be asked to retransmit this message */
       recv_retrans_hash       = last_recv_hash;
       recv_retrans_recv_index = last_recv_index;
       recv_retrans_send_index = msg_index;
-    
+
       /* Prevent from detecting the cause relation between send and recv 
        * in the next valid send */
       last_recv_hash = 0;
     }
 
     /* Update retransmission information */
-    if(scenario[msg_index] -> retrans_delay) {
+    if(curmsg -> retrans_delay) {
       if((transport == T_UDP) && (retrans_enabled)) {
-        next_retrans = clock_tick + scenario[msg_index] -> retrans_delay;
+        next_retrans = clock_tick + curmsg -> retrans_delay;
         nb_retrans = 0;
-        nb_last_delay = scenario[msg_index]->retrans_delay;
+        nb_last_delay = curmsg->retrans_delay;
       }
     } else {
       next_retrans = 0;
     }
-    
-#ifdef PCAPPLAY
+
     actionResult = executeAction(msg_snd, msg_index);
-#endif
-    
+
     /* Update scenario statistics */
-    scenario[msg_index] -> nb_sent++;
+    curmsg -> nb_sent++;
 
     return next();
-  } else if (scenario[msg_index]->M_type == MSG_TYPE_RECV
-#ifdef __3PCC__
-         || scenario[msg_index]->M_type == MSG_TYPE_RECVCMD
-#endif
+  } else if (curmsg->M_type == MSG_TYPE_RECV
+         || curmsg->M_type == MSG_TYPE_RECVCMD
                                                  ) {
-    if (recv_timeout) {
+    if (queued_msg) {
+      char *msg = queued_msg;
+      queued_msg = NULL;
+      bool ret = process_incoming(msg);
+      free(msg);
+      return ret;
+    } else if (recv_timeout) {
       if(recv_timeout > clock_tick || recv_timeout > getmilliseconds()) {
-	if (!remove_running_call(this)) {
-	  ERROR("Tried to remove a running call that wasn't running!\n");
-	}
-	paused_calls.add_paused_call(this, true);
+	setPaused();
 	return true;
       }
       recv_timeout = 0;
-      ++scenario[msg_index]->nb_timeout;
-      if (scenario[msg_index]->on_timeout == 0) {
+      curmsg->nb_timeout++;
+      if (curmsg->on_timeout < 0) {
         // if you set a timeout but not a label, the call is aborted 
-        WARNING_P2("Call-Id: %s, receive timeout on message %d without label to jump to (ontimeout attribute): aborting call", 
+        WARNING("Call-Id: %s, receive timeout on message %d without label to jump to (ontimeout attribute): aborting call",
                    id, msg_index);
-        CStat::instance()->computeStat(CStat::E_CALL_FAILED);
-        CStat::instance()->computeStat(CStat::E_FAILED_TIMEOUT_ON_RECV);
-        if (default_behavior) {
+        computeStat(CStat::E_CALL_FAILED);
+        computeStat(CStat::E_FAILED_TIMEOUT_ON_RECV);
+        if (default_behaviors & DEFAULT_BEHAVIOR_BYE) {
           return (abortCall());
         } else {
-          delete_call(id);
+          delete this;
           return false;
         }
       }
-      WARNING_P3("Call-Id: %s, receive timeout on message %d, jumping to label %d", 
-                  id, msg_index, scenario[msg_index]->on_timeout);
-      msg_index = labelArray[scenario[msg_index]->on_timeout];
+      WARNING("Call-Id: %s, receive timeout on message %d, jumping to label %d",
+                  id, msg_index, curmsg->on_timeout);
+      msg_index = curmsg->on_timeout;
       recv_timeout = 0;
-      if (msg_index < scenario_len) return true;
+      if (msg_index < call_scenario->length) return true;
       // special case - the label points to the end - finish the call
-      CStat::instance()->computeStat(CStat::E_CALL_FAILED);
-      CStat::instance()->computeStat(CStat::E_FAILED_TIMEOUT_ON_RECV);
-      if (default_behavior) {
+      computeStat(CStat::E_CALL_FAILED);
+      computeStat(CStat::E_FAILED_TIMEOUT_ON_RECV);
+      if (default_behaviors & DEFAULT_BEHAVIOR_BYE) {
         return (abortCall());
       } else {
-        delete_call(id);
+        delete this;
         return false;
       }
-    } else if ((scenario[msg_index]->retrans_delay) || (defl_recv_timeout)) {
-      if (scenario[msg_index]->retrans_delay)
+    } else if (curmsg->timeout || defl_recv_timeout) {
+      if (curmsg->timeout)
         // If timeout is specified on message receive, use it
-        recv_timeout = getmilliseconds() + scenario[msg_index]->retrans_delay;
+        recv_timeout = getmilliseconds() + curmsg->timeout;
       else
         // Else use the default timeout if specified
         recv_timeout = getmilliseconds() + defl_recv_timeout;
-      return true;
+	return true;
     } else {
 	/* We are going to wait forever. */
-	if (!remove_running_call(this)) {
-	  ERROR("Tried to remove a running call that wasn't running!\n");
-	}
-	paused_calls.add_paused_call(this, true);
+	setPaused();
     }
   }
   return true;
 }
 
+char *default_message_names[] = {
+	"3pcc_abort",
+	"ack",
+	"ack2",
+	"bye",
+	"cancel",
+	"200",
+};
+char *default_message_strings[] = {
+	/* 3pcc_abort */
+	"call-id: [call_id]\ninternal-cmd: abort_call\n\n",
+	/* ack */
+        "ACK [last_Request_URI] SIP/2.0\n"
+        "[last_Via]\n"
+        "[last_From]\n"
+        "[last_To]\n"
+        "Call-ID: [call_id]\n"
+        "CSeq: [last_cseq_number] ACK\n"
+        "Contact: <sip:sipp@[local_ip]:[local_port];transport=[transport]>\n"
+        "Max-Forwards: 70\n"
+        "Subject: Performance Test\n"
+        "Content-Length: 0\n\n",
+	/* ack2, the only difference is Via, I don't quite know why. */
+        "ACK [last_Request_URI] SIP/2.0\n"
+        "Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n"
+        "[last_From]\n"
+        "[last_To]\n"
+        "Call-ID: [call_id]\n"
+        "CSeq: [last_cseq_number] ACK\n"
+        "Contact: <sip:sipp@[local_ip]:[local_port];transport=[transport]>\n"
+        "Max-Forwards: 70\n"
+        "Subject: Performance Test\n"
+        "Content-Length: 0\n\n",
+	/* bye */
+        "BYE [last_Request_URI] SIP/2.0\n"
+        "Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n"
+        "[last_From]\n"
+        "[last_To]\n"
+        "Call-ID: [call_id]\n"
+        "CSeq: [last_cseq_number+1] BYE\n"
+        "Max-Forwards: 70\n"
+        "Contact: <sip:sipp@[local_ip]:[local_port];transport=[transport]>\n"
+        "Content-Length: 0\n\n",
+	/* cancel */
+        "CANCEL [last_Request_URI] SIP/2.0\n"
+        "[last_Via]\n"
+        "[last_From]\n"
+        "[last_To]\n"
+        "Call-ID: [call_id]\n"
+	"CSeq: [last_cseq_number] CANCEL\n"
+        "Max-Forwards: 70\n"
+        "Contact: <sip:sipp@[local_ip]:[local_port];transport=[transport]>\n"
+        "Content-Length: 0\n\n",
+	/* 200 */
+	"SIP/2.0 200 OK\n"
+	"[last_Via:]\n"
+	"[last_From:]\n"
+	"[last_To:]\n"
+	"[last_Call-ID:]\n"
+	"[last_CSeq:]\n"
+	"Contact: <sip:[local_ip]:[local_port];transport=[transport]>\n"
+	"Content-Length: 0\n\n"
+};
+
+SendingMessage **default_messages;
+
+void init_default_messages() {
+  int messages = sizeof(default_message_strings)/sizeof(default_message_strings[0]);
+  default_messages = new SendingMessage* [messages];
+  for (int i = 0; i < messages; i++) {
+    default_messages[i] = new SendingMessage(main_scenario, default_message_strings[i]);
+  }
+}
+
+void free_default_messages() {
+  int messages = sizeof(default_message_strings)/sizeof(default_message_strings[0]);
+  if (!default_messages) {
+    return;
+  }
+  for (int i = 0; i < messages; i++) {
+    delete default_messages[i];
+  }
+  delete [] default_messages;
+}
+
+SendingMessage *get_default_message(const char *which) {
+  int messages = sizeof(default_message_names)/sizeof(default_message_names[0]);
+  for (int i = 0; i < messages; i++) {
+    if (!strcmp(which, default_message_names[i])) {
+      return default_messages[i];
+    }
+  }
+  ERROR("Internal Error: Unknown default message: %s!", which);
+}
+
+void set_default_message(const char *which, char *msg) {
+  int messages = sizeof(default_message_names)/sizeof(default_message_names[0]);
+  for (int i = 0; i < messages; i++) {
+    if (!strcmp(which, default_message_names[i])) {
+      default_message_strings[i] = msg;
+      return;
+    }
+  }
+  ERROR("Internal Error: Unknown default message: %s!", which);
+}
+
 bool call::process_unexpected(char * msg)
 {
-  scenario[msg_index] -> nb_unexp++;
-  
-  if (scenario[msg_index] -> recv_request) {
-    if (default_behavior) {
-      WARNING_P3("Aborting call on unexpected message for Call-ID '%s': while expecting '%s', received '%s' ",
-                id, scenario[msg_index] -> recv_request, msg);
+  char buffer[MAX_HEADER_LEN];
+  char *desc = buffer;
+
+  message *curmsg = call_scenario->messages[msg_index];
+
+  curmsg->nb_unexp++;
+
+  if (default_behaviors & DEFAULT_BEHAVIOR_ABORTUNEXP) {
+	desc += snprintf(desc, MAX_HEADER_LEN - (desc - buffer), "Aborting ");
   } else {
-      WARNING_P3("Continuing call on unexpected message for Call-ID '%s': while expecting '%s', received '%s' ",
-                  id, scenario[msg_index] -> recv_request, msg);
-    }
+	desc += snprintf(desc, MAX_HEADER_LEN - (desc - buffer), "Continuing ");
+  }
+  desc += snprintf(desc, MAX_HEADER_LEN - (desc - buffer), "call on unexpected message for Call-Id '%s': ", id);
+
+  if (curmsg -> M_type == MSG_TYPE_RECV) {
+    if (curmsg -> recv_request) {
+      desc += snprintf(desc, MAX_HEADER_LEN - (desc - buffer), "while expecting '%s' ", curmsg -> recv_request);
+    } else {
+      desc += snprintf(desc, MAX_HEADER_LEN - (desc - buffer), "while expecting '%d' ", curmsg -> recv_response);
+    }
+  } else if (curmsg -> M_type == MSG_TYPE_SEND) {
+      desc += snprintf(desc, MAX_HEADER_LEN - (desc - buffer), "while sending ");
+  } else if (curmsg -> M_type == MSG_TYPE_PAUSE) {
+      desc += snprintf(desc, MAX_HEADER_LEN - (desc - buffer), "while pausing ");
+  } else if (curmsg -> M_type == MSG_TYPE_SENDCMD) {
+      desc += snprintf(desc, MAX_HEADER_LEN - (desc - buffer), "while sending command ");
+  } else if (curmsg -> M_type == MSG_TYPE_RECVCMD) {
+      desc += snprintf(desc, MAX_HEADER_LEN - (desc - buffer), "while expecting command ");
   } else {
-    if (default_behavior) {
-      WARNING_P3("Aborting call on unexpected message for Call-ID '%s': while expecting '%d' response, received '%s' ", 
-                  id, scenario[msg_index] -> recv_response, msg);
-    } else {
-      WARNING_P3("Continuing call on unexpected message for Call-ID '%s': while expecting '%d' response, received '%s' ", 
-                id, scenario[msg_index] -> recv_response, msg);
-  }
-  }
-  
-  TRACE_MSG((s, "-----------------------------------------------\n"
+      desc += snprintf(desc, MAX_HEADER_LEN - (desc - buffer), "while in message type %d ", curmsg->M_type);
+  }
+  desc += snprintf(desc, MAX_HEADER_LEN - (desc - buffer), "(index %d)", msg_index);
+
+  WARNING("%s, received '%s'", buffer, msg);
+
+  TRACE_MSG("-----------------------------------------------\n"
              "Unexpected %s message received:\n\n%s\n",
              TRANSPORT_TO_STRING(transport),
-             msg));
-  
-  if (default_behavior) {
-#ifdef __3PCC__
-  // if twin socket call => reset the other part here 
-  if (twinSippSocket && (msg_index > 0)) {
-    //WARNING_P2("call-ID '%s', internal-cmd: abort_call %s",id, "");
-    sendCmdBuffer
-      (createSendingMessage((char*)"call-id: [call_id]\ninternal-cmd: abort_call\n", -1));
-  }
-#endif /* __3PCC__ */
-
-  // usage of last_ keywords => for call aborting
-  last_recv_msg = (char *) realloc(last_recv_msg, strlen(msg) + 1);
-  strcpy(last_recv_msg, msg);
-
-    CStat::instance()->computeStat(CStat::E_CALL_FAILED);
-    CStat::instance()->computeStat(CStat::E_FAILED_UNEXPECTED_MSG);
-  return (abortCall());
+             msg);
+
+  if (default_behaviors & DEFAULT_BEHAVIOR_ABORTUNEXP) {
+    // if twin socket call => reset the other part here 
+    if (twinSippSocket && (msg_index > 0)) {
+      sendCmdBuffer(createSendingMessage(get_default_message("3pcc_abort"), -1));
+    }
+
+    // usage of last_ keywords => for call aborting
+    last_recv_msg = (char *) realloc(last_recv_msg, strlen(msg) + 1);
+    strcpy(last_recv_msg, msg);
+
+    computeStat(CStat::E_CALL_FAILED);
+    computeStat(CStat::E_FAILED_UNEXPECTED_MSG);
+    if (default_behaviors & DEFAULT_BEHAVIOR_BYE) {
+      return (abortCall());
+    } else {
+      delete this;
+      return false;
+    }
   } else {
     // Do not abort call nor send anything in reply if default behavior is disabled
     return false;
   }
 }
 
+void call::abort() {
+  WARNING("Aborted call with Call-ID '%s'", id);
+  abortCall();
+}
+
 bool call::abortCall()
 {
-  int res ;
   int is_inv;
 
   char * src_send = NULL ;
@@ -1720,24 +1746,7 @@
       // Answer unexpected errors (4XX, 5XX and beyond) with an ACK 
       // Contributed by F. Tarek Rogers
       if((src_recv) && (get_reply_code(src_recv) >= 400)) {
-
-        strcpy(L_param, "ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0\n");
-        sprintf(L_param, "%s%s", L_param, "Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n");
-        sprintf(L_param, "%s%s", L_param, "From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]\n");
-        sprintf(L_param, "%s%s", L_param, "To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]\n");
-        sprintf(L_param, "%s%s", L_param, "Call-ID: [call_id]\n");
-        char * cseq;
-        cseq = get_header_field_code(src_recv,(char *) "CSeq:");
-        if (cseq != NULL) {
-          sprintf(L_param, "%s%s ACK\n", L_param, cseq);
-        }
-        sprintf(L_param, "%s%s", L_param, "Contact: <sip:sipp@[local_ip]:[local_port];transport=[transport]>\n");
-        sprintf(L_param, "%s%s", L_param, "Max-Forwards: 70\n");
-        sprintf(L_param, "%s%s", L_param, "Subject: Performance Test\n");
-        sprintf(L_param, "%s%s", L_param, "Content-Length: 0\n");
-
-        res = sendBuffer(createSendingMessage((char*)(L_param), -2));
-
+        sendBuffer(createSendingMessage(get_default_message("ack"), -2));
       } else if (src_recv) {
         /* Call is not established and the reply is not a 4XX, 5XX */
         /* And we already received a message. */
@@ -1748,45 +1757,13 @@
            * and send a BYE afterwards                           */
           ack_is_pending = false;
           /* Send an ACK */
-          strcpy(L_param, "ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0\n");
-          sprintf(L_param, "%s%s", L_param, "Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n");
-          sprintf(L_param, "%s%s", L_param, "From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]\n");
-          sprintf(L_param, "%s%s", L_param, "To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]\n");
-          sprintf(L_param, "%s%s", L_param, "Call-ID: [call_id]\n");
-          src_send = last_send_msg ;
-          cseq = get_header_field_code(src_recv,"CSeq:");
-          if (cseq != NULL) {
-            sprintf(L_param, "%s%s ACK\n", L_param, cseq);
-          }
-          sprintf(L_param, "%s%s", L_param, "Contact: <sip:[local_ip]:[local_port];transport=[transport]>\n");
-          sprintf(L_param, "%s%s", L_param,  "Content-Length: 0\n");
-          res = sendBuffer(createSendingMessage((char*)(L_param),-1));
-          
+	  sendBuffer(createSendingMessage(get_default_message("ack"), -1));
+
           /* Send the BYE */
-          cseq = NULL;
-          strcpy(L_param, "BYE sip:[service]@[remote_ip]:[remote_port] SIP/2.0\n");
-          sprintf(L_param, "%s%s", L_param, "Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n");
-          sprintf(L_param, "%s%s", L_param, "From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]\n");
-          sprintf(L_param, "%s%s", L_param, "To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]\n");
-          sprintf(L_param, "%s%s", L_param, "Call-ID: [call_id]\n");
-          cseq = compute_cseq(src_recv);
-          if (cseq != NULL) {
-            sprintf(L_param, "%s%s BYE\n", L_param, compute_cseq(src_recv));
-          }
-          sprintf(L_param, "%s%s", L_param, "Contact: <sip:[local_ip]:[local_port];transport=[transport]>\n");
-          sprintf(L_param, "%s%s", L_param,  "Content-Length: 0\n");
-          res = sendBuffer(createSendingMessage((char*)(L_param),-1));
+	  sendBuffer(createSendingMessage(get_default_message("bye"), -1));
         } else {
           /* Send a CANCEL */
-          strcpy(L_param, "CANCEL sip:[service]@[remote_ip]:[remote_port] SIP/2.0\n");
-          sprintf(L_param, "%s%s", L_param, "Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n");
-          sprintf(L_param, "%s%s", L_param, "From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]\n");
-          sprintf(L_param, "%s%s", L_param, "To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]\n");
-          sprintf(L_param, "%s%s", L_param, "Call-ID: [call_id]\n");
-	       sprintf(L_param, "%sCSeq: 1 CANCEL\n", L_param);
-          sprintf(L_param, "%s%s", L_param, "Contact: <sip:[local_ip]:[local_port];transport=[transport]>\n");
-          sprintf(L_param, "%s%s", L_param,  "Content-Length: 0\n");
-          res = sendBuffer(createSendingMessage((char*)(L_param),-2));
+	  sendBuffer(createSendingMessage(get_default_message("cancel"), -1));
         }
       } else {
         /* Call is not established and the reply is not a 4XX, 5XX */
@@ -1795,42 +1772,40 @@
         /* any answer. */
         /* Do nothing ! */
       }
-    } else {
-      /* Call is established */
+    } else if (last_recv_msg) {
+      /* The call may not be established, if we haven't yet received a message,
+       * because the earlier check depends on the first message being an INVITE
+       * (although it could be something like a message message, therefore we
+       * check that we received a message. */
       char * src_recv = last_recv_msg ;
       char   L_msg_buffer[SIPP_MAX_MSG_SIZE];
       L_msg_buffer[0] = '\0';
       char * L_param = L_msg_buffer;
-      strcpy(L_param, "BYE sip:[service]@[remote_ip]:[remote_port] SIP/2.0\n");
-      sprintf(L_param, "%s%s", L_param, "Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n");
-      sprintf(L_param, "%s%s", L_param, "From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]\n");
-      sprintf(L_param, "%s%s", L_param, "To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]\n");
-      sprintf(L_param, "%s%s", L_param, "Call-ID: [call_id]\n");
-      char * cseq;
-      cseq = compute_cseq(src_recv);
-      if (cseq != NULL) {
-        sprintf(L_param, "%s%s BYE\n", L_param, compute_cseq(src_recv));
-      }
-      sprintf(L_param, "%s%s", L_param, "Contact: <sip:[local_ip]:[local_port];transport=[transport]>\n");
-      sprintf(L_param, "%s%s", L_param,  "Content-Length: 0\n");
-      res = sendBuffer(createSendingMessage((char*)(L_param),-1));
-    }
-  }
-
-  delete_call(id);
+      sendBuffer(createSendingMessage(get_default_message("bye"), -1));
+    }
+  }
+
+  stopListening();
+  deadcall *deadcall_ptr = NULL;
+  if (deadcall_wait) {
+    char reason[100];
+    sprintf(reason, "aborted at index %d", msg_index);
+    deadcall_ptr = new deadcall(id, reason);
+  }
+  delete this;
+
   return false;
 }
 
 bool call::rejectCall()
 {
-  CStat::instance()->computeStat(CStat::E_CALL_FAILED);
-  CStat::instance()->computeStat(CStat::E_FAILED_CALL_REJECTED);
-  delete_call(id);
+  computeStat(CStat::E_CALL_FAILED);
+  computeStat(CStat::E_FAILED_CALL_REJECTED);
+  delete this;
   return false;
 }
 
 
-#ifdef __3PCC__
 int call::sendCmdMessage(int index)
 {
   char * dest;
@@ -1840,35 +1815,30 @@
 
   /* 3pcc extended mode */
   char * peer_dest;
-  int * peer_socket; 
-
-  if(scenario[index] -> M_sendCmdData) {
-    // WARNING_P1("---PREPARING_TWIN_CMD---%s---", scenario[index] -> M_sendCmdData); 
-    dest = createSendingMessage(scenario[index] -> M_sendCmdData, -1);
+  struct sipp_socket **peer_socket;
+
+  message *curmsg = call_scenario->messages[index];
+
+  if(curmsg -> M_sendCmdData) {
+    // WARNING("---PREPARING_TWIN_CMD---%s---", scenario[index] -> M_sendCmdData);
+    dest = createSendingMessage(curmsg -> M_sendCmdData, -1);
     strcat(dest, delimitor);
-    //WARNING_P1("---SEND_TWIN_CMD---%s---", dest); 
+    //WARNING("---SEND_TWIN_CMD---%s---", dest);
 
     int rc;
 
     /* 3pcc extended mode */
-    peer_dest = scenario[index]->peer_dest;
-    if(peer_dest){ 
+    peer_dest = curmsg->peer_dest;
+    if(peer_dest){
       peer_socket = get_peer_socket(peer_dest);
-         rc = send(* peer_socket,
-                   dest,
-                   strlen(dest),
-                   0);
-
-     }else {
-    rc = send(twinSippSocket, 
-              dest, 
-              strlen(dest), 
-              0);
-     } 
+      rc = write_socket(*peer_socket, dest, strlen(dest), WS_BUFFER, &call_peer);
+    }else {
+      rc = write_socket(twinSippSocket, dest, strlen(dest), WS_BUFFER, &call_peer);
+    }
     if(rc <  0) {
-      CStat::instance()->computeStat(CStat::E_CALL_FAILED);
-      CStat::instance()->computeStat(CStat::E_FAILED_CMD_NOT_SENT);
-      delete_call(id);
+      computeStat(CStat::E_CALL_FAILED);
+      computeStat(CStat::E_FAILED_CMD_NOT_SENT);
+      delete this;
       return(-1);
     }
 
@@ -1877,6 +1847,7 @@
   else
     return(-1);
 }
+
 
 int call::sendCmdBuffer(char* cmd)
 {
@@ -1891,554 +1862,459 @@
 
   strcat(dest, delimitor);
 
-
-  rc = send(twinSippSocket, 
-            dest, 
-            strlen(dest), 
-            0);
+  rc = write_socket(twinSippSocket, dest, strlen(dest), WS_BUFFER, &twinSippSocket->ss_remote_sockaddr);
   if(rc <  0) {
-    CStat::instance()->computeStat(CStat::E_CALL_FAILED);
-    CStat::instance()->computeStat(CStat::E_FAILED_CMD_NOT_SENT);
-    delete_call(id);
+    computeStat(CStat::E_CALL_FAILED);
+    computeStat(CStat::E_FAILED_CMD_NOT_SENT);
+    delete this;
     return(-1);
   }
 
   return(0);
 }
 
+
+char* call::createSendingMessage(SendingMessage *src, int P_index) {
+  static char msg_buffer[SIPP_MAX_MSG_SIZE+2];
+  return createSendingMessage(src, P_index, msg_buffer, sizeof(msg_buffer));
+}
+
+char* call::createSendingMessage(SendingMessage *src, int P_index, char *msg_buffer, int buf_len)
+{
+  char * length_marker = NULL;
+  char * auth_marker = NULL;
+  MessageComponent *auth_comp = NULL;
+  bool auth_comp_allocated = false;
+  int    len_offset = 0;
+  char *dest = msg_buffer;
+  bool supresscrlf = false;
+
+  *dest = '\0';
+
+  for (int i = 0; i < src->numComponents(); i++) {
+    MessageComponent *comp = src->getComponent(i);
+    int left = buf_len - (dest - msg_buffer);
+    switch(comp->type) {
+      case E_Message_Literal:
+	if (supresscrlf) {
+	  char *ptr = comp->literal;
+	  while (isspace(*ptr)) ptr++;
+	  dest += snprintf(dest, left, "%s", ptr);
+	  supresscrlf = false;
+	} else {
+	  dest += snprintf(dest, left, "%s", comp->literal);
+	}
+	break;
+      case E_Message_Remote_IP:
+	dest += snprintf(dest, left, "%s", remote_ip_escaped);
+	break;
+      case E_Message_Remote_Host:
+	dest += snprintf(dest, left, "%s", remote_host);
+	break;
+      case E_Message_Remote_Port:
+	dest += snprintf(dest, left, "%d", remote_port + comp->offset);
+	break;
+      case E_Message_Local_IP:
+	dest += snprintf(dest, left, "%s", local_ip_escaped);
+	break;
+      case E_Message_Local_Port:
+	int port;
+	if((transport == T_UDP) && (multisocket) && (toolMode != MODE_SERVER)) {
+	  port = call_port;
+	} else {
+	  port =  local_port;
+	}
+	dest += snprintf(dest, left, "%d", port + comp->offset);
+	break;
+      case E_Message_Transport:
+	dest += snprintf(dest, left, "%s", TRANSPORT_TO_STRING(transport));
+	break;
+      case E_Message_Local_IP_Type:
+	dest += snprintf(dest, left, "%s", (local_ip_is_ipv6 ? "6" : "4"));
+	break;
+      case E_Message_Server_IP: {
+	  /* We should do this conversion once per socket creation, rather than
+	   * repeating it every single time. */
+	  struct sockaddr_storage server_sockaddr;
+
+	  sipp_socklen_t len = SOCK_ADDR_SIZE(&server_sockaddr);
+	  getsockname(call_socket->ss_fd,
+	      (sockaddr *)(void *)&server_sockaddr, &len);
+
+	  if (server_sockaddr.ss_family == AF_INET6) {
+	    char * temp_dest;
+	    temp_dest = (char *) malloc(INET6_ADDRSTRLEN);
+	    memset(temp_dest,0,INET6_ADDRSTRLEN);
+	    inet_ntop(AF_INET6,
+		&((_RCAST(struct sockaddr_in6 *,&server_sockaddr))->sin6_addr),
+		temp_dest,
+		INET6_ADDRSTRLEN);
+	    dest += snprintf(dest, left, "%s",temp_dest);
+	  } else {
+	    dest += snprintf(dest, left, "%s",
+		inet_ntoa((_RCAST(struct sockaddr_in *,&server_sockaddr))->sin_addr));
+	  }
+	}
+	break;
+      case E_Message_Media_IP:
+	dest += snprintf(dest, left, "%s", media_ip_escaped);
+	break;
+      case E_Message_Media_Port:
+      case E_Message_Auto_Media_Port: {
+	int port = media_port + comp->offset;
+	if (comp->type == E_Message_Auto_Media_Port) {
+	  port = media_port + (4 * (number - 1)) % 10000 + comp->offset;
+	}
+#ifdef PCAPPLAY
+	char *begin = dest;
+	while (begin > msg_buffer) {
+	  if (*begin == '\n') {
+	    break;
+	  }
+	  begin--;
+	}
+	if (begin == msg_buffer) {
+	  ERROR("Can not find beginning of a line for the media port!\n");
+	}
+	if (strstr(begin, "audio")) {
+	  if (media_ip_is_ipv6) {
+	    (_RCAST(struct sockaddr_in6 *, &(play_args_a.from)))->sin6_port = port;
+	  } else {
+	    (_RCAST(struct sockaddr_in *, &(play_args_a.from)))->sin_port = port;
+	  }
+	} else if (strstr(begin, "video")) {
+	  if (media_ip_is_ipv6) {
+	    (_RCAST(struct sockaddr_in6 *, &(play_args_v.from)))->sin6_port = port;
+	  } else {
+	    (_RCAST(struct sockaddr_in *, &(play_args_v.from)))->sin_port = port;
+	  }
+	} else {
+	  ERROR("media_port keyword with no audio or video on the current line (%s)", begin);
+	}
 #endif
-
-void call::getHexStringParam(char * dest, char * src, int * len)
-{ 
-  *len=0;
-  /* Allows any hex coded string like '0x5B07F6' */
-  while (isxdigit(*src)) {
-    int val = get_decimal_from_hex(*src);
-    src++;
-    if (isxdigit(*src)) {
-      val = (val << 4) + get_decimal_from_hex(*src);
-      src++;
-    }
-    *dest++ = val & 0xff;
-    (*len)++;
-  }
-}
-
-char* call::getKeywordParam(char * src, char * param, char * output)
-{
-  char *key, *tmp;
-  int len;
-
-  len = 0;
-  key = NULL;
-  if(tmp = strstr(src, param)) {
-    tmp += strlen(param);
-    key = tmp;
-    if ((*key == '0') && (*(key+1) == 'x')) {
-      key += 2;
-      getHexStringParam(output, key, &len);
-      key += len * 2;
+	dest += sprintf(dest, "%u", port);
+	break;
+      }
+      case E_Message_Media_IP_Type:
+	dest += snprintf(dest, left, "%s", (media_ip_is_ipv6 ? "6" : "4"));
+	break;
+      case E_Message_Call_Number:
+	dest += snprintf(dest, left, "%u", number);
+	break;
+      case E_Message_Call_ID:
+	dest += snprintf(dest, left, "%s", id);
+	break;
+      case E_Message_CSEQ:
+	dest += snprintf(dest, left, "%u", cseq + comp->offset);
+	break;
+      case E_Message_PID:
+	dest += snprintf(dest, left, "%d", pid);
+	break;
+      case E_Message_Service:
+	dest += snprintf(dest, left, "%s", service);
+	break;
+      case E_Message_Branch:
+	/* Branch is magic cookie + call number + message index in scenario */
+	if(P_index == -2){
+	  dest += snprintf(dest, left, "z9hG4bK-%u-%u-%d", pid, number, msg_index-1 + comp->offset);
+	} else {
+	  dest += snprintf(dest, left, "z9hG4bK-%u-%u-%d", pid, number, P_index + comp->offset);
+	}
+	break;
+      case E_Message_Index:
+	dest += snprintf(dest, left, "%d", P_index);
+	break;
+      case E_Message_Next_Url:
+	if (next_req_url) {
+	  dest += sprintf(dest, "%s", next_req_url);
+	}
+	break;
+      case E_Message_Len:
+	length_marker = dest;
+	dest += snprintf(dest, left, "     ");
+	len_offset = comp->offset;
+	break;
+      case E_Message_Authentication:
+	if (auth_marker) {
+	  ERROR("Only one [authentication] keyword is currently supported!\n");
+	}
+	auth_marker = dest;
+	dest += snprintf(dest, left, "[authentication place holder]");
+	auth_comp = comp;
+	break;
+      case E_Message_Peer_Tag_Param:
+	if(peer_tag) {
+	  dest += snprintf(dest, left, ";tag=%s", peer_tag);
+	}
+	break;
+      case E_Message_Routes:
+	if (dialog_route_set) {
+	  dest += sprintf(dest, "Route: %s", dialog_route_set);
+	} else if (*(dest - 1) == '\n') {
+	  supresscrlf = true;
+	}
+	break;
+      case E_Message_ClockTick:
+	dest += snprintf(dest, left, "%lu", clock_tick);
+	break;
+      case E_Message_Timestamp:
+	struct timeval currentTime;
+	gettimeofday(&currentTime, NULL);
+	dest += snprintf(dest, left, "%s", CStat::formatTime(&currentTime));
+	break;
+      case E_Message_Users:
+	dest += snprintf(dest, left, "%d", users);
+	break;
+      case E_Message_UserID:
+	dest += snprintf(dest, left, "%d", userId);
+	break;
+      case E_Message_Variable: {
+	 int varId = comp->varId;
+	 CCallVariable *var = M_callVariableTable->getVar(varId);
+	 if(var->isSet()) {
+	   if (var->isRegExp()) {
+	     dest += sprintf(dest, "%s", var->getMatchingValue());
+	   } else if (var->isDouble()) {
+	     dest += sprintf(dest, "%lf", var->getDouble());
+	   } else if (var->isString()) {
+	     dest += sprintf(dest, "%s", var->getString());
+	   } else if (var->isBool()) {
+	     dest += sprintf(dest, "true");
+	   }
+	 } else if (var->isBool()) {
+	   dest += sprintf(dest, "false");
+	 }
+	 break;
+      }
+      case E_Message_Fill: {
+        int varId = comp->varId;
+	int length = (int) M_callVariableTable->getVar(varId)->getDouble();
+	if (length < 0) {
+	  length = 0;
+	}
+	char *filltext = comp->literal;
+	int filllen = strlen(filltext);
+	if (filllen == 0) {
+	  ERROR("Internal error: [fill] keyword has zero-length text.");
+	}
+	for (int i = 0, j = 0; i < length; i++, j++) {
+	  *dest++ = filltext[j % filllen];
+	}
+	*dest = '\0';
+	break;
+      }
+      case E_Message_Injection: {
+	char *orig_dest = dest;
+	getFieldFromInputFile(comp->comp_param.field_param.filename, comp->comp_param.field_param.field, comp->comp_param.field_param.line, dest);
+	/* We are injecting an authentication line. */
+	if (char *tmp = strstr(orig_dest, "[authentication")) {
+	  if (auth_marker) {
+	    ERROR("Only one [authentication] keyword is currently supported!\n");
+	  }
+	  auth_marker = tmp;
+	  auth_comp = (struct MessageComponent *)calloc(1, sizeof(struct MessageComponent));
+	  if (!auth_comp) { ERROR("Out of memory!"); }
+	  auth_comp_allocated = true;
+
+	  tmp = strchr(auth_marker, ']');
+	  char c = *tmp;
+	  *tmp = '\0';
+	  SendingMessage::parseAuthenticationKeyword(call_scenario, auth_comp, auth_marker);
+	  *tmp = c;
+	}
+	if (*(dest - 1) == '\n') {
+	  supresscrlf = true;
+	}
+	break;
+      }
+      case E_Message_Last_Header: {
+	char * last_header = get_last_header(comp->literal);
+	if(last_header) {
+	  dest += sprintf(dest, "%s", last_header);
+	}
+	if (*(dest - 1) == '\n') {
+	  supresscrlf = true;
+	}
+	break;
+      }
+      case E_Message_Last_Message:
+        if(last_recv_msg && strlen(last_recv_msg)) {
+	  dest += sprintf(dest, "%s", last_recv_msg);
+	}
+	break;
+      case E_Message_Last_Request_URI: {
+       char * last_request_uri = get_last_request_uri();
+       dest += sprintf(dest, "%s", last_request_uri);
+       free(last_request_uri);
+       break;
+      }
+      case E_Message_Last_CSeq_Number: {
+       int last_cseq = 0;
+
+       char *last_header = get_last_header("CSeq:");
+       if(last_header) {
+	 last_header += 5;
+	 /* Extract the integer value of the field */
+	 while(isspace(*last_header)) last_header++;
+	 sscanf(last_header,"%d", &last_cseq);
+       }
+       dest += sprintf(dest, "%d", last_cseq + comp->offset);
+       break;
+      }
+      case E_Message_TDM_Map:
+	if (!use_tdmmap)
+	  ERROR("[tdmmap] keyword without -tdmmap parameter on command line");
+	dest += snprintf(dest, left, "%d.%d.%d/%d",
+	    tdm_map_x+(int((tdm_map_number)/((tdm_map_b+1)*(tdm_map_c+1))))%(tdm_map_a+1),
+	    tdm_map_h,
+	    tdm_map_y+(int((tdm_map_number)/(tdm_map_c+1)))%(tdm_map_b+1),
+	    tdm_map_z+(tdm_map_number)%(tdm_map_c+1)
+	    );
+	break;
+    }
+  }
+  /* Need the body for length and auth-int calculation */
+  char *body;
+  if (length_marker || auth_marker) {
+    body = strstr(msg_buffer, "\r\n\r\n");
+  }
+
+  /* Fix up the length. */
+  if (length_marker) {
+    if (auth_marker > body) {
+      ERROR("The authentication keyword should appear in the message header, not the body!");
+    }
+
+    if (body && dest - body > 4 && dest - body < 100004) {
+      char tmp = length_marker[5];
+      sprintf(length_marker, "%5u", dest - body - 4 + len_offset);
+      length_marker[5] = tmp;
     } else {
-      while (*key) {
-        if (((key - src) > KEYWORD_SIZE) || (!(key - src))) {
-          ERROR_P1("Syntax error parsing '%s' parameter", param);
-        } else if (*key == ']' || *key < 33 || *key > 126) {
-          strncpy(output, tmp, key-tmp);
-          output[key-tmp] = '\0';
-          break;
-        }
-        key++;
-      }
-    }
-  } else {
-    output[0] = '\0';
-  }
-  return key;
-}
-
-char* call::createSendingMessage(char * src, int P_index)
-{
-  static char msg_buffer[SIPP_MAX_MSG_SIZE+2];
- 
-  if(src != NULL) {
-    char * dest = msg_buffer;
-    char * key;
-    char * length_marker = NULL;
-    int    offset = 0;
-    int    len_offset = 0;
-    char   current_line[MAX_HEADER_LEN];
-    char * line_mark = NULL;
-    char * tsrc;
-
-    current_line[0] = '\0';
-    while(*src) {
-      if (current_line[0] == '\0') {
-        line_mark = NULL;
-        line_mark = strchr(src, '\n');
-        if (line_mark) {
-          memcpy(current_line, src, line_mark - src);
-          current_line[line_mark-src] = '\0';
-        }
-      }
-      /* This hex encoding could be done in XML parsing, allowing us to skip
-       * these conditionals and branches. */
-      if ((*src == '\\') && (*(src+1) == 'x')) {
-        /* Allows any hex coded char like '\x5B' ([) */
-        src += 2;
-        if (isxdigit(*src)) {
-          int val = get_decimal_from_hex(*src);
-          src++;
-          if (isxdigit(*src)) {
-            val = (val << 4) + get_decimal_from_hex(*src);
-          }
-          *dest++ = val & 0xff;
-        }
-        src++;
-      } else if(*src == '[') {
-        char keyword [KEYWORD_SIZE+1];
-        src++;
-        
-        tsrc=strchr(src, '[');
-        key = strchr(src, ']');
-        if ((tsrc) && (tsrc<key)){
-          memcpy(keyword, src-1,  tsrc - src + 1);
-          keyword[tsrc - src + 1] = 0;
-          src=tsrc+1;
-          dest += sprintf(dest, "%s", keyword);
-        }
-        
-        if((!key) || ((key - src) > KEYWORD_SIZE) || (!(key - src))){
-          ERROR_P1("Syntax error or invalid [keyword] in scenario while parsing '%s'", current_line);
-        }
-        memcpy(keyword, src,  key - src);
- 
-        keyword[key - src] = 0;
-        src = key + 1;
-        // allow +/-n for numeric variables
-        if (!strstr(keyword, "authentication") && !strstr(keyword, "map") && ((key = strchr(keyword,'+')) || (key = strchr(keyword,'-'))) && isdigit(*(key+1))) {
-          offset = atoi(key);
-          *key = 0;
-        } else offset = 0;
-
-        if(!strcmp(keyword, "remote_ip")) {
-          dest += sprintf(dest, "%s", remote_ip_escaped);
-        } else if(!strcmp(keyword, "remote_port")) {
-          dest += sprintf(dest, "%u", remote_port + offset);
-        } else if(!strcmp(keyword, "transport")) {
-          dest += sprintf(dest, "%s", TRANSPORT_TO_STRING(transport));
-        } else if(!strcmp(keyword, "local_ip")) {
-          dest += sprintf(dest, "%s", local_ip_escaped);
-        } else if(!strcmp(keyword, "local_ip_type")) {
-          dest += sprintf(dest, "%s", (local_ip_is_ipv6 ? "6" : "4"));
-        } else if(!strcmp(keyword, "local_port")) {
-          if((transport == T_UDP) && (multisocket) && (toolMode != MODE_SERVER)) {
-            dest += sprintf(dest, "%u", call_port + offset);
-          } else {
-            dest += sprintf(dest, "%u", local_port + offset);
-          }
-        } else if(!strcmp(keyword, "server_ip")) {
-          struct sockaddr_storage server_sockaddr;
-          sipp_socklen_t len = SOCK_ADDR_SIZE(&server_sockaddr);
-          getsockname(call_socket,
-                (sockaddr *)(void *)&server_sockaddr,
-                &len);
-          if (server_sockaddr.ss_family == AF_INET6) {
-            char * temp_dest;
-            temp_dest = (char *) malloc(INET6_ADDRSTRLEN);
-            memset(temp_dest,0,INET6_ADDRSTRLEN);
-            inet_ntop(AF_INET6, 
-                      &((_RCAST(struct sockaddr_in6 *,&server_sockaddr))->sin6_addr),
-                      temp_dest,
-                      INET6_ADDRSTRLEN); 
-            dest += sprintf(dest, "%s",temp_dest);
-          } else {
-            dest += sprintf(dest, "%s", 
-            inet_ntoa((_RCAST(struct sockaddr_in *,&server_sockaddr))->sin_addr));
-          }          
-        } else if(!strcmp(keyword, "media_ip")) {
-          dest += sprintf(dest, "%s", media_ip_escaped);
-#ifdef PCAPPLAY
-        } else if (!strcmp(keyword, "auto_media_port")) {
-          /* to make media ports begin from true media_port exported from sipp.cpp, as number begins to 1
-           * * 4 to allow video (audio+rtcp+video+rtcp)
-           * Modulo 10000 to limit the port number
-           * -> Max 10000 concurrent RTP sessions for pcap_play 
-           */
-          int port = media_port + (4 * (number - 1)) % 10000 + offset;
-          if (strstr(current_line, "m=audio ")) {
-            if (media_ip_is_ipv6) {
-              (_RCAST(struct sockaddr_in6 *, &(play_args_a.from)))->sin6_port = port;
-            } else {
-              (_RCAST(struct sockaddr_in *, &(play_args_a.from)))->sin_port = port;
-            }
-          } else if (strstr(current_line, "m=video ")) {
-          if (media_ip_is_ipv6) {
-              (_RCAST(struct sockaddr_in6 *, &(play_args_v.from)))->sin6_port = port;
-          } else {
-              (_RCAST(struct sockaddr_in *, &(play_args_v.from)))->sin_port = port;
-            }
-          } else {
-            ERROR_P1("auto_media_port keyword with no audio or video on the current line (%s)", current_line);
-          }
-          dest += sprintf(dest, "%u", port);
+      // Other cases: Content-Length is 0
+      sprintf(length_marker, "    0\r\n\r\n");
+    }
+  }
+
+  /*
+   * The authentication substitution must be done outside the above
+   * loop because auth-int will use the body (which must have already
+   * been keyword substituted) to build the md5 hash
+   */
+  if (auth_marker) {
+#ifndef _USE_OPENSSL
+    ERROR("Authentication requires OpenSSL!");
+#else
+    if (!dialog_authentication) {
+      ERROR("Authentication keyword without dialog_authentication!");
+    }
+
+    int	   auth_marker_len;
+    char * tmp;
+    int  authlen;
+
+    auth_marker_len = (strchr(auth_marker, ']') + 1) - auth_marker;
+
+    /* Need the Method name from the CSeq of the Challenge */
+    char method[MAX_HEADER_LEN];
+    tmp = get_last_header("CSeq:");
+    if(!tmp) {
+      ERROR("Could not extract method from cseq of challenge");
+    }
+    tmp += 5;
+    while(isspace(*tmp) || isdigit(*tmp)) tmp++;
+    sscanf(tmp,"%s", method);
+
+    if (!body) {
+      body = "";
+    }
+
+    /* Determine the type of credentials. */
+    char result[MAX_HEADER_LEN];
+    if (dialog_challenge_type == 401) {
+      /* Registrars use Authorization */
+      authlen = sprintf(result, "Authorization: ");
+    } else {
+      /* Proxies use Proxy-Authorization */
+      authlen = sprintf(result, "Proxy-Authorization: ");
+    }
+
+    /* Build the auth credenticals */
+    char uri[MAX_HEADER_LEN];
+    sprintf (uri, "%s:%d", remote_ip, remote_port);
+    /* These cause this function to  not be reentrant. */
+    static char my_auth_user[MAX_HEADER_LEN + 2];
+    static char my_auth_pass[MAX_HEADER_LEN + 2];
+    static char my_aka_OP[MAX_HEADER_LEN + 2];
+    static char my_aka_AMF[MAX_HEADER_LEN + 2];
+    static char my_aka_K[MAX_HEADER_LEN + 2];
+
+    createSendingMessage(auth_comp->comp_param.auth_param.auth_user, -2, my_auth_user, sizeof(my_auth_user));
+    createSendingMessage(auth_comp->comp_param.auth_param.auth_pass, -2, my_auth_pass, sizeof(my_auth_pass));
+    createSendingMessage(auth_comp->comp_param.auth_param.aka_K, -2, my_aka_K, sizeof(my_aka_K));
+    createSendingMessage(auth_comp->comp_param.auth_param.aka_AMF, -2, my_aka_AMF, sizeof(my_aka_AMF));
+    createSendingMessage(auth_comp->comp_param.auth_param.aka_OP, -2, my_aka_OP, sizeof(my_aka_OP));
+
+    if (createAuthHeader(my_auth_user, my_auth_pass, method, uri, body, dialog_authentication,
+	  my_aka_OP, my_aka_AMF, my_aka_K, result + authlen) == 0) {
+      ERROR("%s", result + authlen);
+    }
+    authlen = strlen(result);
+
+    /* Shift the end of the message to its rightful place. */
+    memmove(auth_marker + authlen, auth_marker + auth_marker_len, strlen(auth_marker + auth_marker_len) + 1);
+    /* Copy our result into the hole. */
+    memcpy(auth_marker, result, authlen);
 #endif
-        } else if(!strcmp(keyword, "media_port")) {
-          int port = media_port + offset;
-#ifdef PCAPPLAY
-          if (strstr(current_line, "audio")) {
-            if (media_ip_is_ipv6) {
-              (_RCAST(struct sockaddr_in6 *, &(play_args_a.from)))->sin6_port = port;
-            } else {
-              (_RCAST(struct sockaddr_in *, &(play_args_a.from)))->sin_port = port;
-            }
-          } else if (strstr(current_line, "video")) {
-          if (media_ip_is_ipv6) {
-              (_RCAST(struct sockaddr_in6 *, &(play_args_v.from)))->sin6_port = port;
-            } else {
-              (_RCAST(struct sockaddr_in *, &(play_args_v.from)))->sin_port = port;
-            }
-          } else {
-            ERROR_P1("media_port keyword with no audio or video on the current line (%s)", current_line);
-          }
-#endif
-          dest += sprintf(dest, "%u", port);
-        } else if(!strcmp(keyword, "media_ip_type")) {
-          dest += sprintf(dest, "%s", (media_ip_is_ipv6 ? "6" : "4"));
-        } else if(!strcmp(keyword, "call_number")) {
-          dest += sprintf(dest, "%u", number);
-        } else if(!strcmp(keyword, "call_id")) {
-          dest += sprintf(dest, "%s", id);
-        } else if(!strcmp(keyword, "cseq")) {
-          dest += sprintf(dest, "%u", cseq +offset);
-        } else if(!strcmp(keyword, "pid")) {
-          dest += sprintf(dest, "%u", pid);
-        } else if(!strcmp(keyword, "service")) {
-          dest += sprintf(dest, "%s", service);
-        } else if(!strncmp(keyword, "field", 5)) {
-            char* local_dest = dest;
-            getFieldFromInputFile(keyword, m_localLineNumber, dest);
-            if (dest == local_dest && ('\r' == *(local_dest-1) || '\n' == *(local_dest-1))) {
-                /* If the line begins with a field value and there
-                 * is nothing to add for this field, 
-                 * Jump to the end of line in scenario. SN 
-                 */
-                while((*src) && (*src != '\n')) {
-                    src++;
-                }
-                if(*src == '\n') {
-                    src++;
-                }
-            }
-        } else if(!strcmp(keyword, "peer_tag_param")) {
-          if(peer_tag) {
-            dest += sprintf(dest, ";tag=%s", peer_tag);
-          }
-        } else if(strstr(keyword, "tdmmap")) {
-          /* keyword to generate c= line for TDM 
-           * format: g.h.i/j                    
-           * g: varies in interval a, offset x
-           * h: fix value
-           * i: varies in interval b, offset y
-           * j: varies in interval c, offset z
-           * Format: tdmmap{1-3}{0}{0-27}{1-24}
-           */
-           if (!use_tdmmap) 
-             ERROR("[tdmmap] keyword without -tdmmap parameter on command line");
-           dest += sprintf(dest, "%d.%d.%d/%d", 
-                                  tdm_map_x+(int((tdm_map_number)/((tdm_map_b+1)*(tdm_map_c+1))))%(tdm_map_a+1),
-                                  tdm_map_h,
-                                  tdm_map_y+(int((tdm_map_number)/(tdm_map_c+1)))%(tdm_map_b+1),
-                                  tdm_map_z+(tdm_map_number)%(tdm_map_c+1)
-                                  );
-        } else if(strstr(keyword, "$")) {
-          int varId = atoi(keyword+1);
-          if(varId < SCEN_VARIABLE_SIZE) {
-            if(M_callVariableTable[varId] != NULL) {
-              if(M_callVariableTable[varId]->isSet()) {
-                dest += sprintf(dest, "%s",
-                                M_callVariableTable[varId]->
-                                getMatchingValue());
-                // WARNING_P1("VARIABLE --%s--", M_callVariableTable[varId]->getMatchingValue());
-              } else {
-                dest += sprintf(dest, "%s", "");
-              }
-            }
-          }
-        } else if(strstr(keyword, "last_")) {
-          char * last_header = get_last_header(keyword+5);
-          if(last_header) {
-            dest += sprintf(dest, "%s", last_header);
-          } else {
-            /* Jump to the end of line in scenario if nothing
-             * to insert in place of this header. */
-            while((*src) && (*src != '\n')) {
-              src++;
-            }
-            if(*src == '\n') {
-              src++;
-            }
-          }
-        } else if(strstr(keyword, "routes")) {
-          if (dialog_route_set) {
-             dest += sprintf(dest, "Route: %s", dialog_route_set);
-          } else {
-             // Skip to end of line
-             while((*src) && (*src != '\n')) src++;
-             if (*src == '\n') src++;
-          }  
-#ifdef _USE_OPENSSL
-        } else if(strstr(keyword, "authentication")) {
-            /* This keyword is substituted below */
-            dest += sprintf(dest, "[%s]", keyword);
-#endif
-        } else if(strstr(keyword, "branch")) {
-          /* Branch is magic cookie + call number + message index in scenario */
-	    if(P_index == -2){
-	       dest += sprintf(dest, "z9hG4bK-%u-%u-%d", pid, number, msg_index-1);
-	    } else {
-	      dest += sprintf(dest, "z9hG4bK-%u-%u-%d", pid, number, P_index);
-	    }
-        } else if(strstr(keyword, "msg_index")) {
-          /* Message index in scenario */
-          dest += sprintf(dest, "%d", P_index);
-        } else if(strstr(keyword, "next_url")) {
-          if (next_req_url) {
-            dest += sprintf(dest, "%s", next_req_url);
-          }
-        } else if(strstr(keyword, "len")) {
-            length_marker = dest;
-            dest += sprintf(dest, "    ");
-            len_offset = offset;
-        } else {   // scan for the generic parameters - must be last test
-          int i = 0;
-          while (generic[i]) {
-            char *msg1 = *generic[i];
-            char *msg2 = *(generic[i] + 1);
-            if(!strcmp(keyword, msg1)) {
-              dest += sprintf(dest, "%s", msg2);
-              break;
-            }
-            ++i;
-          }
-          if (!generic[i]) {
-            ERROR_P1("Unsupported keyword '%s' in xml scenario file",
-                   keyword);
-          }
-        }
-      /* This could also be done at XML parsing time. */
-      } else if (*src == '\n') {
-        *dest++ = '\r';
-        *dest++ = *src++;
-        current_line[0] = '\0';
-      } else {
-        *dest++ = *src++;
-      }
-    }
-    *dest = 0;
-
-#ifdef _USE_OPENSSL
-    /* 
-     * The authentication substitution must be done outside the above
-     * loop because auth-int will use the body (which must have already
-     * been keyword substituted) to build the md5 hash
-     */
-
-    if(dialog_authentication && (src = strstr(msg_buffer, "[authentication"))) {
-        char * auth_marker;
-	int	   auth_marker_len;
-
-        char my_auth_user[KEYWORD_SIZE];
-        char my_auth_pass[KEYWORD_SIZE];
-        char my_aka_OP[KEYWORD_SIZE];
-        char my_aka_AMF[KEYWORD_SIZE];
-        char my_aka_K[KEYWORD_SIZE];
-        char * tmp;
-        int  authlen;
-
-        auth_marker = src;
-        auth_marker_len = strchr(src, ']') - src;
-        strcpy(my_auth_user, service);
-        strcpy(my_auth_pass, auth_password);
-        /* Look for optional username and password parameters */
-        /* add aka_OP, aka_AMF, aka_K */
-        key = getKeywordParam(src, "username=", my_auth_user);
-        memset(my_auth_pass,0,KEYWORD_SIZE);
-        key = getKeywordParam(src, "password=", my_auth_pass);
-        memset(my_aka_OP,0,KEYWORD_SIZE);
-        key = getKeywordParam(src, "aka_OP=", my_aka_OP);
-        memset(my_aka_AMF,0,KEYWORD_SIZE);
-        key = getKeywordParam(src, "aka_AMF=", my_aka_AMF);
-        memset(my_aka_K,0,KEYWORD_SIZE);
-        key = getKeywordParam(src, "aka_K=", my_aka_K);
-        if (my_aka_K[0]==0){
-            memcpy(my_aka_K,my_auth_pass,16);
-            my_aka_K[16]=0;
-        }
-       
-        /* Need the Method name from the CSeq of the Challenge */
-        char method[MAX_HEADER_LEN];
-        tmp = get_last_header("CSeq") + 5;
-        if(!tmp) {
-            ERROR("Could not extract method from cseq of challenge");
-        }
-        while(isspace(*tmp) || isdigit(*tmp)) tmp++;
-	/* This looks like it could have been be a bug, shouldn't it be method instead of &method. */
-        sscanf(tmp,"%s", method);
-
-        /* Need the body for auth-int calculation */
-        char body[SIPP_MAX_MSG_SIZE];
-        memset(body, 0, sizeof(body));
-        tmp = msg_buffer;
-        while(*(tmp+4)) {
-            if (*tmp == '\r' && *(tmp + 1) == '\n' &&
-                    *(tmp + 2) == '\r' && *(tmp + 3) == '\n') {
-                sprintf(body, "%s", tmp+4);
-                break;
-            }
-            tmp++;                      
-        }
-
-        /* Build the auth credenticals */
-        char result[MAX_HEADER_LEN];
-        char uri[MAX_HEADER_LEN];
-        sprintf (uri, "%s:%d", remote_ip, remote_port);
-        if (createAuthHeader(my_auth_user, my_auth_pass, method, uri,
-                body, dialog_authentication, 
-                my_aka_OP,  
-                my_aka_AMF,  
-                my_aka_K,
-                result) == 0) {
-            ERROR_P1("%s", result);
-        }
-   
-        char tmp_buffer[SIPP_MAX_MSG_SIZE];
-        dest = strncpy(tmp_buffer, msg_buffer, src - msg_buffer);
-        dest += src - msg_buffer;
-        key = strchr(src, ']');
-        src += key - src + 1;
-
-        if (dialog_challenge_type == 401) {
-          /* Registrars use Authorization */
-          authlen = sprintf(dest, "Authorization: %s", result);
-        } else {
-          /* Proxies use Proxy-Authorization */
-          authlen = sprintf(dest, "Proxy-Authorization: %s", result);
-        }
-        dest += authlen;                 
-        if (length_marker > auth_marker) {
-          length_marker = length_marker - 1 - auth_marker_len + authlen;
-        }
-        dest += sprintf(dest, "%s", src);
-        strcpy(msg_buffer, tmp_buffer);
-	dest = msg_buffer + strlen(msg_buffer);
-    }
-#endif
-
-    // Remove all \r, \n but 1 at the end of a message to send 
-    int len = strlen(msg_buffer);
-    while ( (msg_buffer[len-1] == '\n') &&
-            (msg_buffer[len-2] == '\r') &&
-            (msg_buffer[len-3] == '\n') &&
-            (msg_buffer[len-4] == '\r')) {
-      msg_buffer[len-2] = 0;
-      len -= 2;
-    }
-
-    int    L_flag_crlf = 0 ; // don't need add crlf
-    int    L_content_length = 0;
-
-    if(P_index < 0 ) {
-      L_flag_crlf = 1 ; // Add crlf
-    } else {
-      message::ContentLengthFlag L_flag_content = scenario[P_index] -> content_length_flag ; 
-      switch (L_flag_content) {
-        case  message::ContentLengthValueZero :
-          L_flag_crlf = 1;
-          break ;
-        case  message::ContentLengthValueNoZero :
-          // the msg contains content-length field and his value is greater than 0
-          break ;
-        default :
-          // the msg does not contain content-length field
-          // control the crlf
-          L_content_length = xp_get_content_length(msg_buffer) ;
-          if( L_content_length == 0) {
-            L_flag_crlf = 1;
-          } else if (L_content_length == -1 ) {
-            // The content_length is not present: its a [len] keyword
-          } 
-          break;
-      }
-    } 
-
-    if(L_flag_crlf) {
-      // Add crlf 
-      msg_buffer[len] ='\r';
-      msg_buffer[len+1] ='\n';
-      msg_buffer[len+2] =0;
-    }
-
-    if (length_marker) {
-      key = strstr(length_marker,"\r\n\r\n");
-      if (key && dest - key > 4 && dest - key < 10004) {
-        char tmp = length_marker[4];
-        sprintf(length_marker, "%4u", dest - key - 4 + len_offset);
-        length_marker[4] = tmp;
-      } else {
-        // Other cases: Content-Length is 0
-        sprintf(length_marker, "   0\r\n\r\n");
-      }
-    }
-  } else {
-    ERROR("Unsupported 'send' message in scenario");
-  }
-  return(msg_buffer);
-}
-
-
-#ifdef __3PCC__
+  }
+
+  if (auth_comp_allocated) {
+    SendingMessage::freeMessageComponent(auth_comp);
+  }
+
+  return msg_buffer;
+}
+
 bool call::process_twinSippCom(char * msg)
 {
   int		  search_index;
   bool            found = false;
   T_ActionResult  actionResult;
 
-  if (!running) {
-    paused_calls.remove_paused_call(this);
-    add_running_call(this);
-  }
+  setRunning();
 
   if (checkInternalCmd(msg) == false) {
 
     for(search_index = msg_index;
-      search_index < scenario_len;
+      search_index < call_scenario->length;
       search_index++) {
-      if(scenario[search_index] -> M_type != MSG_TYPE_RECVCMD) {
-        if(scenario[search_index] -> optional) {
-          continue;
-        }
-        /* The received message is different from the expected one */
-        return rejectCall();
+      if(call_scenario->messages[search_index] -> M_type != MSG_TYPE_RECVCMD) {
+	if(call_scenario->messages[search_index] -> optional) {
+	  continue;
+	}
+	/* The received message is different from the expected one */
+	TRACE_MSG("Unexpected control message received (I was expecting a different type of message):\n%s\n", msg);
+	return rejectCall();
       } else {
-        if(extendedTwinSippMode){                   // 3pcc extended mode 
+	if(extendedTwinSippMode){                   // 3pcc extended mode
 	  if(check_peer_src(msg, search_index)){
-            found = true;
-            break;
+	    found = true;
+	    break;
 	  } else{
-	    WARNING_P1("Unexpected sender for the received peer message \n%s\n", msg);
+	    WARNING("Unexpected sender for the received peer message \n%s\n", msg);
 	    return rejectCall();
-	    }
-	 }
-	 else {
-        found = true;
-        break;
-      }
-    }
-    }
-    
+	  }
+	}
+	else {
+	  found = true;
+	  break;
+	}
+      }
+    }
+
     if (found) {
-      scenario[search_index]->M_nbCmdRecv ++;
-      
+      call_scenario->messages[search_index]->M_nbCmdRecv ++;
+      do_bookkeeping(search_index);
+
       // variable treatment
       // Remove \r, \n at the end of a received command
       // (necessary for transport, to be removed for usage)
@@ -2447,7 +2323,7 @@
         msg[strlen(msg)-2] = 0;
       }
       actionResult = executeAction(msg, search_index);
-      
+
       if(actionResult != call::E_AR_NO_ERROR) {
         // Store last action result if it is an error
         // and go on with the scenario
@@ -2457,11 +2333,11 @@
         }
       }
     } else {
+      TRACE_MSG("Unexpected control message received (no such message found):\n%s\n", msg);
       return rejectCall();
     }
     msg_index = search_index; //update the state machine
     return(next());
-    
   } else {
     return (false);
   }
@@ -2492,7 +2368,7 @@
   if (strcmp(L_ptr1, "abort_call") == 0) {
     *L_ptr2 = L_backup;
     abortCall();
-    CStat::instance()->computeStat(CStat::E_CALL_FAILED);
+    computeStat(CStat::E_CALL_FAILED);
     return (true);
   }
 
@@ -2520,7 +2396,7 @@
   if(!*L_ptr2) { return (false); }
   L_backup = *L_ptr2;
   *L_ptr2 = 0;
-  if (strcmp(L_ptr1, scenario[search_index] -> peer_src) == 0) {
+  if (strcmp(L_ptr1, call_scenario->messages[search_index] -> peer_src) == 0) {
     *L_ptr2 = L_backup;
     return(true);
   }
@@ -2528,7 +2404,6 @@
   *L_ptr2 = L_backup;
   return (false);
 }
-#endif
 
 
 void call::extract_cseq_method (char* method, char* msg)
@@ -2551,6 +2426,28 @@
       method[nbytes] = '\0';
     }
   }
+}
+
+void call::extract_transaction (char* txn, char* msg)
+{
+  char *otxn = txn;
+  char *via = get_header_content(msg, "via:");
+  if (!via) {
+    txn[0] = '\0';
+    return;
+  }
+
+  char *branch = strstr(via, ";branch=");
+  if (!branch) {
+    txn[0] = '\0';
+    return;
+  }
+
+  branch += strlen(";branch=");
+  while (*branch && *branch != ';' && *branch != ',' && !isspace(*branch)) {
+    *txn++ = *branch++;
+  }
+  *txn = '\0';
 }
 
 void call::formatNextReqUrl (char* next_req_url)
@@ -2700,39 +2597,50 @@
   }
 }
 
-bool call::matches_scenario(unsigned int index, int reply_code, char * request, char * responsecseqmethod)
-{         
+bool call::matches_scenario(unsigned int index, int reply_code, char * request, char * responsecseqmethod, char *txn)
+{
   int        result;
-          
-  if ((reply_code) && ((scenario[index] -> recv_response) == reply_code) && \
-     (scenario[index]->recv_response_for_cseq_method_list) && \
-     (strstr(scenario[index]->recv_response_for_cseq_method_list, responsecseqmethod))) {
-        return true;
-  }   
-    
-  if ((scenario[index] -> recv_request) && \
-     (!strcmp(scenario[index] -> recv_request, request))) {
-        return true;
-  } 
-  
-  if ((scenario[index] -> recv_request) && (scenario[index] -> regexp_match)) {
-  
-     if (scenario[index] -> regexp_compile == NULL) {
-        regex_t *re = new regex_t;
-        if (regcomp(re, scenario[index] -> recv_request, REG_EXTENDED|REG_NOSUB)) {
-           // regexp is not well formed
-           scenario[index] -> regexp_match = 0;
-           free(re);
-           return false;
-        }
-        scenario[index] -> regexp_compile = re;
-     }
-
-     result = regexec(scenario[index] -> regexp_compile, request, (size_t)0, NULL, 0);
-     if (!result) return true;
+  message *curmsg = call_scenario->messages[index];
+
+  if ((curmsg -> recv_request)) {
+    if (curmsg->regexp_match) {
+      if (curmsg -> regexp_compile == NULL) {
+	regex_t *re = new regex_t;
+	if (regcomp(re, curmsg -> recv_request, REG_EXTENDED|REG_NOSUB)) {
+	  ERROR("Invalid regular expression for index %d: %s", curmsg->recv_request);
+	}
+	curmsg -> regexp_compile = re;
+      }
+      return !regexec(curmsg -> regexp_compile, request, (size_t)0, NULL, 0);
+    } else {
+      return !strcmp(curmsg -> recv_request, request);
+    }
+  } else if (curmsg->recv_response && (curmsg->recv_response == reply_code)) {
+    /* This is a potential candidate, we need to match transactions. */
+    if (curmsg->response_txn) {
+      if (txnID[curmsg->response_txn - 1] && !strcmp(txnID[curmsg->response_txn - 1], txn)) {
+	return true;
+      } else {
+	return false;
+      }
+    } else if (index == 0) {
+      /* Always true for the first message. */
+      return true;
+    } else if (curmsg->recv_response_for_cseq_method_list &&
+	strstr(curmsg->recv_response_for_cseq_method_list, responsecseqmethod)) {
+      /* If we do not have a transaction defined, we just check the CSEQ method. */
+      return true;
+    } else {
+      return false;
+    }
   }
 
   return false;
+}
+
+void call::queue_up(char *msg) {
+  free(queued_msg);
+  queued_msg = strdup(msg);
 }
 
 bool call::process_incoming(char * msg)
@@ -2740,60 +2648,59 @@
   int             reply_code;
   static char     request[65];
   char            responsecseqmethod[65];
+  char            txn[MAX_HEADER_LEN];
   unsigned long   cookie;
   char          * ptr;
   int             search_index;
   bool            found = false;
   T_ActionResult  actionResult;
 
-  int             L_case = 0 ;
-
-  if (!running) {
-    paused_calls.remove_paused_call(this);
-    add_running_call(this);
-  }
-   
-   /* Ignore the messages received during a pause if -pause_msg_ign is set */
-   if(scenario[msg_index] -> M_type == MSG_TYPE_PAUSE && pause_msg_ign) return(true);
+  setRunning();
+
+  /* Ignore the messages received during a pause if -pause_msg_ign is set */
+  if(call_scenario->messages[msg_index] -> M_type == MSG_TYPE_PAUSE && pause_msg_ign) return(true);
 
   /* Authorize nop as a first command, even in server mode */
-  if((msg_index == 0) && (scenario[msg_index] -> M_type == MSG_TYPE_NOP)) {
-    actionResult = executeAction(NULL, msg_index);
-    return next();
+  if((msg_index == 0) && (call_scenario->messages[msg_index] -> M_type == MSG_TYPE_NOP)) {
+    queue_up (msg);
+    paused_until = 0;
+    return run();
   }
   responsecseqmethod[0] = '\0';
+  txn[0] = '\0';
 
   if((transport == T_UDP) && (retrans_enabled)) {
     /* Detects retransmissions from peer and retransmit the
      * message which was sent just after this one was received */
     cookie = hash(msg);
-    if(recv_retrans_hash == cookie) {
+    if((recv_retrans_recv_index >= 0) && (recv_retrans_hash == cookie)) {
 
       int status;
 
       if(lost(recv_retrans_recv_index)) {
-	TRACE_MSG((s, "%s message (retrans) lost (recv).",
-	      TRANSPORT_TO_STRING(transport)));
+	TRACE_MSG("%s message (retrans) lost (recv).",
+	      TRANSPORT_TO_STRING(transport));
 
 	if(comp_state) { comp_free(&comp_state); }
-	scenario[recv_retrans_recv_index] -> nb_lost++;
+	call_scenario->messages[recv_retrans_recv_index] -> nb_lost++;
 	return true;
       }
 
-      scenario[recv_retrans_recv_index] -> nb_recv_retrans++;
+      call_scenario->messages[recv_retrans_recv_index] -> nb_recv_retrans++;
 
       send_scene(recv_retrans_send_index, &status);
 
       if(status == 0) {
-	scenario[recv_retrans_send_index] -> nb_sent_retrans++;
-      } else if(status < -1) {
+	call_scenario->messages[recv_retrans_send_index] -> nb_sent_retrans++;
+	computeStat(CStat::E_RETRANSMISSION);
+      } else if(status < 0) {
 	return false;
       }
 
       return true;
     }
 
-    if(last_recv_hash == cookie) {
+    if((last_recv_index >= 0) && (last_recv_hash == cookie)) {
       /* This one has already been received, but not processed
        * yet => (has not triggered something yet) so we can discard.
        *
@@ -2807,7 +2714,7 @@
        * This case can also appear in case of message duplication by
        * the network. This should not be considered as an unexpected.
        */
-      scenario[last_recv_index]->nb_recv_retrans++;
+      call_scenario->messages[last_recv_index]->nb_recv_retrans++;
       return true;
     }
   }
@@ -2847,6 +2754,7 @@
     request[0]=0;
     // extract the cseq method from the response
     extract_cseq_method (responsecseqmethod, msg);
+    extract_transaction (txn, msg);
   } else if(ptr = strchr(msg, ' ')) {
     if((ptr - msg) < 64) {
       memcpy(request, msg, ptr - msg);
@@ -2868,21 +2776,21 @@
 
       reply_code = 0;
     } else {
-      ERROR_P1("SIP method too long in received message '%s'",
+      ERROR("SIP method too long in received message '%s'",
                msg);
     }
   } else {
-    ERROR_P1("Invalid sip message received '%s'",
+    ERROR("Invalid sip message received '%s'",
              msg);
   }
-    
+
   /* Try to find it in the expected non mandatory responses
    * until the first mandatory response  in the scenario */
   for(search_index = msg_index;
-      search_index < scenario_len;
+      search_index < call_scenario->length;
       search_index++) {
-    if(!matches_scenario(search_index, reply_code, request, responsecseqmethod)) {
-      if(scenario[search_index] -> optional) {
+    if(!matches_scenario(search_index, reply_code, request, responsecseqmethod, txn)) {
+      if(call_scenario->messages[search_index] -> optional) {
         continue;
       }
       /* The received message is different for the expected one */
@@ -2903,23 +2811,44 @@
     for(search_index = msg_index - 1;
         search_index >= 0;
         search_index--) {
-      if (scenario[search_index]->optional == OPTIONAL_FALSE) contig = false;
-      if(matches_scenario(search_index, reply_code, request, responsecseqmethod)) {
-        if (contig || scenario[search_index]->optional == OPTIONAL_GLOBAL) {
+      if (call_scenario->messages[search_index]->optional == OPTIONAL_FALSE) contig = false;
+      if(matches_scenario(search_index, reply_code, request, responsecseqmethod, txn)) {
+        if (contig || call_scenario->messages[search_index]->optional == OPTIONAL_GLOBAL) {
          found = true;
          break;  
         } else {
-          /*
-           * we received a non mandatory msg for an old transaction (this could be due to a retransmit.
-           * If this response is for an INVITE transaction, retransmit the ACK to quench retransmits.
-           */
-          if ( (reply_code) &&
-             (0 == strncmp (responsecseqmethod, "INVITE", strlen(responsecseqmethod)) ) &&
-             (scenario[search_index+1]->M_type == MSG_TYPE_SEND) &&
-             (0 == strncmp(scenario[search_index+1]->send_scheme, "ACK", 3)) ) {
-            sendBuffer(createSendingMessage(scenario[search_index+1] -> send_scheme, (search_index+1)));
-            return true;
-          }
+	  if (int checkTxn = call_scenario->messages[search_index]->response_txn) {
+	    /* This is a reply to an old transaction. */
+	    if (!strcmp(txnID[checkTxn - 1], txn)) {
+		/* This reply is provisional, so it should have no effect if we recieve it out-of-order. */
+		if (reply_code >= 100 && reply_code <= 199) {
+		  TRACE_MSG("-----------------------------------------------\n"
+		      "Ignoring provisional %s message for transaction %s:\n\n%s\n",
+		      TRANSPORT_TO_STRING(transport), call_scenario->txnRevMap[checkTxn - 1], msg);
+		  return true;
+		} else if (call_scenario->messages[search_index + 1]->M_type == MSG_TYPE_SEND && call_scenario->messages[search_index + 1]->send_scheme->isAck()) {
+		  /* This is the message before an ACK, so verify that this is an invite transaction. */
+		  if (!strcmp(responsecseqmethod, "INVITE")) {
+		    sendBuffer(createSendingMessage(call_scenario->messages[search_index+1] -> send_scheme, (search_index+1)));
+		    return true;
+		  }
+		}
+		/* This is a non-provisional message for the transaction, and
+		 * we have already gotten our allowable response. */
+	    }
+	  } else {
+	    /*
+	     * we received a non mandatory msg for an old transaction (this could be due to a retransmit.
+	     * If this response is for an INVITE transaction, retransmit the ACK to quench retransmits.
+	     */
+	    if ( (reply_code) &&
+		(0 == strncmp (responsecseqmethod, "INVITE", strlen(responsecseqmethod)) ) &&
+		(call_scenario->messages[search_index+1]->M_type == MSG_TYPE_SEND) &&
+		(call_scenario->messages[search_index+1]->send_scheme->isAck()) ) {
+	      sendBuffer(createSendingMessage(call_scenario->messages[search_index+1] -> send_scheme, (search_index+1)));
+	      return true;
+	    }
+	  }
         }
       }
     }
@@ -2927,17 +2856,43 @@
 
   /* If it is still not found, process an unexpected message */
   if(!found) {
-    if ((L_case = checkAutomaticResponseMode(request)) == 0) {
-      if (!process_unexpected(msg)) {
-        return false; // Call aborted by unexpected message handling
+    if (call_scenario->unexpected_jump >= 0) {
+      bool recursive = false;
+      if (call_scenario->retaddr >= 0) {
+	if (M_callVariableTable->getVar(call_scenario->retaddr)->getDouble() != 0) {
+	  /* We are already in a jump! */
+	  recursive = true;
+	} else {
+	  M_callVariableTable->getVar(call_scenario->retaddr)->setDouble(msg_index);
+	}
+      }
+      if (!recursive) {
+	if (call_scenario->pausedaddr >= 0) {
+	  M_callVariableTable->getVar(call_scenario->pausedaddr)->setDouble(paused_until);
+	}
+	msg_index = call_scenario->unexpected_jump;
+	queue_up(msg);
+	paused_until = 0;
+	return run();
+      } else {
+	if (!process_unexpected(msg)) {
+	  return false; // Call aborted by unexpected message handling
+	}
       }
     } else {
-      // call aborted by automatic response mode if needed
-      return (automaticResponseMode(L_case, msg)); 
-    }
-  }
-
-  int test = (!found) ? -1 : scenario[search_index]->test;
+      T_AutoMode L_case;
+      if ((L_case = checkAutomaticResponseMode(request)) == 0) {
+	if (!process_unexpected(msg)) {
+	  return false; // Call aborted by unexpected message handling
+	}
+      } else {
+	// call aborted by automatic response mode if needed
+	return automaticResponseMode(L_case, msg);
+      }
+    }
+  }
+
+  int test = (!found) ? -1 : call_scenario->messages[search_index]->test;
   /* test==0: No branching"
    * test==-1 branching without testing"
    * test>0   branching with testing
@@ -2945,10 +2900,10 @@
 
   /* Simulate loss of messages */
   if(lost(search_index)) {
-    TRACE_MSG((s, "%s message lost (recv).", 
-               TRANSPORT_TO_STRING(transport)));
+    TRACE_MSG("%s message lost (recv).",
+               TRANSPORT_TO_STRING(transport));
     if(comp_state) { comp_free(&comp_state); }
-    scenario[search_index] -> nb_lost++;
+    call_scenario->messages[search_index] -> nb_lost++;
     return true;
   }
 
@@ -2957,12 +2912,12 @@
   do_bookkeeping(search_index);
 
   /* Increment the recv counter */
-  scenario[search_index] -> nb_recv++;
+  call_scenario->messages[search_index] -> nb_recv++;
 
   // Action treatment
   if (found) {
-    //WARNING_P1("---EXECUTE_ACTION_ON_MSG---%s---", msg); 
-    
+    //WARNING("---EXECUTE_ACTION_ON_MSG---%s---", msg);
+
     actionResult = executeAction(msg, search_index);
 
     if(actionResult != call::E_AR_NO_ERROR) {
@@ -2974,7 +2929,7 @@
       }
     }
   }
-  
+
   if (request) { // update [cseq] with received CSeq
     unsigned long int rcseq = get_cseq_value(msg);
     if (rcseq > cseq) cseq = rcseq;
@@ -3018,7 +2973,7 @@
   }
 
   /* store the route set only once. TODO: does not support target refreshes!! */
-  if (scenario[search_index] -> bShouldRecordRoutes &&
+  if (call_scenario->messages[search_index] -> bShouldRecordRoutes &&
           NULL == dialog_route_set ) {
 
       next_req_url = (char*) calloc(1, MAX_HEADER_LEN);
@@ -3027,7 +2982,7 @@
       memset(rr, 0, sizeof(rr));
       strcpy(rr, get_header_content(msg, (char*)"Record-Route:"));
 
-      // WARNING_P1("rr [%s]", rr);
+      // WARNING("rr [%s]", rr);
       char ch[MAX_HEADER_LEN];
       strcpy(ch, get_header_content(msg, (char*)"Contact:"));
 
@@ -3047,12 +3002,12 @@
       {
         computeRouteSetAndRemoteTargetUri (rr, ch, true);
       }
-      // WARNING_P1("next_req_url is [%s]", next_req_url);
+      // WARNING("next_req_url is [%s]", next_req_url);
   }
 
 #ifdef _USE_OPENSSL
   /* store the authentication info */
-  if ((scenario[search_index] -> bShouldAuthenticate) && 
+  if ((call_scenario->messages[search_index] -> bShouldAuthenticate) &&
           (reply_code == 401 || reply_code == 407)) {
 
       /* is a challenge */
@@ -3066,13 +3021,18 @@
         ERROR("Couldn't find 'Proxy-Authenticate' or 'WWW-Authenticate' in 401 or 407!");
       }
 
-      dialog_authentication = (char *) calloc(1, strlen(auth) + 2);
+      dialog_authentication = (char *) realloc(dialog_authentication, strlen(auth) + 2);
       sprintf(dialog_authentication, "%s", auth);
 
       /* Store the code of the challenge for building the proper header */
       dialog_challenge_type = reply_code;
   }
 #endif
+
+  /* If we are not advancing state, we should quite before we change this stuff. */
+  if (!call_scenario->messages[search_index]->advance_state) {
+    return true;
+  }
 
   /* Store last received message information for all messages so that we can
    * correctly identify retransmissions, and use its body for inclusion
@@ -3084,29 +3044,30 @@
 
   /* If this was a mandatory message, or if there is an explicit next label set
    * we must update our state machine.  */
-  if (!(scenario[search_index] -> optional) ||
-       scenario[search_index]->next && 
-      ((test == -1) ||
-       (test < SCEN_VARIABLE_SIZE && M_callVariableTable[test] != NULL && M_callVariableTable[test]->isSet()))
+  if (!(call_scenario->messages[search_index] -> optional) ||
+       call_scenario->messages[search_index]->next &&
+       ((test == -1) || (M_callVariableTable->getVar(test)->isSet()))
      ) {
+    /* If we are paused, then we need to wake up so that we properly go through the state machine. */
+    paused_until = 0;
     msg_index = search_index;
     return next();
   } else {
-    unsigned int timeout = call_wake(this);
+    unsigned int timeout = wake();
     unsigned int candidate;
 
-    if (test < SCEN_VARIABLE_SIZE && M_callVariableTable[test] != NULL && M_callVariableTable[test]->isSet()) {
-      WARNING_P1("Last message generates an error and will not be used for next sends (for last_ variables):\r\n%s",msg);
+    if (call_scenario->messages[search_index]->next && M_callVariableTable->getVar(test)->isSet()) {
+      WARNING("Last message generates an error and will not be used for next sends (for last_ variables):\r\n%s",msg);
     }
 
     /* We are just waiting for a message to be received, if any of the
      * potential messages have a timeout we set it as our timeout. We
      * start from the next message and go until any non-receives. */
-    for(search_index++; search_index < scenario_len; search_index++) {
-      if(scenario[search_index] -> M_type != MSG_TYPE_RECV) {
-	break;
-      }
-      candidate = scenario[search_index] -> retrans_delay;
+    for(search_index++; search_index < call_scenario->length; search_index++) {
+      if(call_scenario->messages[search_index] -> M_type != MSG_TYPE_RECV) {
+	break;
+      }
+      candidate = call_scenario->messages[search_index] -> timeout;
       if (candidate == 0) {
 	if (defl_recv_timeout == 0) {
 	  continue;
@@ -3118,131 +3079,232 @@
       }
     }
 
-    if (!remove_running_call(this)) {
-      ERROR("Tried to remove a running call that wasn't running!\n");
-    }
-    paused_calls.add_paused_call(this, true);
+    setPaused();
   }
   return true;
+}
+
+double call::get_rhs(CAction *currentAction) {
+  if (currentAction->getVarInId()) {
+    return M_callVariableTable->getVar(currentAction->getVarInId())->getDouble();
+  } else {
+    return currentAction->getDoubleValue();
+  }
 }
 
 call::T_ActionResult call::executeAction(char * msg, int scenarioIndex)
 {
   CActions*  actions;
   CAction*   currentAction;
-  CVariable* scenVariable;
-  char       msgPart[MAX_SUB_MESSAGE_LENGTH];
-  int        currentId;
-
-  actions = scenario[scenarioIndex]->M_actions;
+
+  actions = call_scenario->messages[scenarioIndex]->M_actions;
   // looking for action to do on this message
   if(actions != NULL) {
-    for(int i=0; i<actions->getUsedAction(); i++) {
+    for(int i=0; i<actions->getActionSize(); i++) {
       currentAction = actions->getAction(i);
       if(currentAction != NULL) {
         if(currentAction->getActionType() == CAction::E_AT_ASSIGN_FROM_REGEXP) {
-          currentId = currentAction->getVarId();
-          scenVariable = scenVariableTable[currentId][scenarioIndex];
-          if(scenVariable != NULL) {
-            if(currentAction->getLookingPlace() == CAction::E_LP_HDR) {
-              extractSubMessage
-                                (msg, 
-                                currentAction->getLookingChar(), 
-                                msgPart,
-                                currentAction->getCaseIndep(),
-                                currentAction->getOccurence(),
-                                currentAction->getHeadersOnly()); 
-        
-              if(strlen(msgPart) > 0) {
-          
-                scenVariable->executeRegExp(msgPart, 
-                                  M_callVariableTable,
-				  currentId,
-				  currentAction->getNbSubVarId(),
-                                  currentAction->getSubVarId());
-          
-                if( (!(M_callVariableTable[currentId]->isSet())) 
-                && (currentAction->getCheckIt() == true) ) {
-                  // the message doesn't match and the checkit 
-                  // action say it MUST match
-                  // Allow easier regexp debugging
-                  WARNING_P2("Failed regexp match: looking "
-                  "in '%s', with regexp '%s'", 
-                  msgPart, 
-                  scenVariable->
-                  getRegularExpression());
-                  // --> Call will be marked as failed
-                  return(call::E_AR_REGEXP_DOESNT_MATCH);
-                }
-              } else {// sub part of message not found
-                if( currentAction->getCheckIt() == true ) {
-                  // the sub message is not found and the
-                  // checking action say it MUST match
-                  // --> Call will be marked as failed but 
-                  // will go on
-                  WARNING_P2("Failed regexp match: header %s not found in message %s\n", currentAction->getLookingChar(), msg);
-                  return(call::E_AR_HDR_NOT_FOUND);
-                } 
-              }
-            } else {// we must look in the entire message
-              // WARNING_P1("LOOKING IN MSG -%s-", msg);
-                scenVariable->executeRegExp(msg, 
-                                  M_callVariableTable,
-				  currentId,
-				  currentAction->getNbSubVarId(),
-                                  currentAction->getSubVarId());
-              if((!(M_callVariableTable[currentId]->isSet())) 
-              && (currentAction->getCheckIt() == true) ) {
-                // the message doesn't match and the checkit 
-                // action say it MUST match
-                // Allow easier regexp debugging
-                WARNING_P2("Failed regexp match: looking in '%s'"
-                ", with regexp '%s'", 
-                msg, 
-                scenVariable->getRegularExpression());
-                // --> rejecting the call
-                return(call::E_AR_REGEXP_DOESNT_MATCH);
-              }
-            }
-          } // end if scen variable != null
+	  char msgPart[MAX_SUB_MESSAGE_LENGTH];
+
+	  /* Where to look. */
+	  char *haystack;
+
+	  if(currentAction->getLookingPlace() == CAction::E_LP_HDR) {
+	    extractSubMessage (msg,
+		currentAction->getLookingChar(),
+		msgPart,
+		currentAction->getCaseIndep(),
+		currentAction->getOccurence(),
+		currentAction->getHeadersOnly());
+	    if(currentAction->getCheckIt() == true && (strlen(msgPart) < 0)) {
+	      // the sub message is not found and the checking action say it
+	      // MUST match --> Call will be marked as failed but will go on
+	      WARNING("Failed regexp match: header %s not found in message %s\n", currentAction->getLookingChar(), msg);
+	      return(call::E_AR_HDR_NOT_FOUND);
+	    }
+	    haystack = msgPart;
+	  } else {
+	    haystack = msg;
+	  }
+	  currentAction->executeRegExp(haystack, M_callVariableTable);
+
+	  if( (!(M_callVariableTable->getVar(currentAction->getVarId())->isSet())) && (currentAction->getCheckIt() == true) ) {
+	    // the message doesn't match and the checkit action say it MUST match
+	    // Allow easier regexp debugging
+	    WARNING("Failed regexp match: looking in '%s', with regexp '%s'",
+		haystack, currentAction->getRegularExpression());
+	    return(call::E_AR_REGEXP_DOESNT_MATCH);
+	  }
         } else /* end action == E_AT_ASSIGN_FROM_REGEXP */ 
-            if (currentAction->getActionType() == CAction::E_AT_LOG_TO_FILE) {
+            if (currentAction->getActionType() == CAction::E_AT_ASSIGN_FROM_VALUE) {
+	      double operand = get_rhs(currentAction);
+	      M_callVariableTable->getVar(currentAction->getVarId())->setDouble(operand);
+        } else if (currentAction->getActionType() == CAction::E_AT_ASSIGN_FROM_INDEX) {
+	  M_callVariableTable->getVar(currentAction->getVarId())->setDouble(msg_index);
+        } else if (currentAction->getActionType() == CAction::E_AT_ASSIGN_FROM_GETTIMEOFDAY) {
+	  struct timeval tv;
+	  gettimeofday(&tv, NULL);
+	  M_callVariableTable->getVar(currentAction->getVarId())->setDouble((double)tv.tv_sec);
+	  M_callVariableTable->getVar(currentAction->getSubVarId(0))->setDouble((double)tv.tv_usec);
+        } else if (currentAction->getActionType() == CAction::E_AT_LOOKUP) {
+	  /* Create strings from the sending messages. */
+	  char *file = strdup(createSendingMessage(currentAction->getMessage(0), -2));
+	  char *key = strdup(createSendingMessage(currentAction->getMessage(1), -2));
+	  double value = -1;
+
+	  str_int_map::iterator index_it = infIndex[file]->find(key);
+	  if (index_it != infIndex[file]->end()) {
+		value = index_it->second;
+	  }
+	  M_callVariableTable->getVar(currentAction->getVarId())->setDouble(value);
+	  free(file);
+	  free(key);
+#ifdef _USE_OPENSSL
+        } else if (currentAction->getActionType() == CAction::E_AT_VERIFY_AUTH) {
+	  bool result;
+	  char *lf;
+	  char *end;
+
+	  lf = strchr(msg, '\n');
+	  end = strchr(msg, ' ');
+
+	  if (!lf || !end) {
+	    result = false;
+	  } else if (lf < end) {
+	    result = false;
+	  } else {
+	    char *auth = get_header(msg, "Authorization:", true);
+	    char *method = (char *)malloc(end - msg + 1);
+	    strncpy(method, msg, end - msg);
+	    method[end - msg] = '\0';
+
+	    /* Generate the username to verify it against. */
+            char *tmp = createSendingMessage(currentAction->getMessage(0), -2 /* do not add crlf*/);
+	    char *username = strdup(tmp);
+	    /* Generate the password to verify it against. */
+            tmp= createSendingMessage(currentAction->getMessage(1), -2 /* do not add crlf*/);
+	    char *password = strdup(tmp);
+
+	    result = verifyAuthHeader(username, password, method, auth);
+
+	    free(username);
+	    free(password);
+	  }
+
+	  M_callVariableTable->getVar(currentAction->getVarId())->setBool(result);
+#endif
+        } else if (currentAction->getActionType() == CAction::E_AT_JUMP) {
+	  double operand = get_rhs(currentAction);
+	  msg_index = (int)operand - 1;
+        } else if (currentAction->getActionType() == CAction::E_AT_PAUSE_RESTORE) {
+	  double operand = get_rhs(currentAction);
+	  paused_until = (int)operand;
+        } else if (currentAction->getActionType() == CAction::E_AT_VAR_ADD) {
+	  double value = M_callVariableTable->getVar(currentAction->getVarId())->getDouble();
+	  double operand = get_rhs(currentAction);
+	  M_callVariableTable->getVar(currentAction->getVarId())->setDouble(value + operand);
+        } else if (currentAction->getActionType() == CAction::E_AT_VAR_SUBTRACT) {
+	  double value = M_callVariableTable->getVar(currentAction->getVarId())->getDouble();
+	  double operand = get_rhs(currentAction);
+	  M_callVariableTable->getVar(currentAction->getVarId())->setDouble(value - operand);
+        } else if (currentAction->getActionType() == CAction::E_AT_VAR_MULTIPLY) {
+	  double value = M_callVariableTable->getVar(currentAction->getVarId())->getDouble();
+	  double operand = get_rhs(currentAction);
+	  M_callVariableTable->getVar(currentAction->getVarId())->setDouble(value * operand);
+        } else if (currentAction->getActionType() == CAction::E_AT_VAR_DIVIDE) {
+	  double value = M_callVariableTable->getVar(currentAction->getVarId())->getDouble();
+	  double operand = get_rhs(currentAction);
+	  if (operand == 0) {
+	    WARNING("Action failure: Can not divide by zero ($%d/$%d)!\n", currentAction->getVarId(), currentAction->getVarInId());
+	  } else {
+	    M_callVariableTable->getVar(currentAction->getVarId())->setDouble(value / operand);
+	  }
+        } else if (currentAction->getActionType() == CAction::E_AT_VAR_TEST) {
+	  double value = currentAction->compare(M_callVariableTable);
+	  M_callVariableTable->getVar(currentAction->getVarId())->setBool(value);
+        } else if (currentAction->getActionType() == CAction::E_AT_VAR_STRCMP) {
+	  char *rhs = M_callVariableTable->getVar(currentAction->getVarInId())->getString();
+	  char *lhs = currentAction->getStringValue();
+	  int value = strcmp(rhs, lhs);
+	  M_callVariableTable->getVar(currentAction->getVarId())->setDouble((double)value);
+        } else if (currentAction->getActionType() == CAction::E_AT_VAR_TRIM) {
+	  CCallVariable *var = M_callVariableTable->getVar(currentAction->getVarId());
+	  char *in = var->getString();
+	  char *p = in;
+	  while (isspace(*p)) {
+		p++;
+	  }
+	  char *q = strdup(p);
+	  var->setString(q);
+	  int l = strlen(q);
+	  for (int i = l - 1; i >= 0 & isspace(q[i]); i--) {
+		q[i] = '\0';
+	  }
+        } else if (currentAction->getActionType() == CAction::E_AT_VAR_TO_DOUBLE) {
+	  double value;
+
+	  if (M_callVariableTable->getVar(currentAction->getVarInId())->toDouble(&value)) {
+	    M_callVariableTable->getVar(currentAction->getVarId())->setDouble(value);
+	  } else {
+	    WARNING("Invalid double conversion from $%d to $%d", currentAction->getVarInId(), currentAction->getVarId());
+	  }
+	} else if (currentAction->getActionType() == CAction::E_AT_ASSIGN_FROM_SAMPLE) {
+	  double value = currentAction->getDistribution()->sample();
+	  M_callVariableTable->getVar(currentAction->getVarId())->setDouble(value);
+	} else if (currentAction->getActionType() == CAction::E_AT_ASSIGN_FROM_STRING) {
             char* x = createSendingMessage(currentAction->getMessage(), -2 /* do not add crlf*/);
-            LOG_MSG((s, "%s\n", x));
-        } else /* end action == E_AT_LOG_TO_FILE */ 
-            if (currentAction->getActionType() == CAction::E_AT_EXECUTE_CMD) {
+	    char *str = strdup(x);
+	    if (!str) {
+		ERROR("Out of memory duplicating string for assignment!");
+	    }
+	    M_callVariableTable->getVar(currentAction->getVarId())->setString(str);
+	} else if (currentAction->getActionType() == CAction::E_AT_LOG_TO_FILE) {
+            char* x = createSendingMessage(currentAction->getMessage(), -2 /* do not add crlf*/);
+            LOG_MSG("%s\n", x);
+	} else if (currentAction->getActionType() == CAction::E_AT_LOG_WARNING) {
+            char* x = createSendingMessage(currentAction->getMessage(), -2 /* do not add crlf*/);
+            WARNING("%s", x);
+        } else if (currentAction->getActionType() == CAction::E_AT_EXECUTE_CMD) {
 
             if (currentAction->getCmdLine()) {
-                char* x = createSendingMessage(currentAction->getCmdLine(), -2 /* do not add crlf*/);
-                // TRACE_MSG((s, "Trying to execute [%s]", x)); 
+                char* x = createSendingMessage(currentAction->getMessage(), -2 /* do not add crlf*/);
+                // TRACE_MSG("Trying to execute [%s]", x);
                 pid_t l_pid;
                 switch(l_pid = fork())
                 {
                     case -1:
                         // error when forking !
-                        ERROR("Forking error");
+                        ERROR_NO("Forking error main");
                         break;
 
                     case 0:
-                        // first child process - execute the command
+                       // first child process - execute the command
                        if((l_pid = fork()) < 0) {
-                         ERROR("Forking error");
+                         ERROR_NO("Forking error child");
                        } else {
-                         if( l_pid == 0)
-                         system(x); // second child runs
-                         exit(EXIT_OTHER);
+                         if( l_pid == 0){
+                         int ret;
+                         ret = system(x); // second child runs
+                         if(ret == -1) {
+                           WARNING("system call error for %s",x);
+                          }
+                        }
+                       exit(EXIT_OTHER); 
                        }
                        break;
                     default:
                        // parent process continue
                        // reap first child immediately
-                       if(waitpid(l_pid, NULL, 0) != l_pid) {  
-                         ERROR("waitpid error"); 
+                       pid_t ret;
+                       while ((ret=waitpid(l_pid, NULL, 0)) != l_pid) {
+                       if (ret != -1) {
+                          ERROR("waitpid returns %1d for child %1d",ret,l_pid);
+                         }
                        }
                        break;
                 }
             }
-        } else /* end action == E_AT_LOG_TO_FILE */ 
+        } else /* end action == E_AT_EXECUTE_CMD */
             if (currentAction->getActionType() == CAction::E_AT_EXEC_INTCMD) {
                 switch (currentAction->getIntCmd())
                 {
@@ -3293,7 +3355,7 @@
             ERROR("Can create thread to send RTP packets");
           pthread_attr_destroy(&attr);
 #endif
-        } else {// end action == E_AT_EXECUTE_CMD
+        } else {
           ERROR("call::executeAction unknown action");
         }
       } // end if current action != null
@@ -3362,151 +3424,54 @@
   }
 }
 
-void call::dumpFileContents(void)
-{
-    WARNING_P3("Line choosing strategy is [%s]. m_counter [%d] numLinesInFile [%d]",
-               m_usage == InputFileSequentialOrder ? "SEQUENTIAL" : "RANDOM",
-               m_counter, numLinesInFile);
-
-    for (int i(0); i < numLinesInFile && fileContents[i][0]; ++i) {
-        WARNING_P2("%dth line reads [%s]", i, fileContents[i].c_str());
-    }
-}
-
-/* Read MAX_CHAR_BUFFER_SIZE size lines from the
- * "fileName" and populate it in the fileContents
- * vector. The file should not be more than
- * MAX_LINES_IN_FILE lines long and each line
- * should be terminated with a '\n'
- */
-
-void call::readInputFileContents(const char* fileName)
-{
-  ifstream *inFile    = new ifstream(fileName);
-  ifstream &inFileObj = *inFile;
-  char      line[MAX_CHAR_BUFFER_SIZE];
-  
-  if (!inFile->good()) {
-    ERROR_P1("Unable to open file %s", fileName);
-    return ;
-  }
-
-  numLinesInFile = 0;
-  call::m_counter = 0;
-  line[0] = '\0';
-  inFileObj.getline(line, MAX_CHAR_BUFFER_SIZE);
-
-  if (NULL != strstr(line, "RANDOM")) {
-      call::m_usage = InputFileRandomOrder;
-  } else if (NULL != strstr(line, "SEQUENTIAL")) {
-      call::m_usage = InputFileSequentialOrder;
-  } else {
-      // default
-      call::m_usage = InputFileSequentialOrder;
-  }
-
-  while (!inFileObj.eof()) {
-    line[0] = '\0';
-    inFileObj.getline(line, MAX_CHAR_BUFFER_SIZE);
-    if (line[0]) {
-      if ('#' != line[0]) {
-        fileContents.push_back(line);
-        numLinesInFile++; /* this counts number of valid data lines */
-      }
-    } else {
-      break;
-    }
-  }
-  // call::dumpFileContents();
-  delete inFile;
-}
- 
-void call::getFieldFromInputFile(const char* keyword, unsigned int lineNum, char*& dest)
-{
-  int nthField    = atoi(keyword+5 /*strlen("field")*/);
-  int origNth     = nthField;
-  
-  if (fileContents.size() > lineNum) {
-    const string& line = fileContents[lineNum];
-    
-    // WARNING_P3("lineNum [%d] nthField [%d] line [%s]",
-    //         lineNum, nthField, line.c_str());
-    
-    size_t pos(0), oldpos(0);
-    do {
-      oldpos = pos;
-      size_t localpos = line.find(';', oldpos);
-      
-      if (localpos != string::npos) {
-        pos = localpos + 1;
-      } else {
-        pos = localpos;
-        break;
-      }
-      
-      //string x = line.substr(oldpos, pos - oldpos);
-      // WARNING_P3("pos [%d] oldpos [%d] is [%s]", pos, oldpos, x.c_str());
-      
-      if (nthField) {
-        --nthField;
-      } else {
-        break;
-      }
-      
-    } while (oldpos != string::npos);
-    
-    if (nthField) {
-      WARNING_P1("Field %d not found in the file", origNth);
-      // field not found in line
-    } else {
-      if (string::npos != oldpos) {
-        if (string::npos != pos) {
-          // should not be decremented for fieldN
-          pos -= (oldpos + 1);
-        }
-    
-        string x = line.substr(oldpos, pos);
-        if (x.length()) {
-        dest += sprintf(dest, "%s", x.c_str());
-        }
-        
-        // WARNING_P2("nthField [%d] is [%s]", origNth, x.c_str());
-      }
-    }
-  } else {
-    // WARNING_P1("Field %d definition not found", nthField);
-  }
-}
-
-void call::getIpFieldFromInputFile(int fieldNr, int lineNum, char *dest)
-{
-      char keyword[10];
-      sprintf(keyword, "field%d", fieldNr);
-      char *p = dest;
-      getFieldFromInputFile(keyword, lineNum, p);
-}
-
-int  call::checkAutomaticResponseMode(char * P_recv) {
-
-  int L_res = 0 ;
+void call::getFieldFromInputFile(const char *fileName, int field, SendingMessage *lineMsg, char*& dest)
+{
+  if (inFiles.find(fileName) == inFiles.end()) {
+    ERROR("Invalid injection file: %s", fileName);
+  }
+  int line = (*m_lineNumber)[fileName];
+  if (lineMsg) {
+	char lineBuffer[20];
+	char *endptr;
+	createSendingMessage(lineMsg, -2, lineBuffer, sizeof(lineBuffer));
+	line = (int) strtod(lineBuffer, &endptr);
+	if (*endptr != 0) {
+	  ERROR("Invalid line number generated: '%s'", lineBuffer);
+	}
+	if (line > inFiles[fileName]->numLines()) {
+	  line = -1;
+	}
+  }
+  if (line < 0) {
+    return;
+  }
+  dest += inFiles[fileName]->getField(line, field, dest, SIPP_MAX_MSG_SIZE);
+}
+
+call::T_AutoMode call::checkAutomaticResponseMode(char * P_recv) {
+
+  int L_res = E_AM_DEFAULT ;
 
   if (strcmp(P_recv, "BYE")==0) {
-    L_res = 1 ;
+    return E_AM_UNEXP_BYE;
   } else if (strcmp(P_recv, "CANCEL") == 0) {
-    L_res = 2 ;
+    return E_AM_UNEXP_CANCEL;
   } else if (strcmp(P_recv, "PING") == 0) {
-    L_res = 3 ;
+    return E_AM_PING;
   } else if (((strcmp(P_recv, "INFO") == 0) || (strcmp(P_recv, "NOTIFY") == 0) || (strcmp(P_recv, "UPDATE") == 0)) 
                && (auto_answer == true)){
-    L_res = 4 ;
-  }
-
-  return (L_res) ;
-  
-}
-
-
-bool call::automaticResponseMode(int P_case, char * P_recv)
+    return E_AM_AA;
+  } else {
+    return E_AM_DEFAULT;
+  }
+}
+
+void call::setLastMsg(const char *msg) {
+  last_recv_msg = (char *) realloc(last_recv_msg, strlen(msg) + 1);
+  strcpy(last_recv_msg, msg);
+}
+
+bool call::automaticResponseMode(T_AutoMode P_case, char * P_recv)
 {
 
   int res ;
@@ -3514,113 +3479,81 @@
   bool last_recv_msg_saved = false;
 
   switch (P_case) {
-  case 1: // response for an unexpected BYE
+  case E_AM_UNEXP_BYE: // response for an unexpected BYE
     // usage of last_ keywords
     last_recv_msg = (char *) realloc(last_recv_msg, strlen(P_recv) + 1);
     strcpy(last_recv_msg, P_recv);
 
     // The BYE is unexpected, count it
-    scenario[msg_index] -> nb_unexp++;
-    if (default_behavior) {
-      WARNING_P1("Aborting call on an unexpected BYE for call: %s", (id==NULL)?"none":id);
-    res = sendBuffer(createSendingMessage(
-                    (char*)"SIP/2.0 200 OK\n"
-                    "[last_Via:]\n"
-                    "[last_From:]\n"
-                    "[last_To:]\n"
-                    "[last_Call-ID:]\n"
-                    "[last_CSeq:]\n"
-                    "Contact: <sip:[local_ip]:[local_port];transport=[transport]>\n"
-                    "Content-Length: 0\n"
-                    , -1)) ;
-
-#ifdef __3PCC__
+    call_scenario->messages[msg_index] -> nb_unexp++;
+    if (default_behaviors & DEFAULT_BEHAVIOR_ABORTUNEXP) {
+      WARNING("Aborting call on an unexpected BYE for call: %s", (id==NULL)?"none":id);
+      if (default_behaviors & DEFAULT_BEHAVIOR_BYE) {
+	sendBuffer(createSendingMessage(get_default_message("200"), -1));
+      }
+
+      // if twin socket call => reset the other part here
+      if (twinSippSocket && (msg_index > 0)) {
+	res = sendCmdBuffer(createSendingMessage(get_default_message("3pcc_abort"), -1));
+      }
+      computeStat(CStat::E_CALL_FAILED);
+      computeStat(CStat::E_FAILED_UNEXPECTED_MSG);
+      delete this;
+    } else {
+      WARNING("Continuing call on an unexpected BYE for call: %s", (id==NULL)?"none":id);
+    }
+      break ;
+      
+  case E_AM_UNEXP_CANCEL: // response for an unexpected cancel
+    // usage of last_ keywords
+    last_recv_msg = (char *) realloc(last_recv_msg, strlen(P_recv) + 1);
+    strcpy(last_recv_msg, P_recv);
+
+    // The CANCEL is unexpected, count it
+    call_scenario->messages[msg_index] -> nb_unexp++;
+    if (default_behaviors & DEFAULT_BEHAVIOR_ABORTUNEXP) {
+      WARNING("Aborting call on an unexpected CANCEL for call: %s", (id==NULL)?"none":id);
+      if (default_behaviors & DEFAULT_BEHAVIOR_BYE) {
+	sendBuffer(createSendingMessage(get_default_message("200"), -1));
+      }
+    
     // if twin socket call => reset the other part here 
     if (twinSippSocket && (msg_index > 0)) {
       res = sendCmdBuffer
-      (createSendingMessage((char*)"call-id: [call_id]\ninternal-cmd: abort_call\n", -1));
-    }
-#endif /* __3PCC__ */
-      CStat::instance()->computeStat(CStat::E_CALL_FAILED);
-      CStat::instance()->computeStat(CStat::E_FAILED_UNEXPECTED_MSG);
-      delete_call(id);
+      (createSendingMessage(get_default_message("3pcc_abort"), -1));
+    }
+    
+    computeStat(CStat::E_CALL_FAILED);
+    computeStat(CStat::E_FAILED_UNEXPECTED_MSG);
+    delete this;
     } else {
-      WARNING_P1("Continuing call on an unexpected BYE for call: %s", (id==NULL)?"none":id);
-    }
-      break ;
-      
-  case 2: // response for an unexpected cancel
-    // usage of last_ keywords
-    last_recv_msg = (char *) realloc(last_recv_msg, strlen(P_recv) + 1);
-    strcpy(last_recv_msg, P_recv);
-
-    // The CANCEL is unexpected, count it
-    scenario[msg_index] -> nb_unexp++;
-    if (default_behavior) {
-      WARNING_P1("Aborting call on an unexpected CANCEL for call: %s", (id==NULL)?"none":id);
-    res = sendBuffer(createSendingMessage(
-                      (char*)"SIP/2.0 200 OK\n"
-                      "[last_Via:]\n"
-                      "[last_From:]\n"
-                      "[last_To:]\n"
-                      "[last_Call-ID:]\n"
-                      "[last_CSeq:]\n"
-                      "Contact: sip:sipp@[local_ip]:[local_port]\n"
-                      "Content-Length: 0\n"
-                      , -1)) ;
-    
-#ifdef __3PCC__
-    // if twin socket call => reset the other part here 
-    if (twinSippSocket && (msg_index > 0)) {
-      res = sendCmdBuffer
-      (createSendingMessage((char*)"call-id: [call_id]\ninternal-cmd: abort_call\n", -1));
-    }
-#endif /* __3PCC__ */
-    
-    CStat::instance()->computeStat(CStat::E_CALL_FAILED);
-    CStat::instance()->computeStat(CStat::E_FAILED_UNEXPECTED_MSG);
-    delete_call(id);
-    } else {
-      WARNING_P1("Continuing call on unexpected CANCEL for call: %s", (id==NULL)?"none":id);
+      WARNING("Continuing call on unexpected CANCEL for call: %s", (id==NULL)?"none":id);
     }
     break ;
       
-  case 3: // response for a random ping
+  case E_AM_PING: // response for a random ping
     // usage of last_ keywords
     last_recv_msg = (char *) realloc(last_recv_msg, strlen(P_recv) + 1);
     strcpy(last_recv_msg, P_recv);
     
-   if (default_behavior) {
-    WARNING_P1("Automatic response mode for an unexpected PING for call: %s", (id==NULL)?"none":id);
-    count_in_stats = false; // Call must not be counted in statistics
-    res = sendBuffer(createSendingMessage(
-                    (char*)"SIP/2.0 200 OK\n"
-                    "[last_Via:]\n"
-                    "[last_Call-ID:]\n"
-                    "[last_To:]\n"
-                    "[last_From:]\n"
-                    "[last_CSeq:]\n"
-                    "Contact: sip:sipp@[local_ip]:[local_port]\n"
-                    "Content-Length: 0\n"
-                    , -1)) ;
+   if (default_behaviors & DEFAULT_BEHAVIOR_PINGREPLY) {
+    WARNING("Automatic response mode for an unexpected PING for call: %s", (id==NULL)?"none":id);
+    sendBuffer(createSendingMessage(get_default_message("200"), -1));
     // Note: the call ends here but it is not marked as bad. PING is a 
     //       normal message.
-#ifdef __3PCC__
     // if twin socket call => reset the other part here 
     if (twinSippSocket && (msg_index > 0)) {
-      res = sendCmdBuffer
-      (createSendingMessage((char*)"call-id: [call_id]\ninternal-cmd: abort_call\n",-1));
-    }
-#endif /* __3PCC__ */
+      res = sendCmdBuffer(createSendingMessage(get_default_message("3pcc_abort"), -1));
+    }
     
-    CStat::instance()->computeStat(CStat::E_AUTO_ANSWERED);
-    delete_call(id);
+    CStat::globalStat(CStat::E_AUTO_ANSWERED);
+    delete this;
     } else {
-      WARNING_P1("Do not answer on an unexpected PING for call: %s", (id==NULL)?"none":id);
+      WARNING("Do not answer on an unexpected PING for call: %s", (id==NULL)?"none":id);
     }
     break ;
 
-  case 4: // response for a random INFO, UPDATE or NOTIFY
+  case E_AM_AA: // response for a random INFO, UPDATE or NOTIFY
     // store previous last msg if msg is INFO, UPDATE or NOTIFY
     // restore last_recv_msg to previous one
     // after sending ok
@@ -3634,17 +3567,8 @@
     last_recv_msg = (char *) realloc(last_recv_msg, strlen(P_recv) + 1);
     strcpy(last_recv_msg, P_recv);
 
-    WARNING_P1("Automatic response mode for an unexpected INFO, UPDATE or NOTIFY for call: %s", (id==NULL)?"none":id);
-    res = sendBuffer(createSendingMessage(
-                    (char*)"SIP/2.0 200 OK\n"
-                    "[last_Via:]\n"
-                    "[last_Call-ID:]\n"
-                    "[last_To:]\n"
-                    "[last_From:]\n"
-                    "[last_CSeq:]\n"
-                    "Contact: sip:sipp@[local_ip]:[local_port]\n"
-                    "Content-Length: 0\n"
-                    , -1)) ;
+    WARNING("Automatic response mode for an unexpected INFO, UPDATE or NOTIFY for call: %s", (id==NULL)?"none":id);
+    sendBuffer(createSendingMessage(get_default_message("200"), -1));
 
     // restore previous last msg
     if (last_recv_msg_saved == true) {
@@ -3655,17 +3579,16 @@
         old_last_recv_msg = NULL;
       }
     }
-    CStat::instance()->computeStat(CStat::E_AUTO_ANSWERED);
+    CStat::globalStat(CStat::E_AUTO_ANSWERED);
     return true;
     break;
 
     default:
-    ERROR_P1("Internal error for automaticResponseMode - mode %d is not implemented!", P_case);
+    ERROR("Internal error for automaticResponseMode - mode %d is not implemented!", P_case);
     break ;
   }
 
   return false;
-  
 }
 
 #ifdef PCAPPLAY

Modified: sip-tester/trunk/debian/changelog
URL: http://svn.debian.org/wsvn/pkg-voip/sip-tester/trunk/debian/changelog?rev=6624&op=diff
==============================================================================
--- sip-tester/trunk/debian/changelog (original)
+++ sip-tester/trunk/debian/changelog Sun Jan  4 03:39:23 2009
@@ -1,3 +1,10 @@
+sip-tester (3.1-1) UNRELEASED; urgency=low
+
+  * (NOT RELEASED YET) New upstream release
+  * Update debian/watch
+
+ -- Mark Purcell <msp at debian.org>  Sun, 04 Jan 2009 13:50:05 +1100
+
 sip-tester (2.0.1-1.2) unstable; urgency=high
 
   * Non-maintainer upload by the Security Team.

Modified: sip-tester/trunk/debian/watch
URL: http://svn.debian.org/wsvn/pkg-voip/sip-tester/trunk/debian/watch?rev=6624&op=diff
==============================================================================
--- sip-tester/trunk/debian/watch (original)
+++ sip-tester/trunk/debian/watch Sun Jan  4 03:39:23 2009
@@ -1,6 +1,2 @@
-# Example watch control file for uscan
-# Rename this file to "watch" and then you can run the "uscan" command
-# to check for upstream updates and more.
-# Site		Directory		Pattern			Version	Script
-version=2
-http://jaist.dl.sourceforge.net/sourceforge/sipp/sipp-(.*).tar.gz
+version=3
+http://sf.net/sipp/sipp.(.+)\.src\.tar\.gz debian svn-upgrade

Modified: sip-tester/trunk/sipp.hpp
URL: http://svn.debian.org/wsvn/pkg-voip/sip-tester/trunk/sipp.hpp?rev=6624&op=diff
==============================================================================
--- sip-tester/trunk/sipp.hpp (original)
+++ sip-tester/trunk/sipp.hpp Sun Jan  4 03:39:23 2009
@@ -45,7 +45,13 @@
 #include <vector>
 #include <string>
 #include <map>
+#include <set>
 #include <math.h>
+#ifndef __SUNOS
+#include <curses.h>
+#else
+#include <stdarg.h>
+#endif
 
 #if defined(__HPUX) || defined(__SUNOS)
 #include <alloca.h>
@@ -56,11 +62,15 @@
 #include "xp_parser.h"
 #include "scenario.hpp"
 #include "screen.hpp"
+#include "task.hpp"
+#include "listener.hpp"
+#include "socketowner.hpp"
 #include "call.hpp"
 #include "comp.h"
 #include "stat.hpp"
 #include "actions.hpp"
 #include "variables.hpp"
+#include "infile.hpp"
 /* Open SSL stuff */
 #ifdef _USE_OPENSSL
 #include "sslcommon.h" 
@@ -92,17 +102,27 @@
 
 /************************** Constants **************************/
 
-#define SIPP_VERSION               20070516
+#ifdef SVN_VERSION
+# ifdef LOCAL_VERSION_EXTRA
+#  define SIPP_VERSION               SVN_VERSION LOCAL_VERSION_EXTRA
+# else
+#  define SIPP_VERSION               SVN_VERSION
+# endif
+#else
+# define SIPP_VERSION               "unknown"
+#endif
+
 #define T_UDP                      0
 #define T_TCP                      1
+#define T_TLS                      2
+
 #ifdef _USE_OPENSSL
-#define T_TLS                      2
 #define DEFAULT_TLS_CERT           ((char *)"cacert.pem")
 #define DEFAULT_TLS_KEY            ((char *)"cakey.pem")
 #define DEFAULT_TLS_CRL            ((char *)"")
-
-#endif
-#define TRANSPORT_TO_STRING(p)     ((p==1) ? "TCP" : ((p==2)? "TLS" :"UDP"))
+#endif
+
+#define TRANSPORT_TO_STRING(p)     ((p==T_TCP) ? "TCP" : ((p==T_TLS)? "TLS" :"UDP"))
 
 #define SIPP_MAXFDS                65536
 #define SIPP_MAX_MSG_SIZE          65536
@@ -119,6 +139,7 @@
 #define DISPLAY_SECONDARY_REPARTITION_SCREEN 6
 
 #define MAX_RECV_LOOPS_PER_CYCLE   1000
+#define MAX_SCHED_LOOPS_PER_CYCLE  1000
 #define NB_UPDATE_PER_CYCLE        1
 
 #define MAX_PATH                   250
@@ -130,13 +151,12 @@
 /******************** Default parameters ***********************/
 
 #define DEFAULT_RATE                 10.0
+#define DEFAULT_RATE_SCALE           1.0
 #define DEFAULT_RATE_PERIOD_MS       1000
 #define DEFAULT_TRANSPORT            T_UDP
 #define DEFAULT_PORT                 5060  
 #define DEFAULT_MEDIA_PORT           6000
-#ifdef __3PCC__
 #define DEFAULT_3PCC_PORT            6060
-#endif
 #define DEFAULT_SERVICE              ((char *)"service")
 #define DEFAULT_AUTH_PASSWORD        ((char *)"password")
 #define DEFAULT_REPORT_FREQ          1000
@@ -145,23 +165,35 @@
 #define DEFAULT_FREQ_DUMP_RTT        200
 #define DEFAULT_MAX_MULTI_SOCKET     50000
 #define DEFAULT_CTRL_SOCKET_PORT     8888
+#define DEFAULT_DEADCALL_WAIT	     33000
+
+#define DEFAULT_BEHAVIOR_NONE	     0
+#define DEFAULT_BEHAVIOR_BYE	     1
+#define DEFAULT_BEHAVIOR_ABORTUNEXP  2
+#define DEFAULT_BEHAVIOR_PINGREPLY   4
+
+#define DEFAULT_BEHAVIOR_ALL	     (DEFAULT_BEHAVIOR_BYE | DEFAULT_BEHAVIOR_ABORTUNEXP | DEFAULT_BEHAVIOR_PINGREPLY)
 
 /************ User controls and command line options ***********/
 
 extern int                duration                _DEFVAL(0);
 extern double             rate                    _DEFVAL(DEFAULT_RATE);
+extern double             rate_scale              _DEFVAL(DEFAULT_RATE_SCALE);
 extern int	          rate_increase           _DEFVAL(0);
 extern int	          rate_max	          _DEFVAL(0);
-extern int                users                   _DEFVAL(0);
+extern bool	          rate_quit		  _DEFVAL(true);
+extern int                users                   _DEFVAL(-1);
 extern int               rate_period_ms           _DEFVAL(DEFAULT_RATE_PERIOD_MS);
 extern unsigned long      defl_recv_timeout       _DEFVAL(0);
+extern unsigned long      defl_send_timeout       _DEFVAL(0);
 extern unsigned long      global_timeout          _DEFVAL(0);
 extern int                transport               _DEFVAL(DEFAULT_TRANSPORT);
 extern bool               retrans_enabled         _DEFVAL(1);
 extern int                max_udp_retrans         _DEFVAL(UDP_MAX_RETRANS);
 extern int                max_invite_retrans      _DEFVAL(UDP_MAX_RETRANS_INVITE_TRANSACTION);
 extern int                max_non_invite_retrans  _DEFVAL(UDP_MAX_RETRANS_NON_INVITE_TRANSACTION);
-extern bool               default_behavior        _DEFVAL(1);
+extern unsigned long      default_behaviors       _DEFVAL(DEFAULT_BEHAVIOR_ALL);
+extern unsigned long	  deadcall_wait		  _DEFVAL(DEFAULT_DEADCALL_WAIT);
 extern bool               pause_msg_ign           _DEFVAL(0);
 extern int                auto_answer             _DEFVAL(0);
 extern int                multisocket             _DEFVAL(0);
@@ -175,6 +207,7 @@
 extern unsigned long      report_freq             _DEFVAL(DEFAULT_REPORT_FREQ);
 extern unsigned long      report_freq_dumpLog     _DEFVAL
                                                 (DEFAULT_REPORT_FREQ_DUMP_LOG);
+extern bool		  periodic_rtd		  _DEFVAL(false);
 extern char		* stat_delimiter          _DEFVAL(";");
 
 extern bool               timeout_exit            _DEFVAL(false);
@@ -184,16 +217,20 @@
 
 extern unsigned int       max_multi_socket        _DEFVAL
                                                 (DEFAULT_MAX_MULTI_SOCKET);
+extern bool		  skip_rlimit		  _DEFVAL(false);
 
 extern unsigned int       timer_resolution        _DEFVAL(DEFAULT_TIMER_RESOLUTION);
 extern int                max_recv_loops          _DEFVAL(MAX_RECV_LOOPS_PER_CYCLE);
+extern int                max_sched_loops         _DEFVAL(MAX_SCHED_LOOPS_PER_CYCLE);
  
 extern char               local_ip[40];
 extern char               local_ip_escaped[42];
 extern bool               local_ip_is_ipv6;    
 extern int                local_port              _DEFVAL(0);
+extern char               control_ip[40];
+extern int                control_port            _DEFVAL(0);
 extern int                buff_size               _DEFVAL(65535);
-extern int                tcp_readsize            _DEFVAL(4096);
+extern int                tcp_readsize            _DEFVAL(65535);
 #ifdef PCAPPLAY
 extern int                hasMedia                _DEFVAL(0);
 #endif
@@ -216,7 +253,6 @@
 extern int                lose_packets            _DEFVAL(0);
 extern double             global_lost             _DEFVAL(0.0);
 extern char               remote_host[255]; 
-#ifdef __3PCC__
 extern char               twinSippHost[255];
 extern char               twinSippIp[40];
 extern char             * master_name;
@@ -224,12 +260,10 @@
 extern int                twinSippPort            _DEFVAL(DEFAULT_3PCC_PORT);
 extern bool               twinSippMode            _DEFVAL(false);
 extern bool               extendedTwinSippMode    _DEFVAL(false);
-#endif
-
+
+extern bool               nostdin                 _DEFVAL(false);        
 extern bool               backgroundMode          _DEFVAL(false);        
 extern bool               signalDump              _DEFVAL(false);        
-
-extern bool               ctrlEW                  _DEFVAL(false);
 
 extern int                currentScreenToDisplay  _DEFVAL
                                                   (DISPLAY_SCENARIO_SCREEN);
@@ -251,8 +285,6 @@
 extern bool               tdm_map[1024];
 
 #ifdef _USE_OPENSSL
-extern BIO                  *bio ;
-extern SSL                  *ssl_tcp_multiplex ;
 extern BIO                  *twinSipp_bio ;
 extern SSL                  *twinSipp_ssl ;
 extern char                 *tls_cert_name     _DEFVAL(DEFAULT_TLS_CERT) ;
@@ -262,36 +294,48 @@
 #endif
 
 // extern field file management
-typedef std::vector<std::string>    IN_FILE_CONTENTS;
-extern IN_FILE_CONTENTS   fileContents;
-extern int                numLinesInFile          _DEFVAL(0);
-
-extern int      new_socket(bool P_use_ipv6, int P_type_socket, int * P_status);
+typedef std::map<string, FileContents *> file_map;
+extern file_map inFiles;
+typedef std::map<string, str_int_map *> file_index;
+extern file_index infIndex;
+extern char *ip_file _DEFVAL(NULL);
+extern char *default_file _DEFVAL(NULL);
+
+// free user id list
+extern list<int> freeUsers;
+extern list<int> retiredUsers;
+extern AllocVariableTable *globalVariables       _DEFVAL(NULL);
+extern AllocVariableTable *userVariables         _DEFVAL(NULL);
+typedef std::map<int, VariableTable *> int_vt_map;
+extern int_vt_map          userVarMap;
+
+//extern int      new_socket(bool P_use_ipv6, int P_type_socket, int * P_status);
+extern struct   sipp_socket *new_sipp_socket(bool use_ipv6, int transport);
+struct sipp_socket *new_sipp_call_socket(bool use_ipv6, int transport, bool *existing);
+struct sipp_socket *sipp_accept_socket(struct sipp_socket *accept_socket);
+extern int	sipp_bind_socket(struct sipp_socket *socket, struct sockaddr_storage *saddr, int *port);
+extern int	sipp_connect_socket(struct sipp_socket *socket, struct sockaddr_storage *dest);
+extern int      sipp_reconnect_socket(struct sipp_socket *socket);
+extern void	sipp_customize_socket(struct sipp_socket *socket);
 extern int      delete_socket(int P_socket);
 extern int      min_socket          _DEFVAL(65535);
 extern int      select_socket       _DEFVAL(0);
 extern bool     socket_close        _DEFVAL(true);
 extern bool     test_socket         _DEFVAL(true);
-extern bool     socket_open         _DEFVAL(true);
 extern bool     maxSocketPresent    _DEFVAL(false);
-extern int      *tab_multi_socket;
 
 extern unsigned long getmilliseconds();
 extern unsigned long long getmicroseconds();
 
 /************************ Statistics **************************/
 
-extern unsigned long total_calls                  _DEFVAL(0);
 extern unsigned long last_report_calls            _DEFVAL(0);
 extern unsigned long nb_net_send_errors           _DEFVAL(0);
 extern unsigned long nb_net_cong                  _DEFVAL(0);
 extern unsigned long nb_net_recv_errors           _DEFVAL(0);
 extern bool          cpu_max                      _DEFVAL(false);
 extern bool          outbound_congestion          _DEFVAL(false);
-extern unsigned int  open_calls_peak              _DEFVAL(0);
-extern unsigned long open_calls_peak_time         _DEFVAL(0);
 extern int           open_calls_user_setting      _DEFVAL(0);
-extern int           nb_out_of_the_blue           _DEFVAL(0);
 extern int           resynch_send                 _DEFVAL(0);
 extern int           resynch_recv                 _DEFVAL(0);
 extern unsigned long rtp_pckts                    _DEFVAL(0);
@@ -305,7 +349,6 @@
 
 /************* Rate Control & Contexts variables **************/
 
-extern unsigned int  open_calls                   _DEFVAL(0);
 extern int           last_running_calls           _DEFVAL(0);
 extern int           last_woken_calls             _DEFVAL(0);
 extern int           last_paused_calls            _DEFVAL(0);
@@ -313,7 +356,6 @@
 extern unsigned long last_rate_change_time        _DEFVAL(0);
 extern unsigned long last_report_time             _DEFVAL(0);
 extern unsigned long last_dump_time               _DEFVAL(0);
-extern unsigned long calls_since_last_rate_change _DEFVAL(0);
 
 /********************** Clock variables ***********************/
 
@@ -329,8 +371,8 @@
 
 /*********************** Global Sockets  **********************/
 
-extern int           main_socket                  _DEFVAL(0);
-extern int           tcp_multiplex                _DEFVAL(0);
+extern struct sipp_socket *main_socket            _DEFVAL(0);
+extern struct sipp_socket *tcp_multiplex          _DEFVAL(0);
 extern int           media_socket                 _DEFVAL(0);
 extern int           media_socket_video           _DEFVAL(0);
 
@@ -339,17 +381,19 @@
 extern int           user_port                    _DEFVAL(0);
 extern char          hostname[80];
 extern bool          is_ipv6                      _DEFVAL(false);
-extern int           start_calls                  _DEFVAL(0);
-extern double        reset_number                 _DEFVAL(0);
+
+extern int           reset_number                 _DEFVAL(0);
 extern int	     reset_close                  _DEFVAL(1);
 extern int	     reset_sleep                  _DEFVAL(1000);
+extern bool	     sendbuffer_warn              _DEFVAL(false);
+/* A list of sockets pending reset. */
+extern set<struct sipp_socket *> sockets_pending_reset;
 
 extern struct        addrinfo * local_addr_storage;
 
-#ifdef __3PCC__
-extern int           twinSippSocket               _DEFVAL(0);
-extern int           localTwinSippSocket          _DEFVAL(0);
-extern struct        sockaddr_storage twinSipp_sockaddr;
+extern struct sipp_socket *twinSippSocket         _DEFVAL(NULL);
+extern struct sipp_socket *localTwinSippSocket    _DEFVAL(NULL);
+extern struct sockaddr_storage twinSipp_sockaddr;
 
 /* 3pcc extended mode */
 typedef struct _T_peer_infos {
@@ -357,22 +401,20 @@
                int                        peer_port;
                struct sockaddr_storage    peer_sockaddr;
                char                       peer_ip[40];
-               int                        peer_socket ;
+               struct sipp_socket         *peer_socket ;
                } T_peer_infos;
 
 typedef std::map<std::string, char * > peer_addr_map;
 extern peer_addr_map peer_addrs;
 typedef std::map<std::string, T_peer_infos> peer_map;
 extern peer_map      peers;
-typedef std::map<int, std::string > peer_socket_map;
+typedef std::map<struct sipp_socket *, std::string > peer_socket_map;
 extern peer_socket_map peer_sockets;
-extern int           local_sockets[MAX_LOCAL_TWIN_SOCKETS];
+extern struct sipp_socket *local_sockets[MAX_LOCAL_TWIN_SOCKETS];
 extern int           local_nb                    _DEFVAL(0);
 extern int           peers_connected             _DEFVAL(0);
-#endif
-
-extern struct        sockaddr_storage remote_sockaddr;
-
+
+extern struct	     sockaddr_storage remote_sockaddr;
 extern short         use_remote_sending_addr      _DEFVAL(0);
 extern struct        sockaddr_storage remote_sending_sockaddr;
 
@@ -387,42 +429,37 @@
 extern FILE * screenf                             _DEFVAL(0);
 extern FILE * logfile                             _DEFVAL(0);
 extern FILE * messagef                            _DEFVAL(0);
-extern FILE * timeoutf                            _DEFVAL(0);
+extern FILE * shortmessagef                       _DEFVAL(0);
+extern FILE * countf                              _DEFVAL(0);
+// extern FILE * timeoutf                            _DEFVAL(0);
 extern bool   useMessagef                         _DEFVAL(0);
+extern bool   useShortMessagef                    _DEFVAL(0);
 extern bool   useScreenf                          _DEFVAL(0);
 extern bool   useLogf                             _DEFVAL(0);
-extern bool   useTimeoutf                         _DEFVAL(0);
+// should we overwrite the existing files?
+extern bool   messagef_overwrite		  _DEFVAL(true);
+extern bool   shortmessagef_overwrite		  _DEFVAL(true);
+extern bool   errorf_overwrite			  _DEFVAL(true);
+extern bool   logfile_overwrite			  _DEFVAL(true);
+//extern bool   useTimeoutf                         _DEFVAL(0);
 extern bool   dumpInFile                          _DEFVAL(0);
 extern bool   dumpInRtt                           _DEFVAL(0);
+extern bool   useCountf                           _DEFVAL(0);
 extern char * scenario_file;
 extern char * slave_cfg_file;
 
-#define TRACE_MSG(arg)      \
-{                           \
-  if(messagef) {            \
-    FILE * s = messagef;    \
-    fprintf arg;            \
-    fflush(messagef);       \
-  }                         \
-}
-
-#define LOG_MSG(arg)        \
-{                           \
-  if(logfile) {             \
-    FILE * s = logfile;     \
-    fprintf arg;            \
-    fflush(logfile);        \
-  }                         \
-}
-
-#define TRACE_TIMEOUT(arg)  \
-{                           \
-  if(timeoutf) {            \
-    FILE * s = timeoutf;    \
-    fprintf arg;            \
-    fflush(timeoutf);       \
-  }                         \
-}
+extern unsigned long long max_log_size		  _DEFVAL(0);
+extern unsigned long long ringbuffer_size	  _DEFVAL(0);
+extern int    ringbuffer_files			  _DEFVAL(0);
+
+extern char   screen_last_error[32768];
+extern char   screen_logfile[MAX_PATH]            _DEFVAL("");
+extern FILE   * screen_errorf			  _DEFVAL(NULL);
+
+void rotate_messagef();
+void rotate_shortmessagef();
+void rotate_logfile();
+void rotate_errorf();
 
 /********************* Mini-Parser Routines *******************/
 
@@ -433,15 +470,67 @@
 
 /********************** Network Interfaces ********************/
 
-void sipp_customize_socket(int socket);
 int send_message(int s, void ** comp_state, char * msg);
 #ifdef _USE_OPENSSL
 int send_message_tls(SSL *s, void ** comp_state, char * msg);
 #endif
 
-void pollset_remove(int idx);
-void remove_from_pollfiles(int sock);
-int pollset_add(call * p_call, int socket);
+/* Socket Buffer Management. */
+#define NO_COPY 0
+#define DO_COPY 1
+struct socketbuf *alloc_socketbuf(char *buffer, size_t size, int copy);
+void free_socketbuf(struct socketbuf *socketbuf);
+
+/* These buffers lets us read past the end of the message, and then split it if
+ * required.  This eliminates the need for reading a message octet by octet and
+ * performing a second read for the content length. */
+struct socketbuf {
+	char *buf;
+	size_t len;
+	size_t offset;
+	struct sockaddr_storage addr;
+	struct socketbuf *next;
+};
+
+/* This is an abstraction of a socket, which provides buffers for input and
+ * output. */
+struct sipp_socket {
+	int  ss_count; /* How many users are there of this socket? */
+
+	int ss_transport; /* T_TCP, T_UDP, or T_TLS. */
+	bool ss_ipv6;
+	bool ss_control; /* Is this a control socket? */
+	bool ss_call_socket; /* Is this a call socket? */
+
+	int ss_fd;	/* The underlying file descriptor for this socket. */
+	void *ss_comp_state; /* The compression state. */
+#ifdef _USE_OPENSSL
+	SSL *ss_ssl;	/* The underlying SSL descriptor for this socket. */
+	BIO *ss_bio;	/* The underlying BIO descriptor for this socket. */
+#endif
+	struct sockaddr_storage ss_remote_sockaddr; /* Who we are talking to. */
+	struct sockaddr_storage ss_dest; /* Who we are talking to. */
+
+
+	int ss_pollidx; /* The index of this socket in our poll structures. */
+	bool ss_congested; /* Is this socket congested? */
+	bool ss_invalid; /* Has this socket been closed remotely? */
+
+	struct socketbuf *ss_in; /* Buffered input. */
+	size_t ss_msglen;	/* Is there a complete SIP message waiting, and if so how big? */
+	struct socketbuf *ss_out; /* Buffered output. */
+};
+
+/* Write data to a socket. */
+int write_socket(struct sipp_socket *socket, char *buffer, ssize_t len, int flags, struct sockaddr_storage *dest);
+/* Mark a socket as "bad". */
+void sipp_socket_invalidate(struct sipp_socket *socket);
+/* Actually free the socket. */
+void sipp_close_socket(struct sipp_socket *socket);
+
+#define WS_EAGAIN 1 /* Return EAGAIN if there is no room for writing the message. */
+#define WS_BUFFER 2 /* Buffer the message if there is no room for writing the message. */
+
 
 #if defined (__hpux) || defined (__alpha) && !defined (__FreeBSD__)
 #define sipp_socklen_t  int
@@ -465,17 +554,18 @@
 char *get_peer_addr(char *);
 int get_decimal_from_hex(char hex);
 
-int reset_connections() ;
-int close_calls();
+bool reconnect_allowed();
+void reset_connection(struct sipp_socket *);
+void close_calls(struct sipp_socket *);
 int close_connections();
 int open_connections();
 void timeout_alarm(int);
 
 /* extended 3PCC mode */
-int * get_peer_socket(char *);
-bool is_a_peer_socket(int);
-bool is_a_local_socket(int);
-void connect_to_peer (char *, int *, sockaddr_storage *, char *, int *);
+struct sipp_socket **get_peer_socket(char *);
+bool is_a_peer_socket(struct sipp_socket *);
+bool is_a_local_socket(struct sipp_socket *);
+void connect_to_peer (char *, int , sockaddr_storage *, char *, struct sipp_socket **);
 void connect_to_all_peers ();
 void connect_local_twin_socket(char *);
 void close_peer_sockets();
@@ -488,4 +578,15 @@
 #undef extern
 #endif
 
+/* THis must go after the GLOBALS_FULL_DEFINITION, because we need the extern keyword. */
+#ifdef __cplusplus
+extern "C" {
+#endif
+int TRACE_MSG(char *fmt, ...);
+int TRACE_SHORTMSG(char *fmt, ...);
+int LOG_MSG(char *fmt, ...);
+#ifdef __cplusplus
+}
+#endif
+
 #endif // __SIPP__




More information about the Pkg-voip-commits mailing list