]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
add capture hooks to libsofia
authorAnthony Minessale <anthm@freeswitch.org>
Sun, 31 Jul 2011 23:36:05 +0000 (18:36 -0500)
committerAnthony Minessale <anthm@freeswitch.org>
Sun, 31 Jul 2011 23:36:05 +0000 (18:36 -0500)
libs/sofia-sip/.update
libs/sofia-sip/libsofia-sip-ua/msg/msg_internal.h
libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport_tag.h
libs/sofia-sip/libsofia-sip-ua/tport/tport.c
libs/sofia-sip/libsofia-sip-ua/tport/tport_internal.h
libs/sofia-sip/libsofia-sip-ua/tport/tport_logging.c
libs/sofia-sip/libsofia-sip-ua/tport/tport_sigcomp.c
libs/sofia-sip/libsofia-sip-ua/tport/tport_tag.c
libs/sofia-sip/libsofia-sip-ua/tport/tport_type_sctp.c
libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tcp.c
libs/sofia-sip/libsofia-sip-ua/tport/tport_type_udp.c

index 83502caf5fecfd6f164505626388b794b3b08853..9c24253418d02e71953078cae219ee1e70a3bf88 100644 (file)
@@ -1 +1 @@
-Wed Jul  6 15:11:41 CDT 2011
+Sun Jul 31 18:36:02 CDT 2011
index b73561c9152a853de040f7c9203a4daa54d709ff..043bf68389a827b17f3bfd74849739c0fe93bc2d 100644 (file)
@@ -114,6 +114,29 @@ struct msg_buffer_s {
   msg_payload_t  *b_chunks;        /**< List of body chunks */
 };
 
+
+struct hep_hdr{
+    u_int8_t hp_v;             /* version */
+    u_int8_t hp_l;             /* length */
+    u_int8_t hp_f;             /* family */
+    u_int8_t hp_p;             /* protocol */
+    u_int16_t hp_sport;        /* source port */
+    u_int16_t hp_dport;        /* destination port */
+};
+
+
+struct hep_iphdr{
+        struct in_addr hp_src; 
+        struct in_addr hp_dst;      /* source and dest address */
+};
+
+#if SU_HAVE_IN6
+struct hep_ip6hdr {
+       struct in6_addr hp6_src;        /* source address */
+       struct in6_addr hp6_dst;        /* destination address */
+};
+#endif
+
 /** Maximum size when streaming. */
 #define MSG_SSIZE_MAX (USIZE_MAX)
 
index 891d26b168f083bdbd71985648217d56353b1e73..1390cc2f749cd69513412ca2d8d98b8227f926c3 100644 (file)
@@ -301,6 +301,12 @@ TPORT_DLL extern tag_typedef_t tptag_dump;
 TPORT_DLL extern tag_typedef_t tptag_dump_ref;
 #define TPTAG_DUMP_REF(x) tptag_dump_ref, tag_str_vr(&(x))
 
+TPORT_DLL extern tag_typedef_t tptag_capt;
+#define TPTAG_CAPT(x) tptag_capt, tag_str_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_capt_ref;
+#define TPTAG_CAPT_REF(x) tptag_capt_ref, tag_str_vr(&(x))
+
 SOFIA_END_DECLS
 
 #endif /* !defined TPORT_TAG_H */
index 8ebab4fd316ea5742bc88b9a388b3acec06cddb6..cc94cf46814c70431aa6a6c692c19c9e51298c6a 100644 (file)
@@ -3554,6 +3554,10 @@ ssize_t tport_vsend(tport_t *self,
 
   if (n > 0 && self->tp_master->mr_dump_file)
     tport_dump_iovec(self, msg, n, iov, iovused, "sent", "to");
+    
+  if (n > 0 && self->tp_master->mr_capt_sock)
+      tport_capt_msg(self, msg, n, iov, iovused, "sent");
+              
 
   if (tport_log->log_level >= 7) {
     size_t i, m = 0;
index 683b79a3603101d9d45ca6cde2ab0a1dd9904582..d4693ad167b1728466ec3c7c8d4f28b2bb297dd0 100644 (file)
@@ -300,6 +300,9 @@ struct tport_master {
   /** FILE to dump received and sent data */
   FILE               *mr_dump_file;
   char               *mr_dump; /**< Filename for dumping received/sent data */
+  /** SOCK to dump received and sent data */
+  su_socket_t         mr_capt_sock;
+  char               *mr_capt_name;    /**< Servername for capturing received/sent data */  
   tport_primary_t    *mr_primaries;        /**< List of primary contacts */
 
   tport_params_t      mr_params[1];
@@ -478,6 +481,9 @@ void tport_dump_iovec(tport_t const *self, msg_t *msg,
                      size_t n, su_iovec_t const iov[], size_t iovused,
                      char const *what, char const *how);
 
+void tport_capt_msg(tport_t const *self, msg_t *msg, size_t n,
+                    su_iovec_t const iov[], size_t iovused, char const *what);
+
 int tport_tcp_ping(tport_t *self, su_time_t now);
 int tport_tcp_pong(tport_t *self);
 
index af2a46d163956a4d68b9f0be4f48c763034777ea..56101e83df53b4f1346c0fbf2203e02e0b7aa266 100644 (file)
  */
 
 #include "config.h"
+#include "msg_internal.h"
 
 #include "tport_internal.h"
 
+#include <sofia-sip/su.h>
 #include <sofia-sip/su_string.h>
 #include <stdlib.h>
 #include <time.h>
@@ -70,6 +72,21 @@ extern char const TPORT_LOG[];       /* dummy declaration for Doxygen */
 extern char const TPORT_DUMP[];        /* dummy declaration for Doxygen */
 #endif
 
+/**@var TPORT_CAPT
+ *
+ * Environment variable for transport data capturing.
+ *
+ * The received and sent data is dumped to the capture server specified by TPORT_CAPT
+ * environment variable. This can be used to save message traces into database and help
+ * hairy debugging tasks.
+ *
+ * @sa TPORT_LOG, TPORT_DEBUG, TPORT_CAPT, tport_log
+ */
+#ifdef DOXYGEN
+extern char const TPORT_CAPT[];        /* dummy declaration for Doxygen */
+#endif
+
+
 /**@var TPORT_DEBUG
  *
  * Environment variable determining the debug log level for @b tport module.
@@ -93,31 +110,140 @@ su_log_t tport_log[] = {
 };
 
 
+
 /** Initialize logging. */
 int tport_open_log(tport_master_t *mr, tagi_t *tags)
 {
   int log_msg = mr->mr_log != 0;
   char const *dump = NULL;
+  char const *capt = NULL;;
   int n;
-
+  
+  if(mr->mr_capt_name) capt = mr->mr_capt_name;
+  
   n = tl_gets(tags,
              TPTAG_LOG_REF(log_msg),
              TPTAG_DUMP_REF(dump),
+             TPTAG_CAPT_REF(capt),
              TAG_END());
 
   if (getenv("MSG_STREAM_LOG") != NULL || getenv("TPORT_LOG") != NULL)
     log_msg = 1;
   mr->mr_log = log_msg ? MSG_DO_EXTRACT_COPY : 0;
 
+  if (getenv("TPORT_CAPT"))
+    capt = getenv("TPORT_CAPT");
   if (getenv("MSG_DUMP"))
     dump = getenv("MSG_DUMP");
   if (getenv("TPORT_DUMP"))
     dump = getenv("TPORT_DUMP");
+  if(capt) {
+
+        char *captname, *p, *host_s;
+        char port[10];
+        su_addrinfo_t *ai = NULL, hints[1] = {{ 0 }};
+        unsigned len =0;
+
+        if (mr->mr_capt_name && mr->mr_capt_sock && strcmp(capt, mr->mr_capt_name) == 0)                
+              return n;
+
+        captname = su_strdup(mr->mr_home, capt);
+        if (captname == NULL)
+              return n;
+                           
+        if(strncmp(captname, "udp:",4) != 0) {
+              su_log("tport_open_log: capturing. Only udp protocol supported [%s]\n", captname);          
+              return n;
+        } 
+        
+        /* separate proto and host */
+        p = captname+4;
+        if( (*(p)) == '\0') {
+                su_log("malformed ip address\n");
+                return n;
+        }
+        host_s = p;
+
+        if( (p = strrchr(p+1, ':')) == 0 ) {
+                su_log("no host or port specified\n");
+                return n;
+        }
+        /*the address contains a port number*/
+        *p = '\0';
+        p++;
+
+        if (atoi(p) <1024  || atoi(p)>65536)
+        {
+                su_log("invalid port number; must be in [1024,65536]\n");
+                return n;
+        }
+
+        memcpy(port, p, sizeof(p));
+                        
+        *p = '\0'; 
+        
+        /* check if we have [] */
+        if (host_s[0] == '[') {
+              len = strlen(host_s + 1) - 1;              
+              if(host_s[len+1] != ']') {
+                su_log("bracket not closed\n");
+                return n;            
+            }            
+            memmove(host_s, host_s + 1, len);
+            host_s[len] = '\0';
+        }                              
+
+        /* and again */
+        captname = su_strdup(mr->mr_home, capt);
+        if (captname == NULL) return n;
+        
+        su_free(mr->mr_home, mr->mr_capt_name);
+        mr->mr_capt_name = captname;
+
+        if (mr->mr_capt_sock)
+          su_close(mr->mr_capt_sock), mr->mr_capt_sock = 0;        
+
+        /* HINTS && getaddrinfo */
+        hints->ai_flags = AI_NUMERICSERV;
+        hints->ai_family = AF_UNSPEC; 
+        hints->ai_socktype = SOCK_DGRAM;
+        hints->ai_protocol = IPPROTO_UDP;
+        
+
+        if (su_getaddrinfo(host_s, port, hints, &ai)) {
+            su_perror("capture: su_getaddrinfo()");
+            return n;
+        }
+        
+       mr->mr_capt_sock = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+       if (mr->mr_capt_sock == INVALID_SOCKET) {
+           su_perror("capture: invalid socket");
+           return n;
+       }
+
+       su_setblocking(mr->mr_capt_sock, 0);         /* Don't block */
+
+       if (connect(mr->mr_capt_sock, ai->ai_addr, (socklen_t)(ai->ai_addrlen)) == -1) {
+           if (errno != EINPROGRESS) {
+                   su_perror("capture: socket connect");
+                   return n;
+           }                   
+       }
+               
+       su_freeaddrinfo(ai);        
+  }
+  else if(mr->mr_capt_sock) {
+      /* close capture server*/
+      su_close(mr->mr_capt_sock);
+      mr->mr_capt_sock = 0;
+  }
 
   if (dump) {
     time_t now;
     char *dumpname;
-
+    
     if (mr->mr_dump && strcmp(dump, mr->mr_dump) == 0)
       return n;
     dumpname = su_strdup(mr->mr_home, dump);
@@ -213,6 +339,115 @@ void tport_dump_iovec(tport_t const *self, msg_t *msg,
   fflush(mr->mr_dump_file);
 }
 
+/** Capture the data from the iovec */
+void tport_capt_msg(tport_t const *self, msg_t *msg, size_t n, 
+                    su_iovec_t const iov[], size_t iovused, char const *what)
+{
+
+   int buflen = 0, error;
+   su_sockaddr_t const *su, *su_self;
+   struct hep_hdr hep_header;
+   struct hep_iphdr hep_ipheader;   
+#if SU_HAVE_IN6
+   struct hep_ip6hdr hep_ip6header;
+#endif   
+   int eth_frame_len = 8000;
+   void* buffer;
+   size_t i, dst = 0;   
+   tport_master_t *mr;
+
+   assert(self); assert(msg);
+
+   su = msg_addr(msg);
+   su_self = self->tp_addr;
+
+   mr = self->tp_master;
+
+   /* If we don't have socket, go out */
+   if (!mr->mr_capt_sock) {
+         su_log("error: capture socket is not open\n");
+         return;
+   }
+
+   /*buffer for ethernet frame*/
+   buffer = (void*)malloc(eth_frame_len);
+
+   /* VOIP Header */   
+   hep_header.hp_v =  1;
+   hep_header.hp_f = su->su_family; 
+   /* Header Length */   
+   hep_header.hp_l = sizeof(struct hep_hdr);   
+   
+   /* PROTOCOL */
+   if(strcmp(self->tp_name->tpn_proto, "tcp") == 0) hep_header.hp_p = IPPROTO_TCP;
+   else if(strcmp(self->tp_name->tpn_proto, "tls") == 0) hep_header.hp_p = IPPROTO_IDP; /* FAKE*/
+   else if(strcmp(self->tp_name->tpn_proto, "sctp") == 0) hep_header.hp_p = IPPROTO_SCTP;
+   else hep_header.hp_p = IPPROTO_UDP; /* DEFAULT UDP */
+
+   /* Check destination */         
+   if(strncmp("recv", what, 4) == 0) dst = 1;
+      
+   /* copy destination and source IPs*/
+   if(su->su_family == AF_INET) {
+
+       memcpy(dst ? &hep_ipheader.hp_dst : &hep_ipheader.hp_src, &su->su_sin.sin_addr.s_addr, sizeof(su->su_sin.sin_addr.s_addr));
+       memcpy(dst ? &hep_ipheader.hp_src : &hep_ipheader.hp_dst, &su_self->su_sin.sin_addr.s_addr, sizeof(su_self->su_sin.sin_addr.s_addr));
+       hep_header.hp_l += sizeof(struct hep_iphdr);
+   }
+#if SU_HAVE_IN6
+   else {   
+       memcpy(dst ? &hep_ip6header.hp6_dst : &hep_ip6header.hp6_src, &su->su_sin.sin_addr.s_addr, sizeof(su->su_sin.sin_addr.s_addr));
+       memcpy(dst ? &hep_ip6header.hp6_src : &hep_ip6header.hp6_dst, &su_self->su_sin.sin_addr.s_addr, sizeof(su_self->su_sin.sin_addr.s_addr));
+       hep_header.hp_l += sizeof(struct hep_ip6hdr);       
+   }
+#endif     
+
+   hep_header.hp_dport = dst ? su->su_port : htons(atoi(self->tp_port));   
+   hep_header.hp_sport = dst ? htons(atoi(self->tp_port)) : su->su_port;
+
+      
+   /* Copy hepheader */
+   memset(buffer, '\0', eth_frame_len);
+   memcpy((void*)buffer, &hep_header, sizeof(struct hep_hdr));
+   buflen = sizeof(struct hep_hdr);
+   
+   if(su->su_family == AF_INET) {
+       memcpy((void*)buffer + buflen, &hep_ipheader, sizeof(struct hep_iphdr));
+       buflen += sizeof(struct hep_iphdr);      
+   }
+#if SU_HAVE_IN6   
+   else {
+       memcpy((void*)buffer+buflen, &hep_ip6header, sizeof(struct hep_ip6hdr));
+       buflen += sizeof(struct hep_ip6hdr);   
+   }   
+#endif             
+   
+   for (i = 0; i < iovused && n > 0; i++) {
+       size_t len = iov[i].mv_len;
+       if (len > n)
+            len = n;   
+       /* if the packet too big for us */
+       if((buflen + len) > eth_frame_len) 
+              break;
+
+      memcpy((void*)(buffer + buflen) , (void*)iov[i].mv_base, len);
+      buflen +=len;
+      n -= len;
+   }
+   
+   /* check if we have error i.e. capture server is down */
+   if ((error = su_soerror(mr->mr_capt_sock))) {
+      su_perror("capture socket error");
+      return;
+   }
+
+   su_send(mr->mr_capt_sock, buffer, buflen, 0);   
+
+   /* Now we release it */
+   if(buffer) free(buffer);  
+}
+
+
 /** Log the message. */
 void tport_log_msg(tport_t *self, msg_t *msg,
                   char const *what, char const *via,
@@ -224,6 +459,7 @@ void tport_log_msg(tport_t *self, msg_t *msg,
   size_t linelen = 0, n, logged = 0, truncated = 0;
   int skip_lf = 0;
 
+
 #define MSG_SEPARATOR \
   "------------------------------------------------------------------------\n"
 #define MAX_LINELEN 2047
index 255eca1d86205d846e2a7ec6e87e5e17c03fe7ef..433db157a5e8dc02d0bce0a2c39e5972107615aa 100644 (file)
@@ -453,6 +453,10 @@ static int tport_recv_sigcomp_r(tport_t *self,
       if (self->tp_master->mr_dump_file && !self->tp_pri->pri_threadpool)
        tport_dump_iovec(self, msg, n, iovec, veclen, "recv", "from");
 
+      /* Send the received data to the capture server */
+      if (self->tp_master->mr_capt_sock && !self->tp_pri->pri_threadpool)
+       tport_dump_iovec(self, msg, 0);
+
       msg_recv_commit(msg, dlen, eos);    /* Mark buffer as used */
     }
     else {
index 2b8064c62577776506041aeefa8320d73fcc7e33..5b7f5fd53e95aa1ef8f977507340ab8df773d93b 100644 (file)
@@ -554,6 +554,19 @@ tag_typedef_t tptag_log = INTTAG_TYPEDEF(log);
  */
 tag_typedef_t tptag_dump = STRTAG_TYPEDEF(dump);
 
+/**@def TPTAG_CAPT(x)
+ *
+ * URL for capturing unparsed messages from transport.
+ *
+ * Use with tport_tcreate(), nta_agent_create(), nua_create(),
+ * nth_engine_create(), or initial nth_site_create().
+ *
+ * @sa #TPORT_CAPT environment variable, TPTAG_LOG().
+ *
+ */
+tag_typedef_t tptag_capt = STRTAG_TYPEDEF(capt);
+
+
 /** Mark transport as trusted.
  *
  * @note Not implemented by tport module.
index 470178fdf8df0ea85a8b542e923ef84c9123f9cf..fba193c957a76750ce415dd09c2101bd22e0027d 100644 (file)
@@ -260,6 +260,9 @@ int tport_recv_sctp(tport_t *self)
   if (self->tp_master->mr_dump_file)
     tport_dump_iovec(self, msg, N, iovec, veclen, "recv", "from");
 
+ if (self->tp_master->mr_capt_sock)
+     tport_capt_msg(self, msg, N, iovec, veclen, "recv");
+     
   msg_recv_commit(msg, N, 0);  /* Mark buffer as used */
 
   return 2;
index 23ce467f36458e4e71ab843a552704215fa77350..062af6e0195c7020b5ddebfbc761d85e0de59e13 100644 (file)
@@ -334,6 +334,10 @@ int tport_recv_stream(tport_t *self)
   /* Write the received data to the message dump file */
   if (self->tp_master->mr_dump_file)
     tport_dump_iovec(self, msg, n, iovec, veclen, "recv", "from");
+    
+  if (self->tp_master->mr_capt_sock)
+      tport_capt_msg(self, msg, n, iovec, veclen, "recv");
+         
 
   /* Mark buffer as used */
   msg_recv_commit(msg, n, n == 0);
index 8d0f2de712b64465c9d17f1b8f4cd90f3335cd2b..5a1715b3e5f1996abefb9c86c57f075b3b9cf3fb 100644 (file)
@@ -362,6 +362,9 @@ int tport_recv_dgram(tport_t *self)
 
   if (self->tp_master->mr_dump_file)
     tport_dump_iovec(self, msg, n, iovec, veclen, "recv", "from");
+    
+  if (self->tp_master->mr_capt_sock)
+    tport_capt_msg(self, msg, n, iovec, veclen, "recv");
 
   *sample = *((uint8_t *)iovec[0].mv_base);