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