Hello!

I did some extra tests, and it seems that there was a bug related to
multihoming in the code I sent you yesterday. So, I send the new diff
file as an attachment!

Menyus

On Thu, Apr 9, 2009 at 2:20 PM, Menyus Hegedűs <[email protected]> wrote:
> Hello!
>
> As far as I know SIPp currently does not support SCTP
> (sipp.2009-01-21.tar.gz 21-Jan-2009 11:51).
>
> Thus, I have implement SCTP for SIPp.
> In the attachment you can find the differences generated by diff.
>
> I did some tests, and it seems to work between 2 linux PCs in multi
> and mono socket mode. New parameters related to SCTP (like multihoming
> or heartbeat) are also working.
>
> Feel free to use it, and send me comments if i did something wrong.
>
> Br, Menyus
>
diff -bruN orig/Makefile sipp.svn/Makefile
--- orig/Makefile       2008-10-29 12:20:06.000000000 +0100
+++ sipp.svn/Makefile   2009-04-07 14:04:43.444388000 +0200
@@ -105,7 +105,7 @@
 CFLAGS_SunOS=${DEBUG_FLAGS} -D__SUNOS
 CFLAGS_Cygwin=-D__CYGWIN -Dsocklen_t=int
 CFLAGS_Darwin=-D__DARWIN
-CFLAGS=$(CFLAGS_$(SYSTEM)) $(VERINFO) $(TLS) $(PCAPPLAY) $(EXTRACFLAGS)
+CFLAGS=$(CFLAGS_$(SYSTEM)) $(VERINFO) $(TLS) $(SCTP) $(PCAPPLAY) $(EXTRACFLAGS)
 
 #C++ Compiler Flags
 CPPFLAGS_hpux=-AA -mt -D__HPUX -D_INCLUDE_LONGLONG -DNOMACROS +W829  
@@ -115,7 +115,7 @@
 CPPFLAGS_SunOS=${DEBUG_FLAGS} -D__SUNOS
 CPPFLAGS_Cygwin=-D__CYGWIN -Dsocklen_t=int
 CPPFLAGS_Darwin=-D__DARWIN
-CPPFLAGS=$(CPPFLAGS_$(SYSTEM)) $(VERINFO) $(TLS) $(PCAPPLAY) $(EXTRACPPFLAGS)
+CPPFLAGS=$(CPPFLAGS_$(SYSTEM)) $(VERINFO) $(TLS) $(SCTP) $(PCAPPLAY) 
$(EXTRACPPFLAGS)
 
 #Linker mapping
 CCLINK_hpux=aCC
@@ -167,6 +167,10 @@
 ossl:
        $(MAKE) OSNAME=`uname|sed -e "s/CYGWIN.*/CYGWIN/"` MODELNAME=`uname 
-m|sed "s/Power Macintosh/ppc/"` OBJ_TLS="auth.o sslinit.o sslthreadsafe.o  
milenage.o rijndael.o" TLS_LIBS="-lssl -lcrypto" TLS="-D_USE_OPENSSL 
-DOPENSSL_NO_KRB5" $(OUTPUT)
 
+# Building with SCTP
+sctp:
+       $(MAKE) OSNAME=`uname|sed -e "s/CYGWIN.*/CYGWIN/"` MODELNAME=`uname 
-m|sed "s/Power Macintosh/ppc/"` SCTP_LIBS="-lsctp" SCTP="-D_USE_SCTP" $(OUTPUT)
+
 #Building with PCAP play
 pcapplay:
        $(MAKE) OSNAME=`uname|sed -e "s/CYGWIN.*/CYGWIN/"` MODELNAME=`uname 
-m|sed "s/Power Macintosh/ppc/"` OBJ_PCAPPLAY="send_packets.o prepare_pcap.o" 
PCAPPLAY_LIBS="-lpcap" PCAPPLAY="-DPCAPPLAY" $(OUTPUT)
@@ -188,7 +192,7 @@
 
 $(OUTPUT): $(OBJ_TLS) $(OBJ_PCAPPLAY) $(OBJ)
        $(CCLINK) $(LFLAGS) $(MFLAGS) $(LIBDIR_$(SYSTEM)) \
-       $(DEBUG_FLAGS) -o $@ $(OBJ_TLS) $(OBJ_PCAPPLAY) $(OBJ) $(LIBS) 
$(TLS_LIBS) $(PCAPPLAY_LIBS) $(EXTRAENDLIBS)
+       $(DEBUG_FLAGS) -o $@ $(OBJ_TLS) $(OBJ_PCAPPLAY) $(OBJ) $(LIBS) 
$(TLS_LIBS) $(PCAPPLAY_LIBS) $(SCTP_LIBS) $(EXTRAENDLIBS)
 
 debug:
        DEBUG_FLAGS="-g -pg" ; export DEBUG_FLAGS ; $(MAKE) all
diff -bruN orig/call.cpp sipp.svn/call.cpp
--- orig/call.cpp       2009-01-09 18:33:04.000000000 +0100
+++ sipp.svn/call.cpp   2009-04-07 16:54:18.474123900 +0200
@@ -760,7 +760,6 @@
     if (existing) {
       return true;
     }
-    
     sipp_customize_socket(call_socket);
 
     if (use_remote_sending_addr) {
@@ -3507,11 +3506,14 @@
        protocol = T_TCP;
       } else if (!strcmp(str_protocol, "tls") || !strcmp(str_protocol, "TLS")) 
{
        protocol = T_TLS;
+      } else if (!strcmp(str_protocol, "sctp") || !strcmp(str_protocol, 
"SCTP")) {
+       protocol = T_SCTP;
       } else {
        ERROR("Unknown transport for setdest: '%s'", str_protocol);
       }
 
-      if (!call_socket && protocol == T_TCP && transport == T_TCP) {
+      if (!call_socket && ((protocol == T_TCP && transport == T_TCP) || 
+                           (protocol == T_SCTP && transport == T_SCTP))) {
        bool existing;
        if ((associate_socket(new_sipp_call_socket(use_ipv6, transport, 
&existing))) == NULL) {
          ERROR_NO("Unable to get a TCP socket");
@@ -3531,7 +3533,7 @@
        /* Nothing to do. */
       } else if (protocol == T_TLS) {
        ERROR("Changing destinations is not supported for TLS.");
-      } else if (protocol == T_TCP) {
+      } else if (protocol == T_TCP || protocol == T_SCTP) {
        if (!multisocket) {
          ERROR("Changing destinations for TCP requires multisocket mode.");
        }
@@ -3565,7 +3567,7 @@
       free(str_port);
       free(str_protocol);
 
-      if (protocol == T_TCP) {
+      if (protocol == T_TCP || protocol == T_SCTP) {
        close(call_socket->ss_fd);
        call_socket->ss_fd = -1;
        call_socket->ss_changed_dest = true;
diff -bruN orig/opentask.cpp sipp.svn/opentask.cpp
--- orig/opentask.cpp   2008-07-10 23:15:56.000000000 +0200
+++ sipp.svn/opentask.cpp       2009-04-07 11:37:13.417612600 +0200
@@ -132,6 +132,7 @@
            main_socket->ss_count++;
            break;
          case T_TCP:
+         case T_SCTP:
          case T_TLS:
            call_ptr->associate_socket(tcp_multiplex);
            tcp_multiplex->ss_count++;
diff -bruN orig/sipp.cpp sipp.svn/sipp.cpp
--- orig/sipp.cpp       2008-12-29 16:56:18.000000000 +0100
+++ sipp.svn/sipp.cpp   2009-04-10 10:57:27.333979900 +0200
@@ -130,6 +130,7 @@
 #define SIPP_OPTION_LFNAME       36
 #define SIPP_OPTION_LFOVERWRITE          37
 #define SIPP_OPTION_PLUGIN       38
+#define SIPP_OPTION_NEED_SCTP    39
 
 /* Put Each option, its help text, and type in this table. */
 struct sipp_option options_table[] = {
@@ -292,6 +293,8 @@
               "- tn: TCP with one socket per call,\n"
               "- l1: TLS with one socket,\n"
               "- ln: TLS with one socket per call,\n"
+              "- s1: SCTP with one socket (default),\n"
+              "- sn: SCTP with one socket per call,\n"
               "- c1: u1 + compression (only if compression plugin loaded),\n"
               "- cn: un + compression (only if compression plugin loaded).  
This plugin is not provided with sipp.\n"
              , SIPP_OPTION_TRANSPORT, NULL, 1},
@@ -345,6 +348,19 @@
                    "Format: -tdmmap {0-3}{99}{5-8}{1-31}", SIPP_OPTION_TDMMAP, 
NULL, 1},
        {"key", "keyword value\nSet the generic parameter named \"keyword\" to 
\"value\".", SIPP_OPTION_KEY, NULL, 1},
        {"set", "variable value\nSet the global variable parameter named 
\"variable\" to \"value\".", SIPP_OPTION_VAR, NULL, 3},
+#ifdef _USE_SCTP
+       {"multihome", "Set multihome address for SCTP", SIPP_OPTION_IP, 
multihome_ip, 1},
+       {"heartbeat", "Set heartbeat interval in ms for SCTP", SIPP_OPTION_INT, 
&heartbeat, 1},
+       {"assocmaxret", "Set association max retransmit counter for SCTP", 
SIPP_OPTION_INT, &assocmaxret, 1},
+       {"pathmaxret", "Set path max retransmit counter for SCTP", 
SIPP_OPTION_INT, &pathmaxret, 1},
+       {"gracefulclose", "if true, SCPT assocition will be closed with 
SHUTDOWN (default).\n if false, SCPT association will be closed by ABORT.\n", 
SIPP_OPTION_BOOL, &gracefulclose, 1},
+#else
+       {"multihome", NULL, SIPP_OPTION_NEED_SCTP, NULL, 1},
+       {"heartbeat", NULL, SIPP_OPTION_NEED_SCTP, NULL, 1},
+       {"assocmaxret", NULL, SIPP_OPTION_NEED_SCTP, NULL, 1},
+       {"pathmaxret", NULL, SIPP_OPTION_NEED_SCTP, NULL, 1},
+       {"gracefulclose", NULL, SIPP_OPTION_NEED_SCTP, NULL, 1},
+#endif
        {"dynamicStart", "variable value\nSet the start offset of dynamic_id 
varaiable",  SIPP_OPTION_INT, &startDynamicId, 1},
        {"dynamicMax",   "variable value\nSet the maximum of dynamic_id 
variable     ",   SIPP_OPTION_INT, &maxDynamicId,   1},
        {"dynamicStep",  "variable value\nSet the increment of dynamic_id 
variable",      SIPP_OPTION_INT, &stepDynamicId,  1}
@@ -600,6 +616,35 @@
 #endif 
 }
 
+#ifdef _USE_SCTP
+int send_sctp_nowait(int s, const void *msg, int len, int flags)
+{
+  struct sctp_sndrcvinfo sinfo;
+  memset(&sinfo,0,sizeof(sinfo));
+  sinfo.sinfo_flags=SCTP_UNORDERED; // according to RFC4168 5.1
+  sinfo.sinfo_stream=0; 
+  
+#if defined(MSG_DONTWAIT) && !defined(__SUNOS)
+  return sctp_send(s, msg, len, &sinfo, flags | MSG_DONTWAIT);
+#else
+  int fd_flags = fcntl(s, F_GETFL , NULL);
+  int initial_fd_flags;
+  int rc;
+
+  initial_fd_flags = fd_flags;
+  //  fd_flags &= ~O_ACCMODE; // Remove the access mode from the value
+  fd_flags |= O_NONBLOCK;
+  fcntl(s, F_SETFL , fd_flags);
+  
+  rc = sctp_send(s, msg, len, &sinfo, flags);
+
+  fcntl(s, F_SETFL , initial_fd_flags);
+
+  return rc;
+#endif 
+}
+#endif
+
 char * get_inet_address(struct sockaddr_storage * addr)
 {
   static char * ip_addr = NULL;
@@ -2333,12 +2378,44 @@
   return len;
 }
 
+#ifdef _USE_SCTP
+void sipp_sctp_peer_params(struct sipp_socket *socket)
+{
+  if (heartbeat>0 || pathmaxret>0)
+  {
+   struct sctp_paddrparams peerparam;
+   memset(&peerparam,0,sizeof(peerparam));
+   
+   sockaddr* addresses;
+   int addresscount=sctp_getpaddrs(socket->ss_fd,0,&addresses);
+   if (addresscount<1) WARNING("sctp_getpaddrs, errno=%d",errno);
+   
+   for (int i=0;i<addresscount;i++)
+   {   
+     memset(&peerparam.spp_address,0,sizeof(peerparam.spp_address));  
+     struct sockaddr_storage* peeraddress=(struct 
sockaddr_storage*)&addresses[i];
+     memcpy(&peerparam.spp_address,peeraddress,SOCK_ADDR_SIZE(peeraddress));
+     
+     peerparam.spp_hbinterval=heartbeat;
+     peerparam.spp_pathmaxrxt=pathmaxret;
+     if (heartbeat>0) peerparam.spp_flags=SPP_HB_ENABLE;
+     
+     if 
(setsockopt(socket->ss_fd,IPPROTO_SCTP,SCTP_PEER_ADDR_PARAMS,&peerparam,sizeof(peerparam))
 == -1) {
+      sctp_freepaddrs(addresses);
+      WARNING("setsockopt(SCTP_PEER_ADDR_PARAMS) failed, errno=%d",errno);
+     }
+    }
+    sctp_freepaddrs(addresses);
+  }
+}
+#endif
+
 void sipp_customize_socket(struct sipp_socket *socket)
 {
   unsigned int buffsize = buff_size;
 
   /* Allows fast TCP reuse of the socket */
-  if (socket->ss_transport == T_TCP || socket->ss_transport == T_TLS ) {
+  if (socket->ss_transport == T_TCP || socket->ss_transport == T_TLS || 
socket->ss_transport == T_SCTP) {
     int sock_opt = 1;
 
     if (setsockopt(socket->ss_fd, SOL_SOCKET, SO_REUSEADDR, (void *)&sock_opt,
@@ -2346,15 +2423,46 @@
       ERROR_NO("setsockopt(SO_REUSEADDR) failed");
     }
 
+#ifdef _USE_SCTP    
+    if (socket->ss_transport == T_SCTP)
+    {
+       struct sctp_event_subscribe event;
+       memset(&event, 0, sizeof(event));
+       event.sctp_data_io_event = 1;
+       event.sctp_association_event = 1;
+       event.sctp_shutdown_event = 1;
+       if 
(setsockopt(socket->ss_fd,IPPROTO_SCTP,SCTP_EVENTS,&event,sizeof(event)) == -1) 
{
+        ERROR_NO("setsockopt(SCTP_EVENTS) failed, errno=%d",errno);
+       }
+       
+       if (assocmaxret>0)
+       {
+        struct sctp_assocparams associnfo;
+        memset(&associnfo,0,sizeof(associnfo));
+        associnfo.sasoc_asocmaxrxt=assocmaxret;
+        if 
(setsockopt(socket->ss_fd,IPPROTO_SCTP,SCTP_ASSOCINFO,&associnfo,sizeof(associnfo))
 == -1) {
+          WARNING("setsockopt(SCTP_ASSOCINFO) failed, errno=%d",errno);
+        }
+       }
+       
+       if (setsockopt(socket->ss_fd, IPPROTO_SCTP, SCTP_NODELAY, (void 
*)&sock_opt,sizeof (sock_opt)) == -1) {
+        WARNING("setsockopt(SCTP_NODELAY) failed, errno=%d",errno);
+       }       
+    }
+#endif
+    
 #ifndef SOL_TCP
 #define SOL_TCP 6
 #endif
+    if (socket->ss_transport != T_SCTP)
+    {
     if (setsockopt(socket->ss_fd, SOL_TCP, TCP_NODELAY, (void *)&sock_opt,
                     sizeof (sock_opt)) == -1) {
       {
         ERROR_NO("setsockopt(TCP_NODELAY) failed");
       }
     }
+    }
 
     {
       struct linger linger;
@@ -2412,6 +2520,26 @@
       rc = -1;
 #endif
       break;
+    case T_SCTP:  
+#ifdef _USE_SCTP
+     {
+      if (socket->sctpstate==SCTP_DOWN)
+      {
+       errno = EPIPE;
+       return -1; 
+      }     
+      else if (socket->sctpstate==SCTP_CONNECTING)
+      {
+       errno = EWOULDBLOCK;
+       return -1;      
+      }
+      rc=send_sctp_nowait(socket->ss_fd, buffer, len, 0);
+     }
+#else
+      errno = EOPNOTSUPP;
+      rc = -1;
+#endif
+      break;      
     case T_TCP:
       rc = send_nowait(socket->ss_fd, buffer, len, 0);
       break;
@@ -2449,6 +2577,10 @@
 
   pollfiles[socket->ss_pollidx].events |= POLLOUT;
 
+#ifdef _USE_SCTP
+  if (socket->ss_transport==T_SCTP && socket->sctpstate==SCTP_CONNECTING) ;
+  else
+#endif
   nb_net_cong++;
   return -1;
 }
@@ -2472,7 +2604,7 @@
     return enter_congestion(socket, again);
   }
 
-  if (socket->ss_transport == T_TCP && errno == EPIPE) {
+  if ((socket->ss_transport == T_TCP || socket->ss_transport == T_SCTP) && 
errno == EPIPE) {
     nb_net_send_errors++;
     close(socket->ss_fd);
     socket->ss_fd = -1;
@@ -2520,6 +2652,8 @@
     assert(errno != EAGAIN);
   }
 
+  if (socket->ss_transport==T_SCTP && ret==-2) return 0;
+
   if (socket->ss_transport == T_TCP || socket->ss_transport == T_TLS) {
     if (ret == 0) {
       /* The remote side closed the connection. */
@@ -2756,7 +2890,7 @@
   if (!socketbuf)
     return 0;
 
-  if (socket->ss_transport == T_UDP) {
+  if (socket->ss_transport == T_UDP || socket->ss_transport == T_SCTP) {
     return socketbuf->len;
   }
 
@@ -2860,9 +2994,75 @@
   while (1);
 }
 
+#ifdef _USE_SCTP
+static void handleSCTPNotify(struct sipp_socket* socket,char* buffer)
+{
+ union sctp_notification *notifMsg; 
+ 
+ notifMsg = (union sctp_notification *)buffer;
+ if (notifMsg->sn_header.sn_type==SCTP_ASSOC_CHANGE)
+ {
+   if (notifMsg->sn_assoc_change.sac_state == SCTP_COMM_UP)
+   {
+     socket->sctpstate=SCTP_UP;
+     sipp_sctp_peer_params(socket);
+   }
+   else
+   {
+      sipp_socket_invalidate(socket);
+      if (reset_close) close_calls(socket);
+   }
+ }
+ else if (notifMsg->sn_header.sn_type==SCTP_SHUTDOWN_EVENT)
+ {
+   sipp_socket_invalidate(socket);
+   if (reset_close) close_calls(socket);
+ } 
+}
+
+void set_multihome_addr(struct sipp_socket* socket,int port)
+{
+  if (strlen(multihome_ip)>0)
+  {  
+     struct addrinfo * multi_addr;
+     struct addrinfo   hints;
+     memset((char*)&hints, 0, sizeof(hints));
+     hints.ai_flags  = AI_PASSIVE;
+     hints.ai_family = PF_UNSPEC;
+
+     if (getaddrinfo(multihome_ip, NULL, &hints, &multi_addr) != 0) 
+     {
+      ERROR("Can't get multihome IP address in getaddrinfo, 
multihome_ip='%s'",multihome_ip);
+     }
+     
+     struct sockaddr_storage secondaryaddress;
+     memset(&secondaryaddress, 0, sizeof(secondaryaddress));
+     
+     memcpy(&secondaryaddress, multi_addr->ai_addr, 
SOCK_ADDR_SIZE(_RCAST(struct sockaddr_storage *,multi_addr->ai_addr)));
+     freeaddrinfo(multi_addr);          
+     
+     if (port>0)
+     {
+      if (secondaryaddress.ss_family==AF_INET) ((struct 
sockaddr_in*)&secondaryaddress)->sin_port=htons(port);
+      else if (secondaryaddress.ss_family==AF_INET6) ((struct 
sockaddr_in6*)&secondaryaddress)->sin6_port=htons(port);
+     }      
+     
+     int ret=sctp_bindx(socket->ss_fd,(struct sockaddr 
*)&secondaryaddress,1,SCTP_BINDX_ADD_ADDR);
+     if (ret<0)
+     {
+      WARNING("Can't bind to multihome address, errno='%d'",errno);      
+     }
+  }
+}
+#endif
+
 /* Pull up to tcp_readsize data bytes out of the socket into our local buffer. 
*/
 static int empty_socket(struct sipp_socket *socket) {
-  int readsize = socket->ss_transport == T_UDP ? SIPP_MAX_MSG_SIZE : 
tcp_readsize;
+  
+  int readsize=0;  
+  if (socket->ss_transport == T_UDP || socket->ss_transport == T_SCTP) 
readsize=SIPP_MAX_MSG_SIZE;
+  else readsize=tcp_readsize;
+
   struct socketbuf *socketbuf;
   char *buffer;
   int ret;
@@ -2891,6 +3091,24 @@
       ERROR("TLS support is not enabled!");
 #endif
       break;
+    case T_SCTP:
+#ifdef _USE_SCTP
+      struct sctp_sndrcvinfo recvinfo;
+      memset(&recvinfo,0,sizeof(recvinfo));
+      int msg_flags=0;
+      
+      ret=sctp_recvmsg(socket->ss_fd, (void*)buffer,readsize,(struct sockaddr 
*)&socketbuf->addr,&addrlen,&recvinfo,&msg_flags);
+      
+      if (MSG_NOTIFICATION & msg_flags)
+      {
+       errno=0;
+       handleSCTPNotify(socket,buffer);
+       return -2;
+      }
+#else
+      ERROR("SCTP support is not enabled!");
+#endif
+      break;
   }
   if (ret <= 0) {
     free_socketbuf(socketbuf);
@@ -2927,6 +3145,17 @@
 #endif
 
   shutdown(socket->ss_fd, SHUT_RDWR);
+  
+#ifdef _USE_SCTP
+  if (socket->ss_transport==T_SCTP && !gracefulclose)
+  {
+   struct linger ling={1,0};
+   if (setsockopt (socket->ss_fd, SOL_SOCKET, SO_LINGER,&ling, sizeof (ling)) 
< 0) {
+        WARNING("Unable to set SO_LINGER option for SCTP close");
+      }  
+  }
+#endif
+  
   close(socket->ss_fd);
   socket->ss_fd = -1;
 
@@ -2950,6 +3179,10 @@
   {
      pending_messages--;
   }
+  
+#ifdef _USE_SCTP
+  if (socket->ss_transport==T_SCTP) socket->sctpstate=SCTP_DOWN;
+#endif
 }
 
 void sipp_close_socket (struct sipp_socket *socket) {
@@ -3070,6 +3303,7 @@
              main_socket->ss_count++;
              break;
            case T_TCP:
+           case T_SCTP:
            case T_TLS:
              new_ptr->associate_socket(tcp_multiplex);
              tcp_multiplex->ss_count++;
@@ -3176,7 +3410,6 @@
   if (pending_messages) {
     return;
   }
-
   /* Get socket events. */
   rs = poll(pollfiles, pollnfds, wait ? 1 : 0);
   if((rs < 0) && (errno == EINTR)) {
@@ -3192,6 +3425,12 @@
     assert(sock);
 
     if(pollfiles[poll_idx].revents & POLLOUT) {
+
+#ifdef _USE_SCTP      
+      if (transport==T_SCTP && sock->sctpstate!=SCTP_UP) ;
+      else
+#endif
+      {      
       /* We can flush this socket. */
       TRACE_MSG("Exit problem event on socket %d \n", sock->ss_fd);
       pollfiles[poll_idx].events &= ~POLLOUT;
@@ -3200,10 +3439,11 @@
       flush_socket(sock);
       events++;
     }
+    }
 
     if(pollfiles[poll_idx].revents & POLLIN) {
       /* We can empty this socket. */
-      if ((transport == T_TCP || transport == T_TLS) && sock == main_socket) {
+      if ((transport == T_TCP || transport == T_TLS || transport == T_SCTP) && 
sock == main_socket) {  
        struct sipp_socket *new_sock = sipp_accept_socket(sock);
        if (!new_sock) {
          ERROR_NO("Accepting new TCP connection.\n");
@@ -3850,11 +4090,21 @@
 
 int socket_fd(bool use_ipv6, int transport) {
   int socket_type;
+  int protocol=0;
   int fd;
 
   switch(transport) {
     case T_UDP:
       socket_type = SOCK_DGRAM;
+      protocol=IPPROTO_UDP;
+      break;
+    case T_SCTP:
+#ifndef _USE_SCTP
+      ERROR("You do not have SCTP support enabled!\n");
+#else
+      socket_type = SOCK_STREAM;
+      protocol=IPPROTO_SCTP;
+#endif
       break;
     case T_TLS:
 #ifndef _USE_OPENSSL
@@ -3865,7 +4115,7 @@
       break;
   }
 
-  if((fd = socket(use_ipv6 ? AF_INET6 : AF_INET, socket_type, 0))== -1) {
+  if((fd = socket(use_ipv6 ? AF_INET6 : AF_INET, socket_type, protocol))== -1) 
{
     ERROR("Unable to get a %s socket (3)", TRANSPORT_TO_STRING(transport));
   }
 
@@ -4031,13 +4281,33 @@
     *port = ntohs((short)((_RCAST(struct sockaddr_in *, saddr))->sin_port));
   }
 
+#ifdef _USE_SCTP  
+  bool isany=false;
+  
+  if (socket->ss_ipv6) {
+    if (memcmp(&(_RCAST(struct sockaddr_in6 *, 
saddr)->sin6_addr),&in6addr_any,sizeof(in6_addr))==0) isany=true;
+  } else {
+    isany= (_RCAST(struct sockaddr_in *, saddr)->sin_addr.s_addr==INADDR_ANY);
+  }
+  
+  if (transport==T_SCTP && !isany) set_multihome_addr(socket,*port); 
+#endif
+  
   return 0;
 }
 
 int sipp_do_connect_socket(struct sipp_socket *socket) {
   int ret;
 
-  assert(socket->ss_transport == T_TCP || socket->ss_transport == T_TLS);
+  assert(socket->ss_transport == T_TCP || socket->ss_transport == T_TLS || 
socket->ss_transport == T_SCTP);  
+  
+#ifdef _USE_SCTP  
+  if (socket->ss_transport==T_SCTP) 
+  {
+   int port=0;
+   sipp_bind_socket(socket, &local_sockaddr, &port);
+  }
+#endif
 
   errno = 0;
   ret = connect(socket->ss_fd, (struct sockaddr *)&socket->ss_dest, 
SOCK_ADDR_SIZE(&socket->ss_dest));
@@ -4056,6 +4326,10 @@
 #endif
   }
 
+#ifdef _USE_SCTP
+     if (socket->ss_transport==T_SCTP) socket->sctpstate=SCTP_CONNECTING;
+#endif
+
   return 0;
 }
 
@@ -4149,6 +4423,9 @@
   
   pid = getpid();
   memset(local_ip, 0, 40);
+#ifdef _USE_SCTP  
+  memset(multihome_ip, 0, 40);
+#endif
   memset(media_ip,0, 40);
   memset(control_ip,0, 40);
   memset(media_ip_escaped,0, 42);
@@ -4336,6 +4613,13 @@
            case 't':
              transport = T_TCP;
              break;
+           case 's':
+#ifdef _USE_SCTP
+             transport = T_SCTP;
+#else
+             ERROR("To use SCTP transport you must compile SIPp with lksctp");
+#endif
+             break;
            case 'l':
 #ifdef _USE_OPENSSL
              transport = T_TLS;
@@ -4374,6 +4658,10 @@
            ERROR("You can only use a perip socket with UDP!\n");
          }
          break;
+  case SIPP_OPTION_NEED_SCTP:
+         CHECK_PASS();
+         ERROR("SCTP support is required for the %s option.", argv[argi]);
+         break;
        case SIPP_OPTION_NEED_SSL:
          CHECK_PASS();
          ERROR("OpenSSL is required for the %s option.", argv[argi]);
@@ -5388,7 +5676,7 @@
     }
   }
 
-  if((!multisocket) && (transport == T_TCP || transport == T_TLS) &&
+  if((!multisocket) && (transport == T_TCP || transport == T_TLS || transport 
== T_SCTP) &&
    (sendMode != MODE_SERVER)) {
     if((tcp_multiplex = new_sipp_socket(local_ip_is_ipv6, transport)) == NULL) 
{
       ERROR_NO("Unable to get a TCP socket");
@@ -5398,6 +5686,7 @@
     if (use_remote_sending_addr) {
         remote_sockaddr = remote_sending_sockaddr ;
     }
+    sipp_customize_socket(tcp_multiplex);
 
     if(sipp_connect_socket(tcp_multiplex, &remote_sockaddr)) {
       if(reset_number >0){
@@ -5417,11 +5706,10 @@
     }
     }
 
-    sipp_customize_socket(tcp_multiplex);
   }
 
 
-  if(transport == T_TCP || transport == T_TLS) {
+  if(transport == T_TCP || transport == T_TLS || transport == T_SCTP) {
     if(listen(main_socket->ss_fd, 100)) {
       ERROR_NO("Unable to listen main socket");
     }
diff -bruN orig/sipp.hpp sipp.svn/sipp.hpp
--- orig/sipp.hpp       2008-12-30 17:09:30.000000000 +0100
+++ sipp.svn/sipp.hpp   2009-04-08 10:05:27.741000400 +0200
@@ -31,6 +31,9 @@
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
+#ifdef _USE_SCTP
+#include <netinet/sctp.h>
+#endif
 #include <sys/time.h>
 #include <sys/poll.h>
 #include <sys/resource.h>
@@ -119,6 +122,7 @@
 #define T_UDP                      0
 #define T_TCP                      1
 #define T_TLS                      2
+#define T_SCTP                     3
 
 #ifdef _USE_OPENSSL
 #define DEFAULT_TLS_CERT           ((char *)"cacert.pem")
@@ -126,7 +130,7 @@
 #define DEFAULT_TLS_CRL            ((char *)"")
 #endif
 
-#define TRANSPORT_TO_STRING(p)     ((p==T_TCP) ? "TCP" : ((p==T_TLS)? "TLS" 
:"UDP"))
+#define TRANSPORT_TO_STRING(p)     ((p==T_TCP) ? "TCP" : ((p==T_TLS)? "TLS" : 
((p==T_UDP)? "UDP" : "SCTP")))
 
 #define SIPP_MAXFDS                65536
 #define SIPP_MAX_MSG_SIZE          65536
@@ -234,6 +238,13 @@
 extern char               local_ip_escaped[42];
 extern bool               local_ip_is_ipv6;    
 extern int                local_port              _DEFVAL(0);
+#ifdef _USE_SCTP
+extern char               multihome_ip[40];
+extern int                heartbeat               _DEFVAL(0);
+extern int                assocmaxret             _DEFVAL(0);
+extern int                pathmaxret              _DEFVAL(0);
+extern bool               gracefulclose           _DEFVAL(true);
+#endif
 extern char               control_ip[40];
 extern int                control_port            _DEFVAL(0);
 extern int                buff_size               _DEFVAL(65535);
@@ -539,6 +550,11 @@
        struct socketbuf *next;
 };
 
+#ifdef _USE_SCTP
+#define SCTP_DOWN 0
+#define SCTP_CONNECTING 1
+#define SCTP_UP 2
+#endif
 /* This is an abstraction of a socket, which provides buffers for input and
  * output. */
 struct sipp_socket {
@@ -567,6 +583,9 @@
        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. */
+#ifdef _USE_SCTP
+  int sctpstate;
+#endif 
 };
 
 /* Write data to a socket. */
------------------------------------------------------------------------------
This SF.net email is sponsored by:
High Quality Requirements in a Collaborative Environment.
Download a free trial of Rational Requirements Composer Now!
http://p.sf.net/sfu/www-ibm-com
_______________________________________________
Sipp-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/sipp-users

Reply via email to