/* Message handler database based on srvid Copyright (C) Amitay Isaacs 2015 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include "replace.h" #include "system/filesys.h" #include #include "lib/util/dlinklist.h" #include "common/db_hash.h" #include "common/srvid.h" struct srvid_handler_list; struct srvid_context { struct db_hash_context *dh; struct srvid_handler_list *list; }; struct srvid_handler { struct srvid_handler *prev, *next; struct srvid_handler_list *list; srvid_handler_fn handler; void *private_data; }; struct srvid_handler_list { struct srvid_handler_list *prev, *next; struct srvid_context *srv; uint64_t srvid; struct srvid_handler *h; }; /* * Initialise message srvid context and database */ int srvid_init(TALLOC_CTX *mem_ctx, struct srvid_context **result) { struct srvid_context *srv; int ret; srv = talloc_zero(mem_ctx, struct srvid_context); if (srv == NULL) { return ENOMEM; } ret = db_hash_init(srv, "messagedb", 8192, DB_HASH_SIMPLE, &srv->dh); if (ret != 0) { talloc_free(srv); return ret; } *result = srv; return 0; } /* * Wrapper functions to insert/delete/fetch srvid_hander_list */ static int srvid_insert(struct srvid_context *srv, uint64_t srvid, struct srvid_handler_list *list) { return db_hash_insert(srv->dh, (uint8_t *)&srvid, sizeof(uint64_t), (uint8_t *)&list, sizeof(list)); } static int srvid_delete(struct srvid_context *srv, uint64_t srvid) { return db_hash_delete(srv->dh, (uint8_t *)&srvid, sizeof(uint64_t)); } static int srvid_fetch_parser(uint8_t *keybuf, size_t keylen, uint8_t *databuf, size_t datalen, void *private_data) { struct srvid_handler_list **list = (struct srvid_handler_list **)private_data; if (datalen != sizeof(*list)) { return EIO; } *list = *(struct srvid_handler_list **)databuf; return 0; } static int srvid_fetch(struct srvid_context *srv, uint64_t srvid, struct srvid_handler_list **list) { return db_hash_fetch(srv->dh, (uint8_t *)&srvid, sizeof(uint64_t), srvid_fetch_parser, list); } /* * When a handler is freed, remove it from the list */ static int srvid_handler_destructor(struct srvid_handler *h) { struct srvid_handler_list *list = h->list; DLIST_REMOVE(list->h, h); if (list->h == NULL) { talloc_free(list); } return 0; } /* * When a list is freed, remove all handlers and remove db entry */ static int srvid_handler_list_destructor(struct srvid_handler_list *list) { struct srvid_handler *h; while (list->h != NULL) { h = list->h; DLIST_REMOVE(list->h, h); TALLOC_FREE(h); } srvid_delete(list->srv, list->srvid); DLIST_REMOVE(list->srv->list, list); return 0; } /* * Register a message handler */ int srvid_register(struct srvid_context *srv, TALLOC_CTX *mem_ctx, uint64_t srvid, srvid_handler_fn handler, void *private_data) { struct srvid_handler_list *list; struct srvid_handler *h; int ret; if (srv == NULL) { return EINVAL; } h = talloc_zero(mem_ctx, struct srvid_handler); if (h == NULL) { return ENOMEM; } h->handler = handler; h->private_data = private_data; ret = srvid_fetch(srv, srvid, &list); if (ret != 0) { /* srvid not yet registered */ list = talloc_zero(srv, struct srvid_handler_list); if (list == NULL) { talloc_free(h); return ENOMEM; } list->srv = srv; list->srvid = srvid; ret = srvid_insert(srv, srvid, list); if (ret != 0) { talloc_free(h); talloc_free(list); return ret; } DLIST_ADD(srv->list, list); talloc_set_destructor(list, srvid_handler_list_destructor); } h->list = list; DLIST_ADD(list->h, h); talloc_set_destructor(h, srvid_handler_destructor); return 0; } /* * Deregister a message handler */ int srvid_deregister(struct srvid_context *srv, uint64_t srvid, void *private_data) { struct srvid_handler_list *list; struct srvid_handler *h; int ret; ret = srvid_fetch(srv, srvid, &list); if (ret != 0) { return ret; } for (h = list->h; h != NULL; h = h->next) { if (h->private_data == private_data) { talloc_free(h); return 0; } } return ENOENT; } /* * Check if a message handler exists */ int srvid_exists(struct srvid_context *srv, uint64_t srvid, void *private_data) { struct srvid_handler_list *list; struct srvid_handler *h; int ret; ret = srvid_fetch(srv, srvid, &list); if (ret != 0) { return ret; } if (list->h == NULL) { return ENOENT; } if (private_data != NULL) { for (h = list->h; h != NULL; h = h->next) { if (h->private_data == private_data) { return 0; } } return ENOENT; } return 0; } /* * Send a message to registered srvid and srvid_all */ int srvid_dispatch(struct srvid_context *srv, uint64_t srvid, uint64_t srvid_all, TDB_DATA data) { struct srvid_handler_list *list; struct srvid_handler *h; int ret; ret = srvid_fetch(srv, srvid, &list); if (ret == 0) { for (h = list->h; h != NULL; h = h->next) { h->handler(srvid, data, h->private_data); } } if (srvid_all == 0) { return ret; } ret = srvid_fetch(srv, srvid_all, &list); if (ret == 0) { for (h = list->h; h != NULL; h = h->next) { h->handler(srvid, data, h->private_data); } } return ret; }