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