Home | History | Annotate | Line # | Download | only in omapip
      1  1.4  christos /*	$NetBSD: buffer.c,v 1.5 2022/04/03 01:10:59 christos Exp $	*/
      2  1.1  christos 
      3  1.1  christos /* buffer.c
      4  1.1  christos 
      5  1.1  christos    Buffer access functions for the object management protocol... */
      6  1.1  christos 
      7  1.1  christos /*
      8  1.5  christos  * Copyright (C) 2004-2022 Internet Systems Consortium, Inc. ("ISC")
      9  1.1  christos  * Copyright (c) 1999-2003 by Internet Software Consortium
     10  1.1  christos  *
     11  1.1  christos  * This Source Code Form is subject to the terms of the Mozilla Public
     12  1.1  christos  * License, v. 2.0. If a copy of the MPL was not distributed with this
     13  1.1  christos  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
     14  1.1  christos  *
     15  1.1  christos  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
     16  1.1  christos  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     17  1.1  christos  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
     18  1.1  christos  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     19  1.1  christos  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     20  1.1  christos  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
     21  1.1  christos  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     22  1.1  christos  *
     23  1.1  christos  *   Internet Systems Consortium, Inc.
     24  1.5  christos  *   PO Box 360
     25  1.5  christos  *   Newmarket, NH 03857 USA
     26  1.1  christos  *   <info (at) isc.org>
     27  1.1  christos  *   https://www.isc.org/
     28  1.1  christos  *
     29  1.1  christos  */
     30  1.1  christos 
     31  1.1  christos #include <sys/cdefs.h>
     32  1.4  christos __RCSID("$NetBSD: buffer.c,v 1.5 2022/04/03 01:10:59 christos Exp $");
     33  1.1  christos 
     34  1.1  christos #include "dhcpd.h"
     35  1.1  christos 
     36  1.1  christos #include <omapip/omapip_p.h>
     37  1.1  christos #include <errno.h>
     38  1.1  christos 
     39  1.1  christos #if defined (TRACING)
     40  1.1  christos static void trace_connection_input_input (trace_type_t *, unsigned, char *);
     41  1.1  christos static void trace_connection_input_stop (trace_type_t *);
     42  1.1  christos static void trace_connection_output_input (trace_type_t *, unsigned, char *);
     43  1.1  christos static void trace_connection_output_stop (trace_type_t *);
     44  1.1  christos static trace_type_t *trace_connection_input;
     45  1.1  christos static trace_type_t *trace_connection_output;
     46  1.1  christos static isc_result_t omapi_connection_reader_trace (omapi_object_t *,
     47  1.1  christos 						   unsigned, char *,
     48  1.1  christos 						   unsigned *);
     49  1.1  christos extern omapi_array_t *omapi_connections;
     50  1.1  christos 
     51  1.1  christos void omapi_buffer_trace_setup ()
     52  1.1  christos {
     53  1.1  christos 	trace_connection_input =
     54  1.1  christos 		trace_type_register ("connection-input",
     55  1.1  christos 				     (void *)0,
     56  1.1  christos 				     trace_connection_input_input,
     57  1.1  christos 				     trace_connection_input_stop, MDL);
     58  1.1  christos 	trace_connection_output =
     59  1.1  christos 		trace_type_register ("connection-output",
     60  1.1  christos 				     (void *)0,
     61  1.1  christos 				     trace_connection_output_input,
     62  1.1  christos 				     trace_connection_output_stop, MDL);
     63  1.1  christos }
     64  1.1  christos 
     65  1.1  christos static void trace_connection_input_input (trace_type_t *ttype,
     66  1.1  christos 					  unsigned length, char *buf)
     67  1.1  christos {
     68  1.1  christos 	unsigned left, taken, cc = 0;
     69  1.1  christos 	char *s;
     70  1.1  christos 	int32_t connect_index;
     71  1.1  christos 	isc_result_t status;
     72  1.1  christos 	omapi_connection_object_t *c = (omapi_connection_object_t *)0;
     73  1.1  christos 
     74  1.1  christos 	memcpy (&connect_index, buf, sizeof connect_index);
     75  1.1  christos 	connect_index = ntohl (connect_index);
     76  1.1  christos 
     77  1.1  christos 	omapi_array_foreach_begin (omapi_connections,
     78  1.1  christos 				   omapi_connection_object_t, lp) {
     79  1.1  christos 		if (lp -> index == ntohl (connect_index)) {
     80  1.1  christos 			omapi_connection_reference (&c, lp, MDL);
     81  1.1  christos 			omapi_connection_dereference (&lp, MDL);
     82  1.1  christos 			break;
     83  1.1  christos 		}
     84  1.1  christos 	} omapi_array_foreach_end (omapi_connections,
     85  1.1  christos 				   omapi_connection_object_t, lp);
     86  1.1  christos 
     87  1.1  christos 	if (!c) {
     88  1.1  christos 		log_error ("trace connection input: no connection index %ld",
     89  1.1  christos 			   (long int)connect_index);
     90  1.1  christos 		return;
     91  1.1  christos 	}
     92  1.1  christos 
     93  1.1  christos 	s = buf + sizeof connect_index;
     94  1.1  christos 	left = length - sizeof connect_index;
     95  1.1  christos 
     96  1.1  christos 	while (left) {
     97  1.1  christos 		taken = 0;
     98  1.1  christos 		status = omapi_connection_reader_trace ((omapi_object_t *)c,
     99  1.1  christos 							left, s, &taken);
    100  1.1  christos 		if (status != ISC_R_SUCCESS) {
    101  1.1  christos 			log_error ("trace connection input: %s",
    102  1.1  christos 				   isc_result_totext (status));
    103  1.1  christos 			break;
    104  1.1  christos 		}
    105  1.1  christos 		if (!taken) {
    106  1.1  christos 			if (cc > 0) {
    107  1.1  christos 				log_error ("trace connection_input: %s",
    108  1.1  christos 					   "input is not being consumed.");
    109  1.1  christos 				break;
    110  1.1  christos 			}
    111  1.1  christos 			cc++;
    112  1.1  christos 		} else {
    113  1.1  christos 			cc = 0;
    114  1.1  christos 			left -= taken;
    115  1.1  christos 		}
    116  1.1  christos 	}
    117  1.1  christos 	omapi_connection_dereference (&c, MDL);
    118  1.1  christos }
    119  1.1  christos 
    120  1.1  christos static void trace_connection_input_stop (trace_type_t *ttype) { }
    121  1.1  christos 
    122  1.1  christos static void trace_connection_output_input (trace_type_t *ttype,
    123  1.1  christos 					  unsigned length, char *buf)
    124  1.1  christos {
    125  1.1  christos 	/* We *could* check to see if the output is correct, but for now
    126  1.1  christos 	   we aren't going to do that. */
    127  1.1  christos }
    128  1.1  christos 
    129  1.1  christos static void trace_connection_output_stop (trace_type_t *ttype) { }
    130  1.1  christos 
    131  1.1  christos #endif
    132  1.1  christos 
    133  1.1  christos /* Make sure that at least len bytes are in the input buffer, and if not,
    134  1.1  christos    read enough bytes to make up the difference. */
    135  1.1  christos 
    136  1.1  christos isc_result_t omapi_connection_reader (omapi_object_t *h)
    137  1.1  christos {
    138  1.1  christos #if defined (TRACING)
    139  1.1  christos 	return omapi_connection_reader_trace (h, 0, (char *)0, (unsigned *)0);
    140  1.1  christos }
    141  1.1  christos 
    142  1.1  christos static isc_result_t omapi_connection_reader_trace (omapi_object_t *h,
    143  1.1  christos 						   unsigned stuff_len,
    144  1.1  christos 						   char *stuff_buf,
    145  1.1  christos 						   unsigned *stuff_taken)
    146  1.1  christos {
    147  1.1  christos #endif
    148  1.1  christos 	omapi_buffer_t *buffer;
    149  1.1  christos 	isc_result_t status;
    150  1.1  christos 	unsigned read_len;
    151  1.1  christos 	int read_status;
    152  1.1  christos 	omapi_connection_object_t *c;
    153  1.1  christos 	unsigned bytes_to_read;
    154  1.5  christos 
    155  1.1  christos 	if (!h || h -> type != omapi_type_connection)
    156  1.1  christos 		return DHCP_R_INVALIDARG;
    157  1.1  christos 	c = (omapi_connection_object_t *)h;
    158  1.1  christos 
    159  1.1  christos 	/* See if there are enough bytes. */
    160  1.1  christos 	if (c -> in_bytes >= OMAPI_BUF_SIZE - 1 &&
    161  1.1  christos 	    c -> in_bytes > c -> bytes_needed)
    162  1.1  christos 		return ISC_R_SUCCESS;
    163  1.1  christos 
    164  1.1  christos 
    165  1.1  christos 	if (c -> inbufs) {
    166  1.1  christos 		for (buffer = c -> inbufs; buffer -> next;
    167  1.1  christos 		     buffer = buffer -> next)
    168  1.1  christos 			;
    169  1.1  christos 		if (!BUFFER_BYTES_FREE (buffer)) {
    170  1.1  christos 			status = omapi_buffer_new (&buffer -> next, MDL);
    171  1.1  christos 			if (status != ISC_R_SUCCESS)
    172  1.1  christos 				return status;
    173  1.1  christos 			buffer = buffer -> next;
    174  1.1  christos 		}
    175  1.1  christos 	} else {
    176  1.1  christos 		status = omapi_buffer_new (&c -> inbufs, MDL);
    177  1.1  christos 		if (status != ISC_R_SUCCESS)
    178  1.1  christos 			return status;
    179  1.1  christos 		buffer = c -> inbufs;
    180  1.1  christos 	}
    181  1.1  christos 
    182  1.1  christos 	bytes_to_read = BUFFER_BYTES_FREE (buffer);
    183  1.1  christos 
    184  1.1  christos 	while (bytes_to_read) {
    185  1.1  christos 		if (buffer -> tail > buffer -> head)
    186  1.1  christos 			read_len = sizeof (buffer -> buf) - buffer -> tail;
    187  1.1  christos 		else
    188  1.1  christos 			read_len = buffer -> head - buffer -> tail;
    189  1.1  christos 
    190  1.1  christos #if defined (TRACING)
    191  1.1  christos 		if (trace_playback()) {
    192  1.1  christos 			if (stuff_len) {
    193  1.1  christos 				if (read_len > stuff_len)
    194  1.1  christos 					read_len = stuff_len;
    195  1.1  christos 				if (stuff_taken)
    196  1.1  christos 					*stuff_taken += read_len;
    197  1.1  christos 				memcpy (&buffer -> buf [buffer -> tail],
    198  1.1  christos 					stuff_buf, read_len);
    199  1.1  christos 				stuff_len -= read_len;
    200  1.1  christos 				stuff_buf += read_len;
    201  1.1  christos 				read_status = read_len;
    202  1.1  christos 			} else {
    203  1.1  christos 				break;
    204  1.1  christos 			}
    205  1.1  christos 		} else
    206  1.1  christos #endif
    207  1.1  christos 		{
    208  1.1  christos 			read_status = read (c -> socket,
    209  1.1  christos 					    &buffer -> buf [buffer -> tail],
    210  1.1  christos 					    read_len);
    211  1.1  christos 		}
    212  1.1  christos 		if (read_status < 0) {
    213  1.1  christos 			if (errno == EWOULDBLOCK)
    214  1.1  christos 				break;
    215  1.1  christos 			else if (errno == EIO)
    216  1.1  christos 				return ISC_R_IOERROR;
    217  1.1  christos 			else if (errno == EINVAL)
    218  1.1  christos 				return DHCP_R_INVALIDARG;
    219  1.1  christos 			else if (errno == ECONNRESET) {
    220  1.1  christos 				omapi_disconnect (h, 1);
    221  1.1  christos 				return ISC_R_SHUTTINGDOWN;
    222  1.1  christos 			} else
    223  1.1  christos 				return ISC_R_UNEXPECTED;
    224  1.1  christos 		}
    225  1.1  christos 
    226  1.1  christos 		/* If we got a zero-length read, as opposed to EWOULDBLOCK,
    227  1.1  christos 		   the remote end closed the connection. */
    228  1.1  christos 		if (read_status == 0) {
    229  1.1  christos 			omapi_disconnect (h, 0);
    230  1.1  christos 			return ISC_R_SHUTTINGDOWN;
    231  1.1  christos 		}
    232  1.1  christos #if defined (TRACING)
    233  1.1  christos 		if (trace_record ()) {
    234  1.1  christos 			trace_iov_t iov [2];
    235  1.1  christos 			int32_t connect_index;
    236  1.1  christos 
    237  1.1  christos 			connect_index = htonl (c -> index);
    238  1.1  christos 
    239  1.1  christos 			iov [0].buf = (char *)&connect_index;
    240  1.1  christos 			iov [0].len = sizeof connect_index;
    241  1.1  christos 			iov [1].buf = &buffer -> buf [buffer -> tail];
    242  1.1  christos 			iov [1].len = read_status;
    243  1.1  christos 
    244  1.1  christos 			status = (trace_write_packet_iov
    245  1.1  christos 				  (trace_connection_input, 2, iov, MDL));
    246  1.1  christos 			if (status != ISC_R_SUCCESS) {
    247  1.1  christos 				trace_stop ();
    248  1.1  christos 				log_error ("trace connection input: %s",
    249  1.1  christos 					   isc_result_totext (status));
    250  1.1  christos 			}
    251  1.1  christos 		}
    252  1.1  christos #endif
    253  1.1  christos 		buffer -> tail += read_status;
    254  1.1  christos 		c -> in_bytes += read_status;
    255  1.1  christos 		if (buffer -> tail == sizeof buffer -> buf)
    256  1.1  christos 			buffer -> tail = 0;
    257  1.1  christos 		if (read_status < read_len)
    258  1.1  christos 			break;
    259  1.1  christos 		bytes_to_read -= read_status;
    260  1.1  christos 	}
    261  1.1  christos 
    262  1.1  christos 	if (c -> bytes_needed <= c -> in_bytes) {
    263  1.1  christos 		omapi_signal (h, "ready", c);
    264  1.1  christos 	}
    265  1.1  christos 	return ISC_R_SUCCESS;
    266  1.1  christos }
    267  1.1  christos 
    268  1.1  christos /* Put some bytes into the output buffer for a connection. */
    269  1.1  christos 
    270  1.1  christos isc_result_t omapi_connection_copyin (omapi_object_t *h,
    271  1.1  christos 				      const unsigned char *bufp,
    272  1.1  christos 				      unsigned len)
    273  1.1  christos {
    274  1.1  christos 	omapi_buffer_t *buffer;
    275  1.1  christos 	isc_result_t status;
    276  1.1  christos 	int bytes_copied = 0;
    277  1.1  christos 	unsigned copy_len;
    278  1.1  christos 	int sig_flags = SIG_MODE_UPDATE;
    279  1.1  christos 	omapi_connection_object_t *c;
    280  1.1  christos 
    281  1.1  christos 	/* no need to verify len as it's unsigned */
    282  1.1  christos 	if (!h || h -> type != omapi_type_connection)
    283  1.1  christos 		return DHCP_R_INVALIDARG;
    284  1.1  christos 	c = (omapi_connection_object_t *)h;
    285  1.1  christos 
    286  1.1  christos 	/* If the connection is closed, return an error if the caller
    287  1.1  christos 	   tries to copy in. */
    288  1.1  christos 	if (c -> state == omapi_connection_disconnecting ||
    289  1.1  christos 	    c -> state == omapi_connection_closed)
    290  1.1  christos 		return ISC_R_NOTCONNECTED;
    291  1.1  christos 
    292  1.1  christos 	if (c -> outbufs) {
    293  1.1  christos 		for (buffer = c -> outbufs;
    294  1.1  christos 		     buffer -> next; buffer = buffer -> next)
    295  1.1  christos 			;
    296  1.1  christos 	} else {
    297  1.1  christos 		status = omapi_buffer_new (&c -> outbufs, MDL);
    298  1.1  christos 		if (status != ISC_R_SUCCESS)
    299  1.1  christos 			goto leave;
    300  1.1  christos 		buffer = c -> outbufs;
    301  1.1  christos 	}
    302  1.1  christos 
    303  1.1  christos 	while (bytes_copied < len) {
    304  1.1  christos 		/* If there is no space available in this buffer,
    305  1.1  christos                    allocate a new one. */
    306  1.1  christos 		if (!BUFFER_BYTES_FREE (buffer)) {
    307  1.1  christos 			status = (omapi_buffer_new (&buffer -> next, MDL));
    308  1.1  christos 			if (status != ISC_R_SUCCESS)
    309  1.1  christos 				goto leave;
    310  1.1  christos 			buffer = buffer -> next;
    311  1.1  christos 		}
    312  1.1  christos 
    313  1.1  christos 		if (buffer -> tail > buffer -> head)
    314  1.1  christos 			copy_len = sizeof (buffer -> buf) - buffer -> tail;
    315  1.1  christos 		else
    316  1.1  christos 			copy_len = buffer -> head - buffer -> tail;
    317  1.1  christos 
    318  1.1  christos 		if (copy_len > (len - bytes_copied))
    319  1.1  christos 			copy_len = len - bytes_copied;
    320  1.1  christos 
    321  1.1  christos 		if (c -> out_key) {
    322  1.1  christos 			if (!c -> out_context)
    323  1.1  christos 				sig_flags |= SIG_MODE_INIT;
    324  1.1  christos 			status = omapi_connection_sign_data
    325  1.1  christos 				(sig_flags, c -> out_key, &c -> out_context,
    326  1.1  christos 				 &bufp [bytes_copied], copy_len,
    327  1.1  christos 				 (omapi_typed_data_t **)0);
    328  1.1  christos 			if (status != ISC_R_SUCCESS)
    329  1.1  christos 				goto leave;
    330  1.1  christos 		}
    331  1.1  christos 
    332  1.1  christos 		memcpy (&buffer -> buf [buffer -> tail],
    333  1.1  christos 			&bufp [bytes_copied], copy_len);
    334  1.1  christos 		buffer -> tail += copy_len;
    335  1.1  christos 		c -> out_bytes += copy_len;
    336  1.1  christos 		bytes_copied += copy_len;
    337  1.1  christos 		if (buffer -> tail == sizeof buffer -> buf)
    338  1.1  christos 			buffer -> tail = 0;
    339  1.1  christos 	}
    340  1.1  christos 
    341  1.1  christos 	status = ISC_R_SUCCESS;
    342  1.1  christos 
    343  1.1  christos  leave:
    344  1.1  christos 	/*
    345  1.1  christos 	 * If we have any bytes to send and we have a proper io object
    346  1.1  christos 	 * inform the socket code that we would like to know when we
    347  1.1  christos 	 * can send more bytes.
    348  1.1  christos 	 */
    349  1.1  christos 	if (c->out_bytes != 0) {
    350  1.1  christos 		if ((c->outer != NULL) &&
    351  1.1  christos 		    (c->outer->type == omapi_type_io_object)) {
    352  1.1  christos 			omapi_io_object_t *io = (omapi_io_object_t *)c->outer;
    353  1.1  christos 			isc_socket_fdwatchpoke(io->fd,
    354  1.1  christos 					       ISC_SOCKFDWATCH_WRITE);
    355  1.1  christos 		}
    356  1.1  christos 	}
    357  1.1  christos 
    358  1.1  christos 	return (status);
    359  1.1  christos }
    360  1.1  christos 
    361  1.1  christos /* Copy some bytes from the input buffer, and advance the input buffer
    362  1.1  christos    pointer beyond the bytes copied out. */
    363  1.1  christos 
    364  1.1  christos isc_result_t omapi_connection_copyout (unsigned char *buf,
    365  1.1  christos 				       omapi_object_t *h,
    366  1.1  christos 				       unsigned size)
    367  1.1  christos {
    368  1.1  christos 	unsigned bytes_remaining;
    369  1.1  christos 	unsigned bytes_this_copy;
    370  1.1  christos 	unsigned first_byte;
    371  1.1  christos 	omapi_buffer_t *buffer;
    372  1.1  christos 	unsigned char *bufp;
    373  1.1  christos 	int sig_flags = SIG_MODE_UPDATE;
    374  1.1  christos 	omapi_connection_object_t *c;
    375  1.1  christos 	isc_result_t status;
    376  1.1  christos 
    377  1.1  christos 	if (!h || h -> type != omapi_type_connection)
    378  1.1  christos 		return DHCP_R_INVALIDARG;
    379  1.1  christos 	c = (omapi_connection_object_t *)h;
    380  1.1  christos 
    381  1.1  christos 	if (size > c -> in_bytes)
    382  1.1  christos 		return ISC_R_NOMORE;
    383  1.1  christos 	bufp = buf;
    384  1.1  christos 	bytes_remaining = size;
    385  1.1  christos 	buffer = c -> inbufs;
    386  1.1  christos 
    387  1.1  christos 	while (bytes_remaining) {
    388  1.1  christos 		if (!buffer)
    389  1.1  christos 			return ISC_R_UNEXPECTED;
    390  1.1  christos 		if (BYTES_IN_BUFFER (buffer)) {
    391  1.1  christos 			if (buffer -> head == (sizeof buffer -> buf) - 1)
    392  1.1  christos 				first_byte = 0;
    393  1.1  christos 			else
    394  1.1  christos 				first_byte = buffer -> head + 1;
    395  1.1  christos 
    396  1.1  christos 			if (first_byte > buffer -> tail) {
    397  1.1  christos 				bytes_this_copy = (sizeof buffer -> buf -
    398  1.1  christos 						   first_byte);
    399  1.1  christos 			} else {
    400  1.1  christos 				bytes_this_copy =
    401  1.1  christos 					buffer -> tail - first_byte;
    402  1.1  christos 			}
    403  1.1  christos 			if (bytes_this_copy > bytes_remaining)
    404  1.1  christos 				bytes_this_copy = bytes_remaining;
    405  1.1  christos 			if (bufp) {
    406  1.1  christos 				if (c -> in_key) {
    407  1.1  christos 					if (!c -> in_context)
    408  1.1  christos 						sig_flags |= SIG_MODE_INIT;
    409  1.1  christos 					status = omapi_connection_sign_data
    410  1.1  christos 						(sig_flags,
    411  1.1  christos 						 c -> in_key,
    412  1.1  christos 						 &c -> in_context,
    413  1.1  christos 						 (unsigned char *)
    414  1.1  christos 						 &buffer -> buf [first_byte],
    415  1.1  christos 						 bytes_this_copy,
    416  1.1  christos 						 (omapi_typed_data_t **)0);
    417  1.1  christos 					if (status != ISC_R_SUCCESS)
    418  1.1  christos 						return status;
    419  1.1  christos 				}
    420  1.1  christos 
    421  1.1  christos 				memcpy (bufp, &buffer -> buf [first_byte],
    422  1.1  christos 					bytes_this_copy);
    423  1.1  christos 				bufp += bytes_this_copy;
    424  1.1  christos 			}
    425  1.1  christos 			bytes_remaining -= bytes_this_copy;
    426  1.1  christos 			buffer -> head = first_byte + bytes_this_copy - 1;
    427  1.1  christos 			c -> in_bytes -= bytes_this_copy;
    428  1.1  christos 		}
    429  1.5  christos 
    430  1.1  christos 		if (!BYTES_IN_BUFFER (buffer))
    431  1.1  christos 			buffer = buffer -> next;
    432  1.1  christos 	}
    433  1.1  christos 
    434  1.1  christos 	/* Get rid of any input buffers that we emptied. */
    435  1.1  christos 	buffer = (omapi_buffer_t *)0;
    436  1.1  christos 	while (c -> inbufs &&
    437  1.1  christos 	       !BYTES_IN_BUFFER (c -> inbufs)) {
    438  1.1  christos 		if (c -> inbufs -> next) {
    439  1.1  christos 			omapi_buffer_reference (&buffer,
    440  1.1  christos 						c -> inbufs -> next, MDL);
    441  1.1  christos 			omapi_buffer_dereference (&c -> inbufs -> next, MDL);
    442  1.1  christos 		}
    443  1.1  christos 		omapi_buffer_dereference (&c -> inbufs, MDL);
    444  1.1  christos 		if (buffer) {
    445  1.1  christos 			omapi_buffer_reference
    446  1.1  christos 				(&c -> inbufs, buffer, MDL);
    447  1.1  christos 			omapi_buffer_dereference (&buffer, MDL);
    448  1.1  christos 		}
    449  1.1  christos 	}
    450  1.1  christos 	return ISC_R_SUCCESS;
    451  1.1  christos }
    452  1.1  christos 
    453  1.1  christos isc_result_t omapi_connection_writer (omapi_object_t *h)
    454  1.1  christos {
    455  1.1  christos 	unsigned bytes_this_write;
    456  1.1  christos 	int bytes_written;
    457  1.1  christos 	unsigned first_byte;
    458  1.1  christos 	omapi_buffer_t *buffer;
    459  1.1  christos 	omapi_connection_object_t *c;
    460  1.1  christos 
    461  1.1  christos 	if (!h || h -> type != omapi_type_connection)
    462  1.1  christos 		return DHCP_R_INVALIDARG;
    463  1.1  christos 	c = (omapi_connection_object_t *)h;
    464  1.1  christos 
    465  1.1  christos 	/* Already flushed... */
    466  1.1  christos 	if (!c -> out_bytes)
    467  1.1  christos 		return ISC_R_SUCCESS;
    468  1.1  christos 
    469  1.1  christos 	buffer = c -> outbufs;
    470  1.1  christos 
    471  1.1  christos 	while (c -> out_bytes) {
    472  1.1  christos 		if (!buffer)
    473  1.1  christos 			return ISC_R_UNEXPECTED;
    474  1.1  christos 		if (BYTES_IN_BUFFER (buffer)) {
    475  1.1  christos 			if (buffer -> head == (sizeof buffer -> buf) - 1)
    476  1.1  christos 				first_byte = 0;
    477  1.1  christos 			else
    478  1.1  christos 				first_byte = buffer -> head + 1;
    479  1.1  christos 
    480  1.1  christos 			if (first_byte > buffer -> tail) {
    481  1.1  christos 				bytes_this_write = (sizeof buffer -> buf -
    482  1.1  christos 						   first_byte);
    483  1.1  christos 			} else {
    484  1.1  christos 				bytes_this_write =
    485  1.1  christos 					buffer -> tail - first_byte;
    486  1.1  christos 			}
    487  1.1  christos 			bytes_written = write (c -> socket,
    488  1.1  christos 					       &buffer -> buf [first_byte],
    489  1.1  christos 					       bytes_this_write);
    490  1.1  christos 			/* If the write failed with EWOULDBLOCK or we wrote
    491  1.1  christos 			   zero bytes, a further write would block, so we have
    492  1.1  christos 			   flushed as much as we can for now.   Other errors
    493  1.1  christos 			   are really errors. */
    494  1.1  christos 			if (bytes_written < 0) {
    495  1.1  christos 				if (errno == EWOULDBLOCK || errno == EAGAIN)
    496  1.1  christos 					return ISC_R_INPROGRESS;
    497  1.1  christos 				else if (errno == EPIPE)
    498  1.1  christos 					return ISC_R_NOCONN;
    499  1.1  christos #ifdef EDQUOT
    500  1.1  christos 				else if (errno == EFBIG || errno == EDQUOT)
    501  1.1  christos #else
    502  1.1  christos 				else if (errno == EFBIG)
    503  1.1  christos #endif
    504  1.1  christos 					return ISC_R_NORESOURCES;
    505  1.1  christos 				else if (errno == ENOSPC)
    506  1.1  christos 					return ISC_R_NOSPACE;
    507  1.1  christos 				else if (errno == EIO)
    508  1.1  christos 					return ISC_R_IOERROR;
    509  1.1  christos 				else if (errno == EINVAL)
    510  1.1  christos 					return DHCP_R_INVALIDARG;
    511  1.1  christos 				else if (errno == ECONNRESET)
    512  1.1  christos 					return ISC_R_SHUTTINGDOWN;
    513  1.1  christos 				else
    514  1.1  christos 					return ISC_R_UNEXPECTED;
    515  1.1  christos 			}
    516  1.1  christos 			if (bytes_written == 0)
    517  1.1  christos 				return ISC_R_INPROGRESS;
    518  1.1  christos 
    519  1.1  christos #if defined (TRACING)
    520  1.1  christos 			if (trace_record ()) {
    521  1.1  christos 				isc_result_t status;
    522  1.1  christos 				trace_iov_t iov [2];
    523  1.1  christos 				int32_t connect_index;
    524  1.5  christos 
    525  1.1  christos 				connect_index = htonl (c -> index);
    526  1.5  christos 
    527  1.1  christos 				iov [0].buf = (char *)&connect_index;
    528  1.1  christos 				iov [0].len = sizeof connect_index;
    529  1.1  christos 				iov [1].buf = &buffer -> buf [buffer -> tail];
    530  1.1  christos 				iov [1].len = bytes_written;
    531  1.5  christos 
    532  1.1  christos 				status = (trace_write_packet_iov
    533  1.1  christos 					  (trace_connection_input, 2, iov,
    534  1.1  christos 					   MDL));
    535  1.1  christos 				if (status != ISC_R_SUCCESS) {
    536  1.1  christos 					trace_stop ();
    537  1.1  christos 					log_error ("trace %s output: %s",
    538  1.1  christos 						   "connection",
    539  1.1  christos 						   isc_result_totext (status));
    540  1.1  christos 				}
    541  1.1  christos 			}
    542  1.1  christos #endif
    543  1.1  christos 
    544  1.1  christos 			buffer -> head = first_byte + bytes_written - 1;
    545  1.1  christos 			c -> out_bytes -= bytes_written;
    546  1.1  christos 
    547  1.1  christos 			/* If we didn't finish out the write, we filled the
    548  1.1  christos 			   O.S. output buffer and a further write would block,
    549  1.1  christos 			   so stop trying to flush now. */
    550  1.1  christos 			if (bytes_written != bytes_this_write)
    551  1.1  christos 				return ISC_R_INPROGRESS;
    552  1.1  christos 		}
    553  1.5  christos 
    554  1.1  christos 		if (!BYTES_IN_BUFFER (buffer))
    555  1.1  christos 			buffer = buffer -> next;
    556  1.1  christos 	}
    557  1.5  christos 
    558  1.1  christos 	/* Get rid of any output buffers we emptied. */
    559  1.1  christos 	buffer = (omapi_buffer_t *)0;
    560  1.1  christos 	while (c -> outbufs &&
    561  1.1  christos 	       !BYTES_IN_BUFFER (c -> outbufs)) {
    562  1.1  christos 		if (c -> outbufs -> next) {
    563  1.1  christos 			omapi_buffer_reference (&buffer,
    564  1.1  christos 						c -> outbufs -> next, MDL);
    565  1.1  christos 			omapi_buffer_dereference (&c -> outbufs -> next, MDL);
    566  1.1  christos 		}
    567  1.1  christos 		omapi_buffer_dereference (&c -> outbufs, MDL);
    568  1.1  christos 		if (buffer) {
    569  1.1  christos 			omapi_buffer_reference (&c -> outbufs, buffer, MDL);
    570  1.1  christos 			omapi_buffer_dereference (&buffer, MDL);
    571  1.1  christos 		}
    572  1.1  christos 	}
    573  1.1  christos 
    574  1.1  christos 	/* If we had data left to write when we're told to disconnect,
    575  1.1  christos 	* we need recall disconnect, now that we're done writing.
    576  1.1  christos 	* See rt46767. */
    577  1.1  christos 	if (c->out_bytes == 0 && c->state == omapi_connection_disconnecting) {
    578  1.1  christos 		omapi_disconnect (h, 1);
    579  1.1  christos 		return ISC_R_SHUTTINGDOWN;
    580  1.1  christos 	}
    581  1.1  christos 
    582  1.1  christos 	return ISC_R_SUCCESS;
    583  1.1  christos }
    584  1.1  christos 
    585  1.1  christos isc_result_t omapi_connection_get_uint32 (omapi_object_t *c,
    586  1.1  christos 					  u_int32_t *result)
    587  1.1  christos {
    588  1.1  christos 	u_int32_t inbuf;
    589  1.1  christos 	isc_result_t status;
    590  1.1  christos 
    591  1.1  christos 	status = omapi_connection_copyout ((unsigned char *)&inbuf,
    592  1.1  christos 					   c, sizeof inbuf);
    593  1.1  christos 	if (status != ISC_R_SUCCESS)
    594  1.1  christos 		return status;
    595  1.1  christos 
    596  1.1  christos 	*result = ntohl (inbuf);
    597  1.1  christos 	return ISC_R_SUCCESS;
    598  1.1  christos }
    599  1.1  christos 
    600  1.1  christos isc_result_t omapi_connection_put_uint32 (omapi_object_t *c,
    601  1.1  christos 					  u_int32_t value)
    602  1.1  christos {
    603  1.1  christos 	u_int32_t inbuf;
    604  1.1  christos 
    605  1.1  christos 	inbuf = htonl (value);
    606  1.5  christos 
    607  1.1  christos 	return omapi_connection_copyin (c, (unsigned char *)&inbuf,
    608  1.1  christos 					sizeof inbuf);
    609  1.1  christos }
    610  1.1  christos 
    611  1.1  christos isc_result_t omapi_connection_get_uint16 (omapi_object_t *c,
    612  1.1  christos 					  u_int16_t *result)
    613  1.1  christos {
    614  1.1  christos 	u_int16_t inbuf;
    615  1.1  christos 	isc_result_t status;
    616  1.1  christos 
    617  1.1  christos 	status = omapi_connection_copyout ((unsigned char *)&inbuf,
    618  1.1  christos 					   c, sizeof inbuf);
    619  1.1  christos 	if (status != ISC_R_SUCCESS)
    620  1.1  christos 		return status;
    621  1.1  christos 
    622  1.1  christos 	*result = ntohs (inbuf);
    623  1.1  christos 	return ISC_R_SUCCESS;
    624  1.1  christos }
    625  1.1  christos 
    626  1.1  christos isc_result_t omapi_connection_put_uint16 (omapi_object_t *c,
    627  1.1  christos 					  u_int32_t value)
    628  1.1  christos {
    629  1.1  christos 	u_int16_t inbuf;
    630  1.1  christos 
    631  1.1  christos 	inbuf = htons (value);
    632  1.5  christos 
    633  1.1  christos 	return omapi_connection_copyin (c, (unsigned char *)&inbuf,
    634  1.1  christos 					sizeof inbuf);
    635  1.1  christos }
    636  1.1  christos 
    637  1.1  christos isc_result_t omapi_connection_write_typed_data (omapi_object_t *c,
    638  1.1  christos 						omapi_typed_data_t *data)
    639  1.1  christos {
    640  1.1  christos 	isc_result_t status;
    641  1.1  christos 	omapi_handle_t handle;
    642  1.1  christos 
    643  1.1  christos 	/* Null data is valid. */
    644  1.1  christos 	if (!data)
    645  1.1  christos 		return omapi_connection_put_uint32 (c, 0);
    646  1.1  christos 
    647  1.1  christos 	switch (data -> type) {
    648  1.1  christos 	      case omapi_datatype_int:
    649  1.1  christos 		status = omapi_connection_put_uint32 (c, sizeof (u_int32_t));
    650  1.1  christos 		if (status != ISC_R_SUCCESS)
    651  1.1  christos 			return status;
    652  1.1  christos 		return omapi_connection_put_uint32 (c, ((u_int32_t)
    653  1.1  christos 							(data -> u.integer)));
    654  1.1  christos 
    655  1.1  christos 	      case omapi_datatype_string:
    656  1.1  christos 	      case omapi_datatype_data:
    657  1.1  christos 		status = omapi_connection_put_uint32 (c, data -> u.buffer.len);
    658  1.1  christos 		if (status != ISC_R_SUCCESS)
    659  1.1  christos 			return status;
    660  1.1  christos 		if (data -> u.buffer.len)
    661  1.1  christos 			return omapi_connection_copyin
    662  1.1  christos 				(c, data -> u.buffer.value,
    663  1.1  christos 				 data -> u.buffer.len);
    664  1.1  christos 		return ISC_R_SUCCESS;
    665  1.1  christos 
    666  1.1  christos 	      case omapi_datatype_object:
    667  1.1  christos 		if (data -> u.object) {
    668  1.1  christos 			status = omapi_object_handle (&handle,
    669  1.1  christos 						      data -> u.object);
    670  1.1  christos 			if (status != ISC_R_SUCCESS)
    671  1.1  christos 				return status;
    672  1.1  christos 		} else
    673  1.1  christos 			handle = 0;
    674  1.1  christos 		status = omapi_connection_put_uint32 (c, sizeof handle);
    675  1.1  christos 		if (status != ISC_R_SUCCESS)
    676  1.1  christos 			return status;
    677  1.1  christos 		return omapi_connection_put_uint32 (c, handle);
    678  1.1  christos 
    679  1.1  christos 	}
    680  1.1  christos 	return DHCP_R_INVALIDARG;
    681  1.1  christos }
    682  1.1  christos 
    683  1.1  christos isc_result_t omapi_connection_put_name (omapi_object_t *c, const char *name)
    684  1.1  christos {
    685  1.1  christos 	isc_result_t status;
    686  1.1  christos 	unsigned len = strlen (name);
    687  1.1  christos 
    688  1.1  christos 	status = omapi_connection_put_uint16 (c, len);
    689  1.1  christos 	if (status != ISC_R_SUCCESS)
    690  1.1  christos 		return status;
    691  1.1  christos 	return omapi_connection_copyin (c, (const unsigned char *)name, len);
    692  1.1  christos }
    693  1.1  christos 
    694  1.1  christos isc_result_t omapi_connection_put_string (omapi_object_t *c,
    695  1.1  christos 					  const char *string)
    696  1.1  christos {
    697  1.1  christos 	isc_result_t status;
    698  1.1  christos 	unsigned len;
    699  1.1  christos 
    700  1.1  christos 	if (string)
    701  1.1  christos 		len = strlen (string);
    702  1.1  christos 	else
    703  1.1  christos 		len = 0;
    704  1.1  christos 
    705  1.1  christos 	status = omapi_connection_put_uint32 (c, len);
    706  1.1  christos 	if (status != ISC_R_SUCCESS)
    707  1.1  christos 		return status;
    708  1.1  christos 	if (len)
    709  1.1  christos 		return omapi_connection_copyin
    710  1.1  christos 			(c, (const unsigned char *)string, len);
    711  1.1  christos 	return ISC_R_SUCCESS;
    712  1.1  christos }
    713  1.1  christos 
    714  1.1  christos isc_result_t omapi_connection_put_handle (omapi_object_t *c, omapi_object_t *h)
    715  1.1  christos {
    716  1.1  christos 	isc_result_t status;
    717  1.1  christos 	omapi_handle_t handle;
    718  1.1  christos 
    719  1.1  christos 	if (h) {
    720  1.1  christos 		status = omapi_object_handle (&handle, h);
    721  1.1  christos 		if (status != ISC_R_SUCCESS)
    722  1.1  christos 			return status;
    723  1.1  christos 	} else
    724  1.1  christos 		handle = 0;	/* The null handle. */
    725  1.1  christos 	status = omapi_connection_put_uint32 (c, sizeof handle);
    726  1.1  christos 	if (status != ISC_R_SUCCESS)
    727  1.1  christos 		return status;
    728  1.1  christos 	return omapi_connection_put_uint32 (c, handle);
    729  1.1  christos }
    730  1.1  christos 
    731  1.1  christos isc_result_t omapi_connection_put_named_uint32 (omapi_object_t *c,
    732  1.1  christos 						const char *name,
    733  1.1  christos 						u_int32_t value)
    734  1.1  christos {
    735  1.1  christos 	isc_result_t status;
    736  1.1  christos 
    737  1.1  christos 	status = omapi_connection_put_name(c, name);
    738  1.1  christos 	if (status != ISC_R_SUCCESS)
    739  1.1  christos 		return (status);
    740  1.1  christos 
    741  1.1  christos 	status = omapi_connection_put_uint32(c, sizeof(u_int32_t));
    742  1.1  christos 	if (status != ISC_R_SUCCESS)
    743  1.1  christos 		return (status);
    744  1.1  christos 
    745  1.1  christos 	status = omapi_connection_put_uint32(c, value);
    746  1.1  christos 	return (status);
    747  1.1  christos }
    748