nua_stack.c 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163
  1. /*
  2. * This file is part of the Sofia-SIP package
  3. *
  4. * Copyright (C) 2005 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_stack.c
  25. * @brief Sofia-SIP User Agent Engine implementation
  26. *
  27. * @author Pekka Pessi <Pekka.Pessi@nokia.com>
  28. * @author Kai Vehmanen <Kai.Vehmanen@nokia.com>
  29. * @author Martti Mela <Martti Mela@nokia.com>
  30. * @author Remeres Jacobs <Remeres.Jacobs@nokia.com>
  31. * @author Tat Chan <Tat.Chan@nokia.com>
  32. *
  33. * @date Created: Wed Feb 14 18:32:58 2001 ppessi
  34. */
  35. #include "config.h"
  36. #include <sofia-sip/su_tag_class.h>
  37. #include <sofia-sip/su_tag_inline.h>
  38. #include <sofia-sip/su_tagarg.h>
  39. #include <sofia-sip/su_strlst.h>
  40. #include <sofia-sip/su_uniqueid.h>
  41. #include <sofia-sip/su_tag_io.h>
  42. #define SU_ROOT_MAGIC_T struct nua_s
  43. #define SU_MSG_ARG_T struct nua_ee_data
  44. #define NUA_SAVED_EVENT_T su_msg_t *
  45. #define NUA_SAVED_SIGNAL_T su_msg_t *
  46. #define NTA_AGENT_MAGIC_T struct nua_s
  47. #define NTA_LEG_MAGIC_T struct nua_handle_s
  48. #define NTA_OUTGOING_MAGIC_T struct nua_client_request
  49. #include <sofia-sip/sip.h>
  50. #include <sofia-sip/sip_header.h>
  51. #include <sofia-sip/sip_status.h>
  52. #include <sofia-sip/sip_util.h>
  53. #include <sofia-sip/tport_tag.h>
  54. #include <sofia-sip/nta.h>
  55. #include <sofia-sip/nta_tport.h>
  56. #include <sofia-sip/auth_client.h>
  57. #include <sofia-sip/soa.h>
  58. #include "sofia-sip/nua.h"
  59. #include "sofia-sip/nua_tag.h"
  60. #include "nua_stack.h"
  61. #include <stddef.h>
  62. #include <stdlib.h>
  63. #include <string.h>
  64. #include <limits.h>
  65. #include <stdio.h>
  66. #include <assert.h>
  67. /* ========================================================================
  68. *
  69. * Protocol stack side
  70. *
  71. * ======================================================================== */
  72. /* ---------------------------------------------------------------------- */
  73. /* Internal types */
  74. /** @internal Linked stack frames from nua event callback */
  75. struct nua_event_frame_s {
  76. nua_event_frame_t *nf_next;
  77. nua_saved_event_t nf_saved[1];
  78. };
  79. static void nua_event_deinit(nua_ee_data_t *ee);
  80. static void nua_application_event(nua_t *, su_msg_r, nua_ee_data_t *ee);
  81. static void nua_stack_signal(nua_t *nua, su_msg_r, nua_ee_data_t *ee);
  82. nua_handle_t *nh_create(nua_t *nua, tag_type_t t, tag_value_t v, ...);
  83. static void nh_append(nua_t *nua, nua_handle_t *nh);
  84. static void nh_remove(nua_t *nua, nua_handle_t *nh);
  85. static void nua_stack_timer(nua_t *nua, su_timer_t *t, su_timer_arg_t *a);
  86. /* ---------------------------------------------------------------------- */
  87. /* Constant data */
  88. /**@internal Default internal error. */
  89. char const nua_internal_error[] = "Internal NUA Error";
  90. char const nua_application_sdp[] = "application/sdp";
  91. #define NUA_STACK_TIMER_INTERVAL (1000)
  92. /* ----------------------------------------------------------------------
  93. * Initialization & deinitialization
  94. */
  95. int nua_stack_init(su_root_t *root, nua_t *nua)
  96. {
  97. su_home_t *home;
  98. nua_handle_t *dnh;
  99. static int initialized_logs = 0;
  100. enter;
  101. if (!initialized_logs) {
  102. extern su_log_t tport_log[];
  103. extern su_log_t nta_log[];
  104. extern su_log_t nea_log[];
  105. extern su_log_t iptsec_log[];
  106. su_log_init(tport_log);
  107. su_log_init(nta_log);
  108. su_log_init(nea_log);
  109. su_log_init(iptsec_log);
  110. initialized_logs = 1;
  111. }
  112. nua->nua_root = root;
  113. nua->nua_timer = su_timer_create(su_root_task(root),
  114. NUA_STACK_TIMER_INTERVAL);
  115. if (!nua->nua_timer)
  116. return -1;
  117. home = nua->nua_home;
  118. nua->nua_handles_tail = &nua->nua_handles;
  119. sip_from_init(nua->nua_from);
  120. dnh = su_home_clone(nua->nua_home, sizeof (*dnh) + sizeof(*dnh->nh_prefs));
  121. if (!dnh)
  122. return -1;
  123. dnh->nh_prefs = (void *)(dnh + 1);
  124. dnh->nh_valid = nua_valid_handle_cookie;
  125. dnh->nh_nua = nua;
  126. nua_handle_ref(dnh); dnh->nh_ref_by_stack = 1;
  127. nua_handle_ref(dnh); dnh->nh_ref_by_user = 1;
  128. nh_append(nua, dnh);
  129. dnh->nh_identity = dnh;
  130. dnh->nh_ds->ds_local = nua->nua_from;
  131. dnh->nh_ds->ds_remote = nua->nua_from;
  132. if (nua_stack_set_defaults(dnh, dnh->nh_prefs) < 0)
  133. return -1;
  134. if (nua_stack_set_params(nua, dnh, nua_i_none, nua->nua_args) < 0)
  135. return -1;
  136. nua->nua_invite_accept = sip_accept_make(home, SDP_MIME_TYPE);
  137. nua->nua_nta = nta_agent_create(root, NONE, NULL, NULL,
  138. NTATAG_MERGE_482(1),
  139. NTATAG_CLIENT_RPORT(1),
  140. NTATAG_UA(1),
  141. #if HAVE_SOFIA_SMIME
  142. NTATAG_SMIME(nua->sm),
  143. #endif
  144. TPTAG_STUN_SERVER(1),
  145. TAG_NEXT(nua->nua_args));
  146. dnh->nh_ds->ds_leg = nta_leg_tcreate(nua->nua_nta,
  147. nua_stack_process_request, dnh,
  148. NTATAG_NO_DIALOG(1),
  149. TAG_END());
  150. if (nua->nua_nta == NULL ||
  151. dnh->nh_ds->ds_leg == NULL ||
  152. nta_agent_set_params(nua->nua_nta, NTATAG_UA(1), TAG_END()) < 0 ||
  153. nua_stack_init_transport(nua, nua->nua_args) < 0) {
  154. SU_DEBUG_1(("nua: initializing SIP stack failed\n" VA_NONE));
  155. return -1;
  156. }
  157. if (nua_stack_set_from(nua, 1, nua->nua_args) < 0)
  158. return -1;
  159. if (nua->nua_prefs->ngp_detect_network_updates)
  160. nua_stack_launch_network_change_detector(nua);
  161. nua_stack_timer(nua, nua->nua_timer, NULL);
  162. return 0;
  163. }
  164. void nua_stack_deinit(su_root_t *root, nua_t *nua)
  165. {
  166. nua_handle_t *nh, *nh_next;
  167. enter;
  168. su_task_deinit(nua->nua_server);
  169. su_task_deinit(nua->nua_client);
  170. su_timer_destroy(nua->nua_timer), nua->nua_timer = NULL;
  171. nta_agent_destroy(nua->nua_nta), nua->nua_nta = NULL;
  172. for (nh = nua->nua_handles; nh; nh = nh_next) {
  173. nh_next = nh->nh_next;
  174. if (nh->nh_soa) {
  175. soa_destroy(nh->nh_soa), nh->nh_soa = NULL;
  176. }
  177. /* Cleanup remaining nua handles as they are su_home_new'ed and not su_home_cloned (do not belong to the nua's home)
  178. See nh_create_handle().
  179. At least one handle will be found here and it is nua default handle
  180. which is su_home_cloned (see nua_stack_init()) and therefore does not actually require to be unrefed.
  181. Nua is about to die so we don't remove nh from nua, just unref nh */
  182. if (nh != nua->nua_handles) {
  183. su_home_t *nh_home = (su_home_t *)nh;
  184. SU_DEBUG_9(("nua(%p): found handle with refcount = "MOD_ZU". Destroying.\n", (void *)nh, su_home_refcount(nh_home)));
  185. while(!su_home_unref(nh_home));
  186. }
  187. }
  188. #if HAVE_SMIME /* Start NRC Boston */
  189. sm_destroy(nua->sm);
  190. #endif /* End NRC Boston */
  191. }
  192. /* ----------------------------------------------------------------------
  193. * Sending events to client application
  194. */
  195. static void nua_stack_shutdown(nua_t *);
  196. void
  197. nua_stack_authenticate(nua_t *, nua_handle_t *, nua_event_t, tagi_t const *),
  198. nua_stack_respond(nua_t *, nua_handle_t *, int , char const *, tagi_t const *),
  199. nua_stack_destroy_handle(nua_t *, nua_handle_t *, tagi_t const *);
  200. /* Notifier */
  201. void
  202. nua_stack_authorize(nua_t *, nua_handle_t *, nua_event_t, tagi_t const *),
  203. nua_stack_notifier(nua_t *, nua_handle_t *, nua_event_t, tagi_t const *),
  204. nua_stack_terminate(nua_t *, nua_handle_t *, nua_event_t, tagi_t const *);
  205. int nh_notifier_shutdown(nua_handle_t *nh, nea_event_t *ev,
  206. tag_type_t t, tag_value_t v, ...);
  207. int nua_stack_tevent(nua_t *nua, nua_handle_t *nh, msg_t *msg,
  208. nua_event_t event, int status, char const *phrase,
  209. tag_type_t tag, tag_value_t value, ...)
  210. {
  211. ta_list ta;
  212. int retval;
  213. ta_start(ta, tag, value);
  214. retval = nua_stack_event(nua, nh, msg, event, status, phrase, ta_args(ta));
  215. ta_end(ta);
  216. return retval;
  217. }
  218. /** @internal Send an event to the application. */
  219. int nua_stack_event(nua_t *nua, nua_handle_t *nh, msg_t *msg,
  220. nua_event_t event, int status, char const *phrase,
  221. tagi_t const *tags)
  222. {
  223. su_msg_r sumsg = SU_MSG_R_INIT;
  224. size_t e_len, len, xtra, p_len;
  225. if (event == nua_r_ack || event == nua_i_none)
  226. return event;
  227. if (nh == nua->nua_dhandle)
  228. nh = NULL;
  229. if (nua_log->log_level >= 5) {
  230. char const *name = nua_event_name(event) + 4;
  231. char const *p = phrase ? phrase : "";
  232. if (status == 0)
  233. SU_DEBUG_5(("nua(%p): event %s %s\n", (void *)nh, name, p));
  234. else
  235. SU_DEBUG_5(("nua(%p): event %s %u %s\n", (void *)nh, name, status, p));
  236. }
  237. if (event == nua_r_destroy) {
  238. if (msg)
  239. msg_destroy(msg);
  240. if (status >= 200) {
  241. nh_destroy(nua, nh);
  242. }
  243. return event;
  244. }
  245. if ((event > nua_r_authenticate && event <= nua_r_ack)
  246. || event < nua_i_error
  247. || (nh && !nh->nh_valid)
  248. || (nua->nua_shutdown && event != nua_r_shutdown &&
  249. !nua->nua_prefs->ngp_shutdown_events)) {
  250. if (msg)
  251. msg_destroy(msg);
  252. return event;
  253. }
  254. if (tags) {
  255. e_len = offsetof(nua_ee_data_t, ee_data[0].e_tags);
  256. len = tl_len(tags);
  257. xtra = tl_xtra(tags, len);
  258. }
  259. else {
  260. e_len = sizeof(nua_ee_data_t), len = 0, xtra = 0;
  261. }
  262. p_len = phrase ? strlen(phrase) + 1 : 1;
  263. if (su_msg_new(sumsg, e_len + len + xtra + p_len) == 0) {
  264. nua_ee_data_t *ee = su_msg_data(sumsg);
  265. nua_event_data_t *e = ee->ee_data;
  266. void *p;
  267. if (tags) {
  268. tagi_t *t = e->e_tags, *t_end = (tagi_t *)((char *)t + len);
  269. void *b = t_end, *end = (char *)b + xtra;
  270. t = tl_dup(t, tags, &b); p = b;
  271. assert(t == t_end); assert(b == end); (void)end;
  272. }
  273. else
  274. p = ee + 1;
  275. ee->ee_nua = nua_stack_ref(nua);
  276. e->e_event = event;
  277. e->e_nh = nh ? nua_handle_ref(nh) : NULL;
  278. e->e_status = status;
  279. e->e_phrase = strcpy(p, phrase ? phrase : "");
  280. if (msg)
  281. e->e_msg = msg, su_home_threadsafe(msg_home(msg));
  282. su_msg_deinitializer(sumsg, nua_event_deinit);
  283. su_msg_send_to(sumsg, nua->nua_client, nua_application_event);
  284. }
  285. return event;
  286. }
  287. static
  288. void nua_event_deinit(nua_ee_data_t *ee)
  289. {
  290. nua_t *nua = ee->ee_nua;
  291. nua_event_data_t *e = ee->ee_data;
  292. nua_handle_t *nh = e->e_nh;
  293. if (e->e_msg)
  294. msg_destroy(e->e_msg), e->e_msg = NULL;
  295. if (nh)
  296. nua_handle_unref(nh), e->e_nh = NULL;
  297. if (nua)
  298. nua_stack_unref(nua), ee->ee_nua = NULL;
  299. }
  300. /*# Receive event from protocol machine and hand it over to application */
  301. static
  302. void nua_application_event(nua_t *dummy, su_msg_r sumsg, nua_ee_data_t *ee)
  303. {
  304. nua_t *nua = ee->ee_nua;
  305. nua_event_data_t *e = ee->ee_data;
  306. nua_handle_t *nh = e->e_nh;
  307. enter;
  308. ee->ee_nua = NULL;
  309. e->e_nh = NULL;
  310. if (nh == NULL) {
  311. /* Xyzzy */
  312. }
  313. else if (nh->nh_valid) {
  314. if (!nh->nh_ref_by_user) {
  315. /* Application must now call nua_handle_destroy() */
  316. nh->nh_ref_by_user = 1;
  317. nua_handle_ref(nh);
  318. }
  319. }
  320. else if (!nh->nh_valid) { /* Handle has been destroyed */
  321. if (nua_log->log_level >= 7) {
  322. char const *name = nua_event_name((enum nua_event_e)e->e_event) + 4;
  323. SU_DEBUG_7(("nua(%p): event %s dropped\n", (void *)nh, name));
  324. }
  325. if (nh) nua_handle_unref_user(nh);
  326. if (nua) nua_unref_user(nua);
  327. return;
  328. }
  329. if (e->e_event == nua_r_shutdown && e->e_status >= 200)
  330. nua->nua_shutdown_final = 1;
  331. if (nua->nua_callback) {
  332. nua_event_frame_t frame[1];
  333. su_msg_save(frame->nf_saved, sumsg);
  334. frame->nf_next = nua->nua_current, nua->nua_current = frame;
  335. nua->nua_callback((enum nua_event_e)e->e_event, e->e_status, e->e_phrase,
  336. nua, nua->nua_magic,
  337. nh, nh ? nh->nh_magic : NULL,
  338. e->e_msg ? sip_object(e->e_msg) : NULL,
  339. e->e_tags);
  340. if (su_msg_is_non_null(frame->nf_saved)) {
  341. su_msg_destroy(frame->nf_saved);
  342. }
  343. nua->nua_current = frame->nf_next;
  344. }
  345. if (nh) nua_handle_unref_user(nh);
  346. if (nua) nua_unref_user(nua);
  347. }
  348. /** Get current request message. @NEW_1_12_4.
  349. *
  350. * @note A response message is returned when processing response message.
  351. *
  352. * @sa #nua_event_e, nua_respond(), NUTAG_WITH_CURRENT()
  353. */
  354. msg_t *nua_current_request(nua_t const *nua)
  355. {
  356. if (nua && nua->nua_current && su_msg_is_non_null(nua->nua_current->nf_saved))
  357. return su_msg_data(nua->nua_current->nf_saved)->ee_data->e_msg;
  358. return NULL;
  359. }
  360. su_msg_t *nua_current_msg(nua_t const *nua, int clear)
  361. {
  362. if (nua && nua->nua_current && su_msg_is_non_null(nua->nua_current->nf_saved)) {
  363. su_msg_t *r = nua->nua_current->nf_saved[0];
  364. if (clear) {
  365. nua->nua_current->nf_saved[0] = NULL;
  366. }
  367. return r;
  368. //return su_msg_data(nua->nua_current->nf_saved)->ee_data->e_msg;
  369. }
  370. return NULL;
  371. }
  372. /** Get request message from saved nua event. @NEW_1_12_4.
  373. *
  374. * @sa nua_save_event(), nua_respond(), NUTAG_WITH_SAVED(),
  375. */
  376. msg_t *nua_saved_event_request(nua_saved_event_t const *saved)
  377. {
  378. return saved && saved[0] ? su_msg_data(saved)->ee_data->e_msg : NULL;
  379. }
  380. /** Save nua event and its arguments.
  381. *
  382. * @sa #nua_event_e, nua_event_data() nua_saved_event_request(), nua_destroy_event()
  383. */
  384. int nua_save_event(nua_t *nua, nua_saved_event_t return_saved[1])
  385. {
  386. if (return_saved) {
  387. if (nua && nua->nua_current) {
  388. su_msg_save(return_saved, nua->nua_current->nf_saved);
  389. return su_msg_is_non_null(return_saved);
  390. }
  391. else
  392. *return_saved = NULL;
  393. }
  394. return 0;
  395. }
  396. /* ---------------------------------------------------------------------- */
  397. /** @internal
  398. * Post signal to stack itself
  399. */
  400. void nua_stack_post_signal(nua_handle_t *nh, nua_event_t event,
  401. tag_type_t tag, tag_value_t value, ...)
  402. {
  403. ta_list ta;
  404. ta_start(ta, tag, value);
  405. nua_signal((nh)->nh_nua, nh, NULL, event, 0, NULL, ta_tags(ta));
  406. ta_end(ta);
  407. }
  408. /*# Send a request to the protocol thread */
  409. int nua_signal(nua_t *nua, nua_handle_t *nh, msg_t *msg,
  410. nua_event_t event,
  411. int status, char const *phrase,
  412. tag_type_t tag, tag_value_t value, ...)
  413. {
  414. su_msg_r sumsg = SU_MSG_R_INIT;
  415. size_t len, xtra, ee_len, l_len = 0, l_xtra = 0;
  416. ta_list ta;
  417. int retval = -1;
  418. if (nua == NULL)
  419. return -1;
  420. if (nua->nua_shutdown_started && event != nua_r_shutdown && event != nua_r_destroy && event != nua_r_handle_unref && event != nua_r_unref)
  421. return -1;
  422. ta_start(ta, tag, value);
  423. ee_len = offsetof(nua_ee_data_t, ee_data[0].e_tags);
  424. len = tl_len(ta_args(ta));
  425. xtra = tl_xtra(ta_args(ta), len);
  426. if (su_msg_new(sumsg, ee_len + len + l_len + xtra + l_xtra) == 0) {
  427. nua_ee_data_t *ee = su_msg_data(sumsg);
  428. nua_event_data_t *e = ee->ee_data;
  429. tagi_t *t = e->e_tags;
  430. void *b = (char *)t + len + l_len;
  431. tagi_t *tend = (tagi_t *)b;
  432. char *bend = (char *)b + xtra + l_xtra;
  433. t = tl_dup(t, ta_args(ta), &b);
  434. assert(tend == t); (void)tend; assert(b == bend); (void)bend;
  435. e->e_always = event == nua_r_destroy || event == nua_r_shutdown || event == nua_r_handle_unref || event == nua_r_unref;
  436. e->e_event = event;
  437. e->e_nh = nh ? nua_handle_ref(nh) : NULL;
  438. e->e_status = status;
  439. e->e_phrase = phrase;
  440. su_msg_deinitializer(sumsg, nua_event_deinit);
  441. retval = su_msg_send_to(sumsg, nua->nua_server, nua_stack_signal);
  442. if (retval == 0){
  443. SU_DEBUG_7(("nua(%p): %s signal %s\n", (void *)nh,
  444. "sent", nua_event_name(event) + 4));
  445. }
  446. else {
  447. SU_DEBUG_0(("nua(%p): %s signal %s\n", (void *)nh,
  448. "FAILED TO SEND", nua_event_name(event) + 4));
  449. }
  450. }
  451. ta_end(ta);
  452. return retval;
  453. }
  454. /* ----------------------------------------------------------------------
  455. * Receiving events from client
  456. */
  457. static
  458. void nua_stack_signal(nua_t *nua, su_msg_r msg, nua_ee_data_t *ee)
  459. {
  460. nua_event_data_t *e = ee->ee_data;
  461. nua_handle_t *nh = e->e_nh;
  462. tagi_t *tags = e->e_tags;
  463. nua_event_t event = (enum nua_event_e)e->e_event;
  464. int error = 0;
  465. if (nh && !nh->nh_destroyed && event != nua_r_handle_unref) {
  466. if (!nh->nh_prev)
  467. nh_append(nua, nh);
  468. if (!nh->nh_ref_by_stack) {
  469. /* Mark handle as used by stack */
  470. nh->nh_ref_by_stack = 1;
  471. nua_handle_ref(nh);
  472. }
  473. }
  474. if (nua_log->log_level >= 5) {
  475. char const *name = nua_event_name((enum nua_event_e)e->e_event);
  476. if (e->e_status == 0)
  477. SU_DEBUG_5(("nua(%p): %s signal %s\n", (void *)nh, "recv", name + 4));
  478. else
  479. SU_DEBUG_5(("nua(%p): recv signal %s %u %s\n",
  480. (void *)nh, name + 4,
  481. e->e_status, e->e_phrase ? e->e_phrase : ""));
  482. }
  483. su_msg_save(nua->nua_signal, msg);
  484. if (nua->nua_shutdown && !e->e_always) {
  485. /* Shutting down */
  486. nua_stack_event(nua, nh, NULL, event,
  487. 901, "Stack is going down",
  488. NULL);
  489. }
  490. else switch (event) {
  491. case nua_r_get_params:
  492. nua_stack_get_params(nua, nh ? nh : nua->nua_dhandle, event, tags);
  493. break;
  494. case nua_r_set_params:
  495. nua_stack_set_params(nua, nh ? nh : nua->nua_dhandle, event, tags);
  496. break;
  497. case nua_r_shutdown:
  498. nua_stack_shutdown(nua);
  499. break;
  500. case nua_r_register:
  501. case nua_r_unregister:
  502. nua_stack_register(nua, nh, event, tags);
  503. break;
  504. case nua_r_invite:
  505. error = nua_stack_invite(nua, nh, event, tags);
  506. break;
  507. case nua_r_cancel:
  508. error = nua_stack_cancel(nua, nh, event, tags);
  509. break;
  510. case nua_r_bye:
  511. error = nua_stack_bye(nua, nh, event, tags);
  512. break;
  513. case nua_r_options:
  514. error = nua_stack_options(nua, nh, event, tags);
  515. break;
  516. case nua_r_refer:
  517. error = nua_stack_refer(nua, nh, event, tags);
  518. break;
  519. case nua_r_publish:
  520. case nua_r_unpublish:
  521. error = nua_stack_publish(nua, nh, event, tags);
  522. break;
  523. case nua_r_info:
  524. error = nua_stack_info(nua, nh, event, tags);
  525. break;
  526. case nua_r_prack:
  527. error = nua_stack_prack(nua, nh, event, tags);
  528. break;
  529. case nua_r_update:
  530. error = nua_stack_update(nua, nh, event, tags);
  531. break;
  532. case nua_r_message:
  533. error = nua_stack_message(nua, nh, event, tags);
  534. break;
  535. case nua_r_subscribe:
  536. case nua_r_unsubscribe:
  537. error = nua_stack_subscribe(nua, nh, event, tags);
  538. break;
  539. case nua_r_notify:
  540. error = nua_stack_notify(nua, nh, event, tags);
  541. break;
  542. case nua_r_notifier:
  543. nua_stack_notifier(nua, nh, event, tags);
  544. break;
  545. case nua_r_terminate:
  546. nua_stack_terminate(nua, nh, event, tags);
  547. break;
  548. case nua_r_method:
  549. error = nua_stack_method(nua, nh, event, tags);
  550. break;
  551. case nua_r_authenticate:
  552. nua_stack_authenticate(nua, nh, event, tags);
  553. break;
  554. case nua_r_authorize:
  555. nua_stack_authorize(nua, nh, event, tags);
  556. break;
  557. case nua_r_ack:
  558. error = nua_stack_ack(nua, nh, event, tags);
  559. break;
  560. case nua_r_respond:
  561. nua_stack_respond(nua, nh, e->e_status, e->e_phrase, tags);
  562. break;
  563. case nua_r_destroy:
  564. if (nh && !nh->nh_destroyed) {
  565. nua_stack_destroy_handle(nua, nh, tags);
  566. su_msg_destroy(nua->nua_signal);
  567. }
  568. return;
  569. case nua_r_unref:
  570. nua_unref(nua);
  571. break;
  572. case nua_r_handle_unref:
  573. nua_handle_unref(nh);
  574. break;
  575. case nua_r_nta_agent_resolver_clean_dns_cache:
  576. nta_agent_resolver_clean_cache(nua->nua_nta);
  577. break;
  578. default:
  579. break;
  580. }
  581. if (error < 0) {
  582. if (nh) {
  583. nua_stack_event(nh->nh_nua, nh, NULL, event,
  584. NUA_ERROR_AT(__FILE__, __LINE__), NULL);
  585. }
  586. }
  587. su_msg_destroy(nua->nua_signal);
  588. }
  589. /* ====================================================================== */
  590. /* Signal and event handling */
  591. /** Get event data.
  592. *
  593. * @sa #nua_event_e, nua_event_save(), nua_saved_event_request(), nua_destroy_event().
  594. */
  595. nua_event_data_t const *nua_event_data(nua_saved_event_t const saved[1])
  596. {
  597. return saved && saved[0] ? su_msg_data(saved)->ee_data : NULL;
  598. }
  599. /** Destroy saved event.
  600. *
  601. * @sa #nua_event_e, nua_event_save(), nua_event_data(), nua_saved_event_request().
  602. */
  603. void nua_destroy_event(nua_saved_event_t saved[1])
  604. {
  605. if (saved && saved[0]) su_msg_destroy(saved);
  606. }
  607. /** @internal Move signal. */
  608. void nua_move_signal(nua_saved_signal_t a[1], nua_saved_signal_t b[1])
  609. {
  610. su_msg_save(a, b);
  611. }
  612. void nua_destroy_signal(nua_saved_signal_t saved[1])
  613. {
  614. if (saved) su_msg_destroy(saved);
  615. }
  616. nua_signal_data_t const *nua_signal_data(nua_saved_signal_t const saved[1])
  617. {
  618. return nua_event_data(saved);
  619. }
  620. /* ====================================================================== */
  621. static int nh_call_pending(nua_handle_t *nh, sip_time_t time);
  622. /**@internal
  623. * Timer routine.
  624. *
  625. * Go through all active handles and execute pending tasks
  626. */
  627. void nua_stack_timer(nua_t *nua, su_timer_t *t, su_timer_arg_t *a)
  628. {
  629. nua_handle_t *nh, *nh_next;
  630. sip_time_t now = sip_now();
  631. su_root_t *root = su_timer_root(t);
  632. su_timer_set(t, nua_stack_timer, a);
  633. if (nua->nua_shutdown) {
  634. nua_stack_shutdown(nua);
  635. return;
  636. }
  637. for (nh = nua->nua_handles; nh; nh = nh_next) {
  638. nh_next = nh->nh_next;
  639. nh_call_pending(nh, now);
  640. su_root_yield(root); /* Handle received packets */
  641. }
  642. }
  643. static
  644. int nh_call_pending(nua_handle_t *nh, sip_time_t now)
  645. {
  646. nua_dialog_state_t *ds = nh->nh_ds;
  647. nua_dialog_usage_t *du;
  648. sip_time_t next = now + NUA_STACK_TIMER_INTERVAL / 1000;
  649. for (du = ds->ds_usage; du; du = du->du_next) {
  650. if (now == 0)
  651. break;
  652. if (du->du_refresh && du->du_refresh < next)
  653. break;
  654. }
  655. if (du == NULL)
  656. return 0;
  657. nua_handle_ref(nh);
  658. while (du) {
  659. nua_dialog_usage_t *du_next = du->du_next;
  660. nua_dialog_usage_refresh(nh, ds, du, now);
  661. if (du_next == NULL)
  662. break;
  663. for (du = nh->nh_ds->ds_usage; du; du = du->du_next)
  664. if (du == du_next)
  665. break;
  666. for (; du; du = du->du_next) {
  667. if (now == 0)
  668. break;
  669. if (du->du_refresh && du->du_refresh < next)
  670. break;
  671. }
  672. }
  673. nua_handle_unref(nh);
  674. return 1;
  675. }
  676. /* ====================================================================== */
  677. /**Shutdown a @nua stack.
  678. *
  679. * When the @nua stack is shutdown, ongoing calls are released,
  680. * registrations unregistered, publications un-PUBLISHed and subscriptions
  681. * terminated. If the stack cannot terminate everything within 30 seconds,
  682. * it sends the #nua_r_shutdown event with status 500.
  683. *
  684. * @param nua Pointer to @nua stack object
  685. *
  686. * @return
  687. * nothing
  688. *
  689. * @par Related tags:
  690. * none
  691. *
  692. * @par Events:
  693. * #nua_r_shutdown
  694. *
  695. * @sa #nua_r_shutdown, nua_destroy(), nua_create(), nua_bye(),
  696. * nua_unregister(), nua_unpublish(), nua_unsubscribe(), nua_notify(),
  697. * nua_handle_destroy(), nua_handle_unref()
  698. */
  699. /** @NUA_EVENT nua_r_shutdown
  700. *
  701. * Answer to nua_shutdown().
  702. *
  703. * Status codes
  704. * - 100 shutdown started
  705. * - 101 shutdown in progress (sent when shutdown has been progressed)
  706. * - 200 shutdown was successful
  707. * - 500 shutdown timeout after 30 sec
  708. *
  709. * @param status shutdown status code
  710. * @param nh NULL
  711. * @param hmagic NULL
  712. * @param sip NULL
  713. * @param tags empty
  714. *
  715. * @sa nua_shutdown(), nua_destroy()
  716. *
  717. * @END_NUA_EVENT
  718. */
  719. /** @internal Shut down stack. */
  720. void nua_stack_shutdown(nua_t *nua)
  721. {
  722. nua_handle_t *nh, *nh_next;
  723. int busy = 0;
  724. sip_time_t now = sip_now();
  725. int status;
  726. char const *phrase;
  727. enter;
  728. if (!nua->nua_shutdown)
  729. nua->nua_shutdown = now;
  730. for (nh = nua->nua_handles; nh; nh = nh_next) {
  731. nua_dialog_state_t *ds = nh->nh_ds;
  732. nh_next = nh->nh_next;
  733. busy += nua_dialog_repeat_shutdown(nh, ds);
  734. if (nh->nh_soa) {
  735. soa_destroy(nh->nh_soa), nh->nh_soa = NULL;
  736. }
  737. if (nua_client_request_pending(ds->ds_cr))
  738. busy++;
  739. if (nh_notifier_shutdown(nh, NULL, NEATAG_REASON("noresource"), TAG_END()))
  740. busy++;
  741. }
  742. if (!busy)
  743. SET_STATUS(200, "Shutdown successful");
  744. else if (now == nua->nua_shutdown)
  745. SET_STATUS(100, "Shutdown started");
  746. else if (now - nua->nua_shutdown < 30)
  747. SET_STATUS(101, "Shutdown in progress");
  748. else
  749. SET_STATUS(500, "Shutdown timeout");
  750. if (status >= 200) {
  751. for (nh = nua->nua_handles; nh; nh = nh_next) {
  752. nh_next = nh->nh_next;
  753. while (nh->nh_ds->ds_usage) {
  754. nua_dialog_usage_remove(nh, nh->nh_ds, nh->nh_ds->ds_usage, NULL, NULL);
  755. }
  756. }
  757. su_timer_destroy(nua->nua_timer), nua->nua_timer = NULL;
  758. nta_agent_destroy(nua->nua_nta), nua->nua_nta = NULL;
  759. }
  760. nua_stack_event(nua, NULL, NULL, nua_r_shutdown, status, phrase, NULL);
  761. }
  762. /* ---------------------------------------------------------------------- */
  763. /** @internal Create a handle */
  764. nua_handle_t *nh_create(nua_t *nua, tag_type_t tag, tag_value_t value, ...)
  765. {
  766. ta_list ta;
  767. nua_handle_t *nh;
  768. enter;
  769. ta_start(ta, tag, value);
  770. nh = nh_create_handle(nua, NULL, ta_args(ta));
  771. ta_end(ta);
  772. if (nh) {
  773. nh->nh_ref_by_stack = 1;
  774. nh_append(nua, nh);
  775. }
  776. return nh;
  777. }
  778. /** @internal Append a handle to the list of handles */
  779. void nh_append(nua_t *nua, nua_handle_t *nh)
  780. {
  781. nh->nh_next = NULL;
  782. nh->nh_prev = nua->nua_handles_tail;
  783. *nua->nua_handles_tail = nh;
  784. nua->nua_handles_tail = &nh->nh_next;
  785. }
  786. nua_handle_t *nh_validate(nua_t *nua, nua_handle_t *maybe)
  787. {
  788. nua_handle_t *nh;
  789. if (maybe)
  790. for (nh = nua->nua_handles; nh; nh = nh->nh_next)
  791. if (nh == maybe)
  792. return nh;
  793. return NULL;
  794. }
  795. void nua_stack_destroy_handle(nua_t *nua, nua_handle_t *nh, tagi_t const *tags)
  796. {
  797. if (nh->nh_destroyed) {
  798. return;
  799. }
  800. if (nh->nh_notifier)
  801. nua_stack_terminate(nua, nh, (enum nua_event_e)0, NULL);
  802. nua_dialog_shutdown(nh, nh->nh_ds);
  803. if (nh->nh_ref_by_user) {
  804. nh->nh_ref_by_user = 0;
  805. nua_handle_unref(nh);
  806. }
  807. nh_destroy(nua, nh);
  808. }
  809. #define nh_is_inserted(nh) ((nh)->nh_prev != NULL)
  810. /** @internal Remove a handle from list of handles */
  811. static
  812. void nh_remove(nua_t *nua, nua_handle_t *nh)
  813. {
  814. assert(nh_is_inserted(nh)); assert(*nh->nh_prev == nh);
  815. if (nh->nh_next)
  816. nh->nh_next->nh_prev = nh->nh_prev;
  817. else
  818. nua->nua_handles_tail = nh->nh_prev;
  819. *nh->nh_prev = nh->nh_next;
  820. nh->nh_prev = NULL;
  821. nh->nh_next = NULL;
  822. }
  823. void nh_destroy(nua_t *nua, nua_handle_t *nh)
  824. {
  825. assert(nh); assert(nh != nua->nua_dhandle);
  826. if (nh->nh_destroyed) {
  827. return;
  828. }
  829. nh->nh_destroyed = 1;
  830. if (nh->nh_notifier)
  831. nea_server_destroy(nh->nh_notifier), nh->nh_notifier = NULL;
  832. while (nh->nh_ds->ds_cr)
  833. nua_client_request_complete(nh->nh_ds->ds_cr);
  834. while (nh->nh_ds->ds_sr)
  835. nua_server_request_destroy(nh->nh_ds->ds_sr);
  836. nua_dialog_deinit(nh, nh->nh_ds);
  837. if (nh->nh_soa)
  838. soa_destroy(nh->nh_soa), nh->nh_soa = NULL;
  839. if (nh_is_inserted(nh))
  840. nh_remove(nua, nh);
  841. nua_handle_unref(nh); /* Remove stack reference */
  842. }
  843. /* ======================================================================== */
  844. /** @internal Create a handle for processing incoming request */
  845. nua_handle_t *nua_stack_incoming_handle(nua_t *nua,
  846. nta_incoming_t *irq,
  847. sip_t const *sip,
  848. int create_dialog)
  849. {
  850. nua_handle_t *nh;
  851. url_t const *url;
  852. sip_to_t to[1];
  853. sip_from_t from[1];
  854. assert(sip && sip->sip_from && sip->sip_to);
  855. if (sip->sip_contact)
  856. url = sip->sip_contact->m_url;
  857. else
  858. url = sip->sip_from->a_url;
  859. /* Strip away parameters */
  860. sip_from_init(from)->a_display = sip->sip_to->a_display;
  861. *from->a_url = *sip->sip_to->a_url;
  862. sip_to_init(to)->a_display = sip->sip_from->a_display;
  863. *to->a_url = *sip->sip_from->a_url;
  864. nh = nh_create(nua,
  865. NUTAG_URL((url_string_t *)url), /* Remote target */
  866. SIPTAG_TO(to), /* Local AoR */
  867. SIPTAG_FROM(from), /* Remote AoR */
  868. TAG_END());
  869. if (nh && nua_stack_init_handle(nua, nh, NULL) < 0)
  870. nh_destroy(nua, nh), nh = NULL;
  871. if (nh && create_dialog) {
  872. struct nua_dialog_state *ds = nh->nh_ds;
  873. nua_dialog_store_peer_info(nh, ds, sip);
  874. ds->ds_leg = nta_leg_tcreate(nua->nua_nta, nua_stack_process_request, nh,
  875. SIPTAG_CALL_ID(sip->sip_call_id),
  876. SIPTAG_FROM(sip->sip_to),
  877. SIPTAG_TO(sip->sip_from),
  878. NTATAG_REMOTE_CSEQ(sip->sip_cseq->cs_seq),
  879. TAG_END());
  880. if (!ds->ds_leg || !nta_leg_tag(ds->ds_leg, nta_incoming_tag(irq, NULL)))
  881. nh_destroy(nua, nh), nh = NULL;
  882. }
  883. if (nh)
  884. nua_dialog_uas_route(nh, nh->nh_ds, sip, 1);
  885. return nh;
  886. }
  887. /** Set flags and special event on handle.
  888. *
  889. * @retval 0 when successful
  890. * @retval -1 upon an error
  891. */
  892. int nua_stack_set_handle_special(nua_handle_t *nh,
  893. enum nh_kind kind,
  894. nua_event_t special)
  895. {
  896. if (nh == NULL)
  897. return -1;
  898. if (special && nh->nh_special && nh->nh_special != special)
  899. return -1;
  900. if (!nh_is_special(nh) && !nh->nh_has_invite) {
  901. switch (kind) {
  902. case nh_has_invite: nh->nh_has_invite = 1; break;
  903. case nh_has_subscribe: nh->nh_has_subscribe = 1; break;
  904. case nh_has_notify: nh->nh_has_notify = 1; break;
  905. case nh_has_register: nh->nh_has_register = 1; break;
  906. case nh_has_nothing:
  907. default:
  908. break;
  909. }
  910. if (special)
  911. nh->nh_special = special;
  912. }
  913. return 0;
  914. }
  915. sip_replaces_t *nua_stack_handle_make_replaces(nua_handle_t *nh,
  916. su_home_t *home,
  917. int early_only)
  918. {
  919. if (nh && nh->nh_ds->ds_leg)
  920. return nta_leg_make_replaces(nh->nh_ds->ds_leg, home, early_only);
  921. else
  922. return NULL;
  923. }
  924. nua_handle_t *nua_stack_handle_by_replaces(nua_t *nua,
  925. sip_replaces_t const *r)
  926. {
  927. if (nua) {
  928. nta_leg_t *leg = nta_leg_by_replaces(nua->nua_nta, r);
  929. if (leg)
  930. return nta_leg_magic(leg, nua_stack_process_request);
  931. }
  932. return NULL;
  933. }
  934. nua_handle_t *nua_stack_handle_by_call_id(nua_t *nua, const char *call_id)
  935. {
  936. if (nua) {
  937. nta_leg_t *leg = nta_leg_by_call_id(nua->nua_nta, call_id);
  938. if (leg)
  939. return nta_leg_magic(leg, nua_stack_process_request);
  940. }
  941. return NULL;
  942. }