r21076: Two pieces of infrastructure from Samba4: An API-compatible messaging wrapper
authorVolker Lendecke <vlendec@samba.org>
Wed, 31 Jan 2007 12:01:52 +0000 (12:01 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:17:33 +0000 (12:17 -0500)
and tdb_wrap_open.

Volker

source/include/util_tdb.h
source/lib/messages.c
source/lib/util_tdb.c

index cb5d98fc5264e78552d33b49eaa040b4efaed1e7..a8def46e441e8d843ded0c8a06c1a2178a72b46a 100644 (file)
@@ -35,6 +35,11 @@ typedef struct keys_node
        TDB_DATA node_key;
 } TDB_LIST_NODE;
 
+struct tdb_wrap {
+       struct tdb_context *tdb;
+       const char *name;
+       struct tdb_wrap *next, *prev;
+};
 
 TDB_LIST_NODE *tdb_search_keys(struct tdb_context*, const char*);
 void tdb_search_list_free(TDB_LIST_NODE*);
index d2313734752e9155cf4c7b33d10ac700b9b2876c..f2d930e357d0d311aee5a72463d65a10887f7c3d 100644 (file)
@@ -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);
+               }
+       }
+}
+
+
 /** @} **/
index 4db39095a64ec2dc7d5a4e8a4867d83aa6bdd49d..b559f589dc53e801ff446fd752571504b7fe83c0 100644 (file)
@@ -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;
+}