File: | libsofia-sip-ua/tport/tport_logging.c |
Warning: | line 438, column 18 Although the value stored to 'error' is used in the enclosing expression, the value is never actually read from 'error' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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(*__errno_location ()).h> |
46 | #include <limits.h> |
47 | |
48 | #define TPORT_STAMP_SIZE144 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){ sizeof(su_log_t), "tport", "TPORT_DEBUG", 0, SU_LOG_MAX, 0, ((void*)0), ((void*)0), } |
112 | }; |
113 | |
114 | |
115 | |
116 | /** Initialize logging. */ |
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((void*)0); |
122 | char const *capt = NULL((void*)0);; |
123 | |
124 | if(mr->mr_capt_name) capt = mr->mr_capt_name; |
125 | |
126 | n = tl_gets(tags, |
127 | TPTAG_LOG_REF(log_msg)tptag_log_ref, tag_bool_vr(&(log_msg)), |
128 | TPTAG_DUMP_REF(dump)tptag_dump_ref, tag_str_vr(&(dump)), |
129 | TPTAG_CAPT_REF(capt)tptag_capt_ref, tag_str_vr(&(capt)), |
130 | TAG_END()(tag_type_t)0, (tag_value_t)0); |
131 | |
132 | if (getenv("MSG_STREAM_LOG") != NULL((void*)0) || getenv("TPORT_LOG") != NULL((void*)0)) |
133 | log_msg = 1; |
134 | mr->mr_log = log_msg ? MSG_DO_EXTRACT_COPYMSG_FLG_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((void*)0), 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_homemr_master->tp_home, capt); |
156 | if (captname == NULL((void*)0)) |
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))(((tport_log != ((void*)0) && tport_log->log_init) == 0 ? 9 : ((tport_log != ((void*)0) && tport_log-> log_init > 1) ? tport_log->log_level : su_log_default-> log_level)) >= 7 ? (_su_llog(tport_log, 7, "tport_logging.c" , (const char *)__func__, 206, "events HEP RRR DATA [%s]\n", p )) : (void)0); |
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_homemr_master->tp_home, capt); |
247 | if (captname == NULL((void*)0)) return n; |
248 | |
249 | su_free(mr->mr_homemr_master->tp_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_NUMERICSERV0x0400; |
257 | hints->ai_family = AF_UNSPEC0; |
258 | hints->ai_socktype = SOCK_DGRAMSOCK_DGRAM; |
259 | hints->ai_protocol = IPPROTO_UDPIPPROTO_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((su_socket_t)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(*__errno_location ()) != EINPROGRESS115) { |
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_homemr_master->tp_home, dump); |
296 | if (dumpname == NULL((void*)0)) |
297 | return n; |
298 | su_free(mr->mr_homemr_master->tp_home, mr->mr_dump); |
299 | mr->mr_dump = dumpname; |
300 | |
301 | if (mr->mr_dump_file && mr->mr_dump_file != stdoutstdout) |
302 | fclose(mr->mr_dump_file), mr->mr_dump_file = NULL((void*)0); |
303 | |
304 | if (strcmp(dumpname, "-")) |
305 | mr->mr_dump_file = fopen(dumpname, "ab"); /* XXX */ |
306 | else |
307 | mr->mr_dump_file = stdoutstdout; |
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 */ |
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(48)] = ""; |
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_GETTIMEOFDAY1) || defined(HAVE_CLOCK_MONOTONIC1) |
331 | struct tm nowtm = { 0 }; |
332 | time_t nowtime = (now.tv_sec - SU_TIME_EPOCH2208988800UL); /* see su_time0.c 'now' is not really 'now', so we decrease it by SU_TIME_EPOCH */ |
333 | #endif |
334 | |
335 | assert(self)((void) sizeof ((self) ? 1 : 0), __extension__ ({ if (self) ; else __assert_fail ("self", "tport_logging.c", 335, __extension__ __PRETTY_FUNCTION__); })); assert(msg)((void) sizeof ((msg) ? 1 : 0), __extension__ ({ if (msg) ; else __assert_fail ("msg", "tport_logging.c", 335, __extension__ __PRETTY_FUNCTION__ ); })); |
336 | |
337 | #if defined(HAVE_GETTIMEOFDAY1) || defined(HAVE_CLOCK_MONOTONIC1) |
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_IN61 |
351 | if (su->su_familysu_sa.sa_family == AF_INET610) { |
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_COMPRESSED0x01000) |
358 | comp = ";comp=sigcomp"; |
359 | |
360 | su_inet_ntopinet_ntop(su->su_familysu_sa.sa_family, SU_ADDR(su)((su)->su_sa.sa_family == 2 ? (void *)&(su)->su_sin .sin_addr : ((su)->su_sa.sa_family == 10 ? (void *)&(su )->su_sin6.sin6_addr : (void *)&(su)->su_sa.sa_data )), name, sizeof(name)); |
361 | |
362 | snprintf(stamp, TPORT_STAMP_SIZE144, |
363 | "%s "MOD_ZU"%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_portsu_sin.sin_port), label[0] ? label : "", comp, |
366 | hour, minute, second, now.tv_usec); |
367 | } |
368 | |
369 | /** Dump the data from the iovec */ |
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_SIZE144]; |
376 | size_t i; |
377 | |
378 | assert(self)((void) sizeof ((self) ? 1 : 0), __extension__ ({ if (self) ; else __assert_fail ("self", "tport_logging.c", 378, __extension__ __PRETTY_FUNCTION__); })); assert(msg)((void) sizeof ((msg) ? 1 : 0), __extension__ ({ if (msg) ; else __assert_fail ("msg", "tport_logging.c", 378, __extension__ __PRETTY_FUNCTION__ ); })); |
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_lensiv_len; |
389 | if (len > n) |
390 | len = n; |
391 | if (fwrite(iov[i].mv_basesiv_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 */ |
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((void*)0); |
407 | tport_master_t *mr; |
408 | |
409 | assert(self)((void) sizeof ((self) ? 1 : 0), __extension__ ({ if (self) ; else __assert_fail ("self", "tport_logging.c", 409, __extension__ __PRETTY_FUNCTION__); })); |
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))) { |
Although the value stored to 'error' is used in the enclosing expression, the value is never actually read from 'error' | |
439 | su_perror("error: tport_logging: capture socket error"); |
440 | goto done; |
441 | } |
442 | |
443 | su_send(mr->mr_capt_sock, buffer, buflen, 0)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 */ |
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_IN61 |
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)((void) sizeof ((self) ? 1 : 0), __extension__ ({ if (self) ; else __assert_fail ("self", "tport_logging.c", 475, __extension__ __PRETTY_FUNCTION__); })); assert(msg)((void) sizeof ((msg) ? 1 : 0), __extension__ ({ if (msg) ; else __assert_fail ("msg", "tport_logging.c", 475, __extension__ __PRETTY_FUNCTION__ ); })); |
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_familysu_sa.sa_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_TCPIPPROTO_TCP; |
499 | else if(strcmp(self->tp_name->tpn_proto, "tls") == 0) hep_header.hp_p = IPPROTO_IDPIPPROTO_IDP; /* FAKE*/ |
500 | else if(strcmp(self->tp_name->tpn_proto, "sctp") == 0) hep_header.hp_p = IPPROTO_SCTPIPPROTO_SCTP; |
501 | else if(strcmp(self->tp_name->tpn_proto, "ws") == 0) hep_header.hp_p = IPPROTO_TCPIPPROTO_TCP; |
502 | else if(strcmp(self->tp_name->tpn_proto, "wss") == 0) hep_header.hp_p = IPPROTO_TCPIPPROTO_TCP; |
503 | else hep_header.hp_p = IPPROTO_UDPIPPROTO_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_familysu_sa.sa_family == AF_INET2) { |
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_IN61 |
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_portsu_sin.sin_port : su->su_portsu_sin.sin_port; |
524 | hep_header.hp_sport = dst ? su->su_portsu_sin.sin_port : su_self->su_portsu_sin.sin_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_familysu_sa.sa_family == AF_INET2) { |
536 | memcpy(*buffer + buflen, &hep_ipheader, sizeof(struct hep_iphdr)); |
537 | buflen += sizeof(struct hep_iphdr); |
538 | } |
539 | #if SU_HAVE_IN61 |
540 | else if(su->su_familysu_sa.sa_family == AF_INET610) { |
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_GETTIMEOFDAY1) || defined(HAVE_CLOCK_MONOTONIC1) |
556 | hep_time.tv_sec = (now.tv_sec - SU_TIME_EPOCH2208988800UL); /* 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_lensiv_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_basesiv_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((void*)0); |
587 | } |
588 | return 0; |
589 | } |
590 | |
591 | |
592 | /** Capture the data from the iovec */ |
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((void*)0); |
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_IN61 |
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)((void) sizeof ((self) ? 1 : 0), __extension__ ({ if (self) ; else __assert_fail ("self", "tport_logging.c", 613, __extension__ __PRETTY_FUNCTION__); })); assert(msg)((void) sizeof ((msg) ? 1 : 0), __extension__ ({ if (msg) ; else __assert_fail ("msg", "tport_logging.c", 613, __extension__ __PRETTY_FUNCTION__ ); })); |
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_familysu_sa.sa_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_TCPIPPROTO_TCP; |
642 | else if(strcmp(self->tp_name->tpn_proto, "tls") == 0) hg->ip_proto.data = IPPROTO_IDPIPPROTO_IDP; /* FAKE*/ |
643 | else if(strcmp(self->tp_name->tpn_proto, "sctp") == 0) hg->ip_proto.data = IPPROTO_SCTPIPPROTO_SCTP; |
644 | else if(strcmp(self->tp_name->tpn_proto, "ws") == 0) hg->ip_proto.data = IPPROTO_TCPIPPROTO_TCP; |
645 | else if(strcmp(self->tp_name->tpn_proto, "wss") == 0) hg->ip_proto.data = IPPROTO_TCPIPPROTO_TCP; |
646 | else hg->ip_proto.data = IPPROTO_UDPIPPROTO_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_familysu_sa.sa_family == AF_INET2) { |
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_IN61 |
674 | else if(su->su_familysu_sa.sa_family == AF_INET610) { |
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_portsu_sin.sin_port : su_self->su_portsu_sin.sin_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_portsu_sin.sin_port : su->su_portsu_sin.sin_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_GETTIMEOFDAY1) || defined(HAVE_CLOCK_MONOTONIC1) |
717 | hg->time_sec.data = htonl(now.tv_sec - SU_TIME_EPOCH2208988800UL); /* 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_lensiv_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((void*)0)){ |
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_familysu_sa.sa_family == AF_INET2) { |
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_IN61 |
783 | /* IPv6 */ |
784 | else if(su->su_familysu_sa.sa_family == AF_INET610) { |
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_lensiv_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_basesiv_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. */ |
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((void*)0); |
831 | size_t buffer_size = 0; |
832 | size_t buffer_pos = 0; |
833 | size_t bytes_written = 0; |
834 | |
835 | #define MSG_SEPARATOR"------------------------------------------------------------------------\n" \ |
836 | "------------------------------------------------------------------------\n" |
837 | |
838 | for (i = n = 0; i < iovlen && i < 80; i++) |
839 | n += iov[i].mv_lensiv_len; |
840 | |
841 | buffer_size = sizeof(char) * n + 1 + TPORT_STAMP_SIZE144 + sizeof(MSG_SEPARATOR"------------------------------------------------------------------------\n"); |
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"------------------------------------------------------------------------\n"); |
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_basesiv_base, *end = s + iov[i].mv_lensiv_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\n", buffer); |
905 | free(buffer); |
906 | } |