nua_event_server.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. /*
  2. * This file is part of the Sofia-SIP package
  3. *
  4. * Copyright (C) 2006 Nokia Corporation.
  5. *
  6. * Contact: Pekka Pessi <pekka.pessi@nokia.com>
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public License
  10. * as published by the Free Software Foundation; either version 2.1 of
  11. * the License, or (at your option) any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful, but
  14. * WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  21. * 02110-1301 USA
  22. *
  23. */
  24. /**@CFILE nua_event_server.c
  25. * @brief Easy event server
  26. *
  27. * @author Pekka Pessi <Pekka.Pessi@nokia.com>
  28. *
  29. * @date Created: Wed Mar 8 11:48:49 EET 2006 ppessi
  30. */
  31. #include "config.h"
  32. #include <stddef.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35. #include <limits.h>
  36. #include <assert.h>
  37. #include <sofia-sip/su_string.h>
  38. #include <sofia-sip/sip_protos.h>
  39. #include <sofia-sip/sip_status.h>
  40. #include <sofia-sip/su_tagarg.h>
  41. #define NEA_SMAGIC_T struct nua_handle_s
  42. #define NEA_EMAGIC_T struct nua_handle_s
  43. #include "nua_stack.h"
  44. /* ======================================================================== */
  45. /* Event server */
  46. static
  47. nea_event_t *nh_notifier_event(nua_handle_t *nh,
  48. su_home_t *home,
  49. sip_event_t const *event,
  50. tagi_t const *tags);
  51. static
  52. void authorize_watcher(nea_server_t *nes,
  53. nua_handle_t *nh,
  54. nea_event_t *ev,
  55. nea_subnode_t *sn,
  56. sip_t const *sip);
  57. void
  58. nua_stack_notifier(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags)
  59. {
  60. su_home_t home[1] = { SU_HOME_INIT(home) };
  61. sip_event_t const *event = NULL;
  62. sip_content_type_t const *ct = NULL;
  63. sip_payload_t const *pl = NULL;
  64. url_string_t const *url = NULL;
  65. char const *event_s = NULL, *ct_s = NULL, *pl_s = NULL;
  66. nea_event_t *ev;
  67. int status = 900;
  68. char const *phrase = nua_internal_error;
  69. nua_stack_init_handle(nua, nh, tags);
  70. tl_gets(tags,
  71. NUTAG_URL_REF(url),
  72. SIPTAG_EVENT_REF(event),
  73. SIPTAG_EVENT_STR_REF(event_s),
  74. SIPTAG_CONTENT_TYPE_STR_REF(ct_s),
  75. SIPTAG_PAYLOAD_REF(pl),
  76. SIPTAG_PAYLOAD_STR_REF(pl_s),
  77. TAG_END());
  78. if (!event && !event_s)
  79. status = 400, phrase = "Missing Event";
  80. else if (!ct && !ct_s)
  81. status = 400, phrase = "Missing Content-Type";
  82. else if (!nh->nh_notifier &&
  83. !(nh->nh_notifier =
  84. nea_server_create(nua->nua_nta, nua->nua_root,
  85. url->us_url,
  86. NH_PGET(nh, max_subscriptions),
  87. NULL, nh,
  88. TAG_NEXT(tags))))
  89. status = 900, phrase = nua_internal_error;
  90. else if (!event && !(event = sip_event_make(home, event_s)))
  91. status = 900, phrase = "Could not create an event header";
  92. else if (!(ev = nh_notifier_event(nh, home, event, tags)))
  93. status = 900, phrase = "Could not create an event view";
  94. else if (nea_server_update(nh->nh_notifier, ev, TAG_NEXT(tags)) < 0)
  95. status = 900, phrase = "No content for event";
  96. else if (nea_server_notify(nh->nh_notifier, ev) < 0)
  97. status = 900, phrase = "Error when notifying watchers";
  98. else
  99. nua_stack_tevent(nua, nh, NULL, e, status = SIP_200_OK,
  100. SIPTAG_EVENT(event),
  101. SIPTAG_CONTENT_TYPE(ct),
  102. TAG_END());
  103. if (status != 200)
  104. nua_stack_event(nua, nh, NULL, e, status, phrase, NULL);
  105. su_home_deinit(home);
  106. }
  107. /* Create a event view for notifier */
  108. static
  109. nea_event_t *nh_notifier_event(nua_handle_t *nh,
  110. su_home_t *home,
  111. sip_event_t const *event,
  112. tagi_t const *tags)
  113. {
  114. nea_event_t *ev = nea_event_get(nh->nh_notifier, event->o_type);
  115. sip_accept_t const *accept = NULL;
  116. char const *accept_s = NULL;
  117. sip_content_type_t const *ct = NULL;
  118. char const *ct_s = NULL;
  119. if (ev == NULL) {
  120. char *o_type, *o_subtype;
  121. char *temp = NULL;
  122. o_type = su_strdup(home, event->o_type);
  123. if (o_type == NULL)
  124. return NULL;
  125. o_subtype = strchr(o_type, '.');
  126. if (o_subtype)
  127. *o_subtype++ = '\0';
  128. tl_gets(tags,
  129. SIPTAG_ACCEPT_REF(accept),
  130. SIPTAG_ACCEPT_STR_REF(accept_s),
  131. SIPTAG_CONTENT_TYPE_REF(ct),
  132. SIPTAG_CONTENT_TYPE_STR_REF(ct_s),
  133. TAG_END());
  134. /*
  135. * XXX - We really should build accept header when we add new content
  136. * types
  137. */
  138. if (accept_s == NULL && accept)
  139. accept_s = temp = sip_header_as_string(home, (sip_header_t *)accept);
  140. if (accept_s == NULL && ct)
  141. accept_s = ct->c_type;
  142. if (accept_s == NULL && ct_s)
  143. accept_s = ct_s;
  144. ev = nea_event_create(nh->nh_notifier,
  145. authorize_watcher, nh,
  146. o_type, o_subtype,
  147. ct ? ct->c_type : ct_s,
  148. accept_s);
  149. su_free(home, temp);
  150. su_free(home, o_type);
  151. }
  152. return ev;
  153. }
  154. /* Callback from nea_server asking nua to authorize subscription */
  155. static
  156. void authorize_watcher(nea_server_t *nes,
  157. nua_handle_t *nh,
  158. nea_event_t *ev,
  159. nea_subnode_t *sn,
  160. sip_t const *sip)
  161. {
  162. nua_t *nua = nh->nh_nua;
  163. msg_t *msg = NULL;
  164. nta_incoming_t *irq = NULL;
  165. int substate = sn->sn_state;
  166. int status; char const *phrase;
  167. SET_STATUS(200, sip_200_OK);
  168. /* OK. In nhp (nua_handle_preferences_t) structure we have the
  169. current default action (or state) for incoming
  170. subscriptions.
  171. Action can now be modified by the application with NUTAG_SUBSTATE().
  172. */
  173. irq = nea_sub_get_request(sn->sn_subscriber);
  174. msg = nta_incoming_getrequest(irq);
  175. if (sn->sn_state == nea_embryonic) {
  176. char const *what;
  177. substate = NH_PGET(nh, substate);
  178. if (substate == nua_substate_embryonic)
  179. substate = nua_substate_pending;
  180. if (substate == nua_substate_terminated) {
  181. what = "rejected"; SET_STATUS(403, sip_403_Forbidden);
  182. }
  183. else if (substate == nua_substate_pending) {
  184. what = "pending"; SET_STATUS(202, sip_202_Accepted);
  185. }
  186. else {
  187. what = "active";
  188. }
  189. SU_DEBUG_7(("nua(%p): authorize_watcher: %s\n", (void *)nh, what));
  190. nea_sub_auth(sn->sn_subscriber, (nea_state_t)substate,
  191. TAG_IF(substate == nua_substate_pending,
  192. NEATAG_FAKE(1)),
  193. TAG_IF(substate == nua_substate_terminated,
  194. NEATAG_REASON("rejected")),
  195. TAG_END());
  196. }
  197. else if (sn->sn_state == nea_terminated || sn->sn_expires == 0) {
  198. substate = nua_substate_terminated;
  199. nea_server_flush(nes, NULL);
  200. SU_DEBUG_7(("nua(%p): authorize_watcher: %s\n",
  201. (void *)nh, "watcher is removed"));
  202. }
  203. nua_stack_tevent(nua, nh, msg, nua_i_subscription, status, phrase,
  204. NUTAG_SUBSTATE(substate),
  205. NEATAG_SUB(sn->sn_subscriber),
  206. TAG_END());
  207. }
  208. /* ---------------------------------------------------------------------- */
  209. /* Authorization of watchers by application */
  210. void nua_stack_authorize(nua_t *nua,
  211. nua_handle_t *nh,
  212. nua_event_t e,
  213. tagi_t const *tags)
  214. {
  215. nea_sub_t *sub = NULL;
  216. int state = nea_extended;
  217. tl_gets(tags,
  218. NEATAG_SUB_REF(sub),
  219. NUTAG_SUBSTATE_REF(state),
  220. TAG_END());
  221. if (sub && state > 0) {
  222. nea_sub_auth(sub, (nea_state_t)state, TAG_NEXT(tags));
  223. nua_stack_event(nua, nh, NULL, e, SIP_200_OK, NULL);
  224. }
  225. else {
  226. nua_stack_event(nua, nh, NULL, e, NUA_ERROR_AT(__FILE__, __LINE__), NULL);
  227. }
  228. }
  229. /** @internal Shutdown notifier object */
  230. int nh_notifier_shutdown(nua_handle_t *nh,
  231. nea_event_t *ev,
  232. tag_type_t t,
  233. tag_value_t v, ...)
  234. {
  235. nea_server_t *nes = nh->nh_notifier;
  236. nea_subnode_t const **subs;
  237. int busy = 0;
  238. if (nes == NULL)
  239. return 0;
  240. subs = nea_server_get_subscribers(nes, ev);
  241. if (subs) {
  242. int i;
  243. ta_list ta;
  244. ta_start(ta, t, v);
  245. for (i = 0; subs[i]; i++)
  246. nea_sub_auth(subs[i]->sn_subscriber, nea_terminated, ta_tags(ta));
  247. ta_end(ta);
  248. busy++;
  249. }
  250. nea_server_free_subscribers(nes, subs);
  251. nea_server_flush(nh->nh_notifier, NULL);
  252. if (ev == NULL)
  253. nea_server_destroy(nh->nh_notifier), nh->nh_notifier = NULL;
  254. return busy;
  255. }
  256. /** @internal Terminate notifier. */
  257. void nua_stack_terminate(nua_t *nua,
  258. nua_handle_t *nh,
  259. nua_event_t e,
  260. tagi_t const *tags)
  261. {
  262. sip_event_t const *event = NULL;
  263. sip_content_type_t const *ct = NULL;
  264. sip_payload_t const *pl = NULL;
  265. char const *event_s = NULL, *ct_s = NULL, *pl_s = NULL;
  266. nea_event_t *nev = NULL;
  267. if (nh->nh_notifier == NULL) {
  268. UA_EVENT2(e, 900, "No event server to terminate");
  269. return;
  270. }
  271. tl_gets(tags,
  272. SIPTAG_EVENT_REF(event),
  273. SIPTAG_EVENT_STR_REF(event_s),
  274. SIPTAG_CONTENT_TYPE_REF(ct),
  275. SIPTAG_CONTENT_TYPE_STR_REF(ct_s),
  276. SIPTAG_PAYLOAD_REF(pl),
  277. SIPTAG_PAYLOAD_STR_REF(pl_s),
  278. TAG_END());
  279. nev = nea_event_get(nh->nh_notifier,
  280. event ? event->o_type : event_s);
  281. if (nev && (pl || pl_s) && (ct || ct_s)) {
  282. nea_server_update(nh->nh_notifier, nev, TAG_NEXT(tags));
  283. }
  284. nh_notifier_shutdown(nh, NULL,
  285. NEATAG_REASON("noresource"),
  286. TAG_NEXT(tags));
  287. nua_stack_event(nua, nh, NULL, e, SIP_200_OK, NULL);
  288. }