[Pkg-voip-commits] r6620 - in /sip-tester/branches/upstream/current: Makefile call.cpp sipp.hpp

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


Author: msp
Date: Sun Jan  4 02:02:39 2009
New Revision: 6620

URL: http://svn.debian.org/wsvn/pkg-voip/?sc=1&rev=6620
Log:
[svn-upgrade] Integrating new upstream version, sip-tester (3.0)

Modified:
    sip-tester/branches/upstream/current/Makefile
    sip-tester/branches/upstream/current/call.cpp
    sip-tester/branches/upstream/current/sipp.hpp

Modified: sip-tester/branches/upstream/current/Makefile
URL: http://svn.debian.org/wsvn/pkg-voip/sip-tester/branches/upstream/current/Makefile?rev=6620&op=diff
==============================================================================
--- sip-tester/branches/upstream/current/Makefile (original)
+++ sip-tester/branches/upstream/current/Makefile Sun Jan  4 02:02:39 2009
@@ -24,8 +24,8 @@
 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
 
 # Libraries directories
 LIBDIR_linux=
@@ -63,7 +63,7 @@
 
 # C compiler
 CC_hpux=aCC
-CC_linux=cc  
+CC_linux=gcc  
 CC_freebsd=cc  
 CC_tru64=cc  
 CC_SunOS=gcc
@@ -73,7 +73,7 @@
 
 # C++ compiler mapping
 CPP_hpux=aCC  
-CPP_linux=gcc  
+CPP_linux=g++  
 CPP_freebsd=g++  
 CPP_tru64=cxx  
 CPP_SunOS=g++
@@ -138,15 +138,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_freebsd= -lcurses -pthread -L /usr/local/lib
 LIBS_SunOS= -lcurses -lpthread -lnsl -lsocket -lstdc++ -lm -ldl -L /usr/local/ssl/lib/
 LIBS_Cygwin= -lcurses -lpthread -lstdc++ -L /usr/lib/WpdPack/Lib
 LIBS_Darwin= -lcurses
 LIBS=$(LIBS_$(SYSTEM)) $(EXTRALIBS)
 
 # Include directories
-INCDIR_linux=-I. -I/opt/openssl/include
-INCDIR_freebsd=-I. -I/opt/openssl/include
+INCDIR_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 +169,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 +190,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

Modified: sip-tester/branches/upstream/current/call.cpp
URL: http://svn.debian.org/wsvn/pkg-voip/sip-tester/branches/upstream/current/call.cpp?rev=6620&op=diff
==============================================================================
--- sip-tester/branches/upstream/current/call.cpp (original)
+++ sip-tester/branches/upstream/current/call.cpp Sun Jan  4 02:02:39 2009
@@ -48,19 +48,19 @@
 #include "sipp.hpp"
 #include "assert.h"
 
-#define KEYWORD_SIZE 256
-
 #ifdef _USE_OPENSSL
 extern  SSL                 *ssl_list[];
 extern  struct pollfd        pollfiles[];
 extern  SSL_CTX             *sip_trp_ssl_ctx;
 #endif
 
-extern  map<string, int>     map_perip_fd;
+extern  map<string, struct sipp_socket *>     map_perip_fd;
 
 call_map calls;
 call_list running_calls;
 timewheel paused_calls;
+
+ socket_call_map_map socket_to_calls;
 
 #ifdef PCAPPLAY
 /* send_packets pthread wrapper */
@@ -100,7 +100,29 @@
   } 
 }
 
-call * add_call(char * call_id, bool ipv6)
+struct sipp_socket *call::associate_socket(struct sipp_socket *socket) {
+  if (socket) {
+    this->call_socket = socket;
+    add_call_to_socket(socket, this);
+  }
+  return socket;
+}
+
+struct sipp_socket *call::dissociate_socket() {
+  struct sipp_socket *ret = this->call_socket;
+
+  remove_call_from_socket(this->call_socket, this);
+  this->call_socket = NULL;
+
+  return ret;
+}
+
+call * add_call(char * call_id , bool use_ipv6, int userId)
+{
+  return add_call(call_id, use_ipv6, userId, false /* Is not automatic. */);
+}
+
+call * add_call(char * call_id , bool use_ipv6, int userId, bool isAutomatic)
 {
   call * new_call;
   unsigned int nb;
@@ -119,7 +141,7 @@
     }
   }
 
-  new_call = new call(call_id, ipv6);
+  new_call = new call(call_id, userId, use_ipv6, isAutomatic);
 
   if(!new_call) {
     ERROR("Memory Overflow");
@@ -134,7 +156,12 @@
   new_call -> tdm_map_number = nb - 1;
 
   /* Vital counters update */
-  next_number++;
+  if (!isAutomatic) {
+    next_number++;
+  } else {
+    /* We do not update the call_id counter, for we create here a call */
+    /* to answer to an out of call message */
+  }
   open_calls++;
 
   /* Statistics update */
@@ -145,28 +172,31 @@
     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;
+call * add_call(char * call_id , struct sipp_socket *socket) {
+  call *new_call = add_call(call_id, socket->ss_ipv6, 0 /* No User. */, false /* Not Auto. */);
+  new_call->associate_socket(socket);
   return new_call;
 }
-#endif
-
-
-call * add_call(bool ipv6)
+
+call * add_call(char * call_id , struct sipp_socket *socket, bool isAutomatic) {
+  call *new_call = add_call(call_id, socket->ss_ipv6, 0 /* No User. */, isAutomatic);
+  new_call->associate_socket(socket);
+  return new_call;
+}
+
+call * add_call(int userId, bool ipv6)
 {
   static char call_id[MAX_HEADER_LEN];
-  
+
   char * src = call_id_string;
   int count = 0;
-  
+
   if(!next_number) { next_number ++; }
-  
+
   while (*src && count < MAX_HEADER_LEN-1) {
       if (*src == '%') {
           ++src;
@@ -190,7 +220,7 @@
   }
   call_id[count] = 0;
 
-  return add_call(call_id, ipv6);
+  return add_call(call_id, ipv6, userId);
 }
 
 call * get_call(char * call_id)
@@ -396,6 +426,60 @@
 
 int timewheel::size() {
   return count;
+}
+
+/* The caller must delete this list. */
+call_list *get_calls_for_socket(struct sipp_socket *socket) {
+  call_list *l = new call_list;
+
+  socket_call_map_map::iterator map_it = socket_to_calls.find(socket);
+
+  /* No map defined for this socket. */
+  if (map_it == socket_to_calls.end()) {
+    return l;
+  }
+
+  call_map *socket_call_map = (call_map *) map_it->second;
+  call_map::iterator call_it;
+
+  for (call_it = socket_call_map->begin();
+       call_it != socket_call_map->end();
+       call_it++) {
+	l->insert(l->end(), call_it->second);
+  }
+
+  return l;
+}
+
+void add_call_to_socket(struct sipp_socket *socket, call *call) {
+  socket_call_map_map::iterator map_it = socket_to_calls.find(socket);
+  /* No map defined for this socket. */
+  if (map_it == socket_to_calls.end()) {
+    socket_to_calls.insert(socket_map_pair(socket, new call_map));
+    map_it = socket_to_calls.find(socket);
+    assert(map_it != socket_to_calls.end());
+  }
+
+ call_map *socket_call_map = (call_map *) map_it->second;
+ socket_call_map->insert(string_call_pair(call->id, call));
+}
+
+void remove_call_from_socket(struct sipp_socket *socket, call *call) {
+  socket_call_map_map::iterator map_it = socket_to_calls.find(socket);
+  /* We must have  a map for this socket. */
+  assert(map_it != socket_to_calls.end());
+
+  call_map *socket_call_map = (call_map *) map_it->second;
+  call_map::iterator call_it = socket_call_map->find(call->id);
+  /* And our call must exist in the map. */
+  assert(call_it != socket_call_map->end());
+  socket_call_map->erase(call_it);
+
+  /* If we have no more calls, we can delete this entry. */
+  if (socket_call_map->begin() == socket_call_map->end()) {
+    delete socket_call_map;
+    socket_to_calls.erase(map_it);
+  }
 }
 
 #ifdef PCAPPLAY
@@ -566,10 +650,7 @@
 
 /******************* 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)
+call::call(char * p_id, int userId, bool ipv6, bool isAutomatic) : use_ipv6(ipv6)
 {
   memset(this, 0, sizeof(call));
   id = strdup(p_id);
@@ -587,24 +668,16 @@
   m_bio = NULL ;
 #endif
 
-  pollset_index = 0 ;
-  poll_flag_write = false ;
-
   call_remote_socket = 0;
   
   // initialising the CallVariable with the Scenario variable
-  bool test_var=false;
-  int i,j;
-  for(i=0; i<SCEN_VARIABLE_SIZE; i++) 
+  int i;
+  if (maxVariableUsed >= 0) {
+	M_callVariableTable = new CCallVariable *[maxVariableUsed + 1];
+  }
+  for(i=0; i<=maxVariableUsed; i++)
     {
-      for (j=0; j<SCEN_MAX_MESSAGES; j++)
-      {
-      if(scenVariableTable[i][j] != NULL) {
-                test_var=true;
-                break;
-            }
-        }
-      if (test_var) {
+      if (variableUsed[i]) {
         M_callVariableTable[i] = new CCallVariable();
         if (M_callVariableTable[i] == NULL) {
           ERROR ("call variable allocation failed");
@@ -624,14 +697,19 @@
   // by default, last action result is NO_ERROR
   last_action_result = call::E_AR_NO_ERROR;
 
-  if (InputFileRandomOrder == m_usage) {
-      m_localLineNumber = rand() % numLinesInFile;
-  } else {
-      m_localLineNumber = m_counter++;
-      if (m_counter >= numLinesInFile) {
-          m_counter = 0;
-      }
-
+  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);
+    }
   }
 
 #ifdef PCAPPLAY
@@ -645,6 +723,7 @@
 
   peer_tag = NULL;
   recv_timeout = 0;
+  send_timeout = 0;
 }
 
 call::~call()
@@ -658,56 +737,22 @@
                                    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++) {
+  sipp_close_socket(dissociate_socket());
+  if (call_remote_socket) {
+    sipp_close_socket(call_remote_socket);
+  }
+
+  /* Deletion of the call variable */
+  for(int i=0; i<=maxVariableUsed; i++) {
     if(M_callVariableTable[i] != NULL) {
       delete M_callVariableTable[i] ;
       M_callVariableTable[i] = NULL;
     }
+  }
+  if(M_callVariableTable) { delete M_callVariableTable; }
+  delete m_lineNumber;
+  if (userId) {
+    freeUsers.push_front(userId);
   }
 
   if(id) { free(id); }
@@ -723,6 +768,7 @@
        free(next_req_url);
   }
 
+
 #ifdef _USE_OPENSSL
   if(dialog_authentication) {
        free(dialog_authentication);
@@ -730,49 +776,50 @@
 #endif
   call_established= false ;
 }
- 
+
 void call::connect_socket_if_needed()
 {
-#ifdef _USE_OPENSSL
-   int err;
-   SSL      *L_ssl_tcp_multiplex=NULL ;
-#endif
+  bool existing;
 
   if(call_socket) return;
   if(!multisocket) return;
 
   if(transport == T_UDP) {
     struct sockaddr_storage saddr;
-    sipp_socklen_t len;
-    
-    int L_status = 0 ;	   // no new socket
-
-    if(toolMode != MODE_CLIENT) return;
+
+    if(toolMode != MODE_CLIENT)
+      return;
 
     char peripaddr[256];
     if (!peripsocket) {
-      if ((call_socket = new_socket(use_ipv6, SOCK_DGRAM, &L_status)) == -1) {
-        ERROR_NO("Unable to get a UDP socket");
-       }
-     } else {
-       getIpFieldFromInputFile(peripfield, m_localLineNumber, peripaddr);
-       map<string, int>::iterator i;
-       i = map_perip_fd.find(peripaddr);
-       if (i == map_perip_fd.end()) {
-         // Socket does not exist
-    if ((call_socket = new_socket(use_ipv6, SOCK_DGRAM, &L_status)) == -1) {
-      ERROR_NO("Unable to get a UDP socket");
-         } else {
-           map_perip_fd[peripaddr] = call_socket;
-         }
-       } else {
-         // Socket exists already
-         call_socket = i->second;
-       }
-    }
-    
-
-    if (L_status) {
+      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, 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;
+    }
+
     memset(&saddr, 0, sizeof(struct sockaddr_storage));
 
     memcpy(&saddr,
@@ -808,56 +855,27 @@
       }
     }
 
-    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;
     }
     
-    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))) {
-      
+    sipp_customize_socket(call_socket);
+
+    if (use_remote_sending_addr) {
+      L_dest = &remote_sending_sockaddr;
+    }
+
+    if (sipp_connect_socket(call_socket, L_dest)) {
       if (reset_number > 0) {
         if(errno == EINVAL){
           /* This occurs sometime on HPUX but is not a true INVAL */
@@ -867,48 +885,14 @@
         }
         start_calls = 1;
       } else {
-      if(errno == EINVAL){
-        /* This occurs sometime on HPUX but is not a true INVAL */
-        ERROR("Unable to connect a TCP socket, remote peer error");
-      } else {
-        ERROR_NO("Unable to connect a TCP socket");
-      }
-      }
-    } else {
-#ifdef _USE_OPENSSL
-     if ( transport == T_TLS ) {
-       m_ctx_ssl = sip_trp_ssl_ctx ;
-       
-       
-      if (!(L_ssl_tcp_multiplex = SSL_new(m_ctx_ssl))){
-            ERROR("Unable to create SSL object : Problem with SSL_new() \n");
-       }
-
-       // if ( (m_bio = BIO_new_socket(call_socket,BIO_NOCLOSE)) == NULL) {
-        
-       if ( (m_bio = BIO_new_socket(call_socket,BIO_CLOSE)) == NULL) {
-             ERROR("Unable to create BIO object:Problem with BIO_new_socket()\n");
-       }
-        
-
-       // SSL_set_fd(L_ssl_tcp_multiplex, call_socket);
-       SSL_set_bio(L_ssl_tcp_multiplex,m_bio,m_bio);
-       // SSL_set_bio(L_ssl_tcp_multiplex,bio,bio);
-
-      if ( (err = SSL_connect(L_ssl_tcp_multiplex)) < 0 ) {
-           ERROR("Error in SSL connection \n");
-  }
-       ssl_list[call_socket] = L_ssl_tcp_multiplex;
-
-  
-     }
-#endif
-
-
-  /* Asks to receive incoming messages */
-  pollset_index = pollset_add(this, call_socket);
-    }
-  }
+	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");
+	}
+      }
+    }
   }
 }
 
@@ -937,23 +921,17 @@
 
 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, "%s\tS\t%s\tCSeq:%s\t%s\n",
+             CStat::instance()->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)));
     
@@ -962,95 +940,54 @@
     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_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");
 	  }
-        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) {
+	}
+      }
+    }
+    sock=call_remote_socket ;
+  }
+
+  rc = write_socket(sock, msg, strlen(msg), WS_BUFFER);
+  if(rc == -1 && errno == EWOULDBLOCK) {
+    return -1;
+  }
+
+  if(rc < 0) {
     CStat::instance()->computeStat(CStat::E_CALL_FAILED);
     CStat::instance()->computeStat(CStat::E_FAILED_CANNOT_SEND_MSG);
     delete_call(id);
   }
-  
+
   return rc; /* OK */
 }
 
 /* This method is used to send messages that are not */
 /* part of the XML scenario                          */
-int call::sendBuffer(char * msg) 
-{
-  int rc;
-
+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) {
+    ERROR_NO("Error sending raw message");
+  }
 }
 
 
@@ -1132,6 +1069,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 */
@@ -1154,12 +1092,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 +1113,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 +1192,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];
@@ -1271,7 +1275,14 @@
 
   /* Socket port must be known before string substitution */
   connect_socket_if_needed();
-  
+
+  assert(call_socket);
+
+  if (call_socket->ss_congested) {
+    *send_status = -1;
+    return NULL;
+  }
+
   if(scenario[index] -> send_scheme) {
     char * dest;
     dest = createSendingMessage(scenario[index] -> send_scheme, index);
@@ -1294,8 +1305,7 @@
     }
 
     if(send_status) {
-      *send_status = 
-        send_raw(msg_buffer, index);
+      *send_status = send_raw(msg_buffer, index);
     } else {
       send_raw(msg_buffer, index);
     }
@@ -1345,7 +1355,7 @@
   /* 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()))
+        (test <= maxVariableUsed && M_callVariableTable[test] != NULL && M_callVariableTable[test]->isSet()))
      ) {
     /* Branching possible, check the probability */
     int chance = scenario[msg_index]->chance;
@@ -1415,7 +1425,9 @@
           msg_index = labelArray[scenario[last_send_index]->on_timeout];
           next_retrans = 0;
           recv_timeout = 0;
-          if (msg_index < scenario_len) return true;
+          if (msg_index < scenario_len) {
+		return true;
+	  }
 
           // here if asked to go to the last label  delete the call
           CStat::instance()->computeStat(CStat::E_CALL_FAILED);
@@ -1470,9 +1482,21 @@
     /* Our pause is over. */
     paused_until = 0;
     return next();
-  } else if(scenario[msg_index] -> pause_function) {
+  } else if(scenario[msg_index] -> pause_distribution || scenario[msg_index]->pause_variable) {
     unsigned int pause;
-    pause  = scenario[msg_index] -> pause_function(scenario[msg_index]);
+    if (scenario[msg_index]->pause_distribution) {
+      pause  = (int)(scenario[msg_index] -> pause_distribution -> sample());
+    } else {
+      int varId = scenario[msg_index]->pause_variable;
+      if(varId <= maxVariableUsed && M_callVariableTable[varId]) {
+	pause = (int) M_callVariableTable[varId]->getDouble();
+      } else {
+	pause = 0;
+      }
+    }
+    if (pause < 0) {
+      pause = 0;
+    }
     if (pause > INT_MAX) {
       pause = INT_MAX;
     }
@@ -1481,7 +1505,7 @@
     /* Increment the number of sessions in pause state */
     ++scenario[msg_index]->sessions;
     return run(); /* In case delay is 0 */
-  } 
+  }
 #ifdef __3PCC__
   else if(scenario[msg_index] -> M_type == MSG_TYPE_SENDCMD) {
     int send_status;
@@ -1531,26 +1555,47 @@
      */
 
     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 (!scenario[msg_index]->send_scheme->isAck() &&
+        !scenario[msg_index]->send_scheme->isCancel() &&
+        !scenario[msg_index]->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_P2("Call-Id: %s, send timeout on message %d: aborting call",
+	      id, msg_index);
+	  CStat::instance()->computeStat(CStat::E_CALL_FAILED);
+	  CStat::instance()->computeStat(CStat::E_FAILED_TIMEOUT_ON_SEND);
+	  if (default_behavior) {
+	    return (abortCall());
+	  } else {
+	    delete_call(id);
+	    return false;
+	  }
+	}
+      } else if (scenario[msg_index]->timeout) {
+	/* Initialize the send timeout to the per message timeout. */
+	send_timeout = clock_tick + scenario[msg_index]->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 */
+    } else if(send_status < 0) { /* Send error */
+      /* The timeout will not be sent, so the timeout is no longer needed. */
+      send_timeout = 0;
       return false; /* call deleted */
     }
-    
+    /* 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);
@@ -1628,14 +1673,14 @@
         delete_call(id);
         return false;
       }
-    } else if ((scenario[msg_index]->retrans_delay) || (defl_recv_timeout)) {
-      if (scenario[msg_index]->retrans_delay)
+    } else if ((scenario[msg_index]->timeout) || (defl_recv_timeout)) {
+      if (scenario[msg_index]->timeout)
         // If timeout is specified on message receive, use it
-        recv_timeout = getmilliseconds() + scenario[msg_index]->retrans_delay;
+        recv_timeout = getmilliseconds() + scenario[msg_index]->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)) {
@@ -1649,48 +1694,59 @@
 
 bool call::process_unexpected(char * msg)
 {
+  char buffer[MAX_HEADER_LEN];
+  char *desc = buffer;
+
   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);
+
+  if (default_behavior) {
+	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 (scenario[msg_index] -> M_type == MSG_TYPE_RECV) {
+    if (scenario[msg_index] -> recv_request) {
+      desc += snprintf(desc, MAX_HEADER_LEN - (desc - buffer), "while expecting '%s' ", scenario[msg_index] -> recv_request);
+    } else {
+      desc += snprintf(desc, MAX_HEADER_LEN - (desc - buffer), "while expecting '%d' ", scenario[msg_index] -> recv_response);
+    }
+  } else if (scenario[msg_index] -> M_type == MSG_TYPE_SEND) {
+      desc += snprintf(desc, MAX_HEADER_LEN - (desc - buffer), "while sending ");
+  } else if (scenario[msg_index] -> M_type == MSG_TYPE_PAUSE) {
+      desc += snprintf(desc, MAX_HEADER_LEN - (desc - buffer), "while pausing ");
+  } else if (scenario[msg_index] -> M_type == MSG_TYPE_SENDCMD) {
+      desc += snprintf(desc, MAX_HEADER_LEN - (desc - buffer), "while sending command ");
+  } else if (scenario[msg_index] -> 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);
-  }
-  }
-  
+      desc += snprintf(desc, MAX_HEADER_LEN - (desc - buffer), "while in message type %d ", scenario[msg_index]->M_type);
+  }
+  desc += snprintf(desc, MAX_HEADER_LEN - (desc - buffer), "(index %d)", msg_index);
+
+  WARNING_P2("%s, received '%s'", buffer, msg);
+
   TRACE_MSG((s, "-----------------------------------------------\n"
              "Unexpected %s message received:\n\n%s\n",
              TRANSPORT_TO_STRING(transport),
              msg));
-  
+
   if (default_behavior) {
-#ifdef __3PCC__
-  // if twin socket call => reset the other part here 
-  if (twinSippSocket && (msg_index > 0)) {
-    //WARNING_P2("call-ID '%s', internal-cmd: abort_call %s",id, "");
-    sendCmdBuffer
-      (createSendingMessage((char*)"call-id: [call_id]\ninternal-cmd: abort_call\n", -1));
-  }
-#endif /* __3PCC__ */
-
-  // usage of last_ keywords => for call aborting
-  last_recv_msg = (char *) realloc(last_recv_msg, strlen(msg) + 1);
-  strcpy(last_recv_msg, msg);
+    // 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\n", -1));
+    }
+
+    // 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());
+    return (abortCall());
   } else {
     // Do not abort call nor send anything in reply if default behavior is disabled
     return false;
@@ -1699,7 +1755,6 @@
 
 bool call::abortCall()
 {
-  int res ;
   int is_inv;
 
   char * src_send = NULL ;
@@ -1720,11 +1775,10 @@
       // 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");
+        strcpy(L_param,  "ACK [last_Request_URI] SIP/2.0\n");
+        sprintf(L_param, "%s%s", L_param, "[last_Via]\n");
+        sprintf(L_param, "%s%s", L_param, "[last_From]\n");
+        sprintf(L_param, "%s%s", L_param, "[last_To]\n");
         sprintf(L_param, "%s%s", L_param, "Call-ID: [call_id]\n");
         char * cseq;
         cseq = get_header_field_code(src_recv,(char *) "CSeq:");
@@ -1734,9 +1788,9 @@
         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));
+        sprintf(L_param, "%s%s", L_param, "Content-Length: 0\n\n");
+
+        sendBuffer(createSendingMessage((char*)(L_param), -2));
 
       } else if (src_recv) {
         /* Call is not established and the reply is not a 4XX, 5XX */
@@ -1748,45 +1802,48 @@
            * 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");
+          strcpy(L_param,  "ACK [last_Request_URI] 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, "[last_From]\n");
+          sprintf(L_param, "%s%s", L_param, "[last_To]\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, "Max-Forwards: 70\n");
           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));
+          sprintf(L_param, "%s%s", L_param, "Content-Length: 0\n\n");
+          sendBuffer(createSendingMessage((char*)(L_param),-1));
           
           /* Send the BYE */
           cseq = NULL;
-          strcpy(L_param, "BYE sip:[service]@[remote_ip]:[remote_port] SIP/2.0\n");
+          strcpy(L_param,  "BYE [last_Request_URI] 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, "[last_From]\n");
+          sprintf(L_param, "%s%s", L_param, "[last_To]\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));
+		  sprintf(L_param, "%s%s", L_param, "Max-Forwards: 70\n");
+          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\n");
+          sendBuffer(createSendingMessage((char*)(L_param),-1));
         } else {
           /* Send a CANCEL */
-          strcpy(L_param, "CANCEL sip:[service]@[remote_ip]:[remote_port] SIP/2.0\n");
-          sprintf(L_param, "%s%s", L_param, "Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]\n");
-          sprintf(L_param, "%s%s", L_param, "From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]\n");
-          sprintf(L_param, "%s%s", L_param, "To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]\n");
+          strcpy(L_param,  "CANCEL [last_Request_URI] SIP/2.0\n");
+          sprintf(L_param, "%s%s", L_param, "[last_Via]\n");
+          sprintf(L_param, "%s%s", L_param, "[last_From]\n");
+          sprintf(L_param, "%s%s", L_param, "[last_To]\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, "%sCSeq: 1 CANCEL\n", L_param);
+		    sprintf(L_param, "%s%s", L_param, "Max-Forwards: 70\n");
           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));
+          sprintf(L_param, "%s%s", L_param, "Content-Length: 0\n\n");
+          sendBuffer(createSendingMessage((char*)(L_param),-2));
         }
       } else {
         /* Call is not established and the reply is not a 4XX, 5XX */
@@ -1795,25 +1852,29 @@
         /* 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");
+      strcpy(L_param,  "BYE [last_Request_URI] 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, "[last_From:]\n");
+      sprintf(L_param, "%s%s", L_param, "[last_To:]\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));
+	   sprintf(L_param, "%s%s", L_param, "Max-Forwards: 70\n");
+      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\n");
+      sendBuffer(createSendingMessage((char*)(L_param),-1));
     }
   }
 
@@ -1830,7 +1891,6 @@
 }
 
 
-#ifdef __3PCC__
 int call::sendCmdMessage(int index)
 {
   char * dest;
@@ -1840,7 +1900,7 @@
 
   /* 3pcc extended mode */
   char * peer_dest;
-  int * peer_socket; 
+  struct sipp_socket **peer_socket;
 
   if(scenario[index] -> M_sendCmdData) {
     // WARNING_P1("---PREPARING_TWIN_CMD---%s---", scenario[index] -> M_sendCmdData); 
@@ -1854,17 +1914,10 @@
     peer_dest = scenario[index]->peer_dest;
     if(peer_dest){ 
       peer_socket = get_peer_socket(peer_dest);
-         rc = send(* peer_socket,
-                   dest,
-                   strlen(dest),
-                   0);
-
-     }else {
-    rc = send(twinSippSocket, 
-              dest, 
-              strlen(dest), 
-              0);
-     } 
+      rc = write_socket(*peer_socket, dest, strlen(dest), WS_BUFFER);
+    }else {
+      rc = write_socket(twinSippSocket, dest, strlen(dest), WS_BUFFER);
+    }
     if(rc <  0) {
       CStat::instance()->computeStat(CStat::E_CALL_FAILED);
       CStat::instance()->computeStat(CStat::E_FAILED_CMD_NOT_SENT);
@@ -1878,6 +1931,7 @@
     return(-1);
 }
 
+
 int call::sendCmdBuffer(char* cmd)
 {
   char * dest;
@@ -1891,11 +1945,7 @@
 
   strcat(dest, delimitor);
 
-
-  rc = send(twinSippSocket, 
-            dest, 
-            strlen(dest), 
-            0);
+  rc = write_socket(twinSippSocket, dest, strlen(dest), WS_BUFFER);
   if(rc <  0) {
     CStat::instance()->computeStat(CStat::E_CALL_FAILED);
     CStat::instance()->computeStat(CStat::E_FAILED_CMD_NOT_SENT);
@@ -1906,494 +1956,376 @@
   return(0);
 }
 
+char* call::createSendingMessage(SendingMessage *src, int P_index)
+{
+  char * length_marker = NULL;
+  char * auth_marker = NULL;
+  MessageComponent *auth_comp = NULL;
+  bool auth_comp_allocated = false;
+  int    len_offset = 0;
+  static char msg_buffer[SIPP_MAX_MSG_SIZE+2];
+  char *dest = msg_buffer;
+  bool supresscrlf = false;
+
+  *dest = '\0';
+
+  for (int i = 0; i < src->numComponents(); i++) {
+    MessageComponent *comp = src->getComponent(i);
+    int left = sizeof(msg_buffer) - (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_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_P1("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_Variable: {
+	 int varId = comp->varId;
+	 if(varId <= maxVariableUsed) {
+	   if(M_callVariableTable[varId] != NULL) {
+	     if(M_callVariableTable[varId]->isSet()) {
+	       if (M_callVariableTable[varId]->isRegExp()) {
+		 dest += sprintf(dest, "%s", M_callVariableTable[varId]->getMatchingValue());
+	       } else if (M_callVariableTable[varId]->isDouble()) {
+		 dest += sprintf(dest, "%lf", M_callVariableTable[varId]->getDouble());
+	       } else if (M_callVariableTable[varId]->isString()) {
+		 dest += sprintf(dest, "%s", M_callVariableTable[varId]->getString());
+	       } else if (M_callVariableTable[varId]->isBool()) {
+		 dest += sprintf(dest, "true");
+	       }
+	     } else if (M_callVariableTable[varId]->isBool()) {
+	       dest += sprintf(dest, "false");
+	     }
+	   }
+	 }
+	 break;
+      }
+      case E_Message_Fill: {
+        int varId = comp->varId;
+	int length = 0;
+	if(varId <= maxVariableUsed && M_callVariableTable[varId]) {
+	  length = (int) M_callVariableTable[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, 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(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_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_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:") + 5;
+    if(!tmp) {
+      ERROR("Could not extract method from cseq of challenge");
+    }
+    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);
+    if (createAuthHeader(auth_comp->comp_param.auth_param.auth_user, auth_comp->comp_param.auth_param.auth_pass,
+	  method, uri, body, dialog_authentication,
+	  auth_comp->comp_param.auth_param.aka_OP, auth_comp->comp_param.auth_param.aka_AMF, auth_comp->comp_param.auth_param.aka_K,
+	  result + authlen) == 0) {
+      ERROR_P1("%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);
-}
+  }
+
+  if (auth_comp_allocated) {
+    SendingMessage::freeMessageComponent(auth_comp);
+  }
+
+  return msg_buffer;
+}
+
+char* call::createSendingMessage(char *src, int P_index, bool skip_sanity)
+{
+  if (src == NULL) {
+	  ERROR("Unsupported 'send' message in scenario");
+  }
+
+  SendingMessage *msgsrc = new SendingMessage(src, skip_sanity);
+  char *msg = createSendingMessage(msgsrc, P_index);
+  delete msgsrc;
+  return msg;
+}
+
 
 
 #ifdef __3PCC__
@@ -2418,6 +2350,7 @@
           continue;
         }
         /* The received message is different from the expected one */
+	TRACE_MSG((s, "Unexpected control message received (I was expecting a different type of message):\n%s\n", msg));
         return rejectCall();
       } else {
         if(extendedTwinSippMode){                   // 3pcc extended mode 
@@ -2457,6 +2390,7 @@
         }
       }
     } else {
+      TRACE_MSG((s, "Unexpected control message received (no such message found):\n%s\n", msg));
       return rejectCall();
     }
     msg_index = search_index; //update the state machine
@@ -2705,8 +2639,8 @@
   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))) {
+     (index == 0 || ((scenario[index]->recv_response_for_cseq_method_list) && \
+     (strstr(scenario[index]->recv_response_for_cseq_method_list, responsecseqmethod))))) {
         return true;
   }   
     
@@ -2752,9 +2686,9 @@
     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);
+
+  /* Ignore the messages received during a pause if -pause_msg_ign is set */
+  if(scenario[msg_index] -> M_type == MSG_TYPE_PAUSE && pause_msg_ign) return(true);
 
   /* Authorize nop as a first command, even in server mode */
   if((msg_index == 0) && (scenario[msg_index] -> M_type == MSG_TYPE_NOP)) {
@@ -2786,7 +2720,8 @@
 
       if(status == 0) {
 	scenario[recv_retrans_send_index] -> nb_sent_retrans++;
-      } else if(status < -1) {
+	CStat::instance()->computeStat(CStat::E_RETRANSMISSION);
+      } else if(status < 0) {
 	return false;
       }
 
@@ -2875,7 +2810,7 @@
     ERROR_P1("Invalid sip message received '%s'",
              msg);
   }
-    
+
   /* Try to find it in the expected non mandatory responses
    * until the first mandatory response  in the scenario */
   for(search_index = msg_index;
@@ -2916,7 +2851,7 @@
           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)) ) {
+             (scenario[search_index+1]->send_scheme->isAck()) ) {
             sendBuffer(createSendingMessage(scenario[search_index+1] -> send_scheme, (search_index+1)));
             return true;
           }
@@ -2933,7 +2868,7 @@
       }
     } else {
       // call aborted by automatic response mode if needed
-      return (automaticResponseMode(L_case, msg)); 
+      return automaticResponseMode(L_case, msg);
     }
   }
 
@@ -2974,7 +2909,7 @@
       }
     }
   }
-  
+
   if (request) { // update [cseq] with received CSeq
     unsigned long int rcseq = get_cseq_value(msg);
     if (rcseq > cseq) cseq = rcseq;
@@ -3066,7 +3001,7 @@
         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 */
@@ -3087,15 +3022,18 @@
   if (!(scenario[search_index] -> optional) ||
        scenario[search_index]->next && 
       ((test == -1) ||
-       (test < SCEN_VARIABLE_SIZE && M_callVariableTable[test] != NULL && M_callVariableTable[test]->isSet()))
+       (test <= maxVariableUsed && M_callVariableTable[test] != NULL && M_callVariableTable[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 candidate;
 
-    if (test < SCEN_VARIABLE_SIZE && M_callVariableTable[test] != NULL && M_callVariableTable[test]->isSet()) {
+    if (scenario[search_index]->next && test <= maxVariableUsed && 
+       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);
     }
 
@@ -3106,7 +3044,7 @@
       if(scenario[search_index] -> M_type != MSG_TYPE_RECV) {
 	break;
       }
-      candidate = scenario[search_index] -> retrans_delay;
+      candidate = scenario[search_index] -> timeout;
       if (candidate == 0) {
 	if (defl_recv_timeout == 0) {
 	  continue;
@@ -3126,6 +3064,14 @@
   return true;
 }
 
+double call::get_rhs(CAction *currentAction) {
+  if (currentAction->getVarInId()) {
+    return M_callVariableTable[currentAction->getVarInId()]->getDouble();
+  } else {
+    return currentAction->getDoubleValue();
+  }
+}
+
 call::T_ActionResult call::executeAction(char * msg, int scenarioIndex)
 {
   CActions*  actions;
@@ -3137,7 +3083,7 @@
   actions = scenario[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) {
@@ -3206,43 +3152,98 @@
             }
           } // end if scen variable != null
         } else /* end action == E_AT_ASSIGN_FROM_REGEXP */ 
-            if (currentAction->getActionType() == CAction::E_AT_LOG_TO_FILE) {
-            char* x = createSendingMessage(currentAction->getMessage(), -2 /* do not add crlf*/);
+            if (currentAction->getActionType() == CAction::E_AT_ASSIGN_FROM_VALUE) {
+	      M_callVariableTable[currentAction->getVarId()]->setDouble(currentAction->getDoubleValue());
+        } else if (currentAction->getActionType() == CAction::E_AT_VAR_ADD) {
+	  double value = M_callVariableTable[currentAction->getVarId()]->getDouble();
+	  double operand = get_rhs(currentAction);
+	  M_callVariableTable[currentAction->getVarId()]->setDouble(value + operand);
+        } else if (currentAction->getActionType() == CAction::E_AT_VAR_SUBTRACT) {
+	  double value = M_callVariableTable[currentAction->getVarId()]->getDouble();
+	  double operand = get_rhs(currentAction);
+	  M_callVariableTable[currentAction->getVarId()]->setDouble(value - operand);
+        } else if (currentAction->getActionType() == CAction::E_AT_VAR_MULTIPLY) {
+	  double value = M_callVariableTable[currentAction->getVarId()]->getDouble();
+	  double operand = get_rhs(currentAction);
+	  M_callVariableTable[currentAction->getVarId()]->setDouble(value * operand);
+        } else if (currentAction->getActionType() == CAction::E_AT_VAR_DIVIDE) {
+	  double value = M_callVariableTable[currentAction->getVarId()]->getDouble();
+	  double operand = get_rhs(currentAction);
+	  if (operand == 0) {
+	    WARNING_P2("Action failure: Can not divide by zero ($%d/$%d)!\n", currentAction->getVarId(), currentAction->getVarInId());
+	  } else {
+	    M_callVariableTable[currentAction->getVarId()]->setDouble(value / operand);
+	  }
+        } else if (currentAction->getActionType() == CAction::E_AT_VAR_TEST) {
+	  double value = currentAction->compare(M_callVariableTable);
+	  M_callVariableTable[currentAction->getVarId()]->setBool(value);
+        } else if (currentAction->getActionType() == CAction::E_AT_VAR_STRCMP) {
+	  char *rhs = M_callVariableTable[currentAction->getVarInId()]->getString();
+	  char *lhs = currentAction->getStringValue();
+	  int value = strcmp(rhs, lhs);
+	  M_callVariableTable[currentAction->getVarId()]->setDouble((double)value);
+        } else if (currentAction->getActionType() == CAction::E_AT_VAR_TO_DOUBLE) {
+	  double value;
+
+	  if (M_callVariableTable[currentAction->getVarInId()]->toDouble(&value)) {
+	    M_callVariableTable[currentAction->getVarId()]->setDouble(value);
+	  } else {
+	    WARNING_P2("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[currentAction->getVarId()]->setDouble(value);
+	} else if (currentAction->getActionType() == CAction::E_AT_ASSIGN_FROM_STRING) {
+            char* x = createSendingMessage(currentAction->getMessage(), -2 /* do not add crlf*/, true /* skip sanity check */);
+	    char *str = strdup(x);
+	    if (!str) {
+		ERROR("Out of memory duplicating string for assignment!");
+	    }
+	    M_callVariableTable[currentAction->getVarId()]->setString(str);
+	} else if (currentAction->getActionType() == CAction::E_AT_LOG_TO_FILE) {
+            char* x = createSendingMessage(currentAction->getMessage(), -2 /* do not add crlf*/, true /* skip sanity check */);
             LOG_MSG((s, "%s\n", x));
-        } else /* end action == E_AT_LOG_TO_FILE */ 
-            if (currentAction->getActionType() == CAction::E_AT_EXECUTE_CMD) {
+        } else if (currentAction->getActionType() == CAction::E_AT_EXECUTE_CMD) {
 
             if (currentAction->getCmdLine()) {
-                char* x = createSendingMessage(currentAction->getCmdLine(), -2 /* do not add crlf*/);
+                char* x = createSendingMessage(currentAction->getCmdLine(), -2 /* do not add crlf*/, true /* skip sanity check. */);
                 // TRACE_MSG((s, "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_P1("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_P2("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 +3294,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,128 +3363,16 @@
   }
 }
 
-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);
+void call::getFieldFromInputFile(const char *fileName, int field, char*& dest)
+{
+  if (inFiles.find(fileName) == inFiles.end()) {
+    ERROR_P1("Invalid injection file: %s", fileName);
+  }
+  int line = (*m_lineNumber)[fileName];
+  if (line < 0) {
+    return;
+  }
+  dest += inFiles[fileName]->getField(line, field, dest, SIPP_MAX_MSG_SIZE);
 }
 
 int  call::checkAutomaticResponseMode(char * P_recv) {
@@ -3523,7 +3412,7 @@
     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(
+    sendBuffer(createSendingMessage(
                     (char*)"SIP/2.0 200 OK\n"
                     "[last_Via:]\n"
                     "[last_From:]\n"
@@ -3531,14 +3420,14 @@
                     "[last_Call-ID:]\n"
                     "[last_CSeq:]\n"
                     "Contact: <sip:[local_ip]:[local_port];transport=[transport]>\n"
-                    "Content-Length: 0\n"
+                    "Content-Length: 0\n\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));
+      (createSendingMessage((char*)"call-id: [call_id]\ninternal-cmd: abort_call\n\n", -1));
     }
 #endif /* __3PCC__ */
       CStat::instance()->computeStat(CStat::E_CALL_FAILED);
@@ -3558,7 +3447,7 @@
     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(
+    sendBuffer(createSendingMessage(
                       (char*)"SIP/2.0 200 OK\n"
                       "[last_Via:]\n"
                       "[last_From:]\n"
@@ -3566,14 +3455,14 @@
                       "[last_Call-ID:]\n"
                       "[last_CSeq:]\n"
                       "Contact: sip:sipp@[local_ip]:[local_port]\n"
-                      "Content-Length: 0\n"
+                      "Content-Length: 0\n\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));
+      (createSendingMessage((char*)"call-id: [call_id]\ninternal-cmd: abort_call\n\n", -1));
     }
 #endif /* __3PCC__ */
     
@@ -3593,7 +3482,7 @@
    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(
+    sendBuffer(createSendingMessage(
                     (char*)"SIP/2.0 200 OK\n"
                     "[last_Via:]\n"
                     "[last_Call-ID:]\n"
@@ -3601,7 +3490,7 @@
                     "[last_From:]\n"
                     "[last_CSeq:]\n"
                     "Contact: sip:sipp@[local_ip]:[local_port]\n"
-                    "Content-Length: 0\n"
+                    "Content-Length: 0\n\n"
                     , -1)) ;
     // Note: the call ends here but it is not marked as bad. PING is a 
     //       normal message.
@@ -3609,7 +3498,7 @@
     // 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));
+      (createSendingMessage((char*)"call-id: [call_id]\ninternal-cmd: abort_call\n\n",-1));
     }
 #endif /* __3PCC__ */
     
@@ -3635,7 +3524,7 @@
     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(
+    sendBuffer(createSendingMessage(
                     (char*)"SIP/2.0 200 OK\n"
                     "[last_Via:]\n"
                     "[last_Call-ID:]\n"
@@ -3643,7 +3532,7 @@
                     "[last_From:]\n"
                     "[last_CSeq:]\n"
                     "Contact: sip:sipp@[local_ip]:[local_port]\n"
-                    "Content-Length: 0\n"
+                    "Content-Length: 0\n\n"
                     , -1)) ;
 
     // restore previous last msg
@@ -3658,6 +3547,41 @@
     CStat::instance()->computeStat(CStat::E_AUTO_ANSWERED);
     return true;
     break;
+
+    case 5: // response for an out of call message
+    old_last_recv_msg = NULL;
+    if (last_recv_msg != NULL) {
+      last_recv_msg_saved = true;
+      old_last_recv_msg = (char *) malloc(strlen(last_recv_msg)+1);
+      strcpy(old_last_recv_msg,last_recv_msg);
+    }
+    // usage of last_ keywords
+    last_recv_msg = (char *) realloc(last_recv_msg, strlen(P_recv) + 1);
+    strcpy(last_recv_msg, P_recv);
+
+    WARNING("Automatic response mode for an out of call message");
+    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\n"
+                    , -1)) ;
+
+    // restore previous last msg
+    if (last_recv_msg_saved == true) {
+      last_recv_msg = (char *) realloc(last_recv_msg, strlen(old_last_recv_msg) + 1);
+      strcpy(last_recv_msg, old_last_recv_msg);
+      if (old_last_recv_msg != NULL) {
+        free(old_last_recv_msg);
+        old_last_recv_msg = NULL;
+      }
+    }
+    CStat::instance()->computeStat(CStat::E_AUTO_ANSWERED);
+    return true;
 
     default:
     ERROR_P1("Internal error for automaticResponseMode - mode %d is not implemented!", P_case);

Modified: sip-tester/branches/upstream/current/sipp.hpp
URL: http://svn.debian.org/wsvn/pkg-voip/sip-tester/branches/upstream/current/sipp.hpp?rev=6620&op=diff
==============================================================================
--- sip-tester/branches/upstream/current/sipp.hpp (original)
+++ sip-tester/branches/upstream/current/sipp.hpp Sun Jan  4 02:02:39 2009
@@ -61,6 +61,7 @@
 #include "stat.hpp"
 #include "actions.hpp"
 #include "variables.hpp"
+#include "infile.hpp"
 /* Open SSL stuff */
 #ifdef _USE_OPENSSL
 #include "sslcommon.h" 
@@ -92,17 +93,18 @@
 
 /************************** Constants **************************/
 
-#define SIPP_VERSION               20070516
+#define SIPP_VERSION               20071128
 #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 +121,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
@@ -155,6 +158,7 @@
 extern int                users                   _DEFVAL(0);
 extern int               rate_period_ms           _DEFVAL(DEFAULT_RATE_PERIOD_MS);
 extern unsigned long      defl_recv_timeout       _DEFVAL(0);
+extern unsigned long      defl_send_timeout       _DEFVAL(0);
 extern unsigned long      global_timeout          _DEFVAL(0);
 extern int                transport               _DEFVAL(DEFAULT_TRANSPORT);
 extern bool               retrans_enabled         _DEFVAL(1);
@@ -187,13 +191,15 @@
 
 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 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
@@ -229,8 +235,6 @@
 extern bool               backgroundMode          _DEFVAL(false);        
 extern bool               signalDump              _DEFVAL(false);        
 
-extern bool               ctrlEW                  _DEFVAL(false);
-
 extern int                currentScreenToDisplay  _DEFVAL
                                                   (DISPLAY_SCENARIO_SCREEN);
 extern int                currentRepartitionToDisplay  _DEFVAL(1);
@@ -251,8 +255,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,19 +264,27 @@
 #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;
+extern char *ip_file _DEFVAL(NULL);
+extern char *default_file _DEFVAL(NULL);
+
+// free user id list
+extern list<int> freeUsers;
+
+//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 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();
@@ -329,8 +339,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);
 
@@ -340,16 +350,15 @@
 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 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 +366,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,11 +394,13 @@
 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 * 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);
+//extern bool   useTimeoutf                         _DEFVAL(0);
 extern bool   dumpInFile                          _DEFVAL(0);
 extern bool   dumpInRtt                           _DEFVAL(0);
 extern char * scenario_file;
@@ -406,6 +415,15 @@
   }                         \
 }
 
+#define TRACE_SHORTMSG(arg)  \
+{                            \
+  if(shortmessagef) {        \
+    FILE * s = shortmessagef;\
+    fprintf arg;             \
+    fflush(shortmessagef);   \
+  }                          \
+}
+
 #define LOG_MSG(arg)        \
 {                           \
   if(logfile) {             \
@@ -415,14 +433,16 @@
   }                         \
 }
 
-#define TRACE_TIMEOUT(arg)  \
+// TODO: finish the -trace_timeout option implementation
+
+/* #define TRACE_TIMEOUT(arg)  \
 {                           \
   if(timeoutf) {            \
     FILE * s = timeoutf;    \
     fprintf arg;            \
     fflush(timeoutf);       \
   }                         \
-}
+} */
 
 /********************* Mini-Parser Routines *******************/
 
@@ -433,15 +453,65 @@
 
 /********************** 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 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. */
+
+
+	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);
+/* 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
@@ -467,15 +537,16 @@
 
 int reset_connections() ;
 int close_calls();
+int 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();




More information about the Pkg-voip-commits mailing list