1 /*
2  * This file is part of the Sofia-SIP package
3  *
4  * Copyright (C) 2006 Nokia Corporation.
5  *
6  * Contact: Pekka Pessi <pekka.pessi@nokia.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  *
23  */
24 
25 /**@CFILE tport_logging.c Logging transported messages.
26  *
27  * See tport.docs for more detailed description of tport interface.
28  *
29  * @author Pekka Pessi <Pekka.Pessi@nokia.com>
30  * @author Martti Mela <Martti.Mela@nokia.com>
31  *
32  * @date Created: Fri Mar 24 08:45:49 EET 2006 ppessi
33  */
34 
35 #include "config.h"
36 #include "msg_internal.h"
37 
38 #include "tport_internal.h"
39 
40 #include <sofia-sip/su.h>
41 #include <sofia-sip/su_string.h>
42 #include <stdlib.h>
43 #include <time.h>
44 #include <assert.h>
45 #include <errno.h>
46 #include <limits.h>
47 
48 #define TPORT_STAMP_SIZE 144
49 
50 /**@var TPORT_LOG
51  *
52  * Environment variable determining if parsed message contents are logged.
53  *
54  * If the TPORT_LOG environment variable is set, the tport module logs the
55  * contents of parsed messages. This eases debugging the signaling greatly.
56  *
57  * @sa TPORT_DUMP, TPORT_DEBUG, tport_log
58  */
59 #ifdef DOXYGEN
60 extern char const TPORT_LOG[];	/* dummy declaration for Doxygen */
61 #endif
62 
63 /**@var TPORT_DUMP
64  *
65  * Environment variable for transport data dump.
66  *
67  * The received and sent data is dumped to the file specified by TPORT_DUMP
68  * environment variable. This can be used to save message traces and help
69  * hairy debugging tasks.
70  *
71  * @sa TPORT_LOG, TPORT_DEBUG, tport_log
72  */
73 #ifdef DOXYGEN
74 extern char const TPORT_DUMP[];	/* dummy declaration for Doxygen */
75 #endif
76 
77 /**@var TPORT_CAPT
78  *
79  * Environment variable for transport data capturing.
80  *
81  * The received and sent data is dumped to the capture server specified by TPORT_CAPT
82  * environment variable. This can be used to save message traces into database and help
83  * hairy debugging tasks.
84  *
85  * @sa TPORT_LOG, TPORT_DEBUG, TPORT_CAPT, tport_log
86  */
87 #ifdef DOXYGEN
88 extern char const TPORT_CAPT[];	/* dummy declaration for Doxygen */
89 #endif
90 
91 
92 /**@var TPORT_DEBUG
93  *
94  * Environment variable determining the debug log level for @b tport module.
95  *
96  * The TPORT_DEBUG environment variable is used to determine the debug logging
97  * level for @b tport module. The default level is 3.
98  *
99  * @sa <sofia-sip/su_debug.h>, tport_log, SOFIA_DEBUG
100  */
101 #ifdef DOXYGEN
102 extern char const TPORT_DEBUG[]; /* dummy declaration for Doxygen */
103 #endif
104 
105 /**Debug log for @b tport module.
106  *
107  * The tport_log is the log object used by @b tport module. The level of
108  * #tport_log is set using #TPORT_DEBUG environment variable.
109  */
110 su_log_t tport_log[] = {
111   SU_LOG_INIT("tport", "TPORT_DEBUG", SU_DEBUG)
112 };
113 
114 
115 
116 /** Initialize logging. */
tport_open_log(tport_master_t * mr,tagi_t * tags)117 int tport_open_log(tport_master_t *mr, tagi_t *tags)
118 {
119   int n;
120   int log_msg = mr->mr_log != 0;
121   char const *dump = NULL;
122   char const *capt = NULL;;
123 
124   if(mr->mr_capt_name) capt = mr->mr_capt_name;
125 
126   n = tl_gets(tags,
127 	      TPTAG_LOG_REF(log_msg),
128 	      TPTAG_DUMP_REF(dump),
129 	      TPTAG_CAPT_REF(capt),
130 	      TAG_END());
131 
132   if (getenv("MSG_STREAM_LOG") != NULL || getenv("TPORT_LOG") != NULL)
133     log_msg = 1;
134   mr->mr_log = log_msg ? MSG_DO_EXTRACT_COPY : 0;
135 
136   if (getenv("TPORT_CAPT"))
137     capt = getenv("TPORT_CAPT");
138   if (getenv("MSG_DUMP"))
139     dump = getenv("MSG_DUMP");
140   if (getenv("TPORT_DUMP"))
141     dump = getenv("TPORT_DUMP");
142 
143   if(capt) {
144 
145         char *captname, *p, *host_s;
146         char port[10];
147         su_addrinfo_t *ai = NULL, hints[1] = {{ 0 }};
148         unsigned len =0, iport = 0;
149 
150 
151 
152         if (mr->mr_capt_name && mr->mr_capt_sock && strcmp(capt, mr->mr_capt_name) == 0)
153               return n;
154 
155         captname = su_strdup(mr->mr_home, capt);
156         if (captname == NULL)
157               return n;
158 
159         if(strncmp(captname, "udp:",4) != 0) {
160               su_log("tport_open_log: capturing. Only udp protocol supported [%s]\n", captname);
161               return n;
162         }
163 
164         /* separate proto and host */
165         p = captname+4;
166         if( (*(p)) == '\0') {
167                 su_log("malformed ip address\n");
168                 return n;
169         }
170         host_s = p;
171 
172         if( (p = strrchr(p+1, ':')) == 0 ) {
173                 su_log("no host or port specified\n");
174                 return n;
175         }
176 
177         /*the address contains a port number*/
178         *p = '\0';
179         p++;
180 
181         iport = atoi(p);
182 
183         if (iport <1024 || iport >65536)
184         {
185                 su_log("invalid port number; must be in [1024,65536]\n");
186                 return n;
187         }
188 
189         snprintf(port, sizeof(port), "%d", iport);
190 
191         /* default values for capture protocol and agent id */
192         mr->mr_prot_ver = 3;
193         mr->mr_agent_id = 200;
194 
195         /* get all params */
196         while(p)
197         {
198                 /* check ; in the URL */
199                 if( (p = strchr(p+1, ';')) == 0 ) {
200                         break;
201                 }
202 
203                 *p = '\0';
204                 p++;
205 
206                 SU_DEBUG_7(("events HEP RRR DATA [%s]\n", p));
207 
208                 if(strncmp(p, "hep=",4) == 0) {
209                         p+=4;
210                         mr->mr_prot_ver = atoi(p);
211                         /* hepv3 come later */
212                         if (mr->mr_prot_ver < 1 || mr->mr_prot_ver > 3)
213                         {
214                                 su_log("invalid hep version number; must be in [1-3]\n");
215                                 mr->mr_prot_ver = 3;
216                                 return n;
217                         }
218                 }
219                 else if(strncmp(p, "capture_id=", 11) == 0) {
220                         p+=11;
221                         if((mr->mr_agent_id = atoi(p)) == 0)
222                         {
223                                 mr->mr_agent_id = 200;
224                                 su_log("invalid capture id number; must be uint32 \n");
225                                 return n;
226                         }
227                 }
228                 else {
229                        su_log("unsupported capture param\n");
230                        return n;
231                 }
232         }
233 
234         /* check if we have [] */
235         if (host_s[0] == '[') {
236               len = strlen(host_s + 1) - 1;
237               if(host_s[len+1] != ']') {
238                 su_log("bracket not closed\n");
239                 return n;
240             }
241             memmove(host_s, host_s + 1, len);
242             host_s[len] = '\0';
243         }
244 
245         /* and again */
246         captname = su_strdup(mr->mr_home, capt);
247         if (captname == NULL) return n;
248 
249         su_free(mr->mr_home, mr->mr_capt_name);
250         mr->mr_capt_name = captname;
251 
252         if (mr->mr_capt_sock)
253           su_close(mr->mr_capt_sock), mr->mr_capt_sock = 0;
254 
255         /* HINTS && getaddrinfo */
256         hints->ai_flags = AI_NUMERICSERV;
257         hints->ai_family = AF_UNSPEC;
258         hints->ai_socktype = SOCK_DGRAM;
259         hints->ai_protocol = IPPROTO_UDP;
260 
261         if (su_getaddrinfo(host_s, port, hints, &ai)) {
262             su_perror("capture: su_getaddrinfo()");
263             return n;
264         }
265 
266 	mr->mr_capt_sock = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
267 	if (mr->mr_capt_sock == INVALID_SOCKET) {
268 	    su_perror("capture: invalid socket");
269 	    return n;
270 	}
271 
272 	su_setblocking(mr->mr_capt_sock, 0);         /* Don't block */
273 
274 	if (connect(mr->mr_capt_sock, ai->ai_addr, (socklen_t)(ai->ai_addrlen)) == -1) {
275 	    if (errno != EINPROGRESS) {
276 		    su_perror("capture: socket connect");
277 		    return n;
278 	    }
279 	}
280 
281 	su_freeaddrinfo(ai);
282   }
283   else if(mr->mr_capt_sock) {
284       /* close capture server*/
285       su_close(mr->mr_capt_sock);
286       mr->mr_capt_sock = 0;
287   }
288 
289   if (dump) {
290     time_t now;
291     char *dumpname;
292 
293     if (mr->mr_dump && strcmp(dump, mr->mr_dump) == 0)
294       return n;
295     dumpname = su_strdup(mr->mr_home, dump);
296     if (dumpname == NULL)
297       return n;
298     su_free(mr->mr_home, mr->mr_dump);
299     mr->mr_dump = dumpname;
300 
301     if (mr->mr_dump_file && mr->mr_dump_file != stdout)
302       fclose(mr->mr_dump_file), mr->mr_dump_file = NULL;
303 
304     if (strcmp(dumpname, "-"))
305       mr->mr_dump_file = fopen(dumpname, "ab"); /* XXX */
306     else
307       mr->mr_dump_file = stdout;
308 
309     if (mr->mr_dump_file) {
310       time(&now);
311       fprintf(mr->mr_dump_file, "dump started at %s\n\n", ctime(&now));
312     }
313   }
314 
315   return n;
316 }
317 
318 /** Create log stamp */
tport_stamp(tport_t const * self,msg_t * msg,char * stamp,char const * what,size_t n,char const * via,su_time_t now)319 void tport_stamp(tport_t const *self, msg_t *msg,
320 		 char *stamp, char const *what,
321 		 size_t n, char const *via,
322 		 su_time_t now)
323 {
324   char label[24] = "";
325   char *comp = "";
326   char name[SU_ADDRSIZE] = "";
327   su_sockaddr_t const *su;
328   unsigned short second, minute, hour;
329   /* should check for ifdef HAVE_LOCALTIME_R instead -_- */
330 #if defined(HAVE_GETTIMEOFDAY) || defined(HAVE_CLOCK_MONOTONIC)
331   struct tm nowtm = { 0 };
332   time_t nowtime = (now.tv_sec - SU_TIME_EPOCH); /* see su_time0.c 'now' is not really 'now', so we decrease it by SU_TIME_EPOCH */
333 #endif
334 
335   assert(self); assert(msg);
336 
337 #if defined(HAVE_GETTIMEOFDAY) || defined(HAVE_CLOCK_MONOTONIC)
338   localtime_r(&nowtime, &nowtm);
339   second = nowtm.tm_sec;
340   minute = nowtm.tm_min;
341   hour = nowtm.tm_hour;
342 #else
343   second = (unsigned short)(now.tv_sec % 60);
344   minute = (unsigned short)((now.tv_sec / 60) % 60);
345   hour = (unsigned short)((now.tv_sec / 3600) % 24);
346 #endif
347 
348   su = msg_addr(msg);
349 
350 #if SU_HAVE_IN6
351   if (su->su_family == AF_INET6) {
352     if (su->su_sin6.sin6_flowinfo)
353       snprintf(label, sizeof(label), "/%u", ntohl(su->su_sin6.sin6_flowinfo));
354   }
355 #endif
356 
357   if (msg_addrinfo(msg)->ai_flags & TP_AI_COMPRESSED)
358     comp = ";comp=sigcomp";
359 
360   su_inet_ntop(su->su_family, SU_ADDR(su), name, sizeof(name));
361 
362   snprintf(stamp, TPORT_STAMP_SIZE,
363 	   "%s "MOD_ZU" bytes %s %s/[%s]:%u%s%s at %02u:%02u:%02u.%06lu:\n",
364 	   what, (size_t)n, via, self->tp_name->tpn_proto,
365 	   name, ntohs(su->su_port), label[0] ? label : "", comp,
366 	   hour, minute, second, now.tv_usec);
367 }
368 
369 /** Dump the data from the iovec */
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)370 void tport_dump_iovec(tport_t const *self, msg_t *msg,
371 		      size_t n, su_iovec_t const iov[], size_t iovused,
372 		      char const *what, char const *how)
373 {
374   tport_master_t *mr;
375   char stamp[TPORT_STAMP_SIZE];
376   size_t i;
377 
378   assert(self); assert(msg);
379 
380   mr = self->tp_master;
381   if (!mr->mr_dump_file)
382     return;
383 
384   tport_stamp(self, msg, stamp, what, n, how, su_now());
385   fputs(stamp, mr->mr_dump_file);
386 
387   for (i = 0; i < iovused && n > 0; i++) {
388     size_t len = iov[i].mv_len;
389     if (len > n)
390       len = n;
391     if (fwrite(iov[i].mv_base, len, 1, mr->mr_dump_file) != 1)
392       break;
393     n -= len;
394   }
395 
396   fputs("\v\n", mr->mr_dump_file);
397   fflush(mr->mr_dump_file);
398 }
399 
400 /** Capture the data from the iovec */
tport_capt_msg(tport_t const * self,msg_t * msg,size_t n,su_iovec_t const iov[],size_t iovused,char const * what)401 void tport_capt_msg(tport_t const *self, msg_t *msg, size_t n,
402                     su_iovec_t const iov[], size_t iovused, char const *what)
403 {
404 
405    int buflen = 0, error;
406    char* buffer = NULL;
407    tport_master_t *mr;
408 
409    assert(self);
410 
411    mr = self->tp_master;
412 
413    /* If we don't have socket, go out */
414    if (!mr->mr_capt_sock) {
415          su_log("error: capture socket is not open\n");
416          return;
417    }
418 
419    switch(mr->mr_prot_ver)
420    {
421 
422             case 3:
423                 buflen = tport_capt_msg_hepv3(self, msg, n, iov, iovused, what, &buffer);
424                 break;
425 
426             case 2:
427             case 1:
428                 buflen = tport_capt_msg_hepv2(self, msg, n, iov, iovused, what, &buffer);
429                 break;
430 
431             default:
432                 su_log("error: unsupported hep version\n");
433                 break;
434    }
435 
436    if(buflen > 0) {
437             /* check if we have error i.e. capture server is down */
438             if ((error = su_soerror(mr->mr_capt_sock))) {
439                      su_perror("error: tport_logging: capture socket error");
440                      goto done;
441             }
442 
443             su_send(mr->mr_capt_sock, buffer, buflen, 0);
444    }
445 
446 
447 done:
448    /* Now we release it */
449    if(buffer) free(buffer);
450    return;
451 }
452 
453 /** Capture the data from the iovec */
tport_capt_msg_hepv2(tport_t const * self,msg_t * msg,size_t n,su_iovec_t const iov[],size_t iovused,char const * what,char ** buffer)454 int tport_capt_msg_hepv2 (tport_t const *self, msg_t *msg, size_t n,
455                     su_iovec_t const iov[], size_t iovused, char const *what, char **buffer)
456 {
457 
458    int buflen = 0;
459    su_sockaddr_t const *su, *su_self;
460    struct hep_hdr hep_header;
461    struct hep_timehdr hep_time = {0};
462    su_time_t now;
463 #if __sun__
464    struct hep_iphdr hep_ipheader = {{{{0}}}};
465 #else
466    struct hep_iphdr hep_ipheader = {{0}};
467 #endif
468 #if SU_HAVE_IN6
469    struct hep_ip6hdr hep_ip6header = {{{{0}}}};
470 #endif
471    int eth_frame_len = 16000;
472    size_t i, dst = 1;
473    tport_master_t *mr;
474 
475    assert(self); assert(msg);
476 
477    su = msg_addr(msg);
478    su_self = self->tp_pri->pri_primary->tp_addr;
479 
480    mr = self->tp_master;
481 
482    /* If we don't have socket, go out */
483    if (!mr->mr_capt_sock) {
484          su_log("error: capture socket is not open\n");
485          return 0;
486    }
487 
488    /*buffer for ethernet frame*/
489    *buffer = (void*)malloc(eth_frame_len);
490 
491    /* VOIP Header */
492    hep_header.hp_v =  mr->mr_prot_ver;
493    hep_header.hp_f = su->su_family;
494    /* Header Length */
495    hep_header.hp_l = sizeof(struct hep_hdr);
496 
497    /* PROTOCOL */
498    if(strcmp(self->tp_name->tpn_proto, "tcp") == 0) hep_header.hp_p = IPPROTO_TCP;
499    else if(strcmp(self->tp_name->tpn_proto, "tls") == 0) hep_header.hp_p = IPPROTO_IDP; /* FAKE*/
500    else if(strcmp(self->tp_name->tpn_proto, "sctp") == 0) hep_header.hp_p = IPPROTO_SCTP;
501    else if(strcmp(self->tp_name->tpn_proto, "ws") == 0) hep_header.hp_p = IPPROTO_TCP;
502    else if(strcmp(self->tp_name->tpn_proto, "wss") == 0) hep_header.hp_p = IPPROTO_TCP;
503    else hep_header.hp_p = IPPROTO_UDP; /* DEFAULT UDP */
504 
505    /* Check destination */
506    if(strncmp("sent", what, 4) == 0) dst = 0;
507 
508    /* copy destination and source IPs*/
509    if(su->su_family == AF_INET) {
510 
511        memcpy(dst ? &hep_ipheader.hp_src : &hep_ipheader.hp_dst, &su->su_sin.sin_addr.s_addr, sizeof(su->su_sin.sin_addr.s_addr));
512        memcpy(dst ? &hep_ipheader.hp_dst : &hep_ipheader.hp_src, &su_self->su_sin.sin_addr.s_addr, sizeof(su_self->su_sin.sin_addr.s_addr));
513        hep_header.hp_l += sizeof(struct hep_iphdr);
514    }
515 #if SU_HAVE_IN6
516    else {
517        memcpy(dst ? &hep_ip6header.hp6_src : &hep_ip6header.hp6_dst, &su->su_sin.sin_addr.s_addr, sizeof(su->su_sin.sin_addr.s_addr));
518        memcpy(dst ? &hep_ip6header.hp6_dst : &hep_ip6header.hp6_src, &su_self->su_sin.sin_addr.s_addr, sizeof(su_self->su_sin.sin_addr.s_addr));
519        hep_header.hp_l += sizeof(struct hep_ip6hdr);
520    }
521 #endif
522 
523    hep_header.hp_dport = dst ? su_self->su_port : su->su_port;
524    hep_header.hp_sport = dst ? su->su_port : su_self->su_port;
525 
526    if (hep_header.hp_v == 2){
527            hep_header.hp_l += sizeof(struct hep_timehdr);
528    }
529 
530    /* Copy hepheader */
531    memset(*buffer, '\0', eth_frame_len);
532    memcpy(*buffer, &hep_header, sizeof(struct hep_hdr));
533    buflen = sizeof(struct hep_hdr);
534 
535    if(su->su_family == AF_INET) {
536        memcpy(*buffer + buflen, &hep_ipheader, sizeof(struct hep_iphdr));
537        buflen += sizeof(struct hep_iphdr);
538    }
539 #if SU_HAVE_IN6
540    else if(su->su_family == AF_INET6) {
541        memcpy(*buffer+buflen, &hep_ip6header, sizeof(struct hep_ip6hdr));
542        buflen += sizeof(struct hep_ip6hdr);
543    }
544 #endif
545    else {
546        su_perror("error: tport_logging: capture: unsupported protocol family");
547        goto done;
548    }
549 
550    /* copy time header */
551    if (hep_header.hp_v == 2) {
552         /* now */
553         now = su_now();
554         /* should check for ifdef HAVE_LOCALTIME_R instead -_- */
555 #if defined(HAVE_GETTIMEOFDAY) || defined(HAVE_CLOCK_MONOTONIC)
556         hep_time.tv_sec = (now.tv_sec - SU_TIME_EPOCH); /* see su_time0.c 'now' is not really 'now', so we decrease it by SU_TIME_EPOCH */
557 #else
558         hep_time.tv_sec = now.tv_sec;
559 #endif
560         hep_time.tv_usec = now.tv_usec;
561 
562         hep_time.captid = mr->mr_agent_id;
563         memcpy((char*)*buffer+buflen, &hep_time, sizeof(struct hep_timehdr));
564         buflen += sizeof(struct hep_timehdr);
565    }
566 
567    for (i = 0; i < iovused && n > 0; i++) {
568        size_t len = iov[i].mv_len;
569        if (len > n)
570             len = n;
571        /* if the packet too big for us */
572        if((buflen + len) > eth_frame_len)
573               break;
574 
575       memcpy(*buffer + buflen , (void*)iov[i].mv_base, len);
576       buflen +=len;
577       n -= len;
578    }
579 
580    return buflen;
581 
582 done:
583    /* Now we release it */
584    if(*buffer) {
585         free(*buffer);
586         *buffer = NULL;
587    }
588    return 0;
589 }
590 
591 
592 /** Capture the data from the iovec */
tport_capt_msg_hepv3(tport_t const * self,msg_t * msg,size_t n,su_iovec_t const iov[],size_t iovused,char const * what,char ** buffer)593 int tport_capt_msg_hepv3 (tport_t const *self, msg_t *msg, size_t n,
594         su_iovec_t const iov[], size_t iovused, char const *what, char **buffer)
595 {
596 
597    su_sockaddr_t const *su, *su_self;
598    struct hep_generic *hg=NULL;
599    unsigned int buflen=0, iplen=0,tlen=0, payload_len = 0;
600    su_time_t now;
601    hep_chunk_ip4_t src_ip4 = {{0}}, dst_ip4 = {{0}};
602    hep_chunk_t payload_chunk;
603    int orig_n = 0;
604 
605 #if SU_HAVE_IN6
606    hep_chunk_ip6_t src_ip6 = {{0}}, dst_ip6 = {{0}};
607 #endif
608 
609    int eth_frame_len = 16000;
610    size_t i, dst = 1;
611    tport_master_t *mr;
612 
613    assert(self); assert(msg);
614 
615    su = msg_addr(msg);
616    su_self = self->tp_pri->pri_primary->tp_addr;
617 
618    mr = self->tp_master;
619 
620    /* If we don't have socket, go out */
621    if (!mr->mr_capt_sock) {
622          su_log("error: capture socket is not open\n");
623          return 0;
624    }
625 
626    /*buffer for ethernet frame*/
627 
628    hg = malloc(sizeof(struct hep_generic));
629    memset(hg, 0, sizeof(struct hep_generic));
630 
631    /* header set */
632    memcpy(hg->header.id, "\x48\x45\x50\x33", 4);
633 
634    /* IP proto */
635    hg->ip_family.chunk.vendor_id = htons(0x0000);
636    hg->ip_family.chunk.type_id   = htons(0x0001);
637    hg->ip_family.data = su->su_family;
638    hg->ip_family.chunk.length = htons(sizeof(hg->ip_family));
639 
640    /* PROTOCOL */
641    if(strcmp(self->tp_name->tpn_proto, "tcp") == 0) hg->ip_proto.data = IPPROTO_TCP;
642    else if(strcmp(self->tp_name->tpn_proto, "tls") == 0) hg->ip_proto.data = IPPROTO_IDP; /* FAKE*/
643    else if(strcmp(self->tp_name->tpn_proto, "sctp") == 0) hg->ip_proto.data = IPPROTO_SCTP;
644    else if(strcmp(self->tp_name->tpn_proto, "ws") == 0) hg->ip_proto.data = IPPROTO_TCP;
645    else if(strcmp(self->tp_name->tpn_proto, "wss") == 0) hg->ip_proto.data = IPPROTO_TCP;
646    else hg->ip_proto.data = IPPROTO_UDP; /* DEFAULT UDP */
647 
648    /* Proto ID */
649    hg->ip_proto.chunk.vendor_id = htons(0x0000);
650    hg->ip_proto.chunk.type_id   = htons(0x0002);
651    hg->ip_proto.chunk.length = htons(sizeof(hg->ip_proto));
652 
653    /* Check destination */
654    if(strncmp("sent", what, 4) == 0) dst = 0;
655 
656    /* copy destination and source IPs*/
657    if(su->su_family == AF_INET) {
658 
659 	/* SRC IP */
660         src_ip4.chunk.vendor_id = htons(0x0000);
661         src_ip4.chunk.type_id   = htons(0x0003);
662         memcpy(dst ? &src_ip4.data : &dst_ip4.data, &su->su_sin.sin_addr.s_addr, sizeof(su->su_sin.sin_addr.s_addr));
663         src_ip4.chunk.length = htons(sizeof(src_ip4));
664 
665         /* DST IP */
666         dst_ip4.chunk.vendor_id = htons(0x0000);
667         dst_ip4.chunk.type_id   = htons(0x0004);
668         memcpy(dst ? &dst_ip4.data : &src_ip4.data,  &su_self->su_sin.sin_addr.s_addr, sizeof(su_self->su_sin.sin_addr.s_addr));
669         dst_ip4.chunk.length = htons(sizeof(dst_ip4));
670 
671         iplen = sizeof(dst_ip4) + sizeof(src_ip4);
672    }
673 #if SU_HAVE_IN6
674    else if(su->su_family == AF_INET6) {
675 
676 	/* SRC IPv6 */
677         src_ip6.chunk.vendor_id = htons(0x0000);
678         src_ip6.chunk.type_id   = htons(0x0005);
679         memcpy(dst ? &src_ip6.data : &dst_ip6.data, &su->su_sin.sin_addr.s_addr, sizeof(su->su_sin.sin_addr.s_addr));
680         src_ip6.chunk.length = htons(sizeof(src_ip6));
681 
682         /* DST IPv6 */
683         dst_ip6.chunk.vendor_id = htons(0x0000);
684         dst_ip6.chunk.type_id   = htons(0x0006);
685         memcpy(dst ? &dst_ip6.data : &src_ip6.data, &su_self->su_sin.sin_addr.s_addr, sizeof(su_self->su_sin.sin_addr.s_addr));
686         dst_ip6.chunk.length = htons(sizeof(dst_ip6));
687 
688         iplen = sizeof(dst_ip6) + sizeof(src_ip6);
689    }
690 #endif
691    else {
692        su_perror("error: tport_logging hepv3: capture: unsupported protocol family");
693        goto done;
694    }
695 
696    /* SRC PORT */
697     hg->src_port.chunk.vendor_id = htons(0x0000);
698     hg->src_port.chunk.type_id   = htons(0x0007);
699     hg->src_port.data = dst ? su->su_port : su_self->su_port;
700     hg->src_port.chunk.length = htons(sizeof(hg->src_port));
701 
702     /* DST PORT */
703     hg->dst_port.chunk.vendor_id = htons(0x0000);
704     hg->dst_port.chunk.type_id   = htons(0x0008);
705     hg->dst_port.data = dst ? su_self->su_port : su->su_port;
706     hg->dst_port.chunk.length = htons(sizeof(hg->dst_port));
707 
708 
709     /* TIMESTAMP SEC */
710     hg->time_sec.chunk.vendor_id = htons(0x0000);
711     hg->time_sec.chunk.type_id   = htons(0x0009);
712     hg->time_sec.chunk.length = htons(sizeof(hg->time_sec));
713 
714     now = su_now();
715     /* should check for ifdef HAVE_LOCALTIME_R instead -_- */
716 #if defined(HAVE_GETTIMEOFDAY) || defined(HAVE_CLOCK_MONOTONIC)
717     hg->time_sec.data = htonl(now.tv_sec - SU_TIME_EPOCH); /* see su_time0.c 'now' is not really 'now', so we decrease it by SU_TIME_EPOCH */
718 #else
719     hg->time_sec.data = htonl(now.tv_sec);
720 #endif
721 
722     /* TIMESTAMP USEC */
723     hg->time_usec.chunk.vendor_id = htons(0x0000);
724     hg->time_usec.chunk.type_id   = htons(0x000a);
725     hg->time_usec.data = htonl(now.tv_usec);
726     hg->time_usec.chunk.length = htons(sizeof(hg->time_usec));
727 
728     /* Protocol TYPE */
729     hg->proto_t.chunk.vendor_id = htons(0x0000);
730     hg->proto_t.chunk.type_id   = htons(0x000b);
731     hg->proto_t.data = 0x001; //SIP
732     hg->proto_t.chunk.length = htons(sizeof(hg->proto_t));
733 
734     /* Capture ID */
735     hg->capt_id.chunk.vendor_id = htons(0x0000);
736     hg->capt_id.chunk.type_id   = htons(0x000c);
737     hg->capt_id.data = htonl(mr->mr_agent_id);
738     hg->capt_id.chunk.length = htons(sizeof(hg->capt_id));
739 
740 
741     /* Payload caclulation */
742     orig_n = n;
743     for (i = 0; i < iovused && n > 0; i++) {
744        	size_t len = iov[i].mv_len;
745 	if (len > n) len = n;
746 	if((payload_len + len) > eth_frame_len) break;
747         payload_len +=len;
748     	n -= len;
749     }
750     /* restore n */
751     n = orig_n;
752 
753     /* Payload */
754     payload_chunk.vendor_id = htons(0x0000);
755     payload_chunk.type_id   = htons(0x000f);
756     payload_chunk.length    = htons(sizeof(payload_chunk) + payload_len);
757 
758     tlen = sizeof(struct hep_generic) + payload_len + iplen + sizeof(hep_chunk_t);
759 
760     /* total */
761     hg->header.length = htons(tlen);
762 
763     *buffer = (void*)malloc(tlen);
764 
765     if (*buffer==NULL){
766        su_perror("error: tport_logging hepv3: no memory for buffer");
767        goto done;
768     }
769 
770     memcpy((void*) *buffer, hg, sizeof(struct hep_generic));
771     buflen = sizeof(struct hep_generic);
772 
773     /* IPv4 */
774    if(su->su_family == AF_INET) {
775         /* SRC IP */
776         memcpy((char*) *buffer+buflen, &src_ip4, sizeof(struct hep_chunk_ip4));
777         buflen += sizeof(struct hep_chunk_ip4);
778 
779         memcpy((char*) *buffer+buflen, &dst_ip4, sizeof(struct hep_chunk_ip4));
780         buflen += sizeof(struct hep_chunk_ip4);
781     }
782 #if SU_HAVE_IN6
783       /* IPv6 */
784     else if(su->su_family == AF_INET6) {
785         /* SRC IPv6 */
786         memcpy((char*) *buffer+buflen, &src_ip6, sizeof(struct hep_chunk_ip6));
787         buflen += sizeof(struct hep_chunk_ip6);
788 
789         memcpy((char*) *buffer+buflen, &dst_ip6, sizeof(struct hep_chunk_ip6));
790         buflen += sizeof(struct hep_chunk_ip6);
791     }
792 #endif
793 
794     /* PAYLOAD CHUNK */
795     memcpy((char*) *buffer+buflen, &payload_chunk,  sizeof(struct hep_chunk));
796     buflen +=  sizeof(struct hep_chunk);
797 
798    /* PAYLOAD */
799    for (i = 0; i < iovused && n > 0; i++) {
800        size_t len = iov[i].mv_len;
801        if (len > n) len = n;
802        /* if the packet too big for us */
803        if((buflen + len) > eth_frame_len)
804               break;
805 
806       memcpy(*buffer + buflen , (void*)iov[i].mv_base, len);
807       buflen +=len;
808       n -= len;
809    }
810 
811    free(hg);
812    return buflen;
813 
814 done:
815    /* Now we release it */
816    if(hg) free(hg);
817    return 0;
818 }
819 
820 
821 /** Log the message. */
tport_log_msg(tport_t * self,msg_t * msg,char const * what,char const * via,su_time_t now)822 void tport_log_msg(tport_t *self, msg_t *msg,
823 		   char const *what, char const *via,
824 		   su_time_t now)
825 {
826   msg_iovec_t iov[80];
827   size_t i, iovlen = msg_iovec(msg, iov, 80);
828   size_t n;
829   int skip_lf = 0;
830   char *buffer = NULL;
831   size_t buffer_size = 0;
832   size_t buffer_pos = 0;
833   size_t bytes_written = 0;
834 
835 #define MSG_SEPARATOR \
836   "------------------------------------------------------------------------\n"
837 
838   for (i = n = 0; i < iovlen && i < 80; i++)
839     n += iov[i].mv_len;
840 
841   buffer_size = sizeof(char) * n + 1 + TPORT_STAMP_SIZE + sizeof(MSG_SEPARATOR);
842   if (buffer_size > 16000) {
843     buffer_size = 16000;
844   }
845 
846   buffer = malloc(buffer_size);
847   buffer[0] = '\0';
848 
849   tport_stamp(self, msg, buffer, what, n, via, now);
850   buffer_pos = strlen(buffer);
851   if (buffer_pos < buffer_size) {
852     bytes_written = snprintf(buffer + buffer_pos, buffer_size - buffer_pos, "%s", MSG_SEPARATOR);
853     if (bytes_written > 0) {
854       buffer_pos += bytes_written;
855     }
856   }
857 
858   for (i = 0; buffer_pos < buffer_size && i < iovlen && i < 80; i++) {
859     char *s = iov[i].mv_base, *end = s + iov[i].mv_len;
860 
861     if (skip_lf && s < end && s[0] == '\n') { s++; skip_lf = 0; }
862 
863     while (s < end) {
864       if (s[0] == '\0') {
865         break;
866       }
867 
868       n = su_strncspn(s, end - s, "\r\n");
869       if (buffer_pos > buffer_size) {
870         break;
871       }
872       bytes_written = snprintf(buffer + buffer_pos, buffer_size - buffer_pos, "%.*s", (int)n, s);
873       if (bytes_written > 0) {
874         buffer_pos += bytes_written;
875       }
876 
877       s += n;
878 
879       if (s == end)
880         break;
881 
882       if (buffer_pos < buffer_size) {
883         buffer[buffer_pos++] = '\n';
884       }
885       /* Skip eol */
886       if (s[0] == '\r') {
887         s++;
888         if (s == end) {
889           skip_lf = 1;
890           continue;
891         }
892       }
893 
894       if (s[0] == '\n') {
895         s++;
896       }
897     }
898   }
899 
900   if (buffer_pos >= buffer_size) {
901     buffer_pos = buffer_size - 1;
902   }
903   buffer[buffer_pos] = '\0';
904   su_log("%s", buffer);
905   free(buffer);
906 }
907