message.c revision 40f53fa8d9c6a4fc38c0014495e7a42b08f52481
/*
* Copyright (C) 1996-2000 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: message.c,v 1.28 2000/08/01 01:32:56 tale Exp $ */
/*
* Subroutines for dealing with message objects.
*/
#include <config.h>
#include <stddef.h>
omapi_object_t *g;
omapi_type_message, sizeof(*message));
if (result != ISC_R_SUCCESS)
return (result);
g = NULL;
if (result != ISC_R_SUCCESS) {
return (result);
}
OBJECT_REF(o, message);
OBJECT_DEREF(&g);
return (result);
}
/*
* XXXDCL Make register/unregister implicitly part of omapi_message_send?
*/
void
omapi_message_t *m;
m = (omapi_message_t *)h;
/*
* Already registered?
*/
registered_messages != m);
if (registered_messages != NULL) {
}
}
void
omapi_message_t *m;
omapi_message_t *n;
m = (omapi_message_t *)h;
/*
* Not registered?
*/
n = NULL;
OBJECT_REF(&n, m->next);
OBJECT_DEREF(&m->next);
}
OBJECT_DEREF(&m->prev);
if (n != NULL)
OBJECT_DEREF(&tmp);
} else {
if (n != NULL)
}
if (n != NULL)
OBJECT_DEREF(&n);
}
/*
* For this function, at least, generic objects have fully spelled
* names and special type objects have short names.
* XXXDCL It would be good to be more consistent about this throughout
* the omapi library code.
*/
omapi_protocol_t *p;
omapi_message_t *m;
unsigned int authlen = 0;
/*
* Allow the function to be called with an object that is managing
* the client side.
*/
p = (omapi_protocol_t *)protocol;
c = (omapi_connection_t *)connection;
m = (omapi_message_t *)message;
if (result == ISC_R_SUCCESS)
p->dst_update = ISC_TRUE;
}
if (result == ISC_R_SUCCESS)
/* XXXTL Write the ID of the authentication key we're using. */
if (result == ISC_R_SUCCESS)
if (result == ISC_R_SUCCESS)
/*
* Write the opcode.
*/
if (result == ISC_R_SUCCESS)
/*
* Write the handle. If we've been given an explicit handle,
* use that. Otherwise, use the handle of the object we're
* sending. The caller is responsible for arranging for one of
* these handles to be set (or not).
*/
(m->h ? m->h
: (m->object ?
: 0)));
if (result == ISC_R_SUCCESS) {
/*
* Set and write the transaction ID.
*/
}
if (result == ISC_R_SUCCESS)
/*
* Write the transaction ID of the message to which this is a
* response.
*/
if (result == ISC_R_SUCCESS)
/*
*/
if (result == ISC_R_SUCCESS)
/*
* Write the zero-length name that terminates the list of
*/
/*
* that's being sent in the message, if there is one.
*/
if (result == ISC_R_SUCCESS)
/*
* Write the zero-length name length value that terminates
*/
isc_region_t r;
dst_context_destroy(&p->dstctx);
isc_buffer_region(p->signature_out, &r);
p->dst_update = ISC_FALSE;
if (result == ISC_R_SUCCESS)
}
/*
* Prime the bytes_needed for the server's reply message.
* There is no need to lock. In the server everything happens in
* the socket thread so only one event function is running at a time,
* and in the client, there should be no events outstanding which
* would cause the socket thread to access this variable .
*/
if (result == ISC_R_SUCCESS) {
INSIST(c->bytes_needed == 0);
c->bytes_needed = p->header_size;
result = connection_send(c);
/*
* The client waited for the result; the server did not.
* The server's result will always be ISC_R_SUCCESS.
*
* If the client's result is not ISC_R_SUCCESS, the connection
* was already closed by the socket event handler that got
* the error. Unfortunately, it is not known whether
* it was send_done or recv_done that ended the connection;
* if the connection object were not destroyed, one way it
* could be inferred is by seeing whether connection->out_bytes
* is 0.
*
* XXXDCL "connection disconnected"
*/
if (result != ISC_R_SUCCESS)
} else if (c->is_client) {
/*
* One of the calls to omapi_connection_put* or to
* object_stuffvalues failed. As of the time of writing
* this comment, that would pretty much only happen if
* the required output buffer space could be dynamically
* allocated.
*
* The server is in recv_done; let the error propagate back up
* the stack to there, and it will close the connection safely.
* If the server tried to free the connection here, recv_done
* wouldn't be able to distinguish the error from errors
* coming out of parts of the library that did not destroy
* the connection.
*
* The client needs the connection destroyed right here,
* because control is about to return to the driving thread
* and it is guaranteed that if omapi_message_send returns
* an error for any reason, then the connection will be gone.
* Otherwise the client would have the same problem described
* for recv_done on the server -- it wouldn't be able to tell
* whether the error freed the connection.
*/
/*
* The client also needs to be notified the message
* never got sent.
*
* XXXDCL "message not sent; connection disconnected"
*/
}
return (result);
}
omapi_message_t *message, *m;
/*
* Note that the checking of connection->is_client throughout this
* function pretty much means that peer-to-peer transactions can't
* happen over a single connection. It is not clear, yet, whether that
* is such a bad thing, but the original design document didn't
* specify that particular operations were only valid on the client
* or on the server.
*/
break;
/*
* If we don't have a real message corresponding to
* the message ID to which this message claims it is a
* response, something's fishy.
*/
if (m == NULL)
return (ISC_R_NOTFOUND);
} else
m = NULL;
&protocol->signature_in);
}
if (connection->is_client) {
"failed to verify signature");
if (result == ISC_R_SUCCESS)
(void)omapi_object_getvalue(mo,
"message",
&tv);
/*
* This keeps the connection from being blown
* away, although it seems fairly reasonable
* to force a disconnect.
*/
return (ISC_R_SUCCESS);
} else
/*
* XXXDCL Should the key be stricken?
* The curious thing about the way this
* is currently set up is that the status
* message won't verify on the client if
* the secret was wrong ... so rather than
* getting processed in OMAPI_OP_STATUS
* below, it will be handled by this ``if''
* statement on the client.
*/
return (send_status(po,
"failed to verify "
"signature"));
}
}
case OMAPI_OP_OPEN:
if (connection->is_client)
return (ISC_R_UNEXPECTED);
if (m != NULL) {
"OPEN can't be a response"));
}
/*
* Get the type of the requested object, if one was
* specified.
*
* In this and subsequent calls to omapi_object_getvalue,
* an error could be returned, typically ISC_R_NOMEMORY.
* send_status *might* fail if the problem is being out
* of memory ... but it is worth a shot.
*/
if (result == ISC_R_SUCCESS) {
} else if (result == ISC_R_NOTFOUND)
else
/*
* Get the create flag.
*/
if (result == ISC_R_SUCCESS) {
} else if (result == ISC_R_NOTFOUND)
create = 0;
else
/*
* Get the update flag.
*/
if (result == ISC_R_SUCCESS) {
} else if (result == ISC_R_NOTFOUND)
update = 0;
else
/*
* Get the exclusive flag.
*/
if (result == ISC_R_SUCCESS) {
} else if (result == ISC_R_NOTFOUND)
exclusive = 0;
else
/*
* All messages except for the first attempt to set
* the dst key used by the protocol must be signed.
*/
#ifdef notyet /* not for 9.0.0 */
"unauthorized access"));
#endif /* notyet */
/*
* If we weren't given a type, look the object up with
* the handle.
*/
if (create != 0)
"type required on create"));
goto refresh;
}
"no lookup key specified"));
/*
* This is pretty hackish, a special case for an attempt
* to open the protocol object. It was done because
* under the current design of OMAPI, there just isn't
* a good way to set the authentication values. The
* connection object and protocol object are the only
* things that hold state on the server throughout the life
* of a particular connection, and the original design
* for lookup methods does not provide a way to identify
* the current protocol or connection object.
*
* To minimize the hackishness, at least the rest of
* the manipulation of the protocol object is done through
* the normal object interfaces, rather than having a
* a special block do the work directly. Small consolation.
*/
if (type == omapi_type_protocol) {
} else
if (result == ISC_R_NOTIMPLEMENTED)
"unsearchable object type"));
if (result != ISC_R_SUCCESS &&
result != ISC_R_NOTFOUND &&
result != OMAPI_R_NOKEYS)
"object lookup failed"));
/*
* If we didn't find the object and we aren't supposed to
* create it, return an error.
*/
"no object matches specification"));
}
/*
* If we found an object, we're supposed to be creating an
* object, and we're not supposed to have found an object,
* return an error.
*/
"specified object already exists"));
}
/*
* If we're creating the object, do it now.
*/
if (result != ISC_R_SUCCESS)
"can't create new object"));
}
/*
* If we're updating it, do so now.
*/
message->h);
if (result != ISC_R_SUCCESS) {
"can't update object"));
}
}
/*
* Now send the new contents of the object back in response.
*/
goto send;
case OMAPI_OP_REFRESH:
if (connection->is_client)
return (ISC_R_UNEXPECTED);
#ifdef notyet /* not for 9.0.0 */
"unauthorized access"));
#endif /* notyet */
if (result != ISC_R_SUCCESS)
"no matching handle"));
send:
return (result);
case OMAPI_OP_UPDATE:
if (! connection->is_client)
"OMAPI_OP_UPDATE is not a "
"valid server operation"));
else {
if (result != ISC_R_SUCCESS)
"no matching handle"));
}
message->h);
else
if (result != ISC_R_SUCCESS) {
"can't update object"));
if (m != NULL)
object_signal((omapi_object_t *)m,
return (ISC_R_SUCCESS);
}
NULL);
if (m != NULL)
return (result);
case OMAPI_OP_NOTIFY:
"notify not implemented yet"));
case OMAPI_OP_STATUS:
if (! connection->is_client)
"OMAPI_OP_STATUS is not a "
"valid server operation"));
/*
* The return status of a request.
*/
if (m == NULL)
return (ISC_R_UNEXPECTED);
/*
* Get the wait status.
*/
if (result == ISC_R_SUCCESS) {
} else
if (result == ISC_R_SUCCESS)
/*
* Even if the two omapi_object_getvalue calls in this
* section returned errors, the operation is considered
* successful. XXXDCL (should it be?)
*/
return (ISC_R_SUCCESS);
case OMAPI_OP_DELETE:
if (connection->is_client)
return (ISC_R_UNEXPECTED);
"unauthorized delete"));
if (result != ISC_R_SUCCESS)
"no matching handle"));
if (result == ISC_R_NOTIMPLEMENTED)
"no remove method for object"));
}
return (ISC_R_NOTIMPLEMENTED);
}
static isc_result_t
{
omapi_message_t *m;
m = (omapi_message_t *)h;
/*
* Can't set authlen.
*/
/*
* Can set authenticator, but the value must be typed data.
* XXXDCL (no longer meaningful)
*/
if (m->authenticator != NULL)
return (ISC_R_SUCCESS);
OBJECT_DEREF(&m->object);
return (ISC_R_SUCCESS);
if (m->notify_object != NULL)
OBJECT_DEREF(&m->notify_object);
return (ISC_R_SUCCESS);
/*
* Can set authid, but it has to be an integer.
*/
return (ISC_R_SUCCESS);
/*
* Can set op, but it has to be an integer.
*/
return (ISC_R_SUCCESS);
/*
* Handle also has to be an integer.
*/
return (ISC_R_SUCCESS);
/*
* Transaction ID has to be an integer.
*/
return (ISC_R_SUCCESS);
/*
* Remote transaction ID has to be an integer.
*/
return (ISC_R_SUCCESS);
}
/*
* Try to find some inner object that can take the value.
*/
}
static isc_result_t
{
omapi_message_t *m;
m = (omapi_message_t *)h;
/*
* Look for values that are in the message data structure.
*/
if (m->authenticator != NULL)
m->authenticator));
else
return (ISC_R_NOTFOUND);
/*
* See if there's an inner object that has the value.
*/
}
static void
}
static isc_result_t
/*
* XXXDCL It would make the client side a bit cleaner if when "status"
* is signalled, it sets both "waitresult" and "waittext" (or some
* such) in the OMAPI_OBJECT_PREAMBLE of both the message and
* the notify_object or regular object.
*/
ap));
else
}
}
/*
* Write all the published values associated with the object through the
* specified connection.
*/
static isc_result_t
{
}
message_init(void) {
}