offline_winfo.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
  1. /* offline presence authorization "requests" e.g. storing
  2. * watcher information for offline presentities */
  3. #include <stdio.h>
  4. #include "../../str.h"
  5. #include "../../dprint.h"
  6. #include "../../mem/mem.h"
  7. #include "dlist.h"
  8. #include "presentity.h"
  9. #include "watcher.h"
  10. #include "pdomain.h"
  11. #include "pa_mod.h"
  12. #include "../../parser/parse_from.h"
  13. #include <libxml/parser.h>
  14. #include <libxml/xpath.h>
  15. #include <presence/pidf.h>
  16. #include <cds/logger.h>
  17. #include <time.h>
  18. #include "offline_winfo.h"
  19. #include "winfo_doc.h"
  20. #include "message.h"
  21. /* ----- Helper and internal functions ----- */
  22. #define add_str_len(len,p) if (p) if (p->s) len += p->len
  23. #define set_member_str(buf,len,dst,src) if (src) if (src->s) { \
  24. memcpy(buf + len, src->s, src->len); \
  25. dst.s = buf + len; \
  26. dst.len = src->len; \
  27. len += src->len; \
  28. }
  29. #define string_val(v,s) (v).type = DB_STR; \
  30. (v).val.str_val=s; \
  31. (v).nul=(s.len == 0);
  32. #define time_val(v,t) (v).type = DB_DATETIME; \
  33. (v).val.time_val=t;\
  34. (v).nul=0;
  35. #define get_str_val(rvi,dst) do{if(!rvi.nul){dst.s=(char*)rvi.val.string_val;dst.len=strlen(dst.s);}}while(0)
  36. #define get_blob_val(rvi,dst) do{if(!rvi.nul){dst=rvi.val.blob_val;}else dst.len=0;}while(0)
  37. #define get_time_val(rvi,dst) do{if(!rvi.nul){dst=rvi.val.time_val;}}while(0)
  38. #define get_int_val(rvi,dst) do{if(!rvi.nul){dst=rvi.val.int_val;}else dst=0;}while(0)
  39. /* expiration time in secs */
  40. int offline_winfo_expiration = 259200;
  41. /* status of last subscription */
  42. static watcher_status_t last_subscription_status = WS_PENDING;
  43. void set_last_subscription_status(watcher_status_t status)
  44. {
  45. last_subscription_status = status;
  46. }
  47. watcher_status_t get_last_subscription_status()
  48. {
  49. return last_subscription_status;
  50. }
  51. static offline_winfo_t *create_winfo(str *uid,
  52. str *wuri,
  53. str *events,
  54. str *domain,
  55. str *status)
  56. {
  57. int len = 0;
  58. offline_winfo_t *info;
  59. add_str_len(len, uid);
  60. add_str_len(len, wuri);
  61. add_str_len(len, events);
  62. add_str_len(len, domain);
  63. add_str_len(len, status);
  64. len += sizeof(offline_winfo_t);
  65. info = (offline_winfo_t*)mem_alloc(len);
  66. if (info) {
  67. memset(info, 0, len);
  68. len = 0;
  69. set_member_str(info->buffer, len, info->uid, uid);
  70. set_member_str(info->buffer, len, info->watcher, wuri);
  71. set_member_str(info->buffer, len, info->events, events);
  72. set_member_str(info->buffer, len, info->domain, domain);
  73. set_member_str(info->buffer, len, info->status, status);
  74. info->created = time(NULL);
  75. info->expires = info->created + offline_winfo_expiration;
  76. info->index = -1;
  77. }
  78. return info;
  79. }
  80. static inline void free_winfo(offline_winfo_t *info)
  81. {
  82. if (info) mem_free(info);
  83. }
  84. static inline void free_winfos(offline_winfo_t *info)
  85. {
  86. offline_winfo_t *n;
  87. while (info) {
  88. n = info->next;
  89. free_winfo(info);
  90. info = n;
  91. }
  92. }
  93. static int db_store_winfo(offline_winfo_t *info)
  94. {
  95. /* ignore duplicit records (should be stored only once!) */
  96. db_key_t cols[20];
  97. db_val_t vals[20];
  98. int n = -1;
  99. if (!pa_db) {
  100. ERR("database not initialized: set parameter \'use_offline_winfo\' to 1\n");
  101. return -1;
  102. }
  103. if (pa_dbf.use_table(pa_db, offline_winfo_table) < 0) {
  104. LOG(L_ERR, "db_add_watcher: Error in use_table\n");
  105. return -1;
  106. }
  107. cols[++n] = col_uid;
  108. string_val(vals[n], info->uid);
  109. cols[++n] = col_watcher;
  110. string_val(vals[n], info->watcher);
  111. cols[++n] = col_events;
  112. string_val(vals[n], info->events);
  113. cols[++n] = col_domain;
  114. string_val(vals[n], info->domain);
  115. cols[++n] = col_status;
  116. string_val(vals[n], info->status);
  117. cols[++n] = col_created_on;
  118. time_val(vals[n], info->created);
  119. cols[++n] = col_expires_on;
  120. time_val(vals[n], info->expires);
  121. /* index ("dbid") is created automaticaly ! */
  122. /* insert new record into database */
  123. if (pa_dbf.insert(pa_db, cols, vals, n + 1) < 0) {
  124. return -1;
  125. }
  126. return 0;
  127. }
  128. static int get_watcher_uri(struct sip_msg* _m, str* uri)
  129. {
  130. struct sip_uri puri;
  131. int res = 0;
  132. uri->s = get_from(_m)->uri.s;
  133. uri->len = get_from(_m)->uri.len;
  134. if (parse_uri(uri->s, uri->len, &puri) < 0) {
  135. LOG(L_ERR, "Error while parsing URI\n");
  136. return -1;
  137. }
  138. #if 0
  139. uri->s = puri.user.s;
  140. if ((!uri->s) || (puri.user.len < 1)) {
  141. uri->s = puri.host.s;
  142. uri->len = puri.host.len;
  143. res = 1; /* it is uri without username ! */
  144. }
  145. #endif
  146. uri->len = puri.host.s + puri.host.len - uri->s;
  147. return res;
  148. }
  149. static int get_events(struct sip_msg* _m, str* events)
  150. {
  151. char *c;
  152. str_clear(events);
  153. if (parse_headers(_m, HDR_EVENT_F, 0) == -1) {
  154. ERR("Error while parsing headers\n");
  155. return -1;
  156. }
  157. if (_m->event) {
  158. /* parse_event(_m->event); */
  159. *events = _m->event->body;
  160. c = str_strchr(events, ';');
  161. if (c) events->len = c - events->s;
  162. }
  163. return 0;
  164. }
  165. int remove_expired_winfos()
  166. {
  167. db_key_t keys[] = { col_expires_on };
  168. db_val_t vals[1] = {
  169. { DB_DATETIME, 0, { .time_val = time(NULL) } }
  170. };
  171. db_op_t ops[] = { OP_LEQ };
  172. int res = 0;
  173. if (!pa_db) {
  174. ERR("database not initialized: set parameter \'use_offline_winfo\' to 1\n");
  175. return -1;
  176. }
  177. if (pa_dbf.use_table(pa_db, offline_winfo_table) < 0) {
  178. LOG(L_ERR, "db_add_watcher: Error in use_table\n");
  179. return -1;
  180. }
  181. res = pa_dbf.delete(pa_db, keys, ops, vals, 1);
  182. if (res < 0 )
  183. DBG("ERROR cleaning expired offline winfo\n");
  184. return res;
  185. }
  186. int db_remove_winfos(offline_winfo_t *info)
  187. {
  188. db_key_t keys[] = { col_dbid };
  189. db_val_t vals[1];
  190. db_op_t ops[] = { OP_EQ };
  191. int res = 0;
  192. if (!pa_db) {
  193. ERR("database not initialized: set parameter \'use_offline_winfo\' to 1\n");
  194. return -1;
  195. }
  196. if (pa_dbf.use_table(pa_db, offline_winfo_table) < 0) {
  197. LOG(L_ERR, "Error in use_table\n");
  198. return -1;
  199. }
  200. while (info) {
  201. vals[0].type = DB_INT;
  202. vals[0].nul = 0;
  203. vals[0].val.int_val = info->index;
  204. res = pa_dbf.delete(pa_db, keys, ops, vals, 1);
  205. if (res < 0 )
  206. DBG("ERROR cleaning expired offline winfo\n");
  207. info = info->next;
  208. }
  209. return res;
  210. }
  211. static void send_winfo_cb(struct cell* t, int type, struct tmcb_params* params)
  212. {
  213. offline_winfo_t *info = NULL;
  214. if (!params) {
  215. ERR("BUG: empty arg\n");
  216. return;
  217. }
  218. if (params->param) info = (offline_winfo_t *)*(params->param);
  219. if (!info) {
  220. ERR("BUG: empty arg\n");
  221. return;
  222. }
  223. if ((params->code >= 200) && (params->code < 300)) {
  224. /* delete infos from DB */
  225. db_remove_winfos(info);
  226. }
  227. else
  228. ERR("%d response on winfo NOTIFY\n", params->code);
  229. /* delete infos from memory */
  230. free_winfos(info);
  231. }
  232. static int send_winfo(presentity_t *p, offline_winfo_t *info)
  233. {
  234. watcher_t *w;
  235. if (!p) {
  236. ERR("BUG: trying to send offline winfo to empty presentity\n");
  237. return -1;
  238. }
  239. w = p->first_winfo_watcher;
  240. while (w) {
  241. if (w->status == WS_ACTIVE) {
  242. if (send_winfo_notify_offline(p, w, info, send_winfo_cb, info) == 0)
  243. return 0;
  244. }
  245. w = w->next;
  246. }
  247. return -1; /* impossible to send it */
  248. }
  249. int db_load_winfo(str *uid, str *events, str *domain, offline_winfo_t **infos)
  250. {
  251. int i, r = 0;
  252. db_res_t *res = NULL;
  253. db_key_t result_cols[] = {
  254. col_watcher, col_created_on, col_expires_on, col_dbid, col_status
  255. };
  256. db_key_t keys[] = { col_uid, col_events };
  257. db_op_t ops[] = { OP_EQ, OP_EQ };
  258. db_val_t k_vals[] = {
  259. { DB_STR, 0, { .str_val = *uid } }
  260. };
  261. offline_winfo_t *info = NULL;
  262. offline_winfo_t *last = NULL;
  263. *infos = NULL;
  264. if (pa_dbf.use_table(pa_db, offline_winfo_table) < 0) {
  265. ERR("Error in use_table\n");
  266. return -1;
  267. }
  268. if (pa_dbf.query (pa_db, keys, ops, k_vals,
  269. result_cols, 1, sizeof(result_cols) / sizeof(db_key_t),
  270. 0, &res) < 0) {
  271. ERR("Error while querying stored winfos\n");
  272. r = -1;
  273. res = NULL;
  274. }
  275. if (res) {
  276. for (i = 0; i < res->n; i++) {
  277. db_row_t *row = &res->rows[i];
  278. db_val_t *row_vals = ROW_VALUES(row);
  279. str watcher = STR_NULL;
  280. str status = STR_NULL;
  281. time_t created_on = 0;
  282. time_t expires_on = 0;
  283. int index = 0;
  284. get_str_val(row_vals[0], watcher);
  285. get_time_val(row_vals[1], created_on);
  286. get_time_val(row_vals[2], expires_on);
  287. get_int_val(row_vals[3], index);
  288. get_str_val(row_vals[4], status);
  289. info = create_winfo(uid, &watcher, events, domain, &status);
  290. if (!info) {
  291. r = -1;
  292. break;
  293. }
  294. info->created = created_on;
  295. info->expires = expires_on;
  296. info->index = index;
  297. if (last) last->next = info;
  298. else *infos = info;
  299. last = info;
  300. }
  301. pa_dbf.free_result(pa_db, res);
  302. }
  303. if ((*infos) && (r != 0)) {
  304. free_winfos(*infos);
  305. *infos = NULL;
  306. }
  307. return r;
  308. }
  309. /* ----- Handler functions ----- */
  310. #if 0
  311. /* not used due to problems with lost AVP after sending NOTIFY */
  312. static int get_status(str *dst)
  313. {
  314. avp_t *avp;
  315. int_str name, val;
  316. struct search_state s;
  317. str avp_subscription_status = STR_STATIC_INIT("subscription_status");
  318. /* if (!dst) return -1; */
  319. name.s = avp_subscription_status;
  320. avp = search_first_avp(AVP_CLASS_USER |
  321. AVP_TRACK_FROM | AVP_NAME_STR | AVP_VAL_STR, name, &val, 0);
  322. if (avp) {
  323. /* don't use default - use value from AVP */
  324. TRACE("subscription status = %.*s\n", FMT_STR(val.s));
  325. *dst = val.s;
  326. return 0;
  327. }
  328. else {
  329. /* leave default value!! */
  330. /* TRACE("left default subscription status\n"); */
  331. TRACE("subscription status AVP not found\n");
  332. }
  333. return 1;
  334. }
  335. #endif
  336. static void get_status_str(str *dst)
  337. {
  338. str s;
  339. switch(get_last_subscription_status()) {
  340. case WS_ACTIVE:
  341. s = watcher_status_names[WS_ACTIVE];
  342. break;
  343. case WS_REJECTED:
  344. case WS_PENDING_TERMINATED:
  345. case WS_TERMINATED:
  346. s = watcher_status_names[WS_TERMINATED];
  347. break;
  348. case WS_PENDING:
  349. s = watcher_status_names[WS_PENDING];
  350. break;
  351. default: str_clear(&s); /* throw out gcc complains */
  352. }
  353. if (dst) *dst = s;
  354. }
  355. int store_offline_winfo(struct sip_msg* _m, char* _domain, char* _table)
  356. {
  357. str uid = STR_NULL;
  358. str wuri = STR_NULL;
  359. str events = STR_NULL;
  360. str domain = STR_NULL;
  361. str status = STR_NULL;
  362. int res = -1;
  363. offline_winfo_t *info;
  364. if (get_presentity_uid(&uid, _m) < 0) {
  365. ERR("Error while extracting presentity UID\n");
  366. return 0; /* ??? impossible to return -1 or 1 */
  367. }
  368. get_watcher_uri(_m, &wuri);
  369. get_events(_m, &events);
  370. if (_domain) {
  371. domain.s = _domain;
  372. domain.len = strlen(_domain);
  373. }
  374. /* get stored subscription status value */
  375. get_status_str(&status);
  376. /* TRACE("subscription status is: %.*s\n", FMT_STR(status)); */
  377. info = create_winfo(&uid, &wuri, &events, &domain, &status);
  378. /* store it into database or use internal data structures too? */
  379. /* better to use only database because of lower memory usage - this
  380. * information could be stored for very long time ! */
  381. db_store_winfo(info);
  382. free_winfo(info); /* don't hold this information in memory ! */
  383. return res;
  384. }
  385. /* send offline winfo as regular watcher info NOTIFY if possible
  386. * (for presentity got from get_to) */
  387. int dump_offline_winfo(struct sip_msg* _m, char* _domain, char* _events)
  388. {
  389. struct pdomain* d;
  390. struct presentity *p;
  391. str uid = STR_NULL;
  392. int res = -1;
  393. str events;
  394. offline_winfo_t *info;
  395. d = (struct pdomain*)_domain;
  396. if (get_presentity_uid(&uid, _m) < 0) {
  397. ERR("Error while extracting presentity UID\n");
  398. return -1;
  399. }
  400. if (_events) {
  401. events.s = _events;
  402. events.len = strlen(_events);
  403. }
  404. if (db_load_winfo(&uid, &events, d->name, &info) != 0) {
  405. return -1;
  406. }
  407. if (!info) {
  408. return 1; /* nothing to do */
  409. }
  410. lock_pdomain(d);
  411. if (find_presentity_uid(d, &uid, &p) == 0) {
  412. /* presentity found */
  413. if (send_winfo(p, info) == 0) res = 1;
  414. else res = -1;
  415. }
  416. unlock_pdomain(d);
  417. return res;
  418. }
  419. void offline_winfo_timer(unsigned int ticks, void* param)
  420. {
  421. remove_expired_winfos();
  422. }
  423. int check_subscription_status(struct sip_msg* _m, char* _status, char* _x)
  424. {
  425. watcher_status_t status = (watcher_status_t)_status;
  426. if (status == get_last_subscription_status()) return 1;
  427. else return -1;
  428. }
  429. /* convert char* parameter to watcher_status_t */
  430. int check_subscription_status_fix(void **param, int param_no)
  431. {
  432. watcher_status_t status = WS_PENDING;
  433. char *s;
  434. str ss;
  435. if (param_no == 1) {
  436. s = (char*)*param;
  437. if (!s) {
  438. ERR("status not given!\n");
  439. return -1;
  440. }
  441. /* TRACE("status name is %s\n", (char*)*param); */
  442. ss.s = s;
  443. ss.len = strlen(s);
  444. status = watcher_status_from_string(&ss);
  445. *param = (void*)status;
  446. }
  447. return 0;
  448. }