Allow a NULL pointer as argument to usb_get_next_event(), and don't
[dragonfly.git] / contrib / dhcp-3.0 / omapip / buffer.c
blob74f53dae68fab5c134c833aebcfe57845fc1da22
1 /* buffer.c
3 Buffer access functions for the object management protocol... */
5 /*
6 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1999-2003 by Internet Software Consortium
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 * Internet Systems Consortium, Inc.
22 * 950 Charter Street
23 * Redwood City, CA 94063
24 * <info@isc.org>
25 * http://www.isc.org/
27 * This software has been written for Internet Systems Consortium
28 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
29 * To learn more about Internet Systems Consortium, see
30 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
31 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
32 * ``http://www.nominum.com''.
35 #include <omapip/omapip_p.h>
37 #if defined (TRACING)
38 static void trace_connection_input_input (trace_type_t *, unsigned, char *);
39 static void trace_connection_input_stop (trace_type_t *);
40 static void trace_connection_output_input (trace_type_t *, unsigned, char *);
41 static void trace_connection_output_stop (trace_type_t *);
42 static trace_type_t *trace_connection_input;
43 static trace_type_t *trace_connection_output;
44 static isc_result_t omapi_connection_reader_trace (omapi_object_t *,
45 unsigned, char *,
46 unsigned *);
47 extern omapi_array_t *omapi_connections;
49 void omapi_buffer_trace_setup ()
51 trace_connection_input =
52 trace_type_register ("connection-input",
53 (void *)0,
54 trace_connection_input_input,
55 trace_connection_input_stop, MDL);
56 trace_connection_output =
57 trace_type_register ("connection-output",
58 (void *)0,
59 trace_connection_output_input,
60 trace_connection_output_stop, MDL);
63 static void trace_connection_input_input (trace_type_t *ttype,
64 unsigned length, char *buf)
66 unsigned left, taken, cc = 0;
67 char *s;
68 int32_t connect_index;
69 isc_result_t status;
70 omapi_connection_object_t *c = (omapi_connection_object_t *)0;
72 memcpy (&connect_index, buf, sizeof connect_index);
73 connect_index = ntohl (connect_index);
75 omapi_array_foreach_begin (omapi_connections,
76 omapi_connection_object_t, lp) {
77 if (lp -> index == ntohl (connect_index)) {
78 omapi_connection_reference (&c, lp, MDL);
79 omapi_connection_dereference (&lp, MDL);
80 break;
82 } omapi_array_foreach_end (omapi_connections,
83 omapi_connection_object_t, lp);
85 if (!c) {
86 log_error ("trace connection input: no connection index %ld",
87 (long int)connect_index);
88 return;
91 s = buf + sizeof connect_index;
92 left = length - sizeof connect_index;
94 while (left) {
95 taken = 0;
96 status = omapi_connection_reader_trace ((omapi_object_t *)c,
97 left, s, &taken);
98 if (status != ISC_R_SUCCESS) {
99 log_error ("trace connection input: %s",
100 isc_result_totext (status));
101 break;
103 if (!taken) {
104 if (cc > 0) {
105 log_error ("trace connection_input: %s",
106 "input is not being consumed.");
107 break;
109 cc++;
110 } else {
111 cc = 0;
112 left -= taken;
115 omapi_connection_dereference (&c, MDL);
118 static void trace_connection_input_stop (trace_type_t *ttype) { }
120 static void trace_connection_output_input (trace_type_t *ttype,
121 unsigned length, char *buf)
123 /* We *could* check to see if the output is correct, but for now
124 we aren't going to do that. */
127 static void trace_connection_output_stop (trace_type_t *ttype) { }
129 #endif
131 /* Make sure that at least len bytes are in the input buffer, and if not,
132 read enough bytes to make up the difference. */
134 isc_result_t omapi_connection_reader (omapi_object_t *h)
136 #if defined (TRACING)
137 return omapi_connection_reader_trace (h, 0, (char *)0, (unsigned *)0);
140 static isc_result_t omapi_connection_reader_trace (omapi_object_t *h,
141 unsigned stuff_len,
142 char *stuff_buf,
143 unsigned *stuff_taken)
145 #endif
146 omapi_buffer_t *buffer;
147 isc_result_t status;
148 unsigned read_len;
149 int read_status;
150 omapi_connection_object_t *c;
151 unsigned bytes_to_read;
153 if (!h || h -> type != omapi_type_connection)
154 return ISC_R_INVALIDARG;
155 c = (omapi_connection_object_t *)h;
157 /* Make sure c -> bytes_needed is valid. */
158 if (c -> bytes_needed < 0)
159 return ISC_R_INVALIDARG;
161 /* See if there are enough bytes. */
162 if (c -> in_bytes >= OMAPI_BUF_SIZE - 1 &&
163 c -> in_bytes > c -> bytes_needed)
164 return ISC_R_SUCCESS;
167 if (c -> inbufs) {
168 for (buffer = c -> inbufs; buffer -> next;
169 buffer = buffer -> next)
171 if (!BUFFER_BYTES_FREE (buffer)) {
172 status = omapi_buffer_new (&buffer -> next, MDL);
173 if (status != ISC_R_SUCCESS)
174 return status;
175 buffer = buffer -> next;
177 } else {
178 status = omapi_buffer_new (&c -> inbufs, MDL);
179 if (status != ISC_R_SUCCESS)
180 return status;
181 buffer = c -> inbufs;
184 bytes_to_read = BUFFER_BYTES_FREE (buffer);
186 while (bytes_to_read) {
187 if (buffer -> tail > buffer -> head)
188 read_len = sizeof (buffer -> buf) - buffer -> tail;
189 else
190 read_len = buffer -> head - buffer -> tail;
192 #if defined (TRACING)
193 if (trace_playback()) {
194 if (stuff_len) {
195 if (read_len > stuff_len)
196 read_len = stuff_len;
197 if (stuff_taken)
198 *stuff_taken += read_len;
199 memcpy (&buffer -> buf [buffer -> tail],
200 stuff_buf, read_len);
201 stuff_len -= read_len;
202 stuff_buf += read_len;
203 read_status = read_len;
204 } else {
205 break;
207 } else
208 #endif
210 read_status = read (c -> socket,
211 &buffer -> buf [buffer -> tail],
212 read_len);
214 if (read_status < 0) {
215 if (errno == EWOULDBLOCK)
216 break;
217 else if (errno == EIO)
218 return ISC_R_IOERROR;
219 else if (errno == EINVAL)
220 return ISC_R_INVALIDARG;
221 else if (errno == ECONNRESET) {
222 omapi_disconnect (h, 1);
223 return ISC_R_SHUTTINGDOWN;
224 } else
225 return ISC_R_UNEXPECTED;
228 /* If we got a zero-length read, as opposed to EWOULDBLOCK,
229 the remote end closed the connection. */
230 if (read_status == 0) {
231 omapi_disconnect (h, 0);
232 return ISC_R_SHUTTINGDOWN;
234 #if defined (TRACING)
235 if (trace_record ()) {
236 trace_iov_t iov [2];
237 int32_t connect_index;
239 connect_index = htonl (c -> index);
241 iov [0].buf = (char *)&connect_index;
242 iov [0].len = sizeof connect_index;
243 iov [1].buf = &buffer -> buf [buffer -> tail];
244 iov [1].len = read_status;
246 status = (trace_write_packet_iov
247 (trace_connection_input, 2, iov, MDL));
248 if (status != ISC_R_SUCCESS) {
249 trace_stop ();
250 log_error ("trace connection input: %s",
251 isc_result_totext (status));
254 #endif
255 buffer -> tail += read_status;
256 c -> in_bytes += read_status;
257 if (buffer -> tail == sizeof buffer -> buf)
258 buffer -> tail = 0;
259 if (read_status < read_len)
260 break;
261 bytes_to_read -= read_status;
264 if (c -> bytes_needed <= c -> in_bytes) {
265 omapi_signal (h, "ready", c);
267 return ISC_R_SUCCESS;
270 /* Put some bytes into the output buffer for a connection. */
272 isc_result_t omapi_connection_copyin (omapi_object_t *h,
273 const unsigned char *bufp,
274 unsigned len)
276 omapi_buffer_t *buffer;
277 isc_result_t status;
278 int bytes_copied = 0;
279 unsigned copy_len;
280 int sig_flags = SIG_MODE_UPDATE;
281 omapi_connection_object_t *c;
283 /* Make sure len is valid. */
284 if (len < 0)
285 return ISC_R_INVALIDARG;
286 if (!h || h -> type != omapi_type_connection)
287 return ISC_R_INVALIDARG;
288 c = (omapi_connection_object_t *)h;
290 /* If the connection is closed, return an error if the caller
291 tries to copy in. */
292 if (c -> state == omapi_connection_disconnecting ||
293 c -> state == omapi_connection_closed)
294 return ISC_R_NOTCONNECTED;
296 if (c -> outbufs) {
297 for (buffer = c -> outbufs;
298 buffer -> next; buffer = buffer -> next)
300 } else {
301 status = omapi_buffer_new (&c -> outbufs, MDL);
302 if (status != ISC_R_SUCCESS)
303 return status;
304 buffer = c -> outbufs;
307 while (bytes_copied < len) {
308 /* If there is no space available in this buffer,
309 allocate a new one. */
310 if (!BUFFER_BYTES_FREE (buffer)) {
311 status = (omapi_buffer_new (&buffer -> next, MDL));
312 if (status != ISC_R_SUCCESS)
313 return status;
314 buffer = buffer -> next;
317 if (buffer -> tail > buffer -> head)
318 copy_len = sizeof (buffer -> buf) - buffer -> tail;
319 else
320 copy_len = buffer -> head - buffer -> tail;
322 if (copy_len > (len - bytes_copied))
323 copy_len = len - bytes_copied;
325 if (c -> out_key) {
326 if (!c -> out_context)
327 sig_flags |= SIG_MODE_INIT;
328 status = omapi_connection_sign_data
329 (sig_flags, c -> out_key, &c -> out_context,
330 &bufp [bytes_copied], copy_len,
331 (omapi_typed_data_t **)0);
332 if (status != ISC_R_SUCCESS)
333 return status;
336 memcpy (&buffer -> buf [buffer -> tail],
337 &bufp [bytes_copied], copy_len);
338 buffer -> tail += copy_len;
339 c -> out_bytes += copy_len;
340 bytes_copied += copy_len;
341 if (buffer -> tail == sizeof buffer -> buf)
342 buffer -> tail = 0;
344 return ISC_R_SUCCESS;
347 /* Copy some bytes from the input buffer, and advance the input buffer
348 pointer beyond the bytes copied out. */
350 isc_result_t omapi_connection_copyout (unsigned char *buf,
351 omapi_object_t *h,
352 unsigned size)
354 unsigned bytes_remaining;
355 unsigned bytes_this_copy;
356 unsigned first_byte;
357 omapi_buffer_t *buffer;
358 unsigned char *bufp;
359 int sig_flags = SIG_MODE_UPDATE;
360 omapi_connection_object_t *c;
361 isc_result_t status;
363 if (!h || h -> type != omapi_type_connection)
364 return ISC_R_INVALIDARG;
365 c = (omapi_connection_object_t *)h;
367 if (size > c -> in_bytes)
368 return ISC_R_NOMORE;
369 bufp = buf;
370 bytes_remaining = size;
371 buffer = c -> inbufs;
373 while (bytes_remaining) {
374 if (!buffer)
375 return ISC_R_UNEXPECTED;
376 if (BYTES_IN_BUFFER (buffer)) {
377 if (buffer -> head == (sizeof buffer -> buf) - 1)
378 first_byte = 0;
379 else
380 first_byte = buffer -> head + 1;
382 if (first_byte > buffer -> tail) {
383 bytes_this_copy = (sizeof buffer -> buf -
384 first_byte);
385 } else {
386 bytes_this_copy =
387 buffer -> tail - first_byte;
389 if (bytes_this_copy > bytes_remaining)
390 bytes_this_copy = bytes_remaining;
391 if (bufp) {
392 if (c -> in_key) {
393 if (!c -> in_context)
394 sig_flags |= SIG_MODE_INIT;
395 status = omapi_connection_sign_data
396 (sig_flags,
397 c -> in_key,
398 &c -> in_context,
399 (unsigned char *)
400 &buffer -> buf [first_byte],
401 bytes_this_copy,
402 (omapi_typed_data_t **)0);
403 if (status != ISC_R_SUCCESS)
404 return status;
407 memcpy (bufp, &buffer -> buf [first_byte],
408 bytes_this_copy);
409 bufp += bytes_this_copy;
411 bytes_remaining -= bytes_this_copy;
412 buffer -> head = first_byte + bytes_this_copy - 1;
413 c -> in_bytes -= bytes_this_copy;
416 if (!BYTES_IN_BUFFER (buffer))
417 buffer = buffer -> next;
420 /* Get rid of any input buffers that we emptied. */
421 buffer = (omapi_buffer_t *)0;
422 while (c -> inbufs &&
423 !BYTES_IN_BUFFER (c -> inbufs)) {
424 if (c -> inbufs -> next) {
425 omapi_buffer_reference (&buffer,
426 c -> inbufs -> next, MDL);
427 omapi_buffer_dereference (&c -> inbufs -> next, MDL);
429 omapi_buffer_dereference (&c -> inbufs, MDL);
430 if (buffer) {
431 omapi_buffer_reference
432 (&c -> inbufs, buffer, MDL);
433 omapi_buffer_dereference (&buffer, MDL);
436 return ISC_R_SUCCESS;
439 isc_result_t omapi_connection_writer (omapi_object_t *h)
441 unsigned bytes_this_write;
442 int bytes_written;
443 unsigned first_byte;
444 omapi_buffer_t *buffer;
445 unsigned char *bufp;
446 omapi_connection_object_t *c;
447 isc_result_t status;
449 if (!h || h -> type != omapi_type_connection)
450 return ISC_R_INVALIDARG;
451 c = (omapi_connection_object_t *)h;
453 /* Already flushed... */
454 if (!c -> out_bytes)
455 return ISC_R_SUCCESS;
457 buffer = c -> outbufs;
459 while (c -> out_bytes) {
460 if (!buffer)
461 return ISC_R_UNEXPECTED;
462 if (BYTES_IN_BUFFER (buffer)) {
463 if (buffer -> head == (sizeof buffer -> buf) - 1)
464 first_byte = 0;
465 else
466 first_byte = buffer -> head + 1;
468 if (first_byte > buffer -> tail) {
469 bytes_this_write = (sizeof buffer -> buf -
470 first_byte);
471 } else {
472 bytes_this_write =
473 buffer -> tail - first_byte;
475 bytes_written = write (c -> socket,
476 &buffer -> buf [first_byte],
477 bytes_this_write);
478 /* If the write failed with EWOULDBLOCK or we wrote
479 zero bytes, a further write would block, so we have
480 flushed as much as we can for now. Other errors
481 are really errors. */
482 if (bytes_written < 0) {
483 if (errno == EWOULDBLOCK || errno == EAGAIN)
484 return ISC_R_SUCCESS;
485 else if (errno == EPIPE)
486 return ISC_R_NOCONN;
487 #ifdef EDQUOT
488 else if (errno == EFBIG || errno == EDQUOT)
489 #else
490 else if (errno == EFBIG)
491 #endif
492 return ISC_R_NORESOURCES;
493 else if (errno == ENOSPC)
494 return ISC_R_NOSPACE;
495 else if (errno == EIO)
496 return ISC_R_IOERROR;
497 else if (errno == EINVAL)
498 return ISC_R_INVALIDARG;
499 else if (errno == ECONNRESET)
500 return ISC_R_SHUTTINGDOWN;
501 else
502 return ISC_R_UNEXPECTED;
504 if (bytes_written == 0)
505 return ISC_R_SUCCESS;
507 #if defined (TRACING)
508 if (trace_record ()) {
509 trace_iov_t iov [2];
510 int32_t connect_index;
512 connect_index = htonl (c -> index);
514 iov [0].buf = (char *)&connect_index;
515 iov [0].len = sizeof connect_index;
516 iov [1].buf = &buffer -> buf [buffer -> tail];
517 iov [1].len = bytes_written;
519 status = (trace_write_packet_iov
520 (trace_connection_input, 2, iov,
521 MDL));
522 if (status != ISC_R_SUCCESS) {
523 trace_stop ();
524 log_error ("trace %s output: %s",
525 "connection",
526 isc_result_totext (status));
529 #endif
531 buffer -> head = first_byte + bytes_written - 1;
532 c -> out_bytes -= bytes_written;
534 /* If we didn't finish out the write, we filled the
535 O.S. output buffer and a further write would block,
536 so stop trying to flush now. */
537 if (bytes_written != bytes_this_write)
538 return ISC_R_SUCCESS;
541 if (!BYTES_IN_BUFFER (buffer))
542 buffer = buffer -> next;
545 /* Get rid of any output buffers we emptied. */
546 buffer = (omapi_buffer_t *)0;
547 while (c -> outbufs &&
548 !BYTES_IN_BUFFER (c -> outbufs)) {
549 if (c -> outbufs -> next) {
550 omapi_buffer_reference (&buffer,
551 c -> outbufs -> next, MDL);
552 omapi_buffer_dereference (&c -> outbufs -> next, MDL);
554 omapi_buffer_dereference (&c -> outbufs, MDL);
555 if (buffer) {
556 omapi_buffer_reference (&c -> outbufs, buffer, MDL);
557 omapi_buffer_dereference (&buffer, MDL);
560 return ISC_R_SUCCESS;
563 isc_result_t omapi_connection_get_uint32 (omapi_object_t *c,
564 u_int32_t *result)
566 u_int32_t inbuf;
567 isc_result_t status;
569 status = omapi_connection_copyout ((unsigned char *)&inbuf,
570 c, sizeof inbuf);
571 if (status != ISC_R_SUCCESS)
572 return status;
574 *result = ntohl (inbuf);
575 return ISC_R_SUCCESS;
578 isc_result_t omapi_connection_put_uint32 (omapi_object_t *c,
579 u_int32_t value)
581 u_int32_t inbuf;
582 isc_result_t status;
584 inbuf = htonl (value);
586 return omapi_connection_copyin (c, (unsigned char *)&inbuf,
587 sizeof inbuf);
590 isc_result_t omapi_connection_get_uint16 (omapi_object_t *c,
591 u_int16_t *result)
593 u_int16_t inbuf;
594 isc_result_t status;
596 status = omapi_connection_copyout ((unsigned char *)&inbuf,
597 c, sizeof inbuf);
598 if (status != ISC_R_SUCCESS)
599 return status;
601 *result = ntohs (inbuf);
602 return ISC_R_SUCCESS;
605 isc_result_t omapi_connection_put_uint16 (omapi_object_t *c,
606 u_int32_t value)
608 u_int16_t inbuf;
609 isc_result_t status;
611 inbuf = htons (value);
613 return omapi_connection_copyin (c, (unsigned char *)&inbuf,
614 sizeof inbuf);
617 isc_result_t omapi_connection_write_typed_data (omapi_object_t *c,
618 omapi_typed_data_t *data)
620 isc_result_t status;
621 omapi_handle_t handle;
623 /* Null data is valid. */
624 if (!data)
625 return omapi_connection_put_uint32 (c, 0);
627 switch (data -> type) {
628 case omapi_datatype_int:
629 status = omapi_connection_put_uint32 (c, sizeof (u_int32_t));
630 if (status != ISC_R_SUCCESS)
631 return status;
632 return omapi_connection_put_uint32 (c, ((u_int32_t)
633 (data -> u.integer)));
635 case omapi_datatype_string:
636 case omapi_datatype_data:
637 status = omapi_connection_put_uint32 (c, data -> u.buffer.len);
638 if (status != ISC_R_SUCCESS)
639 return status;
640 if (data -> u.buffer.len)
641 return omapi_connection_copyin
642 (c, data -> u.buffer.value,
643 data -> u.buffer.len);
644 return ISC_R_SUCCESS;
646 case omapi_datatype_object:
647 if (data -> u.object) {
648 status = omapi_object_handle (&handle,
649 data -> u.object);
650 if (status != ISC_R_SUCCESS)
651 return status;
652 } else
653 handle = 0;
654 status = omapi_connection_put_uint32 (c, sizeof handle);
655 if (status != ISC_R_SUCCESS)
656 return status;
657 return omapi_connection_put_uint32 (c, handle);
660 return ISC_R_INVALIDARG;
663 isc_result_t omapi_connection_put_name (omapi_object_t *c, const char *name)
665 isc_result_t status;
666 unsigned len = strlen (name);
668 status = omapi_connection_put_uint16 (c, len);
669 if (status != ISC_R_SUCCESS)
670 return status;
671 return omapi_connection_copyin (c, (const unsigned char *)name, len);
674 isc_result_t omapi_connection_put_string (omapi_object_t *c,
675 const char *string)
677 isc_result_t status;
678 unsigned len;
680 if (string)
681 len = strlen (string);
682 else
683 len = 0;
685 status = omapi_connection_put_uint32 (c, len);
686 if (status != ISC_R_SUCCESS)
687 return status;
688 if (len)
689 return omapi_connection_copyin
690 (c, (const unsigned char *)string, len);
691 return ISC_R_SUCCESS;
694 isc_result_t omapi_connection_put_handle (omapi_object_t *c, omapi_object_t *h)
696 isc_result_t status;
697 omapi_handle_t handle;
699 if (h) {
700 status = omapi_object_handle (&handle, h);
701 if (status != ISC_R_SUCCESS)
702 return status;
703 } else
704 handle = 0; /* The null handle. */
705 status = omapi_connection_put_uint32 (c, sizeof handle);
706 if (status != ISC_R_SUCCESS)
707 return status;
708 return omapi_connection_put_uint32 (c, handle);