rpc.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. #include "../../error.h"
  2. #include "../../parser/parse_event.h"
  3. #include "pdomain.h"
  4. #include "dlist.h"
  5. #include <cds/sstr.h>
  6. #include <time.h>
  7. #include "qsa_interface.h"
  8. #include "pa_mod.h"
  9. #include <cds/logger.h>
  10. #include <cds/dbid.h>
  11. #include <presence/pidf.h>
  12. #include "publish.h"
  13. extern dlist_t* root; /* FIXME ugly !!!!! */
  14. /* #define rpc_lf(rpc, c) rpc->add(c, "s","") */
  15. #define rpc_lf(rpc, c) do { } while (0)
  16. static void trace_tuple(presence_tuple_t *t, rpc_t* rpc, void* c) {
  17. presence_note_t *n;
  18. extension_element_t *ps;
  19. rpc->printf(c, " %.*s contact=\'%.*s\' exp=%u "
  20. "status=%d published=%d (id=%.*s)",
  21. FMT_STR(t->data.id),
  22. FMT_STR(t->data.contact), t->expires - time(NULL),
  23. (int)t->data.status.basic,
  24. t->is_published, FMT_STR(t->published_id));
  25. rpc_lf(rpc, c);
  26. rpc->printf(c, " notes:");
  27. n = t->data.first_note;
  28. while (n) {
  29. rpc->printf(c, " \'%.*s\'", FMT_STR(n->value));
  30. n = n->next;
  31. }
  32. rpc_lf(rpc, c);
  33. rpc->printf(c, " extension elements:");
  34. rpc_lf(rpc, c);
  35. ps = t->data.first_unknown_element;
  36. while (ps) {
  37. rpc_lf(rpc, c);
  38. rpc->printf(c, " %.*s", FMT_STR(ps->element));
  39. rpc_lf(rpc, c);
  40. ps = ps->next;
  41. }
  42. rpc_lf(rpc, c);
  43. rpc->printf(c, " status extension elements:");
  44. rpc_lf(rpc, c);
  45. ps = t->data.status.first_unknown_element;
  46. while (ps) {
  47. rpc_lf(rpc, c);
  48. rpc->printf(c, " %.*s", FMT_STR(ps->element));
  49. rpc_lf(rpc, c);
  50. ps = ps->next;
  51. }
  52. rpc_lf(rpc, c);
  53. rpc->printf(c, "");
  54. }
  55. static void trace_presentity(presentity_t *p, rpc_t* rpc, void* c)
  56. {
  57. watcher_t *w;
  58. presence_tuple_t *t;
  59. internal_pa_subscription_t *iw;
  60. pa_presence_note_t *n;
  61. pa_extension_element_t *ps;
  62. rpc->printf(c, "* %.*s (uid=%.*s)", FMT_STR(p->data.uri),
  63. FMT_STR(p->uuid));
  64. rpc_lf(rpc, c);
  65. rpc->printf(c, " - tuples:");
  66. rpc_lf(rpc, c);
  67. t = get_first_tuple(p);
  68. while (t) {
  69. trace_tuple(t, rpc, c);
  70. t = get_next_tuple(t);
  71. }
  72. rpc->printf(c, " - watchers:");
  73. rpc_lf(rpc, c);
  74. w = p->first_watcher;
  75. while (w) {
  76. rpc->printf(c, " %.*s status=%d exp=%u",
  77. FMT_STR(w->uri), (int)w->status, w->expires - time(NULL));
  78. rpc_lf(rpc, c);
  79. w = w->next;
  80. }
  81. rpc->printf(c, " - winfo watchers:");
  82. rpc_lf(rpc, c);
  83. w = p->first_winfo_watcher;
  84. while (w) {
  85. rpc->printf(c, " %.*s status=%d exp=%u",
  86. FMT_STR(w->uri), (int)w->status, w->expires - time(NULL));
  87. rpc_lf(rpc, c);
  88. w = w->next;
  89. }
  90. rpc->printf(c, " - internal watchers:");
  91. rpc_lf(rpc, c);
  92. iw = p->first_qsa_subscription;
  93. while (iw) {
  94. rpc->printf(c, " %.*s %d",
  95. FMT_STR(*get_subscriber_id(iw->subscription)), (int)iw->status);
  96. rpc_lf(rpc, c);
  97. iw = iw->next;
  98. }
  99. rpc->printf(c, " - notes:");
  100. rpc_lf(rpc, c);
  101. n = get_first_note(p);
  102. while (n) {
  103. rpc->printf(c, " %.*s (%.*s) exp=%s",
  104. FMT_STR(n->data.value), FMT_STR(n->data.lang),
  105. ctime(&n->expires));
  106. n = get_next_note(n);
  107. }
  108. rpc_lf(rpc, c);
  109. rpc->printf(c, " - extension elements:");
  110. rpc_lf(rpc, c);
  111. ps = get_first_extension(p);
  112. while (ps) {
  113. rpc->printf(c, " exp=%d", (int)(ps->expires - time(NULL)));
  114. rpc_lf(rpc, c);
  115. rpc->printf(c, " %.*s", FMT_STR(ps->data.element));
  116. rpc_lf(rpc, c);
  117. ps = get_next_extension(ps);
  118. }
  119. rpc_lf(rpc, c);
  120. }
  121. static void trace_dlist(dlist_t *dl, rpc_t* rpc, void* c, int detailed)
  122. {
  123. presentity_t *p;
  124. int cnt = 0;
  125. if (!dl) return;
  126. if (!dl->d) return;
  127. lock_pdomain(dl->d);
  128. rpc->add(c, "S", dl->d->name);
  129. p = dl->d->first;
  130. while (p) {
  131. if (detailed) trace_presentity(p, rpc, c);
  132. cnt++;
  133. p = p->next;
  134. }
  135. rpc_lf(rpc, c);
  136. rpc->printf(c, "presentity count: %d", cnt);
  137. unlock_pdomain(dl->d);
  138. }
  139. static const char* rpc_trace_doc[] = {
  140. "Display internal data structure.", /* Documentation string */
  141. 0 /* Method signature(s) */
  142. };
  143. static void rpc_trace(rpc_t* rpc, void* c)
  144. {
  145. dlist_t *dl;
  146. int detailed = 0;
  147. if (rpc->scan(c, "d", &detailed) <= 0) {
  148. detailed = 0;
  149. rpc->fault(c, 400, "Invalid argument - number needed");
  150. return;
  151. }
  152. dl = root;
  153. while (dl) {
  154. trace_dlist(dl, rpc, c, detailed);
  155. dl = dl->next;
  156. }
  157. rpc->send(c);
  158. }
  159. static int grant_watcher(presentity_t *p, watcher_t *w)
  160. {
  161. int changed = 0;
  162. switch (w->status) {
  163. case WS_PENDING:
  164. case WS_REJECTED:
  165. w->status = WS_ACTIVE;
  166. changed = 1;
  167. break;
  168. case WS_PENDING_TERMINATED:
  169. w->status = WS_TERMINATED;
  170. changed = 1;
  171. break;
  172. default: break;
  173. }
  174. if (changed) {
  175. w->flags |= WFLAG_SUBSCRIPTION_CHANGED;
  176. if (w->event_package != EVENT_PRESENCE_WINFO)
  177. p->flags |= PFLAG_WATCHERINFO_CHANGED;
  178. }
  179. return 0;
  180. }
  181. static int grant_internal_watcher(presentity_t *p, internal_pa_subscription_t *w)
  182. {
  183. int changed = 0;
  184. switch (w->status) {
  185. case WS_PENDING:
  186. case WS_REJECTED:
  187. w->status = WS_ACTIVE;
  188. changed = 1;
  189. break;
  190. case WS_PENDING_TERMINATED:
  191. w->status = WS_TERMINATED;
  192. changed = 1;
  193. break;
  194. default: break;
  195. }
  196. if (changed) {
  197. /* w->flags |= WFLAG_SUBSCRIPTION_CHANGED; */
  198. notify_internal_watcher(p, w);
  199. p->flags |= PFLAG_WATCHERINFO_CHANGED;
  200. }
  201. return 0;
  202. }
  203. static int grant_watchers(presentity_t *p, str *wuri)
  204. {
  205. watcher_t *w;
  206. internal_pa_subscription_t *iw;
  207. w = p->first_watcher;
  208. while (w) {
  209. if (str_case_equals(&w->uri, wuri) == 0) grant_watcher(p, w);
  210. w = w->next;
  211. }
  212. iw = p->first_qsa_subscription;
  213. while (iw) {
  214. if (str_case_equals(get_subscriber_id(iw->subscription), wuri) == 0)
  215. grant_internal_watcher(p, iw);
  216. iw = iw->next;
  217. }
  218. return 0;
  219. }
  220. static const char* rpc_authorize_doc[] = {
  221. "Authorize watcher.", /* Documentation string */
  222. 0 /* Method signature(s) */
  223. };
  224. static void rpc_authorize(rpc_t* rpc, void* c)
  225. {
  226. pdomain_t *d;
  227. presentity_t *p;
  228. str pstr, wstr, uid;
  229. char* domain;
  230. if (rpc->scan(c, "sSS", &domain, &pstr, &wstr) < 3) {
  231. rpc->fault(c, 400, "Invalid parameter value");
  232. return;
  233. }
  234. if (find_pdomain(domain, &d) != 0) {
  235. rpc->fault(c, 400, "Unknown domain '%s'\n", domain);
  236. return;
  237. }
  238. if (pres_uri2uid(&uid, &pstr) != 0) {
  239. rpc->fault(c, 400, "Unable to convert '%.*s' to UID\n", pstr.len, pstr.s);
  240. return;
  241. }
  242. lock_pdomain(d);
  243. if (find_presentity_uid(d, &pstr, &p) != 0) {
  244. rpc->fault(c, 400, "Presentity '%.*s' not found\n", pstr.len, pstr.s);
  245. unlock_pdomain(d);
  246. str_free_content(&uid);
  247. return;
  248. }
  249. grant_watchers(p, &wstr);
  250. unlock_pdomain(d);
  251. str_free_content(&uid);
  252. }
  253. static void rpc_pa_publish(rpc_t* rpc, void* c)
  254. {
  255. pdomain_t *d;
  256. presentity_t *p;
  257. presentity_info_t *pi = NULL;
  258. str pstr, doc;
  259. char* domain;
  260. str etag = STR_NULL;
  261. time_t expires = time(NULL);
  262. int exp_sec = 0;
  263. int res;
  264. void *st;
  265. dbid_t generated_etag;
  266. xcap_query_params_t xcap_params;
  267. int has_etag = 1;
  268. res = rpc->scan(c, "sSSd", &domain, &pstr, &doc, &exp_sec);
  269. /* TODO: args = domain, uri, presence doc, expires, etag (for republishing) */
  270. if (res < 4) {
  271. rpc->fault(c, 400, "Invalid parameter value (%d)", res);
  272. return;
  273. }
  274. if (rpc->scan(c, "S", &etag) < 1) {
  275. /* ETag was not set, generate a new one */
  276. generate_dbid(generated_etag);
  277. etag.len = dbid_strlen(generated_etag);
  278. etag.s = dbid_strptr(generated_etag);
  279. has_etag = 0;
  280. }
  281. expires += exp_sec;
  282. if (find_pdomain(domain, &d) != 0) {
  283. rpc->fault(c, 400, "Unknown domain '%s'\n", domain);
  284. return;
  285. }
  286. /*
  287. if (pres_uri2uid(&uid, &pstr) != 0) {
  288. rpc->fault(c, 400, "Unable to convert '%.*s' to UID\n", pstr.len, pstr.s);
  289. return;
  290. } */
  291. lock_pdomain(d);
  292. res = find_presentity_uid(d, &pstr, &p);
  293. if (res > 0) {
  294. memset(&xcap_params, 0, sizeof(xcap_params));
  295. if (fill_xcap_params) fill_xcap_params(NULL, &xcap_params);
  296. res = new_presentity(d, &pstr /* BUG !!! */, &pstr, &xcap_params, &p);
  297. }
  298. if (res < 0) {
  299. rpc->fault(c, 400, "Can't create/find presentity '%.*s'\n", pstr.len, pstr.s);
  300. unlock_pdomain(d);
  301. return;
  302. }
  303. if (doc.len > 0) {
  304. if (parse_pidf_document(&pi, doc.s, doc.len) != 0) {
  305. rpc->fault(c, 400, "Can't parse presence document (not PIDF?)\n");
  306. unlock_pdomain(d);
  307. return;
  308. }
  309. }
  310. else pi = NULL;
  311. /* if (pi) { */
  312. if (process_published_presentity_info(p, pi, &etag, expires, has_etag) != 0) {
  313. if (pi) free_presentity_info(pi);
  314. rpc->fault(c, 400, "Can't publish\n");
  315. unlock_pdomain(d);
  316. return;
  317. }
  318. /* } */
  319. if (pi) free_presentity_info(pi);
  320. unlock_pdomain(d);
  321. if (rpc->add(c, "{", &st) < 0) return;
  322. rpc->struct_add(st, "S", "etag", &etag);
  323. rpc->send(c);
  324. }
  325. static const char* rpc_pa_publish_doc[] = {
  326. "Publish presence document.", /* Documentation string */
  327. 0 /* Method signature(s) */
  328. };
  329. /*
  330. * RPC Methods exported by this module
  331. */
  332. rpc_export_t pa_rpc_methods[] = {
  333. {"pa.authorize", rpc_authorize, rpc_authorize_doc, 0},
  334. {"pa.trace", rpc_trace, rpc_trace_doc, 0},
  335. {"pa.publish", rpc_pa_publish, rpc_pa_publish_doc, 0},
  336. {0, 0, 0, 0}
  337. };