From 032bd8eea89ce24ab5fdd2eb6095b8416ebde558 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 31 Jan 2007 12:01:52 +0000 Subject: r21076: Two pieces of infrastructure from Samba4: An API-compatible messaging wrapper and tdb_wrap_open. Volker (This used to be commit c01f164dcaf88fb7f3bed8f69b210ba8fab326d1) --- source3/lib/messages.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++++ source3/lib/util_tdb.c | 98 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 219 insertions(+) (limited to 'source3/lib') diff --git a/source3/lib/messages.c b/source3/lib/messages.c index d231373475..f2d930e357 100644 --- a/source3/lib/messages.c +++ b/source3/lib/messages.c @@ -678,4 +678,125 @@ void message_unblock(void) { BlockSignals(False, SIGUSR1); } + +/* + * Samba4 API wrapper around the Samba3 implementation. Yes, I know, we could + * import the whole Samba4 thing, but I want notify.c from Samba4 in first. + */ + +struct messaging_callback { + struct messaging_callback *prev, *next; + uint32 msg_type; + void (*fn)(struct messaging_context *msg, void *private_data, + uint32_t msg_type, + struct server_id server_id, DATA_BLOB *data); + void *private_data; +}; + +struct messaging_context { + struct server_id id; + struct messaging_callback *callbacks; +}; + +static int messaging_context_destructor(struct messaging_context *ctx) +{ + struct messaging_callback *cb; + + for (cb = ctx->callbacks; cb; cb = cb->next) { + /* + * We unconditionally remove all instances of our callback + * from the tdb basis. + */ + message_deregister(cb->msg_type); + } + return 0; +} + +struct messaging_context *messaging_init(TALLOC_CTX *mem_ctx, + struct server_id server_id, + struct event_context *ev) +{ + struct messaging_context *ctx; + + if (!(ctx = TALLOC_ZERO_P(mem_ctx, struct messaging_context))) { + return NULL; + } + + ctx->id = server_id; + talloc_set_destructor(ctx, messaging_context_destructor); + return ctx; +} + +static void messaging_callback(int msg_type, struct process_id pid, + void *buf, size_t len, void *private_data) +{ + struct messaging_context *ctx = talloc_get_type_abort( + private_data, struct messaging_context); + struct messaging_callback *cb, *next; + + for (cb = ctx->callbacks; cb; cb = next) { + /* + * Allow a callback to remove itself + */ + next = cb->next; + + if (msg_type == cb->msg_type) { + DATA_BLOB blob; + struct server_id id; + + blob.data = (uint8 *)buf; + blob.length = len; + id.id = pid; + + cb->fn(ctx, cb->private_data, msg_type, id, &blob); + } + } +} + +/* + * Register a dispatch function for a particular message type. Allow multiple + * registrants +*/ +NTSTATUS messaging_register(struct messaging_context *ctx, void *private_data, + uint32_t msg_type, + void (*fn)(struct messaging_context *msg, + void *private_data, + uint32_t msg_type, + struct server_id server_id, + DATA_BLOB *data)) +{ + struct messaging_callback *cb; + + if (!(cb = talloc(ctx, struct messaging_callback))) { + return NT_STATUS_NO_MEMORY; + } + + cb->msg_type = msg_type; + cb->fn = fn; + cb->private_data = private_data; + + DLIST_ADD(ctx->callbacks, cb); + message_register(msg_type, messaging_callback, ctx); + return NT_STATUS_OK; +} + +/* + De-register the function for a particular message type. +*/ +void messaging_deregister(struct messaging_context *ctx, uint32_t msg_type, + void *private_data) +{ + struct messaging_callback *cb, *next; + + for (cb = ctx->callbacks; cb; cb = next) { + next = cb->next; + if ((cb->msg_type == msg_type) + && (cb->private_data == private_data)) { + DLIST_REMOVE(ctx->callbacks, cb); + TALLOC_FREE(cb); + } + } +} + + /** @} **/ diff --git a/source3/lib/util_tdb.c b/source3/lib/util_tdb.c index 4db39095a6..b559f589dc 100644 --- a/source3/lib/util_tdb.c +++ b/source3/lib/util_tdb.c @@ -846,3 +846,101 @@ int tdb_trans_delete(struct tdb_context *tdb, TDB_DATA key) return res; } + +/* + Log tdb messages via DEBUG(). +*/ +static void tdb_wrap_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, + const char *format, ...) PRINTF_ATTRIBUTE(3,4); + +static void tdb_wrap_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, + const char *format, ...) +{ + va_list ap; + char *ptr = NULL; + int debuglevel = 0; + + va_start(ap, format); + vasprintf(&ptr, format, ap); + va_end(ap); + + switch (level) { + case TDB_DEBUG_FATAL: + debug_level = 0; + break; + case TDB_DEBUG_ERROR: + debuglevel = 1; + break; + case TDB_DEBUG_WARNING: + debuglevel = 2; + break; + case TDB_DEBUG_TRACE: + debuglevel = 5; + break; + default: + debuglevel = 0; + } + + if (ptr != NULL) { + const char *name = tdb_name(tdb); + DEBUG(debuglevel, ("tdb(%s): %s", name ? name : "unnamed", ptr)); + free(ptr); + } +} + +static struct tdb_wrap *tdb_list; + +/* destroy the last connection to a tdb */ +static int tdb_wrap_destructor(struct tdb_wrap *w) +{ + tdb_close(w->tdb); + DLIST_REMOVE(tdb_list, w); + return 0; +} + +/* + wrapped connection to a tdb database + to close just talloc_free() the tdb_wrap pointer + */ +struct tdb_wrap *tdb_wrap_open(TALLOC_CTX *mem_ctx, + const char *name, int hash_size, int tdb_flags, + int open_flags, mode_t mode) +{ + struct tdb_wrap *w; + struct tdb_logging_context log_ctx; + log_ctx.log_fn = tdb_wrap_log; + + for (w=tdb_list;w;w=w->next) { + if (strcmp(name, w->name) == 0) { + /* + * Yes, talloc_reference is exactly what we want + * here. Otherwise we would have to implement our own + * reference counting. + */ + return talloc_reference(mem_ctx, w); + } + } + + w = talloc(mem_ctx, struct tdb_wrap); + if (w == NULL) { + return NULL; + } + + if (!(w->name = talloc_strdup(w, name))) { + talloc_free(w); + return NULL; + } + + w->tdb = tdb_open_ex(name, hash_size, tdb_flags, + open_flags, mode, &log_ctx, NULL); + if (w->tdb == NULL) { + talloc_free(w); + return NULL; + } + + talloc_set_destructor(w, tdb_wrap_destructor); + + DLIST_ADD(tdb_list, w); + + return w; +} -- cgit