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