diff --git a/lib/omapi/connection.c b/lib/omapi/connection.c index 3f4c38cf17..e8e667870c 100644 --- a/lib/omapi/connection.c +++ b/lib/omapi/connection.c @@ -15,7 +15,7 @@ * SOFTWARE. */ -/* $Id: connection.c,v 1.6 2000/01/11 01:49:22 tale Exp $ */ +/* $Id: connection.c,v 1.7 2000/01/13 06:13:21 tale Exp $ */ /* Principal Author: Ted Lemon */ @@ -35,12 +35,6 @@ #include -/* - * Forward declarations. - */ -void -connection_send(omapi_connection_object_t *connection); - /* * Swiped from bin/tests/sdig.c. */ @@ -144,6 +138,12 @@ connect_done(isc_task_t *task, isc_event_t *event) { connection->events_pending--; + /* + * XXXDCL For some reason, a "connection refused" error is not + * being indicated here when it would be expected. I wonder + * how that error is indicated. + */ + if (connectevent->result != ISC_R_SUCCESS) { abandon_connection(connection, event, connectevent->result); return; @@ -180,6 +180,7 @@ recv_done(isc_task_t *task, isc_event_t *event) { isc_socket_t *socket; isc_socketevent_t *socketevent; omapi_connection_object_t *connection; + unsigned int original_bytes_needed; socket = event->sender; socketevent = (isc_socketevent_t *)event; @@ -204,21 +205,21 @@ recv_done(isc_task_t *task, isc_event_t *event) { connection->in_bytes += socketevent->n; + original_bytes_needed = connection->bytes_needed; + while (connection->bytes_needed <= connection->in_bytes && connection->bytes_needed > 0) - omapi_signal(event->arg, "ready", connection); + omapi_signal((omapi_object_t *)connection, "ready", + connection); -#if 0 /* - * XXXDCL it may be the case that another recv task should be queued, - * but I haven't thought it through fully. + * Queue up another recv request. If the bufferlist is empty, + * then, something under omapi_signal already called + * omapi_connection_require and queued the recv (which is + * what emptied the bufferlist). */ - if (connection->bytes_needed > 0) - isc_socket_recvv(socket, &connection->input_buffers, - connection->bytes_needed - - connection->in_bytes, - task, recv_done, connection); -#endif + if (! ISC_LIST_EMPTY(connection->input_buffers)) + omapi_connection_require((omapi_object_t *)connection, 0); isc_event_free(&event); @@ -243,7 +244,7 @@ send_done(isc_task_t *task, isc_event_t *event) { /* * XXXDCL I am assuming that partial writes are not done. I hope this - * does not prove to be incorrect. But the assumption can be tested ... + * does not prove to be incorrect. But the assumption can be tested ... */ ENSURE(socketevent->n == connection->out_bytes && socketevent->n == @@ -311,6 +312,7 @@ omapi_connection_toserver(omapi_object_t *protocol, const char *server_name, if (result != ISC_R_SUCCESS) return (result); + /* XXXDCL Make cleanup better */ /* * Prepare the task that will wait for the connection to be made. */ @@ -345,6 +347,8 @@ omapi_connection_toserver(omapi_object_t *protocol, const char *server_name, return (result); } + connection->is_client = ISC_TRUE; + connection->task = task; ISC_LIST_INIT(connection->input_buffers); @@ -352,6 +356,23 @@ omapi_connection_toserver(omapi_object_t *protocol, const char *server_name, ISC_LIST_INIT(connection->output_buffers); ISC_LIST_APPEND(connection->output_buffers, obuffer, link); + result = isc_mutex_init(&connection->mutex); + if (result != ISC_R_SUCCESS) + return (result); + + result = isc_condition_init(&connection->waiter); + if (result != ISC_R_SUCCESS) + return (result); + + /* + * An introductory message is expected from the server. + * It is not necessary to lock the mutex here because there + * will be no recv() tasks that could possibly compete for the + * messages_expected variable, since isc_socket_create has + * not even been called yet. + */ + connection->messages_expected = 1; + /* * Tie the new connection object to the protocol object. */ @@ -395,6 +416,8 @@ omapi_connection_toserver(omapi_object_t *protocol, const char *server_name, return (result); } + connection->events_pending++; + return (result); } @@ -481,6 +504,8 @@ omapi_connection_copyout(unsigned char *dst, omapi_object_t *generic, if (size > connection->in_bytes) return (ISC_R_NOMORE); + connection->bytes_needed -= size; + buffer = ISC_LIST_HEAD(connection->input_buffers); /* @@ -492,7 +517,13 @@ omapi_connection_copyout(unsigned char *dst, omapi_object_t *generic, if (copy_bytes > size) copy_bytes = size; - (void)memcpy(dst, buffer->base + buffer->current, copy_bytes); + /* + * When dst == NULL, this function is being used to skip + * over uninteresting input. + */ + if (dst != NULL) + (void)memcpy(dst, buffer->base + buffer->current, + copy_bytes); isc_buffer_forward(buffer, copy_bytes); @@ -639,21 +670,77 @@ omapi_connection_require(omapi_object_t *generic, unsigned int bytes) { /* * Queue the receive task. * XXXDCL The "minimum" argument has not been fully thought out. - * It will *probably* work fine in a lockstep protocol, but I - * am not so sure what will happen when */ isc_socket_recvv(connection->socket, &connection->input_buffers, connection->bytes_needed - connection->in_bytes, connection->task, recv_done, connection); + connection->events_pending++; + return (OMAPI_R_NOTYET); } +/* + * This function is meant to pause the client until it has received + * a message from the server, either the introductory message or a response + * to a message it has sent. Because the socket library is multithreaded, + * those events can happen before omapi_connection_wait is ever called. + * So a counter needs to be set for every expected message, and this + * function can only return when that counter is 0. + */ +isc_result_t +omapi_connection_wait(omapi_object_t *object, + omapi_object_t *connection_handle, + isc_time_t *timeout) +{ + /* + * 'object' is not really used. + */ + omapi_connection_object_t *connection; + isc_result_t result, wait_result; + + REQUIRE(object != NULL && connection_handle != NULL); + REQUIRE(connection_handle->type == omapi_type_connection); + + connection = (omapi_connection_object_t *)connection_handle; + /* + * This routine is not valid for server connections. + */ + REQUIRE(connection->is_client); + + result = isc_mutex_lock(&connection->mutex); + if (result != ISC_R_SUCCESS) + return (result); + + wait_result = ISC_R_SUCCESS; + + while (connection->messages_expected > 0 && + wait_result == ISC_R_SUCCESS) { + if (timeout == NULL) + wait_result = isc_condition_wait(&connection->waiter, + &connection->mutex); + else + wait_result = + isc_condition_waituntil(&connection->waiter, + &connection->mutex, + timeout); + } + + if (wait_result == ISC_R_SUCCESS || wait_result == ISC_R_TIMEDOUT) { + result = isc_mutex_unlock(&connection->mutex); + if (result != ISC_R_SUCCESS) + return (result); + } + + return (wait_result); +} + isc_result_t omapi_connection_setvalue(omapi_object_t *connection, omapi_object_t *id, omapi_data_string_t *name, omapi_typed_data_t *value) { - REQUIRE(connection != NULL && connection->type == omapi_type_connection); + REQUIRE(connection != NULL && + connection->type == omapi_type_connection); PASS_SETVALUE(connection); } @@ -662,8 +749,9 @@ isc_result_t omapi_connection_getvalue(omapi_object_t *connection, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value) { - REQUIRE(connection != NULL && connection->type == omapi_type_connection); - + REQUIRE(connection != NULL && + connection->type == omapi_type_connection); + PASS_GETVALUE(connection); } @@ -673,24 +761,20 @@ omapi_connection_destroy(omapi_object_t *handle, const char *name) { REQUIRE(handle != NULL && handle->type == omapi_type_connection); + (void)name; + connection = (omapi_connection_object_t *)handle; if (connection->state == omapi_connection_connected) omapi_connection_disconnect(handle, OMAPI_FORCE_DISCONNECT); - - /* - * XXXDCL why is the listener object is being referenced? - * does it need to be in the connection structure at all? - */ - if (connection->listener != NULL) - OBJECT_DEREF(&connection->listener, name); } isc_result_t omapi_connection_signalhandler(omapi_object_t *connection, const char *name, va_list ap) { - REQUIRE(connection != NULL && connection->type == omapi_type_connection); + REQUIRE(connection != NULL && + connection->type == omapi_type_connection); PASS_SIGNAL(connection); } diff --git a/lib/omapi/data.c b/lib/omapi/data.c index bdb5b30821..505c9d4c22 100644 --- a/lib/omapi/data.c +++ b/lib/omapi/data.c @@ -15,7 +15,7 @@ * SOFTWARE. */ -/* $Id: data.c,v 1.1 2000/01/04 20:04:37 tale Exp $ */ +/* $Id: data.c,v 1.2 2000/01/13 06:13:21 tale Exp $ */ /* Principal Author: Ted Lemon */ @@ -53,23 +53,23 @@ omapi_data_new(omapi_typed_data_t **t, omapi_datatype_t type, ...) { s = NULL; switch (type) { - case omapi_datatype_int: + case omapi_datatype_int: len = OMAPI_TYPED_DATA_INT_LEN; intval = va_arg(l, int); break; - case omapi_datatype_string: + case omapi_datatype_string: s = va_arg(l, char *); val = strlen(s); len = OMAPI_TYPED_DATA_NOBUFFER_LEN + val; break; - case omapi_datatype_data: + case omapi_datatype_data: val = va_arg(l, unsigned int); len = OMAPI_TYPED_DATA_NOBUFFER_LEN + val; break; - case omapi_datatype_object: + case omapi_datatype_object: len = OMAPI_TYPED_DATA_OBJECT_LEN; break; - default: + default: UNEXPECTED_ERROR(__FILE__, __LINE__, "unknown type in omapi_data_new: %d\n", type); @@ -108,7 +108,7 @@ omapi_data_reference(omapi_typed_data_t **r, omapi_typed_data_t *h, const char *name) { REQUIRE(r != NULL && h != NULL); - REQUIRE(*r != NULL); + REQUIRE(*r == NULL); (void)name; /* Unused. */ @@ -118,22 +118,40 @@ omapi_data_reference(omapi_typed_data_t **r, omapi_typed_data_t *h, void omapi_data_dereference(omapi_typed_data_t **h, const char *name) { + int length = 0; + + REQUIRE(h != NULL && *h != NULL); REQUIRE((*h)->refcnt > 0); if (--((*h)->refcnt) <= 0) { switch ((*h)->type) { - case omapi_datatype_int: - case omapi_datatype_string: - case omapi_datatype_data: - default: + case omapi_datatype_int: + length = OMAPI_TYPED_DATA_INT_LEN; break; - case omapi_datatype_object: + case omapi_datatype_string: + length = OMAPI_TYPED_DATA_NOBUFFER_LEN + + (*h)->u.buffer.len; + break; + case omapi_datatype_data: + length = OMAPI_TYPED_DATA_NOBUFFER_LEN + + (*h)->u.buffer.len; + break; + case omapi_datatype_object: OBJECT_DEREF(&(*h)->u.object, name); + length = OMAPI_TYPED_DATA_OBJECT_LEN; break; + default: + FATAL_ERROR(__FILE__, __LINE__, + "unknown datatype in " + "omapi_data_dereference: %d\n", + (*h)->type); + /* NOTREACHED */ + return; } - isc_mem_put(omapi_mctx, *h, sizeof(*h)); + isc_mem_put(omapi_mctx, *h, length); } + *h = NULL; } @@ -144,7 +162,7 @@ omapi_data_newstring(omapi_data_string_t **d, unsigned int len, omapi_data_string_t *new; new = isc_mem_get(omapi_mctx, OMAPI_DATA_STRING_EMPTY_SIZE + len); - if (new != NULL) + if (new == NULL) return (ISC_R_NOMEMORY); memset(new, 0, OMAPI_DATA_STRING_EMPTY_SIZE); new->len = len; @@ -186,7 +204,7 @@ omapi_data_newvalue(omapi_value_t **d, const char *name) { omapi_value_t *new; new = isc_mem_get(omapi_mctx, sizeof(*new)); - if (new != NULL) + if (new == NULL) return (ISC_R_NOMEMORY); memset(new, 0, sizeof *new); diff --git a/lib/omapi/dispatch.c b/lib/omapi/dispatch.c index 356478acc3..0a07fd2e88 100644 --- a/lib/omapi/dispatch.c +++ b/lib/omapi/dispatch.c @@ -15,7 +15,7 @@ * SOFTWARE. */ -/* $Id: dispatch.c,v 1.6 2000/01/11 01:49:23 tale Exp $ */ +/* $Id: dispatch.c,v 1.7 2000/01/13 06:13:22 tale Exp $ */ /* Principal Author: Ted Lemon */ @@ -30,25 +30,6 @@ #include -typedef struct omapi_io_object { - OMAPI_OBJECT_PREAMBLE; - struct omapi_io_object * next; - int (*readfd) (omapi_object_t *); - int (*writefd)(omapi_object_t *); - isc_result_t (*reader) (omapi_object_t *); - isc_result_t (*writer) (omapi_object_t *); - isc_result_t (*reaper) (omapi_object_t *); -} omapi_io_object_t; - -typedef struct omapi_waiter_object { - OMAPI_OBJECT_PREAMBLE; - struct omapi_waiter_object * next; - int ready; -} omapi_waiter_object_t; - -static omapi_io_object_t omapi_io_states; -isc_uint32_t cur_time; - isc_result_t omapi_dispatch(struct timeval *t) { /* @@ -59,220 +40,6 @@ omapi_dispatch(struct timeval *t) { return (ISC_R_SUCCESS); } -isc_result_t -omapi_wait_for_completion(omapi_object_t *object, struct timeval *t) { - isc_result_t result; - omapi_waiter_object_t *waiter = NULL; - omapi_object_t *inner; - - if (object != NULL) { - result = omapi_object_new((omapi_object_t **)&waiter, - omapi_type_waiter, sizeof(*waiter)); - if (result != ISC_R_SUCCESS) - return (result); - - /* - * Paste the waiter object onto the inner object we're - * waiting on. - */ - for (inner = object; inner->inner != NULL; - inner = inner->inner) - ; - - OBJECT_REF(&waiter->outer, inner, "omapi_wait_for_completion"); - OBJECT_REF(&inner->inner, waiter, "omapi_wait_for_completion"); - } else - waiter = NULL; - - do { - result = omapi_one_dispatch((omapi_object_t *)waiter, t); - if (result != ISC_R_SUCCESS) - return (result); - } while (waiter == NULL || waiter->ready == 0); - - if (waiter->outer != NULL) { - if (waiter->outer->inner != NULL) { - OBJECT_DEREF(&waiter->outer->inner, - "omapi_wait_for_completion"); - if (waiter->inner != NULL) - OBJECT_REF(&waiter->outer->inner, waiter->inner, - "omapi_wait_for_completion"); - } - OBJECT_DEREF(&waiter->outer, "omapi_wait_for_completion"); - } - if (waiter->inner != NULL) - OBJECT_DEREF(&waiter->inner, "omapi_wait_for_completion"); - - OBJECT_DEREF(&waiter, "omapi_wait_for_completion"); - - return (ISC_R_SUCCESS); -} - -isc_result_t -omapi_one_dispatch(omapi_object_t *wo, struct timeval *t) { - fd_set r, w, x; - int count; - int desc; - int max = 0; - struct timeval now, to; - omapi_io_object_t *io, *prev; - isc_result_t result; - omapi_waiter_object_t *waiter; - - if (wo == NULL || wo->type != omapi_type_waiter) - waiter = NULL; - else - waiter = (omapi_waiter_object_t *)wo; - - FD_ZERO(&r); - FD_ZERO(&w); - FD_ZERO(&x); - - /* - * First, see if the timeout has expired, and if so return. - */ - if (t != NULL) { - gettimeofday(&now, NULL); - cur_time = now.tv_sec; - if (now.tv_sec > t->tv_sec || - (now.tv_sec == t->tv_sec && now.tv_usec >= t->tv_usec)) - return (ISC_R_TIMEDOUT); - - /* - * We didn't time out, so figure out how long until we do. - */ - to.tv_sec = t->tv_sec - now.tv_sec; - to.tv_usec = t->tv_usec - now.tv_usec; - if (to.tv_usec < 0) { - to.tv_usec += 1000000; - to.tv_sec--; - } - } - - /* - * If the object we're waiting on has reached completion, - * return now. - */ - if (waiter != NULL && waiter->ready != 0) - return (ISC_R_SUCCESS); - - /* - * If we have no I/O state, we can't proceed. - */ - io = omapi_io_states.next; - if (io == NULL) - return (ISC_R_NOMORE); - - /* - * Set up the read and write masks. - */ - for (; io != NULL; io = io->next) { - /* - * Check for a read socket. If we shouldn't be - * trying to read for this I/O object, either there - * won't be a readfd function, or it'll return -1. - */ - if (io->readfd != NULL) { - desc = (*(io->readfd))(io->inner); - FD_SET(desc, &r); - if (desc > max) - max = desc; - } - - /* - * Same deal for write fdsets. - */ - if (io->writefd != NULL) { - desc = (*(io->writefd))(io->inner); - FD_SET(desc, &w); - if (desc > max) - max = desc; - } - } - - /* - * Wait for a packet or a timeout. XXXTL - */ - count = select(max + 1, &r, &w, &x, t ? &to : NULL); - - /* - * Get the current time. - */ - gettimeofday(&now, NULL); - cur_time = now.tv_sec; - - /* - * Not likely to be transitory. - */ - if (count < 0) - return (ISC_R_UNEXPECTED); - - for (io = omapi_io_states.next; io != NULL; io = io->next) { - /* - * Check for a read descriptor, and if there is one, - * see if we got input on that socket. - */ - if (io->readfd != NULL && - (desc = (*(io->readfd))(io->inner)) >= 0) { - if (FD_ISSET(desc, &r)) - result = (*(io->reader))(io->inner); - /* XXXTL what to do with result? */ - } - - /* - * Same deal for write descriptors. - */ - if (io->writefd != NULL && - (desc = (*(io->writefd))(io->inner)) >= 0) { - if (FD_ISSET(desc, &w)) - result = (*(io->writer))(io->inner); - /* XXX what to do with result? */ - } - } - - /* - * Now check for I/O handles that are no longer valid, - * and remove them from the list. - */ - prev = NULL; - for (io = omapi_io_states.next; io != NULL; io = io->next) { - if (io->reaper != NULL) { - result = (*(io->reaper))(io->inner); - if (result != ISC_R_SUCCESS) { - omapi_io_object_t *tmp = NULL; - /* - * Save a reference to the next - * pointer, if there is one. - */ - if (io->next != NULL) - OBJECT_REF(&tmp, io->next, "omapi_wfc"); - if (prev != NULL) { - OBJECT_DEREF(&prev->next, "omapi_wfc"); - if (tmp != NULL) - OBJECT_REF(&prev->next, tmp, - "omapi_wfc"); - } else { - OBJECT_DEREF(&omapi_io_states.next, - "omapi_wfc"); - if (tmp != NULL) - OBJECT_REF(&omapi_io_states.next, - tmp, "omapi_wfc"); - else - omapi_signal_in - ((omapi_object_t *) - &omapi_io_states, - "ready"); - } - if (tmp != NULL) - OBJECT_DEREF(&tmp, "omapi_wfc"); - } - } - prev = io; - } - - return (ISC_R_SUCCESS); -} - isc_result_t omapi_io_setvalue(omapi_object_t *io, omapi_object_t *id, omapi_data_string_t *name, omapi_typed_data_t *value) @@ -319,11 +86,14 @@ isc_result_t omapi_waiter_signal_handler(omapi_object_t *h, const char *name, va_list ap) { omapi_waiter_object_t *waiter; + fprintf(stderr, "omapi_waiter_signal_handler\n"); + REQUIRE(h != NULL && h->type == omapi_type_waiter); if (strcmp(name, "ready") == 0) { + fprintf(stderr, "unblocking waiter\n"); waiter = (omapi_waiter_object_t *)h; - waiter->ready = 1; + isc_condition_signal(&waiter->ready); return (ISC_R_SUCCESS); } diff --git a/lib/omapi/generic.c b/lib/omapi/generic.c index 9511c21db3..1429707658 100644 --- a/lib/omapi/generic.c +++ b/lib/omapi/generic.c @@ -15,7 +15,7 @@ * SOFTWARE. */ -/* $Id: generic.c,v 1.5 2000/01/06 23:52:59 tale Exp $ */ +/* $Id: generic.c,v 1.6 2000/01/13 06:13:22 tale Exp $ */ /* Principal Author: Ted Lemon */ @@ -53,7 +53,7 @@ omapi_generic_set_value(omapi_object_t *h, omapi_object_t *id, omapi_value_t *new; omapi_value_t **va; int vm_new; - int i; + unsigned int i; isc_result_t result; REQUIRE(h != NULL && h->type == omapi_type_generic); @@ -129,12 +129,13 @@ omapi_generic_set_value(omapi_object_t *h, omapi_object_t *id, * name/value pair if necessary. */ if (g->nvalues == g->va_max) { - if (g->va_max != 0) - vm_new = 2 * g->va_max; - else - vm_new = 10; + /* + * Increase the maximum number of values by 10. + * 10 is an arbitrary constant. + */ + vm_new = g->va_max + 10; va = isc_mem_get(omapi_mctx, vm_new * sizeof(*va)); - if (va != NULL) + if (va == NULL) return (ISC_R_NOMEMORY); if (g->va_max != 0) { memcpy(va, g->values, g->va_max * sizeof(*va)); @@ -164,7 +165,7 @@ isc_result_t omapi_generic_get_value(omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value) { - int i; + unsigned int i; omapi_generic_object_t *g; REQUIRE(h != NULL && h->type == omapi_type_generic); @@ -181,7 +182,7 @@ omapi_generic_get_value(omapi_object_t *h, omapi_object_t *id, * same as if there were no value that matched * the specified name, so return ISC_R_NOTFOUND. */ - if (g->values[i]->value != NULL) + if (g->values[i]->value == NULL) return (ISC_R_NOTFOUND); /* * Otherwise, return the name/value pair. @@ -198,7 +199,7 @@ omapi_generic_get_value(omapi_object_t *h, omapi_object_t *id, void omapi_generic_destroy(omapi_object_t *h, const char *name) { omapi_generic_object_t *g; - int i; + unsigned int i; REQUIRE(h != NULL && h->type == omapi_type_generic); @@ -235,7 +236,7 @@ omapi_generic_stuff_values(omapi_object_t *connection, omapi_object_t *id, omapi_object_t *h) { omapi_generic_object_t *src; - int i; + unsigned int i; isc_result_t result; REQUIRE(h != NULL && h->type == omapi_type_generic); diff --git a/lib/omapi/handle.c b/lib/omapi/handle.c index e635b43afb..feba1e467b 100644 --- a/lib/omapi/handle.c +++ b/lib/omapi/handle.c @@ -15,7 +15,7 @@ * SOFTWARE. */ -/* $Id: handle.c,v 1.3 2000/01/04 20:04:39 tale Exp $ */ +/* $Id: handle.c,v 1.4 2000/01/13 06:13:23 tale Exp $ */ /* Principal Author: Ted Lemon */ @@ -283,7 +283,7 @@ omapi_handle_lookup_in(omapi_object_t **o, omapi_handle_t h, omapi_handle_table_t *inner; omapi_handle_t scale, index; - if (table != NULL || table->first > h || table->limit <= h) + if (table == NULL || table->first > h || table->limit <= h) return (ISC_R_NOTFOUND); /* diff --git a/lib/omapi/include/omapi/omapip.h b/lib/omapi/include/omapi/omapip.h index a1b527def3..e51d76174a 100644 --- a/lib/omapi/include/omapi/omapip.h +++ b/lib/omapi/include/omapi/omapip.h @@ -27,6 +27,7 @@ #include #include +#include #include ISC_LANG_BEGINDECLS @@ -315,6 +316,10 @@ omapi_connection_stuffvalues(omapi_object_t *connection, omapi_object_t *id, isc_result_t omapi_connection_require(omapi_object_t *connection, unsigned int bytes); +isc_result_t +omapi_connection_wait(omapi_object_t *object, omapi_object_t *connection_handle, + isc_time_t *timeout); + isc_result_t omapi_connection_copyout(unsigned char *data, omapi_object_t *connection, unsigned int length); diff --git a/lib/omapi/include/omapi/private.h b/lib/omapi/include/omapi/private.h index a28dbcb530..856fddb1a5 100644 --- a/lib/omapi/include/omapi/private.h +++ b/lib/omapi/include/omapi/private.h @@ -26,8 +26,10 @@ #include +#include #include #include +#include #include #include #include @@ -67,9 +69,12 @@ typedef struct omapi_message_object { typedef struct omapi_connection_object { OMAPI_OBJECT_PREAMBLE; + isc_mutex_t mutex; isc_socket_t *socket; /* Connection socket. */ isc_task_t *task; - unsigned int events_pending; + unsigned int events_pending; /* socket events */ + unsigned int messages_expected; + isc_condition_t waiter; /* omapi_connection_wait() */ omapi_connection_state_t state; isc_sockaddr_t remote_addr; isc_sockaddr_t local_addr; @@ -91,20 +96,31 @@ typedef struct omapi_connection_object { */ isc_uint32_t out_bytes; isc_bufferlist_t output_buffers; +#if 0 /* * Listener that accepted this connection. * XXXDCL This appears to not be needed. + * ... well, now it is. but it could just be an isc_boolean_t + * that indicates whether this is a server side connection or client. */ omapi_object_t * listener; +#endif + isc_boolean_t is_client; } omapi_connection_object_t; typedef struct omapi_generic_object { OMAPI_OBJECT_PREAMBLE; omapi_value_t ** values; - int nvalues; - int va_max; + unsigned int nvalues; + unsigned int va_max; } omapi_generic_object_t; +typedef struct omapi_waiter_object { + OMAPI_OBJECT_PREAMBLE; + isc_mutex_t mutex; + isc_condition_t ready; +} omapi_waiter_object_t; + /* * Everything needs a memory context. This will likely be made a parameter * where needed rather than a single global context. XXXDCL diff --git a/lib/omapi/listener.c b/lib/omapi/listener.c index 8a1f07ea59..1642042279 100644 --- a/lib/omapi/listener.c +++ b/lib/omapi/listener.c @@ -105,22 +105,17 @@ omapi_listener_accept(isc_task_t *task, isc_event_t *event) { connection->task = connection_task; connection->state = omapi_connection_connected; connection->socket = incoming->newsocket; + connection->is_client = ISC_FALSE; ISC_LIST_INIT(connection->input_buffers); ISC_LIST_APPEND(connection->input_buffers, ibuffer, link); ISC_LIST_INIT(connection->output_buffers); ISC_LIST_APPEND(connection->output_buffers, obuffer, link); - /* - * Point the connection's listener member at the listener object. - * XXXDCL but why is this needed? - */ - listener = event->arg; - OBJECT_REF(&connection->listener, listener, "omapi_listener_accept"); - /* * Notify the listener object that a connection was made. */ + listener = event->arg; result = omapi_signal(listener, "connect", connection); if (result != ISC_R_SUCCESS) /*XXXDCL then what?!*/ diff --git a/lib/omapi/protocol.c b/lib/omapi/protocol.c index c319cdc069..8852b7c0eb 100644 --- a/lib/omapi/protocol.c +++ b/lib/omapi/protocol.c @@ -188,6 +188,7 @@ omapi_protocol_send_message(omapi_object_t *po, omapi_object_t *id, omapi_object_t *c; omapi_message_object_t *m; omapi_message_object_t *om; + omapi_connection_object_t *connection; isc_result_t result; REQUIRE(po != NULL && po->type == omapi_type_protocol && @@ -197,6 +198,7 @@ omapi_protocol_send_message(omapi_object_t *po, omapi_object_t *id, p = (omapi_protocol_object_t *)po; c = (omapi_object_t *)(po->outer); + connection = (omapi_connection_object_t *)c; m = (omapi_message_object_t *)mo; om = (omapi_message_object_t *)omo; @@ -300,9 +302,29 @@ omapi_protocol_send_message(omapi_object_t *po, omapi_object_t *id, /* XXXTL Write the authenticator... */ - connection_send((omapi_connection_object_t *)c); + /* + * When the client sends a message, it expects a reply. + */ + if (connection->is_client) { + result = isc_mutex_lock(&connection->mutex); + if (result != ISC_R_SUCCESS) + goto disconnect; + + connection->messages_expected++; + + result = isc_mutex_unlock(&connection->mutex); + if (result != ISC_R_SUCCESS) + goto disconnect; + + } + + connection_send(connection); return (ISC_R_SUCCESS); + +disconnect: + omapi_connection_disconnect(c, OMAPI_FORCE_DISCONNECT); + return (result); } isc_result_t @@ -311,12 +333,14 @@ omapi_protocol_signal_handler(omapi_object_t *h, const char *name, va_list ap) isc_result_t result; omapi_protocol_object_t *p; omapi_object_t *connection; + omapi_connection_object_t *c; isc_uint16_t nlen; isc_uint32_t vlen; REQUIRE(h != NULL && h->type == omapi_type_protocol); p = (omapi_protocol_object_t *)h; + c = (omapi_connection_object_t *)p->outer; /* * Not a signal we recognize? @@ -328,6 +352,11 @@ omapi_protocol_signal_handler(omapi_object_t *h, const char *name, va_list ap) connection = p->outer; + /* + * XXXDCL figure out how come when this function throws + * an error, it is not seen by the main program. + */ + /* * We get here because we requested that we be woken up after * some number of bytes were read, and that number of bytes @@ -360,10 +389,37 @@ omapi_protocol_signal_handler(omapi_object_t *h, const char *name, va_list ap) return (OMAPI_R_PROTOCOLERROR); } - result = omapi_signal_in(h->inner, "ready"); - if (result != ISC_R_SUCCESS) - /* XXXDCL disconnect? */ - return (result); + /* + * Signal omapi_connection_wait() to wake up. + * Only do this for the client side. + * XXXDCL duplicated below + */ + if (c->is_client) { + result = isc_mutex_lock(&c->mutex); + if (result != ISC_R_SUCCESS) + goto disconnect; + + /* + * This is an unsigned int but on the server it will + * count below 0 for each incoming message received. + * But that's ok, because the server doesn't support + * omapi_connection_wait. + */ + c->messages_expected--; + + result = isc_condition_signal(&c->waiter); + + /* + * Release the lock. Contrary to what you might think + * from some documentation sources, it is necessary + * to do this for the waiting thread to unblock. + */ + if (result == ISC_R_SUCCESS) + result = isc_mutex_unlock(&c->mutex); + + if (result != ISC_R_SUCCESS) + goto disconnect; + } to_header_wait: /* @@ -413,11 +469,10 @@ omapi_protocol_signal_handler(omapi_object_t *h, const char *name, va_list ap) /* * If there was any extra header data, skip over it. */ - if (p->header_size > sizeof(omapi_protocol_header_t)) { - omapi_connection_copyout(0, connection, + if (p->header_size > sizeof(omapi_protocol_header_t)) + omapi_connection_copyout(NULL, connection, (p->header_size - sizeof(omapi_protocol_header_t))); - } /* * XXXTL must compute partial signature across the preceding @@ -530,7 +585,8 @@ omapi_protocol_signal_handler(omapi_object_t *h, const char *name, va_list ap) * Wait for a 32-bit length. */ p->state = omapi_protocol_value_length_wait; - if (omapi_connection_require(connection, 4) != ISC_R_SUCCESS) + result = omapi_connection_require(connection, 4); + if (result != ISC_R_SUCCESS) break; /* @@ -548,9 +604,8 @@ omapi_protocol_signal_handler(omapi_object_t *h, const char *name, va_list ap) if (vlen == 0) goto insert_new_value; - result = omapi_data_new(&p->value, - omapi_datatype_data, vlen, - "omapi_protocol_signal_handler"); + result = omapi_data_new(&p->value, omapi_datatype_data, vlen, + "omapi_protocol_signal_handler"); if (result != ISC_R_SUCCESS) { omapi_connection_disconnect(connection, OMAPI_FORCE_DISCONNECT); @@ -558,7 +613,8 @@ omapi_protocol_signal_handler(omapi_object_t *h, const char *name, va_list ap) } p->state = omapi_protocol_value_wait; - if (omapi_connection_require(connection, vlen) != ISC_R_SUCCESS) + result = omapi_connection_require(connection, vlen); + if (result != ISC_R_SUCCESS) break; /* * If it's already here, fall through. @@ -637,13 +693,38 @@ omapi_protocol_signal_handler(omapi_object_t *h, const char *name, va_list ap) message_done: result = omapi_message_process((omapi_object_t *)p->message, h); - if (result != ISC_R_SUCCESS) { - omapi_connection_disconnect(connection, - OMAPI_FORCE_DISCONNECT); - return (result); + + /* + * Signal omapi_connection_wait() to wake up. + * XXXDCL duplicated from above. + */ + if (c->is_client) { + result = isc_mutex_lock(&c->mutex); + if (result != ISC_R_SUCCESS) + goto disconnect; + + /* + * This is an unsigned int but on the server it will + * count below 0 for each incoming message received. + * But that's ok, because the server doesn't support + * omapi_connection_wait. + */ + c->messages_expected--; + + result = isc_condition_signal(&c->waiter); + if (result != ISC_R_SUCCESS) + goto disconnect; + + result = isc_mutex_unlock(&c->mutex); + if (result != ISC_R_SUCCESS) + goto disconnect; } /* XXXTL unbind the authenticator. */ + + /* + * Free the message object. + */ OBJECT_DEREF(&p->message, "omapi_protocol_signal_handler"); /* @@ -661,6 +742,13 @@ omapi_protocol_signal_handler(omapi_object_t *h, const char *name, va_list ap) } return (ISC_R_SUCCESS); + + /* XXXDCL + * 'goto' could be avoided by wrapping the body in another function. + */ +disconnect: + omapi_connection_disconnect(connection, OMAPI_FORCE_DISCONNECT); + return (result); } isc_result_t diff --git a/lib/omapi/support.c b/lib/omapi/support.c index 119b0ff5a7..e948a80ed1 100644 --- a/lib/omapi/support.c +++ b/lib/omapi/support.c @@ -262,13 +262,16 @@ omapi_signal_in(omapi_object_t *handle, const char *name, ...) { if (handle == NULL) return (ISC_R_NOTFOUND); + va_start(ap, name); - if (handle->type->signal_handler) + if (handle->type->signal_handler != NULL) result = (*(handle->type->signal_handler))(handle, name, ap); else result = ISC_R_NOTFOUND; + va_end(ap); + return (result); } @@ -459,6 +462,7 @@ omapi_object_create(omapi_object_t **obj, omapi_object_t *id, if (type->create == NULL) return (ISC_R_NOTIMPLEMENTED); + return ((*(type->create))(obj, id)); } @@ -468,7 +472,7 @@ omapi_object_update(omapi_object_t *obj, omapi_object_t *id, { omapi_generic_object_t *gsrc; isc_result_t result; - int i; + unsigned int i; REQUIRE(src != NULL);