extra_attrs.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. #include "extra_attrs.h"
  2. #include "uid_avp_db.h"
  3. #include "../../usr_avp.h"
  4. #include "../../sr_module.h"
  5. #include "../../ut.h"
  6. #include "../../mem/mem.h"
  7. #include "../../mem/shm_mem.h"
  8. #include "../../lock_ops.h"
  9. #include "../../script_cb.h"
  10. #include "../../hashes.h"
  11. #define set_str_val(f,s) (f).v.lstr=(s); \
  12. (f).flags = 0;
  13. #define set_str_val_ex(f,s) if ((s).len) { (f).v.lstr=(s); (f).flags = 0; } \
  14. else (f).flags|=DB_NULL;
  15. #define set_int_val(f,t) (f).v.int4=t;\
  16. (f).flags=0;
  17. #define get_str_val(rvi,dst) do{if(!(rvi.flags&DB_NULL)){dst=rvi.v.lstr;} else dst.len = 0;}while(0)
  18. #define get_int_val(rvi,dst) do{if(!(rvi.flags&DB_NULL)){dst=rvi.v.int4;} else dst = 0;}while(0)
  19. typedef struct _registered_table_t {
  20. char *id;
  21. char *table_name;
  22. /* column names */
  23. char *key_column;
  24. char *name_column;
  25. char *type_column;
  26. char *value_column;
  27. char *flags_column;
  28. char *flag_name;
  29. /* pregenerated queries */
  30. db_cmd_t *query;
  31. db_cmd_t *remove;
  32. db_cmd_t *add;
  33. avp_flags_t flag;
  34. int group_mutex_idx;
  35. struct _registered_table_t *next;
  36. char buf[1]; /* buffer for strings allocated with the structure */
  37. } registered_table_t;
  38. static registered_table_t *tables = NULL;
  39. registered_table_t *find_registered_table(const char *id)
  40. {
  41. registered_table_t *t = tables;
  42. while (t) {
  43. if (strcmp(t->id, id) == 0) return t;
  44. t = t->next;
  45. }
  46. return NULL;
  47. }
  48. char *get_token(char *s, str *name, str *value)
  49. {
  50. enum { reading_name, reading_value } state = reading_name;
  51. /* returns 'token' which has the form name[=value][,]
  52. * replaces separators ,= by binary 0 to allow char* strings */
  53. name->s = s;
  54. name->len = 0;
  55. value->s = NULL;
  56. value->len = 0;
  57. while (*s) {
  58. switch (state) {
  59. case reading_name:
  60. switch (*s) {
  61. case '=':
  62. case ':':
  63. state = reading_value;
  64. value->s = s + 1;
  65. *s = 0; /* replace separator */
  66. break;
  67. case ',':
  68. *s = 0; /* replace separator */
  69. return s + 1;
  70. default: name->len++;
  71. }
  72. break;
  73. case reading_value:
  74. if (*s == ',') {
  75. *s = 0; /* replace separator */
  76. return s + 1;
  77. }
  78. else value->len++;
  79. break;
  80. }
  81. s++;
  82. }
  83. return NULL; /* everything read */
  84. }
  85. static int cmp_s(str *a, str *b)
  86. {
  87. int i;
  88. /* Warning: none string can be NULL! */
  89. if (a->len != b->len) return -1;
  90. if (!a->len) return 0; /* equal - empty */
  91. for (i = 0; i < a->len; i++)
  92. if (a->s[i] != b->s[i]) return 1;
  93. return 0;
  94. }
  95. static inline void cpy(char *dst, str *s)
  96. {
  97. memcpy(dst, s->s, s->len);
  98. dst[s->len] = 0;
  99. }
  100. /* adds new 'extra attribute group' (it adds new table for it) */
  101. int declare_attr_group(modparam_t type, char* _param)
  102. {
  103. registered_table_t *rt;
  104. str name, value;
  105. str param;
  106. char *p;
  107. static str table = STR_STATIC_INIT("table");
  108. static str flag = STR_STATIC_INIT("flag");
  109. static str id = STR_STATIC_INIT("id");
  110. static str key_column = STR_STATIC_INIT("key_column");
  111. static str name_column = STR_STATIC_INIT("name_column");
  112. static str value_column = STR_STATIC_INIT("value_column");
  113. static str type_column = STR_STATIC_INIT("type_column");
  114. static str flags_column = STR_STATIC_INIT("flags_column");
  115. if (!(type & PARAM_STR)) {
  116. ERR("Invalid parameter type\n");
  117. return -1;
  118. }
  119. if (!_param) {
  120. ERR("invalid parameter value\n");
  121. return -1;
  122. }
  123. param = *((str*)_param);
  124. DBG("group def: %.*s\n", param.len, param.s);
  125. rt = pkg_malloc(param.len + sizeof(*rt) + 1);
  126. if (!rt) {
  127. ERR("can't allocate PKG memory\n");
  128. return -1;
  129. }
  130. memset(rt, 0, sizeof(*rt));
  131. cpy(rt->buf, &param);
  132. /* default column names */
  133. rt->key_column = "id";
  134. rt->name_column = "name";
  135. rt->type_column = "type";
  136. rt->value_column = "value";
  137. rt->flags_column = "flags";
  138. /* parse the string */
  139. p = rt->buf;
  140. do {
  141. p = get_token(p, &name, &value);
  142. if (cmp_s(&name, &table) == 0) rt->table_name = value.s;
  143. else if (cmp_s(&name, &flag) == 0) rt->flag_name = value.s;
  144. else if (cmp_s(&name, &id) == 0) rt->id = value.s;
  145. else if (cmp_s(&name, &key_column) == 0) rt->key_column = value.s;
  146. else if (cmp_s(&name, &name_column) == 0) rt->name_column = value.s;
  147. else if (cmp_s(&name, &type_column) == 0) rt->type_column = value.s;
  148. else if (cmp_s(&name, &value_column) == 0) rt->value_column = value.s;
  149. else if (cmp_s(&name, &flags_column) == 0) rt->flags_column = value.s;
  150. } while (p);
  151. if ((!rt->id) || (!rt->flag_name)) {
  152. ERR("at least attribute group ID and flags must ve given\n");
  153. return -1;
  154. }
  155. /* insert new element into registered tables */
  156. rt->flag = register_avpflag(rt->flag_name);
  157. if (!rt->flag) {
  158. ERR("can't register AVP flag: %s\n", rt->flag_name);
  159. pkg_free(rt);
  160. return -1;
  161. }
  162. /* append to the beggining - it doesn't depend on the order */
  163. rt->next = tables;
  164. tables = rt;
  165. return 0;
  166. }
  167. /** Initialize all queries needed by 'extra attributes' for given table.
  168. * Variable default_res holds columns which can used by read_attrs. */
  169. static int init_queries(db_ctx_t *ctx, registered_table_t *t)
  170. {
  171. db_fld_t match[] = {
  172. { .name = t->key_column, .type = DB_STR, .op = DB_EQ },
  173. { .name = NULL }
  174. };
  175. db_fld_t query_res[] = {
  176. /* Warning: be careful here - the query must have the same result
  177. * as query for user/uri AVPs to be readable by read_attrs */
  178. { .name = t->name_column, .type = DB_STR, .op = DB_EQ },
  179. { .name = t->type_column, .type = DB_INT, .op = DB_EQ },
  180. { .name = t->value_column, .type = DB_STR, .op = DB_EQ },
  181. { .name = t->flags_column, .type = DB_BITMAP, .op = DB_EQ },
  182. { .name = NULL }
  183. };
  184. db_fld_t add_values[] = {
  185. { .name = t->key_column, .type = DB_STR, .op = DB_EQ },
  186. { .name = t->name_column, .type = DB_STR, .op = DB_EQ },
  187. { .name = t->type_column, .type = DB_INT, .op = DB_EQ },
  188. { .name = t->value_column, .type = DB_STR, .op = DB_EQ },
  189. { .name = t->flags_column, .type = DB_BITMAP, .op = DB_EQ },
  190. { .name = NULL }
  191. };
  192. t->query = db_cmd(DB_GET, ctx, t->table_name, query_res, match, NULL);
  193. t->remove = db_cmd(DB_DEL, ctx, t->table_name, NULL, match, NULL);
  194. t->add = db_cmd(DB_PUT, ctx, t->table_name, NULL, NULL, add_values);
  195. if (t->query && t->remove && t->add) return 0;
  196. else return -1; /* not all queries were initialized */
  197. }
  198. int init_extra_avp_queries(db_ctx_t *ctx)
  199. {
  200. registered_table_t *t = tables;
  201. while (t) {
  202. if (init_queries(ctx, t) < 0) return -1;
  203. t = t->next;
  204. }
  205. return 0;
  206. }
  207. static void get_avp_value_ex(avp_t *avp, str *dst, int *type) {
  208. avp_value_t val;
  209. /* Warning! it uses static buffer from int2str !!! */
  210. get_avp_val(avp, &val);
  211. if (avp->flags & AVP_VAL_STR) {
  212. *dst = val.s;
  213. *type = AVP_VAL_STR;
  214. }
  215. else { /* probably (!) number */
  216. dst->s = int2str(val.n, &dst->len);
  217. *type = 0;
  218. }
  219. }
  220. /** Saves attribute into DB with given ID. The ID must not be NULL. The
  221. * use_table must be called outside of this function (from interface
  222. * functions) */
  223. static inline int save_avp(registered_table_t *t, avp_t *avp, str *id) /* id MUST NOT be NULL */
  224. {
  225. str *s, v;
  226. int type;
  227. static str empty = STR_STATIC_INIT("");
  228. set_str_val(t->add->vals[0], *id);
  229. s = get_avp_name(avp);
  230. if (!s) s = &empty;
  231. set_str_val(t->add->vals[1], *s);
  232. get_avp_value_ex(avp, &v, &type);
  233. set_int_val(t->add->vals[2], type);
  234. set_str_val(t->add->vals[3], v);
  235. set_int_val(t->add->vals[4], avp->flags & (AVP_CLASS_ALL | AVP_TRACK_ALL | AVP_NAME_STR | AVP_VAL_STR));
  236. if (db_exec(NULL, t->add) < 0) {
  237. ERR("Can't insert record into DB\n");
  238. return -1;
  239. }
  240. return 0;
  241. }
  242. /** Loads all attributes with given ID. The ID must not be NULL. */
  243. static int read_avps(db_res_t *res, avp_flags_t flag) /* id must not be NULL */
  244. {
  245. db_rec_t *row;
  246. row = db_first(res);
  247. while (row) {
  248. int flags = 0;
  249. int type = 0;
  250. str value = STR_NULL;
  251. avp_value_t val;
  252. avp_name_t name;
  253. get_str_val(row->fld[0], name.s);
  254. get_int_val(row->fld[1], type);
  255. get_str_val(row->fld[2], value);
  256. get_int_val(row->fld[3], flags);
  257. if (flags & SRDB_LOAD_SER) {
  258. if (type == AVP_VAL_STR) val.s = value;
  259. else str2int(&value, (unsigned int *)&val.n); /* FIXME */
  260. flags |= flag;
  261. /* FIXME: avps probably should be removed before they are added,
  262. * but this should be done in add_avp and not here! */
  263. add_avp(flags, name, val);
  264. }
  265. row = db_next(res);
  266. }
  267. return 0;
  268. }
  269. /** Removes all attributes with given ID. The ID must not be NULL. */
  270. static inline int remove_all_avps(registered_table_t *t, str *id)
  271. {
  272. set_str_val(t->remove->match[0], *id);
  273. if (db_exec(NULL, t->remove) < 0) {
  274. ERR("can't remove attrs\n");
  275. return -1;
  276. }
  277. return 0;
  278. }
  279. /* ----- interface functions ----- */
  280. int load_extra_attrs(struct sip_msg* msg, char* _table, char* _id)
  281. {
  282. registered_table_t *t;
  283. db_res_t *res = NULL;
  284. str id;
  285. t = (registered_table_t *)_table;
  286. if ((!t) || (get_str_fparam(&id, msg, (fparam_t*)_id) < 0)) {
  287. ERR("invalid parameter value\n");
  288. return -1;
  289. }
  290. set_str_val(t->query->match[0], id);
  291. if (db_exec(&res, t->query) < 0) {
  292. ERR("DB query failed\n");
  293. return -1;
  294. }
  295. if (res) {
  296. read_avps(res, t->flag);
  297. db_res_free(res);
  298. }
  299. return 1;
  300. }
  301. int remove_extra_attrs(struct sip_msg* msg, char *_table, char* _id)
  302. {
  303. str id;
  304. registered_table_t *t;
  305. t = (registered_table_t *)_table;
  306. if ((!t) || (get_str_fparam(&id, msg, (fparam_t*)_id) < 0)) {
  307. ERR("invalid parameter value\n");
  308. return -1;
  309. }
  310. remove_all_avps(t, &id);
  311. return 1;
  312. }
  313. int save_extra_attrs(struct sip_msg* msg, char* _table, char *_id)
  314. {
  315. str id;
  316. int i;
  317. struct usr_avp *avp;
  318. static unsigned short lists[] = {
  319. AVP_CLASS_USER | AVP_TRACK_FROM,
  320. AVP_CLASS_USER | AVP_TRACK_TO,
  321. AVP_CLASS_URI | AVP_TRACK_FROM,
  322. AVP_CLASS_URI | AVP_TRACK_TO,
  323. 0
  324. };
  325. registered_table_t *t;
  326. t = (registered_table_t *)_table;
  327. if ((!t) || (get_str_fparam(&id, msg, (fparam_t*)_id) < 0)) {
  328. ERR("invalid parameter value\n");
  329. return -1;
  330. }
  331. /* delete all attrs under given id */
  332. remove_all_avps(t, &id);
  333. /* save all attrs flagged with flag under id */
  334. for (i = 0; lists[i]; i++) {
  335. for (avp = get_avp_list(lists[i]); avp; avp = avp->next) {
  336. if ((avp->flags & t->flag) != 0) save_avp(t, avp, &id);
  337. }
  338. }
  339. return 1;
  340. }
  341. int extra_attrs_fixup(void** param, int param_no)
  342. {
  343. registered_table_t *t;
  344. switch (param_no) {
  345. case 1: /* try to find registered table, error if not found */
  346. t = find_registered_table(*param);
  347. if (!t) {
  348. ERR("can't find attribute group with id: %s\n", (char*)*param);
  349. return -1;
  350. }
  351. *param = (void*)t;
  352. break;
  353. case 2: return fixup_var_str_2(param, param_no);
  354. }
  355. return 0;
  356. }
  357. /******* locking *******/
  358. #define LOCK_CNT 32
  359. gen_lock_t *locks = NULL; /* set of mutexes allocated in shared memory */
  360. int lock_counters[LOCK_CNT]; /* set of counters (each proces has its own counters) */
  361. static int avpdb_post_script_cb(struct sip_msg *msg, unsigned int flags, void *param) {
  362. int i;
  363. for (i=0; i<LOCK_CNT; i++) {
  364. if (lock_counters[i] > 0) {
  365. if (auto_unlock) {
  366. DEBUG("post script auto unlock extra attrs <%d>\n", i);
  367. lock_release(&locks[i]);
  368. lock_counters[i]=0;
  369. } else {
  370. BUG("script writer didn't unlock extra attrs !!!\n");
  371. return 1;
  372. }
  373. }
  374. }
  375. return 1;
  376. }
  377. int init_extra_avp_locks()
  378. {
  379. int i;
  380. registered_table_t *t = tables;
  381. /* zero all 'lock counters' */
  382. memset(lock_counters, 0, sizeof(lock_counters));
  383. locks = shm_malloc(sizeof(gen_lock_t) * LOCK_CNT);
  384. if (!locks) {
  385. ERR("can't allocate mutexes\n");
  386. return -1;
  387. }
  388. for (i = 0; i < LOCK_CNT; i++) {
  389. lock_init(&locks[i]);
  390. }
  391. /* initializes mutexes for extra AVPs */
  392. i = 0;
  393. while (t) {
  394. t->group_mutex_idx = get_hash1_raw(t->table_name, strlen(t->table_name)) % LOCK_CNT;
  395. t = t->next;
  396. }
  397. register_script_cb(avpdb_post_script_cb, REQUEST_CB | ONREPLY_CB | POST_SCRIPT_CB, 0);
  398. return 0;
  399. }
  400. static inline int find_mutex(registered_table_t *t, str *id)
  401. {
  402. /* hash(table_name) + hash(id) */
  403. return ((t->group_mutex_idx + get_hash1_raw(id->s, id->len)) % LOCK_CNT);
  404. }
  405. int lock_extra_attrs(struct sip_msg* msg, char *_table, char* _id)
  406. {
  407. str id;
  408. registered_table_t *t;
  409. int mutex_idx;
  410. t = (registered_table_t *)_table;
  411. if ((!t) || (get_str_fparam(&id, msg, (fparam_t*)_id) < 0)) {
  412. ERR("invalid parameter value\n");
  413. return -1;
  414. }
  415. /* find right mutex according to id/table */
  416. mutex_idx = find_mutex(t, &id);
  417. if (lock_counters[mutex_idx] > 0) {
  418. /* mutex is already locked by this process */
  419. lock_counters[mutex_idx]++;
  420. }
  421. else {
  422. /* the mutex was not locked => lock it and set counter */
  423. lock_get(&locks[mutex_idx]);
  424. lock_counters[mutex_idx] = 1;
  425. }
  426. return 1;
  427. }
  428. int unlock_extra_attrs(struct sip_msg* msg, char *_table, char* _id)
  429. {
  430. str id;
  431. registered_table_t *t;
  432. int mutex_idx;
  433. t = (registered_table_t *)_table;
  434. if ((!t) || (get_str_fparam(&id, msg, (fparam_t*)_id) < 0)) {
  435. ERR("invalid parameter value\n");
  436. return -1;
  437. }
  438. /* find right mutex according to id/table */
  439. mutex_idx = find_mutex(t, &id);
  440. if (lock_counters[mutex_idx] > 1) {
  441. /* mutex is locked more times by this process */
  442. lock_counters[mutex_idx]--;
  443. }
  444. else if (lock_counters[mutex_idx] == 1) {
  445. /* the mutex is locked once => unlock it and reset counter */
  446. lock_release(&locks[mutex_idx]);
  447. lock_counters[mutex_idx] = 0;
  448. }
  449. else {
  450. BUG("trying to unlock without lock group=\"%s\" id=\"%.*s\"\n", t->id, id.len, id.s);
  451. }
  452. return 1;
  453. }