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