| File: | libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c |
| Location: | line 1057, column 20 |
| Description: | Access to field 'nr_ob' results in a dereference of a null pointer (loaded from variable 'nr') |
| 1 | /* | |||
| 2 | * This file is part of the Sofia-SIP package | |||
| 3 | * | |||
| 4 | * Copyright (C) 2006 Nokia Corporation. | |||
| 5 | * | |||
| 6 | * Contact: Pekka Pessi <pekka.pessi@nokia.com> | |||
| 7 | * | |||
| 8 | * This library is free software; you can redistribute it and/or | |||
| 9 | * modify it under the terms of the GNU Lesser General Public License | |||
| 10 | * as published by the Free Software Foundation; either version 2.1 of | |||
| 11 | * the License, or (at your option) any later version. | |||
| 12 | * | |||
| 13 | * This library is distributed in the hope that it will be useful, but | |||
| 14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
| 16 | * Lesser General Public License for more details. | |||
| 17 | * | |||
| 18 | * You should have received a copy of the GNU Lesser General Public | |||
| 19 | * License along with this library; if not, write to the Free Software | |||
| 20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | |||
| 21 | * 02110-1301 USA | |||
| 22 | * | |||
| 23 | */ | |||
| 24 | ||||
| 25 | /**@CFILE nua_register.c | |||
| 26 | * @brief REGISTER and registrations | |||
| 27 | * | |||
| 28 | * @author Pekka Pessi <Pekka.Pessi@nokia.com> | |||
| 29 | * @author Martti Mela <Martti.Mela@nokia.com> | |||
| 30 | * @author Kai Vehmanen <Kai.Vehmanen@nokia.com> | |||
| 31 | * | |||
| 32 | * @date Created: Wed Mar 8 11:48:49 EET 2006 ppessi | |||
| 33 | */ | |||
| 34 | ||||
| 35 | #include "config.h" | |||
| 36 | ||||
| 37 | /** @internal SU network changed detector argument pointer type */ | |||
| 38 | #define SU_NETWORK_CHANGED_MAGIC_Tstruct nua_s struct nua_s | |||
| 39 | ||||
| 40 | #define TP_CLIENT_Tstruct register_usage struct register_usage | |||
| 41 | ||||
| 42 | #include <sofia-sip/su_string.h> | |||
| 43 | #include <sofia-sip/su_strlst.h> | |||
| 44 | #include <sofia-sip/su_uniqueid.h> | |||
| 45 | #include <sofia-sip/su_tagarg.h> | |||
| 46 | ||||
| 47 | #include <sofia-sip/sip_protos.h> | |||
| 48 | #include <sofia-sip/sip_util.h> | |||
| 49 | #include <sofia-sip/sip_status.h> | |||
| 50 | ||||
| 51 | #define NTA_UPDATE_MAGIC_Tstruct nua_s struct nua_s | |||
| 52 | #define NTA_ERROR_MAGIC_Tstruct nua_s struct nua_s | |||
| 53 | ||||
| 54 | #include "nua_stack.h" | |||
| 55 | ||||
| 56 | #include <sofia-sip/hostdomain.h> | |||
| 57 | #include <sofia-sip/nta_tport.h> | |||
| 58 | #include <sofia-sip/tport.h> | |||
| 59 | #include <sofia-sip/tport_tag.h> | |||
| 60 | ||||
| 61 | #define OUTBOUND_OWNER_Tstruct nua_handle_s struct nua_handle_s | |||
| 62 | ||||
| 63 | #include "outbound.h" | |||
| 64 | ||||
| 65 | #if HAVE_SIGCOMP | |||
| 66 | #include <sigcomp.h> | |||
| 67 | #endif | |||
| 68 | ||||
| 69 | #include <stddef.h> | |||
| 70 | #include <stdlib.h> | |||
| 71 | #include <string.h> | |||
| 72 | #include <limits.h> | |||
| 73 | ||||
| 74 | #include <assert.h> | |||
| 75 | ||||
| 76 | /* ======================================================================== */ | |||
| 77 | /* Registrations and contacts */ | |||
| 78 | ||||
| 79 | int nua_registration_from_via(nua_registration_t **list, | |||
| 80 | nua_handle_t *nh, | |||
| 81 | sip_via_t const *via, | |||
| 82 | int public); | |||
| 83 | ||||
| 84 | int nua_registration_add(nua_registration_t **list, nua_registration_t *nr); | |||
| 85 | ||||
| 86 | void nua_registration_remove(nua_registration_t *nr); | |||
| 87 | ||||
| 88 | int nua_registration_set_aor(su_home_t *, nua_registration_t *nr, | |||
| 89 | sip_from_t const *aor); | |||
| 90 | ||||
| 91 | int nua_registration_set_contact(nua_handle_t *, | |||
| 92 | nua_registration_t *nr, | |||
| 93 | sip_contact_t const *m, | |||
| 94 | int terminating); | |||
| 95 | ||||
| 96 | void nua_registration_set_ready(nua_registration_t *nr, int ready); | |||
| 97 | ||||
| 98 | /* ====================================================================== */ | |||
| 99 | /* REGISTER usage */ | |||
| 100 | ||||
| 101 | static char const *nua_register_usage_name(nua_dialog_usage_t const *du); | |||
| 102 | ||||
| 103 | static int nua_register_usage_add(nua_handle_t *nh, | |||
| 104 | nua_dialog_state_t *ds, | |||
| 105 | nua_dialog_usage_t *du); | |||
| 106 | static void nua_register_usage_remove(nua_handle_t *nh, | |||
| 107 | nua_dialog_state_t *ds, | |||
| 108 | nua_dialog_usage_t *du, | |||
| 109 | nua_client_request_t *cr, | |||
| 110 | nua_server_request_t *sr); | |||
| 111 | static void nua_register_usage_update_params(nua_dialog_usage_t const *du, | |||
| 112 | nua_handle_preferences_t const *, | |||
| 113 | nua_handle_preferences_t const *, | |||
| 114 | nua_handle_preferences_t const *); | |||
| 115 | static void nua_register_usage_peer_info(nua_dialog_usage_t *du, | |||
| 116 | nua_dialog_state_t const *ds, | |||
| 117 | sip_t const *sip); | |||
| 118 | static void nua_register_usage_refresh(nua_handle_t *, | |||
| 119 | nua_dialog_state_t *, | |||
| 120 | nua_dialog_usage_t *, | |||
| 121 | sip_time_t); | |||
| 122 | static int nua_register_usage_shutdown(nua_handle_t *, | |||
| 123 | nua_dialog_state_t *, | |||
| 124 | nua_dialog_usage_t *); | |||
| 125 | ||||
| 126 | /** @internal @brief REGISTER usage, aka nua_registration_t. */ | |||
| 127 | struct register_usage { | |||
| 128 | nua_registration_t *nr_next, **nr_prev, **nr_list; /* Doubly linked list and its head */ | |||
| 129 | sip_from_t *nr_aor; /**< AoR for this registration, NULL if none */ | |||
| 130 | sip_contact_t *nr_contact; /**< Our Contact */ | |||
| 131 | sip_contact_t nr_dcontact[1]; /**< Contact in dialog */ | |||
| 132 | sip_via_t *nr_via; /**< Corresponding Via headers */ | |||
| 133 | ||||
| 134 | unsigned long nr_min_expires; /**< Value from 423 negotiation */ | |||
| 135 | ||||
| 136 | /** Status of registration */ | |||
| 137 | unsigned nr_ready:1; | |||
| 138 | ||||
| 139 | /** Kind of registration. | |||
| 140 | * | |||
| 141 | * If nr_default is true, this is not a real registration but placeholder | |||
| 142 | * for Contact header derived from a transport address. | |||
| 143 | * | |||
| 144 | * If nr_secure is true, this registration supports SIPS/TLS. | |||
| 145 | * | |||
| 146 | * If nr_public is true, transport should have public address. | |||
| 147 | */ | |||
| 148 | unsigned nr_default:1, nr_secure:1, nr_public:1, nr_ip4:1, nr_ip6:1; | |||
| 149 | ||||
| 150 | /** Stack-generated contact */ | |||
| 151 | unsigned nr_by_stack:1; | |||
| 152 | ||||
| 153 | unsigned:0; | |||
| 154 | ||||
| 155 | int nr_error_report_id; /**< ID used to ask for error reports from tport */ | |||
| 156 | ||||
| 157 | sip_route_t *nr_route; /**< Outgoing Service-Route */ | |||
| 158 | sip_path_t *nr_path; /**< Incoming Path */ | |||
| 159 | ||||
| 160 | tport_t *nr_tport; /**< Transport to be used when registered */ | |||
| 161 | nua_dialog_state_t *nr_dialogs; /**< List of our dialogs */ | |||
| 162 | ||||
| 163 | #if HAVE_SIGCOMP | |||
| 164 | struct sigcomp_compartment *nr_compartment; | |||
| 165 | #endif | |||
| 166 | ||||
| 167 | outbound_t *nr_ob; /**< Outbound connection */ | |||
| 168 | }; | |||
| 169 | ||||
| 170 | nua_usage_class const nua_register_usage[1] = { | |||
| 171 | { | |||
| 172 | sizeof (struct register_usage), | |||
| 173 | (sizeof nua_register_usage), | |||
| 174 | nua_register_usage_add, | |||
| 175 | nua_register_usage_remove, | |||
| 176 | nua_register_usage_name, | |||
| 177 | nua_register_usage_update_params, | |||
| 178 | nua_register_usage_peer_info, | |||
| 179 | nua_register_usage_refresh, | |||
| 180 | nua_register_usage_shutdown | |||
| 181 | }}; | |||
| 182 | ||||
| 183 | static char const *nua_register_usage_name(nua_dialog_usage_t const *du) | |||
| 184 | { | |||
| 185 | return "register"; | |||
| 186 | } | |||
| 187 | ||||
| 188 | static int nua_register_usage_add(nua_handle_t *nh, | |||
| 189 | nua_dialog_state_t *ds, | |||
| 190 | nua_dialog_usage_t *du) | |||
| 191 | { | |||
| 192 | nua_registration_t *nr = NUA_DIALOG_USAGE_PRIVATE(du)((void *)((du) + 1)); | |||
| 193 | ||||
| 194 | if (ds->ds_has_register) | |||
| 195 | return -1; /* There can be only one usage */ | |||
| 196 | ||||
| 197 | ds->ds_has_register = 1; | |||
| 198 | ||||
| 199 | nr->nr_public = 1; /* */ | |||
| 200 | ||||
| 201 | return 0; | |||
| 202 | } | |||
| 203 | ||||
| 204 | ||||
| 205 | static void nua_register_usage_remove(nua_handle_t *nh, | |||
| 206 | nua_dialog_state_t *ds, | |||
| 207 | nua_dialog_usage_t *du, | |||
| 208 | nua_client_request_t *cr, | |||
| 209 | nua_server_request_t *sr) | |||
| 210 | { | |||
| 211 | nua_registration_t *nr = NUA_DIALOG_USAGE_PRIVATE(du)((void *)((du) + 1)); | |||
| 212 | ||||
| 213 | if (nr->nr_list) | |||
| 214 | nua_registration_remove(nr); /* Remove from list of registrations */ | |||
| 215 | ||||
| 216 | if (nr->nr_ob) | |||
| 217 | outbound_unref(nr->nr_ob); | |||
| 218 | ||||
| 219 | #if HAVE_SIGCOMP | |||
| 220 | if (nr->nr_compartment) | |||
| 221 | sigcomp_compartment_unref(nr->nr_compartment); | |||
| 222 | nr->nr_compartment = NULL((void*)0); | |||
| 223 | #endif | |||
| 224 | ||||
| 225 | if (nr->nr_error_report_id) | |||
| 226 | tport_release(nr->nr_tport, nr->nr_error_report_id, NULL((void*)0), NULL((void*)0), nr, 0); | |||
| 227 | ||||
| 228 | if (nr->nr_tport) | |||
| 229 | tport_unref(nr->nr_tport), nr->nr_tport = NULL((void*)0); | |||
| 230 | ||||
| 231 | ds->ds_has_register = 0; /* There can be only one */ | |||
| 232 | } | |||
| 233 | ||||
| 234 | ||||
| 235 | /** @internal Store information about registrar. */ | |||
| 236 | static void nua_register_usage_peer_info(nua_dialog_usage_t *du, | |||
| 237 | nua_dialog_state_t const *ds, | |||
| 238 | sip_t const *sip) | |||
| 239 | { | |||
| 240 | nua_registration_t *nr = NUA_DIALOG_USAGE_PRIVATE(du)((void *)((du) + 1)); | |||
| 241 | if (nr->nr_ob) | |||
| 242 | outbound_peer_info(nr->nr_ob, sip); | |||
| 243 | } | |||
| 244 | ||||
| 245 | /* ======================================================================== */ | |||
| 246 | /* REGISTER */ | |||
| 247 | ||||
| 248 | static void nua_register_connection_closed(tp_stack_t *sip_stack, | |||
| 249 | nua_registration_t *nr, | |||
| 250 | tport_t *tport, | |||
| 251 | msg_t *msg, | |||
| 252 | int error); | |||
| 253 | ||||
| 254 | /* Interface towards outbound_t */ | |||
| 255 | sip_contact_t *nua_handle_contact_by_via(nua_handle_t *nh, | |||
| 256 | su_home_t *home, | |||
| 257 | int in_dialog, | |||
| 258 | sip_via_t const *v, | |||
| 259 | char const *transport, | |||
| 260 | char const *m_param, | |||
| 261 | ...); | |||
| 262 | ||||
| 263 | static int nua_stack_outbound_refresh(nua_handle_t *, | |||
| 264 | outbound_t *ob); | |||
| 265 | ||||
| 266 | static int nua_stack_outbound_status(nua_handle_t *, | |||
| 267 | outbound_t *ob, | |||
| 268 | int status, char const *phrase, | |||
| 269 | tag_type_t tag, tag_value_t value, ...); | |||
| 270 | ||||
| 271 | static int nua_stack_outbound_failed(nua_handle_t *, | |||
| 272 | outbound_t *ob, | |||
| 273 | int status, char const *phrase, | |||
| 274 | tag_type_t tag, tag_value_t value, ...); | |||
| 275 | ||||
| 276 | static int nua_stack_outbound_credentials(nua_handle_t *, auth_client_t **auc); | |||
| 277 | ||||
| 278 | outbound_owner_vtable nua_stack_outbound_callbacks = { | |||
| 279 | sizeof nua_stack_outbound_callbacks, | |||
| 280 | /* oo_contact */ nua_handle_contact_by_via, | |||
| 281 | /* oo_refresh */ nua_stack_outbound_refresh, | |||
| 282 | /* oo_status */ nua_stack_outbound_status, | |||
| 283 | /* oo_probe_error */ nua_stack_outbound_failed, | |||
| 284 | /* oo_keepalive_error */ nua_stack_outbound_failed, | |||
| 285 | /* oo_credentials */ nua_stack_outbound_credentials | |||
| 286 | }; | |||
| 287 | ||||
| 288 | /**@fn void nua_register(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...); | |||
| 289 | * | |||
| 290 | * Send SIP REGISTER request to the registrar. | |||
| 291 | * | |||
| 292 | * Request status will be delivered to the application using #nua_r_register | |||
| 293 | * event. When successful the registration will be updated periodically. | |||
| 294 | * | |||
| 295 | * The handle used for registration cannot be used for any other purposes. | |||
| 296 | * | |||
| 297 | * @param nh Pointer to operation handle | |||
| 298 | * @param tag, value, ... List of tagged parameters | |||
| 299 | * | |||
| 300 | * @return | |||
| 301 | * nothing | |||
| 302 | * | |||
| 303 | * @par Related tags: | |||
| 304 | * NUTAG_REGISTRAR(), NUTAG_INSTANCE(), NUTAG_OUTBOUND(), | |||
| 305 | * NUTAG_KEEPALIVE(), NUTAG_KEEPALIVE_STREAM(), NUTAG_M_USERNAME(), | |||
| 306 | * NUTAG_M_DISPLAY(), NUTAG_M_PARAMS(), NUTAG_M_FEATURES() | |||
| 307 | * | |||
| 308 | * @par Events: | |||
| 309 | * #nua_r_register, #nua_i_outbound | |||
| 310 | * | |||
| 311 | * @par Generating Contact Header | |||
| 312 | * | |||
| 313 | * If the application did not specify the Contact header in the tags, | |||
| 314 | * nua_register() will generate one. It will obtain the schema, IP address | |||
| 315 | * for the host and port number for the Contact URI from the transport | |||
| 316 | * socket. The diplay name is taken from NUTAG_M_DISPLAY(), URL username | |||
| 317 | * part is taken from NUTAG_M_USERNAME(), URI parameters from | |||
| 318 | * NUTAG_M_PARAMS(), and Contact header parameters from NUTAG_M_FEATURES(). | |||
| 319 | * If NUTAG_CALLEE_CAPS(1) is specified, additional Contact header | |||
| 320 | * parameters are generated based on SDP capabilities and SIP @Allow header. | |||
| 321 | * | |||
| 322 | * Note that @b nua may append a identifier of its own to the @Contact URI | |||
| 323 | * username. Such nua-generated identifier trailer always starts with "=" | |||
| 324 | * (equal sign), rest of the nua-generated identifier may contain any | |||
| 325 | * url-unreserved characters except "=". | |||
| 326 | * | |||
| 327 | * Likewise, nua may add transport parameters (such as "transport=tcp" or | |||
| 328 | * "maddr") to the @Contact URI. It can add addtional header parameters, like | |||
| 329 | * "+sip.instance" or "reg-id", too. | |||
| 330 | * | |||
| 331 | * For instance, if application uses tags like | |||
| 332 | * @code | |||
| 333 | * nua_register(nh, | |||
| 334 | * NUTAG_M_DISPLAY("1"), | |||
| 335 | * NUTAG_M_USERNAME("line-1"), | |||
| 336 | * NUTAG_M_PARAMS("user=phone"), | |||
| 337 | * NUTAG_M_FEATURES("audio"), | |||
| 338 | * NUTAG_CALLEE_CAPS(0), | |||
| 339 | * TAG_END()) | |||
| 340 | * @endcode | |||
| 341 | * @b nua can generate a Contact header like | |||
| 342 | * @code | |||
| 343 | * Contact: 1 <sip:line-1=SSQAIbjv@192.168.1.200;transport=tcp;user=phone> | |||
| 344 | * ;audio;reg-id=1 | |||
| 345 | * ;+sip.instance=urn:uuid:97701ad9-39df-1229-1083-dbc0a85f029c | |||
| 346 | * @endcode | |||
| 347 | * | |||
| 348 | * The incoming request from the proxy should contain the registered contact | |||
| 349 | * URI as the request URI. The application can use the username prefix set | |||
| 350 | * by NUTAG_M_USERNAME() and the non-transport parameters of the request URI | |||
| 351 | * set by NUTAG_M_PARAMS() when determining to which registration the | |||
| 352 | * incoming request belongs. | |||
| 353 | * | |||
| 354 | * For example, a request line correspoding to the @Contact in above example | |||
| 355 | * may look like: | |||
| 356 | * @code | |||
| 357 | * INVITE sip:line-1=SSQAIbjv@192.168.1.200;user=phone SIP/2.0 | |||
| 358 | * @endcode | |||
| 359 | * | |||
| 360 | * @sa NUTAG_M_DISPLAY(), NUTAG_M_USERNAME(), NUTAG_M_PARAMS(), | |||
| 361 | * NUTAG_M_FEATURES(), NUTAG_CALLEE_CAPS(). | |||
| 362 | * | |||
| 363 | * @par NAT, Firewall and Outbound Support | |||
| 364 | * | |||
| 365 | * Normally, @b nua will start start a protocol engine for outbound | |||
| 366 | * connections used for NAT and firewall traversal and connectivity checks | |||
| 367 | * when registering. | |||
| 368 | * | |||
| 369 | * @note If the application provides @b nua with a | |||
| 370 | * @Contact header of its own (or includes a SIPTAG_CONTACT(NULL) tag in | |||
| 371 | * nua_register() tags), the outbound protocol engine is not started. It is | |||
| 372 | * assumed that the application knows better what it is doing when it sets | |||
| 373 | * the @Contact, or it is using experimental CPL upload as specified in | |||
| 374 | * <a href="http://www.ietf.org/internet-drafts/draft-lennox-sip-reg-payload-01.txt"> | |||
| 375 | * draft-lennox-sip-reg-payload-01.txt</a>. | |||
| 376 | * | |||
| 377 | * First, outbound engine will probe for NATs in between UA and registrar. | |||
| 378 | * It will send a REGISTER request as usual. Upon receiving the response it | |||
| 379 | * checks for the presence of "received" and "rport" parameters in the Via | |||
| 380 | * header returned by registrar. The presence of NAT is determined from the | |||
| 381 | * "received" parameter in a Via header. When a REGISTER request was sent, | |||
| 382 | * the stack inserted the actual source IP address in the Via header: if | |||
| 383 | * that is different from the source IP address seen by the registrar, the | |||
| 384 | * registrar inserts the source IP address it sees into the "received" | |||
| 385 | * parameter. | |||
| 386 | * | |||
| 387 | * Please note that an ALG (application-level gateway) modifying the Via | |||
| 388 | * headers in outbound requests and again in incoming responses will make | |||
| 389 | * the above-described NAT check to fail. | |||
| 390 | * | |||
| 391 | * The response to the initial REGISTER should also include option tags | |||
| 392 | * indicating whether registrar supports various SIP extension options: @e | |||
| 393 | * outbound, @e pref, @e path, @e gruu. | |||
| 394 | * | |||
| 395 | * Basically, @e outbound means that instead of registering its contact URI | |||
| 396 | * with a particular address-of-record URI, the user-agent registers a | |||
| 397 | * transport-level connection. Such a connection is identified on the | |||
| 398 | * Contact header field with an instance identifier, application-provided | |||
| 399 | * @ref NUTAG_INSTANCE() "unique string" identifying the user-agent instance | |||
| 400 | * and a stack-generated numeric index identifying the transport-level | |||
| 401 | * connection. | |||
| 402 | * | |||
| 403 | * If the @e outbound extension is supported, NUTAG_OUTBOUND() contains | |||
| 404 | * option string "outbound" and the application has provided an instance | |||
| 405 | * identifer to the stack with NUTAG_INSTANCE(), the nua_register() will try | |||
| 406 | * to use outbound. | |||
| 407 | * | |||
| 408 | * If @e outbound is not supported, nua_register() has to generate a URI | |||
| 409 | * that can be used to reach it from outside. It will check for public | |||
| 410 | * transport addresses detected by underlying stack with, e.g., STUN, UPnP | |||
| 411 | * or SOCKS. If there are public addresses, nua_register() will use them. If | |||
| 412 | * there is no public address, it will try to generate a Contact URI from | |||
| 413 | * the "received" and "rport" parameters found in the Via header of the | |||
| 414 | * response message. | |||
| 415 | * | |||
| 416 | * @todo Actually generate public addresses. | |||
| 417 | * | |||
| 418 | * You can disable this kind of NAT traversal by setting "no-natify" into | |||
| 419 | * NUTAG_OUTBOUND() options string. | |||
| 420 | * | |||
| 421 | * @par GRUU and Service-Route | |||
| 422 | * | |||
| 423 | * After a successful response to the REGISTER request has been received, | |||
| 424 | * nua_register() will update the information about the registration based | |||
| 425 | * on it. If there is a "gruu" parameter included in the response, | |||
| 426 | * nua_register() will save it and use the gruu URI in the Contact header | |||
| 427 | * fields of dialog-establishing messages, such as INVITE or SUBSCRIBE. | |||
| 428 | * Also, if the registrar has included a Service-Route header in the | |||
| 429 | * response, and the service route feature has not been disabled using | |||
| 430 | * NUTAG_SERVICE_ROUTE_ENABLE(), the route URIs from the Service-Route | |||
| 431 | * header will be used for initial non-REGISTER requests. | |||
| 432 | * | |||
| 433 | * The #nua_r_register message will include the contact header and route | |||
| 434 | * used in with the registration. | |||
| 435 | * | |||
| 436 | * @par Registration Keep-Alive | |||
| 437 | * | |||
| 438 | * After the registration has successfully completed the nua_register() will | |||
| 439 | * validate the registration and initiate the keepalive mechanism, too. The | |||
| 440 | * user-agent validates the registration by sending a OPTIONS requests to | |||
| 441 | * itself. If there is an error, nua_register() will indicate that to the | |||
| 442 | * application using #nua_i_outbound event, and start unregistration | |||
| 443 | * procedure (unless that has been explicitly disabled). | |||
| 444 | * | |||
| 445 | * You can disable validation by inserting "no-validate" into | |||
| 446 | * NUTAG_OUTBOUND() string. | |||
| 447 | * | |||
| 448 | * The keepalive mechanism depends on the network features detected earlier. | |||
| 449 | * If @a outbound extension is used, the STUN keepalives will be used. | |||
| 450 | * Otherwise, NUA stack will repeatedly send OPTIONS requests to itself. In | |||
| 451 | * order to save bandwidth, it will include Max-Forwards: 0 in the | |||
| 452 | * keep-alive requests, however. The keepalive interval is determined by | |||
| 453 | * NUTAG_KEEPALIVE() parameter. If the interval is 0, no keepalive messages | |||
| 454 | * is sent. | |||
| 455 | * | |||
| 456 | * You can disable keepalive OPTIONS by inserting "no-options-keepalive" | |||
| 457 | * into NUTAG_OUTBOUND() string. Currently there are no other keepalive | |||
| 458 | * mechanisms available. | |||
| 459 | * | |||
| 460 | * The value of NUTAG_KEEPALIVE_STREAM(), if specified, is used to indicate | |||
| 461 | * the desired transport-layer keepalive interval for stream-based | |||
| 462 | * transports like TLS and TCP. | |||
| 463 | * | |||
| 464 | * As alternative to OPTIONS/STUN keepalives, the client can propose | |||
| 465 | * a more frequent registration refresh interval with | |||
| 466 | * NUTAG_M_FEATURES() (e.g. NUTAG_M_FEATURES("expires=120") given as | |||
| 467 | * parameter to nua_register()). | |||
| 468 | * | |||
| 469 | * @sa #nua_r_register, nua_unregister(), #nua_r_unregister, | |||
| 470 | * #nua_i_register, | |||
| 471 | * @RFC3261 section 10, | |||
| 472 | * @Expires, @Contact, @CallID, @CSeq, | |||
| 473 | * @Path, @RFC3327, @ServiceRoute, @RFC3608, @RFC3680, | |||
| 474 | * NUTAG_REGISTRAR(), NUTAG_INSTANCE(), NUTAG_OUTBOUND(), | |||
| 475 | * NUTAG_KEEPALIVE(), NUTAG_KEEPALIVE_STREAM(), | |||
| 476 | * SIPTAG_CONTACT(), SIPTAG_CONTACT_STR(), NUTAG_M_USERNAME(), | |||
| 477 | * NUTAG_M_DISPLAY(), NUTAG_M_PARAMS(), NUTAG_M_FEATURES(), | |||
| 478 | */ | |||
| 479 | ||||
| 480 | /** @NUA_EVENT nua_r_register | |||
| 481 | * | |||
| 482 | * Response to an outgoing REGISTER. | |||
| 483 | * | |||
| 484 | * The REGISTER may be sent explicitly by nua_register() or implicitly by | |||
| 485 | * NUA state machines. | |||
| 486 | * | |||
| 487 | * When REGISTER request has been restarted the @a status may be 100 even | |||
| 488 | * while the real response status returned is different. | |||
| 489 | * | |||
| 490 | * @param status response status code | |||
| 491 | * (if the request is retried, @a status is 100, the @a | |||
| 492 | * sip->sip_status->st_status contain the real status code | |||
| 493 | * from the response message, e.g., 302, 401, or 407) | |||
| 494 | * @param phrase a short textual description of @a status code | |||
| 495 | * @param nh operation handle associated with the registration | |||
| 496 | * @param hmagic application context associated with the registration | |||
| 497 | * @param sip response message to REGISTER request or NULL upon an error | |||
| 498 | * (status code is in @a status and | |||
| 499 | * descriptive message in @a phrase parameters) | |||
| 500 | * @param tags empty | |||
| 501 | * | |||
| 502 | * @sa nua_register(), nua_unregister(), #nua_r_unregister, | |||
| 503 | * @Contact, @CallID, @CSeq, @RFC3261 section 10, | |||
| 504 | * @Path, @RFC3327, @ServiceRoute, @RFC3608, @RFC3680 | |||
| 505 | * | |||
| 506 | * @END_NUA_EVENT | |||
| 507 | */ | |||
| 508 | ||||
| 509 | /**@fn void nua_unregister(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...); | |||
| 510 | * Unregister. | |||
| 511 | * | |||
| 512 | * Send a REGISTER request with expiration time 0. This removes the | |||
| 513 | * registration from the registrar. If the handle was earlier used | |||
| 514 | * with nua_register() the periodic updates will be terminated. | |||
| 515 | * | |||
| 516 | * If a SIPTAG_CONTACT_STR() with argument "*" is used, all the | |||
| 517 | * registrations will be removed from the registrar otherwise only the | |||
| 518 | * contact address belonging to the NUA stack is removed. | |||
| 519 | * | |||
| 520 | * @param nh Pointer to operation handle | |||
| 521 | * @param tag, value, ... List of tagged parameters | |||
| 522 | * | |||
| 523 | * @return | |||
| 524 | * nothing | |||
| 525 | * | |||
| 526 | * @par Related tags: | |||
| 527 | * NUTAG_REGISTRAR() \n | |||
| 528 | * Header tags defined in <sofia-sip/sip_tag.h> except SIPTAG_EXPIRES() or SIPTAG_EXPIRES_STR() | |||
| 529 | * | |||
| 530 | * @par Events: | |||
| 531 | * #nua_r_unregister | |||
| 532 | * | |||
| 533 | * @sa nua_register(), #nua_r_register, nua_handle_destroy(), nua_shutdown(), | |||
| 534 | * #nua_i_register, | |||
| 535 | * @Expires, @Contact, @CallID, @CSeq, @RFC3261 section 10, | |||
| 536 | * @Path, @RFC3327, @ServiceRoute, @RFC3608, @RFC3680, | |||
| 537 | * NUTAG_REGISTRAR(), NUTAG_INSTANCE(), NUTAG_OUTBOUND(), | |||
| 538 | * NUTAG_KEEPALIVE(), NUTAG_KEEPALIVE_STREAM(), | |||
| 539 | * SIPTAG_CONTACT(), SIPTAG_CONTACT_STR(), NUTAG_M_USERNAME(), | |||
| 540 | * NUTAG_M_DISPLAY(), NUTAG_M_PARAMS(), NUTAG_M_FEATURES(), | |||
| 541 | */ | |||
| 542 | ||||
| 543 | /** @NUA_EVENT nua_r_unregister | |||
| 544 | * | |||
| 545 | * Answer to outgoing un-REGISTER. | |||
| 546 | * | |||
| 547 | * @param status response status code | |||
| 548 | * (if the request is retried, @a status is 100, the @a | |||
| 549 | * sip->sip_status->st_status contain the real status code | |||
| 550 | * from the response message, e.g., 302, 401, or 407) | |||
| 551 | * @param phrase a short textual description of @a status code | |||
| 552 | * @param nh operation handle associated with the registration | |||
| 553 | * @param hmagic application context associated with the registration | |||
| 554 | * @param sip response message to REGISTER request or NULL upon an error | |||
| 555 | * (status code is in @a status and | |||
| 556 | * descriptive message in @a phrase parameters) | |||
| 557 | * @param tags empty | |||
| 558 | * | |||
| 559 | * @sa nua_unregister(), nua_register(), #nua_r_register, | |||
| 560 | * @Contact, @CallID, @CSeq, @RFC3261 section 10, | |||
| 561 | * @Path, @RFC3327, @ServiceRoute, @RFC3608, @RFC3680 | |||
| 562 | * | |||
| 563 | * @END_NUA_EVENT | |||
| 564 | */ | |||
| 565 | ||||
| 566 | static int nua_register_client_template(nua_client_request_t *cr, | |||
| 567 | msg_t **return_msg, | |||
| 568 | tagi_t const *tags); | |||
| 569 | static int nua_register_client_init(nua_client_request_t *cr, | |||
| 570 | msg_t *, sip_t *, | |||
| 571 | tagi_t const *tags); | |||
| 572 | static int nua_register_client_request(nua_client_request_t *cr, | |||
| 573 | msg_t *, sip_t *, | |||
| 574 | tagi_t const *tags); | |||
| 575 | static int nua_register_client_check_restart(nua_client_request_t *cr, | |||
| 576 | int status, char const *phrase, | |||
| 577 | sip_t const *sip); | |||
| 578 | static int nua_register_client_response(nua_client_request_t *cr, | |||
| 579 | int status, char const *phrase, | |||
| 580 | sip_t const *sip); | |||
| 581 | ||||
| 582 | static nua_client_methods_t const nua_register_client_methods = { | |||
| 583 | SIP_METHOD_REGISTERsip_method_register, "REGISTER", /* crm_method, crm_method_name */ | |||
| 584 | 0, /* crm_extra */ | |||
| 585 | { /* crm_flags */ | |||
| 586 | /* create_dialog */ 1, | |||
| 587 | /* in_dialog */ 0, | |||
| 588 | /* target refresh */ 0 | |||
| 589 | }, | |||
| 590 | nua_register_client_template, /* crm_template */ | |||
| 591 | nua_register_client_init, /* crm_init */ | |||
| 592 | nua_register_client_request, /* crm_send */ | |||
| 593 | nua_register_client_check_restart, /* crm_check_restart */ | |||
| 594 | nua_register_client_response, /* crm_recv */ | |||
| 595 | NULL((void*)0), /* crm_preliminary */ | |||
| 596 | NULL((void*)0), /* crm_report */ | |||
| 597 | NULL((void*)0), /* crm_complete */ | |||
| 598 | }; | |||
| 599 | ||||
| 600 | /**@internal Send REGISTER. */ | |||
| 601 | int nua_stack_register(nua_t *nua, | |||
| 602 | nua_handle_t *nh, | |||
| 603 | nua_event_t e, | |||
| 604 | tagi_t const *tags) | |||
| 605 | { | |||
| 606 | return nua_client_create(nh, e, &nua_register_client_methods, tags); | |||
| 607 | } | |||
| 608 | ||||
| 609 | static int nua_register_client_template(nua_client_request_t *cr, | |||
| 610 | msg_t **return_msg, | |||
| 611 | tagi_t const *tags) | |||
| 612 | { | |||
| 613 | nua_dialog_usage_t *du; | |||
| 614 | ||||
| 615 | if (cr->cr_event == nua_r_register) | |||
| 616 | return 0; | |||
| 617 | ||||
| 618 | /* Use a copy of REGISTER message as the template for un-REGISTER */ | |||
| 619 | du = nua_dialog_usage_get(cr->cr_owner->nh_ds, nua_register_usage, NULL((void*)0)); | |||
| 620 | if (du && du->du_cr) { | |||
| 621 | if (nua_client_set_target(cr, du->du_cr->cr_target) < 0) | |||
| 622 | return -1; | |||
| 623 | *return_msg = msg_copy(du->du_cr->cr_msg); | |||
| 624 | return 1; | |||
| 625 | } | |||
| 626 | ||||
| 627 | return 0; | |||
| 628 | } | |||
| 629 | ||||
| 630 | static int nua_register_client_init(nua_client_request_t *cr, | |||
| 631 | msg_t *msg, sip_t *sip, | |||
| 632 | tagi_t const *tags) | |||
| 633 | { | |||
| 634 | nua_handle_t *nh = cr->cr_owner; | |||
| 635 | nua_dialog_usage_t *du; | |||
| 636 | nua_registration_t *nr; | |||
| 637 | sip_to_t const *aor = sip->sip_to; | |||
| 638 | ||||
| 639 | int unreg; | |||
| 640 | ||||
| 641 | /* Explicit empty (NULL) contact - used for CPL store/remove? */ | |||
| 642 | if (!sip->sip_contact && cr->cr_has_contact) | |||
| 643 | /* Do not create any usage */ | |||
| 644 | return 0; | |||
| 645 | ||||
| 646 | unreg = cr->cr_event != nua_r_register || | |||
| 647 | (sip->sip_expires && sip->sip_expires->ex_delta == 0); | |||
| 648 | if (unreg) | |||
| 649 | nua_client_set_terminating(cr, 1); | |||
| 650 | ||||
| 651 | du = nua_dialog_usage_add(nh, nh->nh_ds, nua_register_usage, NULL((void*)0)); | |||
| 652 | if (du == NULL((void*)0)) | |||
| 653 | return -1; | |||
| 654 | nr = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0)); | |||
| 655 | ||||
| 656 | if (nua_client_bind(cr, du) < 0) | |||
| 657 | return -1; | |||
| 658 | ||||
| 659 | if (!nr->nr_list) { | |||
| 660 | nua_registration_add(&nh->nh_nua->nua_registrations, nr); | |||
| 661 | ||||
| 662 | if (aor == NULL((void*)0)) | |||
| 663 | aor = sip->sip_from; | |||
| 664 | if (aor == NULL((void*)0)) | |||
| 665 | aor = nh->nh_nua->nua_from; | |||
| 666 | ||||
| 667 | if (nua_registration_set_aor(nh->nh_home, nr, aor) < 0) | |||
| 668 | return -1; | |||
| 669 | } | |||
| 670 | ||||
| 671 | if (nua_registration_set_contact(nh, nr, sip->sip_contact, unreg) < 0) | |||
| 672 | return -1; | |||
| 673 | ||||
| 674 | if (!nr->nr_ob && (NH_PGET(nh, outbound)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_outbound ? ((nh )->nh_prefs)->nhp_outbound : ((nh)->nh_nua->nua_handles ->nh_prefs)->nhp_outbound) || NH_PGET(nh, instance)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_instance ? ((nh )->nh_prefs)->nhp_instance : ((nh)->nh_nua->nua_handles ->nh_prefs)->nhp_instance))) { | |||
| 675 | nr->nr_ob = outbound_new(nh, &nua_stack_outbound_callbacks, | |||
| 676 | nh->nh_nua->nua_root, | |||
| 677 | nh->nh_nua->nua_nta, | |||
| 678 | NH_PGET(nh, instance)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_instance ? ((nh )->nh_prefs)->nhp_instance : ((nh)->nh_nua->nua_handles ->nh_prefs)->nhp_instance)); | |||
| 679 | if (!nr->nr_ob) | |||
| 680 | return nua_client_return(cr, 900, "Cannot create outbound", msg); | |||
| 681 | ||||
| 682 | nua_register_usage_update_params(du, | |||
| 683 | NULL((void*)0), | |||
| 684 | nh->nh_prefs, | |||
| 685 | nh->nh_dprefsnh_nua->nua_handles->nh_prefs); | |||
| 686 | } | |||
| 687 | ||||
| 688 | if (nr->nr_ob) { | |||
| 689 | outbound_t *ob = nr->nr_ob; | |||
| 690 | sip_contact_t *m; | |||
| 691 | ||||
| 692 | if (!unreg && sip->sip_contact) { | |||
| 693 | for (m = sip->sip_contact; m; m = m->m_next) | |||
| 694 | if (!m->m_expires || strtoul(m->m_expires, NULL((void*)0), 10) != 0) | |||
| 695 | break; | |||
| 696 | ||||
| 697 | if (m == NULL((void*)0)) | |||
| 698 | unreg = 1; /* All contacts have expires=0 */ | |||
| 699 | } | |||
| 700 | ||||
| 701 | if (outbound_set_contact(ob, sip->sip_contact, nr->nr_via, unreg) < 0) | |||
| 702 | return nua_client_return(cr, 900, "Cannot set outbound contact", msg); | |||
| 703 | } | |||
| 704 | ||||
| 705 | return 0; | |||
| 706 | } | |||
| 707 | ||||
| 708 | static | |||
| 709 | int nua_register_client_request(nua_client_request_t *cr, | |||
| 710 | msg_t *msg, sip_t *sip, | |||
| 711 | tagi_t const *tags) | |||
| 712 | { | |||
| 713 | nua_handle_t *nh = cr->cr_owner; | |||
| 714 | nua_dialog_usage_t *du = cr->cr_usage; | |||
| 715 | nua_registration_t *nr; | |||
| 716 | sip_contact_t *m, *contacts = sip->sip_contact; | |||
| 717 | char const *min_expires = NULL((void*)0); | |||
| 718 | int unreg; | |||
| 719 | tport_t *tport = NULL((void*)0); | |||
| 720 | ||||
| 721 | (void)nh; | |||
| 722 | ||||
| 723 | /* Explicit empty (NULL) contact - used for CPL store/remove? */ | |||
| 724 | if (!contacts && cr->cr_has_contact) | |||
| 725 | return nua_base_client_request(cr, msg, sip, tags); | |||
| 726 | ||||
| 727 | if ((du && du->du_shutdown) || | |||
| 728 | (sip->sip_expires && sip->sip_expires->ex_delta == 0)) | |||
| 729 | nua_client_set_terminating(cr, 1); | |||
| 730 | ||||
| 731 | if (contacts) { | |||
| 732 | if (!cr->cr_terminating) { | |||
| 733 | for (m = contacts; m; m = m->m_next) | |||
| 734 | if (!m->m_expires || strtoul(m->m_expires, NULL((void*)0), 10) != 0) | |||
| 735 | break; | |||
| 736 | /* All contacts have expires=0 */ | |||
| 737 | if (m == NULL((void*)0)) | |||
| 738 | nua_client_set_terminating(cr, 1); | |||
| 739 | } | |||
| 740 | } | |||
| 741 | ||||
| 742 | unreg = cr->cr_terminating; | |||
| 743 | ||||
| 744 | nr = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0)); | |||
| 745 | ||||
| 746 | if (nr) { | |||
| 747 | if (nr->nr_ob) { | |||
| 748 | outbound_stop_keepalive(nr->nr_ob); | |||
| 749 | outbound_start_registering(nr->nr_ob); | |||
| 750 | } | |||
| 751 | ||||
| 752 | if (nr->nr_by_stack) { | |||
| 753 | sip_contact_t *m = nr->nr_contact, *previous = NULL((void*)0); | |||
| 754 | ||||
| 755 | outbound_get_contacts(nr->nr_ob, &m, &previous); | |||
| 756 | ||||
| 757 | sip_add_dup(msg, sip, (sip_header_t *)m); | |||
| 758 | /* previous is an outdated contact generated by stack | |||
| 759 | * and it is now unregistered */ | |||
| 760 | if (previous) | |||
| 761 | sip_add_dup(msg, sip, (sip_header_t *)previous); | |||
| 762 | } | |||
| 763 | ||||
| 764 | tport = nr->nr_tport; | |||
| 765 | } | |||
| 766 | ||||
| 767 | for (m = sip->sip_contact; m; m = m->m_next) { | |||
| 768 | if (m->m_url->url_type == url_any) { | |||
| 769 | /* If there is a '*' in contact list, remove everything else */ | |||
| 770 | while (m != sip->sip_contact) | |||
| 771 | sip_header_remove(msg, sip, (sip_header_t *)sip->sip_contact); | |||
| 772 | while (m->m_next) | |||
| 773 | sip_header_remove(msg, sip, (sip_header_t *)m->m_next); | |||
| 774 | contacts = m; | |||
| 775 | break; | |||
| 776 | } | |||
| 777 | ||||
| 778 | if (!m->m_expires) | |||
| 779 | continue; | |||
| 780 | if (unreg) { | |||
| 781 | /* Remove the expire parameters from contacts */ | |||
| 782 | msg_header_remove_param(m->m_common, "expires"); | |||
| 783 | } | |||
| 784 | else if (nr && nr->nr_min_expires && | |||
| 785 | strtoul(m->m_expires, 0, 10) < nr->nr_min_expires) { | |||
| 786 | if (min_expires == NULL((void*)0)) | |||
| 787 | min_expires = su_sprintf(msg_home(msg)((su_home_t*)(msg)), "expires=%lu", | |||
| 788 | nr->nr_min_expires); | |||
| 789 | msg_header_replace_param(msg_home(msg)((su_home_t*)(msg)), m->m_common, min_expires); | |||
| 790 | } | |||
| 791 | } | |||
| 792 | ||||
| 793 | return nua_base_client_trequest(cr, msg, sip, | |||
| 794 | TAG_IF(unreg, SIPTAG_EXPIRES_STR("0"))!(unreg) ? tag_skip : siptag_expires_str, tag_str_v("0"), | |||
| 795 | #if 0 | |||
| 796 | TAG_IF(unreg, NTATAG_SIGCOMP_CLOSE(1))!(unreg) ? tag_skip : ntatag_sigcomp_close, tag_bool_v((1)), | |||
| 797 | TAG_IF(!unreg, NTATAG_COMP("sigcomp"))!(!unreg) ? tag_skip : ntatag_comp, tag_str_v(("sigcomp")), | |||
| 798 | #endif | |||
| 799 | NTATAG_TPORT(tport)ntatag_tport, tag_ptr_v((tport)), | |||
| 800 | TAG_NEXT(tags)tag_next, (tag_value_t)(tags)); | |||
| 801 | } | |||
| 802 | ||||
| 803 | static int nua_register_client_check_restart(nua_client_request_t *cr, | |||
| 804 | int status, char const *phrase, | |||
| 805 | sip_t const *sip) | |||
| 806 | { | |||
| 807 | nua_registration_t *nr = nua_dialog_usage_private(cr->cr_usage)((cr->cr_usage) ? (void*)((cr->cr_usage) + 1) : ((void* )0)); | |||
| 808 | unsigned short retry_count = cr->cr_retry_count; | |||
| 809 | int restart = 0, retry; | |||
| 810 | ||||
| 811 | if (nr && nr->nr_ob) { | |||
| 812 | msg_t *_reqmsg = nta_outgoing_getrequest(cr->cr_orq); | |||
| 813 | sip_t *req = sip_object(_reqmsg); msg_destroy(_reqmsg); | |||
| 814 | ||||
| 815 | retry = outbound_register_response(nr->nr_ob, cr->cr_terminating, | |||
| 816 | req, sip); | |||
| 817 | ||||
| 818 | restart = retry >= ob_reregister_now; | |||
| 819 | ||||
| 820 | if (retry == ob_reregister) | |||
| 821 | /* outbound restarts REGISTER later */; | |||
| 822 | ||||
| 823 | if (retry < 0) | |||
| 824 | /* XXX - report an error? */; | |||
| 825 | } | |||
| 826 | ||||
| 827 | if (nr && status == 423) { | |||
| 828 | if (sip->sip_min_expires) | |||
| 829 | nr->nr_min_expires = sip->sip_min_expires->me_delta; | |||
| 830 | } | |||
| 831 | ||||
| 832 | /* Check for status-specific reasons to retry */ | |||
| 833 | if (nua_base_client_check_restart(cr, status, phrase, sip)) | |||
| 834 | return 1; | |||
| 835 | ||||
| 836 | /* Restart only if nua_base_client_check_restart() did not try to restart */ | |||
| 837 | if (restart && retry_count == cr->cr_retry_count) | |||
| 838 | return nua_client_restart(cr, 100, "Outbound NAT Detected"); | |||
| 839 | ||||
| 840 | return 0; | |||
| 841 | } | |||
| 842 | ||||
| 843 | static int nua_register_client_response(nua_client_request_t *cr, | |||
| 844 | int status, char const *phrase, | |||
| 845 | sip_t const *sip) | |||
| 846 | { | |||
| 847 | nua_handle_t *nh = cr->cr_owner; | |||
| 848 | nua_dialog_usage_t *du = cr->cr_usage; | |||
| 849 | nua_registration_t *nr = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0)); | |||
| 850 | int ready; | |||
| 851 | ||||
| 852 | ready = du && !cr->cr_terminated && status < 300; | |||
| 853 | ||||
| 854 | if (ready) { | |||
| 855 | sip_time_t mindelta = 0; | |||
| 856 | sip_time_t now = sip_now(), delta, reqdelta, mdelta; | |||
| 857 | ||||
| 858 | sip_contact_t const *m, *sent; | |||
| 859 | ||||
| 860 | msg_t *_reqmsg = nta_outgoing_getrequest(cr->cr_orq); | |||
| 861 | sip_t *req = sip_object(_reqmsg); | |||
| 862 | ||||
| 863 | tport_t *tport; | |||
| 864 | ||||
| 865 | msg_destroy(_reqmsg); | |||
| 866 | ||||
| 867 | assert(nr)((nr) ? (void) (0) : __assert_fail ("nr", "nua_register.c", 867 , __PRETTY_FUNCTION__)); assert(sip)((sip) ? (void) (0) : __assert_fail ("sip", "nua_register.c", 867, __PRETTY_FUNCTION__)); assert(req)((req) ? (void) (0) : __assert_fail ("req", "nua_register.c", 867, __PRETTY_FUNCTION__)); | |||
| 868 | ||||
| 869 | #if HAVE_SIGCOMP | |||
| 870 | { | |||
| 871 | struct sigcomp_compartment *cc; | |||
| 872 | cc = nta_outgoing_compartment(cr->cr_orq); | |||
| 873 | sigcomp_compartment_unref(nr->nr_compartment); | |||
| 874 | nr->nr_compartment = cc; | |||
| 875 | } | |||
| 876 | #endif | |||
| 877 | ||||
| 878 | /* XXX - if store/remove, remove | |||
| 879 | Content-Disposition | |||
| 880 | Content-Type | |||
| 881 | body | |||
| 882 | */ | |||
| 883 | ||||
| 884 | /** Search for lowest delta of SIP contacts we tried to register */ | |||
| 885 | mindelta = SIP_TIME_MAX((sip_time_t)((msg_time_t)(9223372036854775807L *2UL+1UL))); | |||
| 886 | ||||
| 887 | reqdelta = req->sip_expires ? req->sip_expires->ex_delta : 0; | |||
| 888 | ||||
| 889 | for (m = sip->sip_contact; m; m = m->m_next) { | |||
| 890 | if (m->m_url->url_type != url_sip && | |||
| 891 | m->m_url->url_type != url_sips) | |||
| 892 | continue; | |||
| 893 | ||||
| 894 | for (sent = req->sip_contact; sent; sent = sent->m_next) { | |||
| 895 | if (url_cmp(m->m_url, sent->m_url)) | |||
| 896 | continue; | |||
| 897 | ||||
| 898 | if (sent->m_expires) | |||
| 899 | mdelta = strtoul(sent->m_expires, NULL((void*)0), 10); | |||
| 900 | else | |||
| 901 | mdelta = reqdelta; | |||
| 902 | ||||
| 903 | if (mdelta == 0) | |||
| 904 | mdelta = 3600; | |||
| 905 | ||||
| 906 | delta = sip_contact_expires(m, sip->sip_expires, sip->sip_date, | |||
| 907 | mdelta, now); | |||
| 908 | if (delta > 0 && delta < mindelta) | |||
| 909 | mindelta = delta; | |||
| 910 | ||||
| 911 | if (url_cmp_all(m->m_url, sent->m_url) == 0) | |||
| 912 | break; | |||
| 913 | } | |||
| 914 | } | |||
| 915 | ||||
| 916 | if (mindelta == SIP_TIME_MAX((sip_time_t)((msg_time_t)(9223372036854775807L *2UL+1UL)))) | |||
| 917 | mindelta = 3600; | |||
| 918 | ||||
| 919 | nua_dialog_usage_set_refresh(du, mindelta); | |||
| 920 | ||||
| 921 | /* RFC 3608 Section 6.1 Procedures at the UA | |||
| 922 | ||||
| 923 | The UA performs a registration as usual. The REGISTER response may | |||
| 924 | contain a Service-Route header field. If so, the UA MAY store the | |||
| 925 | value of the Service-Route header field in an association with the | |||
| 926 | address-of-record for which the REGISTER transaction had registered a | |||
| 927 | contact. If the UA supports multiple addresses-of-record, it may be | |||
| 928 | able to store multiple service routes, one per address-of-record. If | |||
| 929 | the UA refreshes the registration, the stored value of the Service- | |||
| 930 | Route is updated according to the Service-Route header field of the | |||
| 931 | latest 200 class response. If there is no Service-Route header field | |||
| 932 | in the response, the UA clears any service route for that address- | |||
| 933 | of-record previously stored by the UA. If the re-registration | |||
| 934 | request is refused or if an existing registration expires and the UA | |||
| 935 | chooses not to re-register, the UA SHOULD discard any stored service | |||
| 936 | route for that address-of-record. | |||
| 937 | ||||
| 938 | */ | |||
| 939 | su_free(nh->nh_home, nr->nr_route); | |||
| 940 | nr->nr_route = sip_route_dup(nh->nh_home, sip->sip_service_route); | |||
| 941 | ||||
| 942 | { | |||
| 943 | /* RFC 3327 */ | |||
| 944 | /* Store last URI in Path header */ | |||
| 945 | sip_path_t *path = sip->sip_path; | |||
| 946 | ||||
| 947 | while (path && path->r_next) | |||
| 948 | path = path->r_next; | |||
| 949 | ||||
| 950 | if (!nr->nr_path || !path || | |||
| 951 | url_cmp_all(nr->nr_path->r_url, path->r_url)) { | |||
| 952 | su_free(nh->nh_home, nr->nr_path); | |||
| 953 | nr->nr_path = sip_path_dup(nh->nh_home, path); | |||
| 954 | } | |||
| 955 | } | |||
| 956 | ||||
| 957 | if (sip->sip_to->a_url->url_type == url_sips) | |||
| 958 | nr->nr_secure = 1; | |||
| 959 | ||||
| 960 | if (nr->nr_ob) { | |||
| 961 | outbound_gruuize(nr->nr_ob, sip); | |||
| 962 | outbound_start_keepalive(nr->nr_ob, cr->cr_orq); | |||
| 963 | } | |||
| 964 | ||||
| 965 | tport = nta_outgoing_transport (cr->cr_orq); | |||
| 966 | ||||
| 967 | /* cache persistant connection for registration */ | |||
| 968 | if (tport && tport != nr->nr_tport) { | |||
| 969 | if (nr->nr_error_report_id) { | |||
| 970 | if (tport_release(nr->nr_tport, nr->nr_error_report_id, NULL((void*)0), NULL((void*)0), nr, 0) < 0) | |||
| 971 | SU_DEBUG_1(("nua_register: tport_release() 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_register.c" , (const char *)__func__, 971, "nua_register: tport_release() failed\n" "%s", "")) : (void)0); | |||
| 972 | nr->nr_error_report_id = 0; | |||
| 973 | } | |||
| 974 | tport_unref(nr->nr_tport); | |||
| 975 | nr->nr_tport = tport; | |||
| 976 | ||||
| 977 | if (tport_is_secondary(tport)) { | |||
| 978 | tport_set_params(tport, TPTAG_SDWN_ERROR(1)tptag_sdwn_error, tag_bool_v((1)), TAG_END()(tag_type_t)0, (tag_value_t)0); | |||
| 979 | nr->nr_error_report_id = | |||
| 980 | tport_pend(tport, NULL((void*)0), nua_register_connection_closed, nr); | |||
| 981 | } | |||
| 982 | } | |||
| 983 | else | |||
| 984 | tport_unref(tport); /* note: nta_outgoing_transport() makes a ref */ | |||
| 985 | ||||
| 986 | nua_registration_set_ready(nr, 1); | |||
| 987 | } | |||
| 988 | else if (du) { | |||
| 989 | nua_dialog_usage_reset_refresh(du); | |||
| 990 | ||||
| 991 | su_free(nh->nh_home, nr->nr_route); | |||
| 992 | nr->nr_route = NULL((void*)0); | |||
| 993 | ||||
| 994 | outbound_stop_keepalive(nr->nr_ob); | |||
| 995 | ||||
| 996 | /* release the persistant transport for registration */ | |||
| 997 | if (nr->nr_tport) { | |||
| 998 | if (nr->nr_error_report_id) { | |||
| 999 | if (tport_release(nr->nr_tport, nr->nr_error_report_id, NULL((void*)0), NULL((void*)0), nr, 0) < 0) | |||
| 1000 | SU_DEBUG_1(("nua_register: tport_release() 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_register.c" , (const char *)__func__, 1000, "nua_register: tport_release() failed\n" "%s", "")) : (void)0); | |||
| 1001 | nr->nr_error_report_id = 0; | |||
| 1002 | } | |||
| 1003 | ||||
| 1004 | tport_unref(nr->nr_tport), nr->nr_tport = NULL((void*)0); | |||
| 1005 | } | |||
| 1006 | nua_registration_set_ready(nr, 0); | |||
| 1007 | } | |||
| 1008 | ||||
| 1009 | ||||
| 1010 | return nua_base_client_response(cr, status, phrase, sip, NULL((void*)0)); | |||
| 1011 | } | |||
| 1012 | ||||
| 1013 | static | |||
| 1014 | void nua_register_connection_closed(tp_stack_t *sip_stack, | |||
| 1015 | nua_registration_t *nr, | |||
| 1016 | tport_t *tport, | |||
| 1017 | msg_t *msg, | |||
| 1018 | int error) | |||
| 1019 | { | |||
| 1020 | nua_dialog_usage_t *du; | |||
| 1021 | tp_name_t const *tpn; | |||
| 1022 | int pending; | |||
| 1023 | ||||
| 1024 | assert(nr && tport == nr->nr_tport)((nr && tport == nr->nr_tport) ? (void) (0) : __assert_fail ("nr && tport == nr->nr_tport", "nua_register.c", 1024, __PRETTY_FUNCTION__)); | |||
| 1025 | if (nr == NULL((void*)0) || tport != nr->nr_tport) | |||
| 1026 | return; | |||
| 1027 | ||||
| 1028 | du = NUA_DIALOG_USAGE_PUBLIC(nr)((void *)((nua_dialog_usage_t *)(nr) - 1)); | |||
| 1029 | pending = nr->nr_error_report_id; | |||
| 1030 | ||||
| 1031 | if (tport_release(tport, pending, NULL((void*)0), NULL((void*)0), nr, 0) < 0) | |||
| 1032 | SU_DEBUG_1(("nua_register: tport_release() 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_register.c" , (const char *)__func__, 1032, "nua_register: tport_release() failed\n" "%s", "")) : (void)0); | |||
| 1033 | nr->nr_error_report_id = 0; | |||
| 1034 | ||||
| 1035 | tpn = tport_name(nr->nr_tport); | |||
| 1036 | ||||
| 1037 | SU_DEBUG_5(("nua_register(%p): tport to %s/%s:%s%s%s closed %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_register.c" , (const char *)__func__, 1042, "nua_register(%p): tport to %s/%s:%s%s%s closed %s\n" , (void *)du->du_dialog->ds_owner, tpn->tpn_proto, tpn ->tpn_host, tpn->tpn_port, tpn->tpn_comp ? ";comp=" : "", tpn->tpn_comp ? tpn->tpn_comp : "", error != 0 ? su_strerror (error) : "")) : (void)0) | |||
| 1038 | (void *)du->du_dialog->ds_owner,((((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_register.c" , (const char *)__func__, 1042, "nua_register(%p): tport to %s/%s:%s%s%s closed %s\n" , (void *)du->du_dialog->ds_owner, tpn->tpn_proto, tpn ->tpn_host, tpn->tpn_port, tpn->tpn_comp ? ";comp=" : "", tpn->tpn_comp ? tpn->tpn_comp : "", error != 0 ? su_strerror (error) : "")) : (void)0) | |||
| 1039 | tpn->tpn_proto, tpn->tpn_host, tpn->tpn_port,((((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_register.c" , (const char *)__func__, 1042, "nua_register(%p): tport to %s/%s:%s%s%s closed %s\n" , (void *)du->du_dialog->ds_owner, tpn->tpn_proto, tpn ->tpn_host, tpn->tpn_port, tpn->tpn_comp ? ";comp=" : "", tpn->tpn_comp ? tpn->tpn_comp : "", error != 0 ? su_strerror (error) : "")) : (void)0) | |||
| 1040 | tpn->tpn_comp ? ";comp=" : "",((((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_register.c" , (const char *)__func__, 1042, "nua_register(%p): tport to %s/%s:%s%s%s closed %s\n" , (void *)du->du_dialog->ds_owner, tpn->tpn_proto, tpn ->tpn_host, tpn->tpn_port, tpn->tpn_comp ? ";comp=" : "", tpn->tpn_comp ? tpn->tpn_comp : "", error != 0 ? su_strerror (error) : "")) : (void)0) | |||
| 1041 | tpn->tpn_comp ? tpn->tpn_comp : "",((((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_register.c" , (const char *)__func__, 1042, "nua_register(%p): tport to %s/%s:%s%s%s closed %s\n" , (void *)du->du_dialog->ds_owner, tpn->tpn_proto, tpn ->tpn_host, tpn->tpn_port, tpn->tpn_comp ? ";comp=" : "", tpn->tpn_comp ? tpn->tpn_comp : "", error != 0 ? su_strerror (error) : "")) : (void)0) | |||
| 1042 | error != 0 ? su_strerror(error) : ""))((((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_register.c" , (const char *)__func__, 1042, "nua_register(%p): tport to %s/%s:%s%s%s closed %s\n" , (void *)du->du_dialog->ds_owner, tpn->tpn_proto, tpn ->tpn_host, tpn->tpn_port, tpn->tpn_comp ? ";comp=" : "", tpn->tpn_comp ? tpn->tpn_comp : "", error != 0 ? su_strerror (error) : "")) : (void)0); | |||
| 1043 | ||||
| 1044 | tport_unref(nr->nr_tport), nr->nr_tport = NULL((void*)0); | |||
| 1045 | ||||
| 1046 | /* Schedule re-REGISTER immediately */ | |||
| 1047 | nua_dialog_usage_set_refresh_range(du, 0, 0); | |||
| 1048 | } | |||
| 1049 | ||||
| 1050 | static void | |||
| 1051 | nua_register_usage_update_params(nua_dialog_usage_t const *du, | |||
| 1052 | nua_handle_preferences_t const *changed, | |||
| 1053 | nua_handle_preferences_t const *nhp, | |||
| 1054 | nua_handle_preferences_t const *dnhp) | |||
| 1055 | { | |||
| 1056 | nua_registration_t *nr = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0)); | |||
| ||||
| 1057 | outbound_t *ob = nr->nr_ob; | |||
| ||||
| 1058 | ||||
| 1059 | if (!ob) | |||
| 1060 | return; | |||
| 1061 | ||||
| 1062 | if (!changed || | |||
| 1063 | NHP_ISSET(changed, outbound)((changed)->nhp_set_.set_bits.nhb_outbound) || | |||
| 1064 | NHP_ISSET(changed, keepalive)((changed)->nhp_set_.set_bits.nhb_keepalive) || | |||
| 1065 | NHP_ISSET(changed, keepalive_stream)((changed)->nhp_set_.set_bits.nhb_keepalive_stream)) { | |||
| 1066 | char const *outbound = | |||
| 1067 | NHP_ISSET(nhp, outbound)((nhp)->nhp_set_.set_bits.nhb_outbound) ? nhp->nhp_outbound | |||
| 1068 | : dnhp->nhp_outbound; | |||
| 1069 | unsigned keepalive = | |||
| 1070 | NHP_ISSET(nhp, keepalive)((nhp)->nhp_set_.set_bits.nhb_keepalive) ? nhp->nhp_keepalive | |||
| 1071 | : dnhp->nhp_keepalive; | |||
| 1072 | unsigned keepalive_stream = | |||
| 1073 | NHP_ISSET(nhp, keepalive_stream)((nhp)->nhp_set_.set_bits.nhb_keepalive_stream) ? nhp->nhp_keepalive_stream | |||
| 1074 | : NHP_ISSET(dnhp, keepalive_stream)((dnhp)->nhp_set_.set_bits.nhb_keepalive_stream) ? nhp->nhp_keepalive_stream | |||
| 1075 | : keepalive; | |||
| 1076 | ||||
| 1077 | outbound_set_options(ob, outbound, keepalive, keepalive_stream); | |||
| 1078 | } | |||
| 1079 | ||||
| 1080 | if (!changed || NHP_ISSET(changed, proxy)((changed)->nhp_set_.set_bits.nhb_proxy)) { | |||
| 1081 | if (NHP_ISSET(nhp, proxy)((nhp)->nhp_set_.set_bits.nhb_proxy)) | |||
| 1082 | outbound_set_proxy(ob, nhp->nhp_proxy); | |||
| 1083 | } | |||
| 1084 | } | |||
| 1085 | ||||
| 1086 | ||||
| 1087 | static void nua_register_usage_refresh(nua_handle_t *nh, | |||
| 1088 | nua_dialog_state_t *ds, | |||
| 1089 | nua_dialog_usage_t *du, | |||
| 1090 | sip_time_t now) | |||
| 1091 | { | |||
| 1092 | nua_t *nua = nh->nh_nua; | |||
| 1093 | nua_client_request_t *cr = du->du_cr; | |||
| 1094 | ||||
| 1095 | if (cr) { | |||
| 1096 | if (nua_client_resend_request(cr, 0) >= 0) | |||
| 1097 | return; | |||
| 1098 | } | |||
| 1099 | ||||
| 1100 | /* Report that we have de-registered */ | |||
| 1101 | nua_stack_event(nua, nh, NULL((void*)0), nua_r_register, NUA_ERROR_AT(__FILE__, __LINE__)900, "Internal error at " "nua_register.c" ":" "1101", NULL((void*)0)); | |||
| 1102 | nua_dialog_usage_remove(nh, ds, du, NULL((void*)0), NULL((void*)0)); | |||
| 1103 | } | |||
| 1104 | ||||
| 1105 | /** @interal Shut down REGISTER usage. | |||
| 1106 | * | |||
| 1107 | * @retval >0 shutdown done | |||
| 1108 | * @retval 0 shutdown in progress | |||
| 1109 | * @retval <0 try again later | |||
| 1110 | */ | |||
| 1111 | static int nua_register_usage_shutdown(nua_handle_t *nh, | |||
| 1112 | nua_dialog_state_t *ds, | |||
| 1113 | nua_dialog_usage_t *du) | |||
| 1114 | { | |||
| 1115 | nua_client_request_t *cr = du->du_cr; | |||
| 1116 | nua_registration_t *nr = NUA_DIALOG_USAGE_PRIVATE(du)((void *)((du) + 1)); | |||
| 1117 | ||||
| 1118 | if (cr) { | |||
| 1119 | if (nua_client_is_queued(cr)) /* Already registering. */ | |||
| 1120 | return -1; | |||
| 1121 | cr->cr_event = nua_r_unregister; | |||
| 1122 | if (nua_client_resend_request(cr, 1) >= 0) | |||
| 1123 | return 0; | |||
| 1124 | } | |||
| 1125 | ||||
| 1126 | /* release the persistant transport for registration */ | |||
| 1127 | if (nr->nr_tport) | |||
| 1128 | tport_decref(&nr->nr_tport), nr->nr_tport = NULL((void*)0); | |||
| 1129 | ||||
| 1130 | nua_dialog_usage_remove(nh, ds, du, NULL((void*)0), NULL((void*)0)); | |||
| 1131 | return 200; | |||
| 1132 | } | |||
| 1133 | ||||
| 1134 | /* ---------------------------------------------------------------------- */ | |||
| 1135 | /* nua_registration_t interface */ | |||
| 1136 | ||||
| 1137 | #if HAVE_SOFIA_STUN | |||
| 1138 | #include <sofia-sip/stun.h> | |||
| 1139 | #endif | |||
| 1140 | ||||
| 1141 | static void nua_stack_tport_update(nua_t *nua, nta_agent_t *nta); | |||
| 1142 | static void nua_stack_tport_error(nua_t *nua, nta_agent_t *nta, tport_t *tport); | |||
| 1143 | static int nua_registration_add_contact_and_route(nua_handle_t *nh, | |||
| 1144 | nua_registration_t *nr, | |||
| 1145 | msg_t *msg, | |||
| 1146 | sip_t *sip, | |||
| 1147 | int add_contact, | |||
| 1148 | int add_service_route); | |||
| 1149 | ||||
| 1150 | int | |||
| 1151 | nua_stack_init_transport(nua_t *nua, tagi_t const *tags) | |||
| 1152 | { | |||
| 1153 | url_string_t const *contact1 = NULL((void*)0), *contact2 = NULL((void*)0); | |||
| 1154 | url_string_t const *contact3 = NULL((void*)0), *contact4 = NULL((void*)0); | |||
| 1155 | char const *name1 = "sip", *name2 = "sip"; | |||
| 1156 | char const *name3 = "sip", *name4 = "sip"; | |||
| 1157 | char const *certificate_dir = NULL((void*)0); | |||
| 1158 | ||||
| 1159 | tl_gets(tags, | |||
| 1160 | NUTAG_URL_REF(contact1)nutag_url_ref, urltag_url_vr(&(contact1)), | |||
| 1161 | NUTAG_SIPS_URL_REF(contact2)nutag_sips_url_ref, urltag_url_vr(&(contact2)), | |||
| 1162 | NUTAG_WS_URL_REF(contact3)nutag_ws_url_ref, urltag_url_vr(&(contact3)), | |||
| 1163 | NUTAG_WSS_URL_REF(contact4)nutag_wss_url_ref, urltag_url_vr(&(contact4)), | |||
| 1164 | NUTAG_CERTIFICATE_DIR_REF(certificate_dir)nutag_certificate_dir_ref, tag_str_vr((&certificate_dir)), | |||
| 1165 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||
| 1166 | ||||
| 1167 | if (!contact1 && contact2) | |||
| 1168 | contact1 = contact2, contact2 = NULL((void*)0); | |||
| 1169 | ||||
| 1170 | if (contact1 && | |||
| 1171 | (url_is_string(contact1) | |||
| 1172 | ? su_casenmatch(contact1->us_str, "sips:", 5) | |||
| 1173 | : contact1->us_url->url_type == url_sips)) | |||
| 1174 | name1 = "sips"; | |||
| 1175 | ||||
| 1176 | if (contact2 && | |||
| 1177 | (url_is_string(contact2) | |||
| 1178 | ? su_casenmatch(contact2->us_str, "sips:", 5) | |||
| 1179 | : contact2->us_url->url_type == url_sips)) | |||
| 1180 | name2 = "sips"; | |||
| 1181 | ||||
| 1182 | if (contact3 && | |||
| 1183 | (url_is_string(contact3) | |||
| 1184 | ? su_casenmatch(contact3->us_str, "sips:", 5) | |||
| 1185 | : contact3->us_url->url_type == url_sips)) | |||
| 1186 | name3 = "sips"; | |||
| 1187 | ||||
| 1188 | if (contact4 && | |||
| 1189 | (url_is_string(contact4) | |||
| 1190 | ? su_casenmatch(contact4->us_str, "sips:", 5) | |||
| 1191 | : contact4->us_url->url_type == url_sips)) | |||
| 1192 | name4 = "sips"; | |||
| 1193 | ||||
| 1194 | if (!contact1 /* && !contact2 */) { | |||
| 1195 | if (nta_agent_add_tport(nua->nua_nta, NULL((void*)0), | |||
| 1196 | TPTAG_IDENT("sip")tptag_ident, tag_str_v(("sip")), | |||
| 1197 | TPTAG_CERTIFICATE(certificate_dir)tptag_certificate, tag_str_v((certificate_dir)), | |||
| 1198 | TAG_NEXT(nua->nua_args)tag_next, (tag_value_t)(nua->nua_args)) < 0 && | |||
| 1199 | nta_agent_add_tport(nua->nua_nta, URL_STRING_MAKE("sip:*:*")((url_string_t *)(("sip:*:*") && *((char *)("sip:*:*" )) ? ("sip:*:*") : ((void*)0))), | |||
| 1200 | TPTAG_IDENT("sip")tptag_ident, tag_str_v(("sip")), | |||
| 1201 | TPTAG_CERTIFICATE(certificate_dir)tptag_certificate, tag_str_v((certificate_dir)), | |||
| 1202 | TAG_NEXT(nua->nua_args)tag_next, (tag_value_t)(nua->nua_args)) < 0) | |||
| 1203 | return -1; | |||
| 1204 | #if HAVE_SOFIA_STUN | |||
| 1205 | if (stun_is_requested(TAG_NEXT(nua->nua_args)tag_next, (tag_value_t)(nua->nua_args)) && | |||
| 1206 | nta_agent_add_tport(nua->nua_nta, URL_STRING_MAKE("sip:0.0.0.0:*")((url_string_t *)(("sip:0.0.0.0:*") && *((char *)("sip:0.0.0.0:*" )) ? ("sip:0.0.0.0:*") : ((void*)0))), | |||
| 1207 | TPTAG_IDENT("stun")tptag_ident, tag_str_v(("stun")), | |||
| 1208 | TPTAG_PUBLIC(tport_type_stun)tptag_public, tag_int_v((tport_type_stun)), /* use stun */ | |||
| 1209 | TPTAG_CERTIFICATE(certificate_dir)tptag_certificate, tag_str_v((certificate_dir)), | |||
| 1210 | TAG_NEXT(nua->nua_args)tag_next, (tag_value_t)(nua->nua_args)) < 0) { | |||
| 1211 | SU_DEBUG_0(("nua: error initializing STUN transport\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)) >= 0 ? (_su_llog((nua_log), 0, "nua_register.c" , (const char *)__func__, 1211, "nua: error initializing STUN transport\n" "%s", "")) : (void)0); | |||
| 1212 | } | |||
| 1213 | #endif | |||
| 1214 | } | |||
| 1215 | else { | |||
| 1216 | if (nta_agent_add_tport(nua->nua_nta, contact1, | |||
| 1217 | TPTAG_IDENT(name1)tptag_ident, tag_str_v((name1)), | |||
| 1218 | TPTAG_CERTIFICATE(certificate_dir)tptag_certificate, tag_str_v((certificate_dir)), | |||
| 1219 | TAG_NEXT(nua->nua_args)tag_next, (tag_value_t)(nua->nua_args)) < 0) | |||
| 1220 | return -1; | |||
| 1221 | ||||
| 1222 | if (contact2 && | |||
| 1223 | nta_agent_add_tport(nua->nua_nta, contact2, | |||
| 1224 | TPTAG_IDENT(name2)tptag_ident, tag_str_v((name2)), | |||
| 1225 | TPTAG_CERTIFICATE(certificate_dir)tptag_certificate, tag_str_v((certificate_dir)), | |||
| 1226 | TAG_NEXT(nua->nua_args)tag_next, (tag_value_t)(nua->nua_args)) < 0) | |||
| 1227 | return -1; | |||
| 1228 | ||||
| 1229 | if (contact3 && | |||
| 1230 | nta_agent_add_tport(nua->nua_nta, contact3, | |||
| 1231 | TPTAG_IDENT(name3)tptag_ident, tag_str_v((name3)), | |||
| 1232 | TPTAG_CERTIFICATE(certificate_dir)tptag_certificate, tag_str_v((certificate_dir)), | |||
| 1233 | TAG_NEXT(nua->nua_args)tag_next, (tag_value_t)(nua->nua_args)) < 0) | |||
| 1234 | return -1; | |||
| 1235 | ||||
| 1236 | if (contact4 && | |||
| 1237 | nta_agent_add_tport(nua->nua_nta, contact4, | |||
| 1238 | TPTAG_IDENT(name4)tptag_ident, tag_str_v((name4)), | |||
| 1239 | TPTAG_CERTIFICATE(certificate_dir)tptag_certificate, tag_str_v((certificate_dir)), | |||
| 1240 | TAG_NEXT(nua->nua_args)tag_next, (tag_value_t)(nua->nua_args)) < 0) | |||
| 1241 | return -1; | |||
| 1242 | } | |||
| 1243 | ||||
| 1244 | ||||
| 1245 | if (nua_stack_init_registrations(nua) < 0) | |||
| 1246 | return -1; | |||
| 1247 | ||||
| 1248 | return 0; | |||
| 1249 | } | |||
| 1250 | ||||
| 1251 | #if 0 | |||
| 1252 | /* Store network detector param value */ | |||
| 1253 | if (agent->sa_nw_updates == 0) | |||
| 1254 | agent->sa_nw_updates = nw_updates; | |||
| 1255 | NTATAG_DETECT_NETWORK_UPDATES_REF(nw_updates), | |||
| 1256 | unsigned nw_updates = 0; | |||
| 1257 | unsigned nw_updates = 0; | |||
| 1258 | ||||
| 1259 | su_network_changed_t *sa_nw_changed; | |||
| 1260 | ||||
| 1261 | #endif | |||
| 1262 | ||||
| 1263 | static | |||
| 1264 | void nua_network_changed_cb(nua_t *nua, su_root_t *root) | |||
| 1265 | { | |||
| 1266 | ||||
| 1267 | uint32_t nw_updates; | |||
| 1268 | ||||
| 1269 | nw_updates = nua->nua_prefs->ngp_detect_network_updates; | |||
| 1270 | ||||
| 1271 | switch (nw_updates) { | |||
| 1272 | case NUA_NW_DETECT_ONLY_INFO: | |||
| 1273 | nua_stack_event(nua, NULL((void*)0), NULL((void*)0), nua_i_network_changed, SIP_200_OK200, sip_200_OK, NULL((void*)0)); | |||
| 1274 | break; | |||
| 1275 | ||||
| 1276 | case NUA_NW_DETECT_TRY_FULL: | |||
| 1277 | ||||
| 1278 | /* 1) Shutdown all tports */ | |||
| 1279 | nta_agent_close_tports(nua->nua_nta); | |||
| 1280 | ||||
| 1281 | /* 2) Create new tports */ | |||
| 1282 | if (nua_stack_init_transport(nua, nua->nua_args) < 0) | |||
| 1283 | /* We are hosed */ | |||
| 1284 | nua_stack_event(nua, NULL((void*)0), NULL((void*)0), nua_i_network_changed, | |||
| 1285 | 900, "Internal Error", NULL((void*)0)); | |||
| 1286 | else | |||
| 1287 | nua_stack_event(nua, NULL((void*)0), NULL((void*)0), nua_i_network_changed, | |||
| 1288 | SIP_200_OK200, sip_200_OK, NULL((void*)0)); | |||
| 1289 | ||||
| 1290 | break; | |||
| 1291 | ||||
| 1292 | default: | |||
| 1293 | break; | |||
| 1294 | } | |||
| 1295 | ||||
| 1296 | return; | |||
| 1297 | } | |||
| 1298 | ||||
| 1299 | int nua_stack_launch_network_change_detector(nua_t *nua) | |||
| 1300 | { | |||
| 1301 | su_network_changed_t *snc = NULL((void*)0); | |||
| 1302 | ||||
| 1303 | snc = su_root_add_network_changed(nua->nua_home, | |||
| 1304 | nua->nua_root, | |||
| 1305 | nua_network_changed_cb, | |||
| 1306 | nua); | |||
| 1307 | ||||
| 1308 | if (!snc) | |||
| 1309 | return -1; | |||
| 1310 | ||||
| 1311 | nua->nua_nw_changed = snc; | |||
| 1312 | ||||
| 1313 | return 0; | |||
| 1314 | } | |||
| 1315 | ||||
| 1316 | ||||
| 1317 | int | |||
| 1318 | nua_stack_init_registrations(nua_t *nua) | |||
| 1319 | { | |||
| 1320 | /* Create initial identities: peer-to-peer, public, sips */ | |||
| 1321 | nua_registration_t **nr_list = &nua->nua_registrations, **nr_next; | |||
| 1322 | nua_handle_t **nh_list; | |||
| 1323 | nua_handle_t *dnh = nua->nua_dhandlenua_handles; | |||
| 1324 | sip_via_t const *v; | |||
| 1325 | ||||
| 1326 | /* Remove existing, local address based registrations and count the | |||
| 1327 | rest */ | |||
| 1328 | while (nr_list && *nr_list) { | |||
| 1329 | nr_next = &(*nr_list)->nr_next; | |||
| 1330 | if ((*nr_list)->nr_default == 1) { | |||
| 1331 | nua_registration_remove(*nr_list); | |||
| 1332 | /* memset(*nr_list, 170, sizeof(**nr_list)); */ | |||
| 1333 | /* XXX - free, too */ | |||
| 1334 | } | |||
| 1335 | nr_list = nr_next; | |||
| 1336 | } | |||
| 1337 | nr_list = &nua->nua_registrations; | |||
| 1338 | ||||
| 1339 | v = nta_agent_public_via(nua->nua_nta); | |||
| 1340 | if (v) { | |||
| 1341 | nua_registration_from_via(nr_list, dnh, v, 1); | |||
| 1342 | } | |||
| 1343 | ||||
| 1344 | v = nta_agent_via(nua->nua_nta); | |||
| 1345 | if (v) { | |||
| 1346 | nua_registration_from_via(nr_list, dnh, v, 0); | |||
| 1347 | } | |||
| 1348 | else { | |||
| 1349 | sip_via_t v[2]; | |||
| 1350 | ||||
| 1351 | sip_via_init(v)->v_next = v + 1; | |||
| 1352 | v[0].v_protocol = sip_transport_udp; | |||
| 1353 | v[0].v_host = "addr.is.invalid."; | |||
| 1354 | sip_via_init(v + 1); | |||
| 1355 | v[1].v_protocol = sip_transport_tcp; | |||
| 1356 | v[1].v_host = "addr.is.invalid."; | |||
| 1357 | ||||
| 1358 | nua_registration_from_via(nr_list, dnh, v, 0); | |||
| 1359 | } | |||
| 1360 | ||||
| 1361 | /* Go through all the registrations and set to refresh almost | |||
| 1362 | immediately */ | |||
| 1363 | nh_list = &nua->nua_handles; | |||
| 1364 | for (; *nh_list; nh_list = &(*nh_list)->nh_next) { | |||
| 1365 | nua_dialog_state_t *ds; | |||
| 1366 | nua_dialog_usage_t *du; | |||
| 1367 | ||||
| 1368 | ds = (*nh_list)->nh_ds; | |||
| 1369 | du = ds->ds_usage; | |||
| 1370 | ||||
| 1371 | if (ds->ds_has_register == 1 && du->du_class->usage_refresh) { | |||
| 1372 | nua_dialog_usage_refresh(*nh_list, ds, du, 1); | |||
| 1373 | } | |||
| 1374 | } | |||
| 1375 | ||||
| 1376 | nta_agent_bind_tport_update(nua->nua_nta, (nta_update_magic_t *)nua, nua_stack_tport_update); | |||
| 1377 | nta_agent_bind_tport_error(nua->nua_nta, (nta_error_magic_t *)nua, nua_stack_tport_error); | |||
| 1378 | ||||
| 1379 | return 0; | |||
| 1380 | } | |||
| 1381 | ||||
| 1382 | int nua_registration_from_via(nua_registration_t **list, | |||
| 1383 | nua_handle_t *nh, | |||
| 1384 | sip_via_t const *via, | |||
| 1385 | int public) | |||
| 1386 | { | |||
| 1387 | su_home_t *home = nh->nh_home; | |||
| 1388 | sip_via_t *v, *pair, /* v2[2], */ *vias, **vv, **prev; | |||
| 1389 | nua_registration_t *nr = NULL((void*)0), **next; | |||
| 1390 | su_home_t autohome[SU_HOME_AUTO_SIZE(1024)(((1024) + ((sizeof(su_home_t) + 7) & (size_t)~8) + ((3 * sizeof (void *) + 4 * sizeof(unsigned) + 7 * (sizeof (long) + sizeof(void *)) + 7) & (size_t)~8)) / sizeof(su_home_t))]; | |||
| 1391 | int nr_items = 0; | |||
| 1392 | ||||
| 1393 | vias = sip_via_copy(su_home_auto(autohome, sizeof autohome), via); | |||
| 1394 | ||||
| 1395 | for (; *list; list = &(*list)->nr_next) | |||
| 1396 | ++nr_items; | |||
| 1397 | ||||
| 1398 | next = list; | |||
| 1399 | ||||
| 1400 | for (vv = &vias; (v = *vv);) { | |||
| 1401 | char const *protocol; | |||
| 1402 | sip_contact_t *contact; | |||
| 1403 | sip_via_t v2[2]; | |||
| 1404 | ||||
| 1405 | *vv = v->v_next, v->v_next = NULL((void*)0), pair = NULL((void*)0); | |||
| 1406 | ||||
| 1407 | if (v->v_protocol == sip_transport_tcp) | |||
| 1408 | protocol = sip_transport_udp; | |||
| 1409 | else if (v->v_protocol == sip_transport_udp) | |||
| 1410 | protocol = sip_transport_tcp; | |||
| 1411 | else | |||
| 1412 | protocol = NULL((void*)0); | |||
| 1413 | ||||
| 1414 | if (protocol) { | |||
| 1415 | /* Try to pair vias if we have both udp and tcp */ | |||
| 1416 | for (prev = vv; *prev; prev = &(*prev)->v_next) { | |||
| 1417 | if (!su_casematch(protocol, (*prev)->v_protocol)) | |||
| 1418 | continue; | |||
| 1419 | if (!su_casematch(v->v_host, (*prev)->v_host)) | |||
| 1420 | continue; | |||
| 1421 | if (!su_strmatch(v->v_port, (*prev)->v_port)) | |||
| 1422 | continue; | |||
| 1423 | break; | |||
| 1424 | } | |||
| 1425 | ||||
| 1426 | if (*prev) { | |||
| 1427 | pair = *prev; *prev = pair->v_next; pair->v_next = NULL((void*)0); | |||
| 1428 | } | |||
| 1429 | } | |||
| 1430 | ||||
| 1431 | /* if more than one candidate, ignore local entries */ | |||
| 1432 | if (v && (*vv || nr_items > 0) && | |||
| 1433 | host_is_local(v->v_host)) { | |||
| 1434 | SU_DEBUG_9(("nua_register: ignoring contact candidate %s:%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)) >= 9 ? (_su_llog((nua_log), 9, "nua_register.c" , (const char *)__func__, 1435, "nua_register: ignoring contact candidate %s:%s.\n" , v->v_host, v->v_port ? v->v_port : "")) : (void)0) | |||
| 1435 | v->v_host, v->v_port ? v->v_port : ""))((((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_register.c" , (const char *)__func__, 1435, "nua_register: ignoring contact candidate %s:%s.\n" , v->v_host, v->v_port ? v->v_port : "")) : (void)0); | |||
| 1436 | continue; | |||
| 1437 | } | |||
| 1438 | ||||
| 1439 | nr = su_zalloc(home, sizeof *nr); | |||
| 1440 | if (!nr) | |||
| 1441 | break; | |||
| 1442 | ||||
| 1443 | v2[0] = *v; | |||
| 1444 | ||||
| 1445 | if (pair) | |||
| 1446 | /* Don't use protocol if we have both udp and tcp */ | |||
| 1447 | protocol = NULL((void*)0), v2[0].v_next = &v2[1], v2[1] = *pair; | |||
| 1448 | else | |||
| 1449 | protocol = via->v_protocol, v2[0].v_next = NULL((void*)0); | |||
| 1450 | ||||
| 1451 | v2[1].v_next = NULL((void*)0); | |||
| 1452 | ||||
| 1453 | contact = nua_handle_contact_by_via(nh, home, 0, v2, protocol, NULL((void*)0)); | |||
| 1454 | ||||
| 1455 | v = sip_via_dup(home, v2); | |||
| 1456 | ||||
| 1457 | if (!contact || !v) { | |||
| 1458 | su_free(home, nr); | |||
| 1459 | break; | |||
| 1460 | } | |||
| 1461 | ||||
| 1462 | nr->nr_ready = 1, nr->nr_default = 1, nr->nr_public = public; | |||
| 1463 | nr->nr_secure = contact->m_url->url_type == url_sips; | |||
| 1464 | nr->nr_contact = contact; | |||
| 1465 | *nr->nr_dcontact = *contact, nr->nr_dcontact->m_params = NULL((void*)0); | |||
| 1466 | nr->nr_via = v; | |||
| 1467 | nr->nr_ip4 = host_is_ip4_address(contact->m_url->url_host); | |||
| 1468 | nr->nr_ip6 = !nr->nr_ip4 && host_is_ip6_reference(contact->m_url->url_host); | |||
| 1469 | ||||
| 1470 | SU_DEBUG_9(("nua_register: Adding contact URL '%s' to list.\n", contact->m_url->url_host))((((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_register.c" , (const char *)__func__, 1470, "nua_register: Adding contact URL '%s' to list.\n" , contact->m_url->url_host)) : (void)0); | |||
| 1471 | ||||
| 1472 | ++nr_items; | |||
| 1473 | nr->nr_next = *next, nr->nr_prev = next; *next = nr, next = &nr->nr_next; | |||
| 1474 | nr->nr_list = list; | |||
| 1475 | } | |||
| 1476 | ||||
| 1477 | su_home_deinit(autohome); | |||
| 1478 | ||||
| 1479 | return 0; | |||
| 1480 | } | |||
| 1481 | ||||
| 1482 | static | |||
| 1483 | void nua_stack_tport_error(nua_t *nua, nta_agent_t *nta, tport_t *tport) | |||
| 1484 | { | |||
| 1485 | return; | |||
| 1486 | } | |||
| 1487 | ||||
| 1488 | static | |||
| 1489 | void nua_stack_tport_update(nua_t *nua, nta_agent_t *nta) | |||
| 1490 | { | |||
| 1491 | #if 0 | |||
| 1492 | nua_registration_t *default_oc; | |||
| 1493 | nua_registration_t const *defaults = nua->nua_registrations; | |||
| 1494 | sip_via_t *via = nta_agent_via(nta); | |||
| 1495 | ||||
| 1496 | default_oc = outbound_by_aor(defaults, NULL((void*)0), 1); | |||
| 1497 | ||||
| 1498 | if (default_oc) { | |||
| 1499 | assert(default_oc->nr_via)((default_oc->nr_via) ? (void) (0) : __assert_fail ("default_oc->nr_via" , "nua_register.c", 1499, __PRETTY_FUNCTION__)); | |||
| 1500 | ||||
| 1501 | outbound_contacts_from_via(default_oc, | |||
| 1502 | via, | |||
| 1503 | via->v_next); | |||
| 1504 | ||||
| 1505 | /* refresh_register(nua_handle_t *nh, nua_dialog_usage_t *du, sip_time_t now); */ | |||
| 1506 | } | |||
| 1507 | #endif | |||
| 1508 | return; | |||
| 1509 | } | |||
| 1510 | ||||
| 1511 | nua_registration_t *nua_registration_by_aor(nua_registration_t const *list, | |||
| 1512 | sip_from_t const *aor, | |||
| 1513 | url_t const *remote_uri, | |||
| 1514 | int only_default) | |||
| 1515 | { | |||
| 1516 | sip_from_t *alt_aor = NULL((void*)0), _alt_aor[1]; | |||
| 1517 | int sips_aor = aor && aor->a_url->url_type == url_sips; | |||
| 1518 | int sips_uri = remote_uri && remote_uri->url_type == url_sips; | |||
| 1519 | ||||
| 1520 | nua_registration_t const *nr, *public = NULL((void*)0), *any = NULL((void*)0); | |||
| 1521 | nua_registration_t const *registered = NULL((void*)0); | |||
| 1522 | nua_registration_t const *namewise = NULL((void*)0), *sipswise = NULL((void*)0); | |||
| 1523 | ||||
| 1524 | int ip4 = remote_uri && host_is_ip4_address(remote_uri->url_host); | |||
| 1525 | int ip6 = remote_uri && host_is_ip6_reference(remote_uri->url_host); | |||
| 1526 | ||||
| 1527 | if (only_default || aor == NULL((void*)0)) { | |||
| 1528 | /* Ignore AoR, select only by remote_uri */ | |||
| 1529 | for (nr = list; nr; nr = nr->nr_next) { | |||
| 1530 | if (!nr->nr_ready) | |||
| 1531 | continue; | |||
| 1532 | if (only_default && !nr->nr_default) | |||
| 1533 | continue; | |||
| 1534 | if (nr->nr_ip4 && ip6) | |||
| 1535 | continue; | |||
| 1536 | if (nr->nr_ip6 && ip4) | |||
| 1537 | continue; | |||
| 1538 | if (sips_uri ? nr->nr_secure : !nr->nr_secure) | |||
| 1539 | return (nua_registration_t *)nr; | |||
| 1540 | if (!registered && nr->nr_aor) | |||
| 1541 | registered = nr; | |||
| 1542 | if (!public && nr->nr_public) | |||
| 1543 | public = nr; | |||
| 1544 | if (!any) | |||
| 1545 | any = nr; | |||
| 1546 | } | |||
| 1547 | if (registered) | |||
| 1548 | return (nua_registration_t *)registered; | |||
| 1549 | if (public) | |||
| 1550 | return (nua_registration_t *)public; | |||
| 1551 | if (any) | |||
| 1552 | return (nua_registration_t *)any; | |||
| 1553 | return NULL((void*)0); | |||
| 1554 | } | |||
| 1555 | ||||
| 1556 | if (!sips_aor && aor) { | |||
| 1557 | alt_aor = memcpy(_alt_aor, aor, sizeof _alt_aor); | |||
| 1558 | alt_aor->a_url->url_type = url_sips; | |||
| 1559 | alt_aor->a_url->url_scheme = "sips"; | |||
| 1560 | } | |||
| 1561 | ||||
| 1562 | for (nr = list; nr; nr = nr->nr_next) { | |||
| 1563 | if (!nr->nr_ready || !nr->nr_contact) | |||
| 1564 | continue; | |||
| 1565 | if (nr->nr_aor) { | |||
| 1566 | if (aor && url_cmp(nr->nr_aor->a_url, aor->a_url) == 0) | |||
| 1567 | return (nua_registration_t *)nr; | |||
| 1568 | if (!namewise && alt_aor && url_cmp(nr->nr_aor->a_url, aor->a_url) == 0) | |||
| 1569 | namewise = nr; | |||
| 1570 | } | |||
| 1571 | ||||
| 1572 | if (!sipswise && ((sips_aor || sips_uri) ? | |||
| 1573 | nr->nr_secure : !nr->nr_secure)) | |||
| 1574 | sipswise = nr; | |||
| 1575 | if (!registered) | |||
| 1576 | registered = nr; | |||
| 1577 | if (!public && nr->nr_public) | |||
| 1578 | public = nr; | |||
| 1579 | if (!any) | |||
| 1580 | any = nr; | |||
| 1581 | } | |||
| 1582 | ||||
| 1583 | if (namewise) | |||
| 1584 | return (nua_registration_t *)namewise; | |||
| 1585 | if (sipswise) | |||
| 1586 | return (nua_registration_t *)sipswise; | |||
| 1587 | if (registered) | |||
| 1588 | return (nua_registration_t *)registered; | |||
| 1589 | ||||
| 1590 | /* XXX - | |||
| 1591 | should we do some policing whether sips_aor or sips_uri can be used | |||
| 1592 | with sip contact? | |||
| 1593 | */ | |||
| 1594 | if (public) | |||
| 1595 | return (nua_registration_t *)public; | |||
| 1596 | if (any) | |||
| 1597 | return (nua_registration_t *)any; | |||
| 1598 | ||||
| 1599 | return NULL((void*)0); | |||
| 1600 | } | |||
| 1601 | ||||
| 1602 | ||||
| 1603 | nua_registration_t * | |||
| 1604 | nua_registration_for_request(nua_registration_t const *list, sip_t const *sip) | |||
| 1605 | { | |||
| 1606 | sip_from_t const *aor; | |||
| 1607 | url_t *uri; | |||
| 1608 | ||||
| 1609 | aor = sip->sip_from; | |||
| 1610 | uri = sip->sip_request->rq_url; | |||
| 1611 | ||||
| 1612 | return nua_registration_by_aor(list, aor, uri, 0); | |||
| 1613 | } | |||
| 1614 | ||||
| 1615 | nua_registration_t * | |||
| 1616 | nua_registration_for_response(nua_registration_t const *list, | |||
| 1617 | sip_t const *sip, | |||
| 1618 | sip_record_route_t const *record_route, | |||
| 1619 | sip_contact_t const *remote_contact) | |||
| 1620 | { | |||
| 1621 | nua_registration_t *nr; | |||
| 1622 | sip_to_t const *aor = NULL((void*)0); | |||
| 1623 | url_t const *uri = NULL((void*)0); | |||
| 1624 | ||||
| 1625 | if (sip) | |||
| 1626 | aor = sip->sip_to; | |||
| 1627 | ||||
| 1628 | if (record_route) | |||
| 1629 | uri = record_route->r_url; | |||
| 1630 | else if (sip && sip->sip_record_route) | |||
| 1631 | uri = sip->sip_record_route->r_url; | |||
| 1632 | else if (remote_contact) | |||
| 1633 | uri = remote_contact->m_url; | |||
| 1634 | else if (sip && sip->sip_from) | |||
| 1635 | uri = sip->sip_from->a_url; | |||
| 1636 | ||||
| 1637 | nr = nua_registration_by_aor(list, aor, uri, 0); | |||
| 1638 | ||||
| 1639 | return nr; | |||
| 1640 | } | |||
| 1641 | ||||
| 1642 | ||||
| 1643 | /** Return Contact usable in dialogs */ | |||
| 1644 | sip_contact_t const *nua_registration_contact(nua_registration_t const *nr) | |||
| 1645 | { | |||
| 1646 | if (nr->nr_by_stack && nr->nr_ob) { | |||
| 1647 | sip_contact_t const *m = outbound_dialog_contact(nr->nr_ob); | |||
| 1648 | if (m) | |||
| 1649 | return m; | |||
| 1650 | } | |||
| 1651 | ||||
| 1652 | if (nr->nr_contact) | |||
| 1653 | return nr->nr_dcontact; | |||
| 1654 | else | |||
| 1655 | return NULL((void*)0); | |||
| 1656 | } | |||
| 1657 | ||||
| 1658 | /** Return initial route. */ | |||
| 1659 | sip_route_t const *nua_registration_route(nua_registration_t const *nr) | |||
| 1660 | { | |||
| 1661 | return nr ? nr->nr_route : NULL((void*)0); | |||
| 1662 | } | |||
| 1663 | ||||
| 1664 | sip_contact_t const *nua_stack_get_contact(nua_registration_t const *nr) | |||
| 1665 | { | |||
| 1666 | nr = nua_registration_by_aor(nr, NULL((void*)0), NULL((void*)0), 1); | |||
| 1667 | return nr && nr->nr_contact ? nr->nr_dcontact : NULL((void*)0); | |||
| 1668 | } | |||
| 1669 | ||||
| 1670 | /** Add a Contact (and Route) header to request */ | |||
| 1671 | int nua_registration_add_contact_to_request(nua_handle_t *nh, | |||
| 1672 | msg_t *msg, | |||
| 1673 | sip_t *sip, | |||
| 1674 | int add_contact, | |||
| 1675 | int add_service_route) | |||
| 1676 | { | |||
| 1677 | nua_registration_t *nr = NULL((void*)0); | |||
| 1678 | ||||
| 1679 | if (!add_contact && !add_service_route) | |||
| 1680 | return 0; | |||
| 1681 | ||||
| 1682 | if (nh == NULL((void*)0) || msg == NULL((void*)0)) | |||
| 1683 | return -1; | |||
| 1684 | ||||
| 1685 | if (sip == NULL((void*)0)) | |||
| 1686 | sip = sip_object(msg); | |||
| 1687 | ||||
| 1688 | if (nr == NULL((void*)0)) | |||
| 1689 | nr = nua_registration_for_request(nh->nh_nua->nua_registrations, sip); | |||
| 1690 | ||||
| 1691 | return nua_registration_add_contact_and_route(nh, nr, msg, sip, | |||
| 1692 | add_contact, | |||
| 1693 | add_service_route); | |||
| 1694 | } | |||
| 1695 | ||||
| 1696 | /** Add a Contact header to response. | |||
| 1697 | * | |||
| 1698 | * @param nh | |||
| 1699 | * @param msg response message | |||
| 1700 | * @param sip headers in response message | |||
| 1701 | * @param record_route record-route from request | |||
| 1702 | * @param remote_contact Contact from request | |||
| 1703 | */ | |||
| 1704 | int nua_registration_add_contact_to_response(nua_handle_t *nh, | |||
| 1705 | msg_t *msg, | |||
| 1706 | sip_t *sip, | |||
| 1707 | sip_record_route_t const *record_route, | |||
| 1708 | sip_contact_t const *remote_contact) | |||
| 1709 | { | |||
| 1710 | nua_registration_t *nr = NULL((void*)0); | |||
| 1711 | ||||
| 1712 | if (sip == NULL((void*)0)) | |||
| 1713 | sip = sip_object(msg); | |||
| 1714 | ||||
| 1715 | if (nh == NULL((void*)0) || msg == NULL((void*)0) || sip == NULL((void*)0)) | |||
| 1716 | return -1; | |||
| 1717 | ||||
| 1718 | if (nr == NULL((void*)0)) | |||
| 1719 | nr = nua_registration_for_response(nh->nh_nua->nua_registrations, sip, | |||
| 1720 | record_route, remote_contact); | |||
| 1721 | ||||
| 1722 | return nua_registration_add_contact_and_route(nh, nr, msg, sip, | |||
| 1723 | 1, | |||
| 1724 | 0); | |||
| 1725 | } | |||
| 1726 | ||||
| 1727 | /** Add a Contact (and Route) header to request */ | |||
| 1728 | static | |||
| 1729 | int nua_registration_add_contact_and_route(nua_handle_t *nh, | |||
| 1730 | nua_registration_t *nr, | |||
| 1731 | msg_t *msg, | |||
| 1732 | sip_t *sip, | |||
| 1733 | int add_contact, | |||
| 1734 | int add_service_route) | |||
| 1735 | { | |||
| 1736 | if (nr == NULL((void*)0)) | |||
| 1737 | return -1; | |||
| 1738 | ||||
| 1739 | if (add_contact) { | |||
| 1740 | sip_contact_t const *m = NULL((void*)0); | |||
| 1741 | char const *m_display; | |||
| 1742 | char const *m_username; | |||
| 1743 | char const *m_params; | |||
| 1744 | url_t const *u; | |||
| 1745 | ||||
| 1746 | if (nr->nr_by_stack && nr->nr_ob) { | |||
| 1747 | m = outbound_dialog_gruu(nr->nr_ob); | |||
| 1748 | ||||
| 1749 | if (m) | |||
| 1750 | return msg_header_add_dup(msg, (msg_pub_t *)sip, (void const *)m); | |||
| 1751 | ||||
| 1752 | m = outbound_dialog_contact(nr->nr_ob); | |||
| 1753 | } | |||
| 1754 | ||||
| 1755 | if (m == NULL((void*)0)) | |||
| 1756 | m = nr->nr_contact; | |||
| 1757 | ||||
| 1758 | if (!m) | |||
| 1759 | return -1; | |||
| 1760 | ||||
| 1761 | u = m->m_url; | |||
| 1762 | ||||
| 1763 | if (NH_PISSET(nh, m_display)((((nh)->nh_prefs)->nhp_set_.set_bits.nhb_m_display) && (nh)->nh_nua->nua_handles->nh_prefs != (nh)->nh_prefs )) | |||
| 1764 | m_display = NH_PGET(nh, m_display)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_m_display ? (( nh)->nh_prefs)->nhp_m_display : ((nh)->nh_nua->nua_handles ->nh_prefs)->nhp_m_display); | |||
| 1765 | else | |||
| 1766 | m_display = m->m_display; | |||
| 1767 | ||||
| 1768 | if (NH_PISSET(nh, m_username)((((nh)->nh_prefs)->nhp_set_.set_bits.nhb_m_username) && (nh)->nh_nua->nua_handles->nh_prefs != (nh)->nh_prefs )) | |||
| 1769 | m_username = NH_PGET(nh, m_username)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_m_username ? ( (nh)->nh_prefs)->nhp_m_username : ((nh)->nh_nua-> nua_handles->nh_prefs)->nhp_m_username); | |||
| 1770 | else | |||
| 1771 | m_username = m->m_url->url_user; | |||
| 1772 | ||||
| 1773 | if (NH_PISSET(nh, m_params)((((nh)->nh_prefs)->nhp_set_.set_bits.nhb_m_params) && (nh)->nh_nua->nua_handles->nh_prefs != (nh)->nh_prefs )) { | |||
| 1774 | m_params = NH_PGET(nh, m_params)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_m_params ? ((nh )->nh_prefs)->nhp_m_params : ((nh)->nh_nua->nua_handles ->nh_prefs)->nhp_m_params); | |||
| 1775 | ||||
| 1776 | if (u->url_params && m_params && strstr(u->url_params, m_params) == 0) | |||
| 1777 | m_params = NULL((void*)0); | |||
| 1778 | } | |||
| 1779 | else | |||
| 1780 | m_params = NULL((void*)0); | |||
| 1781 | ||||
| 1782 | m = sip_contact_format(msg_home(msg)((su_home_t*)(msg)), | |||
| 1783 | "%s<%s:%s%s%s%s%s%s%s%s%s>", | |||
| 1784 | m_display ? m_display : "", | |||
| 1785 | u->url_scheme, | |||
| 1786 | m_username ? m_username : "", | |||
| 1787 | m_username ? "@" : "", | |||
| 1788 | u->url_host, | |||
| 1789 | u->url_port ? ":" : "", | |||
| 1790 | u->url_port ? u->url_port : "", | |||
| 1791 | u->url_params ? ";" : "", | |||
| 1792 | u->url_params ? u->url_params : "", | |||
| 1793 | m_params ? ";" : "", | |||
| 1794 | m_params ? m_params : ""); | |||
| 1795 | ||||
| 1796 | if (msg_header_insert(msg, (msg_pub_t *)sip, (void *)m) < 0) | |||
| 1797 | return -1; | |||
| 1798 | } | |||
| 1799 | ||||
| 1800 | if (add_service_route && !sip->sip_status) { | |||
| 1801 | sip_route_t const *sr = nua_registration_route(nr); | |||
| 1802 | if (msg_header_add_dup(msg, (msg_pub_t *)sip, (void const *)sr) < 0) | |||
| 1803 | return -1; | |||
| 1804 | } | |||
| 1805 | ||||
| 1806 | return 0; | |||
| 1807 | } | |||
| 1808 | ||||
| 1809 | ||||
| 1810 | /** Add a registration to list of contacts */ | |||
| 1811 | int nua_registration_add(nua_registration_t **list, | |||
| 1812 | nua_registration_t *nr) | |||
| 1813 | { | |||
| 1814 | assert(list && nr)((list && nr) ? (void) (0) : __assert_fail ("list && nr" , "nua_register.c", 1814, __PRETTY_FUNCTION__)); | |||
| 1815 | ||||
| 1816 | if (nr->nr_list == NULL((void*)0)) { | |||
| 1817 | nua_registration_t *next = *list; | |||
| 1818 | if (next) | |||
| 1819 | next->nr_prev = &nr->nr_next; | |||
| 1820 | nr->nr_next = next, nr->nr_prev = list, nr->nr_list = list; | |||
| 1821 | *list = nr; | |||
| 1822 | } | |||
| 1823 | ||||
| 1824 | return 0; | |||
| 1825 | } | |||
| 1826 | ||||
| 1827 | /** Remove from list of registrations */ | |||
| 1828 | void nua_registration_remove(nua_registration_t *nr) | |||
| 1829 | { | |||
| 1830 | if ((*nr->nr_prev = nr->nr_next)) | |||
| 1831 | nr->nr_next->nr_prev = nr->nr_prev; | |||
| 1832 | nr->nr_next = NULL((void*)0), nr->nr_prev = NULL((void*)0), nr->nr_list = NULL((void*)0); | |||
| 1833 | } | |||
| 1834 | ||||
| 1835 | /** Set address-of-record. */ | |||
| 1836 | int nua_registration_set_aor(su_home_t *home, | |||
| 1837 | nua_registration_t *nr, | |||
| 1838 | sip_from_t const *aor) | |||
| 1839 | { | |||
| 1840 | sip_from_t *new_aor, *old_aor; | |||
| 1841 | ||||
| 1842 | if (!home || !nr || !aor) | |||
| 1843 | return -1; | |||
| 1844 | ||||
| 1845 | new_aor = sip_from_dup(home, aor); | |||
| 1846 | if (!new_aor) | |||
| 1847 | return -1; | |||
| 1848 | ||||
| 1849 | old_aor = nr->nr_aor; | |||
| 1850 | nr->nr_aor = new_aor; | |||
| 1851 | msg_header_free(home, (void *)old_aor); | |||
| 1852 | ||||
| 1853 | return 0; | |||
| 1854 | } | |||
| 1855 | ||||
| 1856 | /** Set contact. */ | |||
| 1857 | int nua_registration_set_contact(nua_handle_t *nh, | |||
| 1858 | nua_registration_t *nr, | |||
| 1859 | sip_contact_t const *application_contact, | |||
| 1860 | int terminating) | |||
| 1861 | { | |||
| 1862 | sip_contact_t *m = NULL((void*)0), *previous; | |||
| 1863 | url_t *uri; | |||
| 1864 | ||||
| 1865 | if (!nh || !nr) | |||
| 1866 | return -1; | |||
| 1867 | ||||
| 1868 | uri = nr->nr_aor ? nr->nr_aor->a_url : NULL((void*)0); | |||
| 1869 | ||||
| 1870 | previous = nr->nr_contact; | |||
| 1871 | ||||
| 1872 | if (application_contact) { | |||
| 1873 | m = sip_contact_dup(nh->nh_home, application_contact); | |||
| 1874 | } | |||
| 1875 | else if (terminating && nr->nr_contact) { | |||
| 1876 | return 0; | |||
| 1877 | } | |||
| 1878 | else { | |||
| 1879 | nua_registration_t *nr0; | |||
| 1880 | ||||
| 1881 | nr0 = nua_registration_by_aor(*nr->nr_list, NULL((void*)0), uri, 1); | |||
| 1882 | ||||
| 1883 | if (nr0 && nr0->nr_via) { | |||
| 1884 | char const *tport = nr0->nr_via->v_next ? NULL((void*)0) : nr0->nr_via->v_protocol; | |||
| 1885 | m = nua_handle_contact_by_via(nh, nh->nh_home, 0, | |||
| 1886 | nr0->nr_via, tport, NULL((void*)0)); | |||
| 1887 | } | |||
| 1888 | } | |||
| 1889 | ||||
| 1890 | if (!m) | |||
| 1891 | return -1; | |||
| 1892 | ||||
| 1893 | nr->nr_contact = m; | |||
| 1894 | *nr->nr_dcontact = *m, nr->nr_dcontact->m_params = NULL((void*)0); | |||
| 1895 | nr->nr_ip4 = host_is_ip4_address(m->m_url->url_host); | |||
| 1896 | nr->nr_ip6 = !nr->nr_ip4 && host_is_ip6_reference(m->m_url->url_host); | |||
| 1897 | nr->nr_by_stack = !application_contact; | |||
| 1898 | ||||
| 1899 | msg_header_free(nh->nh_home, (void *)previous); | |||
| 1900 | ||||
| 1901 | return 0; | |||
| 1902 | } | |||
| 1903 | ||||
| 1904 | /** Mark registration as ready */ | |||
| 1905 | void nua_registration_set_ready(nua_registration_t *nr, int ready) | |||
| 1906 | { | |||
| 1907 | if (nr) { | |||
| 1908 | assert(!ready || nr->nr_contact)((!ready || nr->nr_contact) ? (void) (0) : __assert_fail ( "!ready || nr->nr_contact", "nua_register.c", 1908, __PRETTY_FUNCTION__ )); | |||
| 1909 | nr->nr_ready = ready; | |||
| 1910 | } | |||
| 1911 | } | |||
| 1912 | ||||
| 1913 | /** @internal Hook for processing incoming request by registration. | |||
| 1914 | * | |||
| 1915 | * This is used for keepalive/validate OPTIONS. | |||
| 1916 | */ | |||
| 1917 | int nua_registration_process_request(nua_registration_t *list, | |||
| 1918 | nta_incoming_t *irq, | |||
| 1919 | sip_t const *sip) | |||
| 1920 | { | |||
| 1921 | //sip_call_id_t *i; | |||
| 1922 | nua_registration_t *nr; | |||
| 1923 | ||||
| 1924 | if (!outbound_targeted_request(sip)) | |||
| 1925 | return 0; | |||
| 1926 | ||||
| 1927 | /* Process by outbound... */ | |||
| 1928 | //i = sip->sip_call_id; | |||
| 1929 | ||||
| 1930 | for (nr = list; nr; nr = nr->nr_next) { | |||
| 1931 | outbound_t *ob = nr->nr_ob; | |||
| 1932 | if (ob) | |||
| 1933 | if (outbound_process_request(ob, irq, sip)) | |||
| 1934 | return 501; /* Just in case */ | |||
| 1935 | } | |||
| 1936 | ||||
| 1937 | return 481; /* Call/Transaction does not exist */ | |||
| 1938 | } | |||
| 1939 | ||||
| 1940 | /** Outbound requests us to refresh registration */ | |||
| 1941 | static int nua_stack_outbound_refresh(nua_handle_t *nh, | |||
| 1942 | outbound_t *ob) | |||
| 1943 | { | |||
| 1944 | nua_dialog_state_t *ds = nh->nh_ds; | |||
| 1945 | nua_dialog_usage_t *du; | |||
| 1946 | ||||
| 1947 | du = nua_dialog_usage_get(ds, nua_register_usage, NULL((void*)0)); | |||
| 1948 | ||||
| 1949 | if (du) | |||
| 1950 | nua_dialog_usage_refresh(nh, ds, du, 1); | |||
| 1951 | ||||
| 1952 | return 0; | |||
| 1953 | } | |||
| 1954 | ||||
| 1955 | /** @NUA_EVENT nua_i_outbound | |||
| 1956 | * | |||
| 1957 | * Status from outbound engine. | |||
| 1958 | * | |||
| 1959 | * @param status SIP status code or NUA status code (>= 900) | |||
| 1960 | * describing the outbound state | |||
| 1961 | * @param phrase a short textual description of @a status code | |||
| 1962 | * @param nh operation handle associated with the outbound engine | |||
| 1963 | * @param hmagic application context associated with the handle | |||
| 1964 | * @param sip NULL or response message to an keepalive message or | |||
| 1965 | * registration probe | |||
| 1966 | * (error code and message are in status an phrase parameters) | |||
| 1967 | * @param tags empty | |||
| 1968 | * | |||
| 1969 | * @sa NUTAG_OUTBOUND(), NUTAG_KEEPALIVE(), NUTAG_KEEPALIVE_STREAM(), | |||
| 1970 | * nua_register(), #nua_r_register, nua_unregister(), #nua_r_unregister | |||
| 1971 | * | |||
| 1972 | * @END_NUA_EVENT | |||
| 1973 | */ | |||
| 1974 | ||||
| 1975 | /** @internal Callback from outbound_t */ | |||
| 1976 | static int nua_stack_outbound_status(nua_handle_t *nh, outbound_t *ob, | |||
| 1977 | int status, char const *phrase, | |||
| 1978 | tag_type_t tag, tag_value_t value, ...) | |||
| 1979 | { | |||
| 1980 | ta_list ta; | |||
| 1981 | ||||
| 1982 | 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); | |||
| 1983 | ||||
| 1984 | nua_stack_event(nh->nh_nua, nh, NULL((void*)0), | |||
| 1985 | nua_i_outbound, status, phrase, | |||
| 1986 | ta_args(ta)(ta).tl); | |||
| 1987 | ||||
| 1988 | 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)); | |||
| 1989 | ||||
| 1990 | return 0; | |||
| 1991 | } | |||
| 1992 | ||||
| 1993 | /** @internal Callback from outbound_t */ | |||
| 1994 | static int nua_stack_outbound_failed(nua_handle_t *nh, outbound_t *ob, | |||
| 1995 | int status, char const *phrase, | |||
| 1996 | tag_type_t tag, tag_value_t value, ...) | |||
| 1997 | { | |||
| 1998 | ta_list ta; | |||
| 1999 | 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); | |||
| 2000 | ||||
| 2001 | nua_stack_event(nh->nh_nua, nh, NULL((void*)0), | |||
| 2002 | nua_i_outbound, status, phrase, | |||
| 2003 | ta_args(ta)(ta).tl); | |||
| 2004 | ||||
| 2005 | 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)); | |||
| 2006 | ||||
| 2007 | return 0; | |||
| 2008 | } | |||
| 2009 | ||||
| 2010 | /** @internal Callback for obtaining credentials for keepalive */ | |||
| 2011 | static int nua_stack_outbound_credentials(nua_handle_t *nh, | |||
| 2012 | auth_client_t **auc) | |||
| 2013 | { | |||
| 2014 | return auc_copy_credentials(auc, nh->nh_auth); | |||
| 2015 | } | |||
| 2016 | ||||
| 2017 | #include <ctype.h> | |||
| 2018 | #include <sofia-sip/bnf.h> | |||
| 2019 | ||||
| 2020 | /** @internal Generate a @Contact header. */ | |||
| 2021 | sip_contact_t *nua_handle_contact_by_via(nua_handle_t *nh, | |||
| 2022 | su_home_t *home, | |||
| 2023 | int in_dialog, | |||
| 2024 | sip_via_t const *v, | |||
| 2025 | char const *transport, | |||
| 2026 | char const *m_param, | |||
| 2027 | ...) | |||
| 2028 | { | |||
| 2029 | su_strlst_t *l; | |||
| 2030 | char const *s; | |||
| 2031 | char const *host, *port, *maddr, *comp; | |||
| 2032 | int one = 1; | |||
| 2033 | char _transport[16]; | |||
| 2034 | va_list va; | |||
| 2035 | sip_contact_t *m; | |||
| 2036 | url_t url; | |||
| 2037 | ||||
| 2038 | url_init(&url, url_sip); | |||
| 2039 | ||||
| 2040 | if (!v) return NULL((void*)0); | |||
| 2041 | ||||
| 2042 | host = v->v_host; | |||
| 2043 | if (v->v_received) | |||
| 2044 | host = v->v_received; | |||
| 2045 | port = sip_via_port(v, &one); | |||
| 2046 | maddr = v->v_maddr; | |||
| 2047 | comp = v->v_comp; | |||
| 2048 | ||||
| 2049 | if (host == NULL((void*)0)) | |||
| 2050 | return NULL((void*)0); | |||
| 2051 | ||||
| 2052 | if (sip_transport_has_tls(v->v_protocol) || | |||
| 2053 | sip_transport_has_tls(transport)) { | |||
| 2054 | url.url_type = url_sips; | |||
| 2055 | url.url_scheme = url_scheme(url_sips); | |||
| 2056 | if (port && strcmp(port, SIPS_DEFAULT_SERV)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p (port) && __builtin_constant_p ("5061") && ( __s1_len = __builtin_strlen (port), __s2_len = __builtin_strlen ("5061"), (!((size_t)(const void *)((port) + 1) - (size_t)(const void *)(port) == 1) || __s1_len >= 4) && (!((size_t )(const void *)(("5061") + 1) - (size_t)(const void *)("5061" ) == 1) || __s2_len >= 4)) ? __builtin_strcmp (port, "5061" ) : (__builtin_constant_p (port) && ((size_t)(const void *)((port) + 1) - (size_t)(const void *)(port) == 1) && (__s1_len = __builtin_strlen (port), __s1_len < 4) ? (__builtin_constant_p ("5061") && ((size_t)(const void *)(("5061") + 1) - ( size_t)(const void *)("5061") == 1) ? __builtin_strcmp (port, "5061") : (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) ("5061"); int __result = ((( const unsigned char *) (const char *) (port))[0] - __s2[0]); if (__s1_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) (port))[1] - __s2[1]); if (__s1_len > 1 && __result == 0) { __result = (((const unsigned char *) (const char *) (port))[2] - __s2[2]); if (__s1_len > 2 && __result == 0) __result = (((const unsigned char *) (const char *) (port))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p ("5061") && ((size_t)(const void *)(("5061") + 1) - (size_t)(const void *)("5061") == 1) && (__s2_len = __builtin_strlen ("5061"), __s2_len < 4) ? (__builtin_constant_p (port) && ((size_t)(const void *)((port) + 1) - (size_t )(const void *)(port) == 1) ? __builtin_strcmp (port, "5061") : (- (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) (port); int __result = (((const unsigned char *) (const char *) ("5061"))[0] - __s2[0]); if (__s2_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) ("5061"))[1] - __s2[1]); if (__s2_len > 1 && __result == 0) { __result = (((const unsigned char *) (const char *) ("5061"))[2] - __s2[2]); if (__s2_len > 2 && __result == 0) __result = (((const unsigned char *) (const char *) ("5061"))[3] - __s2[3]); } } __result ; })))) : __builtin_strcmp (port, "5061")))); }) == 0) | |||
| 2057 | port = NULL((void*)0); | |||
| 2058 | if (port || host_is_ip_address(host)) | |||
| 2059 | transport = NULL((void*)0); | |||
| 2060 | } | |||
| 2061 | else if (port && host_is_ip_address(host) && | |||
| 2062 | strcmp(port, SIP_DEFAULT_SERV)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p (port) && __builtin_constant_p ("5060") && ( __s1_len = __builtin_strlen (port), __s2_len = __builtin_strlen ("5060"), (!((size_t)(const void *)((port) + 1) - (size_t)(const void *)(port) == 1) || __s1_len >= 4) && (!((size_t )(const void *)(("5060") + 1) - (size_t)(const void *)("5060" ) == 1) || __s2_len >= 4)) ? __builtin_strcmp (port, "5060" ) : (__builtin_constant_p (port) && ((size_t)(const void *)((port) + 1) - (size_t)(const void *)(port) == 1) && (__s1_len = __builtin_strlen (port), __s1_len < 4) ? (__builtin_constant_p ("5060") && ((size_t)(const void *)(("5060") + 1) - ( size_t)(const void *)("5060") == 1) ? __builtin_strcmp (port, "5060") : (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) ("5060"); int __result = ((( const unsigned char *) (const char *) (port))[0] - __s2[0]); if (__s1_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) (port))[1] - __s2[1]); if (__s1_len > 1 && __result == 0) { __result = (((const unsigned char *) (const char *) (port))[2] - __s2[2]); if (__s1_len > 2 && __result == 0) __result = (((const unsigned char *) (const char *) (port))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p ("5060") && ((size_t)(const void *)(("5060") + 1) - (size_t)(const void *)("5060") == 1) && (__s2_len = __builtin_strlen ("5060"), __s2_len < 4) ? (__builtin_constant_p (port) && ((size_t)(const void *)((port) + 1) - (size_t )(const void *)(port) == 1) ? __builtin_strcmp (port, "5060") : (- (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) (port); int __result = (((const unsigned char *) (const char *) ("5060"))[0] - __s2[0]); if (__s2_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) ("5060"))[1] - __s2[1]); if (__s2_len > 1 && __result == 0) { __result = (((const unsigned char *) (const char *) ("5060"))[2] - __s2[2]); if (__s2_len > 2 && __result == 0) __result = (((const unsigned char *) (const char *) ("5060"))[3] - __s2[3]); } } __result ; })))) : __builtin_strcmp (port, "5060")))); }) == 0) { | |||
| 2063 | port = NULL((void*)0); | |||
| 2064 | } | |||
| 2065 | ||||
| 2066 | if (transport) { | |||
| 2067 | if (su_casenmatch(transport, "SIP/2.0/", 8)) | |||
| 2068 | transport += 8; | |||
| 2069 | ||||
| 2070 | /* Make transport parameter lowercase */ | |||
| 2071 | if (strlen(transport) < (sizeof _transport)) { | |||
| 2072 | char *s = strcpy(_transport, transport); | |||
| 2073 | short c; | |||
| 2074 | ||||
| 2075 | for (s = _transport; (c = *s) && c != ';'; s++) | |||
| 2076 | if (isupper(c)((*__ctype_b_loc ())[(int) ((c))] & (unsigned short int) _ISupper )) | |||
| 2077 | *s = tolower(c)(__extension__ ({ int __res; if (sizeof (c) > 1) { if (__builtin_constant_p (c)) { int __c = (c); __res = __c < -128 || __c > 255 ? __c : (*__ctype_tolower_loc ())[__c]; } else __res = tolower (c); } else __res = (*__ctype_tolower_loc ())[(int) (c)]; __res ; })); | |||
| 2078 | ||||
| 2079 | transport = _transport; | |||
| 2080 | } | |||
| 2081 | } | |||
| 2082 | ||||
| 2083 | s = NH_PGET(nh, m_username)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_m_username ? ( (nh)->nh_prefs)->nhp_m_username : ((nh)->nh_nua-> nua_handles->nh_prefs)->nhp_m_username); | |||
| 2084 | if (s) | |||
| 2085 | url.url_user = s; | |||
| 2086 | url.url_host = host; | |||
| 2087 | url.url_port = port; | |||
| 2088 | url.url_params = su_strdup(home, NH_PGET(nh, m_params)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_m_params ? ((nh )->nh_prefs)->nhp_m_params : ((nh)->nh_nua->nua_handles ->nh_prefs)->nhp_m_params)); | |||
| 2089 | if (transport) { | |||
| 2090 | url.url_params = url_strip_param_string((char*)url.url_params, "transport"); | |||
| 2091 | url_param_add(home, &url, su_sprintf(home, "transport=%s", transport)); | |||
| 2092 | } | |||
| 2093 | if (maddr) { | |||
| 2094 | url.url_params = url_strip_param_string((char*)url.url_params, "maddr"); | |||
| 2095 | url_param_add(home, &url, su_sprintf(home, "maddr=%s", maddr)); | |||
| 2096 | } | |||
| 2097 | if (comp) { | |||
| 2098 | url.url_params = url_strip_param_string((char*)url.url_params, "comp"); | |||
| 2099 | url_param_add(home, &url, su_sprintf(home, "comp=%s", comp)); | |||
| 2100 | } | |||
| 2101 | ||||
| 2102 | l = su_strlst_create(NULL((void*)0)); | |||
| 2103 | ||||
| 2104 | s = NH_PGET(nh, m_display)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_m_display ? (( nh)->nh_prefs)->nhp_m_display : ((nh)->nh_nua->nua_handles ->nh_prefs)->nhp_m_display); | |||
| 2105 | if (s) { | |||
| 2106 | int quote = s[span_token_lws(s)] != '\0'; | |||
| 2107 | ||||
| 2108 | su_strlst_append(l, quote ? "\"" : ""); | |||
| 2109 | su_strlst_append(l, s); | |||
| 2110 | su_strlst_append(l, quote ? "\" " : " "); | |||
| 2111 | } | |||
| 2112 | ||||
| 2113 | su_strlst_append(l, "<"); | |||
| 2114 | su_strlst_append(l, url_as_string(home, &url)); | |||
| 2115 | su_strlst_append(l, ">"); | |||
| 2116 | ||||
| 2117 | va_start(va, m_param)__builtin_va_start(va, m_param); | |||
| 2118 | ||||
| 2119 | for (s = m_param; s; s = va_arg(va, char *)__builtin_va_arg(va, char *)) { | |||
| 2120 | if (strlen(s) == 0) | |||
| 2121 | continue; | |||
| 2122 | su_strlst_append(l, s[0] == ';' ? "" : ";"); | |||
| 2123 | su_strlst_append(l, s); | |||
| 2124 | } | |||
| 2125 | ||||
| 2126 | va_end(va)__builtin_va_end(va); | |||
| 2127 | ||||
| 2128 | if (!in_dialog) { | |||
| 2129 | s = NH_PGET(nh, m_features)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_m_features ? ( (nh)->nh_prefs)->nhp_m_features : ((nh)->nh_nua-> nua_handles->nh_prefs)->nhp_m_features); | |||
| 2130 | if (s) | |||
| 2131 | s[0] == ';' ? "" : su_strlst_append(l, ";"), su_strlst_append(l, s); | |||
| 2132 | ||||
| 2133 | if (NH_PGET(nh, callee_caps)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_callee_caps ? ( (nh)->nh_prefs)->nhp_callee_caps : ((nh)->nh_nua-> nua_handles->nh_prefs)->nhp_callee_caps)) { | |||
| 2134 | sip_allow_t const *allow = NH_PGET(nh, allow)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_allow ? ((nh)-> nh_prefs)->nhp_allow : ((nh)->nh_nua->nua_handles-> nh_prefs)->nhp_allow); | |||
| 2135 | ||||
| 2136 | if (allow) { | |||
| 2137 | su_strlst_append(l, ";methods=\""); | |||
| 2138 | if (allow->k_items) { | |||
| 2139 | size_t i; | |||
| 2140 | for (i = 0; allow->k_items[i]; i++) { | |||
| 2141 | su_strlst_append(l, allow->k_items[i]); | |||
| 2142 | if (allow->k_items[i + 1]) | |||
| 2143 | su_strlst_append(l, ","); | |||
| 2144 | } | |||
| 2145 | } | |||
| 2146 | su_strlst_append(l, "\""); | |||
| 2147 | } | |||
| 2148 | ||||
| 2149 | if (nh->nh_soa) { | |||
| 2150 | char **media = soa_media_features(nh->nh_soa, 0, home); | |||
| 2151 | ||||
| 2152 | while (*media) { | |||
| 2153 | if (su_strlst_len(l)) | |||
| 2154 | su_strlst_append(l, ";"); | |||
| 2155 | su_strlst_append(l, *media++); | |||
| 2156 | } | |||
| 2157 | } | |||
| 2158 | } | |||
| 2159 | } | |||
| 2160 | ||||
| 2161 | m = sip_contact_make(home, su_strlst_join(l, su_strlst_home(l), "")); | |||
| 2162 | ||||
| 2163 | su_strlst_destroy(l); | |||
| 2164 | ||||
| 2165 | return m; | |||
| 2166 | } |