revert between 56095 -> 55830 in arch
[AROS.git] / workbench / network / stacks / AROSTCP / dhcp / omapip / trace.c
blob935f537cff91d37aa09a2f4bcc231f3a77a6725d
1 /* trace.c
3 Subroutines that support tracing of OMAPI wire transactions and
4 provide a mechanism for programs using OMAPI to trace their own
5 transactions... */
7 /*
8 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
9 * Copyright (c) 2001-2003 by Internet Software Consortium
11 * Permission to use, copy, modify, and distribute this software for any
12 * purpose with or without fee is hereby granted, provided that the above
13 * copyright notice and this permission notice appear in all copies.
15 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Internet Systems Consortium, Inc.
24 * 950 Charter Street
25 * Redwood City, CA 94063
26 * <info@isc.org>
27 * http://www.isc.org/
29 * This software has been written for Internet Systems Consortium
30 * by Ted Lemon, as part of a project for Nominum, Inc. To learn more
31 * about Internet Systems Consortium, see http://www.isc.org/. To
32 * learn more about Nominum, Inc., see ``http://www.nominum.com''.
35 #include <omapip/omapip_p.h>
37 #if defined (TRACING)
38 void (*trace_set_time_hook) (u_int32_t);
39 static int tracing_stopped;
40 static int traceoutfile;
41 static int traceindex;
42 static trace_type_t **trace_types;
43 static int trace_type_count;
44 static int trace_type_max;
45 static trace_type_t *new_trace_types;
46 static FILE *traceinfile;
47 static tracefile_header_t tracefile_header;
48 static int trace_playback_flag;
49 trace_type_t trace_time_marker;
51 #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
52 extern omapi_array_t *trace_listeners;
53 extern omapi_array_t *omapi_connections;
55 void trace_free_all ()
57 trace_type_t *tp;
58 int i;
59 tp = new_trace_types;
60 while (tp) {
61 new_trace_types = tp -> next;
62 if (tp -> name) {
63 dfree (tp -> name, MDL);
64 tp -> name = (char *)0;
66 dfree (tp, MDL);
67 tp = new_trace_types;
69 for (i = 0; i < trace_type_count; i++) {
70 if (trace_types [i]) {
71 if (trace_types [i] -> name)
72 dfree (trace_types [i] -> name, MDL);
73 dfree (trace_types [i], MDL);
76 dfree (trace_types, MDL);
77 trace_types = (trace_type_t **)0;
78 trace_type_count = trace_type_max = 0;
80 omapi_array_free (&trace_listeners, MDL);
81 omapi_array_free (&omapi_connections, MDL);
83 #endif
85 static isc_result_t trace_type_record (trace_type_t *,
86 unsigned, const char *, int);
88 int trace_playback ()
90 return trace_playback_flag;
93 int trace_record ()
95 if (traceoutfile && !tracing_stopped)
96 return 1;
97 return 0;
100 isc_result_t trace_init (void (*set_time) (u_int32_t),
101 const char *file, int line)
103 trace_type_t *root_type;
104 static int root_setup = 0;
106 if (root_setup)
107 return ISC_R_SUCCESS;
109 trace_set_time_hook = set_time;
111 root_type = trace_type_register ("trace-index-mapping",
112 (void *)0, trace_index_map_input,
113 trace_index_stop_tracing, file, line);
114 if (!root_type)
115 return ISC_R_UNEXPECTED;
116 if (new_trace_types == root_type)
117 new_trace_types = new_trace_types -> next;
118 root_type -> index = 0;
119 trace_type_stash (root_type);
121 root_setup = 1;
122 return ISC_R_SUCCESS;
125 isc_result_t trace_begin (const char *filename,
126 const char *file, int line)
128 tracefile_header_t tfh;
129 int status;
130 trace_type_t *tptr, *next;
131 isc_result_t result;
133 if (traceoutfile) {
134 log_error ("%s(%d): trace_begin called twice",
135 file, line);
136 return ISC_R_INVALIDARG;
139 traceoutfile = open (filename, O_CREAT | O_WRONLY | O_EXCL, 0644);
140 if (traceoutfile < 0) {
141 log_error ("%s(%d): trace_begin: %s: %m",
142 file, line, filename);
143 return ISC_R_UNEXPECTED;
145 #if defined (HAVE_SETFD)
146 if (fcntl (traceoutfile, F_SETFD, 1) < 0)
147 log_error ("Can't set close-on-exec on %s: %m", filename);
148 #endif
150 tfh.magic = htonl (TRACEFILE_MAGIC);
151 tfh.version = htonl (TRACEFILE_VERSION);
152 tfh.hlen = htonl (sizeof (tracefile_header_t));
153 tfh.phlen = htonl (sizeof (tracepacket_t));
155 status = write (traceoutfile, &tfh, sizeof tfh);
156 if (status < 0) {
157 log_error ("%s(%d): trace_begin write failed: %m", file, line);
158 return ISC_R_UNEXPECTED;
159 } else if (status != sizeof tfh) {
160 log_error ("%s(%d): trace_begin: short write (%d:%ld)",
161 file, line, status, (long)(sizeof tfh));
162 trace_stop ();
163 return ISC_R_UNEXPECTED;
166 /* Stash all the types that have already been set up. */
167 if (new_trace_types) {
168 next = new_trace_types;
169 new_trace_types = (trace_type_t *)0;
170 for (tptr = next; tptr; tptr = next) {
171 next = tptr -> next;
172 if (tptr -> index != 0) {
173 result = (trace_type_record
174 (tptr,
175 strlen (tptr -> name), file, line));
176 if (result != ISC_R_SUCCESS)
177 return status;
182 return ISC_R_SUCCESS;
185 isc_result_t trace_write_packet (trace_type_t *ttype, unsigned length,
186 const char *buf, const char *file, int line)
188 trace_iov_t iov;
190 iov.buf = buf;
191 iov.len = length;
192 return trace_write_packet_iov (ttype, 1, &iov, file, line);
195 isc_result_t trace_write_packet_iov (trace_type_t *ttype,
196 int count, trace_iov_t *iov,
197 const char *file, int line)
199 tracepacket_t tmp;
200 int status;
201 int i;
202 int length;
204 /* Really shouldn't get called here, but it may be hard to turn off
205 tracing midstream if the trace file write fails or something. */
206 if (tracing_stopped)
207 return 0;
209 if (!ttype) {
210 log_error ("%s(%d): trace_write_packet with null trace type",
211 file ? file : "<unknown file>", line);
212 return ISC_R_INVALIDARG;
214 if (!traceoutfile) {
215 log_error ("%s(%d): trace_write_packet with no tracefile.",
216 file ? file : "<unknown file>", line);
217 return ISC_R_INVALIDARG;
220 /* Compute the total length of the iov. */
221 length = 0;
222 for (i = 0; i < count; i++)
223 length += iov [i].len;
225 /* We have to swap out the data, because it may be read back on a
226 machine of different endianness. */
227 tmp.type_index = htonl (ttype -> index);
228 tmp.when = htonl (time ((time_t *)0)); /* XXX */
229 tmp.length = htonl (length);
231 status = write (traceoutfile, &tmp, sizeof tmp);
232 if (status < 0) {
233 log_error ("%s(%d): trace_write_packet write failed: %m",
234 file, line);
235 return ISC_R_UNEXPECTED;
236 } else if (status != sizeof tmp) {
237 log_error ("%s(%d): trace_write_packet: short write (%d:%ld)",
238 file, line, status, (long)(sizeof tmp));
239 trace_stop ();
242 for (i = 0; i < count; i++) {
243 status = write (traceoutfile, iov [i].buf, iov [i].len);
244 if (status < 0) {
245 log_error ("%s(%d): %s write failed: %m",
246 file, line, "trace_write_packet");
247 return ISC_R_UNEXPECTED;
248 } else if (status != iov [i].len) {
249 log_error ("%s(%d): %s: short write (%d:%d)",
250 file, line,
251 "trace_write_packet", status, length);
252 trace_stop ();
256 /* Write padding on the end of the packet to align the next
257 packet to an 8-byte boundary. This is in case we decide to
258 use mmap in some clever way later on. */
259 if (length % 8) {
260 static char zero [] = { 0, 0, 0, 0, 0, 0, 0 };
261 unsigned padl = 8 - (length % 8);
263 status = write (traceoutfile, zero, padl);
264 if (status < 0) {
265 log_error ("%s(%d): trace_write_packet write failed: %m",
266 file, line);
267 return ISC_R_UNEXPECTED;
268 } else if (status != padl) {
269 log_error ("%s(%d): trace_write_packet: short write (%d:%d)",
270 file, line, status, padl);
271 trace_stop ();
275 return ISC_R_SUCCESS;
278 void trace_type_stash (trace_type_t *tptr)
280 trace_type_t **vec;
281 int delta;
282 if (trace_type_max <= tptr -> index) {
283 delta = tptr -> index - trace_type_max + 10;
284 vec = dmalloc (((trace_type_max + delta) *
285 sizeof (trace_type_t *)), MDL);
286 if (!vec)
287 return;
288 memset (&vec [trace_type_max], 0,
289 (sizeof (trace_type_t *)) * delta);
290 trace_type_max += delta;
291 if (trace_types) {
292 memcpy (vec, trace_types,
293 trace_type_count * sizeof (trace_type_t *));
294 dfree (trace_types, MDL);
296 trace_types = vec;
298 trace_types [tptr -> index] = tptr;
299 if (tptr -> index >= trace_type_count)
300 trace_type_count = tptr -> index + 1;
303 trace_type_t *trace_type_register (const char *name,
304 void *baggage,
305 void (*have_packet) (trace_type_t *,
306 unsigned, char *),
307 void (*stop_tracing) (trace_type_t *),
308 const char *file, int line)
310 trace_type_t *ttmp;
311 // trace_type_t *tptr;
312 unsigned slen = strlen (name);
313 isc_result_t status;
315 ttmp = dmalloc (sizeof *ttmp, file, line);
316 if (!ttmp)
317 return ttmp;
318 ttmp -> index = -1;
319 ttmp -> name = dmalloc (slen + 1, file, line);
320 if (!ttmp -> name) {
321 dfree (ttmp, file, line);
322 return (trace_type_t *)0;
324 strcpy (ttmp -> name, name);
325 ttmp -> have_packet = have_packet;
326 ttmp -> stop_tracing = stop_tracing;
328 if (traceoutfile) {
329 status = trace_type_record (ttmp, slen, file, line);
330 if (status != ISC_R_SUCCESS) {
331 dfree (ttmp -> name, file, line);
332 dfree (ttmp, file, line);
333 return (trace_type_t *)0;
335 } else {
336 ttmp -> next = new_trace_types;
337 new_trace_types = ttmp;
340 return ttmp;
343 static isc_result_t trace_type_record (trace_type_t *ttmp, unsigned slen,
344 const char *file, int line)
346 trace_index_mapping_t *tim;
347 isc_result_t status;
349 tim = dmalloc (slen + TRACE_INDEX_MAPPING_SIZE, file, line);
350 if (!tim)
351 return ISC_R_NOMEMORY;
352 ttmp -> index = ++traceindex;
353 trace_type_stash (ttmp);
354 tim -> index = htonl (ttmp -> index);
355 memcpy (tim -> name, ttmp -> name, slen);
356 status = trace_write_packet (trace_types [0],
357 slen + TRACE_INDEX_MAPPING_SIZE,
358 (char *)tim, file, line);
359 dfree (tim, file, line);
360 return status;
363 /* Stop all registered trace types from trying to trace. */
365 void trace_stop (void)
367 int i;
369 for (i = 0; i < trace_type_count; i++)
370 if (trace_types [i] -> stop_tracing)
371 (*(trace_types [i] -> stop_tracing))
372 (trace_types [i]);
373 tracing_stopped = 1;
376 void trace_index_map_input (trace_type_t *ttype, unsigned length, char *buf)
378 trace_index_mapping_t *tmap;
379 unsigned len;
380 trace_type_t *tptr, **prev;
382 if (length < TRACE_INDEX_MAPPING_SIZE) {
383 log_error ("short trace index mapping");
384 return;
386 tmap = (trace_index_mapping_t *)buf;
388 prev = &new_trace_types;
389 for (tptr = new_trace_types; tptr; tptr = tptr -> next) {
390 len = strlen (tptr -> name);
391 if (len == length - TRACE_INDEX_MAPPING_SIZE &&
392 !memcmp (tptr -> name, tmap -> name, len)) {
393 tptr -> index = ntohl (tmap -> index);
394 trace_type_stash (tptr);
395 *prev = tptr -> next;
396 return;
398 prev = &tptr -> next;
401 log_error ("No registered trace type for type name %.*s",
402 (int)length - TRACE_INDEX_MAPPING_SIZE, tmap -> name);
403 return;
406 void trace_index_stop_tracing (trace_type_t *ttype) { }
408 void trace_replay_init (void)
410 trace_playback_flag = 1;
413 void trace_file_replay (const char *filename)
415 tracepacket_t *tpkt = (tracepacket_t *)0;
416 int status;
417 char *buf = (char *)0;
418 unsigned buflen;
419 unsigned bufmax = 0;
420 trace_type_t *ttype = (trace_type_t *)0;
421 isc_result_t result;
422 int len;
424 traceinfile = fopen (filename, "r");
425 if (!traceinfile) {
426 log_error ("Can't open tracefile %s: %m", filename);
427 return;
429 #if defined (HAVE_SETFD)
430 if (fcntl (fileno (traceinfile), F_SETFD, 1) < 0)
431 log_error ("Can't set close-on-exec on %s: %m", filename);
432 #endif
433 status = fread (&tracefile_header, 1,
434 sizeof tracefile_header, traceinfile);
435 if (status < sizeof tracefile_header) {
436 if (ferror (traceinfile))
437 log_error ("Error reading trace file header: %m");
438 else
439 log_error ("Short read on trace file header: %d %ld.",
440 status, (long)(sizeof tracefile_header));
441 goto out;
443 tracefile_header.magic = ntohl (tracefile_header.magic);
444 tracefile_header.version = ntohl (tracefile_header.version);
445 tracefile_header.hlen = ntohl (tracefile_header.hlen);
446 tracefile_header.phlen = ntohl (tracefile_header.phlen);
448 if (tracefile_header.magic != TRACEFILE_MAGIC) {
449 log_error ("%s: not a dhcp trace file.", filename);
450 goto out;
452 if (tracefile_header.version > TRACEFILE_VERSION) {
453 log_error ("tracefile version %ld > current %ld.",
454 (long int)tracefile_header.version,
455 (long int)TRACEFILE_VERSION);
456 goto out;
458 if (tracefile_header.phlen < sizeof *tpkt) {
459 log_error ("tracefile packet size too small - %ld < %ld",
460 (long int)tracefile_header.phlen,
461 (long int)sizeof *tpkt);
462 goto out;
464 len = (sizeof tracefile_header) - tracefile_header.hlen;
465 if (len < 0) {
466 log_error ("tracefile header size too small - %ld < %ld",
467 (long int)tracefile_header.hlen,
468 (long int)sizeof tracefile_header);
469 goto out;
471 if (len > 0) {
472 status = fseek (traceinfile, (long)len, SEEK_CUR);
473 if (status < 0) {
474 log_error ("can't seek past header: %m");
475 goto out;
479 tpkt = dmalloc ((unsigned)tracefile_header.phlen, MDL);
480 if (!tpkt) {
481 log_error ("can't allocate trace packet header.");
482 goto out;
485 while ((result = trace_get_next_packet (&ttype, tpkt, &buf, &buflen,
486 &bufmax)) == ISC_R_SUCCESS) {
487 (*ttype -> have_packet) (ttype, tpkt -> length, buf);
488 ttype = (trace_type_t *)0;
490 out:
491 fclose (traceinfile);
492 if (buf)
493 dfree (buf, MDL);
494 if (tpkt)
495 dfree (tpkt, MDL);
498 /* Get the next packet from the file. If ttp points to a nonzero pointer
499 to a trace type structure, check the next packet to see if it's of the
500 expected type, and back off if not. */
502 isc_result_t trace_get_next_packet (trace_type_t **ttp,
503 tracepacket_t *tpkt,
504 char **buf, unsigned *buflen,
505 unsigned *bufmax)
507 trace_type_t *ttype;
508 unsigned paylen;
509 int status;
510 // int len;
511 fpos_t curpos;
513 status = fgetpos (traceinfile, &curpos);
514 if (status < 0)
515 log_error ("Can't save tracefile position: %m");
517 status = fread (tpkt, 1, (size_t)tracefile_header.phlen, traceinfile);
518 if (status < tracefile_header.phlen) {
519 if (ferror (traceinfile))
520 log_error ("Error reading trace packet header: %m");
521 else if (status == 0)
522 return ISC_R_EOF;
523 else
524 log_error ("Short read on trace packet header: "
525 "%ld %ld.",
526 (long int)status,
527 (long int)tracefile_header.phlen);
528 return ISC_R_PROTOCOLERROR;
531 /* Swap the packet. */
532 tpkt -> type_index = ntohl (tpkt -> type_index);
533 tpkt -> length = ntohl (tpkt -> length);
534 tpkt -> when = ntohl (tpkt -> when);
536 /* See if there's a handler for this packet type. */
537 if (tpkt -> type_index < trace_type_count &&
538 trace_types [tpkt -> type_index])
539 ttype = trace_types [tpkt -> type_index];
540 else {
541 log_error ("Trace packet with unknown index %ld",
542 (long int)tpkt -> type_index);
543 return ISC_R_PROTOCOLERROR;
546 /* If we were just hunting for the time marker, we've found it,
547 so back up to the beginning of the packet and return its
548 type. */
549 if (ttp && *ttp == &trace_time_marker) {
550 *ttp = ttype;
551 status = fsetpos (traceinfile, &curpos);
552 if (status < 0) {
553 log_error ("fsetpos in tracefile failed: %m");
554 return ISC_R_PROTOCOLERROR;
556 return ISC_R_EXISTS;
559 /* If we were supposed to get a particular kind of packet,
560 check to see that we got the right kind. */
561 if (ttp && *ttp && ttype != *ttp) {
562 log_error ("Read packet type %s when expecting %s",
563 ttype -> name, (*ttp) -> name);
564 status = fsetpos (traceinfile, &curpos);
565 if (status < 0) {
566 log_error ("fsetpos in tracefile failed: %m");
567 return ISC_R_PROTOCOLERROR;
569 return ISC_R_UNEXPECTEDTOKEN;
572 paylen = tpkt -> length;
573 if (paylen % 8)
574 paylen += 8 - (tpkt -> length % 8);
575 if (paylen > (*bufmax)) {
576 if ((*buf))
577 dfree ((*buf), MDL);
578 (*bufmax) = ((paylen + 1023) & ~1023U);
579 (*buf) = dmalloc ((*bufmax), MDL);
580 if (!(*buf)) {
581 log_error ("Can't allocate input buffer sized %d",
582 (*bufmax));
583 return ISC_R_NOMEMORY;
587 status = fread ((*buf), 1, paylen, traceinfile);
588 if (status < paylen) {
589 if (ferror (traceinfile))
590 log_error ("Error reading trace payload: %m");
591 else
592 log_error ("Short read on trace payload: %d %d.",
593 status, paylen);
594 return ISC_R_PROTOCOLERROR;
597 /* Store the actual length of the payload. */
598 *buflen = tpkt -> length;
600 if (trace_set_time_hook)
601 (*trace_set_time_hook) (tpkt -> when);
603 if (ttp)
604 *ttp = ttype;
605 return ISC_R_SUCCESS;
608 isc_result_t trace_get_packet (trace_type_t **ttp,
609 unsigned *buflen, char **buf)
611 tracepacket_t *tpkt;
612 unsigned bufmax = 0;
613 isc_result_t status;
615 if (!buf || *buf)
616 return ISC_R_INVALIDARG;
618 tpkt = dmalloc ((unsigned)tracefile_header.phlen, MDL);
619 if (!tpkt) {
620 log_error ("can't allocate trace packet header.");
621 return ISC_R_NOMEMORY;
624 status = trace_get_next_packet (ttp, tpkt, buf, buflen, &bufmax);
626 dfree (tpkt, MDL);
627 return status;
630 time_t trace_snoop_time (trace_type_t **ptp)
632 tracepacket_t *tpkt;
633 unsigned bufmax = 0;
634 unsigned buflen = 0;
635 char *buf = (char *)0;
636 // isc_result_t status;
637 time_t result;
638 trace_type_t *ttp;
640 if (!ptp)
641 ptp = &ttp;
643 tpkt = dmalloc ((unsigned)tracefile_header.phlen, MDL);
644 if (!tpkt) {
645 log_error ("can't allocate trace packet header.");
646 return ISC_R_NOMEMORY;
649 *ptp = &trace_time_marker;
650 trace_get_next_packet (ptp, tpkt, &buf, &buflen, &bufmax);
651 result = tpkt -> when;
653 dfree (tpkt, MDL);
654 return result;
657 /* Get a packet from the trace input file that contains a file with the
658 specified name. We don't hunt for the packet - it should be the next
659 packet in the tracefile. If it's not, or something else bad happens,
660 return an error code. */
662 isc_result_t trace_get_file (trace_type_t *ttype,
663 const char *filename, unsigned *len, char **buf)
665 fpos_t curpos;
666 unsigned max = 0;
667 tracepacket_t *tpkt;
668 int status;
669 isc_result_t result;
671 /* Disallow some obvious bogosities. */
672 if (!buf || !len || *buf)
673 return ISC_R_INVALIDARG;
675 /* Save file position in case of filename mismatch. */
676 status = fgetpos (traceinfile, &curpos);
677 if (status < 0)
678 log_error ("Can't save tracefile position: %m");
680 tpkt = dmalloc ((unsigned)tracefile_header.phlen, MDL);
681 if (!tpkt) {
682 log_error ("can't allocate trace packet header.");
683 return ISC_R_NOMEMORY;
686 result = trace_get_next_packet (&ttype, tpkt, buf, len, &max);
687 if (result != ISC_R_SUCCESS) {
688 dfree (tpkt, MDL);
689 if (*buf)
690 dfree (*buf, MDL);
691 return result;
694 /* Make sure the filename is right. */
695 if (strcmp (filename, *buf)) {
696 log_error ("Read file %s when expecting %s", *buf, filename);
697 status = fsetpos (traceinfile, &curpos);
698 if (status < 0) {
699 log_error ("fsetpos in tracefile failed: %m");
700 dfree (tpkt, MDL);
701 dfree (*buf, MDL);
702 return ISC_R_PROTOCOLERROR;
704 return ISC_R_UNEXPECTEDTOKEN;
707 dfree (tpkt, MDL);
708 return ISC_R_SUCCESS;
710 #endif /* TRACING */