diff --git a/libs/sofia-sip/.update b/libs/sofia-sip/.update index 83502caf5f..9c24253418 100644 --- a/libs/sofia-sip/.update +++ b/libs/sofia-sip/.update @@ -1 +1 @@ -Wed Jul 6 15:11:41 CDT 2011 +Sun Jul 31 18:36:02 CDT 2011 diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/msg_internal.h b/libs/sofia-sip/libsofia-sip-ua/msg/msg_internal.h index b73561c915..043bf68389 100644 --- a/libs/sofia-sip/libsofia-sip-ua/msg/msg_internal.h +++ b/libs/sofia-sip/libsofia-sip-ua/msg/msg_internal.h @@ -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) diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport_tag.h b/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport_tag.h index 891d26b168..1390cc2f74 100644 --- a/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport_tag.h +++ b/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport_tag.h @@ -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 */ diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/tport.c b/libs/sofia-sip/libsofia-sip-ua/tport/tport.c index 8ebab4fd31..cc94cf4681 100644 --- a/libs/sofia-sip/libsofia-sip-ua/tport/tport.c +++ b/libs/sofia-sip/libsofia-sip-ua/tport/tport.c @@ -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; diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/tport_internal.h b/libs/sofia-sip/libsofia-sip-ua/tport/tport_internal.h index 683b79a360..d4693ad167 100644 --- a/libs/sofia-sip/libsofia-sip-ua/tport/tport_internal.h +++ b/libs/sofia-sip/libsofia-sip-ua/tport/tport_internal.h @@ -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); diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/tport_logging.c b/libs/sofia-sip/libsofia-sip-ua/tport/tport_logging.c index af2a46d163..56101e83df 100644 --- a/libs/sofia-sip/libsofia-sip-ua/tport/tport_logging.c +++ b/libs/sofia-sip/libsofia-sip-ua/tport/tport_logging.c @@ -33,9 +33,11 @@ */ #include "config.h" +#include "msg_internal.h" #include "tport_internal.h" +#include #include #include #include @@ -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 diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/tport_sigcomp.c b/libs/sofia-sip/libsofia-sip-ua/tport/tport_sigcomp.c index 255eca1d86..433db157a5 100644 --- a/libs/sofia-sip/libsofia-sip-ua/tport/tport_sigcomp.c +++ b/libs/sofia-sip/libsofia-sip-ua/tport/tport_sigcomp.c @@ -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 { diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/tport_tag.c b/libs/sofia-sip/libsofia-sip-ua/tport/tport_tag.c index 2b8064c625..5b7f5fd53e 100644 --- a/libs/sofia-sip/libsofia-sip-ua/tport/tport_tag.c +++ b/libs/sofia-sip/libsofia-sip-ua/tport/tport_tag.c @@ -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. diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_sctp.c b/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_sctp.c index 470178fdf8..fba193c957 100644 --- a/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_sctp.c +++ b/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_sctp.c @@ -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; diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tcp.c b/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tcp.c index 23ce467f36..062af6e019 100644 --- a/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tcp.c +++ b/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tcp.c @@ -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); diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_udp.c b/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_udp.c index 8d0f2de712..5a1715b3e5 100644 --- a/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_udp.c +++ b/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_udp.c @@ -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);