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