Bug Summary

File:libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c
Location:line 774, column 7
Description:Value stored to 'contacts' is never read

Annotated Source Code

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
79int nua_registration_from_via(nua_registration_t **list,
80 nua_handle_t *nh,
81 sip_via_t const *via,
82 int public);
83
84int nua_registration_add(nua_registration_t **list, nua_registration_t *nr);
85
86void nua_registration_remove(nua_registration_t *nr);
87
88int nua_registration_set_aor(su_home_t *, nua_registration_t *nr,
89 sip_from_t const *aor);
90
91int nua_registration_set_contact(nua_handle_t *,
92 nua_registration_t *nr,
93 sip_contact_t const *m,
94 int terminating);
95
96void nua_registration_set_ready(nua_registration_t *nr, int ready);
97
98/* ====================================================================== */
99/* REGISTER usage */
100
101static char const *nua_register_usage_name(nua_dialog_usage_t const *du);
102
103static int nua_register_usage_add(nua_handle_t *nh,
104 nua_dialog_state_t *ds,
105 nua_dialog_usage_t *du);
106static 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);
111static 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 *);
115static void nua_register_usage_peer_info(nua_dialog_usage_t *du,
116 nua_dialog_state_t const *ds,
117 sip_t const *sip);
118static void nua_register_usage_refresh(nua_handle_t *,
119 nua_dialog_state_t *,
120 nua_dialog_usage_t *,
121 sip_time_t);
122static 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. */
127struct 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
170nua_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
183static char const *nua_register_usage_name(nua_dialog_usage_t const *du)
184{
185 return "register";
186}
187
188static 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
205static 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. */
236static 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
248static 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 */
255sip_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
263static int nua_stack_outbound_refresh(nua_handle_t *,
264 outbound_t *ob);
265
266static 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
271static 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
276static int nua_stack_outbound_credentials(nua_handle_t *, auth_client_t **auc);
277
278outbound_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
566static int nua_register_client_template(nua_client_request_t *cr,
567 msg_t **return_msg,
568 tagi_t const *tags);
569static int nua_register_client_init(nua_client_request_t *cr,
570 msg_t *, sip_t *,
571 tagi_t const *tags);
572static int nua_register_client_request(nua_client_request_t *cr,
573 msg_t *, sip_t *,
574 tagi_t const *tags);
575static int nua_register_client_check_restart(nua_client_request_t *cr,
576 int status, char const *phrase,
577 sip_t const *sip);
578static int nua_register_client_response(nua_client_request_t *cr,
579 int status, char const *phrase,
580 sip_t const *sip);
581
582static 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. */
601int 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
609static 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
630static 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
708static
709int 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;
Value stored to 'contacts' is never read
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
803static 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
843static 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
1013static
1014void 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
1050static void
1051nua_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
1087static 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 */
1111static 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
1141static void nua_stack_tport_update(nua_t *nua, nta_agent_t *nta);
1142static void nua_stack_tport_error(nua_t *nua, nta_agent_t *nta, tport_t *tport);
1143static 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
1150int
1151nua_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
1263static
1264void 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
1299int 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
1317int
1318nua_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
1382int 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
1482static
1483void nua_stack_tport_error(nua_t *nua, nta_agent_t *nta, tport_t *tport)
1484{
1485 return;
1486}
1487
1488static
1489void 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
1511nua_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
1603nua_registration_t *
1604nua_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
1615nua_registration_t *
1616nua_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 */
1644sip_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. */
1659sip_route_t const *nua_registration_route(nua_registration_t const *nr)
1660{
1661 return nr ? nr->nr_route : NULL((void*)0);
1662}
1663
1664sip_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 */
1671int 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 */
1704int 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 */
1728static
1729int 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 */
1811int 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 */
1828void 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. */
1836int 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. */
1857int 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 */
1905void 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 */
1917int 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 */
1941static 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 */
1976static 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 */
1994static 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 */
2011static 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. */
2021sip_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}