[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