Initial import from FreeBSD RELENG_4:
[dragonfly.git] / contrib / isc-dhcp / omapip / trace.c
1 /* trace.c
2
3    Subroutines that support tracing of OMAPI wire transactions and
4    provide a mechanism for programs using OMAPI to trace their own
5    transactions... */
6
7 /*
8  * Copyright (c) 2001 Internet Software Consortium.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  *
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. Neither the name of The Internet Software Consortium nor the names
21  *    of its contributors may be used to endorse or promote products derived
22  *    from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
25  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
26  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
27  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28  * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
29  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
32  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
33  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
34  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
35  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  * This software has been written for the Internet Software Consortium
39  * by Ted Lemon, as part of a project for Nominum, Inc.   To learn more
40  * about the Internet Software Consortium, see http://www.isc.org/.  To
41  * learn more about Nominum, Inc., see ``http://www.nominum.com''.
42  */
43
44 #include <omapip/omapip_p.h>
45
46 #if defined (TRACING)
47 void (*trace_set_time_hook) (u_int32_t);
48 static int tracing_stopped;
49 static int traceoutfile;
50 static int traceindex;
51 static trace_type_t **trace_types;
52 static int trace_type_count;
53 static int trace_type_max;
54 static trace_type_t *new_trace_types;
55 static FILE *traceinfile;
56 static tracefile_header_t tracefile_header;
57 static int trace_playback_flag;
58 trace_type_t trace_time_marker;
59
60 #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
61 extern omapi_array_t *trace_listeners;
62 extern omapi_array_t *omapi_connections;
63
64 void trace_free_all ()
65 {
66         trace_type_t *tp;
67         int i;
68         tp = new_trace_types;
69         while (tp) {
70                 new_trace_types = tp -> next;
71                 if (tp -> name) {
72                         dfree (tp -> name, MDL);
73                         tp -> name = (char *)0;
74                 }
75                 dfree (tp, MDL);
76                 tp = new_trace_types;
77         }
78         for (i = 0; i < trace_type_count; i++) {
79                 if (trace_types [i]) {
80                         if (trace_types [i] -> name)
81                                 dfree (trace_types [i] -> name, MDL);
82                         dfree (trace_types [i], MDL);
83                 }
84         }
85         dfree (trace_types, MDL);
86         trace_types = (trace_type_t **)0;
87         trace_type_count = trace_type_max = 0;
88
89         omapi_array_free (&trace_listeners, MDL);
90         omapi_array_free (&omapi_connections, MDL);
91 }
92 #endif
93
94 static isc_result_t trace_type_record (trace_type_t *,
95                                        unsigned, const char *, int);
96
97 int trace_playback ()
98 {
99         return trace_playback_flag;
100 }
101
102 int trace_record ()
103 {
104         if (traceoutfile && !tracing_stopped)
105                 return 1;
106         return 0;
107 }
108
109 isc_result_t trace_init (void (*set_time) (u_int32_t),
110                          const char *file, int line)
111 {
112         trace_type_t *root_type;
113         static int root_setup = 0;
114
115         if (root_setup)
116                 return ISC_R_SUCCESS;
117
118         trace_set_time_hook = set_time;
119
120         root_type = trace_type_register ("trace-index-mapping",
121                                          (void *)0, trace_index_map_input,
122                                          trace_index_stop_tracing, file, line);
123         if (!root_type)
124                 return ISC_R_UNEXPECTED;
125         if (new_trace_types == root_type)
126                 new_trace_types = new_trace_types -> next;
127         root_type -> index = 0;
128         trace_type_stash (root_type);
129
130         root_setup = 1;
131         return ISC_R_SUCCESS;
132 }
133
134 isc_result_t trace_begin (const char *filename,
135                           const char *file, int line)
136 {
137         tracefile_header_t tfh;
138         int status;
139         trace_type_t *tptr, *next;
140         isc_result_t result;
141
142         if (traceoutfile) {
143                 log_error ("%s(%d): trace_begin called twice",
144                            file, line);
145                 return ISC_R_INVALIDARG;
146         }
147
148         traceoutfile = open (filename, O_CREAT | O_WRONLY | O_EXCL, 0644);
149         if (traceoutfile < 0) {
150                 log_error ("%s(%d): trace_begin: %s: %m",
151                            file, line, filename);
152                 return ISC_R_UNEXPECTED;
153         }
154 #if defined (HAVE_SETFD)
155         if (fcntl (traceoutfile, F_SETFD, 1) < 0)
156                 log_error ("Can't set close-on-exec on %s: %m", filename);
157 #endif
158
159         tfh.magic = htonl (TRACEFILE_MAGIC);
160         tfh.version = htonl (TRACEFILE_VERSION);
161         tfh.hlen = htonl (sizeof (tracefile_header_t));
162         tfh.phlen = htonl (sizeof (tracepacket_t));
163         
164         status = write (traceoutfile, &tfh, sizeof tfh);
165         if (status < 0) {
166                 log_error ("%s(%d): trace_begin write failed: %m", file, line);
167                 return ISC_R_UNEXPECTED;
168         } else if (status != sizeof tfh) {
169                 log_error ("%s(%d): trace_begin: short write (%d:%ld)",
170                            file, line, status, (long)(sizeof tfh));
171                 trace_stop ();
172                 return ISC_R_UNEXPECTED;
173         }
174
175         /* Stash all the types that have already been set up. */
176         if (new_trace_types) {
177                 next = new_trace_types;
178                 new_trace_types = (trace_type_t *)0;
179                 for (tptr = next; tptr; tptr = next) {
180                         next = tptr -> next;
181                         if (tptr -> index != 0) {
182                                 result = (trace_type_record
183                                           (tptr,
184                                            strlen (tptr -> name), file, line));
185                                 if (result != ISC_R_SUCCESS)
186                                         return status;
187                         }
188                 }
189         }
190         
191         return ISC_R_SUCCESS;
192 }
193
194 isc_result_t trace_write_packet (trace_type_t *ttype, unsigned length,
195                                  const char *buf, const char *file, int line)
196 {
197         trace_iov_t iov;
198
199         iov.buf = buf;
200         iov.len = length;
201         return trace_write_packet_iov (ttype, 1, &iov, file, line);
202 }
203
204 isc_result_t trace_write_packet_iov (trace_type_t *ttype,
205                                      int count, trace_iov_t *iov,
206                                      const char *file, int line)
207 {
208         tracepacket_t tmp;
209         int status;
210         int i;
211         int length;
212
213         /* Really shouldn't get called here, but it may be hard to turn off
214            tracing midstream if the trace file write fails or something. */
215         if (tracing_stopped)
216                 return 0;
217
218         if (!ttype) {
219                 log_error ("%s(%d): trace_write_packet with null trace type",
220                            file ? file : "<unknown file>", line);
221                 return ISC_R_INVALIDARG;
222         }
223         if (!traceoutfile) {
224                 log_error ("%s(%d): trace_write_packet with no tracefile.",
225                            file ? file : "<unknown file>", line);
226                 return ISC_R_INVALIDARG;
227         }
228         
229         /* Compute the total length of the iov. */
230         length = 0;
231         for (i = 0; i < count; i++)
232                 length += iov [i].len;
233
234         /* We have to swap out the data, because it may be read back on a
235            machine of different endianness. */
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) {
246                 log_error ("%s(%d): trace_write_packet: short write (%d:%ld)",
247                            file, line, status, (long)(sizeof tmp));
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
287 void 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
312 trace_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 {
319         trace_type_t *ttmp, *tptr;
320         unsigned slen = strlen (name);
321         isc_result_t status;
322
323         ttmp = dmalloc (sizeof *ttmp, file, line);
324         if (!ttmp)
325                 return ttmp;
326         ttmp -> index = -1;
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         
336         if (traceoutfile) {
337                 status = trace_type_record (ttmp, slen, file, line);
338                 if (status != ISC_R_SUCCESS) {
339                         dfree (ttmp -> name, file, line);
340                         dfree (ttmp, file, line);
341                         return (trace_type_t *)0;
342                 }
343         } else {
344                 ttmp -> next = new_trace_types;
345                 new_trace_types = ttmp;
346         }
347
348         return ttmp;
349 }
350                                                    
351 static 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
371 /* Stop all registered trace types from trying to trace. */
372
373 void 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
384 void 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
414 void trace_index_stop_tracing (trace_type_t *ttype) { }
415
416 void trace_replay_init (void)
417 {
418         trace_playback_flag = 1;
419 }
420
421 void trace_file_replay (const char *filename)
422 {
423         tracepacket_t *tpkt = (tracepacket_t *)0;
424         int status;
425         char *buf = (char *)0;
426         unsigned buflen;
427         unsigned bufmax = 0;
428         trace_type_t *ttype = (trace_type_t *)0;
429         isc_result_t result;
430         int len;
431
432         traceinfile = fopen (filename, "r");
433         if (!traceinfile) {
434                 log_error ("Can't open tracefile %s: %m", filename);
435                 return;
436         }
437 #if defined (HAVE_SETFD)
438         if (fcntl (fileno (traceinfile), F_SETFD, 1) < 0)
439                 log_error ("Can't set close-on-exec on %s: %m", filename);
440 #endif
441         status = fread (&tracefile_header, 1,
442                         sizeof tracefile_header, traceinfile);
443         if (status < sizeof tracefile_header) {
444                 if (ferror (traceinfile))
445                         log_error ("Error reading trace file header: %m");
446                 else
447                         log_error ("Short read on trace file header: %d %ld.",
448                                    status, (long)(sizeof tracefile_header));
449                 goto out;
450         }
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);
455
456         if (tracefile_header.magic != TRACEFILE_MAGIC) {
457                 log_error ("%s: not a dhcp trace file.", filename);
458                 goto out;
459         }
460         if (tracefile_header.version > TRACEFILE_VERSION) {
461                 log_error ("tracefile version %ld > current %ld.",
462                            (long int)tracefile_header.version,
463                            (long int)TRACEFILE_VERSION);
464                 goto out;
465         }
466         if (tracefile_header.phlen < sizeof *tpkt) {
467                 log_error ("tracefile packet size too small - %ld < %ld",
468                            (long int)tracefile_header.phlen,
469                            (long int)sizeof *tpkt);
470                 goto out;
471         }
472         len = (sizeof tracefile_header) - tracefile_header.hlen;
473         if (len < 0) {
474                 log_error ("tracefile header size too small - %ld < %ld",
475                            (long int)tracefile_header.hlen,
476                            (long int)sizeof tracefile_header);
477                 goto out;
478         }
479         if (len > 0) {
480                 status = fseek (traceinfile, (long)len, SEEK_CUR);
481                 if (status < 0) {
482                         log_error ("can't seek past header: %m");
483                         goto out;
484                 }
485         }
486
487         tpkt = dmalloc ((unsigned)tracefile_header.phlen, MDL);
488         if (!tpkt) {
489                 log_error ("can't allocate trace packet header.");
490                 goto out;
491         }
492
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 = (trace_type_t *)0;
497         }
498       out:
499         fclose (traceinfile);
500         if (buf)
501                 dfree (buf, MDL);
502         if (tpkt)
503                 dfree (tpkt, MDL);
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
510 isc_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;
517         int status;
518         int len;
519         fpos_t curpos;
520
521         status = fgetpos (traceinfile, &curpos);
522         if (status < 0)
523                 log_error ("Can't save tracefile position: %m");
524
525         status = fread (tpkt, 1, (size_t)tracefile_header.phlen, traceinfile);
526         if (status < tracefile_header.phlen) {
527                 if (ferror (traceinfile))
528                         log_error ("Error reading trace packet header: %m");
529                 else if (status == 0)
530                         return ISC_R_EOF;
531                 else
532                         log_error ("Short read on trace packet header: "
533                                    "%ld %ld.",
534                                    (long int)status,
535                                    (long int)tracefile_header.phlen);
536                 return ISC_R_PROTOCOLERROR;
537         }
538
539         /* Swap the packet. */
540         tpkt -> type_index = ntohl (tpkt -> type_index);
541         tpkt -> length = ntohl (tpkt -> length);
542         tpkt -> when = ntohl (tpkt -> when);
543         
544         /* See if there's a handler for this packet type. */
545         if (tpkt -> type_index < trace_type_count &&
546             trace_types [tpkt -> type_index])
547                 ttype = trace_types [tpkt -> type_index];
548         else {
549                 log_error ("Trace packet with unknown index %ld",
550                            (long int)tpkt -> type_index);
551                 return ISC_R_PROTOCOLERROR;
552         }
553
554         /* If we were just hunting for the time marker, we've found it,
555            so back up to the beginning of the packet and return its
556            type. */
557         if (ttp && *ttp == &trace_time_marker) {
558                 *ttp = ttype;
559                 status = fsetpos (traceinfile, &curpos);
560                 if (status < 0) {
561                         log_error ("fsetpos in tracefile failed: %m");
562                         return ISC_R_PROTOCOLERROR;
563                 }
564                 return ISC_R_EXISTS;
565         }
566
567         /* If we were supposed to get a particular kind of packet,
568            check to see that we got the right kind. */
569         if (ttp && *ttp && ttype != *ttp) {
570                 log_error ("Read packet type %s when expecting %s",
571                            ttype -> name, (*ttp) -> name);
572                 status = fsetpos (traceinfile, &curpos);
573                 if (status < 0) {
574                         log_error ("fsetpos in tracefile failed: %m");
575                         return ISC_R_PROTOCOLERROR;
576                 }
577                 return ISC_R_UNEXPECTEDTOKEN;
578         }
579
580         paylen = tpkt -> length;
581         if (paylen % 8)
582                 paylen += 8 - (tpkt -> length % 8);
583         if (paylen > (*bufmax)) {
584                 if ((*buf))
585                         dfree ((*buf), MDL);
586                 (*bufmax) = ((paylen + 1023) & ~1023U);
587                 (*buf) = dmalloc ((*bufmax), MDL);
588                 if (!(*buf)) {
589                         log_error ("Can't allocate input buffer sized %d",
590                                    (*bufmax));
591                         return ISC_R_NOMEMORY;
592                 }
593         }
594         
595         status = fread ((*buf), 1, paylen, traceinfile);
596         if (status < paylen) {
597                 if (ferror (traceinfile))
598                         log_error ("Error reading trace payload: %m");
599                 else
600                         log_error ("Short read on trace payload: %d %d.",
601                                    status, paylen);
602                 return ISC_R_PROTOCOLERROR;
603         }
604
605         /* Store the actual length of the payload. */
606         *buflen = tpkt -> length;
607
608         if (trace_set_time_hook)
609                 (*trace_set_time_hook) (tpkt -> when);
610
611         if (ttp)
612                 *ttp = ttype;
613         return ISC_R_SUCCESS;
614 }
615
616 isc_result_t trace_get_packet (trace_type_t **ttp,
617                                unsigned *buflen, char **buf)
618 {
619         tracepacket_t *tpkt;
620         unsigned bufmax = 0;
621         isc_result_t status;
622
623         if (!buf || *buf)
624                 return ISC_R_INVALIDARG;
625
626         tpkt = dmalloc ((unsigned)tracefile_header.phlen, MDL);
627         if (!tpkt) {
628                 log_error ("can't allocate trace packet header.");
629                 return ISC_R_NOMEMORY;
630         }
631
632         status = trace_get_next_packet (ttp, tpkt, buf, buflen, &bufmax);
633
634         dfree (tpkt, MDL);
635         return status;
636 }
637
638 time_t trace_snoop_time (trace_type_t **ptp)
639 {
640         tracepacket_t *tpkt;
641         unsigned bufmax = 0;
642         unsigned buflen = 0;
643         char *buf = (char *)0;
644         isc_result_t status;
645         time_t result;
646         trace_type_t *ttp;
647         
648         if (!ptp)
649                 ptp = &ttp;
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         *ptp = &trace_time_marker;
658         trace_get_next_packet (ptp, tpkt, &buf, &buflen, &bufmax);
659         result = tpkt -> when;
660
661         dfree (tpkt, MDL);
662         return result;
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
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 ISC_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         if (result != ISC_R_SUCCESS) {
696                 dfree (tpkt, MDL);
697                 if (*buf)
698                         dfree (*buf, MDL);
699                 return result;
700         }
701
702         /* Make sure the filename is right. */
703         if (strcmp (filename, *buf)) {
704                 log_error ("Read file %s when expecting %s", *buf, filename);
705                 status = fsetpos (traceinfile, &curpos);
706                 if (status < 0) {
707                         log_error ("fsetpos in tracefile failed: %m");
708                         dfree (tpkt, MDL);
709                         dfree (*buf, MDL);
710                         return ISC_R_PROTOCOLERROR;
711                 }
712                 return ISC_R_UNEXPECTEDTOKEN;
713         }
714
715         dfree (tpkt, MDL);
716         return ISC_R_SUCCESS;
717 }
718 #endif /* TRACING */