diff options
author | Ted Lemon <source@isc.org> | 1999-09-02 00:32:56 +0000 |
---|---|---|
committer | Ted Lemon <source@isc.org> | 1999-09-02 00:32:56 +0000 |
commit | 61b844bfd7641a62d681a1f70d3b6dbc485ce4b6 (patch) | |
tree | 01e4c19e3b1025eade692fb7f5d6748099f96b01 /omapip/buffer.c | |
parent | a40cbc2b969af1eeb0bdd1912040c3a829a5b220 (diff) | |
download | isc-dhcp-61b844bfd7641a62d681a1f70d3b6dbc485ce4b6.tar.gz |
Omapi library, initial checkin
Diffstat (limited to 'omapip/buffer.c')
-rw-r--r-- | omapip/buffer.c | 396 |
1 files changed, 396 insertions, 0 deletions
diff --git a/omapip/buffer.c b/omapip/buffer.c new file mode 100644 index 00000000..6bd2c946 --- /dev/null +++ b/omapip/buffer.c @@ -0,0 +1,396 @@ +/* buffer.c + + Buffer access functions for the object management protocol... */ + +/* + * Copyright (c) 1996-1999 Internet Software Consortium. + * Use is subject to license terms which appear in the file named + * ISC-LICENSE that should have accompanied this file when you + * received it. If a file named ISC-LICENSE did not accompany this + * file, or you are not sure the one you have is correct, you may + * obtain an applicable copy of the license at: + * + * http://www.isc.org/isc-license-1.0.html. + * + * This file is part of the ISC DHCP distribution. The documentation + * associated with this file is listed in the file DOCUMENTATION, + * included in the top-level directory of this release. + * + * Support and other services are available for ISC products - see + * http://www.isc.org for more information. + */ + +#include <omapip/omapip.h> + +/* Make sure that at least len bytes are in the input buffer, and if not, + read enough bytes to make up the difference. */ + +isc_result_t omapi_connection_reader (omapi_object_t *h) +{ + omapi_buffer_t *buffer; + isc_result_t status; + int read_len, read_status; + omapi_connection_object_t *c; + int bytes_to_read; + + if (!h || h -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + c = (omapi_connection_object_t *)h; + + /* Make sure c -> bytes_needed is valid. */ + if (c -> bytes_needed < 0) + return ISC_R_INVALIDARG; + + /* See if there are enough bytes. */ + if (c -> in_bytes >= OMAPI_BUF_SIZE - 1 && + c -> in_bytes > c -> bytes_needed) + return ISC_R_SUCCESS; + + if (c -> inbufs) { + for (buffer = c -> inbufs; buffer -> next; + buffer = buffer -> next) + ; + if (!BUFFER_BYTES_AVAIL (buffer)) { + status = omapi_buffer_new (&buffer -> next, + "omapi_private_read"); + if (status != ISC_R_SUCCESS) + return status; + buffer = buffer -> next; + } + } else { + status = omapi_buffer_new (&c -> inbufs, + "omapi_private_read"); + if (status != ISC_R_SUCCESS) + return status; + buffer = c -> inbufs; + } + + bytes_to_read = BUFFER_BYTES_AVAIL (buffer); + + while (bytes_to_read) { + if (buffer -> tail >= buffer -> head) + read_len = sizeof (buffer -> buf) - buffer -> tail - 1; + else + read_len = buffer -> tail - buffer -> head - 1; + + read_status = read (c -> socket, + &buffer -> buf [buffer -> tail], read_len); + if (read_status < 0) { + if (errno == EWOULDBLOCK) + return ISC_R_NOMORE; + else if (errno == EIO) + return ISC_R_IOERROR; + else if (errno == EINVAL) + return ISC_R_INVALIDARG; + else if (errno == ECONNRESET) { + omapi_disconnect (h, 0); + return ISC_R_SHUTTINGDOWN; + } else + return ISC_R_UNEXPECTED; + } + if (read_status == 0) { + omapi_disconnect (h, 0); + return ISC_R_SHUTTINGDOWN; + } + buffer -> tail += read_status; + c -> in_bytes += read_status; + if (buffer -> tail == sizeof buffer -> buf) + buffer -> tail = 0; + if (read_status < read_len) + break; + bytes_to_read -= read_status; + } + + if (c -> bytes_needed >= c -> in_bytes) { + omapi_signal (h, "ready", c); + } + return ISC_R_SUCCESS; +} + +/* Put some bytes into the output buffer for a connection. */ + +isc_result_t omapi_connection_copyin (omapi_object_t *h, + unsigned char *bufp, + int len) +{ + omapi_buffer_t *buffer; + isc_result_t status; + int bytes_copied = 0; + int copy_len; + omapi_connection_object_t *c; + + /* Make sure len is valid. */ + if (len < 0) + return ISC_R_INVALIDARG; + if (!h || h -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + c = (omapi_connection_object_t *)h; + + if (c -> outbufs) { + for (buffer = c -> outbufs; + buffer -> next; buffer = buffer -> next) + ; + } else { + status = omapi_buffer_new (&c -> outbufs, + "omapi_private_buffer_copyin"); + if (status != ISC_R_SUCCESS) + return status; + buffer = c -> outbufs; + } + + while (bytes_copied < len) { + /* If there is no space available in this buffer, + allocate a new one. */ + if (!BUFFER_BYTES_AVAIL (buffer)) { + status = (omapi_buffer_new + (&buffer -> next, + "omapi_private_buffer_copyin")); + if (status != ISC_R_SUCCESS) + return status; + buffer = buffer -> next; + } + + if (buffer -> tail < buffer -> head) + copy_len = buffer -> tail - buffer -> head - 1; + else + copy_len = sizeof (buffer -> buf) - buffer -> tail - 1; + if (copy_len > (len - bytes_copied)) + copy_len = len - bytes_copied; + + memcpy (&buffer -> buf [buffer -> tail], + &bufp [bytes_copied], copy_len); + buffer -> tail += copy_len; + c -> out_bytes += copy_len; + bytes_copied += copy_len; + if (buffer -> tail == sizeof buffer -> buf) + buffer -> tail = 0; + } + return ISC_R_SUCCESS; +} + +/* Copy some bytes from the input buffer, and advance the input buffer + pointer beyond the bytes copied out. */ + +u_int32_t omapi_connection_copyout (unsigned char *buf, + omapi_object_t *h, + int size) +{ + int bytes_remaining; + int bytes_this_copy; + omapi_buffer_t *buffer; + unsigned char *bufp; + omapi_connection_object_t *c; + + if (!h || h -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + c = (omapi_connection_object_t *)h; + + if (size > c -> in_bytes) + return ISC_R_NOMORE; + bufp = buf; + bytes_remaining = size; + buffer = c -> inbufs; + + while (bytes_remaining) { + if (!buffer) + return ISC_R_UNEXPECTED; + if (buffer -> head != buffer -> tail) { + if (buffer -> head > buffer -> tail) { + bytes_this_copy = (sizeof buffer -> buf - + buffer -> head); + } else { + bytes_this_copy = + buffer -> tail - buffer -> head; + } + if (bytes_this_copy > bytes_remaining) + bytes_this_copy = bytes_remaining; + if (bufp) { + memcpy (bufp, &buffer -> buf [buffer -> head], + bytes_this_copy); + bufp += bytes_this_copy; + } + bytes_remaining -= bytes_this_copy; + buffer -> head += bytes_this_copy; + if (buffer -> head == sizeof buffer -> buf) + buffer -> head = 0; + c -> in_bytes -= bytes_this_copy; + } + + if (buffer -> head == buffer -> tail) + buffer = buffer -> next; + } + + /* Get rid of any input buffers that we emptied. */ + buffer = (omapi_buffer_t *)0; + while (c -> inbufs && + c -> inbufs -> head == c -> inbufs -> tail) { + if (c -> inbufs -> next) { + omapi_buffer_reference + (&buffer, + c -> inbufs -> next, + "omapi_private_buffer_copyout"); + omapi_buffer_dereference + (&c -> inbufs -> next, + "omapi_private_buffer_copyout"); + } + omapi_buffer_dereference (&c -> inbufs, + "omapi_private_buffer_copyout"); + omapi_buffer_reference (&c -> inbufs, + buffer, + "omapi_private_buffer_copyout"); + omapi_buffer_dereference (&buffer, + "omapi_private_buffer_copyout"); + } + return ISC_R_SUCCESS; +} + +u_int32_t omapi_connection_writer (omapi_object_t *h) +{ + int bytes_this_write; + int bytes_written; + omapi_buffer_t *buffer; + unsigned char *bufp; + omapi_connection_object_t *c; + + if (!h || h -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + c = (omapi_connection_object_t *)h; + + /* Already flushed... */ + if (!c -> out_bytes) + return ISC_R_SUCCESS; + + buffer = c -> outbufs; + + while (c -> out_bytes) { + if (!buffer) + return ISC_R_UNEXPECTED; + if (buffer -> head != buffer -> tail) { + if (buffer -> head > buffer -> tail) { + bytes_this_write = (sizeof buffer -> buf - + buffer -> head); + } else { + bytes_this_write = + (buffer -> tail - buffer -> head); + } + bytes_written = write (c -> socket, + &buffer -> buf [buffer -> head], + bytes_this_write); + /* If the write failed with EWOULDBLOCK or we wrote + zero bytes, a further write would block, so we have + flushed as much as we can for now. Other errors + are really errors. */ + if (bytes_written < 0) { + if (errno == EWOULDBLOCK || errno == EAGAIN) + return ISC_R_SUCCESS; + else if (errno == EPIPE) + return ISC_R_NOCONN; + else if (errno == EFBIG || errno == EDQUOT) + return ISC_R_NORESOURCES; + else if (errno == ENOSPC) + return ISC_R_NOSPACE; + else if (errno == EIO) + return ISC_R_IOERROR; + else if (errno == EINVAL) + return ISC_R_INVALIDARG; + else if (errno == ECONNRESET) + return ISC_R_SHUTTINGDOWN; + else + return ISC_R_UNEXPECTED; + } + if (bytes_written == 0) + return ISC_R_SUCCESS; + + buffer -> head += bytes_written; + if (buffer -> head == sizeof buffer -> buf) + buffer -> head = 0; + c -> out_bytes -= bytes_written; + + /* If we didn't finish out the write, we filled the + O.S. output buffer and a further write would block, + so stop trying to flush now. */ + if (bytes_written != bytes_this_write) + return ISC_R_SUCCESS; + } + + if (buffer -> head == buffer -> tail) + buffer = buffer -> next; + } + + /* Get rid of any output buffers we emptied. */ + buffer = (omapi_buffer_t *)0; + while (c -> outbufs && + c -> outbufs -> head == c -> outbufs -> tail) { + if (c -> outbufs -> next) { + omapi_buffer_reference + (&buffer, c -> outbufs -> next, + "omapi_private_flush"); + omapi_buffer_dereference + (&c -> outbufs -> next, "omapi_private_flush"); + } + omapi_buffer_dereference (&c -> outbufs, + "omapi_private_flush"); + if (buffer) { + omapi_buffer_reference (&c -> outbufs, buffer, + "omapi_private_flush"); + omapi_buffer_dereference (&buffer, + "omapi_private_flush"); + } + } + return ISC_R_SUCCESS; +} + +isc_result_t omapi_connection_get_uint32 (omapi_object_t *c, + u_int32_t *result) +{ + u_int32_t inbuf; + isc_result_t status; + + status = omapi_connection_copyout ((unsigned char *)&inbuf, + c, sizeof inbuf); + if (status != ISC_R_SUCCESS) + return status; + + *result = ntohl (inbuf); + return ISC_R_SUCCESS; +} + +isc_result_t omapi_connection_put_uint32 (omapi_object_t *c, + u_int32_t value) +{ + u_int32_t inbuf; + isc_result_t status; + + inbuf = htonl (value); + + return omapi_connection_copyin (c, (unsigned char *)&inbuf, + sizeof inbuf); +} + +isc_result_t omapi_connection_get_uint16 (omapi_object_t *c, + u_int16_t *result) +{ + u_int16_t inbuf; + isc_result_t status; + + status = omapi_connection_copyout ((unsigned char *)&inbuf, + c, sizeof inbuf); + if (status != ISC_R_SUCCESS) + return status; + + *result = ntohs (inbuf); + return ISC_R_SUCCESS; +} + +isc_result_t omapi_connection_put_uint16 (omapi_object_t *c, + u_int16_t value) +{ + u_int16_t inbuf; + isc_result_t status; + + inbuf = htons (value); + + return omapi_connection_copyin (c, (unsigned char *)&inbuf, + sizeof inbuf); +} + |