virtual_subscription.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. #include "rl_subscription.h"
  2. #include "../../mem/mem.h"
  3. #include "../../mem/shm_mem.h"
  4. #include <xcap/resource_list.h>
  5. #include "rls_mod.h"
  6. #include "result_codes.h"
  7. #include <cds/dstring.h>
  8. #include <cds/logger.h>
  9. #include <presence/qsa.h>
  10. #include <presence/pres_doc.h>
  11. #include <presence/pidf.h>
  12. #include <cds/list.h>
  13. #include "rls_data.h"
  14. #include "rls_auth.h"
  15. /* shared structure holding the data */
  16. typedef struct {
  17. virtual_subscription_t *first;
  18. virtual_subscription_t *last;
  19. /* hash, ... */
  20. notifier_domain_t *domain;
  21. qsa_content_type_t *ct_presence_info;
  22. qsa_content_type_t *ct_raw;
  23. } vs_data_t;
  24. static vs_data_t *vsd = NULL;
  25. /******** global functions (initialization) ********/
  26. int vs_init()
  27. {
  28. static str presence_info = STR_STATIC_INIT(CT_PRESENCE_INFO);
  29. static str raw = STR_STATIC_INIT(CT_RAW);
  30. vsd = (vs_data_t*)mem_alloc(sizeof(vs_data_t));
  31. if (!vsd) {
  32. LOG(L_ERR, "vs_init(): memory allocation error\n");
  33. return -1;
  34. }
  35. vsd->first = NULL;
  36. vsd->last = NULL;
  37. vsd->domain = qsa_get_default_domain();
  38. if (!vsd->domain) {
  39. LOG(L_ERR, "vs_init(): can't register notifier domain\n");
  40. return -1;
  41. }
  42. DEBUG_LOG("QSA (vs) domain: %p\n", vsd->domain);
  43. vsd->ct_presence_info = register_content_type(vsd->domain,
  44. &presence_info, (destroy_function_f)free_presentity_info);
  45. if (!vsd->ct_presence_info) {
  46. ERR("can't register QSA content type\n");
  47. return -1;
  48. }
  49. else TRACE("RLS_PRESENCE_INFO: %p\n", vsd->ct_presence_info);
  50. vsd->ct_raw = register_content_type(vsd->domain,
  51. &raw, (destroy_function_f)free_raw_presence_info);
  52. if (!vsd->ct_raw) {
  53. ERR("can't register QSA content type\n");
  54. return -1;
  55. }
  56. else TRACE("RLS_RAW: %p\n", vsd->ct_raw);
  57. return 0;
  58. }
  59. int vs_destroy()
  60. {
  61. /* virtual subscriptions are freed in rls_free */
  62. if (vsd) {
  63. qsa_release_domain(vsd->domain);
  64. vsd->domain = NULL;
  65. mem_free(vsd);
  66. vsd = NULL;
  67. }
  68. return 0;
  69. }
  70. /******** Helper functions ********/
  71. /* sets new documents (frees them if equal) */
  72. static void set_vs_document(virtual_subscription_t *vs,
  73. str_t *new_doc,
  74. str_t *new_content_type)
  75. {
  76. if (str_case_equals(&vs->state_document, new_doc) == 0) {
  77. /* DEBUG("new document is equal to the older one\n"); */
  78. str_free_content(new_doc);
  79. }
  80. else {
  81. str_free_content(&vs->state_document);
  82. if (new_doc) vs->state_document = *new_doc;
  83. else str_clear(&vs->state_document);
  84. vs->changed = 1;
  85. }
  86. if (str_case_equals(&vs->content_type, new_content_type) == 0) {
  87. /* DEBUG("new content-type is equal to the older one\n"); */
  88. str_free_content(new_content_type);
  89. }
  90. else {
  91. str_free_content(&vs->content_type);
  92. if (new_content_type) vs->content_type = *new_content_type;
  93. else str_clear(&vs->content_type);
  94. vs->changed = 1;
  95. }
  96. }
  97. /* duplicates documents if changed */
  98. static int set_vs_document_dup(virtual_subscription_t *vs,
  99. str_t *new_doc,
  100. str_t *new_content_type)
  101. {
  102. if (str_case_equals(&vs->state_document, new_doc) == 0) {
  103. /* DEBUG("new document is equal to the older one\n"); */
  104. }
  105. else {
  106. str_free_content(&vs->state_document);
  107. str_dup(&vs->state_document, new_doc);
  108. vs->changed = 1;
  109. }
  110. if (str_case_equals(&vs->content_type, new_content_type) == 0) {
  111. /* DEBUG("new content-type is equal to the older one\n"); */
  112. }
  113. else {
  114. str_free_content(&vs->content_type);
  115. str_dup(&vs->content_type, new_content_type);
  116. vs->changed = 1;
  117. }
  118. return 0;
  119. }
  120. static void propagate_change(virtual_subscription_t *vs)
  121. {
  122. if (vs->subscription->type == rls_internal_subscription) {
  123. /* propagate change to higher level */
  124. rls_generate_notify(vs->subscription, 1);
  125. }
  126. else {
  127. /* external subscriptions will send NOTIFY only sometimes
  128. * => we mark it as changed now */
  129. vs->subscription->changed++;
  130. /* FIXME: put this subscription in some queue? (needs remove from it
  131. * when freeing!) */
  132. if (rls) rls->changed_subscriptions++; /* change indicator */
  133. }
  134. }
  135. void process_rls_notification(virtual_subscription_t *vs, client_notify_info_t *info)
  136. {
  137. presentity_info_t *pinfo;
  138. raw_presence_info_t *raw;
  139. str_t new_doc = STR_NULL;
  140. str_t new_type = STR_NULL;
  141. subscription_status_t old_status;
  142. if ((!vs) || (!info)) return;
  143. DBG("Processing notification for VS %p\n", vs);
  144. /* FIXME: put information from more sources together ? */
  145. old_status = vs->status;
  146. switch (info->status) {
  147. case qsa_subscription_active:
  148. vs->status = subscription_active;
  149. break;
  150. case qsa_subscription_pending:
  151. vs->status = subscription_pending;
  152. break;
  153. case qsa_subscription_rejected:
  154. vs->status = subscription_terminated;
  155. break;
  156. case qsa_subscription_terminated:
  157. vs->status = subscription_terminated;
  158. break;
  159. }
  160. if (old_status != vs->status) vs->changed = 1;
  161. if (info->content_type == vsd->ct_raw) {
  162. DEBUG("Processing raw notification\n");
  163. raw = (raw_presence_info_t*)info->data;
  164. if (!raw) return;
  165. /* document MUST be duplicated !!! */
  166. if (set_vs_document_dup(vs, &raw->pres_doc, &raw->content_type) < 0) {
  167. ERR("can't set new status document for VS %p\n", vs);
  168. return;
  169. }
  170. }
  171. else {
  172. if (info->content_type == vsd->ct_presence_info) {
  173. DEBUG("Processing structured notification\n");
  174. pinfo = (presentity_info_t*)info->data;
  175. if (!pinfo) {
  176. str_clear(&new_doc);
  177. str_clear(&new_type);
  178. }
  179. else {
  180. if (create_pidf_document(pinfo, &new_doc, &new_type) < 0) {
  181. ERR("can't create PIDF document\n");
  182. str_free_content(&vs->state_document);
  183. str_free_content(&vs->content_type);
  184. return;
  185. }
  186. set_vs_document(vs, &new_doc, &new_type);
  187. }
  188. }
  189. else {
  190. if (info->content_type)
  191. ERR("received unacceptable notification (%.*s)\n",
  192. FMT_STR(info->content_type->name));
  193. else ERR("received unacceptable notification without content type\n");
  194. str_free_content(&vs->state_document);
  195. str_free_content(&vs->content_type);
  196. return;
  197. }
  198. }
  199. if (vs->changed) propagate_change(vs);
  200. }
  201. void process_internal_notify(virtual_subscription_t *vs,
  202. str_t *new_state_document,
  203. str_t *new_content_type)
  204. {
  205. if (!vs) return;
  206. DBG("Processing internal notification for VS %p\n", vs);
  207. /* don't copy document - use it directly */
  208. set_vs_document(vs, new_state_document, new_content_type);
  209. if (vs->changed) propagate_change(vs);
  210. }
  211. #if 0
  212. static void mark_as_modified(virtual_subscription_t *vs)
  213. {
  214. rl_subscription_t *rls = vs->subscription;
  215. switch (rls->type) {
  216. case rls_external_subscription:
  217. if (sm_subscription_pending(&rls->u.external) == 0) {
  218. /* pending subscription will not be notified */
  219. return;
  220. }
  221. break;
  222. case rls_internal_subscription:
  223. /* FIXME: something like above? */
  224. break;
  225. }
  226. /* NOTIFY should be send only for nonpending subscriptions (or active?)*/
  227. vs->subscription->changed++;
  228. DEBUG_LOG("RL subscription status changed (%p, %d)\n",
  229. rls, rls->changed);
  230. }
  231. static void vs_timer_cb(unsigned int ticks, void *param)
  232. {
  233. virtual_subscription_t *vs;
  234. int changed = 0;
  235. int cntr = 0;
  236. time_t start, stop;
  237. start = time(NULL);
  238. rls_lock();
  239. /* process all messages for virtual subscriptions */
  240. vs = vsd->first;
  241. while (vs) {
  242. if (process_vs_messages(vs) > 0) {
  243. DEBUG_LOG("VS status changed\n");
  244. mark_as_modified(vs);
  245. changed = 1;
  246. }
  247. vs = vs->next;
  248. cntr++; /* debugging purposes */
  249. }
  250. /* TRACE_LOG("processed messages for %d virtual subscription(s)\n", cntr); */
  251. if (changed) {
  252. /* this could be called from some rli_timer ? */
  253. notify_all_modified();
  254. }
  255. rls_unlock();
  256. stop = time(NULL);
  257. if (stop - start > 1) WARN("vs_timer_cb took %d secs\n", (int) (stop - start));
  258. }
  259. #endif
  260. static int add_to_vs_list(virtual_subscription_t *vs)
  261. {
  262. if (!vs) return RES_INTERNAL_ERR;
  263. if (!vsd) {
  264. LOG(L_ERR, "vs_add(): vsd not set!\n");
  265. return RES_INTERNAL_ERR;
  266. }
  267. DOUBLE_LINKED_LIST_ADD(vsd->first, vsd->last, vs);
  268. return RES_OK;
  269. }
  270. static int remove_from_vs_list(virtual_subscription_t *vs)
  271. {
  272. if (!vs) return RES_INTERNAL_ERR;
  273. if (!vsd) {
  274. LOG(L_ERR, "vs_remove(): vsd not set!\n");
  275. return RES_INTERNAL_ERR;
  276. }
  277. DOUBLE_LINKED_LIST_REMOVE(vsd->first, vsd->last, vs);
  278. return RES_OK;
  279. }
  280. int xcap_query_rls_services(xcap_query_params_t *xcap_params,
  281. const str *uri, const str *package,
  282. flat_list_t **dst)
  283. {
  284. if (dst) *dst = NULL;
  285. if (reduce_xcap_needs)
  286. return get_rls_from_full_doc(uri, xcap_params, package, dst);
  287. else
  288. return get_rls(uri, xcap_params, package, dst);
  289. }
  290. static int create_subscriptions(virtual_subscription_t *vs, int nesting_level)
  291. {
  292. /* create concrete local subscription */
  293. str *package = NULL;
  294. str *subscriber = NULL;
  295. flat_list_t *flat = NULL;
  296. package = rls_get_package(vs->subscription);
  297. DEBUG_LOG("creating local subscription to %.*s\n", FMT_STR(vs->uri));
  298. if ((nesting_level != 0) &&
  299. (xcap_query_rls_services(&vs->subscription->xcap_params,
  300. &vs->uri, package, &flat) == 0)) {
  301. if (nesting_level > 0) nesting_level--;
  302. /* it is resource list -> do internal subscription to RLS */
  303. if (rls_create_internal_subscription(vs,
  304. &vs->local_subscription_list, flat,
  305. nesting_level) != 0) {
  306. ERR("can't create internal subscription\n");
  307. free_flat_list(flat);
  308. return -1;
  309. }
  310. free_flat_list(flat);
  311. vs->status = subscription_active;
  312. /* FIXME: rls_authorize_subscription(vs->local_subscription_list); */
  313. }
  314. else {
  315. /* fill QSA subscription data */
  316. clear_subscription_data(&vs->local_subscription_pres_data);
  317. vs->local_subscription_pres_data.dst = &rls->notify_mq;
  318. vs->local_subscription_pres_data.record_id = vs->uri;
  319. subscriber = rls_get_subscriber(vs->subscription);
  320. vs->local_subscription_pres_data.subscriber_data = vs;
  321. if (subscriber)
  322. vs->local_subscription_pres_data.subscriber_id = *subscriber;
  323. /* not RLS record -> do QSA subscription to given package */
  324. vs->local_subscription_pres = subscribe(vsd->domain,
  325. package, &vs->local_subscription_pres_data);
  326. if (!vs->local_subscription_pres) {
  327. LOG(L_ERR, "can't create local subscription (pres)!\n");
  328. return -1;
  329. }
  330. }
  331. return 0;
  332. }
  333. /******** VS manipulation ********/
  334. int vs_create(str *uri,
  335. virtual_subscription_t **dst,
  336. display_name_t *dnames,
  337. rl_subscription_t *subscription,
  338. int nesting_level)
  339. {
  340. int res;
  341. display_name_t *d;
  342. if (!dst) return RES_INTERNAL_ERR;
  343. *dst = NULL;
  344. if (!uri) {
  345. LOG(L_ERR, "vs_create(): no uri given\n");
  346. return RES_INTERNAL_ERR;
  347. }
  348. if ((!uri->s) || (uri->len < 1)) {
  349. LOG(L_ERR, "vs_create(): no uri given\n");
  350. return RES_INTERNAL_ERR;
  351. }
  352. *dst = (virtual_subscription_t*)mem_alloc(sizeof(virtual_subscription_t) + uri->len + 1);
  353. if (!(*dst)) {
  354. LOG(L_ERR, "vs_create(): can't allocate memory\n");
  355. return RES_MEMORY_ERR;
  356. }
  357. (*dst)->next = NULL;
  358. (*dst)->prev = NULL;
  359. vector_init(&(*dst)->display_names, sizeof(vs_display_name_t), 4);
  360. memcpy((*dst)->uri_str, uri->s, uri->len);
  361. (*dst)->uri.s = (*dst)->uri_str;
  362. (*dst)->uri.len = uri->len;
  363. (*dst)->state_document.len = 0;
  364. (*dst)->state_document.s = NULL;
  365. (*dst)->content_type.len = 0;
  366. (*dst)->content_type.s = NULL;
  367. (*dst)->status = subscription_pending;
  368. (*dst)->local_subscription_pres = NULL;
  369. (*dst)->local_subscription_list = NULL;
  370. (*dst)->subscription = subscription;
  371. (*dst)->changed = 0;
  372. generate_db_id(&(*dst)->dbid, *dst);
  373. add_to_vs_list(*dst);
  374. DBG("created VS %p to %.*s\n", *dst, uri->len, uri->s);
  375. res = create_subscriptions(*dst, nesting_level);
  376. if (res != 0) {
  377. vs_free(*dst);
  378. return res;
  379. }
  380. /* TODO: remember the list of Accept headers from client subscribe
  381. * it will be used for Back-End subscriptions */
  382. /* add names */
  383. if (dnames) {
  384. d = SEQUENCE_FIRST(dnames);
  385. while (d) {
  386. vs_add_display_name((*dst), d->name, d->lang);
  387. d = SEQUENCE_NEXT(d);
  388. }
  389. }
  390. return RES_OK;
  391. }
  392. int vs_add_display_name(virtual_subscription_t *vs, const char *name, const char *lang)
  393. {
  394. vs_display_name_t dn;
  395. if (name) {
  396. dn.name.len = strlen(name);
  397. if (dn.name.len > 0) {
  398. dn.name.s = (char *)mem_alloc(dn.name.len);
  399. if (!dn.name.s) dn.name.len = 0;
  400. else memcpy(dn.name.s, name, dn.name.len);
  401. }
  402. }
  403. else {
  404. dn.name.len = 0;
  405. dn.name.s = NULL;
  406. }
  407. if (lang) {
  408. dn.lang.len = strlen(lang);
  409. if (dn.lang.len > 0) {
  410. dn.lang.s = (char *)mem_alloc(dn.lang.len);
  411. if (!dn.lang.s) dn.lang.len = 0;
  412. else memcpy(dn.lang.s, lang, dn.lang.len);
  413. }
  414. }
  415. else {
  416. dn.lang.len = 0;
  417. dn.lang.s = NULL;
  418. }
  419. /* TRACE_LOG("adding display name: %s\n", name);*/
  420. return vector_add(&vs->display_names, &dn);
  421. }
  422. void vs_free(virtual_subscription_t *vs)
  423. {
  424. int i, cnt;
  425. vs_display_name_t dn;
  426. if (vs) {
  427. if (vs->local_subscription_pres)
  428. unsubscribe(vsd->domain, vs->local_subscription_pres);
  429. if (vs->local_subscription_list)
  430. rls_remove(vs->local_subscription_list);
  431. /* remove notification messages for given subscription */
  432. destroy_notifications(vs->local_subscription_pres);
  433. remove_from_vs_list(vs);
  434. str_free_content(&vs->state_document);
  435. str_free_content(&vs->content_type);
  436. /* if ( (vs->package.len > 0) && (vs->package.s) )
  437. mem_free(vs->package.s); */
  438. cnt = vector_size(&vs->display_names);
  439. for (i = 0; i < cnt; i++) {
  440. if (vector_get(&vs->display_names, i, &dn) != 0) continue;
  441. if (dn.name.s && (dn.name.len > 0)) mem_free(dn.name.s);
  442. if (dn.lang.s && (dn.lang.len > 0)) mem_free(dn.lang.s);
  443. }
  444. vector_destroy(&vs->display_names);
  445. mem_free(vs);
  446. /* LOG(L_TRACE, "Virtual Subscription freed\n");*/
  447. }
  448. }