]> git.ipfire.org Git - thirdparty/dhcp.git/blame - omapip/trace.c
[master] ATF usage and documentation cleaned up
[thirdparty/dhcp.git] / omapip / trace.c
CommitLineData
c128c100
TL
1/* trace.c
2
ac679e8f
TL
3 Subroutines that support tracing of OMAPI wire transactions and
4 provide a mechanism for programs using OMAPI to trace their own
5 transactions... */
c128c100
TL
6
7/*
edad9be5 8 * Copyright (c) 2012,2014 by Internet Systems Consortium, Inc. ("ISC")
600ee619
SR
9 * Copyright (c) 2009-2010 by Internet Systems Consortium, Inc. ("ISC")
10 * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC")
98311e4b 11 * Copyright (c) 2001-2003 by Internet Software Consortium
c128c100 12 *
98311e4b
DH
13 * Permission to use, copy, modify, and distribute this software for any
14 * purpose with or without fee is hereby granted, provided that the above
15 * copyright notice and this permission notice appear in all copies.
c128c100 16 *
98311e4b
DH
17 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
18 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
20 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
21 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
22 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
23 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
c128c100 24 *
98311e4b
DH
25 * Internet Systems Consortium, Inc.
26 * 950 Charter Street
27 * Redwood City, CA 94063
28 * <info@isc.org>
2c85ac9b 29 * https://www.isc.org/
c128c100 30 *
c128c100
TL
31 */
32
fe5b0fdd 33#include "dhcpd.h"
c128c100 34#include <omapip/omapip_p.h>
fe5b0fdd 35#include <errno.h>
c128c100
TL
36
37#if defined (TRACING)
88cd8aca 38void (*trace_set_time_hook) (TIME);
c128c100
TL
39static int tracing_stopped;
40static int traceoutfile;
41static int traceindex;
42static trace_type_t **trace_types;
43static int trace_type_count;
44static int trace_type_max;
45static trace_type_t *new_trace_types;
46static FILE *traceinfile;
47static tracefile_header_t tracefile_header;
48static int trace_playback_flag;
ac679e8f 49trace_type_t trace_time_marker;
c128c100 50
d758ad8c
TL
51#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
52extern omapi_array_t *trace_listeners;
53extern omapi_array_t *omapi_connections;
54
a58da042
EH
55extern int errno;
56
d758ad8c
TL
57void trace_free_all ()
58{
59 trace_type_t *tp;
60 int i;
61 tp = new_trace_types;
62 while (tp) {
63 new_trace_types = tp -> next;
64 if (tp -> name) {
65 dfree (tp -> name, MDL);
66 tp -> name = (char *)0;
67 }
68 dfree (tp, MDL);
69 tp = new_trace_types;
70 }
71 for (i = 0; i < trace_type_count; i++) {
72 if (trace_types [i]) {
73 if (trace_types [i] -> name)
74 dfree (trace_types [i] -> name, MDL);
75 dfree (trace_types [i], MDL);
76 }
77 }
78 dfree (trace_types, MDL);
79 trace_types = (trace_type_t **)0;
80 trace_type_count = trace_type_max = 0;
81
82 omapi_array_free (&trace_listeners, MDL);
83 omapi_array_free (&omapi_connections, MDL);
84}
85#endif
86
7a563fb8
TL
87static isc_result_t trace_type_record (trace_type_t *,
88 unsigned, const char *, int);
89
c128c100
TL
90int trace_playback ()
91{
92 return trace_playback_flag;
93}
94
95int trace_record ()
96{
3a4f23b5 97 if (traceoutfile && !tracing_stopped)
c128c100
TL
98 return 1;
99 return 0;
100}
101
88cd8aca 102isc_result_t trace_init (void (*set_time) (TIME),
c128c100
TL
103 const char *file, int line)
104{
105 trace_type_t *root_type;
106 static int root_setup = 0;
107
108 if (root_setup)
109 return ISC_R_SUCCESS;
110
111 trace_set_time_hook = set_time;
112
113 root_type = trace_type_register ("trace-index-mapping",
114 (void *)0, trace_index_map_input,
115 trace_index_stop_tracing, file, line);
116 if (!root_type)
117 return ISC_R_UNEXPECTED;
d758ad8c
TL
118 if (new_trace_types == root_type)
119 new_trace_types = new_trace_types -> next;
c128c100
TL
120 root_type -> index = 0;
121 trace_type_stash (root_type);
122
123 root_setup = 1;
124 return ISC_R_SUCCESS;
125}
126
127isc_result_t trace_begin (const char *filename,
128 const char *file, int line)
129{
130 tracefile_header_t tfh;
131 int status;
7a563fb8
TL
132 trace_type_t *tptr, *next;
133 isc_result_t result;
c128c100
TL
134
135 if (traceoutfile) {
136 log_error ("%s(%d): trace_begin called twice",
137 file, line);
98bf1607 138 return DHCP_R_INVALIDARG;
c128c100
TL
139 }
140
88cd8aca 141 traceoutfile = open (filename, O_CREAT | O_WRONLY | O_EXCL, 0600);
a58da042
EH
142 if (traceoutfile < 0 && errno == EEXIST) {
143 log_error ("WARNING: Overwriting trace file \"%s\"", filename);
600ee619
SR
144 traceoutfile = open (filename, O_WRONLY | O_EXCL | O_TRUNC,
145 0600);
a58da042
EH
146 }
147
c128c100
TL
148 if (traceoutfile < 0) {
149 log_error ("%s(%d): trace_begin: %s: %m",
150 file, line, filename);
151 return ISC_R_UNEXPECTED;
152 }
153#if defined (HAVE_SETFD)
154 if (fcntl (traceoutfile, F_SETFD, 1) < 0)
155 log_error ("Can't set close-on-exec on %s: %m", filename);
156#endif
157
158 tfh.magic = htonl (TRACEFILE_MAGIC);
159 tfh.version = htonl (TRACEFILE_VERSION);
160 tfh.hlen = htonl (sizeof (tracefile_header_t));
161 tfh.phlen = htonl (sizeof (tracepacket_t));
162
163 status = write (traceoutfile, &tfh, sizeof tfh);
164 if (status < 0) {
165 log_error ("%s(%d): trace_begin write failed: %m", file, line);
166 return ISC_R_UNEXPECTED;
167 } else if (status != sizeof tfh) {
c4661845
TL
168 log_error ("%s(%d): trace_begin: short write (%d:%ld)",
169 file, line, status, (long)(sizeof tfh));
c128c100 170 trace_stop ();
7a563fb8
TL
171 return ISC_R_UNEXPECTED;
172 }
173
174 /* Stash all the types that have already been set up. */
175 if (new_trace_types) {
176 next = new_trace_types;
177 new_trace_types = (trace_type_t *)0;
178 for (tptr = next; tptr; tptr = next) {
179 next = tptr -> next;
180 if (tptr -> index != 0) {
181 result = (trace_type_record
182 (tptr,
183 strlen (tptr -> name), file, line));
184 if (result != ISC_R_SUCCESS)
185 return status;
186 }
187 }
c128c100 188 }
7a563fb8 189
c128c100
TL
190 return ISC_R_SUCCESS;
191}
192
193isc_result_t trace_write_packet (trace_type_t *ttype, unsigned length,
194 const char *buf, const char *file, int line)
195{
196 trace_iov_t iov;
197
198 iov.buf = buf;
199 iov.len = length;
200 return trace_write_packet_iov (ttype, 1, &iov, file, line);
201}
202
203isc_result_t trace_write_packet_iov (trace_type_t *ttype,
204 int count, trace_iov_t *iov,
205 const char *file, int line)
206{
207 tracepacket_t tmp;
208 int status;
209 int i;
210 int length;
211
212 /* Really shouldn't get called here, but it may be hard to turn off
213 tracing midstream if the trace file write fails or something. */
214 if (tracing_stopped)
215 return 0;
216
217 if (!ttype) {
218 log_error ("%s(%d): trace_write_packet with null trace type",
219 file ? file : "<unknown file>", line);
98bf1607 220 return DHCP_R_INVALIDARG;
c128c100
TL
221 }
222 if (!traceoutfile) {
223 log_error ("%s(%d): trace_write_packet with no tracefile.",
224 file ? file : "<unknown file>", line);
98bf1607 225 return DHCP_R_INVALIDARG;
c128c100
TL
226 }
227
228 /* Compute the total length of the iov. */
229 length = 0;
230 for (i = 0; i < count; i++)
231 length += iov [i].len;
232
233 /* We have to swap out the data, because it may be read back on a
234 machine of different endianness. */
0f750c4f 235 memset(&tmp, 0, sizeof(tmp));
c128c100
TL
236 tmp.type_index = htonl (ttype -> index);
237 tmp.when = htonl (time ((time_t *)0)); /* XXX */
238 tmp.length = htonl (length);
239
240 status = write (traceoutfile, &tmp, sizeof tmp);
241 if (status < 0) {
242 log_error ("%s(%d): trace_write_packet write failed: %m",
243 file, line);
244 return ISC_R_UNEXPECTED;
245 } else if (status != sizeof tmp) {
c4661845
TL
246 log_error ("%s(%d): trace_write_packet: short write (%d:%ld)",
247 file, line, status, (long)(sizeof tmp));
c128c100
TL
248 trace_stop ();
249 }
250
251 for (i = 0; i < count; i++) {
252 status = write (traceoutfile, iov [i].buf, iov [i].len);
253 if (status < 0) {
254 log_error ("%s(%d): %s write failed: %m",
255 file, line, "trace_write_packet");
256 return ISC_R_UNEXPECTED;
257 } else if (status != iov [i].len) {
258 log_error ("%s(%d): %s: short write (%d:%d)",
259 file, line,
260 "trace_write_packet", status, length);
261 trace_stop ();
262 }
263 }
264
265 /* Write padding on the end of the packet to align the next
266 packet to an 8-byte boundary. This is in case we decide to
267 use mmap in some clever way later on. */
268 if (length % 8) {
269 static char zero [] = { 0, 0, 0, 0, 0, 0, 0 };
270 unsigned padl = 8 - (length % 8);
271
272 status = write (traceoutfile, zero, padl);
273 if (status < 0) {
274 log_error ("%s(%d): trace_write_packet write failed: %m",
275 file, line);
276 return ISC_R_UNEXPECTED;
277 } else if (status != padl) {
278 log_error ("%s(%d): trace_write_packet: short write (%d:%d)",
279 file, line, status, padl);
280 trace_stop ();
281 }
282 }
283
284 return ISC_R_SUCCESS;
285}
286
287void trace_type_stash (trace_type_t *tptr)
288{
289 trace_type_t **vec;
290 int delta;
291 if (trace_type_max <= tptr -> index) {
292 delta = tptr -> index - trace_type_max + 10;
293 vec = dmalloc (((trace_type_max + delta) *
294 sizeof (trace_type_t *)), MDL);
295 if (!vec)
296 return;
297 memset (&vec [trace_type_max], 0,
298 (sizeof (trace_type_t *)) * delta);
299 trace_type_max += delta;
300 if (trace_types) {
301 memcpy (vec, trace_types,
302 trace_type_count * sizeof (trace_type_t *));
303 dfree (trace_types, MDL);
304 }
305 trace_types = vec;
306 }
307 trace_types [tptr -> index] = tptr;
308 if (tptr -> index >= trace_type_count)
309 trace_type_count = tptr -> index + 1;
310}
311
312trace_type_t *trace_type_register (const char *name,
313 void *baggage,
314 void (*have_packet) (trace_type_t *,
315 unsigned, char *),
316 void (*stop_tracing) (trace_type_t *),
317 const char *file, int line)
318{
28868515 319 trace_type_t *ttmp;
c128c100 320 unsigned slen = strlen (name);
7a563fb8 321 isc_result_t status;
c128c100
TL
322
323 ttmp = dmalloc (sizeof *ttmp, file, line);
7a563fb8 324 if (!ttmp)
c128c100 325 return ttmp;
7a563fb8 326 ttmp -> index = -1;
c128c100
TL
327 ttmp -> name = dmalloc (slen + 1, file, line);
328 if (!ttmp -> name) {
329 dfree (ttmp, file, line);
330 return (trace_type_t *)0;
331 }
332 strcpy (ttmp -> name, name);
333 ttmp -> have_packet = have_packet;
334 ttmp -> stop_tracing = stop_tracing;
335
c128c100 336 if (traceoutfile) {
7a563fb8
TL
337 status = trace_type_record (ttmp, slen, file, line);
338 if (status != ISC_R_SUCCESS) {
c128c100
TL
339 dfree (ttmp -> name, file, line);
340 dfree (ttmp, file, line);
7a563fb8 341 return (trace_type_t *)0;
c128c100 342 }
7a563fb8
TL
343 } else {
344 ttmp -> next = new_trace_types;
345 new_trace_types = ttmp;
c128c100
TL
346 }
347
348 return ttmp;
349}
350
7a563fb8
TL
351static isc_result_t trace_type_record (trace_type_t *ttmp, unsigned slen,
352 const char *file, int line)
353{
354 trace_index_mapping_t *tim;
355 isc_result_t status;
356
357 tim = dmalloc (slen + TRACE_INDEX_MAPPING_SIZE, file, line);
358 if (!tim)
359 return ISC_R_NOMEMORY;
360 ttmp -> index = ++traceindex;
361 trace_type_stash (ttmp);
362 tim -> index = htonl (ttmp -> index);
363 memcpy (tim -> name, ttmp -> name, slen);
364 status = trace_write_packet (trace_types [0],
365 slen + TRACE_INDEX_MAPPING_SIZE,
366 (char *)tim, file, line);
367 dfree (tim, file, line);
368 return status;
369}
370
c128c100
TL
371/* Stop all registered trace types from trying to trace. */
372
373void trace_stop (void)
374{
375 int i;
376
377 for (i = 0; i < trace_type_count; i++)
378 if (trace_types [i] -> stop_tracing)
379 (*(trace_types [i] -> stop_tracing))
380 (trace_types [i]);
381 tracing_stopped = 1;
382}
383
384void trace_index_map_input (trace_type_t *ttype, unsigned length, char *buf)
385{
386 trace_index_mapping_t *tmap;
387 unsigned len;
388 trace_type_t *tptr, **prev;
389
390 if (length < TRACE_INDEX_MAPPING_SIZE) {
391 log_error ("short trace index mapping");
392 return;
393 }
394 tmap = (trace_index_mapping_t *)buf;
395
396 prev = &new_trace_types;
397 for (tptr = new_trace_types; tptr; tptr = tptr -> next) {
398 len = strlen (tptr -> name);
399 if (len == length - TRACE_INDEX_MAPPING_SIZE &&
400 !memcmp (tptr -> name, tmap -> name, len)) {
401 tptr -> index = ntohl (tmap -> index);
402 trace_type_stash (tptr);
403 *prev = tptr -> next;
404 return;
405 }
406 prev = &tptr -> next;
407 }
408
409 log_error ("No registered trace type for type name %.*s",
410 (int)length - TRACE_INDEX_MAPPING_SIZE, tmap -> name);
411 return;
412}
413
414void trace_index_stop_tracing (trace_type_t *ttype) { }
415
416void trace_replay_init (void)
417{
418 trace_playback_flag = 1;
419}
420
421void trace_file_replay (const char *filename)
422{
600ee619 423 tracepacket_t *tpkt = NULL;
c128c100 424 int status;
600ee619 425 char *buf = NULL;
a7394d15 426 unsigned buflen;
c128c100 427 unsigned bufmax = 0;
600ee619 428 trace_type_t *ttype = NULL;
c128c100
TL
429 isc_result_t result;
430 int len;
431
432 traceinfile = fopen (filename, "r");
433 if (!traceinfile) {
600ee619 434 log_error("Can't open tracefile %s: %m", filename);
c128c100
TL
435 return;
436 }
437#if defined (HAVE_SETFD)
600ee619
SR
438 if (fcntl (fileno(traceinfile), F_SETFD, 1) < 0)
439 log_error("Can't set close-on-exec on %s: %m", filename);
c128c100 440#endif
600ee619
SR
441 status = fread(&tracefile_header, 1,
442 sizeof tracefile_header, traceinfile);
c128c100 443 if (status < sizeof tracefile_header) {
600ee619
SR
444 if (ferror(traceinfile))
445 log_error("Error reading trace file header: %m");
c128c100 446 else
600ee619
SR
447 log_error("Short read on trace file header: %d %ld.",
448 status, (long)(sizeof tracefile_header));
c128c100
TL
449 goto out;
450 }
600ee619
SR
451 tracefile_header.magic = ntohl(tracefile_header.magic);
452 tracefile_header.version = ntohl(tracefile_header.version);
453 tracefile_header.hlen = ntohl(tracefile_header.hlen);
454 tracefile_header.phlen = ntohl(tracefile_header.phlen);
c128c100
TL
455
456 if (tracefile_header.magic != TRACEFILE_MAGIC) {
600ee619 457 log_error("%s: not a dhcp trace file.", filename);
c128c100
TL
458 goto out;
459 }
460 if (tracefile_header.version > TRACEFILE_VERSION) {
d0042425
DN
461 log_error ("tracefile version %ld > current %ld.",
462 (long int)tracefile_header.version,
463 (long int)TRACEFILE_VERSION);
c128c100
TL
464 goto out;
465 }
466 if (tracefile_header.phlen < sizeof *tpkt) {
600ee619
SR
467 log_error("tracefile packet size too small - %ld < %ld",
468 (long int)tracefile_header.phlen,
469 (long int)sizeof *tpkt);
c128c100
TL
470 goto out;
471 }
472 len = (sizeof tracefile_header) - tracefile_header.hlen;
473 if (len < 0) {
600ee619
SR
474 log_error("tracefile header size too small - %ld < %ld",
475 (long int)tracefile_header.hlen,
476 (long int)sizeof tracefile_header);
c128c100
TL
477 goto out;
478 }
479 if (len > 0) {
600ee619 480 status = fseek(traceinfile, (long)len, SEEK_CUR);
c128c100 481 if (status < 0) {
600ee619 482 log_error("can't seek past header: %m");
c128c100
TL
483 goto out;
484 }
485 }
486
600ee619
SR
487 tpkt = dmalloc((unsigned)tracefile_header.phlen, MDL);
488 if (tpkt == NULL) {
c128c100
TL
489 log_error ("can't allocate trace packet header.");
490 goto out;
491 }
492
600ee619
SR
493 while ((result = trace_get_next_packet(&ttype, tpkt, &buf, &buflen,
494 &bufmax)) == ISC_R_SUCCESS) {
495 (*ttype->have_packet)(ttype, tpkt->length, buf);
496 ttype = NULL;
c128c100
TL
497 }
498 out:
600ee619
SR
499 fclose(traceinfile);
500 if (buf != NULL)
501 dfree(buf, MDL);
502 if (tpkt != NULL)
503 dfree(tpkt, MDL);
c128c100
TL
504}
505
506/* Get the next packet from the file. If ttp points to a nonzero pointer
507 to a trace type structure, check the next packet to see if it's of the
508 expected type, and back off if not. */
509
510isc_result_t trace_get_next_packet (trace_type_t **ttp,
511 tracepacket_t *tpkt,
512 char **buf, unsigned *buflen,
513 unsigned *bufmax)
514{
515 trace_type_t *ttype;
516 unsigned paylen;
600ee619 517 int status, curposok = 0;
c128c100
TL
518 fpos_t curpos;
519
600ee619
SR
520 while(1) {
521 curposok = 0;
522 status = fgetpos(traceinfile, &curpos);
523 if (status < 0) {
524 log_error("Can't save tracefile position: %m");
525 } else {
526 curposok = 1;
527 }
c128c100 528
600ee619
SR
529 status = fread(tpkt, 1, (size_t)tracefile_header.phlen,
530 traceinfile);
531 if (status < tracefile_header.phlen) {
532 if (ferror(traceinfile))
533 log_error("Error reading trace packet header: "
534 "%m");
535 else if (status == 0)
536 return ISC_R_EOF;
537 else
538 log_error ("Short read on trace packet header:"
539 " %ld %ld.",
540 (long int)status,
541 (long int)tracefile_header.phlen);
542 return DHCP_R_PROTOCOLERROR;
543 }
c128c100 544
600ee619
SR
545 /* Swap the packet. */
546 tpkt->type_index = ntohl(tpkt -> type_index);
547 tpkt->length = ntohl(tpkt -> length);
548 tpkt->when = ntohl(tpkt -> when);
c128c100 549
600ee619
SR
550 /* See if there's a handler for this packet type. */
551 if (tpkt->type_index < trace_type_count &&
552 trace_types[tpkt->type_index])
553 ttype = trace_types[tpkt->type_index];
554 else {
555 log_error ("Trace packet with unknown index %ld",
556 (long int)tpkt->type_index);
98bf1607 557 return DHCP_R_PROTOCOLERROR;
6b85636e 558 }
600ee619
SR
559
560 /*
561 * Determine if we should try to expire any timer events.
562 * We do so if:
563 * we aren't looking for a specific type of packet
564 * we have a hook to use to update the timer
565 * the timestamp on the packet doesn't match the current time
566 * When we do so we rewind the file to the beginning of this
567 * packet and then try for a new packet. This allows
568 * any code triggered by a timeout to get the current packet
569 * while we get the next one.
570 */
571
572 if ((ttp != NULL) && (*ttp == NULL) &&
573 (tpkt->when != cur_tv.tv_sec) &&
574 (trace_set_time_hook != NULL)) {
575 if (curposok == 0) {
576 log_error("no curpos for fsetpos in "
577 "tracefile");
578 return DHCP_R_PROTOCOLERROR;
579 }
580
581 status = fsetpos(traceinfile, &curpos);
582 if (status < 0) {
583 log_error("fsetpos in tracefile failed: %m");
584 return DHCP_R_PROTOCOLERROR;
585 }
586
587 (*trace_set_time_hook) (tpkt->when);
588 continue;
589 }
590 break;
6b85636e
TL
591 }
592
c128c100
TL
593 /* If we were supposed to get a particular kind of packet,
594 check to see that we got the right kind. */
595 if (ttp && *ttp && ttype != *ttp) {
596 log_error ("Read packet type %s when expecting %s",
597 ttype -> name, (*ttp) -> name);
598 status = fsetpos (traceinfile, &curpos);
599 if (status < 0) {
600 log_error ("fsetpos in tracefile failed: %m");
98bf1607 601 return DHCP_R_PROTOCOLERROR;
c128c100
TL
602 }
603 return ISC_R_UNEXPECTEDTOKEN;
604 }
605
606 paylen = tpkt -> length;
607 if (paylen % 8)
608 paylen += 8 - (tpkt -> length % 8);
a07d99bb
TM
609
610 /* allocate a buffer if we need one or current buffer is too small */
611 if ((*buf == NULL) || (paylen > (*bufmax))) {
c128c100
TL
612 if ((*buf))
613 dfree ((*buf), MDL);
614 (*bufmax) = ((paylen + 1023) & ~1023U);
615 (*buf) = dmalloc ((*bufmax), MDL);
616 if (!(*buf)) {
617 log_error ("Can't allocate input buffer sized %d",
618 (*bufmax));
619 return ISC_R_NOMEMORY;
620 }
621 }
a07d99bb 622
c128c100
TL
623 status = fread ((*buf), 1, paylen, traceinfile);
624 if (status < paylen) {
625 if (ferror (traceinfile))
626 log_error ("Error reading trace payload: %m");
627 else
628 log_error ("Short read on trace payload: %d %d.",
629 status, paylen);
98bf1607 630 return DHCP_R_PROTOCOLERROR;
c128c100
TL
631 }
632
633 /* Store the actual length of the payload. */
634 *buflen = tpkt -> length;
635
c128c100
TL
636 if (ttp)
637 *ttp = ttype;
638 return ISC_R_SUCCESS;
639}
640
641isc_result_t trace_get_packet (trace_type_t **ttp,
642 unsigned *buflen, char **buf)
643{
644 tracepacket_t *tpkt;
645 unsigned bufmax = 0;
646 isc_result_t status;
647
648 if (!buf || *buf)
98bf1607 649 return DHCP_R_INVALIDARG;
c128c100
TL
650
651 tpkt = dmalloc ((unsigned)tracefile_header.phlen, MDL);
652 if (!tpkt) {
653 log_error ("can't allocate trace packet header.");
654 return ISC_R_NOMEMORY;
655 }
656
657 status = trace_get_next_packet (ttp, tpkt, buf, buflen, &bufmax);
658
659 dfree (tpkt, MDL);
660 return status;
661}
662
663/* Get a packet from the trace input file that contains a file with the
664 specified name. We don't hunt for the packet - it should be the next
665 packet in the tracefile. If it's not, or something else bad happens,
666 return an error code. */
667
668isc_result_t trace_get_file (trace_type_t *ttype,
669 const char *filename, unsigned *len, char **buf)
670{
671 fpos_t curpos;
672 unsigned max = 0;
673 tracepacket_t *tpkt;
674 int status;
675 isc_result_t result;
676
677 /* Disallow some obvious bogosities. */
678 if (!buf || !len || *buf)
98bf1607 679 return DHCP_R_INVALIDARG;
c128c100
TL
680
681 /* Save file position in case of filename mismatch. */
682 status = fgetpos (traceinfile, &curpos);
683 if (status < 0)
684 log_error ("Can't save tracefile position: %m");
685
686 tpkt = dmalloc ((unsigned)tracefile_header.phlen, MDL);
687 if (!tpkt) {
688 log_error ("can't allocate trace packet header.");
689 return ISC_R_NOMEMORY;
690 }
691
692 result = trace_get_next_packet (&ttype, tpkt, buf, len, &max);
0f750c4f
SR
693 /* done with tpkt, free it */
694 dfree (tpkt, MDL);
c128c100 695 if (result != ISC_R_SUCCESS) {
0f750c4f 696 if (*buf) {
c128c100 697 dfree (*buf, MDL);
0f750c4f
SR
698 *buf = NULL;
699 }
c128c100
TL
700 return result;
701 }
702
703 /* Make sure the filename is right. */
704 if (strcmp (filename, *buf)) {
705 log_error ("Read file %s when expecting %s", *buf, filename);
0f750c4f
SR
706 dfree (*buf, MDL);
707 *buf = NULL;
708
c128c100
TL
709 status = fsetpos (traceinfile, &curpos);
710 if (status < 0) {
711 log_error ("fsetpos in tracefile failed: %m");
98bf1607 712 return DHCP_R_PROTOCOLERROR;
c128c100
TL
713 }
714 return ISC_R_UNEXPECTEDTOKEN;
715 }
716
c128c100
TL
717 return ISC_R_SUCCESS;
718}
719#endif /* TRACING */