Remove building with NOCRYPTO option
[minix.git] / external / bsd / dhcp / dist / omapip / buffer.c
blobac21f2ecd4177d264d19fb2cfcf7bb8bc914eb53
1 /* $NetBSD: buffer.c,v 1.1.1.3 2014/07/12 11:57:58 spz Exp $ */
2 /* buffer.c
4 Buffer access functions for the object management protocol... */
6 /*
7 * Copyright (c) 2009,2012-2014 by Internet Systems Consortium, Inc. ("ISC")
8 * Copyright (c) 2004,2005,2007 by Internet Systems Consortium, Inc. ("ISC")
9 * Copyright (c) 1999-2003 by Internet Software Consortium
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.
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.
23 * Internet Systems Consortium, Inc.
24 * 950 Charter Street
25 * Redwood City, CA 94063
26 * <info@isc.org>
27 * https://www.isc.org/
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: buffer.c,v 1.1.1.3 2014/07/12 11:57:58 spz Exp $");
34 #include "dhcpd.h"
36 #include <omapip/omapip_p.h>
37 #include <errno.h>
39 #if defined (TRACING)
40 static void trace_connection_input_input (trace_type_t *, unsigned, char *);
41 static void trace_connection_input_stop (trace_type_t *);
42 static void trace_connection_output_input (trace_type_t *, unsigned, char *);
43 static void trace_connection_output_stop (trace_type_t *);
44 static trace_type_t *trace_connection_input;
45 static trace_type_t *trace_connection_output;
46 static isc_result_t omapi_connection_reader_trace (omapi_object_t *,
47 unsigned, char *,
48 unsigned *);
49 extern omapi_array_t *omapi_connections;
51 void omapi_buffer_trace_setup ()
53 trace_connection_input =
54 trace_type_register ("connection-input",
55 (void *)0,
56 trace_connection_input_input,
57 trace_connection_input_stop, MDL);
58 trace_connection_output =
59 trace_type_register ("connection-output",
60 (void *)0,
61 trace_connection_output_input,
62 trace_connection_output_stop, MDL);
65 static void trace_connection_input_input (trace_type_t *ttype,
66 unsigned length, char *buf)
68 unsigned left, taken, cc = 0;
69 char *s;
70 int32_t connect_index;
71 isc_result_t status;
72 omapi_connection_object_t *c = (omapi_connection_object_t *)0;
74 memcpy (&connect_index, buf, sizeof connect_index);
75 connect_index = ntohl (connect_index);
77 omapi_array_foreach_begin (omapi_connections,
78 omapi_connection_object_t, lp) {
79 if (lp -> index == ntohl (connect_index)) {
80 omapi_connection_reference (&c, lp, MDL);
81 omapi_connection_dereference (&lp, MDL);
82 break;
84 } omapi_array_foreach_end (omapi_connections,
85 omapi_connection_object_t, lp);
87 if (!c) {
88 log_error ("trace connection input: no connection index %ld",
89 (long int)connect_index);
90 return;
93 s = buf + sizeof connect_index;
94 left = length - sizeof connect_index;
96 while (left) {
97 taken = 0;
98 status = omapi_connection_reader_trace ((omapi_object_t *)c,
99 left, s, &taken);
100 if (status != ISC_R_SUCCESS) {
101 log_error ("trace connection input: %s",
102 isc_result_totext (status));
103 break;
105 if (!taken) {
106 if (cc > 0) {
107 log_error ("trace connection_input: %s",
108 "input is not being consumed.");
109 break;
111 cc++;
112 } else {
113 cc = 0;
114 left -= taken;
117 omapi_connection_dereference (&c, MDL);
120 static void trace_connection_input_stop (trace_type_t *ttype) { }
122 static void trace_connection_output_input (trace_type_t *ttype,
123 unsigned length, char *buf)
125 /* We *could* check to see if the output is correct, but for now
126 we aren't going to do that. */
129 static void trace_connection_output_stop (trace_type_t *ttype) { }
131 #endif
133 /* Make sure that at least len bytes are in the input buffer, and if not,
134 read enough bytes to make up the difference. */
136 isc_result_t omapi_connection_reader (omapi_object_t *h)
138 #if defined (TRACING)
139 return omapi_connection_reader_trace (h, 0, (char *)0, (unsigned *)0);
142 static isc_result_t omapi_connection_reader_trace (omapi_object_t *h,
143 unsigned stuff_len,
144 char *stuff_buf,
145 unsigned *stuff_taken)
147 #endif
148 omapi_buffer_t *buffer;
149 isc_result_t status;
150 unsigned read_len;
151 int read_status;
152 omapi_connection_object_t *c;
153 unsigned bytes_to_read;
155 if (!h || h -> type != omapi_type_connection)
156 return DHCP_R_INVALIDARG;
157 c = (omapi_connection_object_t *)h;
159 /* See if there are enough bytes. */
160 if (c -> in_bytes >= OMAPI_BUF_SIZE - 1 &&
161 c -> in_bytes > c -> bytes_needed)
162 return ISC_R_SUCCESS;
165 if (c -> inbufs) {
166 for (buffer = c -> inbufs; buffer -> next;
167 buffer = buffer -> next)
169 if (!BUFFER_BYTES_FREE (buffer)) {
170 status = omapi_buffer_new (&buffer -> next, MDL);
171 if (status != ISC_R_SUCCESS)
172 return status;
173 buffer = buffer -> next;
175 } else {
176 status = omapi_buffer_new (&c -> inbufs, MDL);
177 if (status != ISC_R_SUCCESS)
178 return status;
179 buffer = c -> inbufs;
182 bytes_to_read = BUFFER_BYTES_FREE (buffer);
184 while (bytes_to_read) {
185 if (buffer -> tail > buffer -> head)
186 read_len = sizeof (buffer -> buf) - buffer -> tail;
187 else
188 read_len = buffer -> head - buffer -> tail;
190 #if defined (TRACING)
191 if (trace_playback()) {
192 if (stuff_len) {
193 if (read_len > stuff_len)
194 read_len = stuff_len;
195 if (stuff_taken)
196 *stuff_taken += read_len;
197 memcpy (&buffer -> buf [buffer -> tail],
198 stuff_buf, read_len);
199 stuff_len -= read_len;
200 stuff_buf += read_len;
201 read_status = read_len;
202 } else {
203 break;
205 } else
206 #endif
208 read_status = read (c -> socket,
209 &buffer -> buf [buffer -> tail],
210 read_len);
212 if (read_status < 0) {
213 if (errno == EWOULDBLOCK)
214 break;
215 else if (errno == EIO)
216 return ISC_R_IOERROR;
217 else if (errno == EINVAL)
218 return DHCP_R_INVALIDARG;
219 else if (errno == ECONNRESET) {
220 omapi_disconnect (h, 1);
221 return ISC_R_SHUTTINGDOWN;
222 } else
223 return ISC_R_UNEXPECTED;
226 /* If we got a zero-length read, as opposed to EWOULDBLOCK,
227 the remote end closed the connection. */
228 if (read_status == 0) {
229 omapi_disconnect (h, 0);
230 return ISC_R_SHUTTINGDOWN;
232 #if defined (TRACING)
233 if (trace_record ()) {
234 trace_iov_t iov [2];
235 int32_t connect_index;
237 connect_index = htonl (c -> index);
239 iov [0].buf = (char *)&connect_index;
240 iov [0].len = sizeof connect_index;
241 iov [1].buf = &buffer -> buf [buffer -> tail];
242 iov [1].len = read_status;
244 status = (trace_write_packet_iov
245 (trace_connection_input, 2, iov, MDL));
246 if (status != ISC_R_SUCCESS) {
247 trace_stop ();
248 log_error ("trace connection input: %s",
249 isc_result_totext (status));
252 #endif
253 buffer -> tail += read_status;
254 c -> in_bytes += read_status;
255 if (buffer -> tail == sizeof buffer -> buf)
256 buffer -> tail = 0;
257 if (read_status < read_len)
258 break;
259 bytes_to_read -= read_status;
262 if (c -> bytes_needed <= c -> in_bytes) {
263 omapi_signal (h, "ready", c);
265 return ISC_R_SUCCESS;
268 /* Put some bytes into the output buffer for a connection. */
270 isc_result_t omapi_connection_copyin (omapi_object_t *h,
271 const unsigned char *bufp,
272 unsigned len)
274 omapi_buffer_t *buffer;
275 isc_result_t status;
276 int bytes_copied = 0;
277 unsigned copy_len;
278 int sig_flags = SIG_MODE_UPDATE;
279 omapi_connection_object_t *c;
281 /* no need to verify len as it's unsigned */
282 if (!h || h -> type != omapi_type_connection)
283 return DHCP_R_INVALIDARG;
284 c = (omapi_connection_object_t *)h;
286 /* If the connection is closed, return an error if the caller
287 tries to copy in. */
288 if (c -> state == omapi_connection_disconnecting ||
289 c -> state == omapi_connection_closed)
290 return ISC_R_NOTCONNECTED;
292 if (c -> outbufs) {
293 for (buffer = c -> outbufs;
294 buffer -> next; buffer = buffer -> next)
296 } else {
297 status = omapi_buffer_new (&c -> outbufs, MDL);
298 if (status != ISC_R_SUCCESS)
299 goto leave;
300 buffer = c -> outbufs;
303 while (bytes_copied < len) {
304 /* If there is no space available in this buffer,
305 allocate a new one. */
306 if (!BUFFER_BYTES_FREE (buffer)) {
307 status = (omapi_buffer_new (&buffer -> next, MDL));
308 if (status != ISC_R_SUCCESS)
309 goto leave;
310 buffer = buffer -> next;
313 if (buffer -> tail > buffer -> head)
314 copy_len = sizeof (buffer -> buf) - buffer -> tail;
315 else
316 copy_len = buffer -> head - buffer -> tail;
318 if (copy_len > (len - bytes_copied))
319 copy_len = len - bytes_copied;
321 if (c -> out_key) {
322 if (!c -> out_context)
323 sig_flags |= SIG_MODE_INIT;
324 status = omapi_connection_sign_data
325 (sig_flags, c -> out_key, &c -> out_context,
326 &bufp [bytes_copied], copy_len,
327 (omapi_typed_data_t **)0);
328 if (status != ISC_R_SUCCESS)
329 goto leave;
332 memcpy (&buffer -> buf [buffer -> tail],
333 &bufp [bytes_copied], copy_len);
334 buffer -> tail += copy_len;
335 c -> out_bytes += copy_len;
336 bytes_copied += copy_len;
337 if (buffer -> tail == sizeof buffer -> buf)
338 buffer -> tail = 0;
341 status = ISC_R_SUCCESS;
343 leave:
345 * If we have any bytes to send and we have a proper io object
346 * inform the socket code that we would like to know when we
347 * can send more bytes.
349 if (c->out_bytes != 0) {
350 if ((c->outer != NULL) &&
351 (c->outer->type == omapi_type_io_object)) {
352 omapi_io_object_t *io = (omapi_io_object_t *)c->outer;
353 isc_socket_fdwatchpoke(io->fd,
354 ISC_SOCKFDWATCH_WRITE);
358 return (status);
361 /* Copy some bytes from the input buffer, and advance the input buffer
362 pointer beyond the bytes copied out. */
364 isc_result_t omapi_connection_copyout (unsigned char *buf,
365 omapi_object_t *h,
366 unsigned size)
368 unsigned bytes_remaining;
369 unsigned bytes_this_copy;
370 unsigned first_byte;
371 omapi_buffer_t *buffer;
372 unsigned char *bufp;
373 int sig_flags = SIG_MODE_UPDATE;
374 omapi_connection_object_t *c;
375 isc_result_t status;
377 if (!h || h -> type != omapi_type_connection)
378 return DHCP_R_INVALIDARG;
379 c = (omapi_connection_object_t *)h;
381 if (size > c -> in_bytes)
382 return ISC_R_NOMORE;
383 bufp = buf;
384 bytes_remaining = size;
385 buffer = c -> inbufs;
387 while (bytes_remaining) {
388 if (!buffer)
389 return ISC_R_UNEXPECTED;
390 if (BYTES_IN_BUFFER (buffer)) {
391 if (buffer -> head == (sizeof buffer -> buf) - 1)
392 first_byte = 0;
393 else
394 first_byte = buffer -> head + 1;
396 if (first_byte > buffer -> tail) {
397 bytes_this_copy = (sizeof buffer -> buf -
398 first_byte);
399 } else {
400 bytes_this_copy =
401 buffer -> tail - first_byte;
403 if (bytes_this_copy > bytes_remaining)
404 bytes_this_copy = bytes_remaining;
405 if (bufp) {
406 if (c -> in_key) {
407 if (!c -> in_context)
408 sig_flags |= SIG_MODE_INIT;
409 status = omapi_connection_sign_data
410 (sig_flags,
411 c -> in_key,
412 &c -> in_context,
413 (unsigned char *)
414 &buffer -> buf [first_byte],
415 bytes_this_copy,
416 (omapi_typed_data_t **)0);
417 if (status != ISC_R_SUCCESS)
418 return status;
421 memcpy (bufp, &buffer -> buf [first_byte],
422 bytes_this_copy);
423 bufp += bytes_this_copy;
425 bytes_remaining -= bytes_this_copy;
426 buffer -> head = first_byte + bytes_this_copy - 1;
427 c -> in_bytes -= bytes_this_copy;
430 if (!BYTES_IN_BUFFER (buffer))
431 buffer = buffer -> next;
434 /* Get rid of any input buffers that we emptied. */
435 buffer = (omapi_buffer_t *)0;
436 while (c -> inbufs &&
437 !BYTES_IN_BUFFER (c -> inbufs)) {
438 if (c -> inbufs -> next) {
439 omapi_buffer_reference (&buffer,
440 c -> inbufs -> next, MDL);
441 omapi_buffer_dereference (&c -> inbufs -> next, MDL);
443 omapi_buffer_dereference (&c -> inbufs, MDL);
444 if (buffer) {
445 omapi_buffer_reference
446 (&c -> inbufs, buffer, MDL);
447 omapi_buffer_dereference (&buffer, MDL);
450 return ISC_R_SUCCESS;
453 isc_result_t omapi_connection_writer (omapi_object_t *h)
455 unsigned bytes_this_write;
456 int bytes_written;
457 unsigned first_byte;
458 omapi_buffer_t *buffer;
459 omapi_connection_object_t *c;
461 if (!h || h -> type != omapi_type_connection)
462 return DHCP_R_INVALIDARG;
463 c = (omapi_connection_object_t *)h;
465 /* Already flushed... */
466 if (!c -> out_bytes)
467 return ISC_R_SUCCESS;
469 buffer = c -> outbufs;
471 while (c -> out_bytes) {
472 if (!buffer)
473 return ISC_R_UNEXPECTED;
474 if (BYTES_IN_BUFFER (buffer)) {
475 if (buffer -> head == (sizeof buffer -> buf) - 1)
476 first_byte = 0;
477 else
478 first_byte = buffer -> head + 1;
480 if (first_byte > buffer -> tail) {
481 bytes_this_write = (sizeof buffer -> buf -
482 first_byte);
483 } else {
484 bytes_this_write =
485 buffer -> tail - first_byte;
487 bytes_written = write (c -> socket,
488 &buffer -> buf [first_byte],
489 bytes_this_write);
490 /* If the write failed with EWOULDBLOCK or we wrote
491 zero bytes, a further write would block, so we have
492 flushed as much as we can for now. Other errors
493 are really errors. */
494 if (bytes_written < 0) {
495 if (errno == EWOULDBLOCK || errno == EAGAIN)
496 return ISC_R_INPROGRESS;
497 else if (errno == EPIPE)
498 return ISC_R_NOCONN;
499 #ifdef EDQUOT
500 else if (errno == EFBIG || errno == EDQUOT)
501 #else
502 else if (errno == EFBIG)
503 #endif
504 return ISC_R_NORESOURCES;
505 else if (errno == ENOSPC)
506 return ISC_R_NOSPACE;
507 else if (errno == EIO)
508 return ISC_R_IOERROR;
509 else if (errno == EINVAL)
510 return DHCP_R_INVALIDARG;
511 else if (errno == ECONNRESET)
512 return ISC_R_SHUTTINGDOWN;
513 else
514 return ISC_R_UNEXPECTED;
516 if (bytes_written == 0)
517 return ISC_R_INPROGRESS;
519 #if defined (TRACING)
520 if (trace_record ()) {
521 isc_result_t status;
522 trace_iov_t iov [2];
523 int32_t connect_index;
525 connect_index = htonl (c -> index);
527 iov [0].buf = (char *)&connect_index;
528 iov [0].len = sizeof connect_index;
529 iov [1].buf = &buffer -> buf [buffer -> tail];
530 iov [1].len = bytes_written;
532 status = (trace_write_packet_iov
533 (trace_connection_input, 2, iov,
534 MDL));
535 if (status != ISC_R_SUCCESS) {
536 trace_stop ();
537 log_error ("trace %s output: %s",
538 "connection",
539 isc_result_totext (status));
542 #endif
544 buffer -> head = first_byte + bytes_written - 1;
545 c -> out_bytes -= bytes_written;
547 /* If we didn't finish out the write, we filled the
548 O.S. output buffer and a further write would block,
549 so stop trying to flush now. */
550 if (bytes_written != bytes_this_write)
551 return ISC_R_INPROGRESS;
554 if (!BYTES_IN_BUFFER (buffer))
555 buffer = buffer -> next;
558 /* Get rid of any output buffers we emptied. */
559 buffer = (omapi_buffer_t *)0;
560 while (c -> outbufs &&
561 !BYTES_IN_BUFFER (c -> outbufs)) {
562 if (c -> outbufs -> next) {
563 omapi_buffer_reference (&buffer,
564 c -> outbufs -> next, MDL);
565 omapi_buffer_dereference (&c -> outbufs -> next, MDL);
567 omapi_buffer_dereference (&c -> outbufs, MDL);
568 if (buffer) {
569 omapi_buffer_reference (&c -> outbufs, buffer, MDL);
570 omapi_buffer_dereference (&buffer, MDL);
573 return ISC_R_SUCCESS;
576 isc_result_t omapi_connection_get_uint32 (omapi_object_t *c,
577 u_int32_t *result)
579 u_int32_t inbuf;
580 isc_result_t status;
582 status = omapi_connection_copyout ((unsigned char *)&inbuf,
583 c, sizeof inbuf);
584 if (status != ISC_R_SUCCESS)
585 return status;
587 *result = ntohl (inbuf);
588 return ISC_R_SUCCESS;
591 isc_result_t omapi_connection_put_uint32 (omapi_object_t *c,
592 u_int32_t value)
594 u_int32_t inbuf;
596 inbuf = htonl (value);
598 return omapi_connection_copyin (c, (unsigned char *)&inbuf,
599 sizeof inbuf);
602 isc_result_t omapi_connection_get_uint16 (omapi_object_t *c,
603 u_int16_t *result)
605 u_int16_t inbuf;
606 isc_result_t status;
608 status = omapi_connection_copyout ((unsigned char *)&inbuf,
609 c, sizeof inbuf);
610 if (status != ISC_R_SUCCESS)
611 return status;
613 *result = ntohs (inbuf);
614 return ISC_R_SUCCESS;
617 isc_result_t omapi_connection_put_uint16 (omapi_object_t *c,
618 u_int32_t value)
620 u_int16_t inbuf;
622 inbuf = htons (value);
624 return omapi_connection_copyin (c, (unsigned char *)&inbuf,
625 sizeof inbuf);
628 isc_result_t omapi_connection_write_typed_data (omapi_object_t *c,
629 omapi_typed_data_t *data)
631 isc_result_t status;
632 omapi_handle_t handle;
634 /* Null data is valid. */
635 if (!data)
636 return omapi_connection_put_uint32 (c, 0);
638 switch (data -> type) {
639 case omapi_datatype_int:
640 status = omapi_connection_put_uint32 (c, sizeof (u_int32_t));
641 if (status != ISC_R_SUCCESS)
642 return status;
643 return omapi_connection_put_uint32 (c, ((u_int32_t)
644 (data -> u.integer)));
646 case omapi_datatype_string:
647 case omapi_datatype_data:
648 status = omapi_connection_put_uint32 (c, data -> u.buffer.len);
649 if (status != ISC_R_SUCCESS)
650 return status;
651 if (data -> u.buffer.len)
652 return omapi_connection_copyin
653 (c, data -> u.buffer.value,
654 data -> u.buffer.len);
655 return ISC_R_SUCCESS;
657 case omapi_datatype_object:
658 if (data -> u.object) {
659 status = omapi_object_handle (&handle,
660 data -> u.object);
661 if (status != ISC_R_SUCCESS)
662 return status;
663 } else
664 handle = 0;
665 status = omapi_connection_put_uint32 (c, sizeof handle);
666 if (status != ISC_R_SUCCESS)
667 return status;
668 return omapi_connection_put_uint32 (c, handle);
671 return DHCP_R_INVALIDARG;
674 isc_result_t omapi_connection_put_name (omapi_object_t *c, const char *name)
676 isc_result_t status;
677 unsigned len = strlen (name);
679 status = omapi_connection_put_uint16 (c, len);
680 if (status != ISC_R_SUCCESS)
681 return status;
682 return omapi_connection_copyin (c, (const unsigned char *)name, len);
685 isc_result_t omapi_connection_put_string (omapi_object_t *c,
686 const char *string)
688 isc_result_t status;
689 unsigned len;
691 if (string)
692 len = strlen (string);
693 else
694 len = 0;
696 status = omapi_connection_put_uint32 (c, len);
697 if (status != ISC_R_SUCCESS)
698 return status;
699 if (len)
700 return omapi_connection_copyin
701 (c, (const unsigned char *)string, len);
702 return ISC_R_SUCCESS;
705 isc_result_t omapi_connection_put_handle (omapi_object_t *c, omapi_object_t *h)
707 isc_result_t status;
708 omapi_handle_t handle;
710 if (h) {
711 status = omapi_object_handle (&handle, h);
712 if (status != ISC_R_SUCCESS)
713 return status;
714 } else
715 handle = 0; /* The null handle. */
716 status = omapi_connection_put_uint32 (c, sizeof handle);
717 if (status != ISC_R_SUCCESS)
718 return status;
719 return omapi_connection_put_uint32 (c, handle);
722 isc_result_t omapi_connection_put_named_uint32 (omapi_object_t *c,
723 const char *name,
724 u_int32_t value)
726 isc_result_t status;
728 status = omapi_connection_put_name(c, name);
729 if (status != ISC_R_SUCCESS)
730 return (status);
732 status = omapi_connection_put_uint32(c, sizeof(u_int32_t));
733 if (status != ISC_R_SUCCESS)
734 return (status);
736 status = omapi_connection_put_uint32(c, value);
737 return (status);