bind9/lib/omapi/buffer.c
David Lawrence 0ae0a1f038 checkpoint conversion to ISC (doc/dev/coding.html) style.
* no spaces around " -> " in indirect postfix expression.
  * no space between function name and open parenthesis.
  * no space between array name and open bracket.
  * use NULL not 0 for pointers.
  * explicitly compare pointers to NULL.
  * explicitly compare integers to 0.
  * Do not cast NULL.
  * return type of function declaration on line by itself.
  * open brace of function definition follows close parenthesis if parameters
    all fit on one line.
  * comment-only lines start with /* on line by itself, and end with */
    on line by itself.
  * variable names in structures separated from their types in a column.
  * name the parameters in function prototypes.
  * ifndef multiple header file inclusion.

and other BIND9 conventions not in coding.html:

  * private structures defined in relevant source module, not private header.
  * RCS /* $Id: $ */ comments.
  * Principal Author (Ted Lemon) comments.
  * Updated ISC copyrights.
  * Parenthesize value of return().
  * Parenthesize argument of sizeof().
  * "unsigned int foo" not "unsigned foo".
  * ISC_LANG_(BEGIN|END)DECLS in header files.
  * header files included directly by source/header file that needs them.
  * ... and others I am probably forgetting.

and conversion to some libisc.a modules:

  * use isc/int.h for isc_uintXX_t types, not u_intXX_t.
  * use isc/assertions.h for REQUIRE() and INSIST().
  * use isc/error.h for UNEXPECTED_ERROR.
  * use isc/boolean.h for isc_boolean_t flags instead of int flags.
  * use isc/net.h for networking types.
  * use isc/netdb.h for gethostby*.

STILL TO COME ...

  * more isc_boolean_t.
  * isc/time.h to replace struct timeval.
  * isc/socket.h to replace socket/listen/select/etc.
  * isc/mem.h to replace malloc/free.
  * namespace overhaul & omapi/compatibility.h.

Please collect all your belongings but stand clear of the doors until this
train has come to a complete stop.
1999-11-02 04:01:34 +00:00

532 lines
13 KiB
C

/*
* Copyright (C) 1996, 1997, 1998, 1999 Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*/
/* $Id: buffer.c,v 1.2 1999/11/02 04:01:31 tale Exp $ */
/* Principal Author: Ted Lemon */
/*
* Buffer access functions for the object management protocol.
*/
#include <errno.h>
#include <stddef.h> /* NULL */
#include <unistd.h> /* read */
#include <isc/assertions.h>
#include <isc/error.h>
#include <omapi/omapip_p.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 result;
unsigned int read_len;
int read_status;
omapi_connection_object_t *c;
unsigned int bytes_to_read;
REQUIRE(h != NULL && h->type == omapi_type_connection);
c = (omapi_connection_object_t *)h;
/*
* See if there are enough bytes.
*/
if (c->in_bytes >= OMAPI_BUFFER_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_FREE(buffer) == 0) {
result = omapi_buffer_new(&buffer->next,
"omapi_private_read");
if (result != ISC_R_SUCCESS)
return (result);
buffer = buffer->next;
}
} else {
result = omapi_buffer_new(&c->inbufs, "omapi_private_read");
if (result != ISC_R_SUCCESS)
return (result);
buffer = c->inbufs;
}
bytes_to_read = BUFFER_BYTES_FREE(buffer);
while (bytes_to_read > 0) {
if (buffer->tail > buffer->head)
read_len = sizeof(buffer->data) - buffer->tail;
else
read_len = buffer->head - buffer->tail;
read_status = read(c->socket, &buffer->data[buffer->tail],
read_len);
if (read_status < 0) {
if (errno == EWOULDBLOCK)
break;
else if (errno == EIO)
return (ISC_R_IOERROR);
else if (errno == ECONNRESET) {
omapi_disconnect(h, OMAPI_CLEAN_DISCONNECT);
return (ISC_R_SHUTTINGDOWN);
} else
return (ISC_R_UNEXPECTED);
}
/*
* If we got a zero-length read, as opposed to EWOULDBLOCK,
* the remote end closed the connection.
*/
if (read_status == 0) {
omapi_disconnect(h, OMAPI_CLEAN_DISCONNECT);
return (ISC_R_SHUTTINGDOWN);
}
buffer->tail += read_status;
c->in_bytes += read_status;
if (buffer->tail == sizeof(buffer->data))
buffer->tail = 0;
/*
* Comparison between signed and unsigned.
* The cast is ok because read_status < 0 was checked above.
*/
if ((unsigned int)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, const unsigned char *bufp,
unsigned int len)
{
omapi_buffer_t *buffer;
isc_result_t result;
unsigned int bytes_copied = 0;
unsigned int copy_len;
omapi_connection_object_t *c;
REQUIRE(h != NULL && h->type == omapi_type_connection);
c = (omapi_connection_object_t *)h;
if (c->outbufs) {
for (buffer = c->outbufs;
buffer->next; buffer = buffer->next)
;
} else {
result = omapi_buffer_new(&c->outbufs,
"omapi_private_buffer_copyin");
if (result != ISC_R_SUCCESS)
return (result);
buffer = c->outbufs;
}
while (bytes_copied < len) {
/*
* If there is no space available in this buffer,
* allocate a new one.
*/
if (BUFFER_BYTES_FREE (buffer) == 0) {
result = omapi_buffer_new(&buffer->next,
"omapi_private_buffer_copyin");
if (result != ISC_R_SUCCESS)
return (result);
buffer = buffer->next;
}
if (buffer->tail > buffer->head)
copy_len = sizeof(buffer->data) - buffer->tail;
else
copy_len = buffer->head - buffer->tail;
if (copy_len > (len - bytes_copied))
copy_len = len - bytes_copied;
memcpy (&buffer->data[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->data))
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.
*/
isc_result_t
omapi_connection_copyout(unsigned char *buf, omapi_object_t *h,
unsigned int size)
{
unsigned int bytes_remaining;
unsigned int bytes_this_copy;
unsigned int first_byte;
omapi_buffer_t *buffer;
unsigned char *bufp;
omapi_connection_object_t *c;
REQUIRE(h != NULL && h->type == omapi_type_connection);
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 > 0) {
if (buffer == NULL)
return (ISC_R_UNEXPECTED);
if (BYTES_IN_BUFFER(buffer) != 0) {
if (buffer->head == sizeof(buffer->data) - 1)
first_byte = 0;
else
first_byte = buffer->head + 1;
if (first_byte > buffer->tail)
bytes_this_copy = sizeof(buffer->data) -
first_byte;
else
bytes_this_copy =
buffer->tail - first_byte;
if (bytes_this_copy > bytes_remaining)
bytes_this_copy = bytes_remaining;
if (bufp != NULL) {
memcpy(bufp, &buffer->data[first_byte],
bytes_this_copy);
bufp += bytes_this_copy;
}
bytes_remaining -= bytes_this_copy;
buffer->head = first_byte + bytes_this_copy - 1;
c->in_bytes -= bytes_this_copy;
}
if (BYTES_IN_BUFFER (buffer) == 0)
buffer = buffer->next;
}
/*
* Get rid of any input buffers that we emptied.
*/
buffer = NULL;
while (c->inbufs != NULL && BYTES_IN_BUFFER(c->inbufs) == 0) {
if (c->inbufs->next != NULL) {
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");
if (buffer != NULL) {
omapi_buffer_reference(&c->inbufs, buffer,
"omapi_private_buffer_copyout");
omapi_buffer_dereference(&buffer,
"omapi_private_buffer_copyout");
}
}
return (ISC_R_SUCCESS);
}
isc_result_t
omapi_connection_writer(omapi_object_t *h) {
int bytes_written;
unsigned int bytes_this_write;
unsigned int first_byte;
omapi_buffer_t *buffer;
omapi_connection_object_t *c;
REQUIRE(h != NULL && h->type == omapi_type_connection);
c = (omapi_connection_object_t *)h;
/*
* Already flushed.
*/
if (c->out_bytes == 0)
return (ISC_R_SUCCESS);
buffer = c->outbufs;
while (c->out_bytes > 0) {
if (buffer == NULL)
return (ISC_R_UNEXPECTED);
if (BYTES_IN_BUFFER (buffer) != 0) {
if (buffer->head == sizeof(buffer->data) - 1)
first_byte = 0;
else
first_byte = buffer->head + 1;
if (first_byte > buffer->tail)
bytes_this_write = (sizeof(buffer->data) -
first_byte);
else
bytes_this_write = buffer->tail - first_byte;
bytes_written = write(c->socket,
&buffer->data[first_byte],
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 == ECONNRESET)
return (ISC_R_SHUTTINGDOWN);
else
return (ISC_R_UNEXPECTED);
}
if (bytes_written == 0)
return (ISC_R_SUCCESS);
buffer->head = first_byte + bytes_written - 1;
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.
*
* bytes_written was already checked to not be < 0,
* so the cast is ok.
*/
if ((unsigned int)bytes_written != bytes_this_write)
return (ISC_R_SUCCESS);
}
if (BYTES_IN_BUFFER (buffer) == 0)
buffer = buffer->next;
}
/*
* Get rid of any output buffers we emptied.
*/
buffer = NULL;
while (c->outbufs != NULL && BYTES_IN_BUFFER(c->outbufs) == 0) {
if (c->outbufs->next != NULL) {
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 != NULL) {
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, isc_uint32_t *value) {
isc_uint32_t inbuf;
isc_result_t result;
result = omapi_connection_copyout((unsigned char *)&inbuf, c,
sizeof(inbuf));
if (result != ISC_R_SUCCESS)
return (result);
*value = ntohl(inbuf);
return (ISC_R_SUCCESS);
}
isc_result_t
omapi_connection_put_uint32(omapi_object_t *c, isc_uint32_t value) {
isc_uint32_t inbuf;
inbuf = htonl(value);
return (omapi_connection_copyin(c, (unsigned char *)&inbuf,
sizeof(inbuf)));
}
isc_result_t
omapi_connection_get_uint16(omapi_object_t *c, isc_uint16_t *value) {
isc_uint16_t inbuf;
isc_result_t result;
result = omapi_connection_copyout((unsigned char *)&inbuf, c,
sizeof(inbuf));
if (result != ISC_R_SUCCESS)
return (result);
*value = ntohs (inbuf);
return (ISC_R_SUCCESS);
}
isc_result_t
omapi_connection_put_uint16(omapi_object_t *c, isc_uint32_t value) {
isc_uint16_t inbuf;
REQUIRE(value < 65536);
inbuf = htons((isc_uint16_t)value);
return (omapi_connection_copyin(c, (unsigned char *)&inbuf,
sizeof(inbuf)));
}
isc_result_t
omapi_connection_write_typed_data(omapi_object_t *c, omapi_typed_data_t *data)
{
isc_result_t result;
omapi_handle_t handle;
REQUIRE(data != NULL &&
(data->type == omapi_datatype_int ||
data->type == omapi_datatype_string ||
data->type == omapi_datatype_data ||
data->type == omapi_datatype_object));
switch (data->type) {
case omapi_datatype_int:
result = omapi_connection_put_uint32(c, sizeof(isc_uint32_t));
if (result != ISC_R_SUCCESS)
return (result);
return (omapi_connection_put_uint32(c, ((isc_uint32_t)
(data->u.integer))));
case omapi_datatype_string:
case omapi_datatype_data:
result = omapi_connection_put_uint32(c, data->u.buffer.len);
if (result != ISC_R_SUCCESS)
return (result);
if (data->u.buffer.len > 0)
return (omapi_connection_copyin(c,
data->u.buffer.value,
data->u.buffer.len));
return (ISC_R_SUCCESS);
case omapi_datatype_object:
if (data->u.object != NULL) {
result = omapi_object_handle(&handle, data->u.object);
if (result != ISC_R_SUCCESS)
return (result);
} else
handle = 0;
result = omapi_connection_put_uint32(c, sizeof(handle));
if (result != ISC_R_SUCCESS)
return (result);
return (omapi_connection_put_uint32(c, handle));
}
UNEXPECTED_ERROR(__FILE__, __LINE__,
"unknown type in omapi_connection_write_typed_data: "
"%d\n", data->type);
return (ISC_R_UNEXPECTED);
}
isc_result_t
omapi_connection_put_name(omapi_object_t *c, const char *name) {
isc_result_t result;
unsigned int len = strlen(name);
if (len > 65535)
/* XXXDCL better error? */
return (ISC_R_FAILURE);
result = omapi_connection_put_uint16(c, len);
if (result != ISC_R_SUCCESS)
return (result);
return (omapi_connection_copyin(c, (const unsigned char *)name, len));
}
isc_result_t
omapi_connection_put_string(omapi_object_t *c, const char *string) {
isc_result_t result;
unsigned int len;
if (string != NULL)
len = strlen(string);
else
len = 0;
result = omapi_connection_put_uint32(c, len);
if (result == ISC_R_SUCCESS && len > 0)
result = omapi_connection_copyin(c,
(const unsigned char *)string,
len);
return (result);
}
isc_result_t
omapi_connection_put_handle(omapi_object_t *c, omapi_object_t *h) {
isc_result_t result;
omapi_handle_t handle;
if (h != NULL) {
result = omapi_object_handle(&handle, h);
if (result != ISC_R_SUCCESS)
return (result);
} else
handle = 0; /* The null handle. */
result = omapi_connection_put_uint32(c, sizeof(handle));
if (result == ISC_R_SUCCESS)
result = omapi_connection_put_uint32(c, handle);
return (result);
}