|
@@ -34,25 +34,76 @@
|
|
|
|
|
|
|
|
|
/*!
|
|
|
- * \brief Checks if the key is not too long, hash it with MD5 if necessary
|
|
|
- * \param in input string
|
|
|
+ * \brief Checks if the key is avaiable and not too long, hash it with MD5 if necessary
|
|
|
+ * \param msg SIP message
|
|
|
+ * \param param pseudo-variable input parameter
|
|
|
* \param out output string
|
|
|
+ * \return 0 on success, negative on failure
|
|
|
*/
|
|
|
-static inline void pv_mcd_key_check(str * in, str * out) {
|
|
|
+static inline int pv_mcd_key_check(struct sip_msg *msg, pv_param_t *param, str * out) {
|
|
|
|
|
|
+ str tmp;
|
|
|
static char hash[32];
|
|
|
|
|
|
- if (in->len < 250) {
|
|
|
- out->s = in->s;
|
|
|
- out->len = in->len;
|
|
|
+ if (msg == NULL || param == NULL) {
|
|
|
+ LM_ERR("bad parameters\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (pv_printf_s(msg, param->pvn.u.dname, &tmp) != 0)
|
|
|
+ {
|
|
|
+ LM_ERR("cannot get key name\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (tmp.len < 250) {
|
|
|
+ out->s = tmp.s;
|
|
|
+ out->len = tmp.len;
|
|
|
} else {
|
|
|
- LM_DBG("key too long, hash it\n");
|
|
|
- MD5StringArray (hash, in, 1);
|
|
|
+ LM_DBG("key too long (%d), hash it\n", tmp.len);
|
|
|
+ MD5StringArray (hash, &tmp, 1);
|
|
|
out->s = hash;
|
|
|
out->len = 32;
|
|
|
}
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
+/*!
|
|
|
+ * \brief Helper to get a cached value from memcached
|
|
|
+ * \param msg SIP message
|
|
|
+ * \param key value key
|
|
|
+ * \param mcd_req request
|
|
|
+ * \param mcd_res result
|
|
|
+ * \return null on success, negative on failure
|
|
|
+ */
|
|
|
+static int pv_get_mcd_value_helper(struct sip_msg *msg, str *key,
|
|
|
+ struct memcache_req **mcd_req, struct memcache_res **mcd_res) {
|
|
|
+
|
|
|
+ /* 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);
|
|
|
+
|
|
|
+ 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);
|
|
|
+
|
|
|
+ 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);
|
|
|
+ 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);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
/*!
|
|
|
* \brief Get a cached value from memcached
|
|
@@ -61,45 +112,23 @@ static inline void pv_mcd_key_check(str * in, str * out) {
|
|
|
* \param res result
|
|
|
* \return null on success, negative on failure
|
|
|
*/
|
|
|
-int pv_get_mcd_value(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) {
|
|
|
+int pv_get_mcd_value(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) {
|
|
|
|
|
|
unsigned int res_int = 0;
|
|
|
- str param_str, res_str, key_str;
|
|
|
-
|
|
|
+ str key, res_str;
|
|
|
struct memcache_req *mcd_req = NULL;
|
|
|
struct memcache_res *mcd_res = NULL;
|
|
|
|
|
|
- if (msg==NULL || res==NULL)
|
|
|
- return pv_get_null(msg, param, res);
|
|
|
-
|
|
|
- if(pv_printf_s(msg, param->pvn.u.dname, ¶m_str)!=0)
|
|
|
- {
|
|
|
- LM_ERR("cannot get key name\n");
|
|
|
+ if (pv_mcd_key_check(msg, param, &key) < 0) {
|
|
|
return pv_get_null(msg, param, res);
|
|
|
}
|
|
|
|
|
|
- /* we don't use mc_aget here, because we're multi-process */
|
|
|
- if ( (mcd_req = mc_req_new()) == NULL) {
|
|
|
- PKG_MEM_ERROR;
|
|
|
+ if (res==NULL)
|
|
|
return pv_get_null(msg, param, res);
|
|
|
- }
|
|
|
- LM_DBG("allocate new memcache request at %p\n", mcd_req);
|
|
|
-
|
|
|
- pv_mcd_key_check(¶m_str, &key_str);
|
|
|
|
|
|
- if ( (mcd_res = mc_req_add(mcd_req, key_str.s, key_str.len)) == NULL) {
|
|
|
- PKG_MEM_ERROR;
|
|
|
- return pv_get_null(msg, param, res);
|
|
|
- }
|
|
|
- LM_DBG("allocate new memcache result at %p\n", mcd_res);
|
|
|
-
|
|
|
- mc_get(memcached_h, mcd_req);
|
|
|
- if (! (mcd_res->_flags & MCM_RES_FOUND)) {
|
|
|
- LM_ERR("could not get result for key %.*s\n", key_str.len, key_str.s);
|
|
|
+ if (pv_get_mcd_value_helper(msg, &key, &mcd_req, &mcd_res) < 0) {
|
|
|
return pv_get_null(msg, param, res);
|
|
|
}
|
|
|
- LM_DBG("result: %.*s for key %.*s with flag %d\n", mcd_res->bytes, (char*)mcd_res->val,
|
|
|
- key_str.len, key_str.s, mcd_res->flags);
|
|
|
|
|
|
res_str.len = mcd_res->bytes;
|
|
|
res_str.s = mcd_res->val;
|
|
@@ -109,13 +138,13 @@ int pv_get_mcd_value(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) {
|
|
|
if(mcd_res->flags&VAR_VAL_STR) {
|
|
|
if (pkg_str_dup(&(res->rs), &res_str) < 0) {
|
|
|
LM_ERR("could not copy string\n");
|
|
|
- return pv_get_null(msg, param, res);
|
|
|
+ goto errout;
|
|
|
}
|
|
|
res->flags = PV_VAL_STR;
|
|
|
} else {
|
|
|
if (str2int(&res_str, &res_int) < 0) {
|
|
|
LM_ERR("could not convert string %.*s to integer value\n", res_str.len, res_str.s);
|
|
|
- return pv_get_null(msg, param, res);
|
|
|
+ goto errout;
|
|
|
}
|
|
|
res->rs = res_str;
|
|
|
res->ri = res_int;
|
|
@@ -125,6 +154,11 @@ int pv_get_mcd_value(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) {
|
|
|
mc_req_free(mcd_req);
|
|
|
|
|
|
return 0;
|
|
|
+
|
|
|
+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);
|
|
|
}
|
|
|
|
|
|
|
|
@@ -141,27 +175,17 @@ int pv_get_mcd_value(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) {
|
|
|
int pv_set_mcd_value(struct sip_msg* msg, pv_param_t *param, int op, pv_value_t *val) {
|
|
|
|
|
|
unsigned int val_flag = 0;
|
|
|
- str param_str, val_str, key_str;
|
|
|
-
|
|
|
- if (msg==NULL || param==NULL) {
|
|
|
- LM_ERR("bad parameters\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
+ str val_str, key;
|
|
|
|
|
|
- if(pv_printf_s(msg, param->pvn.u.dname, ¶m_str)!=0)
|
|
|
- {
|
|
|
- LM_ERR("cannot get key name\n");
|
|
|
+ if (pv_mcd_key_check(msg, param, &key) < 0)
|
|
|
return -1;
|
|
|
- }
|
|
|
-
|
|
|
- pv_mcd_key_check(¶m_str, &key_str);
|
|
|
|
|
|
if (val == NULL) {
|
|
|
- if (mc_delete(memcached_h, key_str.s, key_str.len, 0) != 0) {
|
|
|
+ if (mc_delete(memcached_h, key.s, key.len, 0) != 0) {
|
|
|
LM_ERR("could not delete key %.*s\n", param->pvn.u.isname.name.s.len,
|
|
|
param->pvn.u.isname.name.s.s);
|
|
|
}
|
|
|
- LM_DBG("delete key %.*s\n", key_str.len, key_str.s);
|
|
|
+ LM_DBG("delete key %.*s\n", key.len, key.s);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -173,17 +197,17 @@ int pv_get_mcd_value(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) {
|
|
|
}
|
|
|
|
|
|
if (memcached_mode == 0) {
|
|
|
- if (mc_set(memcached_h, key_str.s, key_str.len, val_str.s, val_str.len, memcached_expire, val_flag) != 0) {
|
|
|
- LM_ERR("could not set value for key %.*s\n", key_str.len, key_str.s);
|
|
|
+ if (mc_set(memcached_h, key.s, key.len, val_str.s, val_str.len, memcached_expire, val_flag) != 0) {
|
|
|
+ LM_ERR("could not set value for key %.*s\n", key.len, key.s);
|
|
|
return -1;
|
|
|
}
|
|
|
} else {
|
|
|
- if (mc_add(memcached_h, key_str.s, key_str.len, val_str.s, val_str.len, memcached_expire, val_flag) != 0) {
|
|
|
- LM_ERR("could not add value for key %.*s\n", key_str.len, key_str.s);
|
|
|
+ if (mc_add(memcached_h, key.s, key.len, val_str.s, val_str.len, memcached_expire, val_flag) != 0) {
|
|
|
+ LM_ERR("could not add value for key %.*s\n", key.len, key.s);
|
|
|
return -1;
|
|
|
}
|
|
|
}
|
|
|
- LM_DBG("set value %.*s for key %.*s with flag %d\n", val_str.len, val_str.s, key_str.len, key_str.s, val_flag);
|
|
|
+ LM_DBG("set value %.*s for key %.*s with flag %d\n", val_str.len, val_str.s, key.len, key.s, val_flag);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -207,58 +231,35 @@ static int pv_mcd_atomic_helper(struct sip_msg* msg, pv_param_t *param, int op,
|
|
|
const unsigned int val)) {
|
|
|
|
|
|
unsigned int value = 0;
|
|
|
- str param_str, key_str;
|
|
|
+ str key;
|
|
|
struct memcache_req *mcd_req = NULL;
|
|
|
struct memcache_res *mcd_res = NULL;
|
|
|
|
|
|
- if (msg==NULL || param==NULL) {
|
|
|
- LM_ERR("bad parameters\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- if(pv_printf_s(msg, param->pvn.u.dname, ¶m_str)!=0)
|
|
|
- {
|
|
|
- LM_ERR("cannot get key name\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- pv_mcd_key_check(¶m_str, &key_str);
|
|
|
-
|
|
|
if (! val->flags&PV_VAL_INT) {
|
|
|
- LM_ERR("invalid right 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);
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
- /* we don't use mc_aget here, because we're multi-process */
|
|
|
- if ( (mcd_req = mc_req_new()) == NULL) {
|
|
|
- PKG_MEM_ERROR;
|
|
|
+ if (pv_mcd_key_check(msg, param, &key) < 0)
|
|
|
return -1;
|
|
|
- }
|
|
|
- LM_DBG("allocate new memcache request at %p\n", mcd_req);
|
|
|
-
|
|
|
- if ( (mcd_res = mc_req_add(mcd_req, key_str.s, key_str.len)) == NULL) {
|
|
|
- PKG_MEM_ERROR;
|
|
|
- return -1;
|
|
|
- }
|
|
|
- LM_DBG("allocate new memcache result at %p\n", mcd_res);
|
|
|
|
|
|
- mc_get(memcached_h, mcd_req);
|
|
|
- if (! (mcd_res->_flags & MCM_RES_FOUND)) {
|
|
|
- LM_DBG("key %.*s not found for atomic operation\n", key_str.len, key_str.s);
|
|
|
+ if (pv_get_mcd_value_helper(msg, &key, &mcd_req, &mcd_res) < 0) {
|
|
|
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);
|
|
|
|
|
|
if(mcd_res->flags&VAR_VAL_STR) {
|
|
|
- LM_ERR("could not do atomic operations on string for key %.*s\n", key_str.len, key_str.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;
|
|
|
}
|
|
|
+
|
|
|
+ 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_str.s, key_str.len, val->ri);
|
|
|
+ value = atomic_ops(memcached_h, key.s, key.len, val->ri);
|
|
|
LM_DBG("value from atomic operation %d\n", value);
|
|
|
|
|
|
return 0;
|
|
@@ -291,6 +292,50 @@ int inline pv_dec_mcd_value(struct sip_msg* msg, pv_param_t *param, int op, pv_v
|
|
|
}
|
|
|
|
|
|
|
|
|
+/*!
|
|
|
+ * \brief Set the expire value in the cache of memcached
|
|
|
+ * \note The memcache library don't provide functions to change the expiration
|
|
|
+ * time for a certain key after creation, so we need to do a get and set here.
|
|
|
+ * \param msg SIP message
|
|
|
+ * \param param parameter
|
|
|
+ * \param op not used
|
|
|
+ * \param val value
|
|
|
+ * \return 0 on success, -1 on failure
|
|
|
+ */
|
|
|
+int pv_set_mcd_expire(struct sip_msg* msg, pv_param_t *param, int op, pv_value_t *val)
|
|
|
+{
|
|
|
+ str key;
|
|
|
+ struct memcache_req *mcd_req = NULL;
|
|
|
+ struct memcache_res *mcd_res = NULL;
|
|
|
+
|
|
|
+ if (! val->flags&PV_VAL_INT) {
|
|
|
+ LM_ERR("invalid value %.*s for expire time, strings not allowed\n",
|
|
|
+ val->rs.len, val->rs.s);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (pv_mcd_key_check(msg, param, &key) < 0)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ if (pv_get_mcd_value_helper(msg, &key, &mcd_req, &mcd_res) < 0) {
|
|
|
+ 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);
|
|
|
+
|
|
|
+ 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);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ LM_DBG("free memcache request and result at %p\n", mcd_req);
|
|
|
+ mc_req_free(mcd_req);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
/*!
|
|
|
* \brief Parse the pseudo-variable specification parameter
|
|
|
* \param sp pseudo-variable specification
|