File: | libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c |
Location: | line 2072, column 13 |
Description: | Value stored to 's' during its initialization is never read |
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); |
Value stored to 's' during its initialization is never read | |
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 | } |