mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-29 05:28:00 +00:00
Remove OMAPI.
This commit is contained in:
parent
1b4e6163be
commit
badf66abe0
@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2000, 2001 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: omapi.h,v 1.20 2001/03/04 21:21:35 bwelling Exp $ */
|
||||
|
||||
#ifndef NAMED_OMAPI_H
|
||||
#define NAMED_OMAPI_H 1
|
||||
|
||||
#include <omapi/omapi.h>
|
||||
|
||||
#include <named/aclconf.h>
|
||||
|
||||
#define NS_OMAPI_PORT 953
|
||||
|
||||
/*
|
||||
* This string is the registration name of objects of type control_object_t.
|
||||
*/
|
||||
#define NS_OMAPI_CONTROL "control"
|
||||
|
||||
|
||||
#define NS_OMAPI_COMMAND_STOP "stop"
|
||||
#define NS_OMAPI_COMMAND_HALT "halt"
|
||||
#define NS_OMAPI_COMMAND_RELOAD "reload"
|
||||
#define NS_OMAPI_COMMAND_RELOADCONFIG "reload-config"
|
||||
#define NS_OMAPI_COMMAND_RELOADZONES "reload-zones"
|
||||
#define NS_OMAPI_COMMAND_REFRESH "refresh"
|
||||
#define NS_OMAPI_COMMAND_DUMPSTATS "stats"
|
||||
#define NS_OMAPI_COMMAND_QUERYLOG "querylog"
|
||||
#define NS_OMAPI_COMMAND_DUMPDB "dumpdb"
|
||||
#define NS_OMAPI_COMMAND_TRACE "trace"
|
||||
#define NS_OMAPI_COMMAND_NOTRACE "notrace"
|
||||
|
||||
isc_result_t
|
||||
ns_omapi_init(void);
|
||||
|
||||
isc_result_t
|
||||
ns_omapi_configure(isc_mem_t *mctx, cfg_obj_t *config,
|
||||
ns_aclconfctx_t *aclconfctx);
|
||||
|
||||
void
|
||||
ns_omapi_shutdown(isc_boolean_t exiting);
|
||||
|
||||
#endif /* NAMED_OMAPI_H */
|
@ -1,203 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2000, 2001 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: omapi.c,v 1.32 2001/02/07 00:50:40 bwelling Exp $ */
|
||||
|
||||
/*
|
||||
* Principal Author: DCL
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <isc/app.h>
|
||||
#include <isc/event.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <named/log.h>
|
||||
#include <named/omapi.h>
|
||||
#include <named/server.h>
|
||||
|
||||
/*
|
||||
* The control_object structure is used for receiving commands that
|
||||
* request the server to perform some action, but that do not set or
|
||||
* get any state.
|
||||
*/
|
||||
typedef struct control_object {
|
||||
OMAPI_OBJECT_PREAMBLE;
|
||||
} control_object_t;
|
||||
|
||||
static control_object_t control;
|
||||
static omapi_objecttype_t *control_type;
|
||||
|
||||
#undef REGION_FMT
|
||||
/*
|
||||
* Ok, kind of gross. Sorry. A little.
|
||||
*/
|
||||
#define REGION_FMT(r) (int)(r)->length, (r)->base
|
||||
|
||||
/*
|
||||
* This is the function that is called when an incoming OMAPI_OP_OPEN
|
||||
* message is received with either the create or update option set.
|
||||
* It is called once for each name/value pair in the message's object
|
||||
* value list.
|
||||
*/
|
||||
static isc_result_t
|
||||
control_setvalue(omapi_object_t *handle, omapi_string_t *name,
|
||||
omapi_data_t *value)
|
||||
{
|
||||
isc_region_t region;
|
||||
isc_result_t result;
|
||||
char *args;
|
||||
|
||||
INSIST(handle == (omapi_object_t *)&control);
|
||||
|
||||
omapi_string_totext(name, ®ion);
|
||||
|
||||
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
|
||||
NS_LOGMODULE_OMAPI, ISC_LOG_DEBUG(1),
|
||||
"received control channel command '%.*s'",
|
||||
REGION_FMT(®ion));
|
||||
|
||||
if (value == NULL)
|
||||
return (ISC_R_FAILURE); /* XXX can this happen? */
|
||||
args = omapi_data_strdup(ns_g_mctx, value);
|
||||
if (args == NULL)
|
||||
return (ISC_R_NOMEMORY);
|
||||
|
||||
/*
|
||||
* Compare the 'name' parameter against all known control commands.
|
||||
*/
|
||||
if (omapi_string_strcmp(name, NS_OMAPI_COMMAND_RELOAD) == 0) {
|
||||
result = ns_server_reloadcommand(ns_g_server, args);
|
||||
} else if (omapi_string_strcmp(name, NS_OMAPI_COMMAND_REFRESH) == 0) {
|
||||
result = ns_server_refreshcommand(ns_g_server, args);
|
||||
} else if (omapi_string_strcmp(name, NS_OMAPI_COMMAND_HALT) == 0) {
|
||||
ns_server_flushonshutdown(ns_g_server, ISC_FALSE);
|
||||
isc_app_shutdown();
|
||||
result = ISC_R_SUCCESS;
|
||||
} else if (omapi_string_strcmp(name, NS_OMAPI_COMMAND_STOP) == 0) {
|
||||
ns_server_flushonshutdown(ns_g_server, ISC_TRUE);
|
||||
isc_app_shutdown();
|
||||
result = ISC_R_SUCCESS;
|
||||
} else if (omapi_string_strcmp(name,
|
||||
NS_OMAPI_COMMAND_RELOADCONFIG) == 0 ||
|
||||
omapi_string_strcmp(name,
|
||||
NS_OMAPI_COMMAND_RELOADZONES) == 0) {
|
||||
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
|
||||
NS_LOGMODULE_OMAPI, ISC_LOG_WARNING,
|
||||
"unimplemented channel command '%.*s'",
|
||||
REGION_FMT(®ion));
|
||||
result = ISC_R_NOTIMPLEMENTED;
|
||||
} else if (omapi_string_strcmp(name, NS_OMAPI_COMMAND_DUMPSTATS)
|
||||
== 0) {
|
||||
result = ns_server_dumpstats(ns_g_server);
|
||||
} else if (omapi_string_strcmp(name, NS_OMAPI_COMMAND_QUERYLOG) == 0) {
|
||||
result = ns_server_togglequerylog(ns_g_server);
|
||||
} else if (omapi_string_strcmp(name, NS_OMAPI_COMMAND_DUMPDB) == 0) {
|
||||
ns_server_dumpdb(ns_g_server);
|
||||
result = ISC_R_SUCCESS;
|
||||
} else if (omapi_string_strcmp(name, NS_OMAPI_COMMAND_TRACE) == 0) {
|
||||
result = ns_server_setdebuglevel(ns_g_server, args);
|
||||
} else if (omapi_string_strcmp(name, NS_OMAPI_COMMAND_NOTRACE) == 0) {
|
||||
ns_g_debuglevel = 0;
|
||||
isc_log_setdebuglevel(ns_g_lctx, ns_g_debuglevel);
|
||||
result = ISC_R_SUCCESS;
|
||||
} else {
|
||||
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
|
||||
NS_LOGMODULE_OMAPI, ISC_LOG_WARNING,
|
||||
"unknown control channel command '%.*s'",
|
||||
REGION_FMT(®ion));
|
||||
result = omapi_object_passsetvalue(handle, name, value);
|
||||
}
|
||||
|
||||
isc_mem_free(ns_g_mctx, args);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the function that is called by the library's internal
|
||||
* message_process function when an incoming OMAPI_OP_OPEN message is received.
|
||||
* It is supposed to look up the object in the server that corresponds to the
|
||||
* key data (name/value pair(s)) in 'key'.
|
||||
*/
|
||||
static isc_result_t
|
||||
control_lookup(omapi_object_t **control_object, omapi_object_t *key) {
|
||||
/*
|
||||
* There is only one control object so no key is needed to look it up.
|
||||
*/
|
||||
UNUSED(key);
|
||||
|
||||
omapi_object_reference(control_object, (omapi_object_t *)&control);
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called when the server is sending a reply to a client
|
||||
* that opened an object of its type. It needs to output all published
|
||||
* name/value pairs for the object, and will typically also put the data
|
||||
* for any inner objects (but in this program, there will be no inner
|
||||
* objects). The handle parameter is an object of the type registered
|
||||
* in ns_omapi_listen.
|
||||
*/
|
||||
static isc_result_t
|
||||
control_stuffvalues(omapi_object_t *connection, omapi_object_t *handle) {
|
||||
/*
|
||||
* Currently the server has no values to publish, but it needs
|
||||
* to publish something for its OMAPI_OP_UPDATE function to work
|
||||
* when received by the client.
|
||||
*/
|
||||
return (omapi_object_passstuffvalues(connection, handle));
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
ns_omapi_init(void) {
|
||||
isc_result_t result;
|
||||
|
||||
result = omapi_lib_init(ns_g_mctx, ns_g_taskmgr, ns_g_socketmgr);
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
/*
|
||||
* Register the control_object. NS_OMAPI_CONTROL is
|
||||
* what a client would need to specify as a value for
|
||||
* the value of "type" in a message when contacting
|
||||
* the server to perform a control function.
|
||||
*/
|
||||
result = omapi_object_register(&control_type, NS_OMAPI_CONTROL,
|
||||
control_setvalue,
|
||||
NULL, /* getvalue */
|
||||
NULL, /* destroy */
|
||||
NULL, /* signalhandler */
|
||||
control_stuffvalues,
|
||||
control_lookup,
|
||||
NULL, /* create */
|
||||
NULL); /* remove */
|
||||
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
/*
|
||||
* Initialize the static control object.
|
||||
*/
|
||||
control.refcnt = 1;
|
||||
control.type = control_type;
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
@ -1,660 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2000, 2001 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: omapiconf.c,v 1.17 2001/03/22 00:06:51 bwelling Exp $ */
|
||||
|
||||
/*
|
||||
* Principal Author: DCL
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <isc/base64.h>
|
||||
#include <isc/buffer.h>
|
||||
#include <isc/event.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/once.h>
|
||||
#include <isc/string.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <isccfg/cfg.h>
|
||||
|
||||
#include <dns/result.h>
|
||||
|
||||
#include <named/log.h>
|
||||
#include <named/omapi.h>
|
||||
#include <named/server.h>
|
||||
|
||||
typedef struct ns_omapikey ns_omapikey_t;
|
||||
|
||||
typedef ISC_LIST(ns_omapikey_t) ns_omapikeylist_t;
|
||||
|
||||
struct ns_omapikey {
|
||||
char *keyname;
|
||||
ISC_LINK(ns_omapikey_t) link;
|
||||
};
|
||||
|
||||
typedef struct ns_omapilistener ns_omapilistener_t;
|
||||
|
||||
typedef ISC_LIST(ns_omapilistener_t) ns_omapilistenerlist_t;
|
||||
|
||||
struct ns_omapilistener {
|
||||
/* XXXDCL magic */
|
||||
isc_mem_t * mctx;
|
||||
omapi_object_t * manager;
|
||||
isc_sockaddr_t address;
|
||||
dns_acl_t * acl;
|
||||
ns_omapikeylist_t keyids;
|
||||
ISC_LINK(ns_omapilistener_t) link;
|
||||
};
|
||||
|
||||
static ns_omapilistenerlist_t listeners;
|
||||
static isc_mutex_t listeners_lock;
|
||||
static isc_once_t once = ISC_ONCE_INIT;
|
||||
static isc_boolean_t server_exiting = ISC_FALSE;
|
||||
|
||||
static void
|
||||
initialize_mutex(void) {
|
||||
RUNTIME_CHECK(isc_mutex_init(&listeners_lock) == ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
static void
|
||||
free_omapikeylist(ns_omapikeylist_t *keylist, isc_mem_t *mctx) {
|
||||
while (!ISC_LIST_EMPTY(*keylist)) {
|
||||
ns_omapikey_t *key = ISC_LIST_HEAD(*keylist);
|
||||
ISC_LIST_UNLINK(*keylist, key, link);
|
||||
isc_mem_free(mctx, key->keyname);
|
||||
isc_mem_put(mctx, key, sizeof(*key));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
free_listener(ns_omapilistener_t *listener) {
|
||||
free_omapikeylist(&listener->keyids, listener->mctx);
|
||||
|
||||
if (listener->acl != NULL)
|
||||
dns_acl_detach(&listener->acl);
|
||||
|
||||
if (listener->manager != NULL)
|
||||
omapi_object_dereference(&listener->manager);
|
||||
|
||||
isc_mem_put(listener->mctx, listener, sizeof(*listener));
|
||||
}
|
||||
|
||||
static void
|
||||
listen_done(isc_task_t *task, isc_event_t *event) {
|
||||
ns_omapilistener_t *listener;
|
||||
|
||||
UNUSED(task);
|
||||
|
||||
listener = event->ev_arg;
|
||||
|
||||
LOCK(&listeners_lock);
|
||||
|
||||
ISC_LIST_UNLINK(listeners, listener, link);
|
||||
free_listener(listener);
|
||||
|
||||
if (server_exiting && ISC_LIST_EMPTY(listeners))
|
||||
omapi_lib_destroy();
|
||||
|
||||
UNLOCK(&listeners_lock);
|
||||
|
||||
isc_event_free(&event);
|
||||
}
|
||||
|
||||
void
|
||||
ns_omapi_shutdown(isc_boolean_t exiting) {
|
||||
ns_omapilistener_t *listener;
|
||||
|
||||
RUNTIME_CHECK(isc_once_do(&once, initialize_mutex) == ISC_R_SUCCESS);
|
||||
|
||||
if (exiting) {
|
||||
/*
|
||||
* When not exiting, this function is called from
|
||||
* ns_omapi_configure(), which already holds the lock.
|
||||
*/
|
||||
LOCK(&listeners_lock);
|
||||
|
||||
if (ISC_LIST_EMPTY(listeners))
|
||||
omapi_lib_destroy();
|
||||
else
|
||||
server_exiting = exiting;
|
||||
}
|
||||
|
||||
for (listener = ISC_LIST_HEAD(listeners);
|
||||
listener != NULL;
|
||||
listener = ISC_LIST_NEXT(listener, link))
|
||||
/*
|
||||
* This is asynchronous. As listeners shut down, they will
|
||||
* call listen_done().
|
||||
*/
|
||||
omapi_listener_shutdown(listener->manager);
|
||||
|
||||
if (exiting)
|
||||
UNLOCK(&listeners_lock);
|
||||
}
|
||||
|
||||
static isc_boolean_t
|
||||
verify_connection(isc_sockaddr_t *sockaddr, void *arg) {
|
||||
ns_omapilistener_t *listener;
|
||||
isc_netaddr_t netaddr;
|
||||
isc_result_t result;
|
||||
int match;
|
||||
|
||||
isc_netaddr_fromsockaddr(&netaddr, sockaddr);
|
||||
listener = arg;
|
||||
|
||||
result = dns_acl_match(&netaddr, NULL, listener->acl,
|
||||
&ns_g_server->aclenv, &match, NULL);
|
||||
|
||||
if (result != ISC_R_SUCCESS || match <= 0)
|
||||
return (ISC_FALSE);
|
||||
else
|
||||
return (ISC_TRUE);
|
||||
}
|
||||
|
||||
static isc_boolean_t
|
||||
omapikeylist_find(ns_omapikeylist_t *keylist, const char *keyname) {
|
||||
ns_omapikey_t *key;
|
||||
|
||||
for (key = ISC_LIST_HEAD(*keylist);
|
||||
key != NULL;
|
||||
key = ISC_LIST_NEXT(key, link))
|
||||
{
|
||||
if (strcasecmp(keyname, key->keyname) == 0)
|
||||
return (ISC_TRUE);
|
||||
}
|
||||
return (ISC_FALSE);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
cfgkeylist_find(cfg_obj_t *keylist, const char *keyname, cfg_obj_t **objp) {
|
||||
cfg_listelt_t *element;
|
||||
const char *str;
|
||||
cfg_obj_t *obj;
|
||||
|
||||
for (element = cfg_list_first(keylist);
|
||||
element != NULL;
|
||||
element = cfg_list_next(element))
|
||||
{
|
||||
obj = cfg_listelt_value(element);
|
||||
str = cfg_obj_asstring(cfg_map_getname(obj));
|
||||
if (strcasecmp(str, keyname) == 0)
|
||||
break;
|
||||
}
|
||||
if (element == NULL)
|
||||
return (ISC_R_NOTFOUND);
|
||||
obj = cfg_listelt_value(element);
|
||||
*objp = obj;
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
omapikeylist_fromcfg(cfg_obj_t *keylist, isc_mem_t *mctx,
|
||||
ns_omapikeylist_t *keyids)
|
||||
{
|
||||
cfg_listelt_t *element;
|
||||
char *newstr = NULL;
|
||||
const char *str;
|
||||
cfg_obj_t *obj;
|
||||
ns_omapikey_t *key = NULL;
|
||||
|
||||
for (element = cfg_list_first(keylist);
|
||||
element != NULL;
|
||||
element = cfg_list_next(element))
|
||||
{
|
||||
obj = cfg_listelt_value(element);
|
||||
str = cfg_obj_asstring(obj);
|
||||
newstr = isc_mem_strdup(mctx, str);
|
||||
if (newstr == NULL)
|
||||
goto cleanup;
|
||||
key = isc_mem_get(mctx, sizeof(*key));
|
||||
if (key == NULL)
|
||||
goto cleanup;
|
||||
key->keyname = newstr;
|
||||
ISC_LINK_INIT(key, link);
|
||||
ISC_LIST_APPEND(*keyids, key, link);
|
||||
key = NULL;
|
||||
newstr = NULL;
|
||||
}
|
||||
return (ISC_R_SUCCESS);
|
||||
|
||||
cleanup:
|
||||
if (newstr != NULL)
|
||||
isc_mem_free(mctx, newstr);
|
||||
if (key != NULL)
|
||||
isc_mem_put(mctx, key, sizeof(*key));
|
||||
free_omapikeylist(keyids, mctx);
|
||||
return (ISC_R_NOMEMORY);
|
||||
}
|
||||
|
||||
static isc_boolean_t
|
||||
verify_key(const char *name, unsigned int algorithm, void *arg) {
|
||||
ns_omapilistener_t *listener;
|
||||
|
||||
/*
|
||||
* XXXDCL Ideally algorithm would be checked, too, but the current
|
||||
* config API makes this moderately hard, and omapi will check it
|
||||
* anyway.
|
||||
*/
|
||||
UNUSED(algorithm);
|
||||
|
||||
listener = arg;
|
||||
|
||||
return (omapikeylist_find(&listener->keyids, name));
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
ns_omapi_listen(ns_omapilistener_t *listener) {
|
||||
isc_result_t result;
|
||||
|
||||
REQUIRE(listener->manager == NULL);
|
||||
|
||||
/*
|
||||
* Create a generic object to be the manager for handling
|
||||
* incoming server connections.
|
||||
*/
|
||||
result = omapi_object_create(&listener->manager, NULL, 0);
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
/*
|
||||
* Start listening for connections.
|
||||
*/
|
||||
result = omapi_protocol_listen(listener->manager,
|
||||
&listener->address,
|
||||
verify_connection, verify_key,
|
||||
listen_done, listener);
|
||||
|
||||
if (result != ISC_R_SUCCESS && listener->manager != NULL)
|
||||
omapi_object_dereference(&listener->manager);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
static void
|
||||
register_keys(cfg_obj_t *control, cfg_obj_t *keylist, char *socktext) {
|
||||
char *keyid;
|
||||
cfg_obj_t *key;
|
||||
cfg_obj_t *keydef;
|
||||
cfg_listelt_t *element;
|
||||
char secret[1024];
|
||||
isc_buffer_t b;
|
||||
isc_result_t result;
|
||||
|
||||
/*
|
||||
* Register the keys used by this listener. omapi_auth_deregister()
|
||||
* is used to delete any existing key in case its secret or algorithm
|
||||
* changed.
|
||||
*
|
||||
* XXXDCL but this means a little extra work overall when nothing
|
||||
* changed. In fact, the same key will be register/deregistered/
|
||||
* reregistered if it appears more than once in the controls statement.
|
||||
*
|
||||
* XXXDCL a separate problem is that keys that have been removed
|
||||
* from the controls statement in a reconfiguration are not deleted
|
||||
* until the server shuts down.
|
||||
*/
|
||||
for (element = cfg_list_first(keylist);
|
||||
element != NULL;
|
||||
element = cfg_list_next(element))
|
||||
{
|
||||
key = cfg_listelt_value(element);
|
||||
keyid = cfg_obj_asstring(cfg_map_getname(key));
|
||||
|
||||
omapi_auth_deregister(keyid);
|
||||
|
||||
/*
|
||||
* XXXDCL confparser.y apparently allows any keyid
|
||||
* in the list even if it has not been defined with
|
||||
* the keys statement.
|
||||
*/
|
||||
keydef = NULL;
|
||||
result = cfgkeylist_find(keylist, keyid, &keydef);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
|
||||
"couldn't find key %s for use with "
|
||||
"command channel %s", keyid, socktext);
|
||||
else {
|
||||
cfg_obj_t *algobj = NULL;
|
||||
cfg_obj_t *secretobj = NULL;
|
||||
char *algstr = NULL;
|
||||
char *secretstr = NULL;
|
||||
|
||||
(void)cfg_map_get(keydef, "algorithm", &algobj);
|
||||
(void)cfg_map_get(keydef, "secret", &secretobj);
|
||||
INSIST(algobj != NULL && secretobj != NULL);
|
||||
|
||||
algstr = cfg_obj_asstring(algobj);
|
||||
secretstr = cfg_obj_asstring(secretobj);
|
||||
|
||||
if (strcasecmp(algstr, "hmac-md5") != 0) {
|
||||
cfg_obj_log(control, ns_g_lctx,
|
||||
ISC_LOG_WARNING,
|
||||
"unsupported algorithm '%s' in "
|
||||
"key '%s' for use with command "
|
||||
"channel %s",
|
||||
algstr, keyid, socktext);
|
||||
continue;
|
||||
}
|
||||
|
||||
isc_buffer_init(&b, secret, sizeof(secret));
|
||||
result = isc_base64_decodestring(secretstr, &b);
|
||||
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
cfg_obj_log(keydef, ns_g_lctx, ISC_LOG_WARNING,
|
||||
"secret for key '%s' on "
|
||||
"command channel %s: %s",
|
||||
keyid, socktext,
|
||||
isc_result_totext(result));
|
||||
continue;
|
||||
}
|
||||
|
||||
result = omapi_auth_register(keyid,
|
||||
OMAPI_AUTH_HMACMD5,
|
||||
isc_buffer_base(&b),
|
||||
isc_buffer_usedlength(&b));
|
||||
|
||||
if (result != ISC_R_SUCCESS)
|
||||
cfg_obj_log(keydef, ns_g_lctx, ISC_LOG_WARNING,
|
||||
"couldn't register key '%s' for"
|
||||
"use with command channel %s: %s",
|
||||
keyid, socktext,
|
||||
isc_result_totext(result));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
update_listener(ns_omapilistener_t **listenerp, cfg_obj_t *control,
|
||||
cfg_obj_t *config, isc_sockaddr_t *addr,
|
||||
ns_aclconfctx_t *aclconfctx, char *socktext)
|
||||
{
|
||||
ns_omapilistener_t *listener;
|
||||
cfg_obj_t *allow;
|
||||
cfg_obj_t *keys;
|
||||
dns_acl_t *new_acl = NULL;
|
||||
ns_omapikeylist_t keyids;
|
||||
isc_result_t result;
|
||||
|
||||
for (listener = ISC_LIST_HEAD(listeners);
|
||||
listener != NULL;
|
||||
listener = ISC_LIST_NEXT(listener, link))
|
||||
if (isc_sockaddr_equal(addr, &listener->address))
|
||||
break;
|
||||
|
||||
if (listener == NULL) {
|
||||
*listenerp = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* There is already a listener for this sockaddr.
|
||||
* Update the access list and key information.
|
||||
*
|
||||
* First, keep the old access list unless a new one can be made.
|
||||
*/
|
||||
allow = cfg_tuple_get(control, "allow");
|
||||
result = ns_acl_fromconfig(allow, config, aclconfctx,
|
||||
listener->mctx, &new_acl);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
dns_acl_detach(&listener->acl);
|
||||
dns_acl_attach(new_acl, &listener->acl);
|
||||
dns_acl_detach(&new_acl);
|
||||
} else
|
||||
/* XXXDCL say the old acl is still used? */
|
||||
cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
|
||||
"couldn't install new acl for "
|
||||
"command channel %s: %s",
|
||||
socktext, isc_result_totext(result));
|
||||
|
||||
keys = cfg_tuple_get(control, "keys");
|
||||
ISC_LIST_INIT(keyids);
|
||||
result = omapikeylist_fromcfg(keys, listener->mctx, &keyids);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
|
||||
"couldn't install new keys for "
|
||||
"command channel %s: %s",
|
||||
socktext, isc_result_totext(result));
|
||||
else {
|
||||
free_omapikeylist(&listener->keyids, listener->mctx);
|
||||
listener->keyids = keyids;
|
||||
}
|
||||
|
||||
*listenerp = listener;
|
||||
}
|
||||
|
||||
static void
|
||||
add_listener(isc_mem_t *mctx, ns_omapilistener_t **listenerp,
|
||||
cfg_obj_t *control, cfg_obj_t *config, isc_sockaddr_t *addr,
|
||||
ns_aclconfctx_t *aclconfctx, char *socktext)
|
||||
{
|
||||
ns_omapilistener_t *listener;
|
||||
cfg_obj_t *allow;
|
||||
cfg_obj_t *keys;
|
||||
dns_acl_t *new_acl = NULL;
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
|
||||
listener = isc_mem_get(mctx, sizeof(ns_omapilistener_t));
|
||||
if (listener == NULL)
|
||||
result = ISC_R_NOMEMORY;
|
||||
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
listener->mctx = mctx;
|
||||
listener->manager = NULL;
|
||||
listener->address = *addr;
|
||||
ISC_LINK_INIT(listener, link);
|
||||
ISC_LIST_INIT(listener->keyids);
|
||||
|
||||
/*
|
||||
* Make the acl.
|
||||
*/
|
||||
allow = cfg_tuple_get(control, "allow");
|
||||
result = ns_acl_fromconfig(allow, config, aclconfctx, mctx,
|
||||
&new_acl);
|
||||
}
|
||||
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
dns_acl_attach(new_acl, &listener->acl);
|
||||
dns_acl_detach(&new_acl);
|
||||
|
||||
keys = cfg_tuple_get(control, "keys");
|
||||
result = omapikeylist_fromcfg(keys, listener->mctx,
|
||||
&listener->keyids);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
|
||||
"couldn't install new keys for "
|
||||
"command channel %s: %s",
|
||||
socktext, isc_result_totext(result));
|
||||
}
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
result = ns_omapi_listen(listener);
|
||||
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
isc_log_write(ns_g_lctx, ISC_LOGCATEGORY_GENERAL,
|
||||
NS_LOGMODULE_OMAPI, ISC_LOG_NOTICE,
|
||||
"command channel listening on %s", socktext);
|
||||
*listenerp = listener;
|
||||
|
||||
} else {
|
||||
if (listener != NULL)
|
||||
free_listener(listener);
|
||||
|
||||
cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING,
|
||||
"couldn't add command channel %s: %s",
|
||||
socktext, isc_result_totext(result));
|
||||
|
||||
*listenerp = NULL;
|
||||
}
|
||||
|
||||
/* XXXDCL return error results? fail hard? */
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
ns_omapi_configure(isc_mem_t *mctx, cfg_obj_t *config,
|
||||
ns_aclconfctx_t *aclconfctx)
|
||||
{
|
||||
ns_omapilistener_t *listener;
|
||||
ns_omapilistenerlist_t new_listeners;
|
||||
cfg_obj_t *controlslist = NULL;
|
||||
cfg_obj_t *keylist = NULL;
|
||||
cfg_listelt_t *element, *element2;
|
||||
char socktext[ISC_SOCKADDR_FORMATSIZE];
|
||||
|
||||
RUNTIME_CHECK(isc_once_do(&once, initialize_mutex) == ISC_R_SUCCESS);
|
||||
|
||||
ISC_LIST_INIT(new_listeners);
|
||||
|
||||
/*
|
||||
* Get te list of named.conf 'controls' statements.
|
||||
*/
|
||||
(void)cfg_map_get(config, "controls", &controlslist);
|
||||
|
||||
LOCK(&listeners_lock);
|
||||
/*
|
||||
* Run through the new control channel list, noting sockets that
|
||||
* are already being listened on and moving them to the new list.
|
||||
*
|
||||
* Identifying duplicates addr/port combinations is left to either
|
||||
* the underlying config code, or to the bind attempt getting an
|
||||
* address-in-use error.
|
||||
*/
|
||||
if (controlslist != NULL) {
|
||||
(void)cfg_map_get(config, "key", &keylist);
|
||||
if (keylist == NULL)
|
||||
cfg_obj_log(controlslist, ns_g_lctx, ISC_LOG_WARNING,
|
||||
"no key statements for use by "
|
||||
"control channels");
|
||||
|
||||
for (element = cfg_list_first(controlslist);
|
||||
element != NULL;
|
||||
element = cfg_list_next(element))
|
||||
{
|
||||
cfg_obj_t *controls;
|
||||
cfg_obj_t *inetcontrols = NULL;
|
||||
|
||||
controls = cfg_listelt_value(element);
|
||||
(void)cfg_map_get(controls, "inet", &inetcontrols);
|
||||
if (inetcontrols == NULL)
|
||||
continue;
|
||||
|
||||
for (element2 = cfg_list_first(inetcontrols);
|
||||
element2 != NULL;
|
||||
element2 = cfg_list_next(element2))
|
||||
{
|
||||
cfg_obj_t *control;
|
||||
cfg_obj_t *obj;
|
||||
isc_sockaddr_t *addr;
|
||||
|
||||
/*
|
||||
* The parser handles BIND 8 configuration file
|
||||
* syntax, so it allows unix phrases as well
|
||||
* inet phrases with no keys{} clause.
|
||||
*
|
||||
* "unix" phrases have been reported as
|
||||
* unsupported by the parser.
|
||||
*
|
||||
* The keylist == NULL case was already warned
|
||||
* about a few lines above.
|
||||
*/
|
||||
control = cfg_listelt_value(element2);
|
||||
|
||||
obj = cfg_tuple_get(control, "address");
|
||||
addr = cfg_obj_assockaddr(obj);
|
||||
if (isc_sockaddr_getport(addr) == 0)
|
||||
isc_sockaddr_setport(addr,
|
||||
NS_OMAPI_PORT);
|
||||
|
||||
isc_sockaddr_format(addr, socktext,
|
||||
sizeof(socktext));
|
||||
|
||||
obj = cfg_tuple_get(control, "keys");
|
||||
|
||||
if (cfg_obj_isvoid(obj)) {
|
||||
cfg_obj_log(obj, ns_g_lctx,
|
||||
ISC_LOG_ERROR,
|
||||
"no keys clause in "
|
||||
"control channel %s",
|
||||
socktext);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cfg_list_first(obj) == NULL) {
|
||||
cfg_obj_log(obj, ns_g_lctx,
|
||||
ISC_LOG_ERROR,
|
||||
"no keys specified in "
|
||||
"control channel %s",
|
||||
socktext);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (keylist == NULL)
|
||||
continue;
|
||||
|
||||
isc_log_write(ns_g_lctx,
|
||||
ISC_LOGCATEGORY_GENERAL,
|
||||
NS_LOGMODULE_OMAPI,
|
||||
ISC_LOG_DEBUG(9),
|
||||
"processing control channel %s",
|
||||
socktext);
|
||||
|
||||
register_keys(control, keylist, socktext);
|
||||
|
||||
update_listener(&listener, control, config,
|
||||
addr, aclconfctx, socktext);
|
||||
|
||||
if (listener != NULL)
|
||||
/*
|
||||
* Remove the listener from the old
|
||||
* list, so it won't be shut down.
|
||||
*/
|
||||
ISC_LIST_UNLINK(listeners, listener,
|
||||
link);
|
||||
else
|
||||
/*
|
||||
* This is a new listener.
|
||||
*/
|
||||
add_listener(mctx, &listener, control,
|
||||
config, addr, aclconfctx,
|
||||
socktext);
|
||||
|
||||
if (listener != NULL)
|
||||
ISC_LIST_APPEND(new_listeners,
|
||||
listener, link);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ns_omapi_shutdown() will stop whatever is on the global listeners
|
||||
* list, which currently only has whatever sockaddr was in the previous
|
||||
* configuration (if any) that does not remain in the current
|
||||
* configuration.
|
||||
*/
|
||||
ns_omapi_shutdown(ISC_FALSE);
|
||||
|
||||
/*
|
||||
* Put all of the valid listeners on the listeners list.
|
||||
* Anything already on listeners in the process of shutting down
|
||||
* will be taken care of by listen_done().
|
||||
*/
|
||||
ISC_LIST_APPENDLIST(listeners, new_listeners, link);
|
||||
|
||||
UNLOCK(&listeners_lock);
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
@ -13,7 +13,7 @@
|
||||
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
||||
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
# $Id: Makefile.in,v 1.111 2001/03/13 02:47:15 bwelling Exp $
|
||||
# $Id: Makefile.in,v 1.112 2001/03/27 00:53:16 bwelling Exp $
|
||||
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
@ -30,13 +30,11 @@ CWARNINGS =
|
||||
DNSLIBS = ../../lib/dns/libdns.@A@ @DNS_OPENSSL_LIBS@ @DNS_GSSAPI_LIBS@
|
||||
ISCLIBS = ../../lib/isc/libisc.@A@
|
||||
ISCCFGLIBS = ../../lib/isccfg/libisccfg.@A@
|
||||
OMAPILIBS = ../../lib/omapi/libomapi.@A@
|
||||
LWRESLIBS = ../../lib/lwres/liblwres.@A@
|
||||
|
||||
DNSDEPLIBS = ../../lib/dns/libdns.@A@
|
||||
ISCDEPLIBS = ../../lib/isc/libisc.@A@
|
||||
ISCCFGDEPLIBS = ../../lib/isccfg/libisccfg.@A@
|
||||
OMAPIDEPLIBS = ../../lib/omapi/libomapi.@A@
|
||||
LWRESDEPLIBS = ../../lib/lwres/liblwres.@A@
|
||||
|
||||
LIBS = @LIBS@
|
||||
@ -70,7 +68,6 @@ XTARGETS = adb_test \
|
||||
mempool_test \
|
||||
name_test \
|
||||
nxtify \
|
||||
omapi_test \
|
||||
ratelimiter_test \
|
||||
rbt_test \
|
||||
rdata_test \
|
||||
@ -109,7 +106,6 @@ SRCS = adb_test.c \
|
||||
mempool_test.c \
|
||||
name_test.c \
|
||||
nxtify.c \
|
||||
omapi_test.c \
|
||||
printmsg.c \
|
||||
ratelimiter_test.c \
|
||||
rbt_test.c \
|
||||
@ -164,10 +160,6 @@ name_test: name_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
|
||||
${LIBTOOL} ${PURIFY} ${CC} ${CFLAGS} -o $@ name_test.@O@ \
|
||||
${DNSLIBS} ${ISCLIBS} ${LIBS}
|
||||
|
||||
omapi_test: omapi_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} ${OMAPIDEPLIBS}
|
||||
${LIBTOOL} ${PURIFY} ${CC} ${CFLAGS} -o $@ omapi_test.@O@ \
|
||||
${OMAPILIBS} ${DNSLIBS} ${ISCLIBS} ${LIBS}
|
||||
|
||||
hash_test: hash_test.@O@ ${ISCDEPLIBS}
|
||||
${LIBTOOL} ${PURIFY} ${CC} ${CFLAGS} -o $@ hash_test.@O@ \
|
||||
${ISCLIBS} ${LIBS}
|
||||
|
@ -1,759 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1996-2001 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: omapi_test.c,v 1.29 2001/02/16 01:00:42 bwelling Exp $ */
|
||||
|
||||
/*
|
||||
* Test code for OMAPI.
|
||||
*/
|
||||
#include <config.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <isc/commandline.h>
|
||||
#include <isc/condition.h>
|
||||
#include <isc/entropy.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/socket.h>
|
||||
#include <isc/string.h>
|
||||
#include <isc/task.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <dns/acl.h>
|
||||
|
||||
#include <dst/dst.h>
|
||||
#include <dst/result.h>
|
||||
|
||||
#include <omapi/omapi.h>
|
||||
|
||||
char *progname;
|
||||
isc_mem_t *mctx;
|
||||
|
||||
isc_boolean_t error_noobject = ISC_FALSE;
|
||||
isc_boolean_t error_nosig = ISC_FALSE;
|
||||
isc_boolean_t error_badsig = ISC_FALSE;
|
||||
isc_boolean_t error_unknownsig = ISC_FALSE;
|
||||
isc_boolean_t error_denyall = ISC_FALSE;
|
||||
|
||||
/*
|
||||
* Two different structures are used in this program to store the
|
||||
* value of interest on both the client and the server, but the
|
||||
* same structure can be used on each if desired (with the other variables
|
||||
* that are not in common between them being stored elsewhere).
|
||||
*/
|
||||
typedef struct server_object {
|
||||
OMAPI_OBJECT_PREAMBLE;
|
||||
unsigned long value;
|
||||
isc_boolean_t target_reached;
|
||||
} server_object_t;
|
||||
|
||||
typedef struct client_object {
|
||||
OMAPI_OBJECT_PREAMBLE;
|
||||
unsigned long value;
|
||||
} client_object_t;
|
||||
|
||||
static server_object_t master_data;
|
||||
|
||||
static omapi_objecttype_t *server_type;
|
||||
static omapi_objecttype_t *client_type;
|
||||
|
||||
static isc_condition_t waiter;
|
||||
static isc_mutex_t mutex;
|
||||
|
||||
/*
|
||||
* This is a string that names the registry of objects of type server_object_t.
|
||||
*/
|
||||
#define SERVER_OBJECT_TYPE "test-data"
|
||||
|
||||
/*
|
||||
* This is the name of the variable that is being manipulated in the server.
|
||||
* Note that it necessarily has no direct relevance to the *real* name of
|
||||
* the variable (but of course, making them the same would make for clearer
|
||||
* programming).
|
||||
*/
|
||||
#define MASTER_VALUE "amount"
|
||||
|
||||
#define KEY1_NAME "test-key"
|
||||
#define KEY2_NAME "another-key"
|
||||
|
||||
/*
|
||||
* Create an OMAPI message on the client that requests an object on the
|
||||
* server be opened. If the boolean 'update' is given, then the value
|
||||
* of the client's object will set the value of the server's object,
|
||||
* otherwise the server just refreshes the values in the client's object
|
||||
* with the master data.
|
||||
*/
|
||||
static isc_result_t
|
||||
open_object(omapi_object_t *handle, omapi_object_t *manager,
|
||||
isc_boolean_t update)
|
||||
{
|
||||
omapi_object_t *message = NULL;
|
||||
|
||||
REQUIRE(handle->type == client_type);
|
||||
|
||||
/*
|
||||
* Create a new message object to store the information that will
|
||||
* be sent to the server.
|
||||
*/
|
||||
RUNTIME_CHECK(omapi_message_create(&message) == ISC_R_SUCCESS);
|
||||
|
||||
/*
|
||||
* Specify the OPEN operation, and the UPDATE option if requested.
|
||||
*/
|
||||
RUNTIME_CHECK(omapi_object_setinteger(message, "op", OMAPI_OP_OPEN)
|
||||
== ISC_R_SUCCESS);
|
||||
if (update)
|
||||
RUNTIME_CHECK(omapi_object_setboolean(message, "update",
|
||||
ISC_TRUE)
|
||||
== ISC_R_SUCCESS);
|
||||
|
||||
/*
|
||||
* Tell the server the type of the object being opened; it needs
|
||||
* to know this so that it can apply the proper object methods
|
||||
* for lookup/setvalue.
|
||||
*/
|
||||
RUNTIME_CHECK(omapi_object_setstring(message, "type",
|
||||
SERVER_OBJECT_TYPE)
|
||||
== ISC_R_SUCCESS);
|
||||
|
||||
/*
|
||||
* Associate the client object with the message, so that it
|
||||
* will have its values stuffed in the message. Without it,
|
||||
* the OPEN operation will fail because there is no name/value
|
||||
* pair to use as a key for looking up the desired object at
|
||||
* the server.
|
||||
*/
|
||||
if (! error_noobject)
|
||||
RUNTIME_CHECK(omapi_object_setobject(message, "object", handle)
|
||||
== ISC_R_SUCCESS);
|
||||
|
||||
/*
|
||||
* Set up an object that will receive the "status" signal in its
|
||||
* signal handler when the response is received from the server.
|
||||
* This is not needed as a general rule, because normally the
|
||||
* the object associated with the name "object" in the message
|
||||
* is what gets that message. However, in this case the
|
||||
* particular error that is being tested when error_noobject is true
|
||||
* is one where no item named "object" has been set, so not only
|
||||
* can it not be used as a key when the server gets the message,
|
||||
* it can't be used to get the "status" signal on the client
|
||||
* when the server's "no key" error message comes back.
|
||||
*
|
||||
* If both "object" and "notify-object" are set, only the latter
|
||||
* will receive the signal (as currently written; it was originally
|
||||
* the other way 'round). In this particular case it hardly matters,
|
||||
* as both "object" and "notify-object" are the same object.
|
||||
*/
|
||||
RUNTIME_CHECK(omapi_object_setobject(message, "notify-object", handle)
|
||||
== ISC_R_SUCCESS);
|
||||
|
||||
/*
|
||||
* Add the new message to the list of known messages. When the
|
||||
* server's response comes back, the client will verify that
|
||||
* the response was for a message it really sent.
|
||||
*/
|
||||
omapi_message_register(message);
|
||||
|
||||
/*
|
||||
* Deliver the message to the server. The manager's outer object
|
||||
* is the connection object to the server.
|
||||
*/
|
||||
RUNTIME_CHECK(omapi_message_send(message, manager) == ISC_R_SUCCESS);
|
||||
|
||||
/*
|
||||
* Free the message.
|
||||
*/
|
||||
omapi_message_unregister(message);
|
||||
omapi_object_dereference(&message);
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* client_setvalue() is called on the client by the library's internal
|
||||
* message_process() function when the server replies to the OPEN operation
|
||||
* with its own REFRESH message for the client. It is how the client learns
|
||||
* what data is on the server.
|
||||
*/
|
||||
static isc_result_t
|
||||
client_setvalue(omapi_object_t *handle, omapi_string_t *name,
|
||||
omapi_data_t *value)
|
||||
|
||||
{
|
||||
isc_region_t region;
|
||||
client_object_t *client;
|
||||
|
||||
REQUIRE(handle->type == client_type);
|
||||
|
||||
client = (client_object_t *)handle;
|
||||
|
||||
/*
|
||||
* Only the MASTER_VALUE value has meaning in this program.
|
||||
*/
|
||||
if (omapi_string_strcmp(name, MASTER_VALUE) == 0) {
|
||||
client->value = omapi_data_getint(value);
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
} else if (omapi_string_strcmp(name, "remote-handle") == 0) {
|
||||
/*
|
||||
* The server will also set "remote-handle" to let the client
|
||||
* have an identifier for the object on the server that could
|
||||
* be used with the other OMAPI operations, such as
|
||||
* OMAPI_OP_DELETE. The value of remote-handle is an integer,
|
||||
* fetched with:
|
||||
* omapi_data_getint(&remote_handle, value).
|
||||
*
|
||||
* It is not used by this test program.
|
||||
*/
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
omapi_string_totext(name, ®ion);
|
||||
fprintf(stderr, "client_setvalue: unknown name: '%.*s'\n",
|
||||
(int)region.length, region.base);
|
||||
|
||||
return (ISC_R_NOTFOUND);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is used by omapi_message_send to publish the values of
|
||||
* the data in a client object.
|
||||
*/
|
||||
static isc_result_t
|
||||
client_stuffvalues(omapi_object_t *connection, omapi_object_t *handle) {
|
||||
client_object_t *client;
|
||||
|
||||
REQUIRE(handle->type == client_type);
|
||||
|
||||
client = (client_object_t *)handle;
|
||||
|
||||
/*
|
||||
* Write the MASTER_VALUE name, followed by the value length,
|
||||
* follwed by its value.
|
||||
*/
|
||||
RUNTIME_CHECK(omapi_connection_putname(connection, MASTER_VALUE)
|
||||
== ISC_R_SUCCESS);
|
||||
|
||||
RUNTIME_CHECK(omapi_connection_putuint32(connection,
|
||||
sizeof(isc_uint32_t))
|
||||
== ISC_R_SUCCESS);
|
||||
|
||||
RUNTIME_CHECK(omapi_connection_putuint32(connection, client->value)
|
||||
== ISC_R_SUCCESS);
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
client_signalhandler(omapi_object_t *handle, const char *name, va_list ap) {
|
||||
client_object_t *client;
|
||||
omapi_value_t *tv;
|
||||
isc_region_t region;
|
||||
isc_boolean_t expected;
|
||||
|
||||
REQUIRE(handle->type == client_type);
|
||||
|
||||
client = (client_object_t *)handle;
|
||||
|
||||
if (strcmp(name, "updated") == 0) {
|
||||
client->waitresult = ISC_R_SUCCESS;
|
||||
|
||||
} else if (strcmp(name, "status") == 0) {
|
||||
/*
|
||||
* "status" is signalled with the result of the message's
|
||||
* operation.
|
||||
*/
|
||||
client->waitresult = va_arg(ap, isc_result_t);
|
||||
|
||||
expected = ISC_TF((error_noobject &&
|
||||
client->waitresult == ISC_R_NOTFOUND) ||
|
||||
(error_nosig &&
|
||||
client->waitresult == ISC_R_NOPERM) ||
|
||||
(error_badsig &&
|
||||
client->waitresult == DST_R_VERIFYFAILURE));
|
||||
|
||||
if (client->waitresult != ISC_R_SUCCESS)
|
||||
fprintf(stderr, "%s: message status: %s (%s)\n",
|
||||
progname,
|
||||
isc_result_totext(client->waitresult),
|
||||
expected ? "expected" : "UNEXPECTED");
|
||||
|
||||
tv = va_arg(ap, omapi_value_t *);
|
||||
if (tv != NULL) {
|
||||
omapi_value_getregion(tv, ®ion);
|
||||
fprintf(stderr, "%s: additional text provided: %.*s\n",
|
||||
progname, (int)region.length, region.base);
|
||||
}
|
||||
|
||||
} else {
|
||||
/*
|
||||
* Pass any unknown signal any internal object.
|
||||
* (This normally does not happen; there is no
|
||||
* inner object, nor anything else being signalled.)
|
||||
*/
|
||||
fprintf(stderr, "%s: client_signalhandler: unknown signal: %s",
|
||||
progname, name);
|
||||
return (omapi_object_passsignal(handle, name, ap));
|
||||
}
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the function that is called when an incoming OMAPI_OP_OPEN
|
||||
* message is received with either the create or update option set.
|
||||
* It is called once for each name/value pair in the message's object
|
||||
* value list.
|
||||
*
|
||||
* (Primary caller: message_process())
|
||||
*/
|
||||
static isc_result_t
|
||||
server_setvalue(omapi_object_t *handle, omapi_string_t *name,
|
||||
omapi_data_t *value)
|
||||
{
|
||||
isc_region_t region;
|
||||
|
||||
RUNTIME_CHECK(handle == (omapi_object_t *)&master_data);
|
||||
|
||||
/*
|
||||
* Only one name is supported for this object, MASTER_VALUE.
|
||||
*/
|
||||
if (omapi_string_strcmp(name, MASTER_VALUE) == 0) {
|
||||
fprintf(stderr, "existing value: %lu\n", master_data.value);
|
||||
|
||||
master_data.value = omapi_data_getint(value);
|
||||
fprintf(stderr, "new value: %lu\n", master_data.value);
|
||||
|
||||
/*
|
||||
* 32 is an arbitrary disconnect point.
|
||||
*/
|
||||
if (master_data.value >= 32) {
|
||||
master_data.target_reached = ISC_TRUE;
|
||||
SIGNAL(&waiter);
|
||||
}
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
omapi_string_totext(name, ®ion);
|
||||
fprintf(stderr, "server_setvalue: unknown name: '%.*s'\n",
|
||||
(int)region.length, region.base);
|
||||
|
||||
return (ISC_R_NOTFOUND);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the function that is called by the library's internal
|
||||
* message_process() function when an incoming OMAPI_OP_OPEN
|
||||
* message is received. It is normally supposed to look up the object
|
||||
* in the server that corresponds to the key data (name/value pair(s))
|
||||
* in 'ref'.
|
||||
*/
|
||||
static isc_result_t
|
||||
server_lookup(omapi_object_t **server_object, omapi_object_t *key) {
|
||||
/*
|
||||
* For this test program, there is only one static structure
|
||||
* which is being used, so key is not needed.
|
||||
*/
|
||||
UNUSED(key);
|
||||
|
||||
omapi_object_reference(server_object, (omapi_object_t *)&master_data);
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called when the server is sending a reply to a client
|
||||
* that opened an object of its type. It needs to output all published
|
||||
* name/value pairs for the object, and will typically also put the data
|
||||
* for any inner objects (but in this program, there will be no inner
|
||||
* objects).
|
||||
*/
|
||||
static isc_result_t
|
||||
server_stuffvalues(omapi_object_t *connection, omapi_object_t *handle) {
|
||||
server_object_t *master = (server_object_t *)handle;
|
||||
|
||||
/*
|
||||
* Write the MASTER_VALUE name, followed by the value length,
|
||||
* follwed by its value.
|
||||
*/
|
||||
RUNTIME_CHECK(omapi_connection_putname(connection, MASTER_VALUE)
|
||||
== ISC_R_SUCCESS);
|
||||
|
||||
RUNTIME_CHECK(omapi_connection_putuint32(connection,
|
||||
sizeof(isc_uint32_t))
|
||||
== ISC_R_SUCCESS);
|
||||
|
||||
RUNTIME_CHECK(omapi_connection_putuint32(connection, master->value)
|
||||
== ISC_R_SUCCESS);
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
static void
|
||||
do_connect(const char *host, int port) {
|
||||
omapi_object_t *manager;
|
||||
omapi_object_t *omapi_client = NULL;
|
||||
client_object_t *client = NULL;
|
||||
isc_result_t result;
|
||||
const char *key;
|
||||
const char *bad_secret1 = "this secret is wrong";
|
||||
const char *bad_secret2 = "Yet Another Secret";
|
||||
|
||||
RUNTIME_CHECK(omapi_object_register(&client_type, "client",
|
||||
client_setvalue,
|
||||
NULL, /* getvalue */
|
||||
NULL, /* destroy */
|
||||
client_signalhandler,
|
||||
client_stuffvalues,
|
||||
NULL, /* lookup */
|
||||
NULL, /* create */
|
||||
NULL) /* remove */
|
||||
== ISC_R_SUCCESS);
|
||||
|
||||
/*
|
||||
* Create the top level object which will manage the
|
||||
* connection to the server.
|
||||
*/
|
||||
manager = NULL;
|
||||
RUNTIME_CHECK(omapi_object_create(&manager, NULL, 0)
|
||||
== ISC_R_SUCCESS);
|
||||
|
||||
result = omapi_protocol_connect(manager, host, port, NULL);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
fprintf(stderr, "%s: omapi_protocol_connect: %s\n",
|
||||
progname, isc_result_totext(result));
|
||||
omapi_object_dereference(&manager);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Authenticate to the server.
|
||||
*/
|
||||
key = KEY1_NAME;
|
||||
|
||||
if (error_badsig) {
|
||||
omapi_auth_deregister(KEY1_NAME);
|
||||
|
||||
RUNTIME_CHECK(omapi_auth_register(KEY1_NAME,
|
||||
OMAPI_AUTH_HMACMD5,
|
||||
bad_secret1,
|
||||
strlen(bad_secret1))
|
||||
== ISC_R_SUCCESS);
|
||||
} else if (error_unknownsig) {
|
||||
RUNTIME_CHECK(omapi_auth_register(KEY2_NAME,
|
||||
OMAPI_AUTH_HMACMD5,
|
||||
bad_secret2,
|
||||
strlen(bad_secret2))
|
||||
== ISC_R_SUCCESS);
|
||||
|
||||
key = KEY2_NAME;
|
||||
}
|
||||
|
||||
if (! error_nosig) {
|
||||
result = omapi_auth_use(manager, key, OMAPI_AUTH_HMACMD5);
|
||||
|
||||
if (result != ISC_R_SUCCESS)
|
||||
fprintf(stderr, "%s: omapi_auth_use: %s (%s)\n",
|
||||
progname, isc_result_totext(result),
|
||||
(error_unknownsig && result == ISC_R_NOTFOUND)
|
||||
? "expected" : "UNEXPECTED");
|
||||
}
|
||||
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
/*
|
||||
* Create the client's object.
|
||||
*/
|
||||
omapi_object_create((omapi_object_t **)&client, client_type,
|
||||
sizeof(client_object_t));
|
||||
omapi_client = (omapi_object_t *)client;
|
||||
|
||||
/*
|
||||
* The object needs to have a name/value pair created for it
|
||||
* even before it contacts the server so the server will know
|
||||
* that there is an object that needs values filled in. This
|
||||
* name/value is created with the value of 0, but any interger
|
||||
* value would work.
|
||||
*/
|
||||
RUNTIME_CHECK(omapi_object_setinteger(omapi_client,
|
||||
MASTER_VALUE, 0)
|
||||
== ISC_R_SUCCESS);
|
||||
|
||||
RUNTIME_CHECK(open_object(omapi_client, manager, ISC_FALSE)
|
||||
== ISC_R_SUCCESS);
|
||||
|
||||
if (client->waitresult == ISC_R_SUCCESS) {
|
||||
/*
|
||||
* Set the new value to be stored at the server and
|
||||
* reopen the server object with an UPDATE operation.
|
||||
*/
|
||||
fprintf(stderr, "existing value: %lu\n",
|
||||
client->value);
|
||||
client->value *= 2;
|
||||
if (client->value == 0) /* Check overflow. */
|
||||
client->value = 1;
|
||||
fprintf(stderr, "new value: %lu\n", client->value);
|
||||
|
||||
RUNTIME_CHECK(open_object(omapi_client, manager,
|
||||
ISC_TRUE)
|
||||
== ISC_R_SUCCESS);
|
||||
|
||||
RUNTIME_CHECK(client->waitresult == ISC_R_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Close the connection and wait to be disconnected.
|
||||
*/
|
||||
omapi_protocol_disconnect(manager, OMAPI_CLEAN_DISCONNECT);
|
||||
|
||||
/*
|
||||
* Free the protocol manager and client object.
|
||||
*/
|
||||
omapi_object_dereference(&manager);
|
||||
|
||||
if (omapi_client != NULL)
|
||||
omapi_object_dereference(&omapi_client);
|
||||
}
|
||||
|
||||
static void
|
||||
listen_done(isc_task_t *task, isc_event_t *event) {
|
||||
omapi_object_t *listener = event->ev_arg;
|
||||
|
||||
UNUSED(task);
|
||||
|
||||
fprintf(stderr, "SERVER STOPPED\n");
|
||||
|
||||
isc_event_free(&event);
|
||||
|
||||
omapi_object_dereference(&listener);
|
||||
omapi_lib_destroy();
|
||||
}
|
||||
|
||||
static isc_boolean_t
|
||||
verify_connection(isc_sockaddr_t *sockaddr, void *arg) {
|
||||
/* XXXDCL test the connection verification code */
|
||||
UNUSED(sockaddr);
|
||||
UNUSED(arg);
|
||||
|
||||
return (ISC_TRUE);
|
||||
}
|
||||
|
||||
static isc_boolean_t
|
||||
verify_key(const char *name, unsigned int algorithm, void *arg) {
|
||||
/* XXXDCL test the key verification code */
|
||||
UNUSED(name);
|
||||
UNUSED(algorithm);
|
||||
UNUSED(arg);
|
||||
|
||||
return (ISC_TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
do_listen(int port) {
|
||||
omapi_object_t *listener = NULL;
|
||||
isc_sockaddr_t sockaddr;
|
||||
struct in_addr inaddr;
|
||||
dns_acl_t *acl;
|
||||
|
||||
/*
|
||||
* Create the manager for handling incoming server connections.
|
||||
*/
|
||||
RUNTIME_CHECK(omapi_object_create(&listener, NULL, 0)
|
||||
== ISC_R_SUCCESS);
|
||||
|
||||
/*
|
||||
* Register the server_object. The SERVER_OBJECT_TYPE is what
|
||||
* a client would need to specify as a value for the name "type"
|
||||
* when contacting the server in order to be able to find objects
|
||||
* server_type.
|
||||
*/
|
||||
RUNTIME_CHECK(omapi_object_register(&server_type, SERVER_OBJECT_TYPE,
|
||||
server_setvalue,
|
||||
NULL, /* getvalue */
|
||||
NULL, /* destroy */
|
||||
NULL, /* signalhandler */
|
||||
server_stuffvalues,
|
||||
server_lookup,
|
||||
NULL, /* create */
|
||||
NULL) /* remove */
|
||||
== ISC_R_SUCCESS);
|
||||
|
||||
/*
|
||||
* Initialize the server_object data.
|
||||
*/
|
||||
master_data.type = server_type;
|
||||
master_data.refcnt = 1;
|
||||
master_data.value = 2;
|
||||
master_data.target_reached = ISC_FALSE;
|
||||
|
||||
LOCK(&mutex);
|
||||
|
||||
/*
|
||||
* Set the access control list for valid connections.
|
||||
*/
|
||||
if (error_denyall)
|
||||
RUNTIME_CHECK(dns_acl_none(mctx, &acl) == ISC_R_SUCCESS);
|
||||
else
|
||||
RUNTIME_CHECK(dns_acl_any(mctx, &acl) == ISC_R_SUCCESS);
|
||||
|
||||
/*
|
||||
* Start listening for connections.
|
||||
*/
|
||||
inaddr.s_addr = INADDR_ANY;
|
||||
isc_sockaddr_fromin(&sockaddr, &inaddr, port);
|
||||
RUNTIME_CHECK(omapi_protocol_listen(listener, &sockaddr,
|
||||
verify_connection, verify_key,
|
||||
listen_done, listener)
|
||||
== ISC_R_SUCCESS);
|
||||
|
||||
fprintf(stderr, "SERVER STARTED\n");
|
||||
|
||||
/*
|
||||
* Lose one reference to the acl; the omapi library holds another
|
||||
* reference and should free it when it is done.
|
||||
*/
|
||||
dns_acl_detach(&acl);
|
||||
|
||||
/*
|
||||
* Block until done. "Done" is when server_setvalue has reached
|
||||
* its trigger value.
|
||||
*/
|
||||
do {
|
||||
WAIT(&waiter, &mutex);
|
||||
} while (! master_data.target_reached);
|
||||
|
||||
omapi_listener_shutdown(listener);
|
||||
}
|
||||
|
||||
#undef ARG_IS
|
||||
#define ARG_IS(s) (strcmp(isc_commandline_argument, (s)) == 0)
|
||||
|
||||
int
|
||||
main(int argc, char **argv) {
|
||||
isc_boolean_t show_final_mem = ISC_FALSE;
|
||||
isc_socketmgr_t *socketmgr = NULL;
|
||||
isc_taskmgr_t *taskmgr = NULL;
|
||||
isc_entropy_t *entropy = NULL;
|
||||
const char *secret = "shhh, this is a secret";
|
||||
int ch;
|
||||
|
||||
progname = strrchr(*argv, '/');
|
||||
if (progname != NULL)
|
||||
progname++;
|
||||
else
|
||||
progname = *argv;
|
||||
|
||||
while ((ch = isc_commandline_parse(argc, argv, "e:m")) != -1) {
|
||||
switch (ch) {
|
||||
case 'e':
|
||||
if (ARG_IS("noobject"))
|
||||
error_noobject = ISC_TRUE;
|
||||
|
||||
else if (ARG_IS("nosig"))
|
||||
error_nosig = ISC_TRUE;
|
||||
|
||||
else if (ARG_IS("badsig"))
|
||||
error_badsig = ISC_TRUE;
|
||||
|
||||
else if (ARG_IS("unknownsig"))
|
||||
error_unknownsig = ISC_TRUE;
|
||||
|
||||
else if (ARG_IS("denyall"))
|
||||
error_denyall = ISC_TRUE;
|
||||
else {
|
||||
fprintf(stderr, "Unknown forced error: %s\n",
|
||||
isc_commandline_argument);
|
||||
fprintf(stderr, "Valid forced errors: "
|
||||
"noobject nosig badsig unknownsig\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
break;
|
||||
case 'm':
|
||||
show_final_mem = ISC_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
argc -= isc_commandline_index;
|
||||
argv += isc_commandline_index;
|
||||
|
||||
RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS);
|
||||
|
||||
RUNTIME_CHECK(isc_taskmgr_create(mctx, 1, 0, &taskmgr)
|
||||
== ISC_R_SUCCESS);
|
||||
RUNTIME_CHECK(isc_socketmgr_create(mctx, &socketmgr)
|
||||
== ISC_R_SUCCESS);
|
||||
|
||||
RUNTIME_CHECK(omapi_lib_init(mctx, taskmgr, socketmgr)
|
||||
== ISC_R_SUCCESS);
|
||||
|
||||
RUNTIME_CHECK(isc_mutex_init(&mutex) == ISC_R_SUCCESS);
|
||||
RUNTIME_CHECK(isc_condition_init(&waiter) == ISC_R_SUCCESS);
|
||||
|
||||
/*
|
||||
* Initialize the signature library.
|
||||
*/
|
||||
RUNTIME_CHECK(isc_entropy_create(mctx, &entropy) == ISC_R_SUCCESS);
|
||||
RUNTIME_CHECK(dst_lib_init(mctx, entropy, 0) == ISC_R_SUCCESS);
|
||||
|
||||
/*
|
||||
* The secret key is shared on both the client and server side.
|
||||
*/
|
||||
RUNTIME_CHECK(omapi_auth_register(KEY1_NAME, OMAPI_AUTH_HMACMD5,
|
||||
secret, strlen(secret))
|
||||
== ISC_R_SUCCESS);
|
||||
|
||||
if (argc >= 1 && strcmp(argv[0], "listen") == 0) {
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: %s listen port\n", progname);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
do_listen(atoi(argv[1]));
|
||||
|
||||
} else if (argc >= 1 && !strcmp (argv[0], "connect")) {
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "Usage: %s connect address port\n",
|
||||
progname);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
do_connect(argv[1], atoi(argv[2]));
|
||||
|
||||
omapi_lib_destroy();
|
||||
|
||||
} else {
|
||||
fprintf(stderr, "Usage: %s [-m] [listen | connect] ...\n",
|
||||
progname);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
isc_socketmgr_destroy(&socketmgr);
|
||||
isc_taskmgr_destroy(&taskmgr);
|
||||
|
||||
dst_lib_destroy();
|
||||
isc_entropy_detach(&entropy);
|
||||
|
||||
if (show_final_mem)
|
||||
isc_mem_stats(mctx, stderr);
|
||||
|
||||
isc_mem_destroy(&mctx);
|
||||
|
||||
return (0);
|
||||
}
|
11
configure.in
11
configure.in
@ -18,7 +18,7 @@ AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)dnl
|
||||
esyscmd([sed "s/^/# /" COPYRIGHT])dnl
|
||||
AC_DIVERT_POP()dnl
|
||||
|
||||
AC_REVISION($Revision: 1.241 $)
|
||||
AC_REVISION($Revision: 1.242 $)
|
||||
|
||||
AC_INIT(lib/dns/name.c)
|
||||
AC_PREREQ(2.13)
|
||||
@ -1413,21 +1413,18 @@ AC_SUBST(BIND9_ISC_BUILDINCLUDE)
|
||||
AC_SUBST(BIND9_ISCCC_BUILDINCLUDE)
|
||||
AC_SUBST(BIND9_ISCCFG_BUILDINCLUDE)
|
||||
AC_SUBST(BIND9_DNS_BUILDINCLUDE)
|
||||
AC_SUBST(BIND9_OMAPI_BUILDINCLUDE)
|
||||
AC_SUBST(BIND9_LWRES_BUILDINCLUDE)
|
||||
if test "X$srcdir" != "X"; then
|
||||
BIND9_ISC_BUILDINCLUDE="-I${BIND9_TOP_BUILDDIR}/lib/isc/include"
|
||||
BIND9_ISCCC_BUILDINCLUDE="-I${BIND9_TOP_BUILDDIR}/lib/isccc/include"
|
||||
BIND9_ISCCFG_BUILDINCLUDE="-I${BIND9_TOP_BUILDDIR}/lib/isccfg/include"
|
||||
BIND9_DNS_BUILDINCLUDE="-I${BIND9_TOP_BUILDDIR}/lib/dns/include"
|
||||
BIND9_OMAPI_BUILDINCLUDE="-I${BIND9_TOP_BUILDDIR}/lib/omapi/include"
|
||||
BIND9_LWRES_BUILDINCLUDE="-I${BIND9_TOP_BUILDDIR}/lib/lwres/include"
|
||||
else
|
||||
BIND9_ISC_BUILDINCLUDE=""
|
||||
BIND9_ISCCC_BUILDINCLUDE=""
|
||||
BIND9_ISCCFG_BUILDINCLUDE=""
|
||||
BIND9_DNS_BUILDINCLUDE=""
|
||||
BIND9_OMAPI_BUILDINCLUDE=""
|
||||
BIND9_LWRES_BUILDINCLUDE=""
|
||||
fi
|
||||
|
||||
@ -1456,9 +1453,6 @@ LIBDNS_API=$srcdir/lib/dns/api
|
||||
AC_SUBST_FILE(LIBLWRES_API)
|
||||
LIBLWRES_API=$srcdir/lib/lwres/api
|
||||
|
||||
AC_SUBST_FILE(LIBOMAPI_API)
|
||||
LIBOMAPI_API=$srcdir/lib/omapi/api
|
||||
|
||||
AC_OUTPUT(
|
||||
make/rules
|
||||
make/includes
|
||||
@ -1497,9 +1491,6 @@ AC_OUTPUT(
|
||||
lib/lwres/include/lwres/netdb.h
|
||||
lib/lwres/include/lwres/platform.h
|
||||
lib/lwres/man/Makefile
|
||||
lib/omapi/Makefile
|
||||
lib/omapi/include/Makefile
|
||||
lib/omapi/include/omapi/Makefile
|
||||
lib/tests/Makefile
|
||||
lib/tests/include/Makefile
|
||||
lib/tests/include/tests/Makefile
|
||||
|
447
doc/design/omapi
447
doc/design/omapi
@ -1,447 +0,0 @@
|
||||
Copyright (C) 1999-2001 Internet Software Consortium.
|
||||
See COPYRIGHT in the source root or http://isc.org/copyright.html for terms.
|
||||
|
||||
$Id: omapi,v 1.7 2001/01/09 21:46:48 bwelling Exp $
|
||||
|
||||
This file documents the protocol that the ISC DHCP server and ISC
|
||||
Object Management clients (clients that use the ISC Object Management
|
||||
API) speak between one another.
|
||||
|
||||
Protocol:
|
||||
|
||||
All multi-byte numbers are represented in network byte order.
|
||||
|
||||
On startup, each side sends a status message indicating what version
|
||||
of the protocol they are speaking. The status message looks like
|
||||
this:
|
||||
|
||||
+---------+---------+
|
||||
| version | hlength |
|
||||
+---------+---------+
|
||||
|
||||
version - a 32-bit fixed-point number with the decimal point between
|
||||
the third and second decimal digits from the left,
|
||||
representing the version of the protocol. The current
|
||||
protocol version is 1.00. If the field were considered as
|
||||
a 32-bit integer, this would correspond to a value of 100
|
||||
decimal, or 0x64.
|
||||
|
||||
hlength - a 32-bit integer representing the length of the fixed-length
|
||||
header in subsequent messages. This is normally 56, but
|
||||
can be changed to a value larger than 56 by either side
|
||||
without upgrading the revision number.
|
||||
|
||||
|
||||
The startup message is not authenticated. Either side may reject the
|
||||
other side's startup message as invalid by simply closing the
|
||||
connection. The only fixed part of the startup message is the
|
||||
version number - future versions may delete hlength, or add further
|
||||
startup information.
|
||||
|
||||
Following the startup message, all messages have the same format.
|
||||
Currently, the format includes a fixed-length header (the length in
|
||||
hlength, above)
|
||||
|
||||
+--------+----+--------+----+-----+---------+------------+------------+-----+
|
||||
| authid | op | handle | id | rid | authlen | msg values | obj values | sig |
|
||||
+--------+----+--------+----+-----+---------+------------+------------+-----+
|
||||
|
||||
The fixed-length header consists of:
|
||||
|
||||
authid = a 32-bit authenticator handle.
|
||||
For an original message (one not in response to some other
|
||||
message), this will be chosen by the originator. For a
|
||||
message in response to another message, the authenticator for
|
||||
that message is used, except if the response is an error
|
||||
message indicating that the authenticator used was unknown,
|
||||
in which case the null authenticator is used. Messages that
|
||||
are generated as the result of a notify registration use the
|
||||
authenticator used in the original notify registration.
|
||||
The authenticator itself is generated by having one side of
|
||||
the connection send an object of type "authenticator" to the
|
||||
other side with values that indicate what kind of
|
||||
authentication mechanism to use and what key to use. The two
|
||||
most likely things here are a Kerberos V principal name or the
|
||||
name of a shared secret that can be used to calculate an MD5
|
||||
hash. The mechanism for doing this has yet to be finalized.
|
||||
If authid is zero, the message is not authenticated.
|
||||
|
||||
[[
|
||||
This is not consistent with what the code does (as originally written),
|
||||
which is read a header that has, in order:
|
||||
authid, authlen, op, handle, id, rid
|
||||
]]
|
||||
|
||||
op = 32-bit opcode, one of:
|
||||
open = 1
|
||||
refresh = 2
|
||||
update = 3
|
||||
notify = 4
|
||||
error = 5
|
||||
delete = 6
|
||||
handle = 32-bit object handle
|
||||
A handle on the object being opened, created, refreshed or
|
||||
updated. If no handle is yet available (e.g., with open and
|
||||
new), then the value zero is sent.
|
||||
id = 32-bit transaction id of the message - a monotonically increasing
|
||||
number that starts with some randomly chosen number at the
|
||||
beginning of the life of the connection. The value should never
|
||||
be zero.
|
||||
rid = 32-bit transaction ID of the message to which this message is a
|
||||
response, or zero if this message is not in response to a
|
||||
message from the other side.
|
||||
|
||||
authlen = a 32-bit number representing the length of the authenticator
|
||||
|
||||
msg values = a series of name+value pairs, specific to this message.
|
||||
Each name+value pair starts with a 16-bit name length,
|
||||
followed by that many bytes of name, followed by a 32-bit
|
||||
value length, followed by that many bytes of value. If the
|
||||
length is zero, this is a value of the blank string. If the
|
||||
length is all ones (2^32-1), then there is no value - for an
|
||||
update, this means the value for this name and the name
|
||||
itself should be deleted from the object, which may or may
|
||||
not be possible. The list of name/value pairs ends with a
|
||||
zero-length name, which is not followed by a value
|
||||
length/value pair.
|
||||
|
||||
obj values = a series of name+value pairs, as above, specific to the
|
||||
object being created, updated or refreshed.
|
||||
|
||||
signature = authlen bytes of data signing the message. The signature
|
||||
algorithm is a property of the authenticator handle.
|
||||
|
||||
Message types:
|
||||
|
||||
1: open
|
||||
relevant input values:
|
||||
object-type = the name of the type of object
|
||||
open:create = boolean - create the object if it doesn't yet exist
|
||||
open:exclusive = boolean - don't open the object if it does exist
|
||||
open:update = boolean - update the object with included values
|
||||
if it matches.
|
||||
the handle should always be the null handle
|
||||
|
||||
The input value must also contain key information for the type of
|
||||
object being searched that uniquely identifies an object, or search
|
||||
information that matches only one object. Each object has a key
|
||||
specification (a key is something that uniquely identifies an
|
||||
object), so see the key specification for that object to see
|
||||
what to send here. An open message with the create flag set must
|
||||
specify a key, and not merely matching criteria. Some objects may
|
||||
allow more than one key, and it may be that the union of those keys
|
||||
is required to uniquely identify the object, or it may be that any
|
||||
one such key will uniquely identify the object. The documentation
|
||||
for the type of object will specify this.
|
||||
|
||||
An open message will result in an immediate response message whose
|
||||
opcode will either be "error" or "update". The error message may
|
||||
include an error:reason value containing a text string explaining
|
||||
the error, and will always include an error:code value which will
|
||||
be the numeric error code for what went wrong. Possible error
|
||||
codes are:
|
||||
|
||||
not found - no such object exists
|
||||
already exists - object already exists, and exclusive flag was
|
||||
set.
|
||||
not unique - more than one object matching the specification
|
||||
exists.
|
||||
permission denied - the authenticator ID specified does not
|
||||
have authorization to access this object,
|
||||
or if the update flag was specified, to
|
||||
update the object.
|
||||
|
||||
If the response is an update message, the update message will
|
||||
include the object handle and all of the name/value pairs
|
||||
associated with that object.
|
||||
|
||||
2: refresh
|
||||
|
||||
no input values except the handle need be specified. The null
|
||||
handle may not be specified. If the handle is valid, and the
|
||||
authenticator ID specified has permission to examine the object,
|
||||
then an update message will be sent for that object. Otherwise,
|
||||
one of the following errors will be sent:
|
||||
|
||||
invalid handle - the handle does not refer to a known object
|
||||
permisson denied - the handle refers to an object that the
|
||||
requestor does not have permission to
|
||||
examine.
|
||||
|
||||
3: update
|
||||
|
||||
Requests that the contents of the specified object be updated with
|
||||
the values included. Values that are not specified are not
|
||||
updated. The response will be either an error message or an
|
||||
update-ok message. If rid is nonzero, no response will be
|
||||
generated, even if there was an error. Possible errors include:
|
||||
|
||||
invalid handle - no such object was found
|
||||
permission denied - the handle refers to an object that the
|
||||
requestor does not have permission to
|
||||
modify.
|
||||
not confirmed - the update could not be committed due to some
|
||||
kind of resource problem, for example
|
||||
insufficient memory or a disk failure.
|
||||
|
||||
4: notify
|
||||
|
||||
Requests that whenever the object with the specified handle is
|
||||
modified, an update be sent. If there is something wrong with the
|
||||
request, an error message will be returned immediately.
|
||||
Otherwise, whenever a change is made to the object, an update
|
||||
message will be sent containing whatever changes were made (or
|
||||
possibly all the values associated with the object, depending on
|
||||
the implementation). Possible errors:
|
||||
|
||||
invalid handle
|
||||
permission denied - the handle refers to an object that the
|
||||
requestor does not have permission to
|
||||
examine.
|
||||
not supported - the object implementation does not support
|
||||
notifications
|
||||
|
||||
5: status
|
||||
|
||||
Sends a status code in response to a message. Always sent in
|
||||
response to a message sent by the other side. There should never
|
||||
be a response to this message.
|
||||
|
||||
6: delete
|
||||
|
||||
Deletes the specified object. Response will be either request-ok,
|
||||
or error. Possible errors include:
|
||||
|
||||
invalid handle - no such object was found
|
||||
permission denied - the handle refers to an object that the
|
||||
requestor does not have permission to
|
||||
modify.
|
||||
not confirmed - the deletion could not be committed due to
|
||||
some kind of resource problem, for example
|
||||
insufficient memory or a disk failure.
|
||||
|
||||
7: notify-cancel
|
||||
|
||||
Like notify, but requests that an existing notification be cancelled.
|
||||
|
||||
8: notify-cancelled
|
||||
|
||||
Indicates that because of a local change, a notification that had
|
||||
been registered can no longer be performed. This could be as a
|
||||
result of the permissions on a object changing, or an object being
|
||||
deleted. There should never be a response to this message.
|
||||
|
||||
internals:
|
||||
|
||||
Both client and server use same protocol and infrastructure. There
|
||||
are many object types, each of which is stored in a registry.
|
||||
Objects whose type is not recognized can either be handled by the
|
||||
generic object type, which is registered with the type "*". If no
|
||||
generic object type is registered, then objects with unknown types are
|
||||
simply not supported. On the client, there are probably no special
|
||||
object handlers (although this is by no means forbidden). On the
|
||||
server, probably everything is a special object.
|
||||
|
||||
Each object type has the following methods:
|
||||
|
||||
|
||||
|
||||
|
||||
dhcpctl_status dhcpctl_connect (dhcpctl_handle *connection,
|
||||
char *server_name, int port,
|
||||
dhcpctl_handle *authinfo)
|
||||
synchronous
|
||||
returns nonzero status code if it didn't connect, zero otherwise
|
||||
stores connection handle through connection, which can be used
|
||||
for subsequent access to the specified server.
|
||||
server_name is the name of the server, and port is the TCP
|
||||
port on which it is listening.
|
||||
authinfo is the handle to an object containing authentication
|
||||
information.
|
||||
|
||||
dhcpctl_status dhcpctl_open_object (dhcpctl_handle h,
|
||||
dhcpctl_handle connection,
|
||||
int flags)
|
||||
asynchronous - just queues the request
|
||||
returns nonzero status code if open couldn't be queued
|
||||
returns zero if open was queued
|
||||
h is a handle to an object created by dhcpctl_new_object
|
||||
connection is a connection to a DHCP server
|
||||
flags include:
|
||||
DHCPCTL_CREATE - if the object doesn't exist, create it
|
||||
DHCPCTL_UPDATE - update the object on the server using the
|
||||
attached parameters
|
||||
DHCPCTL_EXCL - error if the object exists and DHCPCTL_CREATE
|
||||
was also specified
|
||||
|
||||
dhcpctl_status dhcpctl_new_object (dhcpctl_handle *h,
|
||||
dhcpctl_handle connection,
|
||||
char *object_type)
|
||||
synchronous - creates a local handle for a host entry.
|
||||
returns nonzero status code if the local host entry couldn't
|
||||
be created
|
||||
stores handle to host through h if successful, and returns zero.
|
||||
object_type is a pointer to a NUL-terminated string containing
|
||||
the ascii name of the type of object being accessed - e.g., "host"
|
||||
|
||||
dhcpctl_status dhcpctl_set_callback (dhcpctl_handle h, void *data,
|
||||
void (*callback) (dhcpctl_handle,
|
||||
dhcpctl_status, void *))
|
||||
synchronous, with asynchronous aftereffect
|
||||
handle is some object upon which some kind of process has been
|
||||
started - e.g., an open, an update or a refresh.
|
||||
data is an anonymous pointer containing some information that
|
||||
the callback will use to figure out what event completed.
|
||||
return value of 0 means callback was successfully set, a nonzero
|
||||
status code is returned otherwise.
|
||||
Upon completion of whatever task is in process, the callback
|
||||
will be passed the handle to the object, a status code
|
||||
indicating what happened, and the anonymous pointer passed to
|
||||
|
||||
dhcpctl_status dhcpctl_wait_for_completion (dhcpctl_handle h,
|
||||
dhcpctl_status *s)
|
||||
synchronous
|
||||
returns zero if the callback completes, a nonzero status if
|
||||
there was some problem relating to the wait operation. The
|
||||
status of the queued request will be stored through s, and
|
||||
will also be either zero for success or nonzero for some kind
|
||||
of failure. Never returns until completion or until the
|
||||
connection to the server is lost. This performs the same
|
||||
function as dhcpctl_set_callback and the subsequent callback,
|
||||
for programs that want to do inline execution instead of using
|
||||
callbacks.
|
||||
|
||||
dhcpctl_status dhcpctl_get_value (data_string *result,
|
||||
dhcpctl_handle h, char *value_name)
|
||||
synchronous
|
||||
returns zero if the call succeeded, a nonzero status code if
|
||||
it didn't.
|
||||
result is the address of an empty data string (initialized
|
||||
with bzero or cleared with data_string_forget). On
|
||||
successful completion, the addressed data string will contain
|
||||
the value that was fetched.
|
||||
dhcpctl_handle refers to some dhcpctl item
|
||||
value_name refers to some value related to that item - e.g.,
|
||||
for a handle associated with a completed host lookup, value
|
||||
could be one of "hardware-address", "dhcp-client-identifier",
|
||||
"known" or "client-hostname".
|
||||
|
||||
dhcpctl_status dhcpctl_get_boolean (int *result,
|
||||
dhcpctl_handle h, char *value_name)
|
||||
like dhcpctl_get_value, but more convenient for boolean
|
||||
values, since no data_string needs to be dealt with.
|
||||
|
||||
dhcpctl_status dhcpctl_set_value (dhcpctl_handle h, data_string value,
|
||||
char *value_name)
|
||||
Sets a value on an object referred to by a dhcpctl_handle.
|
||||
The opposite of dhcpctl_get_value. Does not update the
|
||||
server - just sets the value on the handle.
|
||||
|
||||
dhcpctl_status dhcpctl_set_string_value (dhcpctl_handle h, char *value,
|
||||
char *value_name)
|
||||
Sets a NUL-terminated ASCII value on an object referred to by
|
||||
a dhcpctl_handle. like dhcpctl_set_value, but saves the
|
||||
trouble of creating a data_string for a NUL-terminated string.
|
||||
Does not update the server - just sets the value on the handle.
|
||||
|
||||
dhcpctl_status dhcpctl_set_boolean (dhcpctl_handle h, int value,
|
||||
char *value_name)
|
||||
Sets a boolean value on an object - like dhcpctl_set_value,
|
||||
only more convenient for booleans.
|
||||
|
||||
dhcpctl_status dhcpctl_object_update (dhcpctl_handle h)
|
||||
Queues an update on the object referenced by the handle (there
|
||||
can't be any other work in progress on the handle). An
|
||||
update means local parameters will be sent to the server.
|
||||
|
||||
dhcpctl_status dhcpctl_object_refresh (dhcpctl_handle h)
|
||||
Queues an update on the object referenced by the handle (there
|
||||
can't be any other work in progress on the handle). An
|
||||
update means local parameters will be sent to the server.
|
||||
|
||||
dhcpctl_status dhcpctl_object_delete (dhcpctl_handle h)
|
||||
Queues a delete of the object referenced by the handle (there
|
||||
can't be any other work in progress on the handle). A
|
||||
delete means that the object will be permanently deleted on
|
||||
the remote end, assuming the remote end supports object
|
||||
persistence.
|
||||
|
||||
So a sample program that would update a host declaration would look
|
||||
something like this:
|
||||
|
||||
/* Create a local object into which to store authentication
|
||||
information. */
|
||||
if ((status = dhcpctl_new_object (&auth, dhcpctl_null_handle,
|
||||
"authentication-information")))
|
||||
dhcpctl_error ("Can't create authentication information: %m");
|
||||
|
||||
/* Set up the authenticator with an algorithm type, user name and
|
||||
password. */
|
||||
if ((status = dhcpctl_set_string_value (&auth, "mellon", "username")))
|
||||
dhcpctl_error ("Can't set username: %m", status);
|
||||
if ((status = dhcpctl_set_string_value (&auth, "three blind mice",
|
||||
"password")))
|
||||
dhcpctl_error ("Can't set password: %m", status);
|
||||
if ((status = dhcpctl_set_string_value (&auth, "md5-hash",
|
||||
"algorithm")))
|
||||
dhcpctl_error ("Can't set authentication algorithm: %m.",
|
||||
status);
|
||||
|
||||
/* Connect to the server. */
|
||||
if ((status = dhcpctl_connect (&c, "dhcp.server.com", 612, &auth)))
|
||||
|
||||
dhcpctl_error ("Can't connect to dhcp.server.com: %m",
|
||||
status);
|
||||
|
||||
/* Create a host object. */
|
||||
if ((status = dhcpctl_new_object (&hp, c, "host")))
|
||||
dhcpctl_error ("Host create failed: %m", status);
|
||||
|
||||
/* Create a data_string to contain the host's client
|
||||
identifier, and set it. */
|
||||
if ((status =
|
||||
data_string_create_from_hex (&client_id,
|
||||
"1:08:00:2b:34:1a:c3")))
|
||||
dhcpctl_error ("Can't create client identifier: %m");
|
||||
if ((status = dhcpctl_set_value (hp, client_id,
|
||||
"dhcp-client-identifier")))
|
||||
dhcpctl_error ("Host client identifier set failed.");
|
||||
/* Set the known flag to 1. */
|
||||
if ((status = dhcpctl_set_boolean (hp, 1, "known")))
|
||||
dhcpctl_error ("Host known set failed.");
|
||||
|
||||
/* Open an existing host object that matches the client identifier,
|
||||
and update it from the local context, or if no host entry
|
||||
yet exists matching the identifier, create one and
|
||||
initialize it. */
|
||||
if ((status = dhcpctl_open_object (&hp, c,
|
||||
DHCPCTL_CREATE | DHCPCTL_UPDATE)))
|
||||
dhcpctl_error ("Can't open host: %m", status);
|
||||
|
||||
/* Wait for the process to complete, check status. */
|
||||
if ((status = dhcpctl_wait_for_completion (hp, &wait_status)))
|
||||
dhcpctl_error ("Host create/lookup wait failed: %m", status);
|
||||
if (waitstatus)
|
||||
dhcpctl_error ("Host create/lookup failed: %m", status);
|
||||
|
||||
The API is a bit complicated, for a couple of reasons. I want to
|
||||
make it general, so that there aren't a bazillion functions to call,
|
||||
one for each data type. I want it to be thread-safe, which is why
|
||||
each function returns a status and the error printer requires a status
|
||||
code for input. I want it to be possible to make it asynchronous, so
|
||||
that it can work in tandem with, for example, an X toolkit. If
|
||||
you're just writing a simple update cgi program, you probably won't
|
||||
want to bother to use the asynchronous callbacks, and indeed the above
|
||||
example doesn't.
|
||||
|
||||
I glossed over data strings above - basically, they're objects with a
|
||||
pointer to a reference-counted buffer structure, an offset into that
|
||||
buffer, and a length. These are used within the DHCP server, so you
|
||||
can get an idea of how they work - basically, they're a convenient and
|
||||
efficient way to store a string with a length such that substrings can
|
||||
easily be taken and such that more than one user at a time can have a
|
||||
pointer to the string.
|
||||
|
||||
I will also probably add locking primitives, so that you can get the
|
||||
value of something and be sure that some other updator process won't
|
||||
modify it while you have the lock.
|
@ -1,7 +1,7 @@
|
||||
Copyright (C) 2000, 2001 Internet Software Consortium.
|
||||
See COPYRIGHT in the source root or http://isc.org/copyright.html for terms.
|
||||
|
||||
$Id: roadmap,v 1.2 2001/01/09 21:47:05 bwelling Exp $
|
||||
$Id: roadmap,v 1.3 2001/03/27 00:53:20 bwelling Exp $
|
||||
|
||||
Road Map to the BIND 9 Source Tree
|
||||
|
||||
@ -27,7 +27,7 @@ lib/dns/sec Cryptographic libraries for DNSSEC
|
||||
lib/isc The ISC library
|
||||
task.c Task library
|
||||
unix/socket.c Unix implementation of socket library
|
||||
lib/omapi The OMAPI remote object access library, used by rndc.
|
||||
lib/isccc The command channel library, used by rndc.
|
||||
lib/tests Support code for the test suites.
|
||||
lib/lwres The lightweight resolver library.
|
||||
doc/draft Current internet-drafts pertaining to the DNS
|
||||
|
@ -13,13 +13,13 @@
|
||||
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
||||
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
# $Id: Makefile.in,v 1.14 2001/03/27 00:44:43 bwelling Exp $
|
||||
# $Id: Makefile.in,v 1.15 2001/03/27 00:53:21 bwelling Exp $
|
||||
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
|
||||
SUBDIRS = isc isccc isccfg dns lwres omapi tests
|
||||
SUBDIRS = isc isccc isccfg dns lwres tests
|
||||
TARGETS =
|
||||
|
||||
@BIND9_MAKE_RULES@
|
||||
|
@ -1,5 +0,0 @@
|
||||
Makefile
|
||||
timestamp
|
||||
.libs
|
||||
*.la
|
||||
*.lo
|
@ -1,80 +0,0 @@
|
||||
# Copyright (C) 1999-2001 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: Makefile.in,v 1.17 2001/02/15 19:44:40 bwelling Exp $
|
||||
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
|
||||
@BIND9_VERSION@
|
||||
|
||||
@LIBOMAPI_API@
|
||||
|
||||
@BIND9_INCLUDES@
|
||||
|
||||
CINCLUDES = -I./include \
|
||||
-I${srcdir}/include \
|
||||
${ISC_INCLUDES}
|
||||
|
||||
CDEFINES =
|
||||
CWARNINGS =
|
||||
|
||||
# Alphabetically
|
||||
OBJS = auth.@O@ connection.@O@ data.@O@ generic.@O@ handle.@O@ \
|
||||
lib.@O@ listener.@O@ message.@O@ object.@O@ protocol.@O@ \
|
||||
result.@O@ string.@O@ value.@O@ version.@O@
|
||||
|
||||
# Alphabetically
|
||||
SRCS = auth.c connection.c data.c generic.c handle.c \
|
||||
lib.c listener.c message.c object.c protocol.c \
|
||||
result.c string.c value.c version.c
|
||||
|
||||
LIBS = @LIBS@
|
||||
|
||||
SUBDIRS = include
|
||||
TARGETS = timestamp
|
||||
|
||||
@BIND9_MAKE_RULES@
|
||||
|
||||
version.@O@: version.c
|
||||
${LIBTOOL} ${CC} ${ALL_CFLAGS} \
|
||||
-DVERSION=\"${VERSION}\" \
|
||||
-DLIBINTERFACE=${LIBINTERFACE} \
|
||||
-DLIBREVISION=${LIBREVISION} \
|
||||
-DLIBAGE=${LIBAGE} \
|
||||
-c ${srcdir}/version.c
|
||||
|
||||
libomapi.@SA@: ${OBJS}
|
||||
${AR} ${ARFLAGS} $@ ${OBJS}
|
||||
${RANLIB} $@
|
||||
|
||||
libomapi.la: ${OBJS}
|
||||
${LIBTOOL} --mode=link \
|
||||
${CC} ${ALL_CFLAGS} -o libomapi.la -rpath ${libdir} \
|
||||
-version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \
|
||||
${OBJS} ${LIBS}
|
||||
|
||||
timestamp: libomapi.@A@
|
||||
touch timestamp
|
||||
|
||||
installdirs:
|
||||
$(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${libdir}
|
||||
|
||||
install:: timestamp installdirs
|
||||
${LIBTOOL} ${INSTALL_DATA} libomapi.@A@ ${DESTDIR}${libdir}
|
||||
|
||||
clean distclean::
|
||||
rm -f libomapi.@A@ libomapi.la timestamp
|
@ -1,3 +0,0 @@
|
||||
LIBINTERFACE = 3
|
||||
LIBREVISION = 0
|
||||
LIBAGE = 0
|
347
lib/omapi/auth.c
347
lib/omapi/auth.c
@ -1,347 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2000, 2001 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: auth.c,v 1.21 2001/02/17 00:53:59 bwelling Exp $ */
|
||||
|
||||
/* Principal Author: DCL */
|
||||
|
||||
/*
|
||||
* XXXDCL Todo:
|
||||
* How do keys get specified by named.conf for the control channel?
|
||||
* Could use the keys in the address_match_list (acl) specified in the
|
||||
* "controls" statement. All of the keys would need to be at the beginning,
|
||||
* so the match does not stop at an IP address. The server would register
|
||||
* all of the keys. Currently, however, there is no way to limit a key
|
||||
* to a particular listening interface on the server, as the configuration
|
||||
* file would allow.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Subroutines for dealing with authorization.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <isc/buffer.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/once.h>
|
||||
#include <isc/string.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <omapi/private.h>
|
||||
|
||||
typedef struct auth auth_t;
|
||||
|
||||
#define AUTH_MAGIC 0x41555448U /* AUTH. */
|
||||
#define VALID_AUTH(a) ((a) != NULL && (a)->magic == AUTH_MAGIC)
|
||||
|
||||
/*
|
||||
* XXXDCL For reloading, Make refcounted, and use attach and detach?
|
||||
*/
|
||||
struct auth {
|
||||
unsigned int magic;
|
||||
char *name;
|
||||
unsigned char *secret;
|
||||
size_t secretlen;
|
||||
unsigned int algorithms;
|
||||
|
||||
ISC_LINK(auth_t) link;
|
||||
};
|
||||
|
||||
static ISC_LIST(auth_t) omapi_authlist;
|
||||
static isc_mutex_t mutex; /* To lock the previous variable. */
|
||||
static isc_once_t once = ISC_ONCE_INIT; /* To initialize the mutex. */
|
||||
|
||||
static void
|
||||
initialize_mutex(void) {
|
||||
RUNTIME_CHECK(isc_mutex_init(&mutex) == ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
auth_find(const char *name, unsigned int algorithm, auth_t **ap) {
|
||||
auth_t *a;
|
||||
isc_result_t result;
|
||||
|
||||
REQUIRE(name != NULL);
|
||||
REQUIRE(ap != NULL && *ap == NULL);
|
||||
|
||||
for (a = ISC_LIST_HEAD(omapi_authlist); a != NULL;
|
||||
a = ISC_LIST_NEXT(a, link))
|
||||
if (strcmp(name, a->name) == 0)
|
||||
break;
|
||||
|
||||
if (a == NULL)
|
||||
result = ISC_R_NOTFOUND;
|
||||
|
||||
else if (algorithm != 0 && (algorithm & a->algorithms) != algorithm)
|
||||
result = ISC_R_NOTIMPLEMENTED;
|
||||
|
||||
else {
|
||||
ENSURE(VALID_AUTH(a));
|
||||
|
||||
*ap = a;
|
||||
|
||||
result = ISC_R_SUCCESS;
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
|
||||
isc_result_t
|
||||
auth_makekey(const char *name, unsigned int algorithm, isc_region_t **keyp) {
|
||||
isc_result_t result;
|
||||
auth_t *auth = NULL;
|
||||
isc_region_t *key;
|
||||
|
||||
REQUIRE(name != NULL && algorithm != 0);
|
||||
REQUIRE(keyp != NULL && *keyp == NULL);
|
||||
|
||||
RUNTIME_CHECK(isc_once_do(&once, initialize_mutex) == ISC_R_SUCCESS);
|
||||
LOCK(&mutex);
|
||||
result = auth_find(name, algorithm, &auth);
|
||||
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
switch (algorithm) {
|
||||
case OMAPI_AUTH_HMACMD5:
|
||||
break;
|
||||
default:
|
||||
UNEXPECTED_ERROR(__FILE__, __LINE__,
|
||||
"unknown auth algorithm %d",
|
||||
algorithm);
|
||||
return (ISC_R_UNEXPECTED);
|
||||
}
|
||||
|
||||
key = isc_mem_get(omapi_mctx, sizeof(isc_region_t));
|
||||
if (key == NULL)
|
||||
result = ISC_R_NOMEMORY;
|
||||
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
key->base = auth->secret;
|
||||
key->length = auth->secretlen;
|
||||
*keyp = key;
|
||||
}
|
||||
}
|
||||
|
||||
UNLOCK(&mutex);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
static void
|
||||
auth_delete(auth_t *a) {
|
||||
REQUIRE(VALID_AUTH(a));
|
||||
|
||||
ISC_LIST_UNLINK(omapi_authlist, a, link);
|
||||
|
||||
a->magic = 0;
|
||||
|
||||
isc_mem_free(omapi_mctx, a->secret);
|
||||
isc_mem_free(omapi_mctx, a->name);
|
||||
isc_mem_put(omapi_mctx, a, sizeof(*a));
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
omapi_auth_register(const char *name, unsigned int algorithms,
|
||||
const unsigned char *secret, size_t secretlen)
|
||||
{
|
||||
auth_t *new = NULL;
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
|
||||
REQUIRE(name != NULL && secret != NULL);
|
||||
REQUIRE(algorithms != 0);
|
||||
|
||||
RUNTIME_CHECK(isc_once_do(&once, initialize_mutex) == ISC_R_SUCCESS);
|
||||
LOCK(&mutex);
|
||||
|
||||
if (auth_find(name, 0, &new) == ISC_R_SUCCESS)
|
||||
result = ISC_R_EXISTS;
|
||||
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
new = isc_mem_get(omapi_mctx, sizeof(*new));
|
||||
if (new != NULL)
|
||||
memset(new, 0, sizeof(*new));
|
||||
else
|
||||
result = ISC_R_NOMEMORY;
|
||||
}
|
||||
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
new->name = isc_mem_strdup(omapi_mctx, name);
|
||||
if (new->name == NULL)
|
||||
result = ISC_R_NOMEMORY;
|
||||
|
||||
new->secret = isc_mem_allocate(omapi_mctx, secretlen);
|
||||
if (new->secret == NULL)
|
||||
result = ISC_R_NOMEMORY;
|
||||
else {
|
||||
memcpy(new->secret, secret, secretlen);
|
||||
new->secretlen = secretlen;
|
||||
}
|
||||
|
||||
new->algorithms = algorithms;
|
||||
|
||||
ISC_LINK_INIT(new, link);
|
||||
|
||||
new->magic = AUTH_MAGIC;
|
||||
|
||||
ISC_LIST_APPEND(omapi_authlist, new, link);
|
||||
}
|
||||
|
||||
UNLOCK(&mutex);
|
||||
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
if (new->secret != NULL)
|
||||
isc_mem_free(omapi_mctx, new->secret);
|
||||
if (new->name != NULL)
|
||||
isc_mem_free(omapi_mctx, new->name);
|
||||
if (new != NULL)
|
||||
isc_mem_put(omapi_mctx, new, sizeof(*new));
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* Currently the way to effect a reload is to use omapi_auth_deregister(NULL)
|
||||
* to remove all of the existing auth structs before building a new
|
||||
* omapi_authlist via omapi_auth_register calls. This clearly leaves a
|
||||
* window, however small, where there is no authentication possible.
|
||||
*/
|
||||
void
|
||||
omapi_auth_deregister(const char *name) {
|
||||
auth_t *a = NULL;
|
||||
|
||||
RUNTIME_CHECK(isc_once_do(&once, initialize_mutex) == ISC_R_SUCCESS);
|
||||
LOCK(&mutex);
|
||||
|
||||
if (name == NULL)
|
||||
while ((a = ISC_LIST_HEAD(omapi_authlist)) != NULL)
|
||||
auth_delete(a);
|
||||
|
||||
else
|
||||
if (auth_find(name, 0, &a) == ISC_R_SUCCESS)
|
||||
auth_delete(a);
|
||||
|
||||
UNLOCK(&mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a message from the client to the server that says the key with the
|
||||
* given name should be used to authenticate messages.
|
||||
*/
|
||||
isc_result_t
|
||||
omapi_auth_use(omapi_object_t *manager, const char *name,
|
||||
unsigned int algorithm) {
|
||||
omapi_protocol_t *protocol;
|
||||
omapi_connection_t *connection;
|
||||
omapi_object_t *message = NULL;
|
||||
omapi_object_t *generic = NULL;
|
||||
isc_result_t result;
|
||||
auth_t *auth = NULL;
|
||||
|
||||
REQUIRE(manager != NULL);
|
||||
REQUIRE(manager->type == omapi_type_protocol ||
|
||||
(manager->outer != NULL &&
|
||||
manager->outer->type == omapi_type_protocol));
|
||||
|
||||
if (manager->type == omapi_type_protocol)
|
||||
protocol = (omapi_protocol_t *)manager;
|
||||
else
|
||||
protocol = (omapi_protocol_t *)manager->outer;
|
||||
|
||||
REQUIRE(protocol->outer != NULL &&
|
||||
protocol->outer->type == omapi_type_connection);
|
||||
|
||||
connection = (omapi_connection_t *)protocol->outer;
|
||||
|
||||
INSIST(connection->is_client);
|
||||
|
||||
RUNTIME_CHECK(isc_once_do(&once, initialize_mutex) == ISC_R_SUCCESS);
|
||||
LOCK(&mutex);
|
||||
|
||||
result = auth_find(name, algorithm, &auth);
|
||||
|
||||
UNLOCK(&mutex);
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
result = omapi_object_create(&generic, NULL, 0);
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
result = omapi_message_create(&message);
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
result = omapi_object_setinteger(message, "op", OMAPI_OP_OPEN);
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
result = omapi_object_setboolean(message, "update", ISC_TRUE);
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
result = omapi_object_setstring(message, "type", "protocol");
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
result = omapi_object_setobject(message, "object", generic);
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
result = omapi_object_setstring(generic, "auth-name", name);
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
result = omapi_object_setinteger(generic, "auth-algorithm",
|
||||
(int)algorithm);
|
||||
|
||||
if (message != NULL)
|
||||
omapi_message_register(message);
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
result = omapi_message_send(message, manager);
|
||||
|
||||
if (message != NULL) {
|
||||
omapi_message_unregister(message);
|
||||
omapi_object_dereference(&message);
|
||||
}
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
/*
|
||||
* If the name was not found on the server, ISC_R_NOTFOUND
|
||||
* will be returned. Unlike with a username/password pair,
|
||||
* where it is undesirable to disclose whether it was the
|
||||
* username or password that was at fault, only one item
|
||||
* can be discerned here -- the name, since the secret is
|
||||
* not exchanged. Therefore there is no point in having
|
||||
* the server obfuscate the ISC_R_NOTFOUND error into some
|
||||
* other error.
|
||||
*/
|
||||
result = generic->waitresult;
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
/*
|
||||
* This sets up the key in the protocol structure
|
||||
* on this side of the connection.
|
||||
*/
|
||||
result = object_update((omapi_object_t *)protocol, generic, 0);
|
||||
|
||||
if (generic != NULL)
|
||||
omapi_object_dereference(&generic);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
void
|
||||
auth_destroy(void) {
|
||||
omapi_auth_deregister(NULL);
|
||||
|
||||
DESTROYLOCK(&mutex);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
214
lib/omapi/data.c
214
lib/omapi/data.c
@ -1,214 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1996-2001 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: data.c,v 1.19 2001/01/09 21:59:56 bwelling Exp $ */
|
||||
|
||||
/* Principal Author: Ted Lemon */
|
||||
|
||||
/*
|
||||
* Functions supporting memory allocation for the object management protocol.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdlib.h> /* Required on BSD/OS 3.1 for abort() used in va_arg(). */
|
||||
|
||||
#include <isc/mem.h>
|
||||
#include <isc/string.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <omapi/private.h>
|
||||
|
||||
isc_result_t
|
||||
omapi_data_create(omapi_data_t **t, omapi_datatype_t type, ...) {
|
||||
va_list l;
|
||||
omapi_data_t *new;
|
||||
unsigned int len;
|
||||
unsigned int val;
|
||||
int intval;
|
||||
char *s;
|
||||
|
||||
REQUIRE(type == omapi_datatype_int ||
|
||||
type == omapi_datatype_data ||
|
||||
type == omapi_datatype_string ||
|
||||
type == omapi_datatype_object);
|
||||
|
||||
va_start(l, type);
|
||||
|
||||
/*
|
||||
* Quiet bogus "might be used uninitialized in this function" warnings.
|
||||
*/
|
||||
val = 0;
|
||||
intval = 0;
|
||||
s = NULL;
|
||||
|
||||
switch (type) {
|
||||
case omapi_datatype_int:
|
||||
len = OMAPI_DATA_INT_LEN;
|
||||
intval = va_arg(l, int);
|
||||
break;
|
||||
case omapi_datatype_string:
|
||||
s = va_arg(l, char *);
|
||||
val = strlen(s);
|
||||
len = OMAPI_DATA_NOBUFFER_LEN + val;
|
||||
break;
|
||||
case omapi_datatype_data:
|
||||
val = va_arg(l, unsigned int);
|
||||
len = OMAPI_DATA_NOBUFFER_LEN + val;
|
||||
break;
|
||||
case omapi_datatype_object:
|
||||
len = OMAPI_DATA_OBJECT_LEN;
|
||||
break;
|
||||
default:
|
||||
UNEXPECTED_ERROR(__FILE__, __LINE__,
|
||||
"unknown type in omapi_data_create: %d",
|
||||
type);
|
||||
return (ISC_R_UNEXPECTED);
|
||||
}
|
||||
|
||||
new = isc_mem_get(omapi_mctx, len);
|
||||
if (new == NULL)
|
||||
return (ISC_R_NOMEMORY);
|
||||
memset(new, 0, len);
|
||||
|
||||
switch (type) {
|
||||
case omapi_datatype_int:
|
||||
new->u.integer = intval;
|
||||
break;
|
||||
case omapi_datatype_string:
|
||||
memcpy(new->u.buffer.value, s, val);
|
||||
new->u.buffer.len = val;
|
||||
break;
|
||||
case omapi_datatype_data:
|
||||
new->u.buffer.len = val;
|
||||
break;
|
||||
case omapi_datatype_object:
|
||||
OBJECT_REF(&new->u.object, va_arg(l, omapi_object_t *));
|
||||
break;
|
||||
}
|
||||
new->type = type;
|
||||
omapi_data_reference(t, new);
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
void
|
||||
omapi_data_reference(omapi_data_t **r, omapi_data_t *h) {
|
||||
REQUIRE(r != NULL && h != NULL);
|
||||
REQUIRE(*r == NULL);
|
||||
|
||||
*r = h;
|
||||
h->refcnt++;
|
||||
}
|
||||
|
||||
void
|
||||
omapi_data_dereference(omapi_data_t **h) {
|
||||
unsigned int length = 0;
|
||||
|
||||
|
||||
REQUIRE(h != NULL && *h != NULL);
|
||||
REQUIRE((*h)->refcnt > 0);
|
||||
|
||||
if (--((*h)->refcnt) == 0) {
|
||||
switch ((*h)->type) {
|
||||
case omapi_datatype_int:
|
||||
length = OMAPI_DATA_INT_LEN;
|
||||
break;
|
||||
case omapi_datatype_string:
|
||||
length = OMAPI_DATA_NOBUFFER_LEN + (*h)->u.buffer.len;
|
||||
break;
|
||||
case omapi_datatype_data:
|
||||
length = OMAPI_DATA_NOBUFFER_LEN + (*h)->u.buffer.len;
|
||||
break;
|
||||
case omapi_datatype_object:
|
||||
OBJECT_DEREF(&(*h)->u.object);
|
||||
length = OMAPI_DATA_OBJECT_LEN;
|
||||
break;
|
||||
default:
|
||||
FATAL_ERROR(__FILE__, __LINE__,
|
||||
"unknown datatype in "
|
||||
"omapi_data_dereference: %d\n",
|
||||
(*h)->type);
|
||||
/* NOTREACHED */
|
||||
break;
|
||||
}
|
||||
isc_mem_put(omapi_mctx, *h, length);
|
||||
}
|
||||
|
||||
*h = NULL;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
omapi_data_strcmp(omapi_data_t *s1, const char *s2) {
|
||||
unsigned int len, slen;
|
||||
int order;
|
||||
|
||||
REQUIRE(s1->type == omapi_datatype_data ||
|
||||
s1->type == omapi_datatype_string);
|
||||
|
||||
slen = strlen(s2);
|
||||
if (slen > s1->u.buffer.len)
|
||||
len = s1->u.buffer.len;
|
||||
else
|
||||
len = slen;
|
||||
|
||||
order = memcmp(s1->u.buffer.value, s2, len);
|
||||
if (order == 0) {
|
||||
if (s1->u.buffer.len > slen)
|
||||
order = 1;
|
||||
else if (s1->u.buffer.len < slen)
|
||||
order = -1;
|
||||
}
|
||||
|
||||
return (order);
|
||||
}
|
||||
|
||||
int
|
||||
omapi_data_getint(omapi_data_t *t) {
|
||||
isc_uint32_t stored_value; /* Stored in network byte order. */
|
||||
|
||||
REQUIRE(t != NULL);
|
||||
REQUIRE(t->type == omapi_datatype_int ||
|
||||
((t->type == omapi_datatype_data ||
|
||||
(t->type == omapi_datatype_string)) &&
|
||||
t->u.buffer.len == sizeof(stored_value)));
|
||||
|
||||
if (t->type == omapi_datatype_int)
|
||||
return (t->u.integer);
|
||||
|
||||
memcpy(&stored_value, t->u.buffer.value, sizeof(stored_value));
|
||||
|
||||
return (ntohl(stored_value));
|
||||
}
|
||||
|
||||
char *
|
||||
omapi_data_strdup(isc_mem_t *mctx, omapi_data_t *t) {
|
||||
char *s;
|
||||
|
||||
REQUIRE(mctx != NULL && t != NULL);
|
||||
REQUIRE(t->type == omapi_datatype_string ||
|
||||
t->type == omapi_datatype_data);
|
||||
|
||||
s = isc_mem_allocate(mctx, t->u.buffer.len + 1);
|
||||
if (s != NULL) {
|
||||
memcpy(s, t->u.buffer.value, t->u.buffer.len);
|
||||
s[t->u.buffer.len] = '\0';
|
||||
}
|
||||
|
||||
return (s);
|
||||
}
|
@ -1,256 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1996-2001 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: generic.c,v 1.18 2001/01/09 21:59:57 bwelling Exp $ */
|
||||
|
||||
/* Principal Author: Ted Lemon */
|
||||
|
||||
/*
|
||||
* Subroutines that support the generic object.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdlib.h> /* Required on BSD/OS 3.1 for abort() used in va_arg(). */
|
||||
|
||||
#include <isc/mem.h>
|
||||
#include <isc/string.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <omapi/private.h>
|
||||
|
||||
static isc_result_t
|
||||
generic_setvalue(omapi_object_t *h, omapi_string_t *name, omapi_data_t *value)
|
||||
{
|
||||
omapi_generic_t *g;
|
||||
omapi_value_t *new;
|
||||
omapi_value_t **va;
|
||||
int vm_new;
|
||||
unsigned int i;
|
||||
isc_result_t result;
|
||||
|
||||
REQUIRE(h != NULL && h->type == omapi_type_generic);
|
||||
|
||||
g = (omapi_generic_t *)h;
|
||||
|
||||
/*
|
||||
* See if there's already a value with this name attached to
|
||||
* the generic object, and if so, replace the current value
|
||||
* with the new one.
|
||||
*/
|
||||
for (i = 0; i < g->nvalues; i++) {
|
||||
if (omapi_string_stringcmp(name, g->values[i]->name) == 0) {
|
||||
/*
|
||||
* There's an inconsistency here: the standard
|
||||
* behaviour of a set_values method when
|
||||
* passed a matching name and a null value is
|
||||
* to delete the value associated with that
|
||||
* name (where possible). In the generic
|
||||
* object, we remember the name/null pair,
|
||||
* because generic objects are generally used
|
||||
* to pass messages around, and this is the
|
||||
* way that remote entities delete values from
|
||||
* local objects. If the get_value method of
|
||||
* a generic object is called for a name that
|
||||
* maps to a name/null pair, ISC_R_NOTFOUND is
|
||||
* returned.
|
||||
*/
|
||||
new = NULL;
|
||||
result = omapi_value_create(&new);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (result);
|
||||
|
||||
omapi_string_reference(&new->name, name);
|
||||
if (value != NULL)
|
||||
omapi_data_reference(&new->value, value);
|
||||
|
||||
omapi_value_dereference(&(g->values[i]));
|
||||
omapi_value_reference(&(g->values[i]), new);
|
||||
omapi_value_dereference(&new);
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the name isn't already attached to this object, see if an
|
||||
* inner object has it.
|
||||
*/
|
||||
result = omapi_object_passsetvalue(h, name, value);
|
||||
if (result != ISC_R_NOTFOUND)
|
||||
return (result);
|
||||
|
||||
/*
|
||||
* Okay, so it's a value that no inner object knows about, and
|
||||
* (implicitly, since the outer object set_value method would
|
||||
* have called this object's set_value method) it's an object that
|
||||
* no outer object knows about, it's this object's responsibility
|
||||
* to remember it - that's what generic objects do.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Arrange for there to be space for the pointer to the new
|
||||
* name/value pair if necessary.
|
||||
*/
|
||||
if (g->nvalues == g->va_max) {
|
||||
/*
|
||||
* 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)
|
||||
return (ISC_R_NOMEMORY);
|
||||
if (g->va_max != 0) {
|
||||
memcpy(va, g->values, g->va_max * sizeof(*va));
|
||||
isc_mem_put(omapi_mctx, g->values,
|
||||
g->va_max * sizeof(*va));
|
||||
}
|
||||
|
||||
memset(va + g->va_max, 0, (vm_new - g->va_max) * sizeof(*va));
|
||||
g->values = va;
|
||||
g->va_max = vm_new;
|
||||
}
|
||||
result = omapi_value_create(&g->values[g->nvalues]);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (result);
|
||||
|
||||
omapi_string_reference(&g->values[g->nvalues]->name, name);
|
||||
if (value != NULL)
|
||||
omapi_data_reference(&g->values[g->nvalues]->value, value);
|
||||
g->nvalues++;
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
generic_getvalue(omapi_object_t *h, omapi_string_t *name,
|
||||
omapi_value_t **value)
|
||||
{
|
||||
unsigned int i;
|
||||
omapi_generic_t *g;
|
||||
|
||||
REQUIRE(h != NULL && h->type == omapi_type_generic);
|
||||
|
||||
g = (omapi_generic_t *)h;
|
||||
|
||||
/*
|
||||
* Look up the specified name in our list of objects.
|
||||
*/
|
||||
for (i = 0; i < g->nvalues; i++) {
|
||||
if (omapi_string_stringcmp(name, g->values[i]->name) == 0) {
|
||||
/*
|
||||
* If this is a name/null value pair, this is the
|
||||
* same as if there were no value that matched
|
||||
* the specified name, so return ISC_R_NOTFOUND.
|
||||
*/
|
||||
if (g->values[i]->value == NULL)
|
||||
return (ISC_R_NOTFOUND);
|
||||
/*
|
||||
* Otherwise, return the name/value pair.
|
||||
*/
|
||||
omapi_value_reference(value, g->values[i]);
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
return (omapi_object_passgetvalue(h, name, value));
|
||||
}
|
||||
|
||||
static void
|
||||
generic_destroy(omapi_object_t *h) {
|
||||
omapi_generic_t *g;
|
||||
unsigned int i;
|
||||
|
||||
REQUIRE(h != NULL && h->type == omapi_type_generic);
|
||||
|
||||
g = (omapi_generic_t *)h;
|
||||
|
||||
if (g->values != NULL) {
|
||||
for (i = 0; i < g->nvalues; i++)
|
||||
if (g->values[i] != NULL)
|
||||
omapi_value_dereference(&g->values[i]);
|
||||
|
||||
isc_mem_put(omapi_mctx, g->values,
|
||||
g->va_max * sizeof(*g->values));
|
||||
g->values = NULL;
|
||||
g->va_max = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
generic_signalhandler(omapi_object_t *h, const char *name, va_list ap) {
|
||||
REQUIRE(h != NULL && h->type == omapi_type_generic);
|
||||
|
||||
/*
|
||||
* XXXDCL I suppose that ideally the status would be set in all
|
||||
* objects in the chain.
|
||||
*/
|
||||
if (strcmp(name, "status") == 0) {
|
||||
h->waitresult = va_arg(ap, isc_result_t);
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
return (omapi_object_passsignal(h, name, ap));
|
||||
}
|
||||
|
||||
/*
|
||||
* Write all the published values associated with the object through the
|
||||
* specified connection.
|
||||
*/
|
||||
static isc_result_t
|
||||
generic_stuffvalues(omapi_object_t *connection, omapi_object_t *h) {
|
||||
omapi_generic_t *src;
|
||||
unsigned int i;
|
||||
isc_result_t result;
|
||||
|
||||
REQUIRE(h != NULL && h->type == omapi_type_generic);
|
||||
|
||||
src = (omapi_generic_t *)h;
|
||||
|
||||
for (i = 0; i < src->nvalues; i++) {
|
||||
if (src->values[i] != NULL &&
|
||||
src->values[i]->name->len != 0) {
|
||||
result = omapi_connection_putuint16(connection,
|
||||
src->values[i]->name->len);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (result);
|
||||
result = omapi_connection_putmem(connection,
|
||||
src->values[i]->name->value,
|
||||
src->values[i]->name->len);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (result);
|
||||
|
||||
result = omapi_connection_putdata(connection,
|
||||
src->values[i]->value);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (result);
|
||||
}
|
||||
}
|
||||
|
||||
return (omapi_object_passstuffvalues(connection, h));
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
generic_init(void) {
|
||||
return (omapi_object_register(&omapi_type_generic, "generic",
|
||||
generic_setvalue,
|
||||
generic_getvalue,
|
||||
generic_destroy,
|
||||
generic_signalhandler,
|
||||
generic_stuffvalues,
|
||||
NULL, NULL, NULL));
|
||||
}
|
@ -1,352 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1996-2001 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: handle.c,v 1.18 2001/01/09 21:59:58 bwelling Exp $ */
|
||||
|
||||
/* Principal Author: Ted Lemon */
|
||||
|
||||
/*
|
||||
* Functions for maintaining handles on objects.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <isc/mem.h>
|
||||
#include <isc/once.h>
|
||||
#include <isc/string.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <omapi/private.h>
|
||||
|
||||
/*
|
||||
* The handle table is a hierarchical tree designed for quick mapping
|
||||
* of handle identifiers to objects. Objects contain their own handle
|
||||
* identifiers if they have them, so the reverse mapping is also
|
||||
* quick. The hierarchy is made up of table objects, each of which
|
||||
* has 120 entries, a flag indicating whether the table is a leaf
|
||||
* table or an indirect table, the handle of the first object covered
|
||||
* by the table and the first object after that that's *not* covered
|
||||
* by the table, a count of how many objects of either type are
|
||||
* currently stored in the table, and an array of 120 entries pointing
|
||||
* either to objects or tables.
|
||||
*
|
||||
* When we go to add an object to the table, we look to see if the
|
||||
* next object handle to be assigned is covered by the outermost
|
||||
* table. If it is, we find the place within that table where the
|
||||
* next handle should go, and if necessary create additional nodes in
|
||||
* the tree to contain the new handle. The pointer to the object is
|
||||
* then stored in the correct position.
|
||||
*
|
||||
* XXXTL
|
||||
* Theoretically, we could have some code here to free up handle
|
||||
* tables as they go out of use, but by and large handle tables won't
|
||||
* go out of use, so this is being skipped for now. It shouldn't be
|
||||
* too hard to implement in the future if there's a different
|
||||
* application.
|
||||
*/
|
||||
|
||||
#define OMAPI_HANDLETABLE_SIZE 120
|
||||
|
||||
typedef struct omapi_handletable {
|
||||
omapi_handle_t first;
|
||||
omapi_handle_t limit;
|
||||
omapi_handle_t next;
|
||||
isc_boolean_t leaf;
|
||||
union {
|
||||
omapi_object_t * object;
|
||||
struct omapi_handletable * table;
|
||||
} children[OMAPI_HANDLETABLE_SIZE];
|
||||
} omapi_handletable_t;
|
||||
|
||||
static omapi_handletable_t *toptable;
|
||||
static omapi_handle_t next_handle = 1; /* Next handle to be assigned. */
|
||||
static isc_mutex_t mutex; /* To lock the 2 previous variables. */
|
||||
static isc_once_t once = ISC_ONCE_INIT; /* To initialize the mutex. */
|
||||
|
||||
/*
|
||||
* initialize_mutex() is called by isc_once_do in object_gethandle()
|
||||
*/
|
||||
static void
|
||||
initialize_mutex(void) {
|
||||
RUNTIME_CHECK(isc_mutex_init(&mutex) == ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
table_enclose(omapi_handletable_t **table) {
|
||||
omapi_handletable_t *inner = *table;
|
||||
omapi_handletable_t *new;
|
||||
int idx, base, scale;
|
||||
|
||||
/*
|
||||
* The scale of the table we're enclosing is going to be the
|
||||
* difference between its "first" and "limit" members. So the
|
||||
* scale of the table enclosing it is going to be that multiplied
|
||||
* by the table size.
|
||||
*/
|
||||
scale = (inner->first - inner->limit) * OMAPI_HANDLETABLE_SIZE;
|
||||
|
||||
/*
|
||||
* The range that the enclosing table covers is going to be
|
||||
* the result of subtracting the remainder of dividing the
|
||||
* enclosed table's first entry number by the enclosing
|
||||
* table's scale. If handle IDs are being allocated
|
||||
* sequentially, the enclosing table's "first" value will be
|
||||
* the same as the enclosed table's "first" value.
|
||||
*/
|
||||
base = inner->first - inner->first % scale;
|
||||
|
||||
/*
|
||||
* The index into the enclosing table at which the enclosed table
|
||||
* will be stored is going to be the difference between the "first"
|
||||
* value of the enclosing table and the enclosed table - zero, if
|
||||
* we are allocating sequentially.
|
||||
*/
|
||||
idx = (base - inner->first) / OMAPI_HANDLETABLE_SIZE;
|
||||
|
||||
new = isc_mem_get(omapi_mctx, sizeof(*new));
|
||||
if (new == NULL)
|
||||
return (ISC_R_NOMEMORY);
|
||||
memset(new, 0, sizeof *new);
|
||||
new->first = base;
|
||||
new->limit = base + scale;
|
||||
if (scale == OMAPI_HANDLETABLE_SIZE)
|
||||
new->leaf = ISC_FALSE;
|
||||
new->children[idx].table = inner;
|
||||
*table = new;
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
handle_store(omapi_handle_t h, omapi_handletable_t *table, omapi_object_t *o) {
|
||||
omapi_handletable_t *inner;
|
||||
omapi_handle_t scale, idx;
|
||||
isc_result_t result;
|
||||
|
||||
if (table->first > h || table->limit <= h)
|
||||
return (ISC_R_NOSPACE);
|
||||
|
||||
/*
|
||||
* If this is a leaf table, just stash the object in the
|
||||
* appropriate place.
|
||||
*/
|
||||
if (table->leaf) {
|
||||
OBJECT_REF(&table->children[h - table->first].object, o);
|
||||
o->handle = h;
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* Scale is the number of handles represented by each child of this
|
||||
* table. For a leaf table, scale would be 1. For a first level
|
||||
* of indirection, 120. For a second, 120 * 120. Et cetera.
|
||||
*/
|
||||
scale = (table->limit - table->first) / OMAPI_HANDLETABLE_SIZE;
|
||||
|
||||
/*
|
||||
* So the next most direct table from this one that contains the
|
||||
* handle must be the subtable of this table whose index into this
|
||||
* table's array of children is the handle divided by the scale.
|
||||
*/
|
||||
idx = (h - table->first) / scale;
|
||||
inner = table->children[idx].table;
|
||||
|
||||
/*
|
||||
* If there is no more direct table than this one in the slot
|
||||
* we came up with, make one.
|
||||
*/
|
||||
if (inner == NULL) {
|
||||
inner = isc_mem_get(omapi_mctx, sizeof(*inner));
|
||||
if (inner == NULL)
|
||||
return (ISC_R_NOMEMORY);
|
||||
memset(inner, 0, sizeof(*inner));
|
||||
inner->first = idx * scale + table->first;
|
||||
inner->limit = inner->first + scale;
|
||||
if (scale == OMAPI_HANDLETABLE_SIZE)
|
||||
inner->leaf = ISC_TRUE;
|
||||
table->children[idx].table = inner;
|
||||
}
|
||||
|
||||
result = handle_store(h, inner, o);
|
||||
if (result == ISC_R_NOSPACE) {
|
||||
result = (table_enclose
|
||||
(&table->children[idx].table));
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (result);
|
||||
|
||||
return (handle_store(h, table->children[idx].table, o));
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
object_gethandle(omapi_handle_t *h, omapi_object_t *o) {
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
|
||||
RUNTIME_CHECK(isc_once_do(&once, initialize_mutex) == ISC_R_SUCCESS);
|
||||
|
||||
LOCK(&mutex);
|
||||
|
||||
if (o->handle != 0) {
|
||||
*h = o->handle;
|
||||
UNLOCK(&mutex);
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
if (toptable == NULL) {
|
||||
toptable = isc_mem_get(omapi_mctx, sizeof(*toptable));
|
||||
if (toptable != NULL) {
|
||||
memset(toptable, 0, sizeof(*toptable));
|
||||
toptable->first = 0;
|
||||
toptable->limit = OMAPI_HANDLETABLE_SIZE;
|
||||
toptable->leaf = ISC_TRUE;
|
||||
|
||||
} else
|
||||
result = ISC_R_NOMEMORY;
|
||||
}
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
/*
|
||||
* If this handle doesn't fit in the outer table, we need to
|
||||
* make a new outer table. This is a while loop in case for
|
||||
* some reason we decide to do disjoint handle allocation,
|
||||
* where the next level of indirection still isn't big enough
|
||||
* to enclose the next handle ID.
|
||||
*/
|
||||
while (next_handle >= toptable->limit) {
|
||||
omapi_handletable_t *new;
|
||||
|
||||
new = isc_mem_get(omapi_mctx, sizeof(*new));
|
||||
if (new != NULL) {
|
||||
memset(new, 0, sizeof(*new));
|
||||
new->first = 0;
|
||||
new->limit = toptable->limit *
|
||||
OMAPI_HANDLETABLE_SIZE;
|
||||
new->leaf = ISC_FALSE;
|
||||
new->children[0].table = toptable;
|
||||
toptable = new;
|
||||
|
||||
} else
|
||||
result = ISC_R_NOMEMORY;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to cram this handle into the existing table.
|
||||
*/
|
||||
if (result == ISC_R_SUCCESS)
|
||||
result = handle_store(next_handle, toptable, o);
|
||||
|
||||
if (result == ISC_R_NOSPACE) {
|
||||
result = table_enclose(&toptable);
|
||||
if (result == ISC_R_SUCCESS)
|
||||
result = handle_store(next_handle, toptable, o);
|
||||
}
|
||||
|
||||
/*
|
||||
* If it worked, return the next handle and increment it.
|
||||
*/
|
||||
if (result == ISC_R_SUCCESS)
|
||||
*h = next_handle++;
|
||||
|
||||
UNLOCK(&mutex);
|
||||
return (result);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
lookup_iterate(omapi_object_t **o, omapi_handle_t h,
|
||||
omapi_handletable_t *table)
|
||||
{
|
||||
omapi_handletable_t *inner;
|
||||
omapi_handle_t scale, idx;
|
||||
|
||||
if (table == NULL || table->first > h || table->limit <= h)
|
||||
return (ISC_R_NOTFOUND);
|
||||
|
||||
/*
|
||||
* If this is a leaf table, just grab the object.
|
||||
*/
|
||||
if (table->leaf) {
|
||||
/*
|
||||
* Not there?
|
||||
*/
|
||||
if (table->children[h - table->first].object == NULL)
|
||||
return (ISC_R_NOTFOUND);
|
||||
|
||||
OBJECT_REF(o, table->children[h - table->first].object);
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* Scale is the number of handles represented by each child of this
|
||||
* table. For a leaf table, scale would be 1. For a first level
|
||||
* of indirection, 120. For a second, 120 * 120. Et cetera.
|
||||
*/
|
||||
scale = (table->limit - table->first) / OMAPI_HANDLETABLE_SIZE;
|
||||
|
||||
/*
|
||||
* So the next most direct table from this one that contains the
|
||||
* handle must be the subtable of this table whose index into this
|
||||
* table's array of children is the handle divided by the scale.
|
||||
*/
|
||||
idx = (h - table->first) / scale;
|
||||
inner = table->children[idx].table;
|
||||
|
||||
return (lookup_iterate(o, h, inner));
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
handle_lookup(omapi_object_t **o, omapi_handle_t h) {
|
||||
isc_result_t result;
|
||||
|
||||
LOCK(&mutex);
|
||||
|
||||
result = lookup_iterate(o, h, toptable);
|
||||
|
||||
UNLOCK(&mutex);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
static void
|
||||
free_table(omapi_handletable_t **table) {
|
||||
int i;
|
||||
|
||||
if ((*table)->leaf)
|
||||
isc_mem_put(omapi_mctx, *table, sizeof(**table));
|
||||
|
||||
else
|
||||
for (i = 0; i < OMAPI_HANDLETABLE_SIZE; i++)
|
||||
if ((*table)->children[i].table != NULL)
|
||||
free_table(&(*table)->children[i].table);
|
||||
else
|
||||
break;
|
||||
|
||||
*table = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
handle_destroy(void) {
|
||||
RUNTIME_CHECK(isc_once_do(&once, initialize_mutex) == ISC_R_SUCCESS);
|
||||
|
||||
LOCK(&mutex);
|
||||
|
||||
if (toptable != NULL)
|
||||
free_table(&toptable);
|
||||
|
||||
UNLOCK(&mutex);
|
||||
|
||||
DESTROYLOCK(&mutex);
|
||||
}
|
@ -1 +0,0 @@
|
||||
Makefile
|
@ -1,25 +0,0 @@
|
||||
# Copyright (C) 1999-2001 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: Makefile.in,v 1.6 2001/01/09 22:00:22 bwelling Exp $
|
||||
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
|
||||
SUBDIRS = omapi
|
||||
TARGETS =
|
||||
|
||||
@BIND9_MAKE_RULES@
|
@ -1 +0,0 @@
|
||||
Makefile
|
@ -1,37 +0,0 @@
|
||||
# Copyright (C) 1999-2001 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: Makefile.in,v 1.11 2001/01/09 22:00:24 bwelling Exp $
|
||||
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
|
||||
@BIND9_VERSION@
|
||||
|
||||
HEADERS = compatibility.h lib.h omapi.h private.h result.h types.h
|
||||
|
||||
SUBDIRS =
|
||||
TARGETS =
|
||||
|
||||
@BIND9_MAKE_RULES@
|
||||
|
||||
installdirs:
|
||||
$(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/omapi
|
||||
|
||||
install:: installdirs
|
||||
for i in ${HEADERS}; do \
|
||||
${INSTALL_DATA} ${srcdir}/$$i ${DESTDIR}${includedir}/omapi ; \
|
||||
done
|
@ -1,93 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2000, 2001 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: compatibility.h,v 1.7 2001/01/09 22:00:25 bwelling Exp $ */
|
||||
|
||||
#ifndef OMAPI_COMPATIBILITY_H
|
||||
#define OMAPI_COMPATIBILITY_H 1
|
||||
|
||||
#include <isc/result.h>
|
||||
|
||||
/*****
|
||||
***** Macro definitions for partial compatability with Ted Lemon's original
|
||||
***** design of OMAPI for DCHP. The intent is that with by using this header
|
||||
***** than few changes need be made immediately to the source code in order
|
||||
***** to get it working with the updated OMAPI library. The other changes
|
||||
***** can then be made as is convenient.
|
||||
*****/
|
||||
|
||||
/*
|
||||
* Waiting is done inherently on the client now. It didn't seem to me
|
||||
* that the server needs it, but if it does, connection_wait() could
|
||||
* be made public as omapi_connection_wait().
|
||||
*/
|
||||
#define omapi_wait_for_completion(o, t) ISC_R_SUCCESS
|
||||
|
||||
#define omapi_value_new(v, i) omapi_value_create(v)
|
||||
#define omapi_make_value omapi_value_storedata
|
||||
#define omapi_make_const_value omapi_value_storemem
|
||||
#define omapi_make_int_value omapi_value_storeint
|
||||
#define omapi_make_handle_value omapi_value_storeobject
|
||||
#define omapi_make_string_value omapi_value_storestr
|
||||
|
||||
#define omapi_data_new omapi_data_create
|
||||
#define omapi_td_strcmp omapi_data_strcmp
|
||||
#define omapi_get_int_value omapi_data_getint
|
||||
|
||||
#define omapi_data_string_new(s, l, i) omapi_string_create(s, l)
|
||||
#define omapi_data_string_cmp omapi_string_stringcmp
|
||||
#define omapi_ds_strcmp omapi_string_strcmp
|
||||
|
||||
/*
|
||||
* The get_value, set_value and stuff_values methods all had their id
|
||||
* parameter removed, so those functions for special client/server objects
|
||||
* need to have their definitions adjusted.
|
||||
*
|
||||
*/
|
||||
#define omapi_set_value(h, id, name, value) \
|
||||
omapi_object_set(h, name, value)
|
||||
#define omapi_set_value_str(h, id, name, value) \
|
||||
omapi_object_setdata(h, name, value)
|
||||
#define omapi_set_boolean_value(h, id, name, value) \
|
||||
omapi_object_setboolean(h, name, value)
|
||||
#define omapi_set_int_value(h, id, name, value) \
|
||||
omapi_object_setinteger(h, name, value)
|
||||
#define omapi_set_object_value(h, id, name, value) \
|
||||
omapi_object_setobject(h, name, value)
|
||||
#define omapi_set_string_value(h, id, name, value) \
|
||||
omapi_object_setstring(h, name, value)
|
||||
#define omapi_get_value_str(h, id, name, value) \
|
||||
omapi_object_getvalue(h, name, value)
|
||||
#define omapi_object_type_register omapi_object_register
|
||||
|
||||
#define omapi_init omapi_lib_init
|
||||
|
||||
#define omapi_message_new(m, id) omapi_message_create(m)
|
||||
#define omapi_protocol_send_message(po, id, mo, omo) \
|
||||
omapi_message_send(mo, po)
|
||||
|
||||
#define omapi_listen omapi_listener_listen
|
||||
|
||||
#define omapi_connection_copyin omapi_connection_putmem
|
||||
#define omapi_connection_put_uint16 omapi_connection_putuin16
|
||||
#define omapi_connection_put_uint32 omapi_connection_putuin32
|
||||
#define omapi_connection_put_name omapi_connection_putname
|
||||
#define omapi_connection_put_string omapi_connection_putstring
|
||||
#define omapi_connection_put_handle omapi_connection_puthandle
|
||||
#define omapi_connection_write_typed_data omapi_connection_putdata
|
||||
|
||||
#endif /* OMAPI_COMPATIBILITY_H */
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1999-2001 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: lib.h,v 1.6 2001/01/09 22:00:26 bwelling Exp $ */
|
||||
|
||||
#ifndef OMAPI_LIB_H
|
||||
#define OMAPI_LIB_H 1
|
||||
|
||||
#include <isc/types.h>
|
||||
#include <isc/lang.h>
|
||||
|
||||
ISC_LANG_BEGINDECLS
|
||||
|
||||
extern isc_msgcat_t *omapi_msgcat;
|
||||
|
||||
void
|
||||
omapi_lib_initmsgcat(void);
|
||||
/*
|
||||
* Initialize the OMAPI library's message catalog, omapi_msgcat, if it
|
||||
* has not already been initialized.
|
||||
*/
|
||||
|
||||
ISC_LANG_ENDDECLS
|
||||
|
||||
#endif /* OMAPI_LIB_H */
|
@ -1,382 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1996-2001 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: omapi.h,v 1.19 2001/02/15 19:13:48 bwelling Exp $ */
|
||||
|
||||
/*
|
||||
* Definitions for the object management API and protocol.
|
||||
*/
|
||||
|
||||
#ifndef OMAPI_OMAPI_H
|
||||
#define OMAPI_OMAPI_H 1
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <isc/boolean.h>
|
||||
#include <isc/eventclass.h>
|
||||
#include <isc/lang.h>
|
||||
|
||||
#include <omapi/types.h>
|
||||
|
||||
ISC_LANG_BEGINDECLS
|
||||
|
||||
#define OMAPI_PROTOCOL_VERSION 100
|
||||
|
||||
/*
|
||||
* Protocol operations.
|
||||
*/
|
||||
#define OMAPI_OP_OPEN 1
|
||||
#define OMAPI_OP_REFRESH 2
|
||||
#define OMAPI_OP_UPDATE 3
|
||||
#define OMAPI_OP_NOTIFY 4
|
||||
#define OMAPI_OP_STATUS 5
|
||||
#define OMAPI_OP_DELETE 6
|
||||
|
||||
/*
|
||||
* This preamble is common to all objects manipulated by libomapi.a,
|
||||
* including specials objects created by external users of the library.
|
||||
* It needs to be at the start of every struct that gets used as an object.
|
||||
*/
|
||||
#define OMAPI_OBJECT_PREAMBLE \
|
||||
omapi_objecttype_t * type; \
|
||||
size_t object_size; \
|
||||
int refcnt; \
|
||||
isc_result_t waitresult; \
|
||||
omapi_handle_t handle; \
|
||||
omapi_object_t *outer, *inner; \
|
||||
isc_taskaction_t destroy_action; \
|
||||
void * destroy_arg
|
||||
|
||||
/*
|
||||
* This is the most basic OMAPI object, used as the handle for all
|
||||
* other object types in most public calls.
|
||||
*/
|
||||
struct omapi_object {
|
||||
OMAPI_OBJECT_PREAMBLE;
|
||||
};
|
||||
|
||||
/*
|
||||
* For use with omapi_connection_disconnect().
|
||||
* XXXDCL rename
|
||||
*/
|
||||
#define OMAPI_FORCE_DISCONNECT ISC_TRUE
|
||||
#define OMAPI_CLEAN_DISCONNECT ISC_FALSE
|
||||
|
||||
/*
|
||||
* For use with omapi_auth_*. Will be powers of 2 when there is ever
|
||||
* more than one authentication algorithm available.
|
||||
*/
|
||||
#define OMAPI_AUTH_HMACMD5 1
|
||||
|
||||
#define OMAPI_EVENT_OBJECTFREED (ISC_EVENTCLASS_OMAPI + 1)
|
||||
|
||||
/*****
|
||||
***** Function Prototypes.
|
||||
*****/
|
||||
|
||||
/*
|
||||
* Public functions defined in auth.c.
|
||||
*/
|
||||
isc_result_t
|
||||
omapi_auth_register(const char *name, unsigned int algorithms,
|
||||
const unsigned char *secret, size_t secretlen);
|
||||
|
||||
void
|
||||
omapi_auth_deregister(const char *name);
|
||||
|
||||
isc_result_t
|
||||
omapi_auth_use(omapi_object_t *manager, const char *name,
|
||||
unsigned int algorithm);
|
||||
|
||||
/*
|
||||
* Public functions defined in protocol.c.
|
||||
*/
|
||||
isc_result_t
|
||||
omapi_protocol_connect(omapi_object_t *object, const char *server,
|
||||
in_port_t port, omapi_object_t *authinfo);
|
||||
|
||||
void
|
||||
omapi_protocol_disconnect(omapi_object_t *handle, isc_boolean_t force);
|
||||
|
||||
/*
|
||||
* XXXDCL The use of one void *arg for all three callbacks/taskactions is
|
||||
* questionable.
|
||||
*/
|
||||
isc_result_t
|
||||
omapi_protocol_listen(omapi_object_t *mgr, isc_sockaddr_t *addr,
|
||||
isc_boolean_t ((*verify_connection)
|
||||
(isc_sockaddr_t *incoming,
|
||||
void *connect_arg)),
|
||||
isc_boolean_t ((*verify_key)
|
||||
(const char *name,
|
||||
unsigned int algorithm,
|
||||
void *key_arg)),
|
||||
isc_taskaction_t destroy_action, void *arg);
|
||||
|
||||
/*
|
||||
* Public functions defined in connection.c.
|
||||
*/
|
||||
void
|
||||
omapi_connection_disconnect(omapi_object_t *connection, isc_boolean_t how);
|
||||
|
||||
isc_result_t
|
||||
omapi_connection_putmem(omapi_object_t *connection, const unsigned char *data,
|
||||
unsigned int length);
|
||||
|
||||
isc_result_t
|
||||
omapi_connection_putuint16(omapi_object_t *c, isc_uint32_t value);
|
||||
|
||||
isc_result_t
|
||||
omapi_connection_putuint32(omapi_object_t *c, isc_uint32_t value);
|
||||
|
||||
isc_result_t
|
||||
omapi_connection_putdata(omapi_object_t *connection, omapi_data_t *data);
|
||||
|
||||
isc_result_t
|
||||
omapi_connection_putname(omapi_object_t *connection, const char *name);
|
||||
|
||||
isc_result_t
|
||||
omapi_connection_putstring(omapi_object_t *connection, const char *string);
|
||||
|
||||
isc_result_t
|
||||
omapi_connection_puthandle(omapi_object_t *connection, omapi_object_t *object);
|
||||
|
||||
/*
|
||||
* Public functions defined in listen.c.
|
||||
*/
|
||||
isc_result_t
|
||||
omapi_listener_listen(omapi_object_t *mgr, isc_sockaddr_t *addr,
|
||||
isc_boolean_t ((*verify_connection)
|
||||
(isc_sockaddr_t *incoming,
|
||||
void *connect_arg)),
|
||||
isc_boolean_t ((*verify_key)
|
||||
(const char *name,
|
||||
unsigned int algorithm,
|
||||
void *key_arg)),
|
||||
isc_taskaction_t destroy_action, void *arg);
|
||||
|
||||
void
|
||||
omapi_listener_shutdown(omapi_object_t *mgr);
|
||||
|
||||
/*
|
||||
* Public functions defined in message.c.
|
||||
*/
|
||||
isc_result_t
|
||||
omapi_message_create(omapi_object_t **message);
|
||||
|
||||
void
|
||||
omapi_message_register(omapi_object_t *message);
|
||||
|
||||
void
|
||||
omapi_message_unregister(omapi_object_t *message);
|
||||
|
||||
isc_result_t
|
||||
omapi_message_send(omapi_object_t *message, omapi_object_t *protocol);
|
||||
|
||||
/*
|
||||
* Public functions defined in lib.c.
|
||||
*/
|
||||
isc_result_t
|
||||
omapi_lib_init(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
|
||||
isc_socketmgr_t *socketmgr);
|
||||
|
||||
void
|
||||
omapi_lib_destroy(void);
|
||||
|
||||
/*
|
||||
* Public functions defined in object.c.
|
||||
*/
|
||||
isc_result_t
|
||||
omapi_object_create(omapi_object_t **object, omapi_objecttype_t *type,
|
||||
size_t size);
|
||||
|
||||
void
|
||||
omapi_object_reference(omapi_object_t **reference, omapi_object_t *object);
|
||||
|
||||
void
|
||||
omapi_object_dereference(omapi_object_t **reference);
|
||||
|
||||
isc_result_t
|
||||
omapi_object_register(omapi_objecttype_t **type, const char *name,
|
||||
isc_result_t ((*set_value)(omapi_object_t *,
|
||||
omapi_string_t *,
|
||||
omapi_data_t *)),
|
||||
|
||||
isc_result_t ((*get_value)(omapi_object_t *,
|
||||
omapi_string_t *,
|
||||
omapi_value_t **)),
|
||||
|
||||
void ((*destroy)(omapi_object_t *)),
|
||||
|
||||
isc_result_t ((*signal_handler)(omapi_object_t *,
|
||||
const char *,
|
||||
va_list)),
|
||||
|
||||
isc_result_t ((*stuff_values)(omapi_object_t *,
|
||||
omapi_object_t *)),
|
||||
|
||||
isc_result_t ((*lookup)(omapi_object_t **,
|
||||
omapi_object_t *)),
|
||||
|
||||
isc_result_t ((*create)(omapi_object_t **)),
|
||||
|
||||
isc_result_t ((*expunge)(omapi_object_t *)));
|
||||
|
||||
isc_result_t
|
||||
omapi_object_set(omapi_object_t *handle, omapi_string_t *name,
|
||||
omapi_data_t *value);
|
||||
|
||||
isc_result_t
|
||||
omapi_object_setdata(omapi_object_t *handle, const char *name,
|
||||
omapi_data_t *value);
|
||||
|
||||
isc_result_t
|
||||
omapi_object_setboolean(omapi_object_t *handle, const char *name,
|
||||
isc_boolean_t value);
|
||||
|
||||
isc_result_t
|
||||
omapi_object_setinteger(omapi_object_t *handle, const char *name,
|
||||
int value);
|
||||
|
||||
isc_result_t
|
||||
omapi_object_setobject(omapi_object_t *handle, const char *name,
|
||||
omapi_object_t *value);
|
||||
|
||||
isc_result_t
|
||||
omapi_object_setstring(omapi_object_t *handle, const char *name,
|
||||
const char *value);
|
||||
|
||||
isc_result_t
|
||||
omapi_object_getvalue(omapi_object_t *handle, const char *name,
|
||||
omapi_value_t **value);
|
||||
|
||||
isc_result_t
|
||||
omapi_object_passgetvalue(omapi_object_t *object, omapi_string_t *name,
|
||||
omapi_value_t **value);
|
||||
|
||||
isc_result_t
|
||||
omapi_object_passsetvalue(omapi_object_t *object, omapi_string_t *name,
|
||||
omapi_data_t *value);
|
||||
|
||||
isc_result_t
|
||||
omapi_object_passsignal(omapi_object_t *object, const char *name,
|
||||
va_list args);
|
||||
|
||||
isc_result_t
|
||||
omapi_object_passstuffvalues(omapi_object_t *connection,
|
||||
omapi_object_t *object);
|
||||
|
||||
/*
|
||||
* Public functions defined in data.c.
|
||||
*/
|
||||
isc_result_t
|
||||
omapi_data_create(omapi_data_t **data, omapi_datatype_t type, ...);
|
||||
|
||||
void
|
||||
omapi_data_reference(omapi_data_t **reference, omapi_data_t *data);
|
||||
|
||||
void
|
||||
omapi_data_dereference(omapi_data_t **reference);
|
||||
|
||||
int
|
||||
omapi_data_strcmp(omapi_data_t *string_type, const char *string);
|
||||
|
||||
int
|
||||
omapi_data_getint(omapi_data_t *data);
|
||||
|
||||
char *
|
||||
omapi_data_strdup(isc_mem_t *mctx, omapi_data_t *t);
|
||||
|
||||
/*
|
||||
* Public functions defined in string.c.
|
||||
*/
|
||||
isc_result_t
|
||||
omapi_string_create(omapi_string_t **string, unsigned int length);
|
||||
|
||||
void
|
||||
omapi_string_reference(omapi_string_t **reference, omapi_string_t *string);
|
||||
|
||||
void
|
||||
omapi_string_dereference(omapi_string_t **);
|
||||
|
||||
/*
|
||||
* XXXDCL consider better API
|
||||
*/
|
||||
void
|
||||
omapi_string_totext(omapi_string_t *string, isc_region_t *region);
|
||||
|
||||
int
|
||||
omapi_string_stringcmp(omapi_string_t *string1, omapi_string_t *string2);
|
||||
|
||||
int
|
||||
omapi_string_strcmp(omapi_string_t *data_string, const char *string);
|
||||
|
||||
/*
|
||||
* Public functions defined in value.c.
|
||||
*/
|
||||
isc_result_t
|
||||
omapi_value_create(omapi_value_t **value);
|
||||
|
||||
void
|
||||
omapi_value_reference(omapi_value_t **reference, omapi_value_t *value);
|
||||
|
||||
void
|
||||
omapi_value_dereference(omapi_value_t **reference);
|
||||
|
||||
isc_result_t
|
||||
omapi_value_storedata(omapi_value_t **valuep, omapi_string_t *name,
|
||||
omapi_data_t *value);
|
||||
|
||||
isc_result_t
|
||||
omapi_value_storemem(omapi_value_t **valuep, omapi_string_t *name,
|
||||
const unsigned char *value, unsigned int length);
|
||||
|
||||
isc_result_t
|
||||
omapi_value_storeint(omapi_value_t **valuep, omapi_string_t *name,
|
||||
int value);
|
||||
|
||||
isc_result_t
|
||||
omapi_value_storeobject(omapi_value_t **valuep, omapi_string_t *name,
|
||||
omapi_object_t *handle);
|
||||
|
||||
isc_result_t
|
||||
omapi_value_storestr(omapi_value_t **valuep, omapi_string_t *name,
|
||||
char *string);
|
||||
|
||||
/*
|
||||
* XXXDCL for completeness, it would be good to have more functions that
|
||||
* can fetch the value out of an omapi_data_t into a form that a C progammer
|
||||
* is more used to working with.
|
||||
*/
|
||||
int
|
||||
omapi_value_getint(omapi_value_t *value);
|
||||
|
||||
/*
|
||||
* WARNING: The region returned is (currently) only valid for as long
|
||||
* as the value pointer is valid, which means "until it is completely
|
||||
* dereferenced". If you want to ensure it hangs around, you should
|
||||
* use omapi_value_reference to add another reference to the value pointer,
|
||||
* and then remember to use omapi_value_dereference to free it.
|
||||
* XXXDCL yes, kind of lame. the interface to the omapi_value_get* functions
|
||||
* will probably change.
|
||||
*/
|
||||
void
|
||||
omapi_value_getregion(omapi_value_t *value, isc_region_t *region);
|
||||
|
||||
ISC_LANG_ENDDECLS
|
||||
|
||||
#endif /* OMAPI_OMAPI_H */
|
@ -1,449 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1996-2001 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: private.h,v 1.28 2001/02/15 20:10:04 bwelling Exp $ */
|
||||
|
||||
/*****
|
||||
***** Private master include file for the OMAPI library.
|
||||
*****/
|
||||
|
||||
#ifndef OMAPI_PRIVATE_H
|
||||
#define OMAPI_PRIVATE_H 1
|
||||
|
||||
#include <isc/condition.h>
|
||||
#include <isc/hmacmd5.h>
|
||||
#include <isc/lang.h>
|
||||
#include <isc/mutex.h>
|
||||
#include <isc/socket.h>
|
||||
|
||||
#include <omapi/omapi.h>
|
||||
|
||||
#define OMAPI_BUFFER_SIZE 4096
|
||||
|
||||
/*
|
||||
* Types shared among multiple library files.
|
||||
*/
|
||||
typedef struct omapi_generic omapi_generic_t;
|
||||
typedef struct omapi_message omapi_message_t;
|
||||
typedef struct omapi_connection omapi_connection_t;
|
||||
typedef struct omapi_protocol omapi_protocol_t;
|
||||
|
||||
typedef enum {
|
||||
omapi_connection_unconnected,
|
||||
omapi_connection_connecting,
|
||||
omapi_connection_connected,
|
||||
omapi_connection_disconnecting,
|
||||
omapi_connection_closed
|
||||
} omapi_connection_state_t;
|
||||
|
||||
typedef enum {
|
||||
omapi_protocol_intro_wait,
|
||||
omapi_protocol_header_wait,
|
||||
omapi_protocol_signature_wait,
|
||||
omapi_protocol_name_wait,
|
||||
omapi_protocol_name_length_wait,
|
||||
omapi_protocol_value_wait,
|
||||
omapi_protocol_value_length_wait
|
||||
} omapi_protocol_state_t;
|
||||
|
||||
/*
|
||||
* OMAPI data types.
|
||||
*/
|
||||
|
||||
struct omapi_data {
|
||||
#define OMAPI_DATA_HEADER_LEN (sizeof(int) + sizeof(omapi_datatype_t))
|
||||
int refcnt;
|
||||
omapi_datatype_t type;
|
||||
|
||||
union {
|
||||
/*
|
||||
* OMAPI_DATA_NOBUFFER_LEN purposefully does not
|
||||
* include the 'value' byte, which only serves as a
|
||||
* handle to memory allocated for (usually) more than
|
||||
* one byte that begins at the 'value' location.
|
||||
*/
|
||||
#define OMAPI_DATA_NOBUFFER_LEN (OMAPI_DATA_HEADER_LEN + sizeof(int))
|
||||
struct {
|
||||
unsigned int len;
|
||||
unsigned char value[1];
|
||||
} buffer;
|
||||
|
||||
#define OMAPI_DATA_OBJECT_LEN \
|
||||
(OMAPI_DATA_HEADER_LEN + sizeof(omapi_object_t *))
|
||||
omapi_object_t *object;
|
||||
|
||||
#define OMAPI_DATA_INT_LEN (OMAPI_DATA_HEADER_LEN + sizeof(int))
|
||||
int integer;
|
||||
} u;
|
||||
};
|
||||
|
||||
struct omapi_string {
|
||||
/*
|
||||
* OMAPI_STRING_EMPTY_SIZE purposefully does not
|
||||
* include the 'value' byte, which only serves as a
|
||||
* handle to memory allocated for (usually) more than
|
||||
* one byte that begins at the 'value' location.
|
||||
*/
|
||||
#define OMAPI_STRING_EMPTY_SIZE (2 * sizeof(int))
|
||||
int refcnt;
|
||||
unsigned int len;
|
||||
unsigned char value[1];
|
||||
};
|
||||
|
||||
struct omapi_value {
|
||||
int refcnt;
|
||||
omapi_string_t * name;
|
||||
omapi_data_t * value;
|
||||
};
|
||||
|
||||
struct omapi_generic {
|
||||
OMAPI_OBJECT_PREAMBLE;
|
||||
omapi_value_t ** values;
|
||||
unsigned int nvalues;
|
||||
unsigned int va_max;
|
||||
};
|
||||
|
||||
struct omapi_message {
|
||||
OMAPI_OBJECT_PREAMBLE;
|
||||
omapi_message_t * next;
|
||||
omapi_message_t * prev;
|
||||
omapi_object_t * object;
|
||||
omapi_object_t * notify_object;
|
||||
isc_uint32_t authlen;
|
||||
omapi_data_t * authenticator;
|
||||
isc_uint32_t authid;
|
||||
isc_uint32_t op;
|
||||
omapi_handle_t h;
|
||||
isc_uint32_t id;
|
||||
isc_uint32_t rid;
|
||||
};
|
||||
|
||||
struct omapi_connection {
|
||||
OMAPI_OBJECT_PREAMBLE;
|
||||
/*
|
||||
* The wait lock is necessary to ensure that connection_wait is
|
||||
* blocking for the signal before any event is received that might
|
||||
* potentially free the connection. This ensures that end_connection
|
||||
* will unblock connection_wait so that connection_wait can free
|
||||
* the connection.
|
||||
*
|
||||
* Consider, for example, the problem that send_intro has without
|
||||
* this lock. It first needs to call connection_require to start
|
||||
* a recv task to get the server's intro. Then it needs to send
|
||||
* the intro itself. One sample problem that can then arise from
|
||||
* this is that the recv task completes before the wait is established
|
||||
* and it triggers an error, such as an premature EOF or an unsupported
|
||||
* version number in the header. The client would have no way of
|
||||
* knowing an error occurred.
|
||||
*
|
||||
* Fortunately, there is no such problem in the server. Since all
|
||||
* uses of the connection object happen from the socket thread,
|
||||
* no function will continue to use a connection object after there
|
||||
* has been an error on it, no other event can be posted until the
|
||||
* current event handler is done, and all events subsequent to
|
||||
* abandoning the connection will be ISC_R_CANCELED, so the event
|
||||
* handlers will not try to use the connection object.
|
||||
*
|
||||
* XXXDCL the above comments are somewhat out of date.
|
||||
*/
|
||||
isc_mutex_t wait_lock;
|
||||
isc_socket_t *socket;
|
||||
isc_task_t *task;
|
||||
/*
|
||||
* The error that caused the connection to be freed.
|
||||
*/
|
||||
isc_result_t result;
|
||||
/*
|
||||
* Number of socket events outstanding. This should always be
|
||||
* either 0 or 1 under the current model; having any more than
|
||||
* one event pending at any given time complicates the thread
|
||||
* locking issues.
|
||||
*/
|
||||
unsigned int events_pending;
|
||||
/*
|
||||
* Blocks connection_wait until the outstanding event completes.
|
||||
*/
|
||||
isc_condition_t waiter;
|
||||
/*
|
||||
* True if connection_wait is blocking on the water condition variable.
|
||||
*/
|
||||
isc_boolean_t waiting;
|
||||
omapi_connection_state_t state;
|
||||
/*
|
||||
* These are set when a connection is made, but not currently used.
|
||||
*/
|
||||
isc_sockaddr_t remote_addr;
|
||||
isc_sockaddr_t local_addr;
|
||||
/*
|
||||
* Bytes of input needed before wakeup.
|
||||
*/
|
||||
isc_uint32_t bytes_needed;
|
||||
/*
|
||||
* Bytes of input already buffered.
|
||||
* XXXDCL use isc_bufferlist_available() instead?
|
||||
*/
|
||||
isc_uint32_t in_bytes;
|
||||
isc_bufferlist_t input_buffers;
|
||||
/*
|
||||
* Bytes of output in output buffers.
|
||||
*/
|
||||
isc_uint32_t out_bytes;
|
||||
isc_bufferlist_t output_buffers;
|
||||
/*
|
||||
* True if the connection was created by omapi_protocol_connect.
|
||||
*/
|
||||
isc_boolean_t is_client;
|
||||
/*
|
||||
* The listener that accepted the connection.
|
||||
* XXXDCL (Means is_client is false, making is_client is somewhat
|
||||
* redundant.)
|
||||
*/
|
||||
omapi_object_t * listener;
|
||||
/*
|
||||
* The server links known connections in a list at the connections
|
||||
* member of the omapi_listener_t struct.
|
||||
*/
|
||||
ISC_LINK(omapi_connection_t) link;
|
||||
};
|
||||
|
||||
struct omapi_protocol {
|
||||
OMAPI_OBJECT_PREAMBLE;
|
||||
isc_uint32_t header_size;
|
||||
isc_uint32_t protocol_version;
|
||||
isc_uint32_t next_xid;
|
||||
omapi_object_t * authinfo; /* Default authinfo. */
|
||||
omapi_protocol_state_t state; /* Input state. */
|
||||
isc_boolean_t reading_message_values;
|
||||
omapi_message_t * message; /* Incoming message. */
|
||||
omapi_string_t * name; /* Incoming name. */
|
||||
omapi_data_t * value; /* Incoming value. */
|
||||
/*
|
||||
* Authentication information.
|
||||
*/
|
||||
char * authname;
|
||||
unsigned int algorithm;
|
||||
isc_boolean_t auth_update;
|
||||
isc_region_t *key;
|
||||
isc_hmacmd5_t hmacctx;
|
||||
isc_region_t signature_in;
|
||||
isc_buffer_t *signature_out;
|
||||
isc_result_t verify_result;
|
||||
/*
|
||||
* A callback to find out whether a requested key is valid on
|
||||
* the connection, and the arg the caller wants to help it decide.
|
||||
* Only gets set on the server side.
|
||||
*/
|
||||
isc_boolean_t ((*verify_key)(const char *name,
|
||||
unsigned int algorithm,
|
||||
void *key_arg));
|
||||
void * verify_key_arg;
|
||||
};
|
||||
|
||||
/*****
|
||||
***** Private Global Library Variables.
|
||||
*****/
|
||||
extern omapi_objecttype_t *omapi_type_connection;
|
||||
extern omapi_objecttype_t *omapi_type_listener;
|
||||
extern omapi_objecttype_t *omapi_type_generic;
|
||||
extern omapi_objecttype_t *omapi_type_protocol;
|
||||
extern omapi_objecttype_t *omapi_type_message;
|
||||
extern omapi_objecttype_t *omapi_object_types;
|
||||
|
||||
/*
|
||||
* Everything needs a memory context.
|
||||
*/
|
||||
extern isc_mem_t *omapi_mctx;
|
||||
|
||||
/*
|
||||
* Task to keep the omapi_taskmgr alive until omapi_lib_destroy is called.
|
||||
*/
|
||||
extern isc_task_t *omapi_task;
|
||||
|
||||
/*
|
||||
* XXXDCL comment, localize?
|
||||
*/
|
||||
extern isc_taskmgr_t *omapi_taskmgr;
|
||||
|
||||
/*
|
||||
* XXXDCL comment, localize?
|
||||
*/
|
||||
extern isc_socketmgr_t *omapi_socketmgr;
|
||||
|
||||
/*****
|
||||
***** Convenience macros.
|
||||
*****/
|
||||
#define OBJECT_REF(objectp, object) \
|
||||
omapi_object_reference((omapi_object_t **)objectp, \
|
||||
(omapi_object_t *)object)
|
||||
|
||||
#define OBJECT_DEREF(objectp) \
|
||||
omapi_object_dereference((omapi_object_t **)objectp)
|
||||
|
||||
#define PASS_CHECK(object, function) \
|
||||
(object->inner != NULL && object->inner->type->function != NULL)
|
||||
|
||||
ISC_LANG_BEGINDECLS
|
||||
|
||||
/*
|
||||
* Private library functions defined in auth.c.
|
||||
*/
|
||||
#define auth_destroy omapi__auth_destroy
|
||||
void
|
||||
auth_destroy(void);
|
||||
|
||||
#define auth_makekey omapi__auth_makekey
|
||||
isc_result_t
|
||||
auth_makekey(const char *name, unsigned int algorithm, isc_region_t **keyp);
|
||||
|
||||
/*
|
||||
* Private library functions defined in connection.c.
|
||||
*/
|
||||
#define connection_init omapi__connection_init
|
||||
isc_result_t
|
||||
connection_init(void);
|
||||
|
||||
#define connect_toserver omapi__connect_toserver
|
||||
isc_result_t
|
||||
connect_toserver(omapi_object_t *connection, const char *server,
|
||||
in_port_t port);
|
||||
|
||||
#define connection_send omapi__connection_send
|
||||
isc_result_t
|
||||
connection_send(omapi_connection_t *connection);
|
||||
|
||||
#define connection_require omapi__connection_require
|
||||
isc_result_t
|
||||
connection_require(omapi_connection_t *connection, unsigned int bytes);
|
||||
|
||||
#define connection_copyout omapi__connection_copyout
|
||||
void
|
||||
connection_copyout(unsigned char *data, omapi_connection_t *connection,
|
||||
unsigned int length);
|
||||
|
||||
#define connection_getuint32 omapi__connection_getuint32
|
||||
void
|
||||
connection_getuint32(omapi_connection_t *c, isc_uint32_t *value);
|
||||
|
||||
#define connection_getuint16 omapi__connection_getuint16
|
||||
void
|
||||
connection_getuint16(omapi_connection_t *c, isc_uint16_t *value);
|
||||
|
||||
/*
|
||||
* Private library functions defined in generic.c.
|
||||
*/
|
||||
#define generic_init omapi__generic_init
|
||||
isc_result_t
|
||||
generic_init(void);
|
||||
|
||||
/*
|
||||
* Private functions defined in handle.c.
|
||||
*/
|
||||
#define object_gethandle omapi__object_gethandle
|
||||
isc_result_t
|
||||
object_gethandle(omapi_handle_t *handle, omapi_object_t *object);
|
||||
|
||||
#define handle_lookup omapi__handle_lookup
|
||||
isc_result_t
|
||||
handle_lookup(omapi_object_t **object, omapi_handle_t handle);
|
||||
|
||||
#define handle_destroy omapi__handle_destroy
|
||||
void
|
||||
handle_destroy(void);
|
||||
|
||||
/*
|
||||
* Private library functions defined in listener.c.
|
||||
*/
|
||||
#define listener_init omapi__listener_init
|
||||
isc_result_t
|
||||
listener_init(void);
|
||||
|
||||
/*
|
||||
* Private library functions defined in message.c.
|
||||
*/
|
||||
#define message_init omapi__message_init
|
||||
isc_result_t
|
||||
message_init(void);
|
||||
|
||||
#define message_process omapi__message_process
|
||||
isc_result_t
|
||||
message_process(omapi_object_t *message, omapi_object_t *protocol);
|
||||
|
||||
/*
|
||||
* Private library functions defined in object.c.
|
||||
*/
|
||||
#define object_signal omapi__object_signal
|
||||
isc_result_t
|
||||
object_signal(omapi_object_t *handle, const char *name, ...);
|
||||
|
||||
#define object_vsignal omapi__object_vsignal
|
||||
isc_result_t
|
||||
object_vsignal(omapi_object_t *handle, const char *name, va_list ap);
|
||||
|
||||
#define object_stuffvalues omapi__object_stuffvalues
|
||||
isc_result_t
|
||||
object_stuffvalues(omapi_object_t *handle, omapi_object_t *object);
|
||||
|
||||
#define object_update omapi__object_update
|
||||
isc_result_t
|
||||
object_update(omapi_object_t *object, omapi_object_t *source,
|
||||
omapi_handle_t handle);
|
||||
|
||||
#define object_findtype omapi__object_findtype
|
||||
omapi_objecttype_t *
|
||||
object_findtype(omapi_value_t *tv);
|
||||
|
||||
#define object_methodlookup omapi__object_methodlookup
|
||||
isc_result_t
|
||||
object_methodlookup(omapi_objecttype_t *type, omapi_object_t **object,
|
||||
omapi_object_t *key);
|
||||
|
||||
#define object_methodcreate omapi__object_methodcreate
|
||||
isc_result_t
|
||||
object_methodcreate(omapi_objecttype_t *type, omapi_object_t **object);
|
||||
|
||||
#define object_methodexpunge omapi__object_methodexpunge
|
||||
isc_result_t
|
||||
object_methodexpunge(omapi_objecttype_t *type, omapi_object_t *object);
|
||||
|
||||
#define object_destroytypes omapi__object_destroytypes
|
||||
void
|
||||
object_destroytypes(void);
|
||||
|
||||
/*
|
||||
* Private library functions defined in protocol.c.
|
||||
*/
|
||||
#define protocol_init omapi__protocol_init
|
||||
isc_result_t
|
||||
protocol_init(void);
|
||||
|
||||
#define send_intro omapi__send_intro
|
||||
isc_result_t
|
||||
send_intro(omapi_object_t *object, unsigned int version);
|
||||
|
||||
#define send_status omapi__send_status
|
||||
isc_result_t
|
||||
send_status(omapi_object_t *protcol, isc_result_t waitstatus,
|
||||
unsigned int response_id, const char *message);
|
||||
|
||||
#define send_update omapi__send_update
|
||||
isc_result_t
|
||||
send_update(omapi_object_t *protocol, unsigned int response_id,
|
||||
omapi_object_t *object);
|
||||
|
||||
ISC_LANG_ENDDECLS
|
||||
|
||||
#endif /* OMAPI_PRIVATE_H */
|
@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1999-2001 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: result.h,v 1.8 2001/01/09 22:00:30 bwelling Exp $ */
|
||||
|
||||
#ifndef OMAPI_RESULT_H
|
||||
#define OMAPI_RESULT_H 1
|
||||
|
||||
#include <isc/lang.h>
|
||||
#include <isc/result.h> /* Contractual promise. */
|
||||
#include <isc/resultclass.h>
|
||||
|
||||
ISC_LANG_BEGINDECLS
|
||||
|
||||
#define OMAPI_R_NOTYET (ISC_RESULTCLASS_OMAPI + 0)
|
||||
#define OMAPI_R_NOTCONNECTED (ISC_RESULTCLASS_OMAPI + 1)
|
||||
#define OMAPI_R_NOKEYS (ISC_RESULTCLASS_OMAPI + 2)
|
||||
#define OMAPI_R_INVALIDARG (ISC_RESULTCLASS_OMAPI + 3)
|
||||
#define OMAPI_R_VERSIONMISMATCH (ISC_RESULTCLASS_OMAPI + 4)
|
||||
#define OMAPI_R_PROTOCOLERROR (ISC_RESULTCLASS_OMAPI + 5)
|
||||
|
||||
#define OMAPI_R_NRESULTS 6 /* Number of results */
|
||||
|
||||
const char *
|
||||
omapi_result_totext(isc_result_t);
|
||||
|
||||
void
|
||||
omapi_result_register(void);
|
||||
|
||||
ISC_LANG_ENDDECLS
|
||||
|
||||
#endif /* OMAPI_RESULT_H */
|
@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1996-2001 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: types.h,v 1.8 2001/01/09 22:00:31 bwelling Exp $ */
|
||||
|
||||
#ifndef OMAPI_TYPES_H
|
||||
#define OMAPI_TYPES_H 1
|
||||
|
||||
/*****
|
||||
***** Type definitions.
|
||||
*****/
|
||||
|
||||
/*
|
||||
* These structures are all opaque; they are fully defined in private.h
|
||||
* for use only by the internal library. If there is a need to get
|
||||
* at their internal data for some purpose, new APIs can be added for that.
|
||||
*/
|
||||
typedef unsigned int omapi_handle_t;
|
||||
typedef struct omapi_object omapi_object_t;
|
||||
typedef struct omapi_objecttype omapi_objecttype_t;
|
||||
typedef struct omapi_data omapi_data_t;
|
||||
typedef struct omapi_string omapi_string_t;
|
||||
typedef struct omapi_value omapi_value_t;
|
||||
|
||||
typedef enum {
|
||||
omapi_datatype_int,
|
||||
omapi_datatype_string,
|
||||
omapi_datatype_data,
|
||||
omapi_datatype_object
|
||||
} omapi_datatype_t;
|
||||
|
||||
#endif /* OMAPI_TYPES_H */
|
140
lib/omapi/lib.c
140
lib/omapi/lib.c
@ -1,140 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1999-2001 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: lib.c,v 1.15 2001/02/16 04:14:16 tale Exp $ */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <isc/msgcat.h>
|
||||
#include <isc/once.h>
|
||||
#include <isc/task.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <omapi/lib.h>
|
||||
#include <omapi/private.h>
|
||||
|
||||
/***
|
||||
*** Library Globals.
|
||||
***/
|
||||
|
||||
isc_msgcat_t *omapi_msgcat = NULL;
|
||||
|
||||
omapi_objecttype_t *omapi_type_connection;
|
||||
omapi_objecttype_t *omapi_type_listener;
|
||||
omapi_objecttype_t *omapi_type_generic;
|
||||
omapi_objecttype_t *omapi_type_protocol;
|
||||
omapi_objecttype_t *omapi_type_message;
|
||||
omapi_objecttype_t *omapi_object_types;
|
||||
|
||||
isc_mem_t *omapi_mctx;
|
||||
isc_task_t *omapi_task;
|
||||
isc_taskmgr_t *omapi_taskmgr;
|
||||
isc_socketmgr_t *omapi_socketmgr;
|
||||
|
||||
/***
|
||||
*** Private to lib.c.
|
||||
***/
|
||||
|
||||
static isc_once_t msgcat_once = ISC_ONCE_INIT;
|
||||
|
||||
/***
|
||||
*** Functions.
|
||||
***/
|
||||
|
||||
static void
|
||||
open_msgcat(void) {
|
||||
isc_msgcat_open("libomapi.cat", &omapi_msgcat);
|
||||
}
|
||||
|
||||
void
|
||||
omapi_lib_initmsgcat(void) {
|
||||
|
||||
/*
|
||||
* Initialize the OMAPI library's message catalog, omapi_msgcat, if it
|
||||
* has not already been initialized.
|
||||
*/
|
||||
RUNTIME_CHECK(isc_once_do(&msgcat_once, open_msgcat) == ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
omapi_lib_init(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
|
||||
isc_socketmgr_t *socketmgr)
|
||||
{
|
||||
isc_result_t result;
|
||||
|
||||
/*
|
||||
* Can only be called once without an intervening omapi_lib_destroy.
|
||||
*/
|
||||
REQUIRE(omapi_mctx == NULL &&
|
||||
omapi_socketmgr == NULL &&
|
||||
omapi_taskmgr == NULL &&
|
||||
omapi_task == NULL &&
|
||||
omapi_object_types == NULL);
|
||||
|
||||
REQUIRE(mctx != NULL && taskmgr != NULL && socketmgr != NULL);
|
||||
|
||||
omapi_mctx = mctx;
|
||||
omapi_taskmgr = taskmgr;
|
||||
omapi_socketmgr = socketmgr;
|
||||
|
||||
result = isc_task_create(omapi_taskmgr, 0, &omapi_task);
|
||||
if (result == ISC_R_SUCCESS)
|
||||
isc_task_setname(omapi_task, "omapi", NULL);
|
||||
|
||||
/*
|
||||
* Initialize the standard object types.
|
||||
*/
|
||||
if (result == ISC_R_SUCCESS)
|
||||
result = generic_init();
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
result = listener_init();
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
result = connection_init();
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
result = protocol_init();
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
result = message_init();
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* This does not free connections and other in-use objects, only the
|
||||
* things created by omapi_lib_init(). It is the callers responsibility to
|
||||
* free the other things (as via omapi_connection_disconnect or
|
||||
* omapi_object_dereference).
|
||||
*/
|
||||
void
|
||||
omapi_lib_destroy(void) {
|
||||
object_destroytypes();
|
||||
|
||||
handle_destroy();
|
||||
|
||||
auth_destroy();
|
||||
|
||||
isc_task_destroy(&omapi_task);
|
||||
|
||||
omapi_mctx = NULL;
|
||||
omapi_socketmgr = NULL;
|
||||
omapi_taskmgr = NULL;
|
||||
}
|
@ -1,506 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1996-2001 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: listener.c,v 1.32 2001/01/09 22:00:01 bwelling Exp $ */
|
||||
|
||||
/*
|
||||
* Subroutines that support the generic listener object.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdlib.h> /* NULL and abort() */
|
||||
|
||||
#include <isc/buffer.h>
|
||||
#include <isc/bufferlist.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/string.h>
|
||||
#include <isc/task.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <omapi/private.h>
|
||||
|
||||
typedef struct omapi_listener_object {
|
||||
OMAPI_OBJECT_PREAMBLE;
|
||||
isc_mutex_t mutex;
|
||||
isc_task_t *task;
|
||||
isc_socket_t *socket; /* Listening socket. */
|
||||
isc_boolean_t (*verify_connection)(isc_sockaddr_t *sockaddr,
|
||||
void *connect_arg);
|
||||
isc_boolean_t (*verify_key)(const char *name, unsigned int algorithm,
|
||||
void *key_arg);
|
||||
void *callback_arg;
|
||||
/*
|
||||
* Locked by mutex.
|
||||
*/
|
||||
isc_boolean_t listening;
|
||||
ISC_LIST(omapi_connection_t) connections;
|
||||
} omapi_listener_t;
|
||||
|
||||
static void
|
||||
free_listener(omapi_listener_t *listener) {
|
||||
/*
|
||||
* Break the link between the listener object and its parent
|
||||
* (usually a generic object); this is done so the server's
|
||||
* reference to its managing object does not prevent the
|
||||
* listener object from being destroyed.
|
||||
*/
|
||||
OBJECT_DEREF(&listener->inner->outer);
|
||||
OBJECT_DEREF(&listener->inner);
|
||||
|
||||
/*
|
||||
* The listener object can now be freed.
|
||||
*/
|
||||
OBJECT_DEREF(&listener);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reader callback for a listener object. Accept an incoming connection.
|
||||
*/
|
||||
static void
|
||||
listener_accept(isc_task_t *task, isc_event_t *event) {
|
||||
isc_result_t result;
|
||||
isc_buffer_t *ibuffer = NULL;
|
||||
isc_buffer_t *obuffer = NULL;
|
||||
isc_task_t *connection_task = NULL;
|
||||
isc_socket_t *sock;
|
||||
isc_sockaddr_t sockaddr;
|
||||
omapi_connection_t *connection = NULL;
|
||||
omapi_protocol_t *protocol = NULL;
|
||||
omapi_listener_t *listener;
|
||||
|
||||
/*
|
||||
* XXXDCL audit error handling
|
||||
*/
|
||||
|
||||
result = ((isc_socket_newconnev_t *)event)->result;
|
||||
sock = ((isc_socket_newconnev_t *)event)->newsocket;
|
||||
listener = (omapi_listener_t *)event->ev_arg;
|
||||
|
||||
/*
|
||||
* No more need for the event, once all the desired data has been
|
||||
* used from it.
|
||||
*/
|
||||
isc_event_free(&event);
|
||||
|
||||
if (result == ISC_R_CANCELED) {
|
||||
/*
|
||||
* omapi_listener_shutdown was called.
|
||||
*/
|
||||
LOCK(&listener->mutex);
|
||||
|
||||
listener->listening = ISC_FALSE;
|
||||
|
||||
if (ISC_LIST_HEAD(listener->connections) == NULL) {
|
||||
UNLOCK(&listener->mutex);
|
||||
free_listener(listener);
|
||||
|
||||
} else {
|
||||
/*
|
||||
* All connections this listener was responsible for
|
||||
* must be removed.
|
||||
*
|
||||
* XXXDCL
|
||||
* Since it is possible that this shutdown was
|
||||
* triggered by one of the clients, it would be nice
|
||||
* to give it a little time to exit, as well as allow
|
||||
* any other connections to finish up cleanly.
|
||||
* Unfortunately, since this could be called in the
|
||||
* task/event thread of a program (as it is in named),
|
||||
* no other events can be delivered while this routine
|
||||
* blocks, so a loop to use isc_condition_waituntil
|
||||
* until all of the connections are gone is pointless.
|
||||
*/
|
||||
for (connection = ISC_LIST_HEAD(listener->connections);
|
||||
connection != NULL;
|
||||
connection = ISC_LIST_NEXT(connection, link))
|
||||
omapi_connection_disconnect((omapi_object_t *)
|
||||
connection,
|
||||
OMAPI_FORCE_DISCONNECT);
|
||||
UNLOCK(&listener->mutex);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up another accept task for the socket.
|
||||
*/
|
||||
isc_socket_accept(listener->socket, task, listener_accept, listener);
|
||||
|
||||
/*
|
||||
* Check for the validity of new connection event.
|
||||
* If the result is not ISC_R_SUCCESS, what can really
|
||||
* be done about it other than just flunking out of here?
|
||||
*/
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Is the connection from a valid host?
|
||||
*/
|
||||
result = isc_socket_getpeername(sock, &sockaddr);
|
||||
if (result != ISC_R_SUCCESS ||
|
||||
!listener->verify_connection(&sockaddr, listener->callback_arg)) {
|
||||
/*
|
||||
* Permission denied. Close the connection.
|
||||
* XXXDCL isc_log_write an error.
|
||||
*/
|
||||
isc_socket_detach(&sock);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The new connection is good to go. Allocate the buffers for it and
|
||||
* prepare its own task.
|
||||
*/
|
||||
if (isc_task_create(omapi_taskmgr, 0, &connection_task) !=
|
||||
ISC_R_SUCCESS)
|
||||
goto free_task;
|
||||
|
||||
ibuffer = NULL;
|
||||
result = isc_buffer_allocate(omapi_mctx, &ibuffer, OMAPI_BUFFER_SIZE);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
goto free_ibuffer;
|
||||
|
||||
obuffer = NULL;
|
||||
result = isc_buffer_allocate(omapi_mctx, &obuffer, OMAPI_BUFFER_SIZE);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
goto free_obuffer;
|
||||
|
||||
/*
|
||||
* Create a new connection object.
|
||||
*/
|
||||
result = omapi_object_create((omapi_object_t **)&connection,
|
||||
omapi_type_connection, sizeof(*connection));
|
||||
if (result != ISC_R_SUCCESS)
|
||||
goto free_obuffer;
|
||||
|
||||
connection->task = connection_task;
|
||||
connection->state = omapi_connection_connected;
|
||||
connection->socket = sock;
|
||||
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);
|
||||
ISC_LINK_INIT(connection, link);
|
||||
|
||||
/*
|
||||
* Create a new protocol object to oversee the handling of this
|
||||
* connection.
|
||||
*/
|
||||
protocol = NULL;
|
||||
result = omapi_object_create((omapi_object_t **)&protocol,
|
||||
omapi_type_protocol,
|
||||
sizeof(omapi_protocol_t));
|
||||
if (result != ISC_R_SUCCESS)
|
||||
goto free_connection_object;
|
||||
|
||||
|
||||
/*
|
||||
* Hand off the key verification information to the protocol object.
|
||||
*/
|
||||
protocol->verify_key = listener->verify_key;
|
||||
protocol->verify_key_arg = listener->callback_arg;
|
||||
|
||||
/*
|
||||
* Tie the protocol object bidirectionally to the connection
|
||||
* object, with the connection as the outer object.
|
||||
*/
|
||||
OBJECT_REF(&protocol->outer, connection);
|
||||
OBJECT_REF(&connection->inner, protocol);
|
||||
|
||||
/*
|
||||
* Lose the external reference to the protocol object so both the
|
||||
* connection object and protocol object will be freed when the
|
||||
* connection ends.
|
||||
*/
|
||||
OBJECT_DEREF(&protocol);
|
||||
|
||||
/*
|
||||
* Add the connection to the list of connections known by the
|
||||
* listener. This is an added reference to the connection
|
||||
* object, but since there's no easy way to use omapi_object_reference
|
||||
* with the ISC_LIST macros, that reference is just not counted.
|
||||
*/
|
||||
LOCK(&listener->mutex);
|
||||
ISC_LIST_APPEND(listener->connections, connection, link);
|
||||
UNLOCK(&listener->mutex);
|
||||
|
||||
/*
|
||||
* Remember the listener that accepted the connection, so it
|
||||
* can be told when the connection goes away.
|
||||
*/
|
||||
OBJECT_REF(&connection->listener, listener);
|
||||
|
||||
/*
|
||||
* Send the introductory message. The return value does not
|
||||
* matter; if send_intro failed, it already destroyed the connection.
|
||||
*/
|
||||
(void)send_intro(connection->inner, OMAPI_PROTOCOL_VERSION);
|
||||
|
||||
return;
|
||||
|
||||
free_connection_object:
|
||||
/*
|
||||
* Destroy the connection. This will free everything created
|
||||
* in this function but the event, which was already freed.
|
||||
*/
|
||||
OBJECT_DEREF(&connection);
|
||||
return;
|
||||
|
||||
/*
|
||||
* Free resources that were being created for the connection object.
|
||||
*/
|
||||
free_obuffer:
|
||||
isc_buffer_free(&obuffer);
|
||||
free_ibuffer:
|
||||
isc_buffer_free(&ibuffer);
|
||||
free_task:
|
||||
isc_task_destroy(&connection_task);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
omapi_listener_listen(omapi_object_t *manager, isc_sockaddr_t *addr,
|
||||
isc_boolean_t ((*verify_connection)
|
||||
(isc_sockaddr_t *incoming,
|
||||
void *connect_arg)),
|
||||
isc_boolean_t ((*verify_key)
|
||||
(const char *name,
|
||||
unsigned int algorithm,
|
||||
void *key_arg)),
|
||||
isc_taskaction_t destroy_action, void *arg)
|
||||
{
|
||||
isc_result_t result;
|
||||
isc_task_t *task;
|
||||
omapi_listener_t *listener;
|
||||
|
||||
REQUIRE(manager != NULL);
|
||||
REQUIRE(addr != NULL && isc_sockaddr_getport(addr) != 0);
|
||||
|
||||
task = NULL;
|
||||
result = isc_task_create(omapi_taskmgr, 0, &task);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (result);
|
||||
|
||||
/*
|
||||
* Create the listener object.
|
||||
*/
|
||||
listener = NULL;
|
||||
result = omapi_object_create((omapi_object_t **)&listener,
|
||||
omapi_type_listener, sizeof(*listener));
|
||||
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
isc_task_destroy(&task);
|
||||
return (result);
|
||||
}
|
||||
|
||||
listener->task = task;
|
||||
|
||||
RUNTIME_CHECK(isc_mutex_init(&listener->mutex) == ISC_R_SUCCESS);
|
||||
ISC_LIST_INIT(listener->connections);
|
||||
|
||||
/*
|
||||
* Create a socket on which to listen.
|
||||
*/
|
||||
listener->socket = NULL;
|
||||
result = isc_socket_create(omapi_socketmgr, PF_INET,
|
||||
isc_sockettype_tcp, &listener->socket);
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
result = isc_socket_bind(listener->socket, addr);
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
/*
|
||||
* Now tell the kernel to listen for connections.
|
||||
*/
|
||||
result = isc_socket_listen(listener->socket, 0);
|
||||
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
/*
|
||||
* Queue up the first accept event. The listener object
|
||||
* will be passed to listener_accept() when it is called.
|
||||
*/
|
||||
listener->listening = ISC_TRUE;
|
||||
result = isc_socket_accept(listener->socket, task,
|
||||
listener_accept, listener);
|
||||
}
|
||||
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
/*
|
||||
* Tie the listener object to the calling object.
|
||||
*/
|
||||
OBJECT_REF(&manager->outer, listener);
|
||||
OBJECT_REF(&listener->inner, manager);
|
||||
|
||||
/*
|
||||
* The destroy action is not set until here because it should
|
||||
* only be called if the listener was successfully set up.
|
||||
*/
|
||||
listener->destroy_action = destroy_action;
|
||||
listener->destroy_arg = arg;
|
||||
listener->verify_connection = verify_connection;
|
||||
listener->verify_key = verify_key;
|
||||
listener->callback_arg = arg;
|
||||
|
||||
} else {
|
||||
/*
|
||||
* Failed to set up the listener.
|
||||
*/
|
||||
listener->listening = ISC_FALSE;
|
||||
OBJECT_DEREF(&listener);
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
void
|
||||
omapi_listener_shutdown(omapi_object_t *listener) {
|
||||
omapi_listener_t *l;
|
||||
|
||||
REQUIRE((listener != NULL && listener->type == omapi_type_listener) ||
|
||||
(listener->outer != NULL &&
|
||||
listener->outer->type == omapi_type_listener));
|
||||
|
||||
if (listener->type == omapi_type_listener)
|
||||
l = (omapi_listener_t *)listener;
|
||||
else
|
||||
l = (omapi_listener_t *)listener->outer;
|
||||
|
||||
/*
|
||||
* It is improper to call this function without having had a successful
|
||||
* run of omapi_listener_listen.
|
||||
*/
|
||||
REQUIRE(l->socket != NULL && l->task != NULL);
|
||||
|
||||
/*
|
||||
* Stop accepting connections.
|
||||
*/
|
||||
isc_socket_cancel(l->socket, NULL, ISC_SOCKCANCEL_ACCEPT);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
listener_setvalue(omapi_object_t *listener, omapi_string_t *name,
|
||||
omapi_data_t *value)
|
||||
{
|
||||
/*
|
||||
* Nothing meaningful can be set in a listener object; just
|
||||
* continue the call through the object chain.
|
||||
*/
|
||||
REQUIRE(listener != NULL && listener->type == omapi_type_listener);
|
||||
|
||||
return (omapi_object_passsetvalue(listener, name, value));
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
listener_getvalue(omapi_object_t *listener, omapi_string_t *name,
|
||||
omapi_value_t **value)
|
||||
{
|
||||
/*
|
||||
* Nothing meaningful can be fetched from a listener object; just
|
||||
* continue the call through the object chain.
|
||||
*/
|
||||
REQUIRE(listener != NULL && listener->type == omapi_type_listener);
|
||||
|
||||
return (omapi_object_passgetvalue(listener, name, value));
|
||||
}
|
||||
|
||||
static void
|
||||
listener_destroy(omapi_object_t *listener) {
|
||||
omapi_listener_t *l;
|
||||
|
||||
REQUIRE(listener != NULL && listener->type == omapi_type_listener);
|
||||
|
||||
l = (omapi_listener_t *)listener;
|
||||
|
||||
LOCK(&l->mutex);
|
||||
INSIST(ISC_LIST_EMPTY(l->connections));
|
||||
UNLOCK(&l->mutex);
|
||||
|
||||
DESTROYLOCK(&l->mutex);
|
||||
|
||||
if (l->task != NULL)
|
||||
isc_task_destroy(&l->task);
|
||||
|
||||
if (l->socket != NULL)
|
||||
isc_socket_detach(&l->socket);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
listener_signalhandler(omapi_object_t *listener, const char *name, va_list ap)
|
||||
{
|
||||
omapi_connection_t *c;
|
||||
omapi_listener_t *l;
|
||||
isc_result_t result;
|
||||
|
||||
REQUIRE(listener != NULL && listener->type == omapi_type_listener);
|
||||
|
||||
l = (omapi_listener_t *)listener;
|
||||
|
||||
/*
|
||||
* free_connection() signals the listener when one of the connections
|
||||
* it accepted has gone away.
|
||||
*/
|
||||
if (strcmp(name, "disconnect") == 0) {
|
||||
c = va_arg(ap, omapi_connection_t *);
|
||||
|
||||
LOCK(&l->mutex);
|
||||
ISC_LIST_UNLINK(l->connections, c, link);
|
||||
|
||||
if (! l->listening && ISC_LIST_HEAD(l->connections) == NULL) {
|
||||
/*
|
||||
* The listener has been shutdown and the last
|
||||
* connection was received.
|
||||
*/
|
||||
UNLOCK(&l->mutex);
|
||||
free_listener(l);
|
||||
|
||||
} else
|
||||
UNLOCK(&l->mutex);
|
||||
|
||||
result = ISC_R_SUCCESS;
|
||||
} else
|
||||
result = omapi_object_passsignal(listener, name, ap);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write all the published values associated with the object through the
|
||||
* specified connection.
|
||||
*/
|
||||
static isc_result_t
|
||||
listener_stuffvalues(omapi_object_t *connection, omapi_object_t *listener)
|
||||
{
|
||||
REQUIRE(listener != NULL && listener->type == omapi_type_listener);
|
||||
|
||||
return (omapi_object_passstuffvalues(connection, listener));
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
listener_init(void) {
|
||||
return (omapi_object_register(&omapi_type_listener, "listener",
|
||||
listener_setvalue,
|
||||
listener_getvalue,
|
||||
listener_destroy,
|
||||
listener_signalhandler,
|
||||
listener_stuffvalues,
|
||||
NULL, NULL, NULL));
|
||||
}
|
@ -1,946 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1996-2001 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.30 2001/02/15 19:44:43 bwelling Exp $ */
|
||||
|
||||
/*
|
||||
* Subroutines for dealing with message objects.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <isc/buffer.h>
|
||||
#include <isc/string.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <omapi/private.h>
|
||||
#include <omapi/result.h>
|
||||
|
||||
omapi_message_t *registered_messages;
|
||||
|
||||
isc_result_t
|
||||
omapi_message_create(omapi_object_t **o) {
|
||||
omapi_message_t *message = NULL;
|
||||
omapi_object_t *g;
|
||||
isc_result_t result;
|
||||
|
||||
result = omapi_object_create((omapi_object_t **)&message,
|
||||
omapi_type_message, sizeof(*message));
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (result);
|
||||
|
||||
g = NULL;
|
||||
result = omapi_object_create(&g, NULL, 0);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
OBJECT_DEREF(&message);
|
||||
return (result);
|
||||
}
|
||||
|
||||
OBJECT_REF(&message->inner, g);
|
||||
OBJECT_REF(&g->outer, message);
|
||||
OBJECT_REF(o, message);
|
||||
|
||||
OBJECT_DEREF(&message);
|
||||
OBJECT_DEREF(&g);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* XXXDCL Make register/unregister implicitly part of omapi_message_send?
|
||||
*/
|
||||
void
|
||||
omapi_message_register(omapi_object_t *h) {
|
||||
omapi_message_t *m;
|
||||
|
||||
REQUIRE(h != NULL && h->type == omapi_type_message);
|
||||
|
||||
m = (omapi_message_t *)h;
|
||||
|
||||
/*
|
||||
* Already registered?
|
||||
*/
|
||||
REQUIRE(m->prev == NULL && m->next == NULL &&
|
||||
registered_messages != m);
|
||||
|
||||
if (registered_messages != NULL) {
|
||||
OBJECT_REF(&m->next, registered_messages);
|
||||
OBJECT_REF(®istered_messages->prev, m);
|
||||
OBJECT_DEREF(®istered_messages);
|
||||
}
|
||||
|
||||
OBJECT_REF(®istered_messages, m);
|
||||
}
|
||||
|
||||
void
|
||||
omapi_message_unregister(omapi_object_t *h) {
|
||||
omapi_message_t *m;
|
||||
omapi_message_t *n;
|
||||
|
||||
REQUIRE(h != NULL && h->type == omapi_type_message);
|
||||
|
||||
m = (omapi_message_t *)h;
|
||||
|
||||
/*
|
||||
* Not registered?
|
||||
*/
|
||||
REQUIRE(m->prev != NULL || registered_messages == m);
|
||||
|
||||
n = NULL;
|
||||
if (m->next != NULL) {
|
||||
OBJECT_REF(&n, m->next);
|
||||
OBJECT_DEREF(&m->next);
|
||||
}
|
||||
|
||||
if (m->prev != NULL) {
|
||||
omapi_message_t *tmp = NULL;
|
||||
OBJECT_REF(&tmp, m->prev);
|
||||
OBJECT_DEREF(&m->prev);
|
||||
|
||||
if (tmp->next != NULL)
|
||||
OBJECT_DEREF(&tmp->next);
|
||||
|
||||
if (n != NULL)
|
||||
OBJECT_REF(&tmp->next, n);
|
||||
|
||||
OBJECT_DEREF(&tmp);
|
||||
|
||||
} else {
|
||||
OBJECT_DEREF(®istered_messages);
|
||||
if (n != NULL)
|
||||
OBJECT_REF(®istered_messages, n);
|
||||
}
|
||||
|
||||
if (n != NULL)
|
||||
OBJECT_DEREF(&n);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
omapi_message_send(omapi_object_t *message, omapi_object_t *protocol) {
|
||||
/*
|
||||
* 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_connection_t *c;
|
||||
omapi_message_t *m;
|
||||
omapi_object_t *connection;
|
||||
unsigned int authlen = 0;
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
|
||||
REQUIRE(message != NULL && message->type == omapi_type_message);
|
||||
/*
|
||||
* Allow the function to be called with an object that is managing
|
||||
* the client side.
|
||||
*/
|
||||
REQUIRE((protocol != NULL && protocol->type == omapi_type_protocol) ||
|
||||
(protocol->outer != NULL &&
|
||||
protocol->outer->type == omapi_type_protocol));
|
||||
|
||||
if (protocol->type != omapi_type_protocol)
|
||||
protocol = protocol->outer;
|
||||
|
||||
p = (omapi_protocol_t *)protocol;
|
||||
|
||||
connection = (omapi_object_t *)(protocol->outer);
|
||||
c = (omapi_connection_t *)connection;
|
||||
|
||||
INSIST(connection != NULL &&
|
||||
connection->type == omapi_type_connection);
|
||||
|
||||
m = (omapi_message_t *)message;
|
||||
|
||||
if (p->key != NULL) {
|
||||
isc_hmacmd5_init(&p->hmacctx, p->key->base, p->key->length);
|
||||
authlen = ISC_MD5_DIGESTLENGTH;
|
||||
p->auth_update = ISC_TRUE;
|
||||
}
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
/* XXXTL Write the ID of the authentication key we're using. */
|
||||
result = omapi_connection_putuint32(connection, 0);
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
result = omapi_connection_putuint32(connection, authlen);
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
/*
|
||||
* Write the opcode.
|
||||
*/
|
||||
result = omapi_connection_putuint32(connection, m->op);
|
||||
|
||||
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).
|
||||
*/
|
||||
result = omapi_connection_putuint32(connection,
|
||||
(m->h ? m->h
|
||||
: (m->object ?
|
||||
m->object->handle
|
||||
: 0)));
|
||||
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
/*
|
||||
* Set and write the transaction ID.
|
||||
*/
|
||||
m->id = p->next_xid++;
|
||||
result = omapi_connection_putuint32(connection, m->id);
|
||||
}
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
/*
|
||||
* Write the transaction ID of the message to which this is a
|
||||
* response.
|
||||
*/
|
||||
result = omapi_connection_putuint32(connection, m->rid);
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
/*
|
||||
* Stuff out the name/value pairs specific to this message.
|
||||
*/
|
||||
result = object_stuffvalues(connection, message);
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
/*
|
||||
* Write the zero-length name that terminates the list of
|
||||
* name/value pairs specific to the message.
|
||||
*/
|
||||
result = omapi_connection_putuint16(connection, 0);
|
||||
|
||||
if (result == ISC_R_SUCCESS && m->object != NULL)
|
||||
/*
|
||||
* Stuff out all the published name/value pairs in the object
|
||||
* that's being sent in the message, if there is one.
|
||||
*/
|
||||
result = object_stuffvalues(connection, m->object);
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
/*
|
||||
* Write the zero-length name length value that terminates
|
||||
* the list of name/value pairs for the associated object.
|
||||
*/
|
||||
result = omapi_connection_putuint16(connection, 0);
|
||||
|
||||
if (result == ISC_R_SUCCESS && p->key != NULL) {
|
||||
isc_region_t r;
|
||||
|
||||
isc_buffer_clear(p->signature_out);
|
||||
|
||||
INSIST(isc_buffer_availablelength(p->signature_out) >=
|
||||
ISC_MD5_DIGESTLENGTH);
|
||||
isc_hmacmd5_sign(&p->hmacctx,
|
||||
isc_buffer_base(p->signature_out));
|
||||
|
||||
isc_hmacmd5_invalidate(&p->hmacctx);
|
||||
|
||||
isc_buffer_region(p->signature_out, &r);
|
||||
|
||||
p->auth_update = ISC_FALSE;
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
result = omapi_connection_putmem(connection,
|
||||
r.base, r.length);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
object_signal(message, "status", result, NULL);
|
||||
|
||||
} 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.
|
||||
*/
|
||||
omapi_connection_disconnect(connection,
|
||||
OMAPI_FORCE_DISCONNECT);
|
||||
|
||||
|
||||
/*
|
||||
* The client also needs to be notified the message
|
||||
* never got sent.
|
||||
*
|
||||
* XXXDCL "message not sent; connection disconnected"
|
||||
*/
|
||||
object_signal(message, "status", result, NULL);
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
message_process(omapi_object_t *mo, omapi_object_t *po) {
|
||||
omapi_message_t *message, *m;
|
||||
omapi_object_t *object = NULL;
|
||||
omapi_objecttype_t *type = NULL;
|
||||
omapi_protocol_t *protocol;
|
||||
omapi_connection_t *connection;
|
||||
omapi_value_t *tv = NULL;
|
||||
unsigned long create, update, exclusive;
|
||||
isc_result_t result, waitstatus;
|
||||
|
||||
REQUIRE(mo != NULL && mo->type == omapi_type_message);
|
||||
REQUIRE(po != NULL);
|
||||
|
||||
message = (omapi_message_t *)mo;
|
||||
protocol = (omapi_protocol_t *)po;
|
||||
|
||||
INSIST(po->outer != NULL && po->outer->type == omapi_type_connection);
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
connection = (omapi_connection_t *)po->outer;
|
||||
|
||||
if (message->rid != 0) {
|
||||
for (m = registered_messages; m != NULL; m = m->next)
|
||||
if (m->id == message->rid)
|
||||
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;
|
||||
|
||||
if (protocol->key != NULL) {
|
||||
if (protocol->signature_in.length < ISC_MD5_DIGESTLENGTH ||
|
||||
!isc_hmacmd5_verify(&protocol->hmacctx,
|
||||
protocol->signature_in.base))
|
||||
protocol->verify_result = ISC_R_FAILURE;
|
||||
|
||||
isc_hmacmd5_invalidate(&protocol->hmacctx);
|
||||
|
||||
if (protocol->verify_result != ISC_R_SUCCESS) {
|
||||
if (connection->is_client) {
|
||||
INSIST(m != NULL);
|
||||
result = omapi_object_setstring(mo, "message",
|
||||
"failed to verify signature");
|
||||
if (result == ISC_R_SUCCESS)
|
||||
(void)omapi_object_getvalue(mo,
|
||||
"message",
|
||||
&tv);
|
||||
|
||||
object_signal((omapi_object_t *)m, "status",
|
||||
protocol->verify_result, tv);
|
||||
|
||||
if (tv != NULL)
|
||||
omapi_value_dereference(&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,
|
||||
protocol->verify_result,
|
||||
message->id,
|
||||
"failed to verify "
|
||||
"signature"));
|
||||
}
|
||||
}
|
||||
|
||||
switch (message->op) {
|
||||
case OMAPI_OP_OPEN:
|
||||
if (connection->is_client)
|
||||
return (ISC_R_UNEXPECTED);
|
||||
|
||||
if (m != NULL) {
|
||||
return (send_status(po, OMAPI_R_INVALIDARG,
|
||||
message->id,
|
||||
"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.
|
||||
*/
|
||||
result = omapi_object_getvalue(mo, "type", &tv);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
if (tv->value->type == omapi_datatype_data ||
|
||||
tv->value->type == omapi_datatype_string)
|
||||
type = object_findtype(tv);
|
||||
omapi_value_dereference(&tv);
|
||||
} else if (result == ISC_R_NOTFOUND)
|
||||
type = NULL;
|
||||
else
|
||||
return (send_status(po, result, message->id,
|
||||
isc_result_totext(result)));
|
||||
|
||||
/*
|
||||
* Get the create flag.
|
||||
*/
|
||||
result = omapi_object_getvalue(mo, "create", &tv);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
create = omapi_value_getint(tv);
|
||||
omapi_value_dereference(&tv);
|
||||
} else if (result == ISC_R_NOTFOUND)
|
||||
create = 0;
|
||||
else
|
||||
return (send_status(po, result, message->id,
|
||||
isc_result_totext(result)));
|
||||
|
||||
/*
|
||||
* Get the update flag.
|
||||
*/
|
||||
result = omapi_object_getvalue(mo, "update", &tv);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
update = omapi_value_getint(tv);
|
||||
omapi_value_dereference(&tv);
|
||||
} else if (result == ISC_R_NOTFOUND)
|
||||
update = 0;
|
||||
else
|
||||
return (send_status(po, result, message->id,
|
||||
isc_result_totext(result)));
|
||||
|
||||
/*
|
||||
* Get the exclusive flag.
|
||||
*/
|
||||
result = omapi_object_getvalue(mo, "exclusive", &tv);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
exclusive = omapi_value_getint(tv);
|
||||
omapi_value_dereference(&tv);
|
||||
} else if (result == ISC_R_NOTFOUND)
|
||||
exclusive = 0;
|
||||
else
|
||||
return (send_status(po, result, message->id,
|
||||
isc_result_totext(result)));
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
if (type != omapi_type_protocol && protocol->key == NULL)
|
||||
return (send_status(po, ISC_R_NOPERM, message->id,
|
||||
"unauthorized access"));
|
||||
#endif /* notyet */
|
||||
|
||||
/*
|
||||
* If we weren't given a type, look the object up with
|
||||
* the handle.
|
||||
*/
|
||||
if (type == NULL) {
|
||||
if (create != 0)
|
||||
return (send_status(po, OMAPI_R_INVALIDARG,
|
||||
message->id,
|
||||
"type required on create"));
|
||||
|
||||
goto refresh;
|
||||
}
|
||||
|
||||
if (message->object == NULL)
|
||||
return (send_status(po, ISC_R_NOTFOUND, message->id,
|
||||
"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) {
|
||||
OBJECT_REF(&object, po);
|
||||
result = ISC_R_SUCCESS;
|
||||
|
||||
} else
|
||||
result = object_methodlookup(type, &object,
|
||||
message->object);
|
||||
|
||||
if (result == ISC_R_NOTIMPLEMENTED)
|
||||
return (send_status(po, result, message->id,
|
||||
"unsearchable object type"));
|
||||
|
||||
if (result != ISC_R_SUCCESS &&
|
||||
result != ISC_R_NOTFOUND &&
|
||||
result != OMAPI_R_NOKEYS)
|
||||
return (send_status(po, result, message->id,
|
||||
"object lookup failed"));
|
||||
|
||||
/*
|
||||
* If we didn't find the object and we aren't supposed to
|
||||
* create it, return an error.
|
||||
*/
|
||||
if (result == ISC_R_NOTFOUND && create == 0) {
|
||||
return (send_status(po, ISC_R_NOTFOUND, message->id,
|
||||
"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.
|
||||
*/
|
||||
if (result == ISC_R_SUCCESS && create != 0 && exclusive != 0) {
|
||||
OBJECT_DEREF(&object);
|
||||
return (send_status(po, ISC_R_EXISTS, message->id,
|
||||
"specified object already exists"));
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're creating the object, do it now.
|
||||
*/
|
||||
if (object == NULL) {
|
||||
result = object_methodcreate(type, &object);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (send_status(po, result, message->id,
|
||||
"can't create new object"));
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're updating it, do so now.
|
||||
*/
|
||||
if (create != 0 || update != 0) {
|
||||
result = object_update(object, message->object,
|
||||
message->h);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
OBJECT_DEREF(&object);
|
||||
return (send_status(po, result, message->id,
|
||||
"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 */
|
||||
if (protocol->key == NULL)
|
||||
return (send_status(po, ISC_R_NOPERM, message->id,
|
||||
"unauthorized access"));
|
||||
#endif /* notyet */
|
||||
|
||||
refresh:
|
||||
result = handle_lookup(&object, message->h);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (send_status(po, result, message->id,
|
||||
"no matching handle"));
|
||||
|
||||
send:
|
||||
result = send_update(po, message->id, object);
|
||||
OBJECT_DEREF(&object);
|
||||
return (result);
|
||||
|
||||
case OMAPI_OP_UPDATE:
|
||||
if (! connection->is_client)
|
||||
return (send_status(po, OMAPI_R_INVALIDARG,
|
||||
message->id,
|
||||
"OMAPI_OP_UPDATE is not a "
|
||||
"valid server operation"));
|
||||
|
||||
if (m->object != NULL)
|
||||
OBJECT_REF(&object, m->object);
|
||||
|
||||
else {
|
||||
result = handle_lookup(&object, message->h);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (send_status(po, result, message->id,
|
||||
"no matching handle"));
|
||||
}
|
||||
|
||||
if (message->object != NULL)
|
||||
result = object_update(object, message->object,
|
||||
message->h);
|
||||
else
|
||||
result = ISC_R_SUCCESS;
|
||||
|
||||
OBJECT_DEREF(&object);
|
||||
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
if (message->rid == 0)
|
||||
return (send_status(po, result, message->id,
|
||||
"can't update object"));
|
||||
if (m != NULL)
|
||||
object_signal((omapi_object_t *)m,
|
||||
"status", result, NULL);
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
if (message->rid == 0)
|
||||
result = send_status(po, ISC_R_SUCCESS, message->id,
|
||||
NULL);
|
||||
|
||||
if (m != NULL)
|
||||
object_signal((omapi_object_t *)m, "status",
|
||||
ISC_R_SUCCESS, NULL);
|
||||
|
||||
return (result);
|
||||
|
||||
case OMAPI_OP_NOTIFY:
|
||||
return (send_status(po, ISC_R_NOTIMPLEMENTED, message->id,
|
||||
"notify not implemented yet"));
|
||||
|
||||
case OMAPI_OP_STATUS:
|
||||
if (! connection->is_client)
|
||||
return (send_status(po, OMAPI_R_INVALIDARG,
|
||||
message->id,
|
||||
"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.
|
||||
*/
|
||||
result = omapi_object_getvalue(mo, "result", &tv);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
waitstatus = omapi_value_getint(tv);
|
||||
omapi_value_dereference(&tv);
|
||||
} else
|
||||
waitstatus = ISC_R_UNEXPECTED;
|
||||
|
||||
result = omapi_object_getvalue(mo, "message", &tv);
|
||||
|
||||
object_signal((omapi_object_t *)m, "status", waitstatus, tv);
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
omapi_value_dereference(&tv);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
if (protocol->key == NULL)
|
||||
return (send_status(po, ISC_R_NOPERM, message->id,
|
||||
"unauthorized delete"));
|
||||
|
||||
result = handle_lookup(&object, message->h);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (send_status(po, result, message->id,
|
||||
"no matching handle"));
|
||||
|
||||
result = object_methodexpunge(object->type, object);
|
||||
if (result == ISC_R_NOTIMPLEMENTED)
|
||||
return (send_status(po, ISC_R_NOTIMPLEMENTED,
|
||||
message->id,
|
||||
"no remove method for object"));
|
||||
|
||||
OBJECT_DEREF(&object);
|
||||
|
||||
return (send_status(po, result, message->id, NULL));
|
||||
}
|
||||
|
||||
return (ISC_R_NOTIMPLEMENTED);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
message_setvalue(omapi_object_t *h, omapi_string_t *name, omapi_data_t *value)
|
||||
{
|
||||
omapi_message_t *m;
|
||||
|
||||
REQUIRE(h != NULL && h->type == omapi_type_message);
|
||||
|
||||
m = (omapi_message_t *)h;
|
||||
|
||||
/*
|
||||
* Can't set authlen.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Can set authenticator, but the value must be typed data.
|
||||
* XXXDCL (no longer meaningful)
|
||||
*/
|
||||
if (omapi_string_strcmp(name, "authenticator") == 0) {
|
||||
if (m->authenticator != NULL)
|
||||
omapi_data_dereference(&m->authenticator);
|
||||
omapi_data_reference(&m->authenticator, value);
|
||||
return (ISC_R_SUCCESS);
|
||||
|
||||
} else if (omapi_string_strcmp(name, "object") == 0) {
|
||||
INSIST(value != NULL && value->type == omapi_datatype_object);
|
||||
|
||||
if (m->object != NULL)
|
||||
OBJECT_DEREF(&m->object);
|
||||
OBJECT_REF(&m->object, value->u.object);
|
||||
return (ISC_R_SUCCESS);
|
||||
|
||||
} else if (omapi_string_strcmp(name, "notify-object") == 0) {
|
||||
INSIST(value != NULL && value->type == omapi_datatype_object);
|
||||
|
||||
if (m->notify_object != NULL)
|
||||
OBJECT_DEREF(&m->notify_object);
|
||||
OBJECT_REF(&m->notify_object, value->u.object);
|
||||
return (ISC_R_SUCCESS);
|
||||
|
||||
/*
|
||||
* Can set authid, but it has to be an integer.
|
||||
*/
|
||||
} else if (omapi_string_strcmp(name, "authid") == 0) {
|
||||
INSIST(value != NULL && value->type == omapi_datatype_int);
|
||||
|
||||
m->authid = value->u.integer;
|
||||
return (ISC_R_SUCCESS);
|
||||
|
||||
/*
|
||||
* Can set op, but it has to be an integer.
|
||||
*/
|
||||
} else if (omapi_string_strcmp(name, "op") == 0) {
|
||||
INSIST(value != NULL && value->type == omapi_datatype_int);
|
||||
|
||||
m->op = value->u.integer;
|
||||
return (ISC_R_SUCCESS);
|
||||
|
||||
/*
|
||||
* Handle also has to be an integer.
|
||||
*/
|
||||
} else if (omapi_string_strcmp(name, "handle") == 0) {
|
||||
INSIST(value != NULL && value->type == omapi_datatype_int);
|
||||
|
||||
m->h = value->u.integer;
|
||||
return (ISC_R_SUCCESS);
|
||||
|
||||
/*
|
||||
* Transaction ID has to be an integer.
|
||||
*/
|
||||
} else if (omapi_string_strcmp(name, "id") == 0) {
|
||||
INSIST(value != NULL && value->type == omapi_datatype_int);
|
||||
|
||||
m->id = value->u.integer;
|
||||
return (ISC_R_SUCCESS);
|
||||
|
||||
/*
|
||||
* Remote transaction ID has to be an integer.
|
||||
*/
|
||||
} else if (omapi_string_strcmp(name, "rid") == 0) {
|
||||
INSIST(value != NULL && value->type == omapi_datatype_int);
|
||||
|
||||
m->rid = value->u.integer;
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to find some inner object that can take the value.
|
||||
*/
|
||||
return (omapi_object_passsetvalue(h, name, value));
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
message_getvalue(omapi_object_t *h, omapi_string_t *name,
|
||||
omapi_value_t **value)
|
||||
{
|
||||
omapi_message_t *m;
|
||||
|
||||
REQUIRE(h != NULL && h->type == omapi_type_message);
|
||||
|
||||
m = (omapi_message_t *)h;
|
||||
|
||||
/*
|
||||
* Look for values that are in the message data structure.
|
||||
*/
|
||||
if (omapi_string_strcmp(name, "authenticator") == 0) {
|
||||
if (m->authenticator != NULL)
|
||||
return (omapi_value_storedata(value, name,
|
||||
m->authenticator));
|
||||
else
|
||||
return (ISC_R_NOTFOUND);
|
||||
|
||||
} else if (omapi_string_strcmp(name, "authlen") == 0)
|
||||
return (omapi_value_storeint(value, name, (int)m->authlen));
|
||||
|
||||
else if (omapi_string_strcmp(name, "authid") == 0)
|
||||
return (omapi_value_storeint(value, name, (int)m->authid));
|
||||
|
||||
else if (omapi_string_strcmp(name, "op") == 0)
|
||||
return (omapi_value_storeint(value, name, (int)m->op));
|
||||
|
||||
else if (omapi_string_strcmp(name, "handle") == 0)
|
||||
return (omapi_value_storeint(value, name, (int)m->h));
|
||||
|
||||
else if (omapi_string_strcmp(name, "id") == 0)
|
||||
return (omapi_value_storeint(value, name, (int)m->id));
|
||||
|
||||
else if (omapi_string_strcmp(name, "rid") == 0)
|
||||
return (omapi_value_storeint(value, name, (int)m->rid));
|
||||
|
||||
/*
|
||||
* See if there's an inner object that has the value.
|
||||
*/
|
||||
return (omapi_object_passgetvalue(h, name, value));
|
||||
}
|
||||
|
||||
static void
|
||||
message_destroy(omapi_object_t *handle) {
|
||||
omapi_message_t *message;
|
||||
|
||||
REQUIRE(handle != NULL && handle->type == omapi_type_message);
|
||||
|
||||
message = (omapi_message_t *)handle;
|
||||
|
||||
if (message->authenticator != NULL)
|
||||
omapi_data_dereference(&message->authenticator);
|
||||
|
||||
INSIST(message->prev == NULL && message->next == NULL &&
|
||||
registered_messages != message);
|
||||
|
||||
if (message->object != NULL)
|
||||
OBJECT_DEREF(&message->object);
|
||||
|
||||
if (message->notify_object != NULL)
|
||||
OBJECT_DEREF(&message->notify_object);
|
||||
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
message_signalhandler(omapi_object_t *handle, const char *name, va_list ap) {
|
||||
omapi_message_t *message;
|
||||
|
||||
REQUIRE(handle != NULL && handle->type == omapi_type_message);
|
||||
|
||||
message = (omapi_message_t *)handle;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
if (strcmp(name, "status") == 0 &&
|
||||
(message->object != NULL || message->notify_object != NULL)) {
|
||||
if (message->notify_object != NULL)
|
||||
return (object_vsignal(message->notify_object, name,
|
||||
ap));
|
||||
else
|
||||
return (object_vsignal(message->object, name, ap));
|
||||
}
|
||||
|
||||
return (omapi_object_passsignal(handle, name, ap));
|
||||
}
|
||||
|
||||
/*
|
||||
* Write all the published values associated with the object through the
|
||||
* specified connection.
|
||||
*/
|
||||
static isc_result_t
|
||||
message_stuffvalues(omapi_object_t *connection, omapi_object_t *message)
|
||||
{
|
||||
REQUIRE(message != NULL && message->type == omapi_type_message);
|
||||
|
||||
return (omapi_object_passstuffvalues(connection, message));
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
message_init(void) {
|
||||
return (omapi_object_register(&omapi_type_message, "message",
|
||||
message_setvalue,
|
||||
message_getvalue,
|
||||
message_destroy,
|
||||
message_signalhandler,
|
||||
message_stuffvalues,
|
||||
NULL, NULL, NULL));
|
||||
}
|
@ -1,598 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1996-2001 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: object.c,v 1.23 2001/01/09 22:00:04 bwelling Exp $ */
|
||||
|
||||
/* Principal Author: Ted Lemon */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <isc/mem.h>
|
||||
#include <isc/string.h>
|
||||
#include <isc/task.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
|
||||
#include <omapi/private.h>
|
||||
|
||||
struct omapi_objecttype {
|
||||
const char * name;
|
||||
omapi_objecttype_t * next;
|
||||
|
||||
isc_result_t (*set_value)(omapi_object_t *object,
|
||||
omapi_string_t *name,
|
||||
omapi_data_t *value);
|
||||
|
||||
isc_result_t (*get_value)(omapi_object_t *object,
|
||||
omapi_string_t *name,
|
||||
omapi_value_t **value);
|
||||
|
||||
void (*destroy)(omapi_object_t *object);
|
||||
|
||||
isc_result_t (*signal_handler)(omapi_object_t *object,
|
||||
const char *name,
|
||||
va_list args);
|
||||
|
||||
isc_result_t (*stuff_values)(omapi_object_t *connection,
|
||||
omapi_object_t *object);
|
||||
|
||||
isc_result_t (*lookup)(omapi_object_t **object,
|
||||
omapi_object_t *key);
|
||||
|
||||
isc_result_t (*create)(omapi_object_t **object);
|
||||
|
||||
isc_result_t (*expunge)(omapi_object_t *object);
|
||||
};
|
||||
|
||||
isc_result_t
|
||||
omapi_object_create(omapi_object_t **object, omapi_objecttype_t *type,
|
||||
size_t size)
|
||||
{
|
||||
omapi_object_t *new;
|
||||
|
||||
REQUIRE(object != NULL && *object == NULL);
|
||||
REQUIRE(size > 0 || type == NULL);
|
||||
|
||||
if (type == NULL) {
|
||||
type = omapi_type_generic;
|
||||
size = sizeof(omapi_generic_t);
|
||||
}
|
||||
|
||||
new = isc_mem_get(omapi_mctx, size);
|
||||
if (new == NULL)
|
||||
return (ISC_R_NOMEMORY);
|
||||
|
||||
memset(new, 0, size);
|
||||
|
||||
new->object_size = size;
|
||||
new->refcnt = 1;
|
||||
new->type = type;
|
||||
|
||||
*object = new;
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
void
|
||||
omapi_object_reference(omapi_object_t **r, omapi_object_t *h) {
|
||||
REQUIRE(r != NULL && *r == NULL);
|
||||
REQUIRE(h != NULL);
|
||||
|
||||
*r = h;
|
||||
h->refcnt++;
|
||||
}
|
||||
|
||||
void
|
||||
omapi_object_dereference(omapi_object_t **h) {
|
||||
int outer_reference = 0;
|
||||
int inner_reference = 0;
|
||||
int handle_reference = 0;
|
||||
int extra_references;
|
||||
omapi_object_t *p = NULL;
|
||||
|
||||
REQUIRE(h != NULL && *h != NULL);
|
||||
REQUIRE((*h)->refcnt > 0);
|
||||
|
||||
/*
|
||||
* See if this object's inner object refers back to it, but don't
|
||||
* count this as a reference if we're being asked to free the
|
||||
* reference from the inner object.
|
||||
*/
|
||||
/*
|
||||
* XXXDCL my wording
|
||||
* Note whether the object being dereferenced has an inner object, but
|
||||
* only if the inner object's own outer pointer is not what is
|
||||
* being dereferenced.
|
||||
* (XXXDCL when does it happen that way ?)
|
||||
*/
|
||||
if ((*h)->inner != NULL && (*h)->inner->outer != NULL &&
|
||||
h != &((*h)->inner->outer))
|
||||
inner_reference = 1;
|
||||
|
||||
/*
|
||||
* Ditto for the outer object.
|
||||
*/
|
||||
if ((*h)->outer != NULL && (*h)->outer->inner != NULL &&
|
||||
h != &((*h)->outer->inner))
|
||||
outer_reference = 1;
|
||||
|
||||
/*
|
||||
* Ditto for the handle object. The code below assumes that
|
||||
* the only reason we'd get a dereference from the handle
|
||||
* table is if this function does it - otherwise we'd have to
|
||||
* traverse the handle table to find the address where the
|
||||
* reference is stored and compare against that, and we don't
|
||||
* want to do that if we can avoid it.
|
||||
*/
|
||||
if ((*h)->handle != 0)
|
||||
handle_reference = 1;
|
||||
|
||||
/*
|
||||
* If we are getting rid of the last reference other than
|
||||
* references to inner and outer objects, or from the handle
|
||||
* table, then we must examine all the objects in either
|
||||
* direction to see if they hold any non-inner, non-outer,
|
||||
* non-handle-table references. If not, we need to free the
|
||||
* entire chain of objects.
|
||||
*/
|
||||
INSIST((*h)->refcnt >=
|
||||
inner_reference + outer_reference + handle_reference + 1);
|
||||
|
||||
if ((*h)->refcnt ==
|
||||
inner_reference + outer_reference + handle_reference + 1) {
|
||||
/*
|
||||
* If refcnt is > 1, then inner_reference + outer_reference +
|
||||
* handle_reference is > 0, so there are list references to
|
||||
* chase.
|
||||
*/
|
||||
if ((*h)->refcnt > 1) {
|
||||
/*
|
||||
* XXXTL we could check for a reference from the
|
||||
* handle table here.
|
||||
*/
|
||||
extra_references = 0;
|
||||
|
||||
if (inner_reference != 0)
|
||||
for (p = (*h)->inner;
|
||||
p != NULL && extra_references == 0;
|
||||
p = p->inner) {
|
||||
extra_references += p->refcnt - 1;
|
||||
if (p->inner != NULL)
|
||||
--extra_references;
|
||||
if (p->handle != 0)
|
||||
--extra_references;
|
||||
}
|
||||
|
||||
if (outer_reference != 0)
|
||||
for (p = (*h)->outer;
|
||||
p != NULL && extra_references == 0;
|
||||
p = p->outer) {
|
||||
extra_references += p->refcnt - 1;
|
||||
if (p->outer != NULL)
|
||||
--extra_references;
|
||||
if (p->handle != 0)
|
||||
--extra_references;
|
||||
}
|
||||
} else
|
||||
extra_references = 0;
|
||||
|
||||
if (extra_references == 0) {
|
||||
isc_taskaction_t action = (*h)->destroy_action;
|
||||
void *arg = (*h)->destroy_arg;
|
||||
|
||||
if (inner_reference != 0)
|
||||
OBJECT_DEREF(&(*h)->inner);
|
||||
if (outer_reference != 0)
|
||||
OBJECT_DEREF(&(*h)->outer);
|
||||
if ((*h)->type->destroy != NULL)
|
||||
(*((*h)->type->destroy))(*h);
|
||||
(*h)->refcnt = 0;
|
||||
isc_mem_put(omapi_mctx, *h, (*h)->object_size);
|
||||
|
||||
if (action != NULL) {
|
||||
isc_event_t *event;
|
||||
|
||||
event = isc_event_allocate(omapi_mctx, NULL,
|
||||
OMAPI_EVENT_OBJECTFREED,
|
||||
action, arg,
|
||||
sizeof(isc_event_t));
|
||||
if (event != NULL)
|
||||
isc_task_send(omapi_task, &event);
|
||||
}
|
||||
|
||||
} else
|
||||
(*h)->refcnt--;
|
||||
|
||||
} else
|
||||
(*h)->refcnt--;
|
||||
|
||||
*h = NULL;
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
omapi_object_register(omapi_objecttype_t **type, const char *name,
|
||||
isc_result_t (*set_value)(omapi_object_t *,
|
||||
omapi_string_t *,
|
||||
omapi_data_t *),
|
||||
|
||||
isc_result_t (*get_value)(omapi_object_t *,
|
||||
omapi_string_t *,
|
||||
omapi_value_t **),
|
||||
|
||||
void (*destroy)(omapi_object_t *),
|
||||
|
||||
isc_result_t (*signal_handler)(omapi_object_t *,
|
||||
const char *, va_list),
|
||||
|
||||
isc_result_t (*stuff_values)(omapi_object_t *,
|
||||
omapi_object_t *),
|
||||
|
||||
isc_result_t (*lookup)(omapi_object_t **,
|
||||
omapi_object_t *),
|
||||
|
||||
isc_result_t (*create)(omapi_object_t **),
|
||||
|
||||
isc_result_t (*expunge)(omapi_object_t *))
|
||||
{
|
||||
omapi_objecttype_t *t;
|
||||
|
||||
t = isc_mem_get(omapi_mctx, sizeof(*t));
|
||||
if (t == NULL)
|
||||
return (ISC_R_NOMEMORY);
|
||||
memset(t, 0, sizeof(*t));
|
||||
|
||||
t->name = name;
|
||||
|
||||
t->set_value = set_value;
|
||||
t->get_value = get_value;
|
||||
t->destroy = destroy;
|
||||
t->signal_handler = signal_handler;
|
||||
t->stuff_values = stuff_values;
|
||||
t->lookup = lookup;
|
||||
t->create = create;
|
||||
t->expunge = expunge;
|
||||
|
||||
t->next = omapi_object_types;
|
||||
omapi_object_types = t;
|
||||
|
||||
if (type != NULL)
|
||||
*type = t;
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
omapi_objecttype_t *
|
||||
object_findtype(omapi_value_t *tv) {
|
||||
omapi_objecttype_t *type;
|
||||
|
||||
for (type = omapi_object_types; type != NULL; type = type->next)
|
||||
if (omapi_data_strcmp(tv->value, type->name) == 0)
|
||||
break;
|
||||
|
||||
return (type);
|
||||
}
|
||||
|
||||
void
|
||||
object_destroytypes(void) {
|
||||
omapi_objecttype_t *type, *next_type;
|
||||
|
||||
for (type = omapi_object_types; type != NULL; type = next_type) {
|
||||
next_type = type->next;
|
||||
isc_mem_put(omapi_mctx, type, sizeof(*type));
|
||||
}
|
||||
|
||||
omapi_object_types = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Call the signal method for an object chain, starting at the outermost
|
||||
* object.
|
||||
*/
|
||||
isc_result_t
|
||||
object_signal(omapi_object_t *handle, const char *name, ...) {
|
||||
va_list ap;
|
||||
omapi_object_t *outer;
|
||||
isc_result_t result;
|
||||
|
||||
va_start(ap, name);
|
||||
for (outer = handle; outer->outer != NULL; outer = outer->outer)
|
||||
;
|
||||
if (outer->type->signal_handler != NULL)
|
||||
result = (*(outer->type->signal_handler))(outer, name, ap);
|
||||
else
|
||||
result = ISC_R_NOTFOUND;
|
||||
va_end(ap);
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* Call the signal method for the named object. Used by message_process().
|
||||
*/
|
||||
isc_result_t
|
||||
object_vsignal(omapi_object_t *handle, const char *name, va_list ap) {
|
||||
REQUIRE(handle != NULL);
|
||||
|
||||
if (handle->type->signal_handler != NULL)
|
||||
return ((handle->type->signal_handler)(handle, name, ap));
|
||||
else
|
||||
return (ISC_R_NOTFOUND);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
omapi_object_set(omapi_object_t *h, omapi_string_t *name, omapi_data_t *value)
|
||||
{
|
||||
omapi_object_t *outer;
|
||||
|
||||
for (outer = h; outer->outer != NULL; outer = outer->outer)
|
||||
;
|
||||
if (outer->type->set_value != NULL)
|
||||
return (*(outer->type->set_value))(outer, name, value);
|
||||
return (ISC_R_NOTFOUND);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
omapi_object_setdata(omapi_object_t *h, const char *name, omapi_data_t *value)
|
||||
{
|
||||
omapi_string_t *nds;
|
||||
isc_result_t result;
|
||||
|
||||
nds = NULL;
|
||||
result = omapi_string_create(&nds, strlen(name));
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (result);
|
||||
memcpy(nds->value, name, strlen(name));
|
||||
|
||||
return (omapi_object_set(h, nds, value));
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
omapi_object_setboolean(omapi_object_t *h, const char *name,
|
||||
isc_boolean_t value)
|
||||
{
|
||||
int boolean_value;
|
||||
isc_result_t result;
|
||||
omapi_data_t *tv = NULL;
|
||||
omapi_string_t *n = NULL;
|
||||
|
||||
result = omapi_string_create(&n, strlen(name));
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (result);
|
||||
memcpy(n->value, name, strlen(name));
|
||||
|
||||
boolean_value = (value == ISC_TRUE ? 1 : 0);
|
||||
|
||||
result = omapi_data_create(&tv, omapi_datatype_int, boolean_value);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
omapi_string_dereference(&n);
|
||||
return (result);
|
||||
}
|
||||
|
||||
result = omapi_object_set(h, n, tv);
|
||||
omapi_string_dereference(&n);
|
||||
omapi_data_dereference(&tv);
|
||||
return (result);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
omapi_object_setinteger(omapi_object_t *h, const char *name, int value) {
|
||||
isc_result_t result;
|
||||
omapi_data_t *tv = NULL;
|
||||
omapi_string_t *n = NULL;
|
||||
|
||||
result = omapi_string_create(&n, strlen(name));
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (result);
|
||||
memcpy(n->value, name, strlen(name));
|
||||
|
||||
result = omapi_data_create(&tv, omapi_datatype_int, value);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
omapi_string_dereference(&n);
|
||||
return (result);
|
||||
}
|
||||
|
||||
result = omapi_object_set(h, n, tv);
|
||||
omapi_string_dereference(&n);
|
||||
omapi_data_dereference(&tv);
|
||||
return (result);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
omapi_object_setobject(omapi_object_t *h, const char *name,
|
||||
omapi_object_t *value)
|
||||
{
|
||||
isc_result_t result;
|
||||
omapi_data_t *tv = NULL;
|
||||
omapi_string_t *n = NULL;
|
||||
|
||||
result = omapi_string_create(&n, strlen(name));
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (result);
|
||||
memcpy(n->value, name, strlen(name));
|
||||
|
||||
result = omapi_data_create(&tv, omapi_datatype_object, value);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
omapi_string_dereference(&n);
|
||||
return (result);
|
||||
}
|
||||
|
||||
result = omapi_object_set(h, n, tv);
|
||||
omapi_string_dereference(&n);
|
||||
omapi_data_dereference(&tv);
|
||||
return (result);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
omapi_object_setstring(omapi_object_t *h, const char *name, const char *value)
|
||||
{
|
||||
isc_result_t result;
|
||||
omapi_data_t *tv = NULL;
|
||||
omapi_string_t *n = NULL;
|
||||
|
||||
result = omapi_string_create(&n, strlen(name));
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (result);
|
||||
memcpy(n->value, name, strlen(name));
|
||||
|
||||
result = omapi_data_create(&tv, omapi_datatype_string, value);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
omapi_string_dereference(&n);
|
||||
return (result);
|
||||
}
|
||||
|
||||
result = omapi_object_set(h, n, tv);
|
||||
omapi_string_dereference(&n);
|
||||
omapi_data_dereference(&tv);
|
||||
return (result);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
omapi_object_getvalue(omapi_object_t *h, const char *name,
|
||||
omapi_value_t **value)
|
||||
{
|
||||
omapi_object_t *outer;
|
||||
omapi_string_t *nds;
|
||||
isc_result_t result;
|
||||
|
||||
nds = NULL;
|
||||
result = omapi_string_create(&nds, strlen(name));
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (result);
|
||||
memcpy(nds->value, name, strlen(name));
|
||||
|
||||
for (outer = h; outer->outer != NULL; outer = outer->outer)
|
||||
;
|
||||
if (outer->type->get_value != NULL)
|
||||
result = (*(outer->type->get_value))(outer, nds, value);
|
||||
else
|
||||
result = ISC_R_NOTFOUND;
|
||||
|
||||
omapi_string_dereference(&nds);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
object_stuffvalues(omapi_object_t *connection, omapi_object_t *object) {
|
||||
omapi_object_t *outer;
|
||||
|
||||
for (outer = object; outer->outer != NULL; outer = outer->outer)
|
||||
;
|
||||
if (outer->type->stuff_values != NULL)
|
||||
return ((*(outer->type->stuff_values))(connection, outer));
|
||||
return (ISC_R_NOTFOUND);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
object_update(omapi_object_t *obj, omapi_object_t *src, omapi_handle_t handle)
|
||||
{
|
||||
omapi_generic_t *gsrc;
|
||||
isc_result_t result;
|
||||
unsigned int i;
|
||||
|
||||
REQUIRE(src != NULL);
|
||||
|
||||
if (src->type != omapi_type_generic)
|
||||
return (ISC_R_NOTIMPLEMENTED);
|
||||
|
||||
gsrc = (omapi_generic_t *)src;
|
||||
|
||||
for (i = 0; i < gsrc->nvalues; i++) {
|
||||
result = omapi_object_set(obj,
|
||||
gsrc->values[i]->name,
|
||||
gsrc->values[i]->value);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (result);
|
||||
}
|
||||
|
||||
if (handle != 0)
|
||||
omapi_object_setinteger(obj, "remote-handle", (int)handle);
|
||||
|
||||
result = object_signal(obj, "updated");
|
||||
|
||||
if (result != ISC_R_NOTFOUND)
|
||||
return (result);
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
omapi_object_passgetvalue(omapi_object_t *object, omapi_string_t *name,
|
||||
omapi_value_t **value)
|
||||
{
|
||||
if (PASS_CHECK(object, get_value))
|
||||
return (*(object->inner->type->get_value))(object->inner,
|
||||
name, value);
|
||||
else
|
||||
return (ISC_R_NOTFOUND);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
omapi_object_passsetvalue(omapi_object_t *object, omapi_string_t *name,
|
||||
omapi_data_t *value)
|
||||
{
|
||||
if (PASS_CHECK(object, set_value))
|
||||
return (*(object->inner->type->set_value))(object->inner,
|
||||
name, value);
|
||||
else
|
||||
return (ISC_R_NOTFOUND);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
omapi_object_passsignal(omapi_object_t *object, const char *name, va_list ap) {
|
||||
if (PASS_CHECK(object, signal_handler))
|
||||
return (*(object->inner->type->signal_handler))(object->inner,
|
||||
name, ap);
|
||||
else
|
||||
return (ISC_R_NOTFOUND);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
omapi_object_passstuffvalues(omapi_object_t *connection,
|
||||
omapi_object_t *object)
|
||||
{
|
||||
if (PASS_CHECK(object, stuff_values))
|
||||
return (*(object->inner->type->stuff_values))(connection,
|
||||
object->inner);
|
||||
else
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
object_methodlookup(omapi_objecttype_t *type, omapi_object_t **object,
|
||||
omapi_object_t *key)
|
||||
{
|
||||
if (type->lookup != NULL)
|
||||
return ((*(type->lookup))(object, key));
|
||||
else
|
||||
return (ISC_R_NOTIMPLEMENTED);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
object_methodcreate(omapi_objecttype_t *type, omapi_object_t **object) {
|
||||
if (type->create != NULL)
|
||||
return ((*(type->create))(object));
|
||||
else
|
||||
return (ISC_R_NOTIMPLEMENTED);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
object_methodexpunge(omapi_objecttype_t *type, omapi_object_t *object) {
|
||||
if (type->expunge != NULL)
|
||||
return ((*(type->expunge))(object));
|
||||
else
|
||||
return (ISC_R_NOTIMPLEMENTED);
|
||||
}
|
@ -1,812 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1996-2001 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: protocol.c,v 1.37 2001/03/14 17:59:25 halley Exp $ */
|
||||
|
||||
/*
|
||||
* Functions supporting the object management protocol.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stddef.h> /* NULL */
|
||||
#include <stdlib.h> /* random */
|
||||
|
||||
#include <isc/buffer.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/string.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <omapi/private.h>
|
||||
#include <omapi/result.h>
|
||||
|
||||
/*
|
||||
* OMAPI protocol header, version 1.00
|
||||
*/
|
||||
typedef struct omapi_protocolheader {
|
||||
unsigned int authlen; /* Length of authenticator. */
|
||||
unsigned int authid; /* Authenticator object ID. */
|
||||
unsigned int op; /* Operation code. */
|
||||
omapi_handle_t handle; /* Handle of object being operated on or 0. */
|
||||
unsigned int id; /* Transaction ID. */
|
||||
unsigned int rid; /* ID of transaction responding to. */
|
||||
} omapi_protocolheader_t;
|
||||
|
||||
isc_result_t
|
||||
omapi_protocol_connect(omapi_object_t *h, const char *server_name,
|
||||
in_port_t port, omapi_object_t *authinfo)
|
||||
{
|
||||
isc_result_t result;
|
||||
omapi_protocol_t *obj = NULL;
|
||||
|
||||
REQUIRE(h != NULL && server_name != NULL);
|
||||
REQUIRE(port != 0);
|
||||
|
||||
result = omapi_object_create((omapi_object_t **)&obj,
|
||||
omapi_type_protocol, sizeof(*obj));
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (result);
|
||||
|
||||
OBJECT_REF(&h->outer, obj);
|
||||
OBJECT_REF(&obj->inner, h);
|
||||
|
||||
/*
|
||||
* Drop this function's direct reference to the protocol object
|
||||
* so that connect_toserver or send_intro can free the connection
|
||||
* and protocol objects in the event of an error.
|
||||
*/
|
||||
OBJECT_DEREF(&obj);
|
||||
|
||||
result = connect_toserver(h->outer, server_name, port);
|
||||
|
||||
/*
|
||||
* Send the introductory message. This will also wait (via
|
||||
* connection_send) for the server's introductory message before
|
||||
* proceeding. While the original design for OMAPI declared that this
|
||||
* was to be entirely asynchronous, it just won't work for the client
|
||||
* side program to go storming ahead, making calls that try to use the
|
||||
* connection object, when it is possible that the thread that reads
|
||||
* the socket will wake up with the server's intro message, find some
|
||||
* sort of problem, and then blow away the connection object while the
|
||||
* client program is asynchronously trying to use it. (This could be
|
||||
* done, of course, with a lot more thread locking than currently
|
||||
* happens.)
|
||||
*
|
||||
* If send_intro fails, the connection is already destroyed.
|
||||
*/
|
||||
if (result == ISC_R_SUCCESS)
|
||||
result = send_intro(h->outer, OMAPI_PROTOCOL_VERSION);
|
||||
|
||||
if (authinfo != NULL)
|
||||
OBJECT_REF(&((omapi_protocol_t *)h->outer)->authinfo,authinfo);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
void
|
||||
omapi_protocol_disconnect(omapi_object_t *handle, isc_boolean_t force) {
|
||||
omapi_protocol_t *protocol;
|
||||
omapi_connection_t *connection;
|
||||
|
||||
REQUIRE(handle != NULL);
|
||||
|
||||
protocol = (omapi_protocol_t *)handle->outer;
|
||||
|
||||
if (protocol == NULL)
|
||||
return; /* Already disconnected. */
|
||||
|
||||
INSIST(protocol->type == omapi_type_protocol);
|
||||
|
||||
connection = (omapi_connection_t *)protocol->outer;
|
||||
|
||||
INSIST(connection != NULL &&
|
||||
connection->type == omapi_type_connection);
|
||||
|
||||
omapi_connection_disconnect((omapi_object_t *)connection, force);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send the protocol introduction message.
|
||||
*/
|
||||
isc_result_t
|
||||
send_intro(omapi_object_t *h, unsigned int ver) {
|
||||
isc_result_t result;
|
||||
omapi_protocol_t *p;
|
||||
omapi_connection_t *connection;
|
||||
|
||||
REQUIRE(h != NULL && h->type == omapi_type_protocol);
|
||||
REQUIRE(h->outer != NULL && h->outer->type == omapi_type_connection);
|
||||
|
||||
p = (omapi_protocol_t *)h;
|
||||
connection = (omapi_connection_t *)h->outer;
|
||||
|
||||
result = omapi_connection_putuint32((omapi_object_t *)connection, ver);
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
result =
|
||||
omapi_connection_putuint32((omapi_object_t *)connection,
|
||||
sizeof(omapi_protocolheader_t));
|
||||
|
||||
/*
|
||||
* Require the other end to send an intro - this kicks off the
|
||||
* protocol input state machine. This does not use connection_require
|
||||
* to set the number of bytes required because then a socket recv would
|
||||
* be queued. To simplify the MT issues, the library only expects to
|
||||
* have one task outstanding at a time, so the number of bytes
|
||||
* that will be expected is set here, but the actual recv for
|
||||
* them is not queued until after the send event posts.
|
||||
*/
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
p->state = omapi_protocol_intro_wait;
|
||||
connection->bytes_needed = 8;
|
||||
|
||||
/*
|
||||
* Make up an initial transaction ID for this connection.
|
||||
* XXXDCL better generator than random()?
|
||||
*/
|
||||
p->next_xid = random();
|
||||
|
||||
result = connection_send(connection);
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
} else
|
||||
/*
|
||||
* One of the calls to omapi_connection_put* 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 listener_accept, so the connection can just
|
||||
* be freed right here; listener_accept will not try to
|
||||
* use it when this function exits.
|
||||
*
|
||||
* The client is in omapi_protocol_connect, its driving thread.
|
||||
* It too has no events pending, so the connection will
|
||||
* be freed.
|
||||
*/
|
||||
omapi_connection_disconnect(h->outer, OMAPI_FORCE_DISCONNECT);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up a listener for the omapi protocol.
|
||||
*/
|
||||
isc_result_t
|
||||
omapi_protocol_listen(omapi_object_t *manager, isc_sockaddr_t *addr,
|
||||
isc_boolean_t ((*verify_connection)
|
||||
(isc_sockaddr_t *incoming,
|
||||
void *connect_arg)),
|
||||
isc_boolean_t ((*verify_key)
|
||||
(const char *name,
|
||||
unsigned int algorithm,
|
||||
void *key_arg)),
|
||||
isc_taskaction_t destroy_action, void *arg)
|
||||
{
|
||||
return (omapi_listener_listen(manager, addr, verify_connection,
|
||||
verify_key, destroy_action, arg));
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
send_status(omapi_object_t *po, isc_result_t waitstatus,
|
||||
unsigned int rid, const char *msg)
|
||||
{
|
||||
isc_result_t result;
|
||||
omapi_object_t *message = NULL;
|
||||
|
||||
REQUIRE(po != NULL && po->type == omapi_type_protocol);
|
||||
REQUIRE(po->outer != NULL && po->outer->type == omapi_type_connection);
|
||||
REQUIRE(! ((omapi_connection_t *)po->outer)->is_client);
|
||||
|
||||
result = omapi_message_create(&message);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (result);
|
||||
|
||||
result = omapi_object_setinteger(message, "op", OMAPI_OP_STATUS);
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
result = omapi_object_setinteger(message, "rid", (int)rid);
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
result = omapi_object_setinteger(message, "result",
|
||||
(int)waitstatus);
|
||||
|
||||
/*
|
||||
* If a message has been provided, send it.
|
||||
*/
|
||||
if (result == ISC_R_SUCCESS && msg != NULL)
|
||||
result = omapi_object_setstring(message, "message", msg);
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
result = omapi_message_send(message, po);
|
||||
|
||||
OBJECT_DEREF(&message);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
send_update(omapi_object_t *po, unsigned int rid, omapi_object_t *object) {
|
||||
isc_result_t result;
|
||||
omapi_object_t *message = NULL;
|
||||
|
||||
REQUIRE(po != NULL && po->type == omapi_type_protocol);
|
||||
REQUIRE(! ((omapi_connection_t *)po->outer)->is_client);
|
||||
|
||||
result = omapi_message_create(&message);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (result);
|
||||
|
||||
result = omapi_object_setinteger(message, "op", OMAPI_OP_UPDATE);
|
||||
|
||||
if (result == ISC_R_SUCCESS && rid != 0) {
|
||||
omapi_handle_t handle;
|
||||
|
||||
result = omapi_object_setinteger(message, "rid", (int)rid);
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
result = object_gethandle(&handle, object);
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
result = omapi_object_setinteger(message, "handle",
|
||||
(int)handle);
|
||||
}
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
result = omapi_object_setobject(message, "object", object);
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
result = omapi_message_send(message, po);
|
||||
|
||||
OBJECT_DEREF(&message);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
dispatch_messages(omapi_protocol_t *protocol,
|
||||
omapi_connection_t *connection)
|
||||
{
|
||||
isc_uint16_t nlen;
|
||||
isc_uint32_t vlen;
|
||||
isc_result_t result;
|
||||
|
||||
/*
|
||||
* XXXDCL figure out how come when this function throws
|
||||
* an error, it does not seem to be seen by the driving program.
|
||||
* (this comment may no longer be true, but bears testing anyway)
|
||||
*/
|
||||
|
||||
/*
|
||||
* We get here because we requested that we be woken up after
|
||||
* some number of bytes were read, and that number of bytes
|
||||
* has in fact been read.
|
||||
*/
|
||||
switch (protocol->state) {
|
||||
case omapi_protocol_intro_wait:
|
||||
/*
|
||||
* Get protocol version and header size in network byte order.
|
||||
*/
|
||||
connection_getuint32(connection, &protocol->protocol_version);
|
||||
connection_getuint32(connection, &protocol->header_size);
|
||||
|
||||
/*
|
||||
* Currently only the current protocol version is supported.
|
||||
*/
|
||||
if (protocol->protocol_version != OMAPI_PROTOCOL_VERSION)
|
||||
return (OMAPI_R_VERSIONMISMATCH);
|
||||
|
||||
if (protocol->header_size < sizeof(omapi_protocolheader_t))
|
||||
return (OMAPI_R_PROTOCOLERROR);
|
||||
|
||||
/*
|
||||
* The next thing that shows up on incoming connections
|
||||
* should be a message header.
|
||||
*/
|
||||
protocol->state = omapi_protocol_header_wait;
|
||||
|
||||
/*
|
||||
* The client needs to have bytes_needed primed for the
|
||||
* size of a message header, so that when send_done runs,
|
||||
* it can kick off an isc_socket_recv (via connection_require)
|
||||
* to get the server's response. It does this in
|
||||
* omapi_message_send, so nothing need be done here now.
|
||||
*
|
||||
* The server needs to actually kick off its recv now to
|
||||
* be ready for the first message from the client. The
|
||||
* server's startup path looks like this:
|
||||
* 1 server sends intro, bytes_needed is set to intro size (8).
|
||||
* 2 send_done posts, recv of 8 for intro is queued.
|
||||
* 3 recv_done posts, calls the protocol_signalhandler and
|
||||
* ends up here.
|
||||
*/
|
||||
if (connection->is_client) {
|
||||
result = OMAPI_R_NOTYET;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register a need for the number of bytes in a header, and if
|
||||
* that many are here already, process them immediately.
|
||||
*/
|
||||
result = connection_require(connection, protocol->header_size);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
break;
|
||||
|
||||
/* FALLTHROUGH */
|
||||
|
||||
case omapi_protocol_header_wait:
|
||||
result = omapi_message_create((omapi_object_t **)
|
||||
&protocol->message);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
break;
|
||||
|
||||
if (protocol->key != NULL) {
|
||||
isc_hmacmd5_init(&protocol->hmacctx,
|
||||
protocol->key->base,
|
||||
protocol->key->length);
|
||||
protocol->verify_result = ISC_R_SUCCESS;
|
||||
protocol->auth_update = ISC_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fetch the header values.
|
||||
*/
|
||||
/* XXXDCL authid is unused */
|
||||
connection_getuint32(connection, &protocol->message->authid);
|
||||
/* XXXTL bind the authenticator here! */
|
||||
connection_getuint32(connection, &protocol->message->authlen);
|
||||
connection_getuint32(connection, &protocol->message->op);
|
||||
connection_getuint32(connection, &protocol->message->h);
|
||||
connection_getuint32(connection, &protocol->message->id);
|
||||
connection_getuint32(connection, &protocol->message->rid);
|
||||
|
||||
/*
|
||||
* If there was any extra header data, skip over it,
|
||||
* because it has no use in this version of the protocol.
|
||||
*/
|
||||
if (protocol->header_size > sizeof(omapi_protocolheader_t))
|
||||
connection_copyout(NULL, connection,
|
||||
(protocol->header_size -
|
||||
sizeof(omapi_protocolheader_t)));
|
||||
|
||||
/*
|
||||
* XXXTL must compute partial signature across the preceding
|
||||
* bytes. Also, if authenticator specifies encryption as well
|
||||
* as signing, we may have to decrypt the data on the way in.
|
||||
*/
|
||||
|
||||
/*
|
||||
* After reading the header, first read in message-specific
|
||||
* values, then object values.
|
||||
*/
|
||||
protocol->reading_message_values = ISC_TRUE;
|
||||
|
||||
need_name_length:
|
||||
/*
|
||||
* Need to get the 16-bit length of the value's name.
|
||||
*/
|
||||
protocol->state = omapi_protocol_name_length_wait;
|
||||
result = connection_require(connection, 2);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
break;
|
||||
|
||||
/* FALLTHROUGH */
|
||||
case omapi_protocol_name_length_wait:
|
||||
connection_getuint16(connection, &nlen);
|
||||
|
||||
/*
|
||||
* A zero-length name signals the end of name+value pairs.
|
||||
*/
|
||||
if (nlen == 0) {
|
||||
/*
|
||||
* If the message values were being read, now
|
||||
* the object values need to be read. Otherwise
|
||||
* move on to reading the authenticator.
|
||||
*/
|
||||
if (protocol->reading_message_values) {
|
||||
protocol->reading_message_values = ISC_FALSE;
|
||||
/*
|
||||
* The goto could be removed by setting the
|
||||
* state and doing omapi_connection_require()
|
||||
* here, then returning the result to
|
||||
* protocol_signalhandler which would call
|
||||
* this function immediately if the result
|
||||
* was ISC_R_SUCCESS, but that seems even
|
||||
* more obtuse than using goto.
|
||||
*/
|
||||
goto need_name_length;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the authenticator length is zero, there's no
|
||||
* signature to read in, so go straight to processing
|
||||
* the message.
|
||||
*/
|
||||
if (protocol->message->authlen == 0)
|
||||
goto message_done;
|
||||
|
||||
/*
|
||||
* The next thing that is expected is the message
|
||||
* signature.
|
||||
*/
|
||||
protocol->state = omapi_protocol_signature_wait;
|
||||
|
||||
/* Wait for the number of bytes specified for the
|
||||
* authenticator. If they are all here, go read it in.
|
||||
* As noted above, the goto could be removed by
|
||||
* returning the result to the caller no matter
|
||||
* what its value, because the protocol_signalhandler
|
||||
* would just call this function right back, but
|
||||
* something seems more obtuse about that than goto.
|
||||
*/
|
||||
result = connection_require(connection,
|
||||
protocol->message->authlen);
|
||||
if (result == ISC_R_SUCCESS)
|
||||
goto signature_wait;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Non-zero name length. Allocate a buffer for the name
|
||||
* then wait for all its bytes to be available.
|
||||
*/
|
||||
result = omapi_string_create(&protocol->name, nlen);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
break;
|
||||
|
||||
protocol->state = omapi_protocol_name_wait;
|
||||
result = connection_require(connection, nlen);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
break;
|
||||
|
||||
/* FALLTHROUGH */
|
||||
case omapi_protocol_name_wait:
|
||||
connection_copyout(protocol->name->value, connection,
|
||||
protocol->name->len);
|
||||
|
||||
/*
|
||||
* Wait for the 32-bit length of the value.
|
||||
*/
|
||||
protocol->state = omapi_protocol_value_length_wait;
|
||||
result = connection_require(connection, 4);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
break;
|
||||
|
||||
/* FALLTHROUGH */
|
||||
case omapi_protocol_value_length_wait:
|
||||
connection_getuint32(connection, &vlen);
|
||||
|
||||
/*
|
||||
* Zero-length values are allowed; they are for deleted
|
||||
* values. If the value length is zero, skip the read but
|
||||
* still store the name with its zero length value.
|
||||
*/
|
||||
if (vlen == 0)
|
||||
goto insert_new_value;
|
||||
|
||||
result = omapi_data_create(&protocol->value,
|
||||
omapi_datatype_data, vlen);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Check to see if all the bytes of the value are here.
|
||||
*/
|
||||
protocol->state = omapi_protocol_value_wait;
|
||||
result = connection_require(connection, vlen);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
break;
|
||||
|
||||
/* FALLTHROUGH */
|
||||
case omapi_protocol_value_wait:
|
||||
connection_copyout(protocol->value->u.buffer.value,
|
||||
connection,
|
||||
protocol->value->u.buffer.len);
|
||||
|
||||
/*
|
||||
* Silence the gcc message "warning: `result' might be used
|
||||
* uninitialized in this function"
|
||||
*/
|
||||
result = ISC_R_SUCCESS;
|
||||
|
||||
insert_new_value:
|
||||
|
||||
if (protocol->reading_message_values)
|
||||
result = omapi_object_set((omapi_object_t *)
|
||||
protocol->message,
|
||||
protocol->name,
|
||||
protocol->value);
|
||||
|
||||
else {
|
||||
if (protocol->message->object == NULL) {
|
||||
/*
|
||||
* Create a generic object to receive the
|
||||
* values of the object in the incoming
|
||||
* message.
|
||||
*/
|
||||
result = omapi_object_create(&protocol->
|
||||
message->object,
|
||||
NULL, 0);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
break;
|
||||
}
|
||||
|
||||
result = omapi_object_set((omapi_object_t *)
|
||||
protocol->message->object,
|
||||
protocol->name,
|
||||
protocol->value);
|
||||
}
|
||||
if (result != ISC_R_SUCCESS)
|
||||
break;
|
||||
|
||||
omapi_string_dereference(&protocol->name);
|
||||
if (protocol->value != NULL)
|
||||
omapi_data_dereference(&protocol->value);
|
||||
|
||||
goto need_name_length;
|
||||
|
||||
signature_wait:
|
||||
case omapi_protocol_signature_wait:
|
||||
result = omapi_data_create(&protocol->message->authenticator,
|
||||
omapi_datatype_data,
|
||||
protocol->message->authlen);
|
||||
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (result);
|
||||
|
||||
/*
|
||||
* Turn off the dst_verify updating while the signature
|
||||
* bytes are copied; they are not part of what was signed.
|
||||
*/
|
||||
protocol->auth_update = ISC_FALSE;
|
||||
|
||||
connection_copyout(protocol->message->authenticator->
|
||||
u.buffer.value,
|
||||
connection,
|
||||
protocol->message->authlen);
|
||||
|
||||
protocol->signature_in.base =
|
||||
protocol->message->authenticator->u.buffer.value;
|
||||
protocol->signature_in.length = protocol->message->authlen;
|
||||
|
||||
/* XXXTL now do something to verify the signature. */
|
||||
|
||||
/* FALLTHROUGH */
|
||||
message_done:
|
||||
/*
|
||||
* Hail, hail, the gang's all here! The whole message
|
||||
* has been read in, so process it. Even if an error
|
||||
* is returned, a bit of cleanup has to be done, but
|
||||
* it can't muck with the result assigned here.
|
||||
*/
|
||||
result = message_process((omapi_object_t *)protocol->message,
|
||||
(omapi_object_t *)protocol);
|
||||
|
||||
/* XXXTL unbind the authenticator. */
|
||||
|
||||
/*
|
||||
* Free the message object.
|
||||
*/
|
||||
OBJECT_DEREF(&protocol->message);
|
||||
|
||||
/*
|
||||
* The next thing the protocol reads will be a new message.
|
||||
*/
|
||||
protocol->state = omapi_protocol_header_wait;
|
||||
|
||||
/*
|
||||
* Now, if message_process had indicated an error, let it be
|
||||
* returned from here.
|
||||
*/
|
||||
if (result != ISC_R_SUCCESS)
|
||||
break;
|
||||
|
||||
/*
|
||||
* The next recv will be queued from send_done. On the
|
||||
* server, this will be after it has sent its reply to the
|
||||
* just-processed message by using omapi_message_send.
|
||||
* On the client it will happen after it sends its
|
||||
* next message with omapi_message_send.
|
||||
*
|
||||
* The OMAPI_R_NOTYET return value tells protocol_signalhandler
|
||||
* that to return ISC_R_SUCCESS back to recv_done.
|
||||
*/
|
||||
result = OMAPI_R_NOTYET;
|
||||
break;
|
||||
|
||||
default:
|
||||
UNEXPECTED_ERROR(__FILE__, __LINE__, "unknown state in "
|
||||
"omapi_protocol_signal_handler: %d",
|
||||
protocol->state);
|
||||
result = ISC_R_UNEXPECTED;
|
||||
break;
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
protocol_signalhandler(omapi_object_t *h, const char *name, va_list ap) {
|
||||
isc_result_t result;
|
||||
omapi_protocol_t *p;
|
||||
omapi_connection_t *c;
|
||||
|
||||
REQUIRE(h != NULL && h->type == omapi_type_protocol);
|
||||
|
||||
p = (omapi_protocol_t *)h;
|
||||
c = (omapi_connection_t *)p->outer;
|
||||
|
||||
/*
|
||||
* Not a signal we recognize?
|
||||
*/
|
||||
if (strcmp(name, "ready") != 0)
|
||||
return (omapi_object_passsignal(h, name, ap));
|
||||
|
||||
INSIST(p->outer != NULL && p->outer->type == omapi_type_connection);
|
||||
|
||||
do {
|
||||
result = dispatch_messages(p, c);
|
||||
} while (result == ISC_R_SUCCESS);
|
||||
|
||||
/*
|
||||
* Getting "not yet" means more data is needed before another message
|
||||
* can be processed.
|
||||
*/
|
||||
if (result == OMAPI_R_NOTYET)
|
||||
result = ISC_R_SUCCESS;
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
protocol_setvalue(omapi_object_t *h, omapi_string_t *name, omapi_data_t *value)
|
||||
{
|
||||
omapi_protocol_t *p;
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
|
||||
REQUIRE(h != NULL && h->type == omapi_type_protocol);
|
||||
|
||||
p = (omapi_protocol_t *)h;
|
||||
|
||||
if (omapi_string_strcmp(name, "auth-name") == 0) {
|
||||
p->authname = omapi_data_strdup(omapi_mctx, value);
|
||||
if (p->authname == NULL)
|
||||
return (ISC_R_NOMEMORY);
|
||||
|
||||
} else if (omapi_string_strcmp(name, "auth-algorithm") == 0) {
|
||||
p->algorithm = omapi_data_getint(value);
|
||||
if (p->algorithm == 0)
|
||||
/*
|
||||
* XXXDCL better error?
|
||||
*/
|
||||
return (ISC_R_NOTIMPLEMENTED);
|
||||
|
||||
} else
|
||||
return (omapi_object_passsetvalue(h, name, value));
|
||||
|
||||
/*
|
||||
* XXXDCL if either auth-name or auth-algorithm is not in the incoming
|
||||
* message, then the client will not get a meaningful error message
|
||||
* in reply. this is bad.
|
||||
*
|
||||
* ... it is a general problem in the current omapi design ...
|
||||
*/
|
||||
if (p->authname != NULL && p->algorithm != 0) {
|
||||
/*
|
||||
* Verifying the key through a callback is (currently) only
|
||||
* done by the server.
|
||||
* XXXDCL the client should have some way of checking whether
|
||||
* what is being set is what it asked for.
|
||||
*/
|
||||
if (p->verify_key != NULL &&
|
||||
!p->verify_key(p->authname, p->algorithm,
|
||||
p->verify_key_arg))
|
||||
return (ISC_R_NOPERM);
|
||||
|
||||
if (p->key != NULL) {
|
||||
isc_mem_put(omapi_mctx, p->key, sizeof(isc_region_t));
|
||||
p->key = NULL;
|
||||
}
|
||||
|
||||
result = auth_makekey(p->authname, p->algorithm, &p->key);
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
result = isc_buffer_allocate(omapi_mctx,
|
||||
&p->signature_out,
|
||||
ISC_MD5_DIGESTLENGTH);
|
||||
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
if (p->key != NULL) {
|
||||
isc_mem_put(omapi_mctx, p->key,
|
||||
sizeof(isc_region_t));
|
||||
p->key = NULL;
|
||||
}
|
||||
isc_mem_free(omapi_mctx, p->authname);
|
||||
p->authname = NULL;
|
||||
p->algorithm = 0;
|
||||
p->key = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
protocol_getvalue(omapi_object_t *h, omapi_string_t *name,
|
||||
omapi_value_t **value)
|
||||
{
|
||||
REQUIRE(h != NULL && h->type == omapi_type_protocol);
|
||||
|
||||
return (omapi_object_passgetvalue(h, name, value));
|
||||
}
|
||||
|
||||
static void
|
||||
protocol_destroy(omapi_object_t *h) {
|
||||
omapi_protocol_t *p;
|
||||
|
||||
REQUIRE(h != NULL && h->type == omapi_type_protocol);
|
||||
|
||||
p = (omapi_protocol_t *)h;
|
||||
|
||||
if (p->message != NULL)
|
||||
OBJECT_DEREF(&p->message);
|
||||
|
||||
if (p->authinfo != NULL)
|
||||
OBJECT_DEREF(&p->authinfo);
|
||||
|
||||
if (p->authname != NULL) {
|
||||
isc_mem_free(omapi_mctx, p->authname);
|
||||
p->authname = NULL;
|
||||
}
|
||||
|
||||
if (p->signature_out != NULL) {
|
||||
isc_buffer_free(&p->signature_out);
|
||||
p->signature_out = NULL;
|
||||
}
|
||||
|
||||
if (p->key != NULL) {
|
||||
isc_mem_put(omapi_mctx, p->key, sizeof(isc_region_t));
|
||||
p->key = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
protocol_stuffvalues(omapi_object_t *connection, omapi_object_t *h) {
|
||||
REQUIRE(h != NULL && h->type == omapi_type_protocol);
|
||||
|
||||
return (omapi_object_passstuffvalues(connection, h));
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
protocol_init(void) {
|
||||
return (omapi_object_register(&omapi_type_protocol, "protocol",
|
||||
protocol_setvalue,
|
||||
protocol_getvalue,
|
||||
protocol_destroy,
|
||||
protocol_signalhandler,
|
||||
protocol_stuffvalues,
|
||||
NULL, NULL, NULL));
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1999-2001 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: result.c,v 1.11 2001/01/09 22:00:10 bwelling Exp $ */
|
||||
#include <config.h>
|
||||
|
||||
#include <isc/once.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <omapi/result.h>
|
||||
#include <omapi/lib.h>
|
||||
|
||||
static const char *text[OMAPI_R_NRESULTS] = {
|
||||
"data not yet available", /* 0 */
|
||||
"not connected", /* 1 */
|
||||
"no key specified", /* 2 */
|
||||
"invalid argument", /* 3 */
|
||||
"protocol version mismatch", /* 4 */
|
||||
"protocol error", /* 5 */
|
||||
};
|
||||
|
||||
|
||||
#define OMAPI_RESULT_RESULTSET 2
|
||||
|
||||
static isc_once_t once = ISC_ONCE_INIT;
|
||||
|
||||
static void
|
||||
initialize_action(void) {
|
||||
isc_result_t result;
|
||||
|
||||
result = isc_result_register(ISC_RESULTCLASS_OMAPI, OMAPI_R_NRESULTS,
|
||||
text, omapi_msgcat,
|
||||
OMAPI_RESULT_RESULTSET);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
UNEXPECTED_ERROR(__FILE__, __LINE__,
|
||||
"isc_result_register() failed: %u", result);
|
||||
}
|
||||
|
||||
static void
|
||||
initialize(void) {
|
||||
omapi_lib_initmsgcat();
|
||||
RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
const char *
|
||||
omapi_result_totext(isc_result_t result) {
|
||||
initialize();
|
||||
|
||||
return (isc_result_totext(result));
|
||||
}
|
||||
|
||||
void
|
||||
omapi_result_register(void) {
|
||||
initialize();
|
||||
}
|
@ -1,115 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1996-2001 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: string.c,v 1.10 2001/01/09 22:00:12 bwelling Exp $ */
|
||||
|
||||
/* Principal Author: Ted Lemon */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <isc/mem.h>
|
||||
#include <isc/string.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <omapi/private.h>
|
||||
|
||||
isc_result_t
|
||||
omapi_string_create(omapi_string_t **d, unsigned int len) {
|
||||
omapi_string_t *new;
|
||||
|
||||
new = isc_mem_get(omapi_mctx, OMAPI_STRING_EMPTY_SIZE + len);
|
||||
if (new == NULL)
|
||||
return (ISC_R_NOMEMORY);
|
||||
memset(new, 0, OMAPI_STRING_EMPTY_SIZE);
|
||||
new->len = len;
|
||||
|
||||
omapi_string_reference(d, new);
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
void
|
||||
omapi_string_reference(omapi_string_t **r, omapi_string_t *h) {
|
||||
REQUIRE(r != NULL && h != NULL);
|
||||
REQUIRE(*r == NULL);
|
||||
|
||||
*r = h;
|
||||
h->refcnt++;
|
||||
}
|
||||
|
||||
void
|
||||
omapi_string_dereference(omapi_string_t **h) {
|
||||
REQUIRE(h != NULL && *h != NULL);
|
||||
REQUIRE((*h)->refcnt > 0);
|
||||
|
||||
if (--((*h)->refcnt) <= 0)
|
||||
isc_mem_put(omapi_mctx, *h,
|
||||
OMAPI_STRING_EMPTY_SIZE + (*h)->len);
|
||||
|
||||
*h = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
omapi_string_totext(omapi_string_t *string, isc_region_t *region) {
|
||||
REQUIRE(string != NULL && region != NULL);
|
||||
|
||||
region->base = string->value;
|
||||
region->length = string->len;
|
||||
}
|
||||
|
||||
int
|
||||
omapi_string_stringcmp(omapi_string_t *s1, omapi_string_t *s2) {
|
||||
unsigned int len;
|
||||
int order;
|
||||
|
||||
if (s1->len > s2->len)
|
||||
len = s2->len;
|
||||
else
|
||||
len = s1->len;
|
||||
|
||||
order = memcmp(s1->value, s2->value, len);
|
||||
if (order == 0) {
|
||||
if (s1->len > s2->len)
|
||||
order = 1;
|
||||
else if (s1->len < s2->len)
|
||||
order = -1;
|
||||
}
|
||||
|
||||
return (order);
|
||||
}
|
||||
|
||||
int
|
||||
omapi_string_strcmp(omapi_string_t *s1, const char *s2) {
|
||||
unsigned int len, slen;
|
||||
int order;
|
||||
|
||||
slen = strlen(s2);
|
||||
if (slen > s1->len)
|
||||
len = s1->len;
|
||||
else
|
||||
len = slen;
|
||||
|
||||
order = memcmp(s1->value, s2, len);
|
||||
if (order == 0) {
|
||||
if (s1->len > slen)
|
||||
order = 1;
|
||||
else if (s1->len < slen)
|
||||
order= -1;
|
||||
}
|
||||
|
||||
return (order);
|
||||
}
|
@ -1,209 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1996-2001 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: value.c,v 1.11 2001/01/09 22:00:15 bwelling Exp $ */
|
||||
|
||||
/* Principal Author: Ted Lemon */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <isc/mem.h>
|
||||
#include <isc/string.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <omapi/private.h>
|
||||
|
||||
isc_result_t
|
||||
omapi_value_create(omapi_value_t **d) {
|
||||
omapi_value_t *new;
|
||||
|
||||
new = isc_mem_get(omapi_mctx, sizeof(*new));
|
||||
if (new == NULL)
|
||||
return (ISC_R_NOMEMORY);
|
||||
memset(new, 0, sizeof *new);
|
||||
|
||||
omapi_value_reference(d, new);
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
void
|
||||
omapi_value_reference(omapi_value_t **r, omapi_value_t *h) {
|
||||
REQUIRE(r != NULL && h != NULL);
|
||||
REQUIRE(*r == NULL);
|
||||
|
||||
*r = h;
|
||||
h->refcnt++;
|
||||
}
|
||||
|
||||
void
|
||||
omapi_value_dereference(omapi_value_t **h) {
|
||||
REQUIRE(h != NULL && *h != NULL);
|
||||
REQUIRE((*h)->refcnt > 0);
|
||||
|
||||
if (--((*h)->refcnt) <= 0) {
|
||||
if ((*h)->name != NULL)
|
||||
omapi_string_dereference(&(*h)->name);
|
||||
if ((*h)->value != NULL)
|
||||
omapi_data_dereference(&(*h)->value);
|
||||
isc_mem_put(omapi_mctx, *h, sizeof(omapi_value_t));
|
||||
}
|
||||
*h = NULL;
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
omapi_value_storedata(omapi_value_t **vp, omapi_string_t *name,
|
||||
omapi_data_t *value)
|
||||
{
|
||||
isc_result_t result;
|
||||
|
||||
result = omapi_value_create(vp);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (result);
|
||||
|
||||
omapi_string_reference(&(*vp)->name, name);
|
||||
|
||||
if (value != NULL)
|
||||
omapi_data_reference(&(*vp)->value, value);
|
||||
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
omapi_value_storemem(omapi_value_t **vp, omapi_string_t *name,
|
||||
const unsigned char *value, unsigned int len)
|
||||
{
|
||||
isc_result_t result;
|
||||
|
||||
result = omapi_value_create(vp);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (result);
|
||||
|
||||
omapi_string_reference(&(*vp)->name, name);
|
||||
|
||||
if (value != NULL) {
|
||||
result = omapi_data_create(&(*vp)->value,
|
||||
omapi_datatype_data, len);
|
||||
if (result == ISC_R_SUCCESS)
|
||||
memcpy((*vp)->value->u.buffer.value, value, len);
|
||||
}
|
||||
|
||||
if (result != ISC_R_SUCCESS)
|
||||
omapi_value_dereference(vp);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
omapi_value_storeint(omapi_value_t **vp, omapi_string_t *name, int value) {
|
||||
isc_result_t result;
|
||||
|
||||
result = omapi_value_create(vp);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (result);
|
||||
|
||||
omapi_string_reference(&(*vp)->name, name);
|
||||
|
||||
result = omapi_data_create(&(*vp)->value, omapi_datatype_int);
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
(*vp)->value->u.integer = value;
|
||||
|
||||
if (result != ISC_R_SUCCESS)
|
||||
omapi_value_dereference(vp);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
omapi_value_storeobject(omapi_value_t **vp, omapi_string_t *name,
|
||||
omapi_object_t *value)
|
||||
{
|
||||
isc_result_t result;
|
||||
|
||||
result = omapi_value_create(vp);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (result);
|
||||
|
||||
omapi_string_reference(&(*vp)->name, name);
|
||||
|
||||
if (value != NULL) {
|
||||
result = omapi_data_create(&(*vp)->value, omapi_datatype_int);
|
||||
|
||||
if (result == ISC_R_SUCCESS)
|
||||
result = object_gethandle((omapi_handle_t *)
|
||||
&(*vp)->value->u.integer,
|
||||
value);
|
||||
}
|
||||
|
||||
if (result != ISC_R_SUCCESS)
|
||||
omapi_value_dereference(vp);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
omapi_value_storestr(omapi_value_t **vp, omapi_string_t *name, char *value)
|
||||
{
|
||||
isc_result_t result;
|
||||
|
||||
result = omapi_value_create(vp);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (result);
|
||||
|
||||
omapi_string_reference(&(*vp)->name, name);
|
||||
|
||||
if (value != NULL)
|
||||
result = omapi_data_create(&(*vp)->value,
|
||||
omapi_datatype_string, value);
|
||||
|
||||
if (result != ISC_R_SUCCESS)
|
||||
omapi_value_dereference(vp);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
int
|
||||
omapi_value_getint(omapi_value_t *value) {
|
||||
REQUIRE(value != NULL && value->value != NULL);
|
||||
REQUIRE(value->value->type == omapi_datatype_int ||
|
||||
((value->value->type == omapi_datatype_data ||
|
||||
(value->value->type == omapi_datatype_string)) &&
|
||||
value->value->u.buffer.len == sizeof(isc_uint32_t)));
|
||||
|
||||
return (omapi_data_getint(value->value));
|
||||
}
|
||||
|
||||
/*
|
||||
* WARNING: The region is valid only as long as the value pointer
|
||||
* is valid. See omapi.h.
|
||||
*/
|
||||
void
|
||||
omapi_value_getregion(omapi_value_t *value, isc_region_t *region) {
|
||||
REQUIRE(value != NULL && value->value != NULL);
|
||||
REQUIRE(value->value->type == omapi_datatype_data ||
|
||||
value->value->type == omapi_datatype_string);
|
||||
|
||||
/*
|
||||
* Boy, the word "value" appears a lot. Almost like a Smurf song.
|
||||
* La la la la la la, la la la la la.
|
||||
*/
|
||||
region->base = value->value->u.buffer.value;
|
||||
region->length = value->value->u.buffer.len;
|
||||
}
|
||||
|
@ -1,24 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1999-2001 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: version.c,v 1.6 2001/01/09 22:00:18 bwelling Exp $ */
|
||||
|
||||
char omapi_version[] = VERSION;
|
||||
|
||||
unsigned int omapi_libinterface = LIBINTERFACE;
|
||||
unsigned int omapi_librevision = LIBREVISION;
|
||||
unsigned int omapi_libage = LIBAGE;
|
@ -13,7 +13,7 @@
|
||||
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
||||
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
# $Id: includes.in,v 1.13 2001/03/27 00:44:57 bwelling Exp $
|
||||
# $Id: includes.in,v 1.14 2001/03/27 00:53:56 bwelling Exp $
|
||||
|
||||
# Search for machine-generated header files in the build tree,
|
||||
# and for normal headers in the source tree (${top_srcdir}).
|
||||
@ -37,9 +37,6 @@ DNS_INCLUDES = @BIND9_DNS_BUILDINCLUDE@ \
|
||||
-I${top_srcdir}/lib/dns/include \
|
||||
-I${top_srcdir}/lib/dns/sec/dst/include
|
||||
|
||||
OMAPI_INCLUDES = @BIND9_OMAPI_BUILDINCLUDE@ \
|
||||
-I${top_srcdir}/lib/omapi/include
|
||||
|
||||
LWRES_INCLUDES = @BIND9_LWRES_BUILDINCLUDE@ \
|
||||
-I${top_srcdir}/lib/lwres/include
|
||||
|
||||
|
@ -56,7 +56,6 @@
|
||||
./bin/named/include/named/lwsearch.h C 2000,2001
|
||||
./bin/named/include/named/main.h C 1999,2000,2001
|
||||
./bin/named/include/named/notify.h C 1999,2000,2001
|
||||
./bin/named/include/named/omapi.h C 2000,2001
|
||||
./bin/named/include/named/query.h C 1999,2000,2001
|
||||
./bin/named/include/named/server.h C 1999,2000,2001
|
||||
./bin/named/include/named/sortlist.h C 2000,2001
|
||||
@ -83,8 +82,6 @@
|
||||
./bin/named/main.c C 1999,2000,2001
|
||||
./bin/named/named.8 MAN 2000,2001
|
||||
./bin/named/notify.c C 1999,2000,2001
|
||||
./bin/named/omapi.c C 2000,2001
|
||||
./bin/named/omapiconf.c C 2000,2001
|
||||
./bin/named/query.c C 1999,2000,2001
|
||||
./bin/named/server.c C 1999,2000,2001
|
||||
./bin/named/sortlist.c C 2000,2001
|
||||
@ -293,7 +290,6 @@
|
||||
./bin/tests/net/sockaddr_multicast.c C 2000,2001
|
||||
./bin/tests/net/testsuite.h C 2000,2001
|
||||
./bin/tests/nxtify.c C 1999,2000,2001
|
||||
./bin/tests/omapi_test.c C 1996,1997,1998,1999,2000,2001
|
||||
./bin/tests/printmsg.c C 1998,1999,2000,2001
|
||||
./bin/tests/printmsg.h C 1998,1999,2000,2001
|
||||
./bin/tests/ratelimiter_test.c C 1999,2000,2001
|
||||
@ -809,7 +805,6 @@
|
||||
./doc/design/logging TXT.BRIEF 1999,2000,2001
|
||||
./doc/design/lwres TXT.BRIEF 2000,2001
|
||||
./doc/design/ncache TXT.BRIEF 1999,2000,2001
|
||||
./doc/design/omapi TXT.BRIEF 1999,2000,2001
|
||||
./doc/design/rdataset TXT.BRIEF 1999,2000,2001
|
||||
./doc/design/red-black TXT.BRIEF 1999,2000,2001
|
||||
./doc/design/resolver TXT.BRIEF 1999,2000,2001
|
||||
@ -1461,33 +1456,6 @@
|
||||
./lib/lwres/man/lwres_string_parse.3 MAN 2000,2001
|
||||
./lib/lwres/man/resolver.5 MAN 2000,2001
|
||||
./lib/lwres/version.c C 2000,2001
|
||||
./lib/omapi/.cvsignore X 1999,2000,2001
|
||||
./lib/omapi/Makefile.in MAKE 1999,2000,2001
|
||||
./lib/omapi/api X 1999,2000,2001
|
||||
./lib/omapi/auth.c C 2000,2001
|
||||
./lib/omapi/connection.c C 1996,1997,1998,1999,2000,2001
|
||||
./lib/omapi/data.c C 1996,1997,1998,1999,2000,2001
|
||||
./lib/omapi/generic.c C 1996,1997,1998,1999,2000,2001
|
||||
./lib/omapi/handle.c C 1996,1997,1998,1999,2000,2001
|
||||
./lib/omapi/include/.cvsignore X 1999,2000,2001
|
||||
./lib/omapi/include/Makefile.in MAKE 1999,2000,2001
|
||||
./lib/omapi/include/omapi/.cvsignore X 1999,2000,2001
|
||||
./lib/omapi/include/omapi/Makefile.in MAKE 1999,2000,2001
|
||||
./lib/omapi/include/omapi/compatibility.h C 2000,2001
|
||||
./lib/omapi/include/omapi/lib.h C 1999,2000,2001
|
||||
./lib/omapi/include/omapi/omapi.h C 1996,1997,1998,1999,2000,2001
|
||||
./lib/omapi/include/omapi/private.h C 1996,1997,1998,1999,2000,2001
|
||||
./lib/omapi/include/omapi/result.h C 1999,2000,2001
|
||||
./lib/omapi/include/omapi/types.h C 1996,1997,1998,1999,2000,2001
|
||||
./lib/omapi/lib.c C 1999,2000,2001
|
||||
./lib/omapi/listener.c C 1996,1997,1998,1999,2000,2001
|
||||
./lib/omapi/message.c C 1996,1997,1998,1999,2000,2001
|
||||
./lib/omapi/object.c C 1996,1997,1998,1999,2000,2001
|
||||
./lib/omapi/protocol.c C 1996,1997,1998,1999,2000,2001
|
||||
./lib/omapi/result.c C 1999,2000,2001
|
||||
./lib/omapi/string.c C 1996,1997,1998,1999,2000,2001
|
||||
./lib/omapi/value.c C 1996,1997,1998,1999,2000,2001
|
||||
./lib/omapi/version.c C 1999,2000,2001
|
||||
./lib/tests/.cvsignore X 1999,2000,2001
|
||||
./lib/tests/Makefile.in MAKE 1998,1999,2000,2001
|
||||
./lib/tests/include/.cvsignore X 1999,2000,2001
|
||||
|
Loading…
x
Reference in New Issue
Block a user