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