[Freeswitch-svn] [commit] r12871 - freeswitch/trunk/src/mod/applications/mod_memcache
FreeSWITCH SVN
rupa at freeswitch.org
Wed Apr 1 12:02:59 PDT 2009
Author: rupa
Date: Wed Apr 1 14:02:59 2009
New Revision: 12871
Log:
add API for memcached
have to run through valgrind still
Added:
freeswitch/trunk/src/mod/applications/mod_memcache/
freeswitch/trunk/src/mod/applications/mod_memcache/Makefile
freeswitch/trunk/src/mod/applications/mod_memcache/mod_memcache.c (contents, props changed)
Added: freeswitch/trunk/src/mod/applications/mod_memcache/Makefile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/applications/mod_memcache/Makefile Wed Apr 1 14:02:59 2009
@@ -0,0 +1,31 @@
+MEMCACHED=libmemcached-0.27
+switch_srcdir=../../../..
+
+WANT_CURL=yes
+
+MEMCACHED_DIR=$(switch_srcdir)/libs/$(MEMCACHED)
+
+MEMCACHEDLA=$(MEMCACHED_DIR)/libmemcached/libmemcached.la
+
+LOCAL_CFLAGS=-I$(MEMCACHED_DIR)
+LOCAL_LIBADD=$(MEMCACHEDLA)
+
+include $(switch_srcdir)/build/modmake.rules
+
+DEFAULT_ARGS=--prefix=$(PREFIX) --disable-shared --with-pic
+
+$(LOCAL_OBJS): $(LOCAL_SOURCES)
+
+$(MEMCACHED_DIR):
+ $(GETLIB) $(MEMCACHED).tar.gz
+
+$(MEMCACHED_DIR)/Makefile: $(MEMCACHED_DIR)
+ cd $(MEMCACHED_DIR) && CFLAGS=$(AM_CFLAGS) CC=$(CC) CXX=$(CXX) ./configure --disable-shared --with-pic CPPFLAGS= LDFLAGS=
+ $(TOUCH_TARGET)
+
+$(MEMCACHEDLA): $(MEMCACHED_DIR)/Makefile
+ cd $(MEMCACHED_DIR) && $(MAKE)
+ $(TOUCH_TARGET)
+
+
+
Added: freeswitch/trunk/src/mod/applications/mod_memcache/mod_memcache.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/applications/mod_memcache/mod_memcache.c Wed Apr 1 14:02:59 2009
@@ -0,0 +1,391 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2009, Anthony Minessale II <anthm at freeswitch.org>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthm at freeswitch.org>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Rupa Schomaker <rupa at rupa.com>
+ * Anthony Minessale II <anthm at freeswitch.org>
+ * Neal Horman <neal at wanlink dot com>
+ *
+ *
+ * mod_memcache.c -- API for memcache
+ *
+ */
+#include <switch.h>
+#include <libmemcached/memcached.h>
+
+/* Prototypes */
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_memcache_shutdown);
+SWITCH_MODULE_RUNTIME_FUNCTION(mod_memcache_runtime);
+SWITCH_MODULE_LOAD_FUNCTION(mod_memcache_load);
+
+/* SWITCH_MODULE_DEFINITION(name, load, shutdown, runtime)
+ * Defines a switch_loadable_module_function_table_t and a static const char[] modname
+ */
+SWITCH_MODULE_DEFINITION(mod_memcache, mod_memcache_load, mod_memcache_shutdown, NULL);
+
+static char *SYNTAX = "memcache <set|replace|add> <key> <value> [expiration [flags]]\n"
+ "memcache <getflags> <key>\n"
+ "memcache <delete> <key>\n"
+ "memcache <increment|decrement> <key> [offset]\n"
+ "memcache <flush>\n"
+ "memcache <status> [verbose]\n";
+
+static struct {
+ memcached_st *memcached;
+ char *memcached_str;
+} globals;
+
+static switch_status_t config_callback_memcached(switch_xml_config_item_t *data, switch_config_callback_type_t callback_type, switch_bool_t changed)
+{
+ memcached_server_st *memcached_server = NULL;
+ memcached_st *newmemcached = NULL;
+ memcached_st *oldmemcached = NULL;
+ char *memcached_str = NULL;
+ memcached_return rc;
+ unsigned int servercount;
+
+ if ((callback_type == CONFIG_LOAD || callback_type == CONFIG_RELOAD) && changed) {
+ memcached_str = *((char**)data->ptr);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "memcached data: %s\n", memcached_str);
+
+ /* initialize main ptr */
+ memcached_server = memcached_servers_parse(memcached_str);
+ if (!memcached_server) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unable to initialize memcached data structure (server_list).\n");
+ goto error;
+ }
+
+ if ((servercount = memcached_server_list_count(memcached_server)) == 0) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "No memcache servers defined. Server string: %s.\n", memcached_str);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%u servers defined.\n", servercount);
+ }
+
+ /* setup memcached */
+ newmemcached = memcached_create(NULL);
+ if (!newmemcached) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unable to initialize memcached data structure (memcached_st).\n");
+ goto error;
+ }
+ rc = memcached_server_push(newmemcached, memcached_server);
+ if (rc != MEMCACHED_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memcache error adding server list: %s\n", memcached_strerror(newmemcached, rc));
+ goto error;
+ }
+ /* memcached_behavior_set(newmemcached, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1); */
+
+ /* swap pointers */
+ oldmemcached = globals.memcached;
+ globals.memcached = newmemcached;
+ newmemcached = NULL;
+ }
+
+ if (memcached_server) {
+ memcached_server_list_free(memcached_server);
+ }
+ if (newmemcached) {
+ memcached_free(newmemcached);
+ }
+ if (oldmemcached) {
+ memcached_free(oldmemcached);
+ }
+ return SWITCH_STATUS_SUCCESS;
+
+error:
+ if (memcached_server) {
+ memcached_server_list_free(memcached_server);
+ }
+ if (newmemcached) {
+ memcached_free(newmemcached);
+ }
+ if (oldmemcached) {
+ memcached_free(oldmemcached);
+ }
+ return SWITCH_STATUS_GENERR;
+}
+
+static switch_xml_config_string_options_t config_opt_memcache_servers = {NULL, 0, ".*"}; /* anything is ok here */
+
+static switch_xml_config_item_t instructions[] = {
+ /* parameter name type reloadable pointer default value options structure */
+ SWITCH_CONFIG_ITEM_CALLBACK("memcache-servers", SWITCH_CONFIG_STRING, CONFIG_REQUIRED | CONFIG_RELOAD, &globals.memcached_str, NULL, config_callback_memcached, &config_opt_memcache_servers,
+ "host,host:port,host", "List of memcached servers."),
+ SWITCH_CONFIG_ITEM_END()
+};
+
+static switch_status_t do_config(switch_bool_t reload)
+{
+ switch_xml_t cfg, xml, settings;
+
+ memset(&globals, 0, sizeof(globals));
+
+ if (!(xml = switch_xml_open_cfg("memcache.conf", &cfg, NULL))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Could not open memcache.conf\n");
+ return SWITCH_STATUS_FALSE;
+ }
+
+ if ((settings = switch_xml_child(cfg, "settings"))) {
+ if (switch_xml_config_parse(switch_xml_child(settings, "param"), 0, instructions) == SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,"Config parsed ok!\n");
+ }
+ }
+
+ if (xml) {
+ switch_xml_free(xml);
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_STANDARD_API(memcache_function)
+{
+ char *argv[5] = { 0 };
+ int argc;
+ char *subcmd = NULL;
+ char *key = NULL;
+ char *val = NULL;
+ char *expires_str = NULL;
+ char *flags_str = NULL;
+ char *mydata = NULL;
+ size_t string_length = 0;
+ time_t expires = 0;
+ uint32_t flags = 0;
+ unsigned int server_count = 0;
+
+ memcached_return rc;
+ memcached_st *memcached = NULL;
+ memcached_stat_st *stat = NULL;
+ memcached_server_st *server_list;
+
+ if (switch_strlen_zero(cmd)) {
+ goto usage;
+ }
+
+ mydata = strdup(cmd);
+ if ((argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) {
+ if (argc < 1) {
+ goto usage;
+ }
+
+ /* clone memcached struct so we're thread safe */
+ memcached = memcached_clone(NULL, globals.memcached);
+ if (!memcached) {
+ stream->write_function(stream, "-ERR Error cloning memcached object\n");
+ }
+
+ subcmd = argv[0];
+
+ if ((!strcasecmp(subcmd, "set") || !strcasecmp(subcmd, "replace") || !strcasecmp(subcmd, "add")) && argc > 2) {
+ key = argv[1];
+ val = argv[2];
+
+ if(argc > 3) {
+ expires_str = argv[3];
+ expires = (time_t)strtol(expires_str, NULL, 10);
+ }
+ if(argc > 4) {
+ flags_str = argv[4];
+ flags = (uint32_t)strtol(flags_str, NULL, 16);
+ }
+ if (!strcasecmp(subcmd, "set")) {
+ rc = memcached_set(memcached, key, strlen(key), val, strlen(val), expires, flags);
+ } else if (!strcasecmp(subcmd, "replace")) {
+ rc = memcached_replace(memcached, key, strlen(key), val, strlen(val), expires, flags);
+ } else if (!strcasecmp(subcmd, "add")) {
+ rc = memcached_add(memcached, key, strlen(key), val, strlen(val), expires, flags);
+ }
+
+ if (rc == MEMCACHED_SUCCESS) {
+ stream->write_function(stream, "+OK\n");
+ } else {
+ stream->write_function(stream, "-ERR Error while running command %s: %s\n", subcmd, memcached_strerror(memcached, rc));
+ }
+ } else if (!strcasecmp(subcmd, "get") && argc > 1) {
+ key = argv[1];
+
+ val = memcached_get(memcached, key, strlen(key), &string_length, &flags, &rc);
+ if (rc == MEMCACHED_SUCCESS) {
+ stream->write_function(stream, "%.*s", (int)string_length, val);
+ } else {
+ stream->write_function(stream, "-ERR Error while running command %s: %s\n", subcmd, memcached_strerror(memcached, rc));
+ }
+ } else if (!strcasecmp(subcmd, "getflags") && argc > 1) {
+ key = argv[1];
+
+ val = memcached_get(memcached, key, strlen(key), &string_length, &flags, &rc);
+ if (rc == MEMCACHED_SUCCESS) {
+ stream->write_function(stream, "%x", flags);
+ } else {
+ stream->write_function(stream, "-ERR Error while running command %s: %s\n", subcmd, memcached_strerror(memcached, rc));
+ }
+ } else if ((!strcasecmp(subcmd, "increment") || !strcasecmp(subcmd, "decrement")) && argc > 1) {
+ key = argv[1];
+ uint64_t ivalue;
+ unsigned int offset = 1;
+ if(argc > 2) {
+ offset = (unsigned int)strtol(argv[2], NULL, 10);
+ }
+ if (!strcasecmp(subcmd, "increment")) {
+ rc = memcached_increment(memcached, key, strlen(key), offset, &ivalue);
+ } else if (!strcasecmp(subcmd, "decrement")) {
+ rc = memcached_decrement(memcached, key, strlen(key), offset, &ivalue);
+ }
+ if (rc == MEMCACHED_SUCCESS) {
+ stream->write_function(stream, "%ld", ivalue);
+ } else {
+ stream->write_function(stream, "-ERR Error while running command %s %s: %s\n", subcmd, key, memcached_strerror(memcached, rc));
+ }
+ } else if (!strcasecmp(subcmd, "delete") && argc > 1) {
+ key = argv[1];
+ if(argc > 2) {
+ expires_str = argv[3];
+ expires = (time_t)strtol(expires_str, NULL, 10);
+ }
+ rc = memcached_delete(memcached, key, strlen(key), expires);
+ if (rc == MEMCACHED_SUCCESS) {
+ stream->write_function(stream, "+OK\n", key);
+ } else {
+ stream->write_function(stream, "-ERR Error while running command %s %s: %s\n", subcmd, key, memcached_strerror(memcached, rc));
+ }
+ } else if (!strcasecmp(subcmd, "flush")) {
+ if(argc > 1) {
+ expires_str = argv[3];
+ expires = (time_t)strtol(expires_str, NULL, 10);
+ }
+ rc = memcached_flush(memcached, expires);
+ if (rc == MEMCACHED_SUCCESS) {
+ stream->write_function(stream, "+OK\n", key);
+ } else {
+ stream->write_function(stream, "-ERR Error while running command %s : %s\n", subcmd, memcached_strerror(memcached, rc));
+ }
+ } else if (!strcasecmp(subcmd, "status")) {
+ switch_bool_t verbose = SWITCH_FALSE;
+
+ if (argc > 1) {
+ if (!strcasecmp(argv[1], "verbose")) {
+ verbose = SWITCH_TRUE;
+ }
+ }
+
+ stream->write_function(stream, "Lib version: %s\n", memcached_lib_version());
+ stat = memcached_stat(memcached, NULL, &rc);
+ if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_SOME_ERRORS) {
+ stream->write_function(stream, "-ERR Error communicating with servers (%s)\n", memcached_strerror(memcached, rc));
+ }
+ server_list = memcached_server_list(memcached);
+ server_count = memcached_server_count(memcached);
+ stream->write_function(stream, "Servers: %d\n", server_count);
+ for (int x=0; x < server_count; x++) {
+ stream->write_function(stream, " %s (%u)\n", memcached_server_name(memcached, server_list[x]), memcached_server_port(memcached, server_list[x]));
+ if (verbose == SWITCH_TRUE) {
+ char **list;
+ char **ptr;
+ char *value;
+ memcached_return rc2;
+
+ list = memcached_stat_get_keys(memcached, &stat[x], &rc);
+ for (ptr = list; *ptr; ptr++) {
+ value = memcached_stat_get_value(memcached, &stat[x], *ptr, &rc2);
+ stream->write_function(stream, " %s: %s\n", *ptr, value);
+ switch_safe_free(value);
+ }
+ switch_safe_free(list);
+ stream->write_function(stream, "\n");
+ }
+ }
+ } else {
+ goto usage;
+ }
+ }
+
+ if (memcached) {
+ memcached_quit(memcached);
+ memcached_free(memcached);
+ }
+ switch_safe_free(mydata);
+ switch_safe_free(stat);
+ return SWITCH_STATUS_SUCCESS;
+usage:
+ if (memcached) {
+ memcached_quit(memcached);
+ memcached_free(memcached);
+ }
+ switch_safe_free(mydata);
+ stream->write_function(stream, "-ERR\n%s\n", SYNTAX);
+ return SWITCH_STATUS_SUCCESS;
+}
+
+/* Macro expands to: switch_status_t mod_memcache_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) */
+SWITCH_MODULE_LOAD_FUNCTION(mod_memcache_load)
+{
+ switch_api_interface_t *api_interface;
+ /* connect my internal structure to the blank pointer passed to me */
+ *module_interface = switch_loadable_module_create_module_interface(pool, modname);
+
+ do_config(SWITCH_FALSE);
+
+ SWITCH_ADD_API(api_interface, "memcache", "Memcache API", memcache_function, "syntax");
+
+ /* indicate that the module should continue to be loaded */
+ return SWITCH_STATUS_SUCCESS;
+}
+
+/*
+ Called when the system shuts down
+ Macro expands to: switch_status_t mod_memcache_shutdown() */
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_memcache_shutdown)
+{
+ /* Cleanup dynamically allocated config settings */
+ switch_xml_config_cleanup(instructions);
+ if (globals.memcached) {
+ memcached_free(globals.memcached);
+ }
+ return SWITCH_STATUS_SUCCESS;
+}
+
+
+/*
+ If it exists, this is called in it's own thread when the module-load completes
+ If it returns anything but SWITCH_STATUS_TERM it will be called again automatically
+ Macro expands to: switch_status_t mod_memcache_runtime()
+SWITCH_MODULE_RUNTIME_FUNCTION(mod_memcache_runtime)
+{
+ while(looping)
+ {
+ switch_cond_next();
+ }
+ return SWITCH_STATUS_TERM;
+}
+*/
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4
+ */
More information about the Freeswitch-svn
mailing list