Merge from vendor branch DHCP:
[dragonfly.git] / contrib / isc-dhcp / omapip / mrtrace.c
1 /* mrtrace.c
2
3    Subroutines that support minires tracing... */
4
5 /*
6  * Copyright (c) 2001 Internet Software Consortium.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of The Internet Software Consortium nor the names
19  *    of its contributors may be used to endorse or promote products derived
20  *    from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26  * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  * This software has been written for the Internet Software Consortium
37  * by Ted Lemon, as part of a project for Nominum, Inc.   To learn more
38  * about the Internet Software Consortium, see http://www.isc.org/.  To
39  * learn more about Nominum, Inc., see ``http://www.nominum.com''.
40  */
41
42 #include <omapip/omapip_p.h>
43
44 #include "minires/minires.h"
45 #include "arpa/nameser.h"
46
47 static void trace_mr_output_input (trace_type_t *, unsigned, char *);
48 static void trace_mr_output_stop (trace_type_t *);
49 static void trace_mr_input_input (trace_type_t *, unsigned, char *);
50 static void trace_mr_input_stop (trace_type_t *);
51 static void trace_mr_statp_input (trace_type_t *, unsigned, char *);
52 static void trace_mr_statp_stop (trace_type_t *);
53 static void trace_mr_randomid_input (trace_type_t *, unsigned, char *);
54 static void trace_mr_randomid_stop (trace_type_t *);
55 trace_type_t *trace_mr_output;
56 trace_type_t *trace_mr_input;
57 trace_type_t *trace_mr_statp;
58 trace_type_t *trace_mr_randomid;
59 ssize_t trace_mr_send (int, void *, size_t, int);
60 ssize_t trace_mr_read_playback (struct sockaddr_in *, void *, size_t);
61 void trace_mr_read_record (struct sockaddr_in *, void *, ssize_t);
62 ssize_t trace_mr_recvfrom (int s, void *, size_t, int,
63                            struct sockaddr *, SOCKLEN_T *);
64 ssize_t trace_mr_read (int, void *, size_t);
65 int trace_mr_connect (int s, struct sockaddr *, SOCKLEN_T);
66 int trace_mr_socket (int, int, int);
67 int trace_mr_bind (int, struct sockaddr *, SOCKLEN_T);
68 int trace_mr_close (int);
69 time_t trace_mr_time (time_t *);
70 int trace_mr_select (int, fd_set *, fd_set *, fd_set *, struct timeval *);
71 unsigned int trace_mr_res_randomid (unsigned int);
72
73 extern time_t cur_time;
74
75 #if defined (TRACING)
76 void trace_mr_init ()
77 {
78         trace_mr_output = trace_type_register ("mr-output", (void *)0,
79                                                trace_mr_output_input,
80                                                trace_mr_output_stop, MDL);
81         trace_mr_input = trace_type_register ("mr-input", (void *)0,
82                                               trace_mr_input_input,
83                                               trace_mr_input_stop, MDL);
84         trace_mr_statp = trace_type_register ("mr-statp", (void *)0,
85                                               trace_mr_statp_input,
86                                               trace_mr_statp_stop, MDL);
87         trace_mr_randomid = trace_type_register ("mr-randomid", (void *)0,
88                                                  trace_mr_randomid_input,
89                                                  trace_mr_randomid_stop, MDL);
90 }
91
92 void trace_mr_statp_setup (res_state statp)
93 {
94         unsigned buflen = 0;
95         char *buf = (char *)0;
96         isc_result_t status;
97         u_int32_t id;
98         int i;
99
100         if (trace_playback ()) {
101                 int nscount;
102                 status = trace_get_packet (&trace_mr_statp, &buflen, &buf);
103                 if (status != ISC_R_SUCCESS) {
104                         log_error ("trace_mr_statp: no statp packet found.");
105                         return;
106                 }
107                 nscount = buflen / sizeof (struct in_addr);
108                 if (nscount * (sizeof (struct in_addr)) != buflen ||
109                     nscount < 1) {
110                         log_error ("trace_mr_statp: bogus length: %d",
111                                    buflen);
112                         return;
113                 }
114                 if (nscount > MAXNS)
115                         nscount = MAXNS;
116                 for (i = 0; i < nscount; i++) {
117 #if defined (HAVE_SA_LEN)
118                         statp -> nsaddr_list [i].sin_len =
119                                 sizeof (struct sockaddr_in);
120 #endif
121                         memset (&statp -> nsaddr_list [i].sin_zero, 0,
122                                 sizeof statp -> nsaddr_list [i].sin_zero);
123                         statp -> nsaddr_list [i].sin_port = htons (53); /*XXX*/
124                         statp -> nsaddr_list [i].sin_family = AF_INET;
125                         memcpy (&statp -> nsaddr_list [i].sin_addr,
126                                 (buf + i * (sizeof (struct in_addr))),
127                                 sizeof (struct in_addr));
128                 }
129                 statp -> nscount = nscount;
130                 dfree (buf, MDL);
131                 buf = (char *)0;
132         }
133         if (trace_record ()) {
134                 trace_iov_t *iov;
135                 iov = dmalloc ((statp -> nscount *
136                                 sizeof (trace_iov_t)), MDL);
137                 if (!iov) {
138                         trace_stop ();
139                         log_error ("No memory for statp iov.");
140                         return;
141                 }
142                 for (i = 0; i < statp -> nscount; i++) {
143                         iov [i].buf =
144                                 (char *)&statp -> nsaddr_list [i].sin_addr;
145                         iov [i].len = sizeof (struct in_addr);
146                 }
147                 trace_write_packet_iov (trace_mr_statp, i, iov, MDL);
148                 dfree (iov, MDL);
149         }
150 }
151 #endif
152
153 ssize_t trace_mr_send (int fd, void *msg, size_t len, int flags)
154 {
155         ssize_t rv;
156 #if defined (TRACING)
157         isc_result_t status;
158         unsigned buflen = 0;
159         char *inbuf = (char *)0;
160         u_int32_t result;
161         u_int32_t sflags;
162
163         if (trace_playback()) {
164                 status = trace_get_packet (&trace_mr_output, &buflen, &inbuf);
165                 if (status != ISC_R_SUCCESS) {
166                         log_error ("trace_mr_recvfrom: no input found.");
167                         errno = ECONNREFUSED;
168                         return -1;
169                 }
170                 if (buflen < sizeof result) {
171                         log_error ("trace_mr_recvfrom: data too short.");
172                         errno = ECONNREFUSED;
173                         dfree (inbuf, MDL);
174                         return -1;
175                 }
176                 memcpy (&result, inbuf, sizeof result);
177                 rv = ntohl (result);
178                 dfree (inbuf, MDL);
179         } else
180 #endif
181                 rv = send (fd, msg, len, flags);
182 #if defined (TRACING)
183         if (trace_record ()) {
184                 trace_iov_t iov [3];
185                 result = htonl (rv);
186                 sflags = htonl (flags);
187                 iov [0].len = sizeof result;
188                 iov [0].buf = (char *)&result;
189                 iov [1].len = sizeof sflags;
190                 iov [1].buf = (char *)&flags;
191                 iov [2].len = len;
192                 iov [2].buf = msg;
193                 trace_write_packet_iov (trace_mr_output, 2, iov, MDL);
194         }
195 #endif
196         return rv;
197 }
198
199 #if defined (TRACING)
200 ssize_t trace_mr_read_playback (struct sockaddr_in *from,
201                                 void *buf, size_t nbytes)
202 {
203         isc_result_t status;
204         unsigned buflen = 0, left;
205         char *inbuf = (char *)0;
206         char *bufp;
207         u_int32_t result;
208
209         status = trace_get_packet (&trace_mr_input, &buflen, &inbuf);
210         if (status != ISC_R_SUCCESS) {
211                 log_error ("trace_mr_recvfrom: no input found.");
212                 errno = ECONNREFUSED;
213                 return -1;
214         }
215         if (buflen < sizeof result) {
216                 log_error ("trace_mr_recvfrom: data too short.");
217                 errno = ECONNREFUSED;
218                 dfree (inbuf, MDL);
219                 return -1;
220         }
221         bufp = inbuf;
222         left = buflen;
223         memcpy (&result, bufp, sizeof result);
224         result = ntohl (result);
225         bufp += sizeof result;
226         left -= sizeof result;
227         if (result == 0) {
228                 if (left < ((sizeof from -> sin_port) +
229                             sizeof (from -> sin_addr))) {
230                         log_error ("trace_mr_recvfrom: data too short.");
231                         errno = ECONNREFUSED;
232                         dfree (inbuf, MDL);
233                         return -1;
234                 }
235                 if (from)
236                         memcpy (&from -> sin_addr, bufp,
237                                 sizeof from -> sin_addr);
238                 bufp += sizeof from -> sin_addr;
239                 left -= sizeof from -> sin_addr;
240                 if (from)
241                         memcpy (&from -> sin_port, bufp,
242                                 sizeof from -> sin_port);
243                 bufp += sizeof from -> sin_port;
244                 left -= sizeof from -> sin_port;
245                 if (from) {
246                         from -> sin_family = AF_INET;
247 #if defined(HAVE_SA_LEN)
248                         from -> sin_len = sizeof (struct sockaddr_in);
249 #endif
250                         memset (from -> sin_zero, 0, sizeof from -> sin_zero);
251                 }
252                 if (left > nbytes) {
253                         log_error ("trace_mr_recvfrom: too much%s",
254                                    " data.");
255                         errno = ECONNREFUSED;
256                         dfree (inbuf, MDL);
257                         return -1;
258                 }
259                 memcpy (buf, bufp, left);
260                 dfree (inbuf, MDL);
261                 return left;
262         }
263         errno = ECONNREFUSED;
264         return -1;
265 }
266
267 void trace_mr_read_record (struct sockaddr_in *from, void *buf, ssize_t rv)
268 {
269         trace_iov_t iov [4];
270         u_int32_t result;
271         int iolen = 0;
272         static char zero [4] = { 0, 0, 0, 0 };
273         
274         if (rv < 0)
275                 result = htonl (errno);         /* XXX */
276         else
277                 result = 0;
278         iov [iolen].buf = (char *)&result;
279         iov [iolen++].len = sizeof result;
280         if (rv > 0) {
281                 if (from) {
282                         iov [iolen].buf = (char *)&from -> sin_addr;
283                         iov [iolen++].len = sizeof from -> sin_addr;
284                         iov [iolen].buf = (char *)&from -> sin_port;
285                         iov [iolen++].len = sizeof from -> sin_port;
286                 } else {
287                         iov [iolen].buf = zero;
288                         iov [iolen++].len = sizeof from -> sin_addr;
289                         iov [iolen].buf = zero;
290                         iov [iolen++].len = sizeof from -> sin_port;
291                 }
292
293                 iov [iolen].buf = buf;
294                 iov [iolen++].len = rv;
295         }
296         trace_write_packet_iov (trace_mr_input, iolen, iov, MDL);
297 }
298 #endif
299
300 ssize_t trace_mr_recvfrom (int s, void *buf, size_t len, int flags,
301                            struct sockaddr *from, SOCKLEN_T *fromlen)
302 {
303         ssize_t rv;
304
305 #if defined (TRACING)
306         if (trace_playback ())
307                 rv = trace_mr_read_playback ((struct sockaddr_in *)from,
308                                              buf, len);
309         else
310 #endif
311                 rv = recvfrom (s, buf, len, flags, from, fromlen);
312 #if defined (TRACING)
313         if (trace_record ()) {
314                 trace_mr_read_record ((struct sockaddr_in *)from, buf, rv);
315         }
316 #endif
317         return rv;
318 }
319
320 ssize_t trace_mr_read (int d, void *buf, size_t nbytes)
321 {
322         ssize_t rv;
323
324 #if defined (TRACING)
325         if (trace_playback ())
326                 rv = trace_mr_read_playback ((struct sockaddr_in *)0,
327                                              buf, nbytes);
328         else
329 #endif
330                 rv = read (d, buf, nbytes);
331 #if defined (TRACING)
332         if (trace_record ()) {
333                 trace_mr_read_record ((struct sockaddr_in *)0, buf, rv);
334         }
335 #endif
336         return rv;
337 }
338
339 int trace_mr_connect (int s, struct sockaddr *name, SOCKLEN_T namelen)
340 {
341 #if defined (TRACING)
342         if (!trace_playback ())
343 #endif
344                 return connect (s, name, namelen);
345 #if defined (TRACING)
346         return 0;
347 #endif
348 }
349
350 int trace_mr_socket (int domain, int type, int protocol)
351 {
352 #if defined (TRACING)
353         if (!trace_playback ())
354 #endif
355                 return socket (domain, type, protocol);
356 #if defined (TRACING)
357         return 100;
358 #endif
359 }
360
361 int trace_mr_bind (int s, struct sockaddr *name, SOCKLEN_T namelen)
362 {
363 #if defined (TRACING)
364         if (!trace_playback ())
365 #endif
366                 return bind (s, name, namelen);
367 #if defined (TRACING)
368         return 0;
369 #endif
370 }
371
372 int trace_mr_close (int s)
373 {
374 #if defined (TRACING)
375         if (!trace_playback ())
376 #endif
377                 return close (s);
378 #if defined (TRACING)
379         return 0;
380 #endif
381 }
382
383 time_t trace_mr_time (time_t *tp)
384 {
385 #if defined (TRACING)
386         if (trace_playback ()) {
387                 if (tp)
388                         *tp = cur_time;
389                 return cur_time;
390         }
391 #endif
392         return time (tp);
393 }
394
395 int trace_mr_select (int s, fd_set *r, fd_set *w, fd_set *x, struct timeval *t)
396 {
397 #if defined (TRACING)
398         trace_type_t *ttp = (trace_type_t *)0;
399
400         if (trace_playback ()) {
401                 time_t nct = trace_snoop_time (&ttp);
402                 time_t secr = t -> tv_sec;
403                 t -> tv_sec = nct - cur_time;
404                 if (t -> tv_sec > secr)
405                         return 0;
406                 if (ttp == trace_mr_input)
407                         return 1;
408                 return 0;
409         }
410 #endif
411         return select (s, r, w, x, t);
412 }
413
414 unsigned int trace_mr_res_randomid (unsigned int oldid)
415 {
416         u_int32_t id;
417         int rid = oldid;
418 #if defined (TRACING)
419         unsigned buflen = 0;
420         char *buf = (char *)0;
421         isc_result_t status;
422
423         if (trace_playback ()) {
424                 int nscount;
425                 status = trace_get_packet (&trace_mr_randomid, &buflen, &buf);
426                 if (status != ISC_R_SUCCESS) {
427                         log_error ("trace_mr_statp: no statp packet found.");
428                         return oldid;
429                 }
430                 if (buflen != sizeof id) {
431                         log_error ("trace_mr_randomid: bogus length: %d",
432                                    buflen);
433                         return oldid;
434                 }
435                 memcpy (&id, buf, sizeof id);
436                 dfree (buf, MDL);
437                 buf = (char *)0;
438                 rid = ntohl (id);
439         }
440         if (trace_record ()) {
441                 id = htonl (rid);
442                 trace_write_packet (trace_mr_randomid,
443                                     sizeof id, (char *)&id, MDL);
444         }
445 #endif
446         return rid;
447 }
448
449 #if defined (TRACING)
450 static void trace_mr_output_input (trace_type_t *ttype,
451                                    unsigned length, char *buf)
452 {
453 }
454
455 static void trace_mr_output_stop (trace_type_t *ttype)
456 {
457 }
458
459 static void trace_mr_input_input (trace_type_t *ttype,
460                                   unsigned length, char *buf)
461 {
462         log_error ("unaccounted-for minires input.");
463 }
464
465 static void trace_mr_input_stop (trace_type_t *ttype)
466 {
467 }
468
469 static void trace_mr_statp_input (trace_type_t *ttype,
470                                   unsigned length, char *buf)
471 {
472         log_error ("unaccounted-for minires statp input.");
473 }
474
475 static void trace_mr_statp_stop (trace_type_t *ttype)
476 {
477 }
478
479 static void trace_mr_randomid_input (trace_type_t *ttype,
480                                      unsigned length, char *buf)
481 {
482         log_error ("unaccounted-for minires randomid input.");
483 }
484
485 static void trace_mr_randomid_stop (trace_type_t *ttype)
486 {
487 }
488 #endif