Pārlūkot izejas kodu

memcached: port module to use the newer libmemcached library
* based on a patch from Charles Chance, sipcentric.com
* He added new functionality to set the expiry directly in the key
* Added memory manager wrapping functions and some more logging,
* smaller cleanups in the code structure
* This is work in progress, the memory management stuff is not yet
* finished, as this needs different logic for client lib version
* before and after 0.32. It will not work at the moment correctly.

Henning Westerholt 12 gadi atpakaļ
vecāks
revīzija
066011935c

+ 1 - 1
modules/memcached/Makefile

@@ -9,6 +9,6 @@ NAME=memcached.so
 DEFS+=-DKAMAILIO_MOD_INTERFACE
 DEFS+=-DKAMAILIO_MOD_INTERFACE
 
 
 DEFS +=-I$(LOCALBASE)/include -I$(SYSBASE)/include
 DEFS +=-I$(LOCALBASE)/include -I$(SYSBASE)/include
-LIBS+=-L$(LOCALBASE)/lib -L$(SYSBASE)/lib -lmemcache
+LIBS+=-L$(LOCALBASE)/lib -L$(SYSBASE)/lib -lmemcached
 
 
 include ../../Makefile.modules
 include ../../Makefile.modules

+ 138 - 83
modules/memcached/mcd_var.c

@@ -1,7 +1,6 @@
-/**
- * $Id$
- *
- * Copyright (C) 2009 Henning Westerholt
+/*
+ * Copyright (C) 2009, 2013 Henning Westerholt
+ * Copyright (C) 2013 Charles Chance, sipcentric.com
  *
  *
  * This file is part of Kamailio, a free SIP server.
  * This file is part of Kamailio, a free SIP server.
  *
  *
@@ -34,15 +33,73 @@
 
 
 
 
 /*!
 /*!
- * \brief Checks if the key is avaiable and not too long, hash it with MD5 if necessary
+ * \brief Checks for '=>' delimiter in key name string and if present, extracts expiry value.
+ * \param data string to parse
+ * \param key output string name
+ * \param exp output int expiry (if present)
+ * \return 0 on success, negative on failure
+ */
+static inline int pv_mcd_key_expiry_split_str(str *data, str *key, unsigned int *exp) {
+	char *p;
+	str str_exp;
+	
+	if (data == NULL || data->s == NULL || data->len <= 0) {
+		LM_ERR("invalid parameters\n");
+		return -1;
+	}
+	
+	p = data->s;
+	key->s = p;
+	key->len = 0;
+
+	while(p < data->s + data->len) {
+		if (*p == '=') {
+			p++;
+			if (*p == '>') {
+				break;
+			} else {
+				key->len++;
+			}
+		} else {
+	                key->len++;
+			p++;
+		}
+	}
+
+	if (key->len < data->len) {
+		/* delimiter is present, try to extract expiry value */
+		p++;
+		if (p < data->s + data->len) {
+			str_exp.s = p;
+			str_exp.len = 0;
+			while(p<data->s+data->len) {
+				str_exp.len++;
+				p++;
+			}
+		}
+		if (str_exp.len > 0) {
+			/* convert to int */
+			*exp = atoi(str_exp.s);
+		}
+		LM_DBG("key is %.*s expiry is %d\n", key->len, key->s, *exp);
+	}
+
+	return 0;
+}
+
+/*!
+ * \brief Checks if the key is avaiable and not too long, hashing it with MD5 if necessary.
  * \param msg SIP message
  * \param msg SIP message
  * \param param pseudo-variable input parameter
  * \param param pseudo-variable input parameter
- * \param out output string
+ * \param key output string name
+ * \param exp output int expiry (if present)
  * \return 0 on success, negative on failure
  * \return 0 on success, negative on failure
  */
  */
-static inline int pv_mcd_key_check(struct sip_msg *msg, pv_param_t *param, str * out) {
+static inline int pv_mcd_key_check(struct sip_msg *msg, pv_param_t *param, str * key, unsigned int * exp ) {
 
 
+	str pvn;
 	str tmp;
 	str tmp;
+
 	static char hash[32];
 	static char hash[32];
 
 
 	if (msg == NULL || param == NULL) {
 	if (msg == NULL || param == NULL) {
@@ -50,20 +107,24 @@ static inline int pv_mcd_key_check(struct sip_msg *msg, pv_param_t *param, str *
 		return -1;
 		return -1;
 	}
 	}
 
 
-	if (pv_printf_s(msg, param->pvn.u.dname, &tmp) != 0)
+	if (pv_printf_s(msg, param->pvn.u.dname, &pvn) != 0)
 	{
 	{
-		LM_ERR("cannot get key name\n");
+		LM_ERR("cannot get pv name\n");
+		return -1;
+	}
+
+	if (pv_mcd_key_expiry_split_str(&pvn, &tmp, exp) != 0) {
 		return -1;
 		return -1;
 	}
 	}
 
 
 	if (tmp.len < 250) {
 	if (tmp.len < 250) {
-		out->s = tmp.s;
-		out->len = tmp.len;
+		key->s = tmp.s;
+		key->len = tmp.len;
 	} else {
 	} else {
 		LM_DBG("key too long (%d), hash it\n", tmp.len);
 		LM_DBG("key too long (%d), hash it\n", tmp.len);
 		MD5StringArray (hash, &tmp, 1);
 		MD5StringArray (hash, &tmp, 1);
-		out->s = hash;
-		out->len = 32;
+		key->s = hash;
+		key->len = 32;
 	}
 	}
 	return 0;
 	return 0;
 }
 }
@@ -72,39 +133,33 @@ static inline int pv_mcd_key_check(struct sip_msg *msg, pv_param_t *param, str *
  * \brief Helper to get a cached value from memcached
  * \brief Helper to get a cached value from memcached
  * \param msg SIP message
  * \param msg SIP message
  * \param key value key
  * \param key value key
- * \param mcd_req request
- * \param mcd_res result
+ * \param return_value returned value
+ * \param flags returned flags
  * \return null on success, negative on failure
  * \return null on success, negative on failure
  */
  */
 static int pv_get_mcd_value_helper(struct sip_msg *msg, str *key,
 static int pv_get_mcd_value_helper(struct sip_msg *msg, str *key,
-		struct memcache_req **mcd_req, struct memcache_res **mcd_res) {
+		char **return_value, uint32_t *flags) {
 
 
-	/* we don't use mc_aget here, because we're multi-process */
-	if ( (*mcd_req = mc_req_new()) == NULL) {
-		PKG_MEM_ERROR;
-		return -1;
-	}
-	LM_DBG("allocate new memcache request at %p\n", *mcd_req);
+	memcached_return rc;
+	size_t return_value_length;
 
 
-	if ( (*mcd_res = mc_req_add(*mcd_req, key->s, key->len)) == NULL) {
-		PKG_MEM_ERROR;
-		return -1;
-	}
-	LM_DBG("allocate new memcache result at %p\n", *mcd_res);
+	*return_value = memcached_get(memcached_h, key->s, key->len, &return_value_length, flags, &rc);
 
 
-	mc_get(memcached_h, *mcd_req);
-	if (! ( (*mcd_res)->_flags & MCM_RES_FOUND)) {
-		LM_ERR("could not get result for key %.*s\n", key->len, key->s);
-		LM_DBG("free memcache request and result at %p\n", mcd_req);
-		mc_req_free(*mcd_req);
+	if (*return_value == NULL) {
+		if (rc == MEMCACHED_NOTFOUND) {
+			LM_DBG("key %.*s not found\n", key->len, key->s);
+		} else {
+			LM_ERR("could not get result for key %.*s - error was '%s'\n", key->len, key->s, memcached_strerror(memcached_h, rc));
+		}
 		return -1;
 		return -1;
 	}
 	}
-	LM_DBG("result: %.*s for key %.*s with flag %d\n", (*mcd_res)->bytes, (char*)(*mcd_res)->val,
-		key->len, key->s, (*mcd_res)->flags);
+
+	LM_DBG("result: %s for key %.*s with flag %d\n", *return_value, key->len, key->s, *flags);
 
 
 	return 0;
 	return 0;
 }
 }
 
 
+
 /*!
 /*!
  * \brief Get a cached value from memcached
  * \brief Get a cached value from memcached
  * \param msg SIP message
  * \param msg SIP message
@@ -116,26 +171,32 @@ int pv_get_mcd_value(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) {
 
 
 	unsigned int res_int = 0;
 	unsigned int res_int = 0;
 	str key, res_str;
 	str key, res_str;
-	struct memcache_req *mcd_req = NULL;
-	struct memcache_res *mcd_res = NULL;
+	unsigned int expiry = mcd_expire;
 
 
-	if (pv_mcd_key_check(msg, param, &key) < 0) {
+  	char *return_value;
+	uint32_t return_flags;
+
+	if (pv_mcd_key_check(msg, param, &key, &expiry) < 0) {
 		return pv_get_null(msg, param, res);
 		return pv_get_null(msg, param, res);
 	}
 	}
 
 
 	if (res==NULL)
 	if (res==NULL)
 		return pv_get_null(msg, param, res);
 		return pv_get_null(msg, param, res);
 
 
-	if (pv_get_mcd_value_helper(msg, &key, &mcd_req, &mcd_res) < 0) {
+	if (pv_get_mcd_value_helper(msg, &key, &return_value, &return_flags) < 0) {
 		return pv_get_null(msg, param, res);
 		return pv_get_null(msg, param, res);
 	}
 	}
 
 
-	res_str.len = mcd_res->bytes;
-	res_str.s = mcd_res->val;
+
+	res_str.len = strlen(return_value);
+	res_str.s = return_value;
+
+
 	/* apparently memcached adds whitespaces to the beginning of the value after atomic operations */
 	/* apparently memcached adds whitespaces to the beginning of the value after atomic operations */
+
 	trim_len(res_str.len, res_str.s, res_str);
 	trim_len(res_str.len, res_str.s, res_str);
 
 
-	if(mcd_res->flags&VAR_VAL_STR) {
+	if(return_flags&VAR_VAL_STR) {
 		 if (pkg_str_dup(&(res->rs), &res_str) < 0) {
 		 if (pkg_str_dup(&(res->rs), &res_str) < 0) {
 			LM_ERR("could not copy string\n");
 			LM_ERR("could not copy string\n");
 			goto errout;
 			goto errout;
@@ -150,18 +211,15 @@ int pv_get_mcd_value(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) {
 		res->ri = res_int;
 		res->ri = res_int;
 		res->flags = PV_VAL_STR|PV_VAL_INT|PV_TYPE_INT;
 		res->flags = PV_VAL_STR|PV_VAL_INT|PV_TYPE_INT;
 	}
 	}
-	LM_DBG("free memcache request and result at %p\n", mcd_req);
-	mc_req_free(mcd_req);
 
 
 	return 0;
 	return 0;
 
 
 errout:
 errout:
-	LM_DBG("free memcache request and result at %p\n", mcd_req);
-	mc_req_free(mcd_req);
 	return pv_get_null(msg, param, res);
 	return pv_get_null(msg, param, res);
 }
 }
 
 
 
 
+
 /*!
 /*!
  * \brief Set a value in the cache of memcached
  * \brief Set a value in the cache of memcached
  * \todo Replacement of already existing values is not done atomically at the moment.
  * \todo Replacement of already existing values is not done atomically at the moment.
@@ -176,16 +234,18 @@ errout:
 
 
 	unsigned int val_flag = 0;
 	unsigned int val_flag = 0;
 	str val_str, key;
 	str val_str, key;
+	unsigned int expiry = mcd_expire;
 
 
-	if (pv_mcd_key_check(msg, param, &key) < 0)
+	if (pv_mcd_key_check(msg, param, &key, &expiry) < 0)
 		return -1;
 		return -1;
 
 
 	if (val == NULL) {
 	if (val == NULL) {
-		if (mc_delete(memcached_h, key.s, key.len, 0) != 0) {
+		if (memcached_delete(memcached_h, key.s, key.len, 0) != MEMCACHED_SUCCESS) {
 			LM_ERR("could not delete key %.*s\n", param->pvn.u.isname.name.s.len,
 			LM_ERR("could not delete key %.*s\n", param->pvn.u.isname.name.s.len,
 				param->pvn.u.isname.name.s.s);
 				param->pvn.u.isname.name.s.s);
+			return -1;
 		}
 		}
-		LM_DBG("delete key %.*s\n", key.len, key.s);
+		LM_WARN("delete key %.*s\n", key.len, key.s);
 		return 0;
 		return 0;
 	}
 	}
 
 
@@ -196,13 +256,13 @@ errout:
 		val_flag = VAR_VAL_STR;
 		val_flag = VAR_VAL_STR;
 	}
 	}
 
 
-	if (memcached_mode == 0) {
-		if (mc_set(memcached_h, key.s, key.len, val_str.s, val_str.len, memcached_expire, val_flag) != 0) {
+	if (mcd_mode == 0) {
+		if (memcached_set(memcached_h, key.s, key.len, val_str.s, val_str.len, expiry, val_flag) != MEMCACHED_SUCCESS) {
 			LM_ERR("could not set value for key %.*s\n", key.len, key.s);
 			LM_ERR("could not set value for key %.*s\n", key.len, key.s);
 			return -1;
 			return -1;
 		}
 		}
 	} else {
 	} else {
-		if (mc_add(memcached_h, key.s, key.len, val_str.s, val_str.len, memcached_expire, val_flag) != 0) {
+		if (memcached_add(memcached_h, key.s, key.len, val_str.s, val_str.len, expiry, val_flag) != MEMCACHED_SUCCESS) {
 			LM_ERR("could not add value for key %.*s\n", key.len, key.s);
 			LM_ERR("could not add value for key %.*s\n", key.len, key.s);
 			return -1;
 			return -1;
 		}
 		}
@@ -223,44 +283,41 @@ errout:
  * \param param parameter
  * \param param parameter
  * \param op not used
  * \param op not used
  * \param val value
  * \param val value
- * \param atomic_ops function pointer to the atomic operation from the memcache library
+ * \param atomic_ops function pointer to the atomic operation from the memcached library
  * \return 0 on success, -1 on failure
  * \return 0 on success, -1 on failure
  */
  */
 static int pv_mcd_atomic_helper(struct sip_msg* msg, pv_param_t *param, int op, pv_value_t *val,
 static int pv_mcd_atomic_helper(struct sip_msg* msg, pv_param_t *param, int op, pv_value_t *val,
-		unsigned int (* atomic_ops) (struct memcache *mc, char *key, const size_t key_len,
-		const unsigned int val)) {
+		memcached_return (* atomic_ops) (memcached_st *mc, const char *key, size_t key_length, uint32_t offset, uint64_t *value)) {
 
 
-	unsigned int value = 0;
+	uint64_t value = 0;
 	str key;
 	str key;
-	struct memcache_req *mcd_req = NULL;
-	struct memcache_res *mcd_res = NULL;
+	unsigned int expiry = mcd_expire;
+	char *return_value;
+	uint32_t return_flags;
+	memcached_return rc;
 	
 	
-	if (! val->flags&PV_VAL_INT) {
+	if (!(val->flags&PV_VAL_INT)) {
 		LM_ERR("invalid value %.*s for atomic operation, strings not allowed\n",
 		LM_ERR("invalid value %.*s for atomic operation, strings not allowed\n",
 			val->rs.len, val->rs.s);
 			val->rs.len, val->rs.s);
 		return -1;
 		return -1;
 	}
 	}
 
 
-	if (pv_mcd_key_check(msg, param, &key) < 0)
+	if (pv_mcd_key_check(msg, param, &key, &expiry) < 0)
 		return -1;
 		return -1;
 
 
-	if (pv_get_mcd_value_helper(msg, &key, &mcd_req, &mcd_res) < 0) {
+	if (pv_get_mcd_value_helper(msg, &key, &return_value, &return_flags) < 0) {
 		return -1;
 		return -1;
 	}
 	}
 
 
-	if(mcd_res->flags&VAR_VAL_STR) {
+	if(return_flags&VAR_VAL_STR) {
 		LM_ERR("could not do atomic operations on string for key %.*s\n", key.len, key.s);
 		LM_ERR("could not do atomic operations on string for key %.*s\n", key.len, key.s);
-		LM_DBG("free memcache request and result at %p\n", mcd_req);
-		mc_req_free(mcd_req);
 		return -1;
 		return -1;
 	}
 	}
 
 
-	LM_DBG("atomic operation on result %.*s for %d with flag %d\n", mcd_res->bytes, (char*)mcd_res->val, val->ri, mcd_res->flags);
-	LM_DBG("free memcache request and result at %p\n", mcd_req);
-	mc_req_free(mcd_req);
-
-	value = atomic_ops(memcached_h, key.s, key.len, val->ri);
-	LM_DBG("value from atomic operation %d\n", value);
+	if ((rc = atomic_ops(memcached_h, key.s, key.len, val->ri, &value)) != MEMCACHED_SUCCESS) {
+		LM_ERR("error performing atomic operation on key %.*s - %s\n", key.len, key.s, memcached_strerror(memcached_h, rc));
+		return -1;
+	}
 
 
 	return 0;
 	return 0;
 }
 }
@@ -275,7 +332,7 @@ static int pv_mcd_atomic_helper(struct sip_msg* msg, pv_param_t *param, int op,
  * \return 0 on success, -1 on failure
  * \return 0 on success, -1 on failure
  */
  */
 int inline pv_inc_mcd_value(struct sip_msg* msg, pv_param_t *param, int op, pv_value_t *val) {
 int inline pv_inc_mcd_value(struct sip_msg* msg, pv_param_t *param, int op, pv_value_t *val) {
-	return pv_mcd_atomic_helper(msg, param, op, val, mc_incr);
+	return pv_mcd_atomic_helper(msg, param, op, val, memcached_increment);
 }
 }
 
 
 
 
@@ -288,7 +345,7 @@ int inline pv_inc_mcd_value(struct sip_msg* msg, pv_param_t *param, int op, pv_v
  * \return 0 on success, -1 on failure
  * \return 0 on success, -1 on failure
  */
  */
 int inline pv_dec_mcd_value(struct sip_msg* msg, pv_param_t *param, int op, pv_value_t *val) {
 int inline pv_dec_mcd_value(struct sip_msg* msg, pv_param_t *param, int op, pv_value_t *val) {
-	return pv_mcd_atomic_helper(msg, param, op, val, mc_decr);
+	return pv_mcd_atomic_helper(msg, param, op, val, memcached_decrement);
 }
 }
 
 
 
 
@@ -305,32 +362,30 @@ int inline pv_dec_mcd_value(struct sip_msg* msg, pv_param_t *param, int op, pv_v
 int pv_set_mcd_expire(struct sip_msg* msg, pv_param_t *param, int op, pv_value_t *val)
 int pv_set_mcd_expire(struct sip_msg* msg, pv_param_t *param, int op, pv_value_t *val)
 {
 {
 	str key;
 	str key;
-	struct memcache_req *mcd_req = NULL;
-	struct memcache_res *mcd_res = NULL;
+	unsigned int expiry = mcd_expire;
+        char *return_value;
+        uint32_t return_flags;
+        memcached_return rc;
 
 
-	if (! val->flags&PV_VAL_INT) {
+	if (!(val->flags&PV_VAL_INT)) {
 		LM_ERR("invalid value %.*s for expire time, strings not allowed\n",
 		LM_ERR("invalid value %.*s for expire time, strings not allowed\n",
 			val->rs.len, val->rs.s);
 			val->rs.len, val->rs.s);
 		return -1;
 		return -1;
 	}
 	}
 
 
-	if (pv_mcd_key_check(msg, param, &key) < 0)
+	if (pv_mcd_key_check(msg, param, &key, &expiry) < 0)
 		return -1;
 		return -1;
 
 
-	if (pv_get_mcd_value_helper(msg, &key, &mcd_req, &mcd_res) < 0) {
+	if (pv_get_mcd_value_helper(msg, &key, &return_value, &return_flags) < 0) {
 		return -1;
 		return -1;
 	}
 	}
 
 
-	LM_DBG("set expire time %d on result %.*s for %d with flag %d\n", val->ri, mcd_res->bytes, (char*)mcd_res->val, val->ri, mcd_res->flags);
+	LM_DBG("set expire time %d for key %.*s with flag %d\n", val->ri, key.len, key.s, return_flags);
 
 
-	if (mc_set(memcached_h, key.s, key.len, mcd_res->val, mcd_res->bytes, val->ri, mcd_res->flags) != 0) {
-		LM_ERR("could not set expire time %d for key %.*s\n", val->ri, key.len, key.s);
-		LM_DBG("free memcache request and result at %p\n", mcd_req);
-		mc_req_free(mcd_req);
+	if ((rc= memcached_set(memcached_h, key.s, key.len, return_value, strlen(return_value), val->ri, return_flags)) != MEMCACHED_SUCCESS) {
+		LM_ERR("could not set expire time %d for key %.*s - error was %s\n", val->ri, key.len, key.s, memcached_strerror(memcached_h, rc));
 		return -1;
 		return -1;
 	}
 	}
-	LM_DBG("free memcache request and result at %p\n", mcd_req);
-	mc_req_free(mcd_req);
 
 
 	return 0;
 	return 0;
 }
 }

+ 3 - 4
modules/memcached/mcd_var.h

@@ -1,7 +1,6 @@
-/**
- * $Id$
- *
- * Copyright (C) 2009 Henning Westerholt
+/*
+ * Copyright (C) 2009, 2013 Henning Westerholt
+ * Copyright (C) 2013 Charles Chance, sipcentric.com
  *
  *
  * This file is part of Kamailio, a free SIP server.
  * This file is part of Kamailio, a free SIP server.
  *
  *

+ 85 - 119
modules/memcached/memcached.c

@@ -1,7 +1,6 @@
 /*
 /*
- * $Id$
- *
- * Copyright (C) 2009 Henning Westerholt
+ * Copyright (C) 2009, 2013 Henning Westerholt
+ * Copyright (C) 2013 Charles Chance, sipcentric.com
  *
  *
  * This file is part of Kamailio, a free SIP server.
  * This file is part of Kamailio, a free SIP server.
  *
  *
@@ -37,23 +36,18 @@
 MODULE_VERSION
 MODULE_VERSION
 
 
 
 
-#define DP_ALERT_TEXT    "ALERT:"
-#define DP_ERR_TEXT      "ERROR:"
-#define DP_WARN_TEXT     "WARNING:"
-#define DP_NOTICE_TEXT   "NOTICE:"
-#define DP_INFO_TEXT     "INFO:"
-
-
 /*! server string */
 /*! server string */
-char* memcached_srv_str = "localhost:11211";
-/*! cache expire time in seconds */
-unsigned int memcached_expire = 10800;
+char* mcd_srv_str = "localhost:11211";
+/*! cache (default) expire time in seconds */
+unsigned int mcd_expire = 0;
 /*! cache storage mode, set or add */
 /*! cache storage mode, set or add */
-unsigned int memcached_mode = 0;
+unsigned int mcd_mode = 0;
 /*! server timeout in ms*/
 /*! server timeout in ms*/
-int memcached_timeout = 5000;
+int mcd_timeout = 5000;
 /*! memcached handle */
 /*! memcached handle */
-struct memcache* memcached_h = NULL;
+struct memcached_st *memcached_h;
+/*! memcached server list */
+struct memcached_server_st *servers;
 
 
 
 
 static int mod_init(void);
 static int mod_init(void);
@@ -81,10 +75,10 @@ static pv_export_t mod_pvs[] = {
  * Exported parameters
  * Exported parameters
  */
  */
 static param_export_t params[] = {
 static param_export_t params[] = {
-	{"servers", STR_PARAM, &memcached_srv_str },
-	{"expire",   INT_PARAM, &memcached_expire },
-	{"timeout", INT_PARAM, &memcached_timeout },
-	{"mode",    INT_PARAM, &memcached_mode },
+	{"servers", STR_PARAM, &mcd_srv_str },
+	{"expire",   INT_PARAM, &mcd_expire },
+	{"timeout", INT_PARAM, &mcd_timeout },
+	{"mode",    INT_PARAM, &mcd_mode },
 	{0, 0, 0}
 	{0, 0, 0}
 };
 };
 
 
@@ -113,7 +107,7 @@ struct module_exports exports = {
  * \param mem freed memory
  * \param mem freed memory
  * \see pkg_free
  * \see pkg_free
  */
  */
-static inline void memcached_free(void *mem) {
+static inline void mcd_free(void *mem) {
 	pkg_free(mem);
 	pkg_free(mem);
 }
 }
 
 
@@ -124,7 +118,7 @@ static inline void memcached_free(void *mem) {
  * \return allocated memory, or NULL on failure
  * \return allocated memory, or NULL on failure
  * \see pkg_malloc
  * \see pkg_malloc
  */
  */
-static inline void* memcached_malloc(const size_t size) {
+static inline void* mcd_malloc(const size_t size) {
 	return pkg_malloc(size);
 	return pkg_malloc(size);
 }
 }
 
 
@@ -136,69 +130,10 @@ static inline void* memcached_malloc(const size_t size) {
  * \return allocated memory, or NULL on failure
  * \return allocated memory, or NULL on failure
  * \see pkg_realloc
  * \see pkg_realloc
  */
  */
-static inline void* memcached_realloc(void *mem, const size_t size) {
+static inline void* mcd_realloc(void *mem, const size_t size) {
  	return pkg_realloc(mem, size);
  	return pkg_realloc(mem, size);
 }
 }
 
 
-
-/*!
- * \brief Small wrapper around our internal logging function
- */
-static int memcache_err_func(MCM_ERR_FUNC_ARGS) {
-
-	const struct memcache_ctxt *ctxt;
-	struct memcache_err_ctxt *ectxt;
-	int error_level;
-	const char * error_str;
-
-	MCM_ERR_INIT_CTXT(ctxt, ectxt);
-
-	switch (ectxt->severity) {
-		case MCM_ERR_LVL_INFO:
-			error_level = L_INFO;
-			error_str = DP_INFO_TEXT;
-			break;
-		case MCM_ERR_LVL_NOTICE:
-			error_level = L_NOTICE;
-			error_str = DP_NOTICE_TEXT;
-			break;
-		case MCM_ERR_LVL_WARN:
-			error_level = L_WARN;
-			error_str = DP_WARN_TEXT;
-			break;
-		case MCM_ERR_LVL_ERR:
-			error_level = L_ERR;
-			error_str  = DP_ERR_TEXT;
-			/* try to continue */
- 			ectxt->cont = 'y';
-			break;
-		case MCM_ERR_LVL_FATAL:
-  		default:
-			error_level = L_ALERT;
-			error_str = DP_ALERT_TEXT;
-			ectxt->cont = 'y';
-			break;
-	}
-
-	/*
-	* ectxt->errmsg - per error message passed along via one of the MCM_*_MSG() macros (optional)
-	* ectxt->errstr - memcache error string (optional, though almost always set)
-	*/
-	if (ectxt->errstr != NULL && ectxt->errmsg != NULL)
-		LM_GEN1(error_level, "%s memcached: %s():%u: %s: %.*s\n", error_str, ectxt->funcname, ectxt->lineno, ectxt->errstr,
-			(int)ectxt->errlen, ectxt->errmsg);
-	else if (ectxt->errstr == NULL && ectxt->errmsg != NULL)
-		LM_GEN1(error_level, "%s memcached: %s():%u: %.*s\n", error_str, ectxt->funcname, ectxt->lineno, (int)ectxt->errlen,
-			ectxt->errmsg);
-	else if (ectxt->errstr != NULL && ectxt->errmsg == NULL)
-		LM_GEN1(error_level, "%s memcached: %s():%u: %s\n", error_str, ectxt->funcname, ectxt->lineno, ectxt->errstr);
-	else
-		LM_GEN1(error_level, "%s memcached: %s():%u\n", error_str, ectxt->funcname, ectxt->lineno);
-
-	return 0;
-}
-
-
 /*!
 /*!
  * \brief Module initialization function
  * \brief Module initialization function
  * \return 0 on success, -1 on failure
  * \return 0 on success, -1 on failure
@@ -206,58 +141,90 @@ static int memcache_err_func(MCM_ERR_FUNC_ARGS) {
 static int mod_init(void) {
 static int mod_init(void) {
 	char *server, *port;
 	char *server, *port;
 	unsigned int len = 0;
 	unsigned int len = 0;
+	memcached_return rc;
 
 
-	/* setup the callbacks to our internal memory manager */
-	if (mcMemSetup(memcached_free, memcached_malloc,
-			memcached_malloc, memcached_realloc) != 0) {
-		LM_ERR("could not setup memory management callbacks\n");
-		return -1;
-	}
-
-	if (mcErrSetup(memcache_err_func) != 0) {
-		LM_ERR("could not setup error handler callback\n");
-		return -1;
-	}
-
-	/*! delete eventual log filters */
-	mc_err_filter_del(MCM_ERR_LVL_INFO);
-	mc_err_filter_del(MCM_ERR_LVL_NOTICE);
-
-	memcached_h = mc_new();
-	if (memcached_h == NULL) {
-		PKG_MEM_ERROR;
-		return -1;
-	}
-	
-	if ((port = strchr(memcached_srv_str, ':')) != NULL) {
+	if ((port = strchr(mcd_srv_str, ':')) != NULL) {
 		port = port + 1;
 		port = port + 1;
-		len = strlen(memcached_srv_str) - strlen(port) - 1;
+		len = strlen(mcd_srv_str) - strlen(port) - 1;
 	} else {
 	} else {
 		LM_DBG("no port definition, using default port\n");
 		LM_DBG("no port definition, using default port\n");
 		port = "11211";
 		port = "11211";
-		len = strlen(memcached_srv_str) ;
+		len = strlen(mcd_srv_str) ;
 	}
 	}
 	
 	
-
 	server = pkg_malloc(len);
 	server = pkg_malloc(len);
 	if (server == NULL) {
 	if (server == NULL) {
 		PKG_MEM_ERROR;
 		PKG_MEM_ERROR;
 		return -1;
 		return -1;
 	}
 	}
 
 
-	strncpy(server, memcached_srv_str, len);
+	strncpy(server, mcd_srv_str, len);
 	server[len] = '\0';
 	server[len] = '\0';
 
 
-	mc_timeout(memcached_h, 0, memcached_timeout);
+        servers = memcached_server_list_append(servers, server, atoi(port), &rc);
 
 
-	if (mc_server_add(memcached_h, server, port) != 0) {
-		LM_ERR("could not add server %s:%s\n", server, port);
+	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);
+	
+	#ifdef MEMCACHED_ENABLE_DEPRECATED
+	/** 
+	 * \note Set callbacks to our internal memory manager
+	 * \bug this don't work for now
+	 * \todo Move to new memcached_set_memory_allocators function, this deprecated since 0.32
+	 * 
+	 * MEMCACHED_CALLBACK_MALLOC_FUNCTION
+	 * This alllows yout to pass in a customized version of malloc that
+	 * will be used instead of the builtin malloc(3) call. The prototype
+	 * for this is:
+	 * void *(*memcached_malloc_function)(memcached_st *ptr, const size_t size);
+	 * 
+	 * MEMCACHED_CALLBACK_REALLOC_FUNCTION
+	 * This alllows yout to pass in a customized version of realloc that
+	 * will be used instead of the builtin realloc(3) call. The prototype
+	 * for this is:
+	 * void *(*memcached_realloc_function)(memcached_st *ptr, void *mem, const size_t size);
+	 * 
+	 * MEMCACHED_CALLBACK_FREE_FUNCTION
+	 * This alllows yout to pass in a customized version of realloc that
+	 * will be used instead of the builtin free(3) call. The prototype
+	 * for this is:
+	 * typedef void (*memcached_free_function)(memcached_st *ptr, void *mem);
+	 */
+	LM_DBG("set memory manager callbacks");	
+	if (memcached_callback_set(memcached_h, MEMCACHED_CALLBACK_MALLOC_FUNCTION, mcd_free) != MEMCACHED_SUCCESS) {
+		LM_ERR("could not set malloc callback handler");
+		return -1;
+	}
+	if (memcached_callback_set(memcached_h, MEMCACHED_CALLBACK_REALLOC_FUNCTION, mcd_realloc) != MEMCACHED_SUCCESS) {
+		LM_ERR("could not set realloc callback handler");
+		return -1;
+	}
+	if (memcached_callback_set(memcached_h, MEMCACHED_CALLBACK_FREE_FUNCTION, mcd_free) != MEMCACHED_SUCCESS) {
+		LM_ERR("could not set free callback handler");
+		return -1;
+	}
+	LM_DBG("memory manager callbacks set");
+	#endif
+	
+	if (memcached_behavior_set(memcached_h, MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT, mcd_timeout) != MEMCACHED_SUCCESS) {
+		LM_ERR("could not set server connection timeout");
+		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;
 		return -1;
 	}
 	}
-	LM_INFO("connected to server %s:%s\n", server, port);
-	pkg_free(server);
 
 
-	LM_INFO("memcached client version is %s, released on %d\n", mc_version(), mc_reldate());
+	pkg_free(server);
+	
+	LM_INFO("libmemcached version is %s\n", memcached_lib_version());
 	return 0;
 	return 0;
 }
 }
 
 
@@ -267,8 +234,7 @@ static int mod_init(void) {
  */
  */
 static void mod_destroy(void) {
 static void mod_destroy(void) {
 	if (memcached_h != NULL)
 	if (memcached_h != NULL)
-		mc_server_disconnect_all(memcached_h);
-
-	if (memcached_h != NULL)
-		mc_free(memcached_h);
+		memcached_free(memcached_h);
+	if (servers != NULL)
+		memcached_server_list_free(servers);
 }
 }

+ 10 - 10
modules/memcached/memcached.h

@@ -1,7 +1,6 @@
 /*
 /*
- * $Id$
- *
- * Copyright (C) 2009 Henning Westerholt
+ * Copyright (C) 2009, 2013 Henning Westerholt
+ * Copyright (C) 2013 Charles Chance, sipcentric.com
  *
  *
  * This file is part of Kamailio, a free SIP server.
  * This file is part of Kamailio, a free SIP server.
  *
  *
@@ -24,21 +23,22 @@
  * \brief memcached module
  * \brief memcached module
  */
  */
 
 
-#include <memcache.h>
+#include <libmemcached/memcached.h>
 
 
 #ifndef MEMCACHED_H
 #ifndef MEMCACHED_H
 #define MEMCACHED_H
 #define MEMCACHED_H
 
 
 /*! server string */
 /*! server string */
-extern char* db_memcached_srv_str;
+extern char* mcd_srv_str;
 /*! cache expire time in seconds */
 /*! cache expire time in seconds */
-extern unsigned int memcached_expire;
+extern unsigned int mcd_expire;
 /*! cache storage mode, set or add */
 /*! cache storage mode, set or add */
-extern unsigned int memcached_mode;
+extern unsigned int mcd_mode;
 /*! server timeout */
 /*! server timeout */
-extern int memcached_timeout;
+extern int mcd_timeout;
 /*! memcached handle */
 /*! memcached handle */
-extern struct memcache* memcached_h;
-
+extern struct memcached_st* memcached_h;
+/*! memcached server list */
+extern struct memcached_server_st *servers;
 
 
 #endif
 #endif