123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 |
- /*
- * Copyright (C) 2009, 2013 Henning Westerholt
- * Copyright (C) 2013 Charles Chance, sipcentric.com
- *
- * This file is part of Kamailio, a free SIP server.
- *
- * Kamailio 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 2 of the License, or
- * (at your option) any later version
- *
- * Kamailio 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 <http://www.gnu.org/licenses/>.
- */
- /*!
- * \file
- * \brief memcached module
- */
- #include "memcached.h"
- #include "mcd_var.h"
- #include "../../sr_module.h"
- #include "../../mem/mem.h"
- #include "../../dprint.h"
- #include "../../ut.h"
- #include "../../str.h"
- MODULE_VERSION
- /*! server string */
- char* mcd_srv_str = "localhost:11211";
- /*! cache (default) expire time in seconds */
- unsigned int mcd_expire = 0;
- /*! cache storage mode, set or add */
- unsigned int mcd_mode = 0;
- /*! server timeout in ms*/
- unsigned int mcd_timeout = 5000;
- /*! Internal or system memory manager, default is system */
- unsigned int mcd_memory = 0;
- /*! stringify all values retrieved from memcached, default false */
- unsigned int mcd_stringify = 0;
- /*! memcached handle */
- struct memcached_st *memcached_h;
- /*! memcached server list */
- struct memcached_server_st *servers;
- static int mod_init(void);
- static void mod_destroy(void);
- /*!
- * Exported pseudo-variables
- */
- static pv_export_t mod_pvs[] = {
- { {"mct", sizeof("mct")-1}, PVT_OTHER, pv_get_mcd_value, pv_set_mcd_value,
- pv_parse_mcd_name, 0, 0, 0 },
- { {"mcinc", sizeof("mcinc")-1}, PVT_OTHER, pv_get_mcd_value, pv_inc_mcd_value,
- pv_parse_mcd_name, 0, 0, 0 },
- { {"mcdec", sizeof("mcdec")-1}, PVT_OTHER, pv_get_mcd_value, pv_dec_mcd_value,
- pv_parse_mcd_name, 0, 0, 0 },
- { {"mctex", sizeof("mctex")-1}, PVT_OTHER, pv_get_null, pv_set_mcd_expire,
- pv_parse_mcd_name, 0, 0, 0 },
- { {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
- };
- /*!
- * Exported parameters
- */
- static param_export_t params[] = {
- {"servers", PARAM_STRING, &mcd_srv_str },
- {"expire", INT_PARAM, &mcd_expire },
- {"timeout", INT_PARAM, &mcd_timeout },
- {"mode", INT_PARAM, &mcd_mode },
- {"memory", INT_PARAM, &mcd_memory },
- {"stringify", INT_PARAM, &mcd_stringify },
- {0, 0, 0}
- };
- /*!
- * Module interface
- */
- struct module_exports exports = {
- "memcached",
- DEFAULT_DLFLAGS,
- 0,
- params,
- 0,
- 0,
- mod_pvs,
- 0,
- mod_init,
- 0,
- mod_destroy,
- 0
- };
- /*!
- * \brief Wrapper functions around our internal memory management for libmemcached (version >= 0.38) callback
- * \param mem freed memory
- * \note pkg_free does not allow NULL pointer as standard free, therefore we check it here
- * \see pkg_free
- */
- static inline void mcd_free(memcached_st *ptr, void *mem, void *context) {
- if (mem)
- pkg_free(mem);
- }
- /*!
- * \brief Wrapper functions around our internal memory management for libmemcached (version < 0.38) callback
- * \param mem freed memory
- * \note pkg_free does not allow NULL pointer as standard free, therefore we check it here
- * \see pkg_free
- */
- static inline void mcd_free_compat(memcached_st *ptr, void *mem) {
- if (mem)
- pkg_free(mem);
- }
- /*!
- * \brief Wrapper functions around our internal memory management for libmemcached (version >= 0.38) callback
- * \param size allocated size
- * \return allocated memory, or NULL on failure
- * \see pkg_malloc
- */
- static inline void* mcd_malloc(memcached_st *ptr, const size_t size, void *context) {
- return pkg_malloc(size);
- }
- /*!
- * \brief Wrapper functions around our internal memory management for libmemcached (version < 0.38) callback
- * \param size allocated size
- * \return allocated memory, or NULL on failure
- * \see pkg_malloc
- */
- static inline void* mcd_malloc_compat(memcached_st *ptr, const size_t size) {
- return pkg_malloc(size);
- }
- /*!
- * \brief Wrapper functions around our internal memory management for libmemcached (version >= 0.38) callback
- * \param mem pointer to allocated memory
- * \param size new size of memory area
- * \return allocated memory, or NULL on failure
- * \see pkg_realloc
- */
- static inline void* mcd_realloc(memcached_st *ptr, void *mem, const size_t size, void *context) {
- return pkg_realloc(mem, size);
- }
- /*!
- * \brief Wrapper functions around our internal memory management for libmemcached (version < 0.38) callback
- * \param mem pointer to allocated memory
- * \param size new size of memory area
- * \return allocated memory, or NULL on failure
- * \see pkg_realloc
- */
- static inline void* mcd_realloc_compat(memcached_st *ptr, void *mem, const size_t size) {
- return pkg_realloc(mem, size);
- }
- /*!
- * \brief Wrapper functions around our internal memory management for libmemcached (version >= 0.38) callback
- * \param mem pointer to allocated memory
- * \param size new size of memory area
- * \return allocated memory, or NULL on failure
- * \see pkg_malloc
- * \todo this is not optimal, use internal calloc implemention which is not exported yet
- */
- static inline void * mcd_calloc(memcached_st *ptr, size_t nelem, const size_t elsize, void *context) {
- void* tmp = NULL;
- tmp = pkg_malloc(nelem * elsize);
- if (tmp != NULL) {
- memset(tmp, 0, nelem * elsize);
- }
- return tmp;
- }
- /*!
- * \brief Wrapper functions around our internal memory management for libmemcached (version < 0.38) callback
- * \param mem pointer to allocated memory
- * \param size new size of memory area
- * \return allocated memory, or NULL on failure
- * \see pkg_malloc
- * \todo this is not optimal, use internal calloc implemention which is not exported yet
- */
- static inline void * mcd_calloc_compat(memcached_st *ptr, size_t nelem, const size_t elsize) {
- void* tmp = NULL;
- tmp = pkg_malloc(nelem * elsize);
- if (tmp != NULL) {
- memset(tmp, 0, nelem * elsize);
- }
- return tmp;
- }
- /**
- * \brief Callback to check if we could connect successfully to a server
- * \param ptr memcached handler
- * \param server server instance
- * \param context context for callback
- * \return MEMCACHED_SUCCESS on success, MEMCACHED_CONNECTION_FAILURE on failure
- * \todo FIXME
- static inline memcached_server_fn mcd_check_connection(const memcached_st *ptr, memcached_server_instance_st my_server, void *context) {
- if (my_server->fd < 0) {
- return MEMCACHED_CONNECTION_FAILURE;
- }
- return MEMCACHED_SUCCESS;
- }
- */
- /*!
- * \brief Module initialization function
- * \return 0 on success, -1 on failure
- */
- static int mod_init(void) {
- char *server, *port;
- unsigned int len = 0;
- memcached_return rc;
- if ((port = strchr(mcd_srv_str, ':')) != NULL) {
- port = port + 1;
- len = strlen(mcd_srv_str) - strlen(port) - 1;
- } else {
- LM_DBG("no port definition, using default port\n");
- port = "11211";
- len = strlen(mcd_srv_str) ;
- }
- server = pkg_malloc(len);
- if (server == NULL) {
- PKG_MEM_ERROR;
- return -1;
- }
- strncpy(server, mcd_srv_str, len);
- server[len] = '\0';
- memcached_h = memcached_create(NULL);
- if (memcached_h == NULL) {
- LM_ERR("could not create memcached structure\n");
- return -1;
- }
- LM_DBG("allocated new server handle at %p", memcached_h);
- if (mcd_memory == 1) {
- LM_INFO("Use internal kamailio memory manager for memcached client library\n");
- #if LIBMEMCACHED_VERSION_HEX >= 0x00038000
- rc = memcached_set_memory_allocators(memcached_h, (memcached_malloc_fn)mcd_malloc,
- (memcached_free_fn)mcd_free, (memcached_realloc_fn)mcd_realloc,
- (memcached_calloc_fn)mcd_calloc, NULL);
- #else
- rc = memcached_set_memory_allocators(memcached_h, (memcached_malloc_function)mcd_malloc_compat,
- (memcached_free_function)mcd_free_compat, (memcached_realloc_function)mcd_realloc_compat,
- (memcached_calloc_function)mcd_calloc_compat);
- #endif
- if (rc == MEMCACHED_SUCCESS) {
- LM_DBG("memory manager callbacks set\n");
- } else {
- LM_ERR("memory manager callbacks not set, returned %s.\n", memcached_strerror(memcached_h, rc));
- return -1;
- }
- } else {
- LM_INFO("Use system memory manager for memcached client library\n");
- }
- servers = memcached_server_list_append(servers, server, atoi(port), &rc);
- if (memcached_behavior_set(memcached_h, MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT, mcd_timeout) != MEMCACHED_SUCCESS) {
- LM_ERR("could not set server connection timeout\n");
- return -1;
- }
- rc = memcached_server_push(memcached_h, servers);
- if (rc == MEMCACHED_SUCCESS) {
- LM_DBG("added server list to structure\n");
- } else {
- LM_ERR("attempt to add server list to structure returned %s.\n", memcached_strerror(memcached_h, rc));
- return -1;
- }
- pkg_free(server);
- /** \todo FIXME logic to handle connection errors on startup
- memcached_server_cursor(memcached_h, (const memcached_server_fn*) &mcd_check_connection, NULL, 1);
- */
- LM_INFO("libmemcached version is %s\n", memcached_lib_version());
- return 0;
- }
- /*!
- * \brief Module shutdown function
- */
- static void mod_destroy(void) {
- if (servers != NULL)
- memcached_server_list_free(servers);
- /* Crash on shutdown with internal memory manager, even if we disable the mm callbacks */
- if (mcd_memory != 1 && memcached_h != NULL)
- memcached_free(memcached_h);
- }
|