mcd_var.c

Go to the documentation of this file.
00001 
00027 #include "mcd_var.h"
00028 
00029 #include "memcached.h"
00030 #include "../../ut.h"
00031 #include "../../mem/mem.h"
00032 #include "../pv/pv_svar.h"
00033 #include "../../md5utils.h"
00034 
00035 
00043 static inline int pv_mcd_key_check(struct sip_msg *msg, pv_param_t *param, str * out) {
00044 
00045         str tmp;
00046         static char hash[32];
00047 
00048         if (msg == NULL || param == NULL) {
00049                 LM_ERR("bad parameters\n");
00050                 return -1;
00051         }
00052 
00053         if (pv_printf_s(msg, param->pvn.u.dname, &tmp) != 0)
00054         {
00055                 LM_ERR("cannot get key name\n");
00056                 return -1;
00057         }
00058 
00059         if (tmp.len < 250) {
00060                 out->s = tmp.s;
00061                 out->len = tmp.len;
00062         } else {
00063                 LM_DBG("key too long (%d), hash it\n", tmp.len);
00064                 MD5StringArray (hash, &tmp, 1);
00065                 out->s = hash;
00066                 out->len = 32;
00067         }
00068         return 0;
00069 }
00070 
00079 static int pv_get_mcd_value_helper(struct sip_msg *msg, str *key,
00080                 struct memcache_req **mcd_req, struct memcache_res **mcd_res) {
00081 
00082         /* we don't use mc_aget here, because we're multi-process */
00083         if ( (*mcd_req = mc_req_new()) == NULL) {
00084                 PKG_MEM_ERROR;
00085                 return -1;
00086         }
00087         LM_DBG("allocate new memcache request at %p\n", *mcd_req);
00088 
00089         if ( (*mcd_res = mc_req_add(*mcd_req, key->s, key->len)) == NULL) {
00090                 PKG_MEM_ERROR;
00091                 return -1;
00092         }
00093         LM_DBG("allocate new memcache result at %p\n", *mcd_res);
00094 
00095         mc_get(memcached_h, *mcd_req);
00096         if (! ( (*mcd_res)->_flags & MCM_RES_FOUND)) {
00097                 LM_ERR("could not get result for key %.*s\n", key->len, key->s);
00098                 LM_DBG("free memcache request and result at %p\n", mcd_req);
00099                 mc_req_free(*mcd_req);
00100                 return -1;
00101         }
00102         LM_DBG("result: %.*s for key %.*s with flag %d\n", (*mcd_res)->bytes, (char*)(*mcd_res)->val,
00103                 key->len, key->s, (*mcd_res)->flags);
00104 
00105         return 0;
00106 }
00107 
00115 int pv_get_mcd_value(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) {
00116 
00117         unsigned int res_int = 0;
00118         str key, res_str;
00119         struct memcache_req *mcd_req = NULL;
00120         struct memcache_res *mcd_res = NULL;
00121 
00122         if (pv_mcd_key_check(msg, param, &key) < 0) {
00123                 return pv_get_null(msg, param, res);
00124         }
00125 
00126         if (res==NULL)
00127                 return pv_get_null(msg, param, res);
00128 
00129         if (pv_get_mcd_value_helper(msg, &key, &mcd_req, &mcd_res) < 0) {
00130                 return pv_get_null(msg, param, res);
00131         }
00132 
00133         res_str.len = mcd_res->bytes;
00134         res_str.s = mcd_res->val;
00135         /* apparently memcached adds whitespaces to the beginning of the value after atomic operations */
00136         trim_len(res_str.len, res_str.s, res_str);
00137 
00138         if(mcd_res->flags&VAR_VAL_STR) {
00139                  if (pkg_str_dup(&(res->rs), &res_str) < 0) {
00140                         LM_ERR("could not copy string\n");
00141                         goto errout;
00142                 }
00143                 res->flags = PV_VAL_STR;
00144         } else {
00145                 if (str2int(&res_str, &res_int) < 0) {
00146                         LM_ERR("could not convert string %.*s to integer value\n", res_str.len, res_str.s);
00147                         goto errout;
00148                 }
00149                 res->rs = res_str;
00150                 res->ri = res_int;
00151                 res->flags = PV_VAL_STR|PV_VAL_INT|PV_TYPE_INT;
00152         }
00153         LM_DBG("free memcache request and result at %p\n", mcd_req);
00154         mc_req_free(mcd_req);
00155 
00156         return 0;
00157 
00158 errout:
00159         LM_DBG("free memcache request and result at %p\n", mcd_req);
00160         mc_req_free(mcd_req);
00161         return pv_get_null(msg, param, res);
00162 }
00163 
00164 
00175  int pv_set_mcd_value(struct sip_msg* msg, pv_param_t *param, int op, pv_value_t *val) {
00176 
00177         unsigned int val_flag = 0;
00178         str val_str, key;
00179 
00180         if (pv_mcd_key_check(msg, param, &key) < 0)
00181                 return -1;
00182 
00183         if (val == NULL) {
00184                 if (mc_delete(memcached_h, key.s, key.len, 0) != 0) {
00185                         LM_ERR("could not delete key %.*s\n", param->pvn.u.isname.name.s.len,
00186                                 param->pvn.u.isname.name.s.s);
00187                 }
00188                 LM_DBG("delete key %.*s\n", key.len, key.s);
00189                 return 0;
00190         }
00191 
00192         if (val->flags&PV_VAL_INT) {
00193                 val_str.s = int2str(val->ri, &val_str.len);
00194         } else {
00195                 val_str = val->rs;
00196                 val_flag = VAR_VAL_STR;
00197         }
00198 
00199         if (memcached_mode == 0) {
00200                 if (mc_set(memcached_h, key.s, key.len, val_str.s, val_str.len, memcached_expire, val_flag) != 0) {
00201                         LM_ERR("could not set value for key %.*s\n", key.len, key.s);
00202                         return -1;
00203                 }
00204         } else {
00205                 if (mc_add(memcached_h, key.s, key.len, val_str.s, val_str.len, memcached_expire, val_flag) != 0) {
00206                         LM_ERR("could not add value for key %.*s\n", key.len, key.s);
00207                         return -1;
00208                 }
00209         }
00210         LM_DBG("set value %.*s for key %.*s with flag %d\n", val_str.len, val_str.s, key.len, key.s, val_flag);
00211 
00212         return 0;
00213 }
00214 
00215 
00229 static int pv_mcd_atomic_helper(struct sip_msg* msg, pv_param_t *param, int op, pv_value_t *val,
00230                 unsigned int (* atomic_ops) (struct memcache *mc, char *key, const size_t key_len,
00231                 const unsigned int val)) {
00232 
00233         unsigned int value = 0;
00234         str key;
00235         struct memcache_req *mcd_req = NULL;
00236         struct memcache_res *mcd_res = NULL;
00237         
00238         if (! val->flags&PV_VAL_INT) {
00239                 LM_ERR("invalid value %.*s for atomic operation, strings not allowed\n",
00240                         val->rs.len, val->rs.s);
00241                 return -1;
00242         }
00243 
00244         if (pv_mcd_key_check(msg, param, &key) < 0)
00245                 return -1;
00246 
00247         if (pv_get_mcd_value_helper(msg, &key, &mcd_req, &mcd_res) < 0) {
00248                 return -1;
00249         }
00250 
00251         if(mcd_res->flags&VAR_VAL_STR) {
00252                 LM_ERR("could not do atomic operations on string for key %.*s\n", key.len, key.s);
00253                 LM_DBG("free memcache request and result at %p\n", mcd_req);
00254                 mc_req_free(mcd_req);
00255                 return -1;
00256         }
00257 
00258         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);
00259         LM_DBG("free memcache request and result at %p\n", mcd_req);
00260         mc_req_free(mcd_req);
00261 
00262         value = atomic_ops(memcached_h, key.s, key.len, val->ri);
00263         LM_DBG("value from atomic operation %d\n", value);
00264 
00265         return 0;
00266 }
00267 
00268 
00277 int inline pv_inc_mcd_value(struct sip_msg* msg, pv_param_t *param, int op, pv_value_t *val) {
00278         return pv_mcd_atomic_helper(msg, param, op, val, mc_incr);
00279 }
00280 
00281 
00290 int inline pv_dec_mcd_value(struct sip_msg* msg, pv_param_t *param, int op, pv_value_t *val) {
00291         return pv_mcd_atomic_helper(msg, param, op, val, mc_decr);
00292 }
00293 
00294 
00305 int pv_set_mcd_expire(struct sip_msg* msg, pv_param_t *param, int op, pv_value_t *val)
00306 {
00307         str key;
00308         struct memcache_req *mcd_req = NULL;
00309         struct memcache_res *mcd_res = NULL;
00310 
00311         if (! val->flags&PV_VAL_INT) {
00312                 LM_ERR("invalid value %.*s for expire time, strings not allowed\n",
00313                         val->rs.len, val->rs.s);
00314                 return -1;
00315         }
00316 
00317         if (pv_mcd_key_check(msg, param, &key) < 0)
00318                 return -1;
00319 
00320         if (pv_get_mcd_value_helper(msg, &key, &mcd_req, &mcd_res) < 0) {
00321                 return -1;
00322         }
00323 
00324         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);
00325 
00326         if (mc_set(memcached_h, key.s, key.len, mcd_res->val, mcd_res->bytes, val->ri, mcd_res->flags) != 0) {
00327                 LM_ERR("could not set expire time %d for key %.*s\n", val->ri, key.len, key.s);
00328                 LM_DBG("free memcache request and result at %p\n", mcd_req);
00329                 mc_req_free(mcd_req);
00330                 return -1;
00331         }
00332         LM_DBG("free memcache request and result at %p\n", mcd_req);
00333         mc_req_free(mcd_req);
00334 
00335         return 0;
00336 }
00337 
00338 
00345 int pv_parse_mcd_name(pv_spec_p sp, str *in) {
00346 
00347         pv_elem_t * tmp = NULL;
00348 
00349         if(sp==NULL || in==NULL || in->len<=0)
00350                 return -1;
00351 
00352 
00353         tmp = pkg_malloc(sizeof(pv_elem_t));
00354         if (tmp == NULL) {
00355                 PKG_MEM_ERROR;
00356                 return -1;
00357         }
00358         memset(tmp, 0, sizeof(pv_elem_t));
00359 
00360         if(pv_parse_format(in, &tmp) || tmp==NULL) {
00361                 LM_ERR("wrong format [%.*s]\n", in->len, in->s);
00362                 return -1;
00363         }
00364 
00365         sp->pvp.pvn.u.dname = tmp;
00366         sp->pvp.pvn.type = PV_NAME_PVAR;
00367 
00368         return 0;
00369 }