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 | } |