Bug Summary

File:nta/nta.c
Warning:line 3434, column 7
Access to field 'cs_method' results in a dereference of a null pointer (loaded from field 'sip_cseq')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name nta.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-eagerly-assume -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -mrelocation-model pic -pic-level 2 -mthread-model posix -mdisable-fp-elim -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -resource-dir /usr/lib/llvm-7/lib/clang/7.0.1 -D HAVE_CONFIG_H -I . -I ../.. -I ../../libsofia-sip-ua/su/sofia-sip -I ./../ipt -I ../ipt -I ./../msg -I ../msg -I ./../sip -I ../sip -I ./../bnf -I ../bnf -I ./../sresolv -I ../sresolv -I ./../tport -I ../tport -I ./../url -I ../url -I ./../features -I ../features -I ./../su -I ../su -I ../../s2check -I ./../stun -I ../stun -D SU_DEBUG=0 -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-7/lib/clang/7.0.1/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir /drone/src/libsofia-sip-ua/nta -ferror-limit 19 -fmessage-length 0 -fobjc-runtime=gcc -fdiagnostics-show-option -analyzer-output=html -o /drone/src/scan-build/2021-08-26-205203-363-1 -x c nta.c -faddrsig
1/*
2 * This file is part of the Sofia-SIP package
3 *
4 * Copyright (C) 2005 Nokia Corporation.
5 *
6 * Contact: Pekka Pessi <pekka.pessi@nokia.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2.1 of
11 * the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301 USA
22 *
23 */
24
25/**@CFILE nta.c
26 * @brief Sofia SIP Transaction API implementation
27 *
28 * This source file has been divided into sections as follows:
29 * 1) agent
30 * 2) tport handling
31 * 3) dispatching messages received from network
32 * 4) message creation and message utility functions
33 * 5) stateless operation
34 * 6) dialogs (legs)
35 * 7) server transactions (incoming)
36 * 8) client transactions (outgoing)
37 * 9) resolving URLs for client transactions
38 * 10) 100rel reliable responses (reliable)
39 * 11) SigComp handling and public transport interface
40 *
41 * @author Pekka Pessi <Pekka.Pessi@nokia.com>
42 *
43 * @date Created: Tue Jun 13 02:57:51 2000 ppessi
44 *
45 * @sa
46 * @RFC3261, @RFC4320
47 */
48
49#include "config.h"
50#ifdef HAVE_ZLIB_COMPRESS1
51#include <zlib.h>
52#endif
53#include <sofia-sip/su_string.h>
54
55/** @internal SU message argument structure type */
56#define SU_MSG_ARG_Tunion sm_arg_u union sm_arg_u
57/** @internal SU timer argument pointer type */
58#define SU_TIMER_ARG_Tstruct nta_agent_s struct nta_agent_s
59
60#include <sofia-sip/su_alloc.h>
61#include <sofia-sip/su.h>
62#include <sofia-sip/su_time.h>
63#include <sofia-sip/su_wait.h>
64#include <sofia-sip/su_tagarg.h>
65
66#include <sofia-sip/base64.h>
67#include <sofia-sip/su_uniqueid.h>
68
69#include <sofia-sip/sip.h>
70#include <sofia-sip/sip_header.h>
71#include <sofia-sip/sip_util.h>
72#include <sofia-sip/sip_status.h>
73
74#include <sofia-sip/hostdomain.h>
75#include <sofia-sip/url_tag.h>
76
77#include <sofia-sip/msg_addr.h>
78#include <sofia-sip/msg_parser.h>
79#include <sofia-sip/htable.h>
80
81/* Resolver context type */
82#define SRES_CONTEXT_Tnta_outgoing_t nta_outgoing_t
83
84/* We are customer of tport_t */
85#define TP_AGENT_Tnta_agent_t nta_agent_t
86#define TP_MAGIC_Tsip_via_t sip_via_t
87#define TP_CLIENT_Tnta_outgoing_t nta_outgoing_t
88
89#include "nta_internal.h"
90
91#include <stddef.h>
92#include <stdlib.h>
93#include <stdio.h>
94#include <stdarg.h>
95#include <assert.h>
96#include <limits.h>
97#include <errno(*__errno_location ()).h>
98
99/* From AM_INIT/AC_INIT in our "config.h" */
100char const nta_version[] = PACKAGE_VERSION"1.13.5";
101
102#if HAVE_FUNC1
103#elif HAVE_FUNCTION1
104#define __func__ __FUNCTION__
105#else
106static char const __func__[] = "nta";
107#endif
108
109#ifndef _MSC_VER
110#define NONE((void *)-1) ((void *)-1)
111#else
112#define NONE((void *)-1) ((void *)(INT_PTR)-1)
113#endif
114/* ------------------------------------------------------------------------- */
115
116/** Resolving order */
117enum nta_res_order_e
118{
119 nta_res_ip6_ip4,
120 nta_res_ip4_ip6,
121 nta_res_ip6_only,
122 nta_res_ip4_only
123};
124
125HTABLE_DECLARE_WITH(leg_htable, lht, nta_leg_t, size_t, hash_value_t)typedef struct leg_htable_s { size_t lht_size; size_t lht_used
; nta_leg_t**lht_table; } leg_htable_t
;
126HTABLE_DECLARE_WITH(outgoing_htable, oht, nta_outgoing_t, size_t, hash_value_t)typedef struct outgoing_htable_s { size_t oht_size; size_t oht_used
; nta_outgoing_t**oht_table; } outgoing_htable_t
;
127HTABLE_DECLARE_WITH(incoming_htable, iht, nta_incoming_t, size_t, hash_value_t)typedef struct incoming_htable_s { size_t iht_size; size_t iht_used
; nta_incoming_t**iht_table; } incoming_htable_t
;
128
129typedef struct outgoing_queue_t {
130 nta_outgoing_t **q_tail;
131 nta_outgoing_t *q_head;
132 size_t q_length;
133 unsigned q_timeout;
134} outgoing_queue_t;
135
136typedef struct incoming_queue_t {
137 nta_incoming_t **q_tail;
138 nta_incoming_t *q_head;
139 size_t q_length;
140 unsigned q_timeout;
141} incoming_queue_t;
142
143struct nta_agent_s
144{
145 su_home_t sa_home[1];
146 su_root_t *sa_root;
147 su_timer_t *sa_timer;
148 nta_agent_magic_t *sa_magic;
149 nta_message_f *sa_callback;
150
151 nta_update_magic_t *sa_update_magic;
152 nta_update_tport_f *sa_update_tport;
153
154 nta_error_magic_t *sa_error_magic;
155 nta_error_tport_f *sa_error_tport;
156
157 uint32_t sa_next; /**< Timestamp for next agent_timer. */
158
159 msg_mclass_t const *sa_mclass;
160 uint32_t sa_flags; /**< SIP message flags */
161 unsigned sa_preload; /**< Memory preload for SIP messages. */
162
163 tport_t *sa_tports;
164 sip_contact_t *sa_contact;
165 sip_via_t *sa_vias; /**< @Via headers for all transports */
166 sip_via_t *sa_public_vias; /**< @Vias for public transports */
167 sip_contact_t *sa_aliases;/**< List of aliases for agent */
168
169 uint64_t sa_branch; /**< Generator for branch parameters */
170 uint64_t sa_tags; /**< Generator for tag parameters */
171
172#if HAVE_SOFIA_SRESOLV1
173 sres_resolver_t *sa_resolver; /**< DNS resolver */
174 enum nta_res_order_e sa_res_order; /** Resolving order (AAAA/A) */
175#endif
176
177 url_t *sa_default_proxy; /**< Default outbound proxy */
178 unsigned sa_bad_req_mask; /**< Request error mask */
179 unsigned sa_bad_resp_mask; /**< Response error mask */
180 usize_t sa_maxsize; /**< Maximum size of incoming messages */
181 usize_t sa_max_proceeding; /**< Maximum size of proceeding queue */
182
183 unsigned sa_udp_mtu; /**< Maximum size of outgoing UDP requests */
184
185 unsigned sa_t1; /**< SIP T1 - initial retransmit interval (500 ms) */
186 unsigned sa_t2; /**< SIP T2 - maximum retransmit interval (4000 ms) */
187 unsigned sa_t4; /**< SIP T4 - clear message time (5000 ms) */
188
189
190 unsigned sa_t1x64; /**< SIP T1X64 - transaction lifetime (32 s) */
191
192 unsigned sa_tls_orq_connect_timeout; /**< Connect Timeout for outgoing requests using TLS (ms) */
193
194 unsigned sa_progress; /**< Progress timer.
195 Interval between retransmitting
196 provisional responses. */
197
198 unsigned sa_timer_c; /**< SIP timer C.
199 Maximum interval between receiving
200 provisional responses. */
201
202 unsigned sa_graylist; /**< Graylisting period */
203 unsigned sa_blacklist; /**< Blacklisting period */
204
205 unsigned sa_drop_prob : 10; /**< NTA is used to test packet drop */
206 unsigned sa_is_a_uas : 1; /**< NTA is acting as an User Agent server */
207 unsigned sa_is_stateless : 1; /**< Process requests statelessly
208 * unless they match existing dialog.
209 */
210 unsigned sa_user_via:1; /**< Let application provide @Via headers */
211 unsigned sa_extra_100:1; /**< Allow NTA to return "100 Trying" response
212 * even if application has not responded.
213 */
214 unsigned sa_pass_100:1; /**< Pass the "100 Trying"
215 * provisional responses to the application
216 */
217 unsigned sa_timeout_408:1; /**< A "408 Request Timeout" message
218 * is generated when outgoing request expires.
219 */
220 unsigned sa_pass_408:1; /**< A "408 Request Timeout" responses
221 * are passed to client.
222 */
223 unsigned sa_merge_482 : 1; /**< A "482 Request Merged" response is returned
224 * to merged requests.
225 */
226 unsigned sa_cancel_2543 : 1; /**< Send a CANCEL to an INVITE without
227 * waiting for an provisional response.
228 */
229 unsigned sa_cancel_487 : 1; /**< Return 487 response automatically when
230 * a CANCEL is received.
231 */
232
233 unsigned sa_invite_100rel:1; /**< Include 100rel in INVITE requests. */
234 unsigned sa_timestamp : 1; /**< Insert @Timestamp in requests. */
235
236 unsigned sa_tport_ip4 : 1; /**< Transports support IPv4. */
237 unsigned sa_tport_ip6 : 1; /**< Transports support IPv6. */
238 unsigned sa_tport_udp : 1; /**< Transports support UDP. */
239 unsigned sa_tport_tcp : 1; /**< Transports support TCP. */
240 unsigned sa_tport_sctp : 1; /**< Transports support SCTP. */
241 unsigned sa_tport_tls : 1; /**< Transports support TLS. */
242 unsigned sa_tport_ws : 1; /**< Transports support WS. */
243 unsigned sa_tport_wss : 1; /**< Transports support WSS. */
244
245 unsigned sa_use_naptr : 1; /**< Use NAPTR lookup */
246 unsigned sa_use_srv : 1; /**< Use SRV lookup */
247
248 unsigned sa_srv_503 : 1; /**< SRV: choice another destination on 503 RFC 3263 */
249
250 unsigned sa_tport_threadpool:1; /**< Transports use threadpool */
251
252 unsigned sa_rport:1; /**< Use rport at client */
253 unsigned sa_server_rport:2; /**< Use rport at server */
254 unsigned sa_tcp_rport:1; /**< Use rport with tcp, too */
255 unsigned sa_tls_rport:1; /**< Use rport with tls, too */
256
257 unsigned sa_auto_comp:1; /**< Automatically create compartments */
258 unsigned sa_in_timer:1; /**< Set when executing timers */
259 unsigned sa_use_timer_c:1; /**< Application has set value for timer C */
260
261 unsigned :0;
262
263#if HAVE_SMIME
264 sm_object_t *sa_smime;
265#else
266 void *sa_smime;
267#endif
268
269 /** @MaxForwards */
270 sip_max_forwards_t sa_max_forwards[1];
271
272 /** Name of SigComp algorithm */
273 char const *sa_algorithm;
274 /** Options for SigComp. */
275 char const *sa_sigcomp_options;
276 char const* const *sa_sigcomp_option_list;
277 char const *sa_sigcomp_option_free;
278
279 nta_compressor_t *sa_compressor;
280
281 /* Statistics */
282 struct {
283 usize_t as_recv_msg;
284 usize_t as_recv_request;
285 usize_t as_recv_response;
286 usize_t as_bad_message;
287 usize_t as_bad_request;
288 usize_t as_bad_response;
289 usize_t as_drop_request;
290 usize_t as_drop_response;
291 usize_t as_client_tr;
292 usize_t as_server_tr;
293 usize_t as_dialog_tr;
294 usize_t as_acked_tr;
295 usize_t as_canceled_tr;
296 usize_t as_trless_request;
297 usize_t as_trless_to_tr;
298 usize_t as_trless_response;
299 usize_t as_trless_200;
300 usize_t as_merged_request;
301 usize_t as_sent_msg;
302 usize_t as_sent_request;
303 usize_t as_sent_response;
304 usize_t as_retry_request;
305 usize_t as_retry_response;
306 usize_t as_recv_retry;
307 usize_t as_tout_request;
308 usize_t as_tout_response;
309 } sa_stats[1];
310
311 /** Hash of dialogs. */
312 leg_htable_t sa_dialogs[1];
313 /** Default leg */
314 nta_leg_t *sa_default_leg;
315 /** Hash of legs without dialogs. */
316 leg_htable_t sa_defaults[1];
317 /** Hash table for outgoing transactions */
318 outgoing_htable_t sa_outgoing[1];
319 nta_outgoing_t *sa_default_outgoing;
320 /** Hash table for incoming transactions */
321 incoming_htable_t sa_incoming[1];
322 nta_incoming_t *sa_default_incoming;
323
324 /* Queues (states) for outgoing client transactions */
325 struct {
326 /** Queue for retrying client transactions */
327 nta_outgoing_t *re_list;
328 nta_outgoing_t **re_t1; /**< Special place for T1 timer */
329 size_t re_length; /**< Length of sa_out.re_list */
330
331 outgoing_queue_t delayed[1];
332 outgoing_queue_t resolving[1];
333
334 outgoing_queue_t trying[1]; /* Timer F / Timer E */
335 outgoing_queue_t completed[1]; /* Timer K */
336 outgoing_queue_t terminated[1];
337
338 /* Special queues (states) for outgoing INVITE transactions */
339 outgoing_queue_t inv_calling[1]; /* Timer B/A */
340 outgoing_queue_t inv_proceeding[1]; /* Timer C */
341 outgoing_queue_t inv_completed[1]; /* Timer D */
342
343 /* Temporary queue for transactions waiting to be freed */
344 outgoing_queue_t *free;
345 } sa_out;
346
347 /* Queues (states) for incoming server transactions */
348 struct {
349 /** Queue for retransmitting response of server transactions */
350 nta_incoming_t *re_list;
351 nta_incoming_t **re_t1; /**< Special place for T1 timer */
352 size_t re_length; /**< Length of sa_in.re_list */
353
354 incoming_queue_t proceeding[1]; /**< Request received */
355 incoming_queue_t preliminary[1]; /**< 100rel sent */
356 incoming_queue_t completed[1]; /**< Final answer sent (non-invite). */
357 incoming_queue_t inv_completed[1]; /**< Final answer sent (INVITE). */
358 incoming_queue_t inv_confirmed[1]; /**< Final answer sent, ACK recvd. */
359 incoming_queue_t terminated[1]; /**< Terminated, ready to free. */
360 incoming_queue_t final_failed[1];
361 } sa_in;
362
363 /* Special task for freeing memory */
364 su_clone_r sa_terminator;
365};
366
367struct nta_leg_s
368{
369 su_home_t leg_home[1];
370 hash_value_t leg_hash;
371
372 unsigned leg_dialog : 1;
373 unsigned leg_stateless : 1; /**< Process requests statelessly */
374#ifdef NTA_STRICT_ROUTING
375 unsigned leg_contact_set : 1;
376#else
377 unsigned leg_loose_route : 1; /**< Topmost route in set is LR */
378#endif
379 unsigned leg_route_set : 1; /**< Route set has been saved */
380 unsigned leg_local_is_to : 1; /**< Backwards-compatibility. */
381 unsigned leg_tagged : 1; /**< Tagged after creation.
382 *
383 * Request missing @To tag matches
384 * a tagged leg even after tagging.
385 */
386 unsigned leg_compressed:1;
387 unsigned:0;
388 nta_request_f *leg_callback;
389 nta_leg_magic_t *leg_magic;
390 nta_agent_t *leg_agent;
391
392 url_t const *leg_url; /**< Match incoming requests. */
393 char const *leg_method; /**< Match incoming requests. */
394
395 uint32_t leg_seq; /**< Sequence number for next transaction */
396 uint32_t leg_rseq; /**< Remote sequence number */
397 sip_call_id_t *leg_id; /**< Call ID */
398 sip_from_t *leg_remote; /**< Remote address (@To/@From) */
399 sip_to_t *leg_local; /**< Local address (@From/@To) */
400
401 sip_route_t *leg_route; /**< @Route for outgoing requests. */
402 sip_contact_t *leg_target; /**< Remote destination (from @Contact). */
403};
404
405struct nta_incoming_s
406{
407 su_home_t *irq_home;
408 hash_value_t irq_hash;
409 nta_agent_t *irq_agent;
410 nta_ack_cancel_f *irq_callback;
411 nta_incoming_magic_t *irq_magic;
412
413 /* Timeout/state queue */
414 nta_incoming_t **irq_prev;
415 nta_incoming_t *irq_next;
416 incoming_queue_t *irq_queue;
417
418 /* Retry queue */
419 nta_incoming_t **irq_rprev;
420 nta_incoming_t *irq_rnext;
421
422 sip_method_t irq_method;
423 sip_request_t *irq_rq;
424 sip_from_t *irq_from;
425 sip_to_t *irq_to;
426 char const *irq_tag;
427 sip_cseq_t *irq_cseq;
428 sip_call_id_t *irq_call_id;
429 sip_via_t *irq_via;
430 sip_record_route_t *irq_record_route;
431 char const *irq_branch;
432
433 uint32_t irq_rseq;
434
435 sip_timestamp_t *irq_timestamp;
436 su_time_t irq_received;
437
438 uint32_t irq_timeout; /**< Timer H, I, J */
439 uint32_t irq_retry; /**< Timer G */
440 unsigned short irq_interval; /**< Next timer */
441
442 short irq_status;
443
444 unsigned irq_retries:8;
445 unsigned irq_default:1; /**< Default transaction */
446 unsigned irq_canceled:1; /**< Transaction is canceled */
447 unsigned irq_completed:1; /**< Transaction is completed */
448 unsigned irq_confirmed:1; /**< Response has been acked */
449 unsigned irq_terminated:1; /**< Transaction is terminated */
450 unsigned irq_final_failed:1; /**< Sending final response failed */
451 unsigned irq_destroyed :1; /**< Transaction is destroyed */
452 unsigned irq_in_callback:1; /**< Callback is being invoked */
453 unsigned irq_reliable_tp:1; /**< Transport is reliable */
454 unsigned irq_sigcomp_zap:1; /**< Reset SigComp */
455 unsigned irq_must_100rel:1; /**< 100rel is required */
456 unsigned irq_extra_100:1; /**< 100 Trying should be sent */
457 unsigned irq_tag_set:1; /**< Tag is not from request */
458 unsigned irq_compressed:1;
459 unsigned :0;
460
461 tp_name_t irq_tpn[1];
462 tport_t *irq_tport;
463 struct sigcomp_compartment *irq_cc;
464 msg_t *irq_request;
465 msg_t *irq_request2; /**< ACK/CANCEL */
466 msg_t *irq_response;
467
468 nta_reliable_t *irq_reliable; /**< List of reliable responses */
469};
470
471struct nta_reliable_s
472{
473 nta_reliable_t *rel_next;
474 nta_incoming_t *rel_irq;
475 nta_prack_f *rel_callback;
476 nta_reliable_magic_t *rel_magic;
477 uint32_t rel_rseq;
478 unsigned short rel_status;
479 unsigned rel_pracked:1;
480 unsigned rel_precious:1;
481 msg_t *rel_response;
482 msg_t *rel_unsent;
483};
484
485typedef struct sipdns_resolver sipdns_resolver_t;
486
487struct nta_outgoing_s
488{
489 hash_value_t orq_hash; /**< Hash value */
490 nta_agent_t *orq_agent;
491 nta_response_f *orq_callback;
492 nta_outgoing_magic_t *orq_magic;
493
494 /* Timeout/state queue */
495 nta_outgoing_t **orq_prev;
496 nta_outgoing_t *orq_next;
497 outgoing_queue_t *orq_queue;
498
499 /* Retry queue */
500 nta_outgoing_t **orq_rprev;
501 nta_outgoing_t *orq_rnext;
502
503 sip_method_t orq_method;
504 char const *orq_method_name;
505 url_t const *orq_url; /**< Original RequestURI */
506
507 sip_from_t const *orq_from;
508 sip_to_t const *orq_to;
509 char const *orq_tag; /**< Tag from final response. */
510
511 sip_cseq_t const *orq_cseq;
512 sip_call_id_t const *orq_call_id;
513
514 msg_t *orq_request;
515 msg_t *orq_response;
516
517 su_time_t orq_sent; /**< When request was sent? */
518 unsigned orq_delay; /**< RTT estimate */
519
520 uint32_t orq_retry; /**< Timer A, E */
521 uint32_t orq_timeout; /**< Timer B, D, F, K */
522
523 unsigned short orq_interval; /**< Next timer A/E */
524
525 unsigned short orq_status;
526 unsigned char orq_retries; /**< Number of tries this far */
527
528 unsigned orq_default:1; /**< This is default transaction */
529 unsigned orq_inserted:1;
530 unsigned orq_resolved:1;
531 unsigned orq_via_added:1;
532 unsigned orq_prepared:1;
533 unsigned orq_canceled:1;
534 unsigned orq_terminated:1;
535 unsigned orq_destroyed:1;
536 unsigned orq_completed:1;
537 unsigned orq_delayed:1;
538 unsigned orq_user_tport:1; /**< Application provided tport - don't retry */
539 unsigned orq_try_tcp_instead:1;
540 unsigned orq_try_udp_instead:1;
541 unsigned orq_reliable:1; /**< Transport is reliable */
542 unsigned orq_call_tls_connect_timeout_is_set:1; /** Per Call connect timeout for outgoing requests using TLS set flag*/
543
544 unsigned orq_forked:1; /**< Tagged fork */
545
546 /* Attributes */
547 unsigned orq_sips:1;
548 unsigned orq_uas:1; /**< Running this transaction as UAS */
549 unsigned orq_user_via:1;
550 unsigned orq_stateless:1;
551 unsigned orq_pass_100:1;
552 unsigned orq_sigcomp_new:1; /**< Create compartment if needed */
553 unsigned orq_sigcomp_zap:1; /**< Reset SigComp after completing */
554 unsigned orq_must_100rel:1;
555 unsigned orq_timestamp:1; /**< Insert @Timestamp header. */
556 unsigned orq_100rel:1; /**< Support 100rel */
557 unsigned:0; /* pad */
558
559#if HAVE_SOFIA_SRESOLV1
560 sipdns_resolver_t *orq_resolver;
561#endif
562 url_t *orq_route; /**< Route URL */
563 tp_name_t orq_tpn[1]; /**< Where to send request */
564
565 tport_t *orq_tport;
566 struct sigcomp_compartment *orq_cc;
567 tagi_t *orq_tags; /**< Tport tag items */
568
569 char const *orq_branch; /**< Transaction branch */
570 char const *orq_via_branch; /**< @Via branch */
571
572 int *orq_status2b; /**< Delayed response */
573
574 nta_outgoing_t *orq_cancel; /**< Delayed CANCEL transaction */
575
576 nta_outgoing_t *orq_forking; /**< Untagged transaction */
577 nta_outgoing_t *orq_forks; /**< Tagged transactions */
578 uint32_t orq_rseq; /**< Latest incoming rseq */
579 int orq_pending; /**< Request is pending in tport */
580 uint32_t orq_call_tls_connect_timeout; /** Per Call connect timeout for outgoing requests using TLS */
581};
582
583/* ------------------------------------------------------------------------- */
584
585/* Internal tags */
586
587/* Delay sending of request */
588#define NTATAG_DELAY_SENDING(x)ntatag_delay_sending, tag_bool_v((x)) ntatag_delay_sending, tag_bool_v((x))
589#define NTATAG_DELAY_SENDING_REF(x)ntatag_delay_sending_ref, tag_bool_vr(&(x)) \
590ntatag_delay_sending_ref, tag_bool_vr(&(x))
591
592extern tag_typedef_t ntatag_delay_sending;
593extern tag_typedef_t ntatag_delay_sending_ref;
594
595/* Allow sending incomplete responses */
596#define NTATAG_INCOMPLETE(x)ntatag_incomplete, tag_bool_v((x)) ntatag_incomplete, tag_bool_v((x))
597#define NTATAG_INCOMPLETE_REF(x)ntatag_incomplete_ref, tag_bool_vr(&(x)) \
598ntatag_incomplete_ref, tag_bool_vr(&(x))
599
600extern tag_typedef_t ntatag_incomplete;
601extern tag_typedef_t ntatag_incomplete_ref;
602
603nta_compressor_vtable_t *nta_compressor_vtable = NULL((void*)0);
604
605/* Agent */
606static int agent_tag_init(nta_agent_t *self);
607static int agent_timer_init(nta_agent_t *agent);
608static void agent_timer(su_root_magic_t *rm, su_timer_t *, nta_agent_t *);
609static int agent_launch_terminator(nta_agent_t *agent);
610static void agent_kill_terminator(nta_agent_t *agent);
611static int agent_set_params(nta_agent_t *agent, tagi_t *tags);
612static void agent_set_udp_params(nta_agent_t *self, usize_t udp_mtu);
613static int agent_get_params(nta_agent_t *agent, tagi_t *tags);
614
615/* Transport interface */
616static sip_via_t const *agent_tport_via(tport_t *tport);
617static int outgoing_insert_via(nta_outgoing_t *orq, sip_via_t const *);
618static int nta_tpn_by_via(tp_name_t *tpn, sip_via_t const *v, int *using_rport);
619
620static msg_t *nta_msg_create_for_transport(nta_agent_t *agent, int flags,
621 char const data[], usize_t dlen,
622 tport_t const *tport,
623 tp_client_t *via);
624
625static int complete_response(msg_t *response,
626 int status, char const *phrase,
627 msg_t *request);
628
629static int mreply(nta_agent_t *agent,
630 msg_t *reply,
631 int status, char const *phrase,
632 msg_t *req_msg,
633 tport_t *tport,
634 int incomplete,
635 int sdwn_after,
636 char const *to_tag,
637 tag_type_t tag, tag_value_t value, ...);
638
639#define IF_SIGCOMP_TPTAG_COMPARTMENT(cc)!(cc && cc != ((void *)-1)) ? tag_skip : tptag_compartment
, tag_ptr_v((cc)),
TAG_IF(cc && cc != NONE, TPTAG_COMPARTMENT(cc))!(cc && cc != ((void *)-1)) ? tag_skip : tptag_compartment
, tag_ptr_v((cc))
,
640#define IF_SIGCOMP_TPTAG_COMPARTMENT_REF(cc)tptag_compartment_ref, tag_ptr_vr(&(cc), cc), TPTAG_COMPARTMENT_REF(cc)tptag_compartment_ref, tag_ptr_vr(&(cc), cc),
641
642struct sigcomp_compartment;
643
644struct sigcomp_compartment *
645nta_compartment_ref(struct sigcomp_compartment *cc);
646
647static
648struct sigcomp_compartment *
649agent_compression_compartment(nta_agent_t *sa, tport_t *tp, tp_name_t const *tpn,
650 int new_if_needed);
651
652static
653int agent_accept_compressed(nta_agent_t *sa, msg_t *msg,
654 struct sigcomp_compartment *cc);
655
656static int agent_close_compressor(nta_agent_t *sa,
657 struct sigcomp_compartment *cc);
658
659static int agent_zap_compressor(nta_agent_t *sa,
660 struct sigcomp_compartment *cc);
661
662
663static char const * stateful_branch(su_home_t *home, nta_agent_t *);
664static char const * stateless_branch(nta_agent_t *, msg_t *, sip_t const *,
665 tp_name_t const *tp);
666
667#define NTA_BRANCH_PRIME(uint64_t)(0xB9591D1C361C6521ULL) SU_U64_C(0xB9591D1C361C6521)(uint64_t)(0xB9591D1C361C6521ULL)
668#define NTA_TAG_PRIME(uint64_t)(0xB9591D1C361C6521ULL) SU_U64_C(0xB9591D1C361C6521)(uint64_t)(0xB9591D1C361C6521ULL)
669
670#ifndef UINT32_MAX(4294967295U)
671#define UINT32_MAX(4294967295U) (0xffffffffU)
672#endif
673
674HTABLE_PROTOS_WITH(leg_htable, lht, nta_leg_t, size_t, hash_value_t)static inline int leg_htable_resize(su_home_t *, leg_htable_t
lht[1], size_t); static inline int leg_htable_is_full(leg_htable_t
const *); static inline nta_leg_t **leg_htable_hash(leg_htable_t
const *, hash_value_t hv); static inline nta_leg_t **leg_htable_next
(leg_htable_t const *, nta_leg_t * const *ee); static inline void
leg_htable_append(leg_htable_t *lht, nta_leg_t const *e); static
inline void leg_htable_insert(leg_htable_t *lht, nta_leg_t const
*e); static inline int leg_htable_remove(leg_htable_t *, nta_leg_t
const *e)
;
675static nta_leg_t *leg_find(nta_agent_t const *sa,
676 char const *method_name,
677 url_t const *request_uri,
678 sip_call_id_t const *i,
679 char const *from_tag,
680 char const *to_tag);
681static nta_leg_t *dst_find(nta_agent_t const *sa, url_t const *u0,
682 char const *method);
683static void leg_recv(nta_leg_t *, msg_t *, sip_t *, tport_t *);
684static void leg_free(nta_agent_t *sa, nta_leg_t *leg);
685
686#define NTA_HASH(i, cs)((i)->i_hash + 26839U * (uint32_t)(cs)) ((i)->i_hash + 26839U * (uint32_t)(cs))
687
688HTABLE_PROTOS_WITH(incoming_htable, iht, nta_incoming_t, size_t, hash_value_t)static inline int incoming_htable_resize(su_home_t *, incoming_htable_t
iht[1], size_t); static inline int incoming_htable_is_full(incoming_htable_t
const *); static inline nta_incoming_t **incoming_htable_hash
(incoming_htable_t const *, hash_value_t hv); static inline nta_incoming_t
**incoming_htable_next(incoming_htable_t const *, nta_incoming_t
* const *ee); static inline void incoming_htable_append(incoming_htable_t
*iht, nta_incoming_t const *e); static inline void incoming_htable_insert
(incoming_htable_t *iht, nta_incoming_t const *e); static inline
int incoming_htable_remove(incoming_htable_t *, nta_incoming_t
const *e)
;
689static nta_incoming_t *incoming_create(nta_agent_t *agent,
690 msg_t *request,
691 sip_t *sip,
692 tport_t *tport,
693 char const *tag);
694static int incoming_callback(nta_leg_t *leg, nta_incoming_t *irq, sip_t *sip);
695static void incoming_free(nta_incoming_t *irq);
696su_inlinestatic inline void incoming_cut_off(nta_incoming_t *irq);
697su_inlinestatic inline void incoming_reclaim(nta_incoming_t *irq);
698static void incoming_queue_init(incoming_queue_t *,
699 unsigned timeout);
700static void incoming_queue_adjust(nta_agent_t *sa,
701 incoming_queue_t *queue,
702 unsigned timeout);
703
704static nta_incoming_t *incoming_find(nta_agent_t const *agent,
705 sip_t const *sip,
706 sip_via_t const *v,
707 nta_incoming_t **merge,
708 nta_incoming_t **ack,
709 nta_incoming_t **cancel);
710static int incoming_reply(nta_incoming_t *irq, msg_t *msg, sip_t *sip);
711su_inlinestatic inline int incoming_recv(nta_incoming_t *irq, msg_t *msg, sip_t *sip,
712 tport_t *tport);
713su_inlinestatic inline int incoming_ack(nta_incoming_t *irq, msg_t *msg, sip_t *sip,
714 tport_t *tport);
715su_inlinestatic inline int incoming_cancel(nta_incoming_t *irq, msg_t *msg, sip_t *sip,
716 tport_t *tport);
717static void request_merge(nta_agent_t *,
718 msg_t *msg, sip_t *sip, tport_t *tport,
719 char const *to_tag);
720su_inlinestatic inline int incoming_timestamp(nta_incoming_t *, msg_t *, sip_t *);
721static void _nta_incoming_timer(nta_agent_t *);
722
723static nta_reliable_t *reliable_mreply(nta_incoming_t *,
724 nta_prack_f *, nta_reliable_magic_t *,
725 msg_t *, sip_t *);
726static int reliable_send(nta_incoming_t *, nta_reliable_t *, msg_t *, sip_t *);
727static int reliable_final(nta_incoming_t *irq, msg_t *msg, sip_t *sip);
728static msg_t *reliable_response(nta_incoming_t *irq);
729static nta_reliable_t *reliable_find(nta_agent_t const *, sip_t const *);
730static int reliable_recv(nta_reliable_t *rel, msg_t *, sip_t *, tport_t *);
731static void reliable_flush(nta_incoming_t *irq);
732static void reliable_timeout(nta_incoming_t *irq, int timeout);
733
734HTABLE_PROTOS_WITH(outgoing_htable, oht, nta_outgoing_t, size_t, hash_value_t)static inline int outgoing_htable_resize(su_home_t *, outgoing_htable_t
oht[1], size_t); static inline int outgoing_htable_is_full(outgoing_htable_t
const *); static inline nta_outgoing_t **outgoing_htable_hash
(outgoing_htable_t const *, hash_value_t hv); static inline nta_outgoing_t
**outgoing_htable_next(outgoing_htable_t const *, nta_outgoing_t
* const *ee); static inline void outgoing_htable_append(outgoing_htable_t
*oht, nta_outgoing_t const *e); static inline void outgoing_htable_insert
(outgoing_htable_t *oht, nta_outgoing_t const *e); static inline
int outgoing_htable_remove(outgoing_htable_t *, nta_outgoing_t
const *e)
;
735static nta_outgoing_t *outgoing_create(nta_agent_t *agent,
736 nta_response_f *callback,
737 nta_outgoing_magic_t *magic,
738 url_string_t const *route_url,
739 tp_name_t const *tpn,
740 msg_t *msg,
741 tag_type_t tag, tag_value_t value, ...);
742static void outgoing_queue_init(outgoing_queue_t *,
743 unsigned timeout);
744static void outgoing_queue_adjust(nta_agent_t *sa,
745 outgoing_queue_t *queue,
746 unsigned timeout);
747static void outgoing_free(nta_outgoing_t *orq);
748su_inlinestatic inline void outgoing_cut_off(nta_outgoing_t *orq);
749su_inlinestatic inline void outgoing_reclaim(nta_outgoing_t *orq);
750static nta_outgoing_t *outgoing_find(nta_agent_t const *sa,
751 msg_t const *msg,
752 sip_t const *sip,
753 sip_via_t const *v);
754static int outgoing_recv(nta_outgoing_t *orq, int status, msg_t *, sip_t *);
755static void outgoing_default_recv(nta_outgoing_t *, int, msg_t *, sip_t *);
756static void _nta_outgoing_timer(nta_agent_t *);
757static int outgoing_recv_reliable(nta_outgoing_t *orq, msg_t *msg, sip_t *sip);
758
759/* Internal message passing */
760union sm_arg_u {
761 struct outgoing_recv_s {
762 nta_outgoing_t *orq;
763 msg_t *msg;
764 sip_t *sip;
765 int status;
766 } a_outgoing_recv[1];
767
768 incoming_queue_t a_incoming_queue[1];
769 outgoing_queue_t a_outgoing_queue[1];
770};
771
772/* Global module data */
773
774/**@var char const NTA_DEBUG[];
775 *
776 * Environment variable determining the default debug log level.
777 *
778 * The NTA_DEBUG environment variable is used to determine the default
779 * debug logging level. The normal level is 3.
780 *
781 * @sa <sofia-sip/su_debug.h>, #su_log_global, #SOFIA_DEBUG
782 */
783#ifdef DOXYGEN
784extern char const NTA_DEBUG[]; /* dummy declaration for Doxygen */
785#endif
786
787#ifndef SU_DEBUG0
788#define SU_DEBUG0 3
789#endif
790
791/**Debug log for @b nta module.
792 *
793 * The nta_log is the log object used by @b nta module. The level of
794 * nta_log is set using #NTA_DEBUG environment variable.
795 */
796su_log_t nta_log[] = { SU_LOG_INIT("nta", "NTA_DEBUG", SU_DEBUG){ sizeof(su_log_t), "nta", "NTA_DEBUG", 0, SU_LOG_MAX, 0, ((void
*)0), ((void*)0), }
};
797
798/* ====================================================================== */
799/* 1) Agent */
800
801/**
802 * Create an NTA agent object.
803 *
804 * Create an NTA agent object. The agent
805 * object creates and binds a server socket with address specified in @e url.
806 * If the @e host portion of the @e url is @c "*", the agent listens to all
807 * addresses available on the host.
808 *
809 * When a message is received, the agent object parses it. If the result is
810 * a valid SIP message, the agent object passes the message to the
811 * application by invoking the nta_message_f @e callback function.
812 *
813 * @note
814 * The @e url can be either parsed url (of type url_t ()), or a valid
815 * SIP URL as a string.
816 *
817 * @note
818 * If @e url is @c NULL, the default @e url @c "sip:*" is used.
819 * @par
820 * If @e url is @c NONE (iow, (void*)-1), no server sockets are bound.
821 * @par
822 * If @p transport parameters are specified in @a url, agent uses only
823 * specified transport type.
824 *
825 * @par
826 * If an @p maddr parameter is specified in @e url, agent binds to the
827 * specified address, but uses @e host part of @e url when it generates
828 * @Contact and @Via headers. The @p maddr parameter is also included,
829 * unless it equals to @c INADDR_ANY (@p 0.0.0.0 or @p [::]).
830 *
831 * @param root pointer to a su_root_t used for synchronization
832 * @param contact_url URL that agent uses to bind the server sockets
833 * @param callback pointer to callback function
834 * @param magic pointer to user data
835 * @param tag,value,... tagged arguments
836 *
837 * @TAGS
838 * NTATAG_ALIASES(),
839 * NTATAG_BAD_REQ_MASK(), NTATAG_BAD_RESP_MASK(), NTATAG_BLACKLIST(),
840 * NTATAG_CANCEL_2543(), NTATAG_CANCEL_487(), NTATAG_CLIENT_RPORT(),
841 * NTATAG_DEBUG_DROP_PROB(), NTATAG_DEFAULT_PROXY(),
842 * NTATAG_EXTRA_100(), NTATAG_GRAYLIST(),
843 * NTATAG_MAXSIZE(), NTATAG_MAX_FORWARDS(), NTATAG_MERGE_482(), NTATAG_MCLASS()
844 * NTATAG_PASS_100(), NTATAG_PASS_408(), NTATAG_PRELOAD(), NTATAG_PROGRESS(),
845 * NTATAG_REL100(),
846 * NTATAG_SERVER_RPORT(),
847 * NTATAG_SIPFLAGS(),
848 * NTATAG_SIP_T1X64(), NTATAG_SIP_T1(), NTATAG_SIP_T2(), NTATAG_SIP_T4(),
849 * NTATAG_STATELESS(),
850 * NTATAG_TAG_3261(), NTATAG_TCP_RPORT(), NTATAG_TIMEOUT_408(),
851 * NTATAG_TLS_RPORT(), NTATAG_TLS_ORQ_CONNECT_TIMEOUT(),
852 * NTATAG_TIMER_C(), NTATAG_MAX_PROCEEDING(),
853 * NTATAG_UA(), NTATAG_UDP_MTU(), NTATAG_USER_VIA(),
854 * NTATAG_USE_NAPTR(), NTATAG_USE_SRV() and NTATAG_USE_TIMESTAMP().
855 *
856 * @note The value from following tags are stored, but they currently do nothing:
857 * NTATAG_SIGCOMP_ALGORITHM(), NTATAG_SIGCOMP_OPTIONS(), NTATAG_SMIME()
858 *
859 * @note It is possible to provide @c (url_string_t*)-1 as @a contact_url.
860 * In that case, no server sockets are bound.
861 *
862 * @retval handle to the agent when successful,
863 * @retval NULL upon an error.
864 *
865 * @sa NUTAG_
866 */
867nta_agent_t *nta_agent_create(su_root_t *root,
868 url_string_t const *contact_url,
869 nta_message_f *callback,
870 nta_agent_magic_t *magic,
871 tag_type_t tag, tag_value_t value, ...)
872{
873 nta_agent_t *agent;
874 ta_list ta;
875
876 if (root == NULL((void*)0))
877 return su_seterrno(EINVAL22), NULL((void*)0);
878
879 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)
;
880
881 if ((agent = su_home_new(sizeof(*agent)))) {
882 unsigned timer_c = 0, timer_d = 32000;
883
884 agent->sa_root = root;
885 agent->sa_callback = callback;
886 agent->sa_magic = magic;
887 agent->sa_flags = MSG_DO_CANONICMSG_FLG_CANONIC;
888
889 agent->sa_maxsize = 2 * 1024 * 1024; /* 2 MB */
890 agent->sa_bad_req_mask =
891 /*
892 * Bit-wise not of these - what is left is suitable for UAs with
893 * 100rel, timer, events, publish
894 */
895 (unsigned) ~(sip_mask_response | sip_mask_proxy | sip_mask_registrar |
896 sip_mask_pref | sip_mask_privacy);
897 agent->sa_bad_resp_mask =
898 (unsigned) ~(sip_mask_request | sip_mask_proxy | sip_mask_registrar |
899 sip_mask_pref | sip_mask_privacy);
900 agent->sa_t1 = NTA_SIP_T1;
901 agent->sa_t2 = NTA_SIP_T2;
902 agent->sa_t4 = NTA_SIP_T4;
903 agent->sa_t1x64 = 64 * NTA_SIP_T1;
904 agent->sa_timer_c = 185 * 1000;
905 agent->sa_graylist = 600;
906 agent->sa_drop_prob = 0;
907 agent->sa_is_a_uas = 0;
908 agent->sa_progress = 60 * 1000;
909 agent->sa_user_via = 0;
910 agent->sa_extra_100 = 0;
911 agent->sa_pass_100 = 0;
912 agent->sa_timeout_408 = 1;
913 agent->sa_pass_408 = 0;
914 agent->sa_merge_482 = 0;
915 agent->sa_cancel_2543 = 0;
916 agent->sa_cancel_487 = 1;
917 agent->sa_invite_100rel = 0;
918 agent->sa_timestamp = 0;
919 agent->sa_use_naptr = 1;
920 agent->sa_use_srv = 1;
921 agent->sa_srv_503 = 1;
922 agent->sa_auto_comp = 0;
923 agent->sa_server_rport = 1;
924
925 /* RFC 3261 section 8.1.1.6 */
926 sip_max_forwards_init(agent->sa_max_forwards);
927
928 if (getenv("SIPCOMPACT"))
929 agent->sa_flags |= MSG_DO_COMPACTMSG_FLG_COMPACT;
930
931 agent_set_params(agent, ta_args(ta)(ta).tl);
932
933 if (agent->sa_mclass == NULL((void*)0))
934 agent->sa_mclass = sip_default_mclass();
935
936 agent->sa_in.re_t1 = &agent->sa_in.re_list;
937
938 incoming_queue_init(agent->sa_in.proceeding, 0);
939 incoming_queue_init(agent->sa_in.preliminary, agent->sa_t1x64); /* P1 */
940 incoming_queue_init(agent->sa_in.inv_completed, agent->sa_t1x64); /* H */
941 incoming_queue_init(agent->sa_in.inv_confirmed, agent->sa_t4); /* I */
942 incoming_queue_init(agent->sa_in.completed, agent->sa_t1x64); /* J */
943 incoming_queue_init(agent->sa_in.terminated, 0);
944 incoming_queue_init(agent->sa_in.final_failed, 0);
945
946 agent->sa_out.re_t1 = &agent->sa_out.re_list;
947
948 if (agent->sa_use_timer_c || !agent->sa_is_a_uas)
949 timer_c = agent->sa_timer_c;
950 if (timer_d < agent->sa_t1x64)
951 timer_d = agent->sa_t1x64;
952
953 outgoing_queue_init(agent->sa_out.delayed, 0);
954 outgoing_queue_init(agent->sa_out.resolving, 0);
955 outgoing_queue_init(agent->sa_out.trying, agent->sa_t1x64); /* F */
956 outgoing_queue_init(agent->sa_out.completed, agent->sa_t4); /* K */
957 outgoing_queue_init(agent->sa_out.terminated, 0);
958 /* Special queues (states) for outgoing INVITE transactions */
959 outgoing_queue_init(agent->sa_out.inv_calling, agent->sa_t1x64); /* B */
960 outgoing_queue_init(agent->sa_out.inv_proceeding, timer_c); /* C */
961 outgoing_queue_init(agent->sa_out.inv_completed, timer_d); /* D */
962
963 if (leg_htable_resize(agent->sa_home, agent->sa_dialogs, 0) < 0 ||
964 leg_htable_resize(agent->sa_home, agent->sa_defaults, 0) < 0 ||
965 outgoing_htable_resize(agent->sa_home, agent->sa_outgoing, 0) < 0 ||
966 incoming_htable_resize(agent->sa_home, agent->sa_incoming, 0) < 0) {
967 SU_DEBUG_0(("nta_agent_create: failure with %s\n", "hash tables"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 0 ? (_su_llog(nta_log, 0, "nta.c", (const char *)__func__
, 967, "nta_agent_create: failure with %s\n", "hash tables"))
: (void)0)
;
968 goto deinit;
969 }
970 SU_DEBUG_9(("nta_agent_create: initialized %s\n", "hash tables"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__
, 970, "nta_agent_create: initialized %s\n", "hash tables")) :
(void)0)
;
971
972 if (contact_url != (url_string_t *)-1 &&
973 nta_agent_add_tport(agent, contact_url, ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
) < 0) {
974 SU_DEBUG_7(("nta_agent_create: failure with %s\n", "transport"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__
, 974, "nta_agent_create: failure with %s\n", "transport")) :
(void)0)
;
975 goto deinit;
976 }
977 SU_DEBUG_9(("nta_agent_create: initialized %s\n", "transports"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__
, 977, "nta_agent_create: initialized %s\n", "transports")) :
(void)0)
;
978
979 if (agent_tag_init(agent) < 0) {
980 SU_DEBUG_3(("nta_agent_create: failure with %s\n", "random identifiers"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 980, "nta_agent_create: failure with %s\n", "random identifiers"
)) : (void)0)
;
981 goto deinit;
982 }
983 SU_DEBUG_9(("nta_agent_create: initialized %s\n", "random identifiers"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__
, 983, "nta_agent_create: initialized %s\n", "random identifiers"
)) : (void)0)
;
984
985 if (agent_timer_init(agent) < 0) {
986 SU_DEBUG_0(("nta_agent_create: failure with %s\n", "timer"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 0 ? (_su_llog(nta_log, 0, "nta.c", (const char *)__func__
, 986, "nta_agent_create: failure with %s\n", "timer")) : (void
)0)
;
987 goto deinit;
988 }
989 SU_DEBUG_9(("nta_agent_create: initialized %s\n", "timer"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__
, 989, "nta_agent_create: initialized %s\n", "timer")) : (void
)0)
;
990
991 if (agent_launch_terminator(agent) == 0)
992 SU_DEBUG_9(("nta_agent_create: initialized %s\n", "threads"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__
, 992, "nta_agent_create: initialized %s\n", "threads")) : (void
)0)
;
993
994#if HAVE_SOFIA_SRESOLV1
995 agent->sa_resolver = sres_resolver_create(root, NULL((void*)0), ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
);
996 if (!agent->sa_resolver) {
997 SU_DEBUG_0(("nta_agent_create: failure with %s\n", "resolver"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 0 ? (_su_llog(nta_log, 0, "nta.c", (const char *)__func__
, 997, "nta_agent_create: failure with %s\n", "resolver")) : (
void)0)
;
998 }
999 SU_DEBUG_9(("nta_agent_create: initialized %s\n", "resolver"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__
, 999, "nta_agent_create: initialized %s\n", "resolver")) : (
void)0)
;
1000#endif
1001
1002 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))
;
1003
1004 return agent;
1005
1006 deinit:
1007 nta_agent_destroy(agent);
1008 }
1009
1010 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))
;
1011
1012 return NULL((void*)0);
1013}
1014
1015/**
1016 * Destroy an NTA agent object.
1017 *
1018 * @param agent the NTA agent object to be destroyed.
1019 *
1020 */
1021void nta_agent_destroy(nta_agent_t *agent)
1022{
1023 if (agent) {
1024 size_t i;
1025 outgoing_htable_t *oht = agent->sa_outgoing;
1026 incoming_htable_t *iht = agent->sa_incoming;
1027 /* Currently, this is pretty pointless, as legs don't keep any resources */
1028 leg_htable_t *lht;
1029 nta_leg_t *leg;
1030
1031 for (i = 0, lht = agent->sa_dialogs; i < lht->lht_size; i++) {
1032 if ((leg = lht->lht_table[i])) {
1033 SU_DEBUG_3(("nta_agent_destroy: destroying dialog with <"(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 1035, "nta_agent_destroy: destroying dialog with <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
">\n", (leg->leg_remote->a_url)->url_scheme ? (leg
->leg_remote->a_url)->url_scheme : "", (leg->leg_remote
->a_url)->url_type != url_any && (leg->leg_remote
->a_url)->url_scheme && (leg->leg_remote->
a_url)->url_scheme[0] ? ":" : "", (leg->leg_remote->
a_url)->url_root && ((leg->leg_remote->a_url
)->url_host || (leg->leg_remote->a_url)->url_user
) ? "//" : "", (leg->leg_remote->a_url)->url_user ? (
leg->leg_remote->a_url)->url_user : "", (leg->leg_remote
->a_url)->url_user && (leg->leg_remote->a_url
)->url_password ? ":" : "", (leg->leg_remote->a_url)
->url_user && (leg->leg_remote->a_url)->url_password
? (leg->leg_remote->a_url)->url_password : "", (leg
->leg_remote->a_url)->url_user && (leg->leg_remote
->a_url)->url_host ? "@" : "", (leg->leg_remote->
a_url)->url_host ? (leg->leg_remote->a_url)->url_host
: "", (leg->leg_remote->a_url)->url_host &&
(leg->leg_remote->a_url)->url_port ? ":" : "", (leg
->leg_remote->a_url)->url_host && (leg->leg_remote
->a_url)->url_port ? (leg->leg_remote->a_url)->
url_port : "", (leg->leg_remote->a_url)->url_root &&
(leg->leg_remote->a_url)->url_path ? "/" : "", (leg
->leg_remote->a_url)->url_path ? (leg->leg_remote
->a_url)->url_path : "", (leg->leg_remote->a_url)
->url_params ? ";" : "", (leg->leg_remote->a_url)->
url_params ? (leg->leg_remote->a_url)->url_params : ""
, (leg->leg_remote->a_url)->url_headers ? "?" : "", (
leg->leg_remote->a_url)->url_headers ? (leg->leg_remote
->a_url)->url_headers : "", (leg->leg_remote->a_url
)->url_fragment ? "#" : "", (leg->leg_remote->a_url)
->url_fragment ? (leg->leg_remote->a_url)->url_fragment
: "")) : (void)0)
1034 URL_PRINT_FORMAT ">\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 1035, "nta_agent_destroy: destroying dialog with <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
">\n", (leg->leg_remote->a_url)->url_scheme ? (leg
->leg_remote->a_url)->url_scheme : "", (leg->leg_remote
->a_url)->url_type != url_any && (leg->leg_remote
->a_url)->url_scheme && (leg->leg_remote->
a_url)->url_scheme[0] ? ":" : "", (leg->leg_remote->
a_url)->url_root && ((leg->leg_remote->a_url
)->url_host || (leg->leg_remote->a_url)->url_user
) ? "//" : "", (leg->leg_remote->a_url)->url_user ? (
leg->leg_remote->a_url)->url_user : "", (leg->leg_remote
->a_url)->url_user && (leg->leg_remote->a_url
)->url_password ? ":" : "", (leg->leg_remote->a_url)
->url_user && (leg->leg_remote->a_url)->url_password
? (leg->leg_remote->a_url)->url_password : "", (leg
->leg_remote->a_url)->url_user && (leg->leg_remote
->a_url)->url_host ? "@" : "", (leg->leg_remote->
a_url)->url_host ? (leg->leg_remote->a_url)->url_host
: "", (leg->leg_remote->a_url)->url_host &&
(leg->leg_remote->a_url)->url_port ? ":" : "", (leg
->leg_remote->a_url)->url_host && (leg->leg_remote
->a_url)->url_port ? (leg->leg_remote->a_url)->
url_port : "", (leg->leg_remote->a_url)->url_root &&
(leg->leg_remote->a_url)->url_path ? "/" : "", (leg
->leg_remote->a_url)->url_path ? (leg->leg_remote
->a_url)->url_path : "", (leg->leg_remote->a_url)
->url_params ? ";" : "", (leg->leg_remote->a_url)->
url_params ? (leg->leg_remote->a_url)->url_params : ""
, (leg->leg_remote->a_url)->url_headers ? "?" : "", (
leg->leg_remote->a_url)->url_headers ? (leg->leg_remote
->a_url)->url_headers : "", (leg->leg_remote->a_url
)->url_fragment ? "#" : "", (leg->leg_remote->a_url)
->url_fragment ? (leg->leg_remote->a_url)->url_fragment
: "")) : (void)0)
1035 URL_PRINT_ARGS(leg->leg_remote->a_url)))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 1035, "nta_agent_destroy: destroying dialog with <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
">\n", (leg->leg_remote->a_url)->url_scheme ? (leg
->leg_remote->a_url)->url_scheme : "", (leg->leg_remote
->a_url)->url_type != url_any && (leg->leg_remote
->a_url)->url_scheme && (leg->leg_remote->
a_url)->url_scheme[0] ? ":" : "", (leg->leg_remote->
a_url)->url_root && ((leg->leg_remote->a_url
)->url_host || (leg->leg_remote->a_url)->url_user
) ? "//" : "", (leg->leg_remote->a_url)->url_user ? (
leg->leg_remote->a_url)->url_user : "", (leg->leg_remote
->a_url)->url_user && (leg->leg_remote->a_url
)->url_password ? ":" : "", (leg->leg_remote->a_url)
->url_user && (leg->leg_remote->a_url)->url_password
? (leg->leg_remote->a_url)->url_password : "", (leg
->leg_remote->a_url)->url_user && (leg->leg_remote
->a_url)->url_host ? "@" : "", (leg->leg_remote->
a_url)->url_host ? (leg->leg_remote->a_url)->url_host
: "", (leg->leg_remote->a_url)->url_host &&
(leg->leg_remote->a_url)->url_port ? ":" : "", (leg
->leg_remote->a_url)->url_host && (leg->leg_remote
->a_url)->url_port ? (leg->leg_remote->a_url)->
url_port : "", (leg->leg_remote->a_url)->url_root &&
(leg->leg_remote->a_url)->url_path ? "/" : "", (leg
->leg_remote->a_url)->url_path ? (leg->leg_remote
->a_url)->url_path : "", (leg->leg_remote->a_url)
->url_params ? ";" : "", (leg->leg_remote->a_url)->
url_params ? (leg->leg_remote->a_url)->url_params : ""
, (leg->leg_remote->a_url)->url_headers ? "?" : "", (
leg->leg_remote->a_url)->url_headers ? (leg->leg_remote
->a_url)->url_headers : "", (leg->leg_remote->a_url
)->url_fragment ? "#" : "", (leg->leg_remote->a_url)
->url_fragment ? (leg->leg_remote->a_url)->url_fragment
: "")) : (void)0)
;
1036 leg_free(agent, leg);
1037 }
1038 }
1039
1040 for (i = 0, lht = agent->sa_defaults; i < lht->lht_size; i++) {
1041 if ((leg = lht->lht_table[i])) {
1042 SU_DEBUG_3(("%s: destroying leg for <"(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 1044, "%s: destroying leg for <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
">\n", __func__, (leg->leg_url)->url_scheme ? (leg->
leg_url)->url_scheme : "", (leg->leg_url)->url_type !=
url_any && (leg->leg_url)->url_scheme &&
(leg->leg_url)->url_scheme[0] ? ":" : "", (leg->leg_url
)->url_root && ((leg->leg_url)->url_host || (
leg->leg_url)->url_user) ? "//" : "", (leg->leg_url)
->url_user ? (leg->leg_url)->url_user : "", (leg->
leg_url)->url_user && (leg->leg_url)->url_password
? ":" : "", (leg->leg_url)->url_user && (leg->
leg_url)->url_password ? (leg->leg_url)->url_password
: "", (leg->leg_url)->url_user && (leg->leg_url
)->url_host ? "@" : "", (leg->leg_url)->url_host ? (
leg->leg_url)->url_host : "", (leg->leg_url)->url_host
&& (leg->leg_url)->url_port ? ":" : "", (leg->
leg_url)->url_host && (leg->leg_url)->url_port
? (leg->leg_url)->url_port : "", (leg->leg_url)->
url_root && (leg->leg_url)->url_path ? "/" : ""
, (leg->leg_url)->url_path ? (leg->leg_url)->url_path
: "", (leg->leg_url)->url_params ? ";" : "", (leg->
leg_url)->url_params ? (leg->leg_url)->url_params : ""
, (leg->leg_url)->url_headers ? "?" : "", (leg->leg_url
)->url_headers ? (leg->leg_url)->url_headers : "", (
leg->leg_url)->url_fragment ? "#" : "", (leg->leg_url
)->url_fragment ? (leg->leg_url)->url_fragment : "")
) : (void)0)
1043 URL_PRINT_FORMAT ">\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 1044, "%s: destroying leg for <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
">\n", __func__, (leg->leg_url)->url_scheme ? (leg->
leg_url)->url_scheme : "", (leg->leg_url)->url_type !=
url_any && (leg->leg_url)->url_scheme &&
(leg->leg_url)->url_scheme[0] ? ":" : "", (leg->leg_url
)->url_root && ((leg->leg_url)->url_host || (
leg->leg_url)->url_user) ? "//" : "", (leg->leg_url)
->url_user ? (leg->leg_url)->url_user : "", (leg->
leg_url)->url_user && (leg->leg_url)->url_password
? ":" : "", (leg->leg_url)->url_user && (leg->
leg_url)->url_password ? (leg->leg_url)->url_password
: "", (leg->leg_url)->url_user && (leg->leg_url
)->url_host ? "@" : "", (leg->leg_url)->url_host ? (
leg->leg_url)->url_host : "", (leg->leg_url)->url_host
&& (leg->leg_url)->url_port ? ":" : "", (leg->
leg_url)->url_host && (leg->leg_url)->url_port
? (leg->leg_url)->url_port : "", (leg->leg_url)->
url_root && (leg->leg_url)->url_path ? "/" : ""
, (leg->leg_url)->url_path ? (leg->leg_url)->url_path
: "", (leg->leg_url)->url_params ? ";" : "", (leg->
leg_url)->url_params ? (leg->leg_url)->url_params : ""
, (leg->leg_url)->url_headers ? "?" : "", (leg->leg_url
)->url_headers ? (leg->leg_url)->url_headers : "", (
leg->leg_url)->url_fragment ? "#" : "", (leg->leg_url
)->url_fragment ? (leg->leg_url)->url_fragment : "")
) : (void)0)
1044 __func__, URL_PRINT_ARGS(leg->leg_url)))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 1044, "%s: destroying leg for <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
">\n", __func__, (leg->leg_url)->url_scheme ? (leg->
leg_url)->url_scheme : "", (leg->leg_url)->url_type !=
url_any && (leg->leg_url)->url_scheme &&
(leg->leg_url)->url_scheme[0] ? ":" : "", (leg->leg_url
)->url_root && ((leg->leg_url)->url_host || (
leg->leg_url)->url_user) ? "//" : "", (leg->leg_url)
->url_user ? (leg->leg_url)->url_user : "", (leg->
leg_url)->url_user && (leg->leg_url)->url_password
? ":" : "", (leg->leg_url)->url_user && (leg->
leg_url)->url_password ? (leg->leg_url)->url_password
: "", (leg->leg_url)->url_user && (leg->leg_url
)->url_host ? "@" : "", (leg->leg_url)->url_host ? (
leg->leg_url)->url_host : "", (leg->leg_url)->url_host
&& (leg->leg_url)->url_port ? ":" : "", (leg->
leg_url)->url_host && (leg->leg_url)->url_port
? (leg->leg_url)->url_port : "", (leg->leg_url)->
url_root && (leg->leg_url)->url_path ? "/" : ""
, (leg->leg_url)->url_path ? (leg->leg_url)->url_path
: "", (leg->leg_url)->url_params ? ";" : "", (leg->
leg_url)->url_params ? (leg->leg_url)->url_params : ""
, (leg->leg_url)->url_headers ? "?" : "", (leg->leg_url
)->url_headers ? (leg->leg_url)->url_headers : "", (
leg->leg_url)->url_fragment ? "#" : "", (leg->leg_url
)->url_fragment ? (leg->leg_url)->url_fragment : "")
) : (void)0)
;
1045 leg_free(agent, leg);
1046 }
1047 }
1048
1049 if (agent->sa_default_leg)
1050 leg_free(agent, agent->sa_default_leg);
1051
1052 for (i = iht->iht_size; i-- > 0; )
1053 while (iht->iht_table[i]) {
1054 nta_incoming_t *irq = iht->iht_table[i];
1055
1056 if (!irq->irq_destroyed)
1057 SU_DEBUG_3(("%s: destroying %s server transaction from <"(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 1060, "%s: destroying %s server transaction from <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
">\n", __func__, irq->irq_rq->rq_method_name, (irq->
irq_from->a_url)->url_scheme ? (irq->irq_from->a_url
)->url_scheme : "", (irq->irq_from->a_url)->url_type
!= url_any && (irq->irq_from->a_url)->url_scheme
&& (irq->irq_from->a_url)->url_scheme[0] ? ":"
: "", (irq->irq_from->a_url)->url_root && (
(irq->irq_from->a_url)->url_host || (irq->irq_from
->a_url)->url_user) ? "//" : "", (irq->irq_from->
a_url)->url_user ? (irq->irq_from->a_url)->url_user
: "", (irq->irq_from->a_url)->url_user && (
irq->irq_from->a_url)->url_password ? ":" : "", (irq
->irq_from->a_url)->url_user && (irq->irq_from
->a_url)->url_password ? (irq->irq_from->a_url)->
url_password : "", (irq->irq_from->a_url)->url_user &&
(irq->irq_from->a_url)->url_host ? "@" : "", (irq->
irq_from->a_url)->url_host ? (irq->irq_from->a_url
)->url_host : "", (irq->irq_from->a_url)->url_host
&& (irq->irq_from->a_url)->url_port ? ":" :
"", (irq->irq_from->a_url)->url_host && (irq
->irq_from->a_url)->url_port ? (irq->irq_from->
a_url)->url_port : "", (irq->irq_from->a_url)->url_root
&& (irq->irq_from->a_url)->url_path ? "/" :
"", (irq->irq_from->a_url)->url_path ? (irq->irq_from
->a_url)->url_path : "", (irq->irq_from->a_url)->
url_params ? ";" : "", (irq->irq_from->a_url)->url_params
? (irq->irq_from->a_url)->url_params : "", (irq->
irq_from->a_url)->url_headers ? "?" : "", (irq->irq_from
->a_url)->url_headers ? (irq->irq_from->a_url)->
url_headers : "", (irq->irq_from->a_url)->url_fragment
? "#" : "", (irq->irq_from->a_url)->url_fragment ? (
irq->irq_from->a_url)->url_fragment : "")) : (void)0
)
1058 URL_PRINT_FORMAT ">\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 1060, "%s: destroying %s server transaction from <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
">\n", __func__, irq->irq_rq->rq_method_name, (irq->
irq_from->a_url)->url_scheme ? (irq->irq_from->a_url
)->url_scheme : "", (irq->irq_from->a_url)->url_type
!= url_any && (irq->irq_from->a_url)->url_scheme
&& (irq->irq_from->a_url)->url_scheme[0] ? ":"
: "", (irq->irq_from->a_url)->url_root && (
(irq->irq_from->a_url)->url_host || (irq->irq_from
->a_url)->url_user) ? "//" : "", (irq->irq_from->
a_url)->url_user ? (irq->irq_from->a_url)->url_user
: "", (irq->irq_from->a_url)->url_user && (
irq->irq_from->a_url)->url_password ? ":" : "", (irq
->irq_from->a_url)->url_user && (irq->irq_from
->a_url)->url_password ? (irq->irq_from->a_url)->
url_password : "", (irq->irq_from->a_url)->url_user &&
(irq->irq_from->a_url)->url_host ? "@" : "", (irq->
irq_from->a_url)->url_host ? (irq->irq_from->a_url
)->url_host : "", (irq->irq_from->a_url)->url_host
&& (irq->irq_from->a_url)->url_port ? ":" :
"", (irq->irq_from->a_url)->url_host && (irq
->irq_from->a_url)->url_port ? (irq->irq_from->
a_url)->url_port : "", (irq->irq_from->a_url)->url_root
&& (irq->irq_from->a_url)->url_path ? "/" :
"", (irq->irq_from->a_url)->url_path ? (irq->irq_from
->a_url)->url_path : "", (irq->irq_from->a_url)->
url_params ? ";" : "", (irq->irq_from->a_url)->url_params
? (irq->irq_from->a_url)->url_params : "", (irq->
irq_from->a_url)->url_headers ? "?" : "", (irq->irq_from
->a_url)->url_headers ? (irq->irq_from->a_url)->
url_headers : "", (irq->irq_from->a_url)->url_fragment
? "#" : "", (irq->irq_from->a_url)->url_fragment ? (
irq->irq_from->a_url)->url_fragment : "")) : (void)0
)
1059 __func__, irq->irq_rq->rq_method_name,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 1060, "%s: destroying %s server transaction from <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
">\n", __func__, irq->irq_rq->rq_method_name, (irq->
irq_from->a_url)->url_scheme ? (irq->irq_from->a_url
)->url_scheme : "", (irq->irq_from->a_url)->url_type
!= url_any && (irq->irq_from->a_url)->url_scheme
&& (irq->irq_from->a_url)->url_scheme[0] ? ":"
: "", (irq->irq_from->a_url)->url_root && (
(irq->irq_from->a_url)->url_host || (irq->irq_from
->a_url)->url_user) ? "//" : "", (irq->irq_from->
a_url)->url_user ? (irq->irq_from->a_url)->url_user
: "", (irq->irq_from->a_url)->url_user && (
irq->irq_from->a_url)->url_password ? ":" : "", (irq
->irq_from->a_url)->url_user && (irq->irq_from
->a_url)->url_password ? (irq->irq_from->a_url)->
url_password : "", (irq->irq_from->a_url)->url_user &&
(irq->irq_from->a_url)->url_host ? "@" : "", (irq->
irq_from->a_url)->url_host ? (irq->irq_from->a_url
)->url_host : "", (irq->irq_from->a_url)->url_host
&& (irq->irq_from->a_url)->url_port ? ":" :
"", (irq->irq_from->a_url)->url_host && (irq
->irq_from->a_url)->url_port ? (irq->irq_from->
a_url)->url_port : "", (irq->irq_from->a_url)->url_root
&& (irq->irq_from->a_url)->url_path ? "/" :
"", (irq->irq_from->a_url)->url_path ? (irq->irq_from
->a_url)->url_path : "", (irq->irq_from->a_url)->
url_params ? ";" : "", (irq->irq_from->a_url)->url_params
? (irq->irq_from->a_url)->url_params : "", (irq->
irq_from->a_url)->url_headers ? "?" : "", (irq->irq_from
->a_url)->url_headers ? (irq->irq_from->a_url)->
url_headers : "", (irq->irq_from->a_url)->url_fragment
? "#" : "", (irq->irq_from->a_url)->url_fragment ? (
irq->irq_from->a_url)->url_fragment : "")) : (void)0
)
1060 URL_PRINT_ARGS(irq->irq_from->a_url)))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 1060, "%s: destroying %s server transaction from <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
">\n", __func__, irq->irq_rq->rq_method_name, (irq->
irq_from->a_url)->url_scheme ? (irq->irq_from->a_url
)->url_scheme : "", (irq->irq_from->a_url)->url_type
!= url_any && (irq->irq_from->a_url)->url_scheme
&& (irq->irq_from->a_url)->url_scheme[0] ? ":"
: "", (irq->irq_from->a_url)->url_root && (
(irq->irq_from->a_url)->url_host || (irq->irq_from
->a_url)->url_user) ? "//" : "", (irq->irq_from->
a_url)->url_user ? (irq->irq_from->a_url)->url_user
: "", (irq->irq_from->a_url)->url_user && (
irq->irq_from->a_url)->url_password ? ":" : "", (irq
->irq_from->a_url)->url_user && (irq->irq_from
->a_url)->url_password ? (irq->irq_from->a_url)->
url_password : "", (irq->irq_from->a_url)->url_user &&
(irq->irq_from->a_url)->url_host ? "@" : "", (irq->
irq_from->a_url)->url_host ? (irq->irq_from->a_url
)->url_host : "", (irq->irq_from->a_url)->url_host
&& (irq->irq_from->a_url)->url_port ? ":" :
"", (irq->irq_from->a_url)->url_host && (irq
->irq_from->a_url)->url_port ? (irq->irq_from->
a_url)->url_port : "", (irq->irq_from->a_url)->url_root
&& (irq->irq_from->a_url)->url_path ? "/" :
"", (irq->irq_from->a_url)->url_path ? (irq->irq_from
->a_url)->url_path : "", (irq->irq_from->a_url)->
url_params ? ";" : "", (irq->irq_from->a_url)->url_params
? (irq->irq_from->a_url)->url_params : "", (irq->
irq_from->a_url)->url_headers ? "?" : "", (irq->irq_from
->a_url)->url_headers ? (irq->irq_from->a_url)->
url_headers : "", (irq->irq_from->a_url)->url_fragment
? "#" : "", (irq->irq_from->a_url)->url_fragment ? (
irq->irq_from->a_url)->url_fragment : "")) : (void)0
)
;
1061
1062 incoming_free(irq);
1063 }
1064
1065 for (i = oht->oht_size; i-- > 0;)
1066 while (oht->oht_table[i]) {
1067 nta_outgoing_t *orq = oht->oht_table[i];
1068
1069 if (!orq->orq_destroyed)
1070 SU_DEBUG_3(("%s: destroying %s%s client transaction to <"(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 1075, "%s: destroying %s%s client transaction to <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
">\n", __func__, (orq->orq_forking || orq->orq_forks
) ? "forked " : "forking", orq->orq_method_name, (orq->
orq_to->a_url)->url_scheme ? (orq->orq_to->a_url)
->url_scheme : "", (orq->orq_to->a_url)->url_type
!= url_any && (orq->orq_to->a_url)->url_scheme
&& (orq->orq_to->a_url)->url_scheme[0] ? ":"
: "", (orq->orq_to->a_url)->url_root && ((orq
->orq_to->a_url)->url_host || (orq->orq_to->a_url
)->url_user) ? "//" : "", (orq->orq_to->a_url)->url_user
? (orq->orq_to->a_url)->url_user : "", (orq->orq_to
->a_url)->url_user && (orq->orq_to->a_url
)->url_password ? ":" : "", (orq->orq_to->a_url)->
url_user && (orq->orq_to->a_url)->url_password
? (orq->orq_to->a_url)->url_password : "", (orq->
orq_to->a_url)->url_user && (orq->orq_to->
a_url)->url_host ? "@" : "", (orq->orq_to->a_url)->
url_host ? (orq->orq_to->a_url)->url_host : "", (orq
->orq_to->a_url)->url_host && (orq->orq_to
->a_url)->url_port ? ":" : "", (orq->orq_to->a_url
)->url_host && (orq->orq_to->a_url)->url_port
? (orq->orq_to->a_url)->url_port : "", (orq->orq_to
->a_url)->url_root && (orq->orq_to->a_url
)->url_path ? "/" : "", (orq->orq_to->a_url)->url_path
? (orq->orq_to->a_url)->url_path : "", (orq->orq_to
->a_url)->url_params ? ";" : "", (orq->orq_to->a_url
)->url_params ? (orq->orq_to->a_url)->url_params :
"", (orq->orq_to->a_url)->url_headers ? "?" : "", (
orq->orq_to->a_url)->url_headers ? (orq->orq_to->
a_url)->url_headers : "", (orq->orq_to->a_url)->url_fragment
? "#" : "", (orq->orq_to->a_url)->url_fragment ? (orq
->orq_to->a_url)->url_fragment : "")) : (void)0)
1071 URL_PRINT_FORMAT ">\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 1075, "%s: destroying %s%s client transaction to <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
">\n", __func__, (orq->orq_forking || orq->orq_forks
) ? "forked " : "forking", orq->orq_method_name, (orq->
orq_to->a_url)->url_scheme ? (orq->orq_to->a_url)
->url_scheme : "", (orq->orq_to->a_url)->url_type
!= url_any && (orq->orq_to->a_url)->url_scheme
&& (orq->orq_to->a_url)->url_scheme[0] ? ":"
: "", (orq->orq_to->a_url)->url_root && ((orq
->orq_to->a_url)->url_host || (orq->orq_to->a_url
)->url_user) ? "//" : "", (orq->orq_to->a_url)->url_user
? (orq->orq_to->a_url)->url_user : "", (orq->orq_to
->a_url)->url_user && (orq->orq_to->a_url
)->url_password ? ":" : "", (orq->orq_to->a_url)->
url_user && (orq->orq_to->a_url)->url_password
? (orq->orq_to->a_url)->url_password : "", (orq->
orq_to->a_url)->url_user && (orq->orq_to->
a_url)->url_host ? "@" : "", (orq->orq_to->a_url)->
url_host ? (orq->orq_to->a_url)->url_host : "", (orq
->orq_to->a_url)->url_host && (orq->orq_to
->a_url)->url_port ? ":" : "", (orq->orq_to->a_url
)->url_host && (orq->orq_to->a_url)->url_port
? (orq->orq_to->a_url)->url_port : "", (orq->orq_to
->a_url)->url_root && (orq->orq_to->a_url
)->url_path ? "/" : "", (orq->orq_to->a_url)->url_path
? (orq->orq_to->a_url)->url_path : "", (orq->orq_to
->a_url)->url_params ? ";" : "", (orq->orq_to->a_url
)->url_params ? (orq->orq_to->a_url)->url_params :
"", (orq->orq_to->a_url)->url_headers ? "?" : "", (
orq->orq_to->a_url)->url_headers ? (orq->orq_to->
a_url)->url_headers : "", (orq->orq_to->a_url)->url_fragment
? "#" : "", (orq->orq_to->a_url)->url_fragment ? (orq
->orq_to->a_url)->url_fragment : "")) : (void)0)
1072 __func__,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 1075, "%s: destroying %s%s client transaction to <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
">\n", __func__, (orq->orq_forking || orq->orq_forks
) ? "forked " : "forking", orq->orq_method_name, (orq->
orq_to->a_url)->url_scheme ? (orq->orq_to->a_url)
->url_scheme : "", (orq->orq_to->a_url)->url_type
!= url_any && (orq->orq_to->a_url)->url_scheme
&& (orq->orq_to->a_url)->url_scheme[0] ? ":"
: "", (orq->orq_to->a_url)->url_root && ((orq
->orq_to->a_url)->url_host || (orq->orq_to->a_url
)->url_user) ? "//" : "", (orq->orq_to->a_url)->url_user
? (orq->orq_to->a_url)->url_user : "", (orq->orq_to
->a_url)->url_user && (orq->orq_to->a_url
)->url_password ? ":" : "", (orq->orq_to->a_url)->
url_user && (orq->orq_to->a_url)->url_password
? (orq->orq_to->a_url)->url_password : "", (orq->
orq_to->a_url)->url_user && (orq->orq_to->
a_url)->url_host ? "@" : "", (orq->orq_to->a_url)->
url_host ? (orq->orq_to->a_url)->url_host : "", (orq
->orq_to->a_url)->url_host && (orq->orq_to
->a_url)->url_port ? ":" : "", (orq->orq_to->a_url
)->url_host && (orq->orq_to->a_url)->url_port
? (orq->orq_to->a_url)->url_port : "", (orq->orq_to
->a_url)->url_root && (orq->orq_to->a_url
)->url_path ? "/" : "", (orq->orq_to->a_url)->url_path
? (orq->orq_to->a_url)->url_path : "", (orq->orq_to
->a_url)->url_params ? ";" : "", (orq->orq_to->a_url
)->url_params ? (orq->orq_to->a_url)->url_params :
"", (orq->orq_to->a_url)->url_headers ? "?" : "", (
orq->orq_to->a_url)->url_headers ? (orq->orq_to->
a_url)->url_headers : "", (orq->orq_to->a_url)->url_fragment
? "#" : "", (orq->orq_to->a_url)->url_fragment ? (orq
->orq_to->a_url)->url_fragment : "")) : (void)0)
1073 (orq->orq_forking || orq->orq_forks) ? "forked " : "forking",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 1075, "%s: destroying %s%s client transaction to <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
">\n", __func__, (orq->orq_forking || orq->orq_forks
) ? "forked " : "forking", orq->orq_method_name, (orq->
orq_to->a_url)->url_scheme ? (orq->orq_to->a_url)
->url_scheme : "", (orq->orq_to->a_url)->url_type
!= url_any && (orq->orq_to->a_url)->url_scheme
&& (orq->orq_to->a_url)->url_scheme[0] ? ":"
: "", (orq->orq_to->a_url)->url_root && ((orq
->orq_to->a_url)->url_host || (orq->orq_to->a_url
)->url_user) ? "//" : "", (orq->orq_to->a_url)->url_user
? (orq->orq_to->a_url)->url_user : "", (orq->orq_to
->a_url)->url_user && (orq->orq_to->a_url
)->url_password ? ":" : "", (orq->orq_to->a_url)->
url_user && (orq->orq_to->a_url)->url_password
? (orq->orq_to->a_url)->url_password : "", (orq->
orq_to->a_url)->url_user && (orq->orq_to->
a_url)->url_host ? "@" : "", (orq->orq_to->a_url)->
url_host ? (orq->orq_to->a_url)->url_host : "", (orq
->orq_to->a_url)->url_host && (orq->orq_to
->a_url)->url_port ? ":" : "", (orq->orq_to->a_url
)->url_host && (orq->orq_to->a_url)->url_port
? (orq->orq_to->a_url)->url_port : "", (orq->orq_to
->a_url)->url_root && (orq->orq_to->a_url
)->url_path ? "/" : "", (orq->orq_to->a_url)->url_path
? (orq->orq_to->a_url)->url_path : "", (orq->orq_to
->a_url)->url_params ? ";" : "", (orq->orq_to->a_url
)->url_params ? (orq->orq_to->a_url)->url_params :
"", (orq->orq_to->a_url)->url_headers ? "?" : "", (
orq->orq_to->a_url)->url_headers ? (orq->orq_to->
a_url)->url_headers : "", (orq->orq_to->a_url)->url_fragment
? "#" : "", (orq->orq_to->a_url)->url_fragment ? (orq
->orq_to->a_url)->url_fragment : "")) : (void)0)
1074 orq->orq_method_name,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 1075, "%s: destroying %s%s client transaction to <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
">\n", __func__, (orq->orq_forking || orq->orq_forks
) ? "forked " : "forking", orq->orq_method_name, (orq->
orq_to->a_url)->url_scheme ? (orq->orq_to->a_url)
->url_scheme : "", (orq->orq_to->a_url)->url_type
!= url_any && (orq->orq_to->a_url)->url_scheme
&& (orq->orq_to->a_url)->url_scheme[0] ? ":"
: "", (orq->orq_to->a_url)->url_root && ((orq
->orq_to->a_url)->url_host || (orq->orq_to->a_url
)->url_user) ? "//" : "", (orq->orq_to->a_url)->url_user
? (orq->orq_to->a_url)->url_user : "", (orq->orq_to
->a_url)->url_user && (orq->orq_to->a_url
)->url_password ? ":" : "", (orq->orq_to->a_url)->
url_user && (orq->orq_to->a_url)->url_password
? (orq->orq_to->a_url)->url_password : "", (orq->
orq_to->a_url)->url_user && (orq->orq_to->
a_url)->url_host ? "@" : "", (orq->orq_to->a_url)->
url_host ? (orq->orq_to->a_url)->url_host : "", (orq
->orq_to->a_url)->url_host && (orq->orq_to
->a_url)->url_port ? ":" : "", (orq->orq_to->a_url
)->url_host && (orq->orq_to->a_url)->url_port
? (orq->orq_to->a_url)->url_port : "", (orq->orq_to
->a_url)->url_root && (orq->orq_to->a_url
)->url_path ? "/" : "", (orq->orq_to->a_url)->url_path
? (orq->orq_to->a_url)->url_path : "", (orq->orq_to
->a_url)->url_params ? ";" : "", (orq->orq_to->a_url
)->url_params ? (orq->orq_to->a_url)->url_params :
"", (orq->orq_to->a_url)->url_headers ? "?" : "", (
orq->orq_to->a_url)->url_headers ? (orq->orq_to->
a_url)->url_headers : "", (orq->orq_to->a_url)->url_fragment
? "#" : "", (orq->orq_to->a_url)->url_fragment ? (orq
->orq_to->a_url)->url_fragment : "")) : (void)0)
1075 URL_PRINT_ARGS(orq->orq_to->a_url)))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 1075, "%s: destroying %s%s client transaction to <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
">\n", __func__, (orq->orq_forking || orq->orq_forks
) ? "forked " : "forking", orq->orq_method_name, (orq->
orq_to->a_url)->url_scheme ? (orq->orq_to->a_url)
->url_scheme : "", (orq->orq_to->a_url)->url_type
!= url_any && (orq->orq_to->a_url)->url_scheme
&& (orq->orq_to->a_url)->url_scheme[0] ? ":"
: "", (orq->orq_to->a_url)->url_root && ((orq
->orq_to->a_url)->url_host || (orq->orq_to->a_url
)->url_user) ? "//" : "", (orq->orq_to->a_url)->url_user
? (orq->orq_to->a_url)->url_user : "", (orq->orq_to
->a_url)->url_user && (orq->orq_to->a_url
)->url_password ? ":" : "", (orq->orq_to->a_url)->
url_user && (orq->orq_to->a_url)->url_password
? (orq->orq_to->a_url)->url_password : "", (orq->
orq_to->a_url)->url_user && (orq->orq_to->
a_url)->url_host ? "@" : "", (orq->orq_to->a_url)->
url_host ? (orq->orq_to->a_url)->url_host : "", (orq
->orq_to->a_url)->url_host && (orq->orq_to
->a_url)->url_port ? ":" : "", (orq->orq_to->a_url
)->url_host && (orq->orq_to->a_url)->url_port
? (orq->orq_to->a_url)->url_port : "", (orq->orq_to
->a_url)->url_root && (orq->orq_to->a_url
)->url_path ? "/" : "", (orq->orq_to->a_url)->url_path
? (orq->orq_to->a_url)->url_path : "", (orq->orq_to
->a_url)->url_params ? ";" : "", (orq->orq_to->a_url
)->url_params ? (orq->orq_to->a_url)->url_params :
"", (orq->orq_to->a_url)->url_headers ? "?" : "", (
orq->orq_to->a_url)->url_headers ? (orq->orq_to->
a_url)->url_headers : "", (orq->orq_to->a_url)->url_fragment
? "#" : "", (orq->orq_to->a_url)->url_fragment ? (orq
->orq_to->a_url)->url_fragment : "")) : (void)0)
;
1076
1077 orq->orq_forks = NULL((void*)0), orq->orq_forking = NULL((void*)0);
1078 outgoing_free(orq);
1079 }
1080
1081 su_timer_destroy(agent->sa_timer), agent->sa_timer = NULL((void*)0);
1082
1083# if HAVE_SOFIA_SRESOLV1
1084 sres_resolver_destroy(agent->sa_resolver), agent->sa_resolver = NULL((void*)0);
1085# endif
1086
1087 tport_destroy(agent->sa_tports), agent->sa_tports = NULL((void*)0);
1088
1089 agent_kill_terminator(agent);
1090
1091 su_home_unref(agent->sa_home);
1092 }
1093}
1094
1095/** Return agent context. */
1096nta_agent_magic_t *nta_agent_magic(nta_agent_t const *agent)
1097{
1098 return agent ? agent->sa_magic : NULL((void*)0);
1099}
1100
1101/** Return @Contact header.
1102 *
1103 * Get a @Contact header, which can be used to reach @a agent.
1104 *
1105 * @param agent NTA agent object
1106 *
1107 * User agents can insert the @Contact header in the outgoing REGISTER,
1108 * INVITE, and ACK requests and replies to incoming INVITE and OPTIONS
1109 * transactions.
1110 *
1111 * Proxies can use the @Contact header to create appropriate @RecordRoute
1112 * headers:
1113 * @code
1114 * r_r = sip_record_route_create(msg_home(msg),
1115 * sip->sip_request->rq_url,
1116 * contact->m_url);
1117 * @endcode
1118 *
1119 * @return A sip_contact_t object corresponding to the @a agent.
1120 */
1121sip_contact_t *nta_agent_contact(nta_agent_t const *agent)
1122{
1123 return agent ? agent->sa_contact : NULL((void*)0);
1124}
1125
1126/** Return a list of @Via headers.
1127 *
1128 * Get @Via headers for all activated transport.
1129 *
1130 * @param agent NTA agent object
1131 *
1132 * @return A list of #sip_via_t objects used by the @a agent.
1133 */
1134sip_via_t *nta_agent_via(nta_agent_t const *agent)
1135{
1136 return agent ? agent->sa_vias : NULL((void*)0);
1137}
1138
1139/** Return a list of public (UPnP, STUN) @Via headers.
1140 *
1141 * Get public @Via headers for all activated transports.
1142 *
1143 * @param agent NTA agent object
1144 *
1145 * @return A list of #sip_via_t objects used by the @a agent.
1146 */
1147sip_via_t *nta_agent_public_via(nta_agent_t const *agent)
1148{
1149 return agent ? agent->sa_public_vias : NULL((void*)0);
1150}
1151
1152/** Match a @Via header @a v with @Via headers in @a agent.
1153 *
1154 */
1155static
1156sip_via_t *agent_has_via(nta_agent_t const *agent, sip_via_t const *via)
1157{
1158 sip_via_t const *v;
1159
1160 for (v = agent->sa_public_vias; v; v = v->v_next) {
1161 if (!su_casematch(via->v_host, v->v_host))
1162 continue;
1163 if (!su_strmatch(via->v_port, v->v_port))
1164 continue;
1165 if (!su_casematch(via->v_protocol, v->v_protocol))
1166 continue;
1167 return (sip_via_t *)v;
1168 }
1169
1170 for (v = agent->sa_vias; v; v = v->v_next) {
1171 if (!su_casematch(via->v_host, v->v_host))
1172 continue;
1173 if (!su_strmatch(via->v_port, v->v_port))
1174 continue;
1175 if (!su_casematch(via->v_protocol, v->v_protocol))
1176 continue;
1177 return (sip_via_t *)v;
1178 }
1179
1180 return NULL((void*)0);
1181}
1182
1183/** Return @UserAgent header.
1184 *
1185 * Get @UserAgent information with NTA version.
1186 *
1187 * @param agent NTA agent object (may be NULL)
1188 *
1189 * @return A string containing the @a agent version.
1190 */
1191char const *nta_agent_version(nta_agent_t const *agent)
1192{
1193 return "nta" "/" VERSION"1.13.5";
1194}
1195
1196/** Initialize default tag */
1197static int agent_tag_init(nta_agent_t *self)
1198{
1199 sip_contact_t *m = self->sa_contact;
1200 uint32_t hash = su_random();
1201
1202 if (m) {
1203 if (m->m_url->url_user)
1204 hash = 914715421U * hash + msg_hash_string(m->m_url->url_user);
1205 if (m->m_url->url_host)
1206 hash = 914715421U * hash + msg_hash_string(m->m_url->url_host);
1207 if (m->m_url->url_port)
1208 hash = 914715421U * hash + msg_hash_string(m->m_url->url_port);
1209 if (m->m_url->url_params)
1210 hash = 914715421U * hash + msg_hash_string(m->m_url->url_params);
1211 }
1212
1213 if (hash == 0)
1214 hash = 914715421U;
1215
1216 self->sa_branch = NTA_BRANCH_PRIME(uint64_t)(0xB9591D1C361C6521ULL) * (uint64_t)su_nanotime(NULL((void*)0));
1217 self->sa_branch *= hash;
1218
1219 self->sa_tags = NTA_TAG_PRIME(uint64_t)(0xB9591D1C361C6521ULL) * self->sa_branch;
1220
1221 return 0;
1222}
1223
1224/** Initialize agent timer. */
1225static
1226int agent_timer_init(nta_agent_t *agent)
1227{
1228 agent->sa_timer = su_timer_create(su_root_task(agent->sa_root),
1229 NTA_SIP_T1 / 8);
1230#if 0
1231 return su_timer_set(agent->sa_timer,
1232 agent_timer,
1233 agent);
1234#endif
1235 return -(agent->sa_timer == NULL((void*)0));
1236}
1237
1238/**
1239 * Agent timer routine.
1240 */
1241static
1242void agent_timer(su_root_magic_t *rm, su_timer_t *timer, nta_agent_t *agent)
1243{
1244 su_time_t stamp = su_now();
1245 uint32_t now = su_time_ms(stamp), next, latest;
1246
1247 now += now == 0;
1248
1249 agent->sa_next = 0;
1250
1251 agent->sa_in_timer = 1;
1252
1253
1254 _nta_outgoing_timer(agent);
1255 _nta_incoming_timer(agent);
1256
1257 agent->sa_in_timer = 0;
1258
1259 /* Calculate next timeout */
1260 next = latest = now + NTA_TIME_MAX + 1;
1261
1262#define NEXT_TIMEOUT(next, p, f, now) \
1263 (void)(p && (int32_t)(p->f - (next)) < 0 && \
1264 ((next) = ((int32_t)(p->f - (now)) > 0 ? p->f : (now))))
1265
1266 NEXT_TIMEOUT(next, agent->sa_out.re_list, orq_retry, now);
1267 NEXT_TIMEOUT(next, agent->sa_out.inv_completed->q_head, orq_timeout, now);
1268 NEXT_TIMEOUT(next, agent->sa_out.completed->q_head, orq_timeout, now);
1269 NEXT_TIMEOUT(next, agent->sa_out.inv_calling->q_head, orq_timeout, now);
1270 if (agent->sa_out.inv_proceeding->q_timeout)
1271 NEXT_TIMEOUT(next, agent->sa_out.inv_proceeding->q_head, orq_timeout, now);
1272 NEXT_TIMEOUT(next, agent->sa_out.trying->q_head, orq_timeout, now);
1273
1274 NEXT_TIMEOUT(next, agent->sa_in.preliminary->q_head, irq_timeout, now);
1275 NEXT_TIMEOUT(next, agent->sa_in.inv_completed->q_head, irq_timeout, now);
1276 NEXT_TIMEOUT(next, agent->sa_in.inv_confirmed->q_head, irq_timeout, now);
1277 NEXT_TIMEOUT(next, agent->sa_in.completed->q_head, irq_timeout, now);
1278 NEXT_TIMEOUT(next, agent->sa_in.re_list, irq_retry, now);
1279
1280 if (agent->sa_next)
1281 NEXT_TIMEOUT(next, agent, sa_next, now);
1282
1283#undef NEXT_TIMEOUT
1284
1285 if (next == latest) {
1286 /* Do not set timer? */
1287 /* check it there are still things queued, if there are, that means everything scheduled is > 15 days in the future */
1288 /* in this case, we had a large time shift, we should schedule for 15 days in the future (which is probably still before now) */
1289 /* and this should sort itself out on the next run through */
1290 if ( !agent->sa_out.completed->q_head && !agent->sa_out.trying->q_head && !agent->sa_out.inv_calling->q_head &&
1291 !agent->sa_out.re_list && !agent->sa_in.inv_confirmed->q_head && !agent->sa_in.preliminary->q_head &&
1292 !agent->sa_in.completed->q_head && !agent->sa_in.inv_completed->q_head && !agent->sa_in.re_list ) {
1293 SU_DEBUG_9(("nta: timer not set\n" VA_NONE))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__
, 1293, "nta: timer not set\n" "%s", "")) : (void)0)
;
1294 return;
1295 }
1296 }
1297
1298 if (next == now) if (++next == 0) ++next;
1299
1300 SU_DEBUG_9(("nta: timer %s to %ld ms\n", "set next", (long)(next - now)))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__
, 1300, "nta: timer %s to %ld ms\n", "set next", (long)(next -
now))) : (void)0)
;
1301
1302 agent->sa_next = next;
1303
1304 su_timer_set_at(timer, agent_timer, agent, su_time_add(stamp, next - now));
1305}
1306
1307/** Add uin32_t milliseconds to the time. */
1308static su_time_t add_milliseconds(su_time_t t0, uint32_t ms)
1309{
1310 unsigned long sec = ms / 1000, usec = (ms % 1000) * 1000;
1311
1312 t0.tv_usec += usec;
1313 t0.tv_sec += sec;
1314
1315 if (t0.tv_usec >= 1000000) {
1316 t0.tv_sec += 1;
1317 t0.tv_usec -= 1000000;
1318 }
1319
1320 return t0;
1321}
1322
1323/** Calculate nonzero value for timeout.
1324 *
1325 * Sets or adjusts agent timer when needed.
1326 *
1327 * @retval 0 if offset is 0
1328 * @retval timeout (millisecond counter) otherwise
1329 */
1330static
1331uint32_t set_timeout(nta_agent_t *agent, uint32_t offset)
1332{
1333 su_time_t now;
1334 uint32_t next, ms;
1335
1336 if (offset == 0)
1337 return 0;
1338
1339 now = su_now();
1340 ms = su_time_ms(now);
1341
1342 next = ms + offset;
1343
1344 if (next == 0) next = 1;
1345
1346 if (agent->sa_in_timer) /* Currently executing timer */
1347 return next;
1348
1349 if (agent->sa_next == 0 || (int32_t)(agent->sa_next - next - 5L) > 0) {
1350 /* Set timer */
1351 if (agent->sa_next)
1352 SU_DEBUG_9(("nta: timer %s to %ld ms\n", "shortened", (long)offset))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__
, 1352, "nta: timer %s to %ld ms\n", "shortened", (long)offset
)) : (void)0)
;
1353 else
1354 SU_DEBUG_9(("nta: timer %s to %ld ms\n", "set", (long)offset))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__
, 1354, "nta: timer %s to %ld ms\n", "set", (long)offset)) : (
void)0)
;
1355
1356 su_timer_set_at(agent->sa_timer, agent_timer, agent,
1357 add_milliseconds(now, offset));
1358 agent->sa_next = next;
1359 }
1360
1361 return next;
1362}
1363
1364
1365/** Return current timeval. */
1366static
1367su_time_t agent_now(nta_agent_t const *agent)
1368{
1369 return su_now();
1370}
1371
1372
1373/** Launch transaction terminator task */
1374static
1375int agent_launch_terminator(nta_agent_t *agent)
1376{
1377#ifdef TPTAG_THRPSIZE
1378 if (agent->sa_tport_threadpool) {
1379 su_home_threadsafe(agent->sa_home);
1380 return su_clone_start(agent->sa_root,
1381 agent->sa_terminator,
1382 NULL((void*)0),
1383 NULL((void*)0),
1384 NULL((void*)0));
1385 }
1386#endif
1387 return -1;
1388}
1389
1390/** Kill transaction terminator task */
1391static
1392void agent_kill_terminator(nta_agent_t *agent)
1393{
1394 su_clone_wait(agent->sa_root, agent->sa_terminator);
1395}
1396
1397
1398/**Set NTA Parameters.
1399 *
1400 * The nta_agent_set_params() function sets the stack parameters. The
1401 * parameters determine the way NTA handles the retransmissions, how long
1402 * NTA keeps transactions alive, does NTA apply proxy or user-agent logic to
1403 * INVITE transactions, or how the @Via headers are generated.
1404 *
1405 * @note
1406 * Setting the parameters NTATAG_MAXSIZE(), NTATAG_UDP_MTU(), NTATAG_MAX_PROCEEDING(),
1407 * NTATAG_SIP_T1X64(), NTATAG_SIP_T1(), NTATAG_SIP_T2(), NTATAG_SIP_T4() to
1408 * 0 selects the default value.
1409 *
1410 * @TAGS
1411 * NTATAG_ALIASES(),
1412 * NTATAG_BAD_REQ_MASK(), NTATAG_BAD_RESP_MASK(), NTATAG_BLACKLIST(),
1413 * NTATAG_CANCEL_2543(), NTATAG_CANCEL_487(), NTATAG_CLIENT_RPORT(),
1414 * NTATAG_DEBUG_DROP_PROB(), NTATAG_DEFAULT_PROXY(),
1415 * NTATAG_EXTRA_100(), NTATAG_GRAYLIST(),
1416 * NTATAG_MAXSIZE(), NTATAG_MAX_FORWARDS(), NTATAG_MERGE_482(), NTATAG_MCLASS()
1417 * NTATAG_PASS_100(), NTATAG_PASS_408(), NTATAG_PRELOAD(), NTATAG_PROGRESS(),
1418 * NTATAG_REL100(),
1419 * NTATAG_SERVER_RPORT(),
1420 * NTATAG_SIPFLAGS(),
1421 * NTATAG_SIP_T1X64(), NTATAG_SIP_T1(), NTATAG_SIP_T2(), NTATAG_SIP_T4(),
1422 * NTATAG_STATELESS(),
1423 * NTATAG_TAG_3261(), NTATAG_TCP_RPORT(), NTATAG_TIMEOUT_408(),
1424 * NTATAG_TLS_RPORT(), NTATAG_TLS_ORQ_CONNECT_TIMEOUT(),
1425 * NTATAG_TIMER_C(), NTATAG_MAX_PROCEEDING(),
1426 * NTATAG_UA(), NTATAG_UDP_MTU(), NTATAG_USER_VIA(),
1427 * NTATAG_USE_NAPTR(), NTATAG_USE_SRV() and NTATAG_USE_TIMESTAMP().
1428 *
1429 * @note The value from following tags are stored, but they currently do nothing:
1430 * NTATAG_SIGCOMP_ALGORITHM(), NTATAG_SIGCOMP_OPTIONS(), NTATAG_SMIME()
1431 */
1432int nta_agent_set_params(nta_agent_t *agent,
1433 tag_type_t tag, tag_value_t value, ...)
1434{
1435 int retval;
1436
1437 if (agent) {
1438 ta_list ta;
1439 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)
;
1440 retval = agent_set_params(agent, ta_args(ta)(ta).tl);
1441 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))
;
1442 } else {
1443 su_seterrno(EINVAL22);
1444 retval = -1;
1445 }
1446
1447 return retval;
1448}
1449
1450/** Internal function for setting tags */
1451static
1452int agent_set_params(nta_agent_t *agent, tagi_t *tags)
1453{
1454 int n, nC, m;
1455 unsigned bad_req_mask = agent->sa_bad_req_mask;
1456 unsigned bad_resp_mask = agent->sa_bad_resp_mask;
1457 usize_t maxsize = agent->sa_maxsize;
1458 usize_t max_proceeding = agent->sa_max_proceeding;
1459 unsigned max_forwards = agent->sa_max_forwards->mf_count;
1460 unsigned udp_mtu = agent->sa_udp_mtu;
1461 unsigned sip_t1 = agent->sa_t1;
1462 unsigned sip_t2 = agent->sa_t2;
1463 unsigned sip_t4 = agent->sa_t4;
1464 unsigned sip_t1x64 = agent->sa_t1x64;
1465 unsigned tls_orq_connect_timeout = agent->sa_tls_orq_connect_timeout;
1466 unsigned timer_c = agent->sa_timer_c;
1467 unsigned timer_d = 32000;
1468 unsigned graylist = agent->sa_graylist;
1469 unsigned blacklist = agent->sa_blacklist;
1470 int ua = agent->sa_is_a_uas;
1471 unsigned progress = agent->sa_progress;
1472 int stateless = agent->sa_is_stateless;
1473 unsigned drop_prob = agent->sa_drop_prob;
1474 int user_via = agent->sa_user_via;
1475 int extra_100 = agent->sa_extra_100;
1476 int pass_100 = agent->sa_pass_100;
1477 int timeout_408 = agent->sa_timeout_408;
1478 int pass_408 = agent->sa_pass_408;
1479 int merge_482 = agent->sa_merge_482;
1480 int cancel_2543 = agent->sa_cancel_2543;
1481 int cancel_487 = agent->sa_cancel_487;
1482 int invite_100rel = agent->sa_invite_100rel;
1483 int use_timestamp = agent->sa_timestamp;
1484 int use_naptr = agent->sa_use_naptr;
1485 int use_srv = agent->sa_use_srv;
1486 int srv_503 = agent->sa_srv_503;
1487 void *smime = agent->sa_smime;
1488 uint32_t flags = agent->sa_flags;
1489 int rport = agent->sa_rport;
1490 int server_rport = agent->sa_server_rport;
1491 int tcp_rport = agent->sa_tcp_rport;
1492 int tls_rport = agent->sa_tls_rport;
1493 unsigned preload = agent->sa_preload;
1494 unsigned threadpool = agent->sa_tport_threadpool;
1495 char const *sigcomp = agent->sa_sigcomp_options;
1496 char const *algorithm = NONE((void *)-1);
1497 msg_mclass_t const *mclass = NONE((void *)-1);
1498 sip_contact_t const *aliases = NONE((void *)-1);
1499 url_string_t const *proxy = NONE((void *)-1);
1500 tport_t *tport;
1501
1502 su_home_t *home = agent->sa_home;
1503
1504 n = tl_gets(tags,
1505 NTATAG_ALIASES_REF(aliases)ntatag_aliases_ref, siptag_contact_vr(&(aliases)),
1506 NTATAG_BAD_REQ_MASK_REF(bad_req_mask)ntatag_bad_req_mask_ref, tag_uint_vr(&(bad_req_mask)),
1507 NTATAG_BAD_RESP_MASK_REF(bad_resp_mask)ntatag_bad_resp_mask_ref, tag_uint_vr(&(bad_resp_mask)),
1508 NTATAG_BLACKLIST_REF(blacklist)ntatag_blacklist_ref, tag_uint_vr(&(blacklist)),
1509 NTATAG_CANCEL_2543_REF(cancel_2543)ntatag_cancel_2543_ref, tag_bool_vr(&(cancel_2543)),
1510 NTATAG_CANCEL_487_REF(cancel_487)ntatag_cancel_487_ref, tag_bool_vr(&(cancel_487)),
1511 NTATAG_DEBUG_DROP_PROB_REF(drop_prob)ntatag_debug_drop_prob_ref, tag_uint_vr(&(drop_prob)),
1512 NTATAG_DEFAULT_PROXY_REF(proxy)ntatag_default_proxy_ref, urltag_url_vr(&(proxy)),
1513 NTATAG_EXTRA_100_REF(extra_100)ntatag_extra_100_ref, tag_bool_vr(&(extra_100)),
1514 NTATAG_GRAYLIST_REF(graylist)ntatag_graylist_ref, tag_uint_vr(&(graylist)),
1515 NTATAG_MAXSIZE_REF(maxsize)ntatag_maxsize_ref, tag_usize_vr(&(maxsize)),
1516 NTATAG_MAX_PROCEEDING_REF(max_proceeding)ntatag_max_proceeding_ref, tag_usize_vr(&(max_proceeding)
)
,
1517 NTATAG_MAX_FORWARDS_REF(max_forwards)ntatag_max_forwards_ref, tag_uint_vr(&(max_forwards)),
1518 NTATAG_MCLASS_REF(mclass)ntatag_mclass_ref, tag_cptr_vr(&(mclass), (mclass)),
1519 NTATAG_MERGE_482_REF(merge_482)ntatag_merge_482_ref, tag_bool_vr(&(merge_482)),
1520 NTATAG_PASS_100_REF(pass_100)ntatag_pass_100_ref, tag_bool_vr(&(pass_100)),
1521 NTATAG_PASS_408_REF(pass_408)ntatag_pass_408_ref, tag_bool_vr(&(pass_408)),
1522 NTATAG_PRELOAD_REF(preload)ntatag_preload_ref, tag_uint_vr(&(preload)),
1523 NTATAG_PROGRESS_REF(progress)ntatag_progress_ref, tag_uint_vr(&(progress)),
1524 NTATAG_REL100_REF(invite_100rel)ntatag_rel100_ref, tag_bool_vr(&(invite_100rel)),
1525 NTATAG_RPORT_REF(rport)ntatag_client_rport_ref, tag_bool_vr(&(rport)),
1526 NTATAG_SERVER_RPORT_REF(server_rport)ntatag_server_rport_ref, tag_int_vr(&(server_rport)),
1527 NTATAG_SIGCOMP_ALGORITHM_REF(algorithm)ntatag_sigcomp_algorithm_ref, tag_str_vr(&(algorithm)),
1528 NTATAG_SIGCOMP_OPTIONS_REF(sigcomp)ntatag_sigcomp_options_ref, tag_str_vr(&(sigcomp)),
1529 NTATAG_SIPFLAGS_REF(flags)ntatag_sipflags_ref, tag_uint_vr(&(flags)),
1530 NTATAG_SIP_T1X64_REF(sip_t1x64)ntatag_sip_t1x64_ref, tag_uint_vr(&(sip_t1x64)),
1531 NTATAG_SIP_T1_REF(sip_t1)ntatag_sip_t1_ref, tag_uint_vr(&(sip_t1)),
1532 NTATAG_SIP_T2_REF(sip_t2)ntatag_sip_t2_ref, tag_uint_vr(&(sip_t2)),
1533 NTATAG_SIP_T4_REF(sip_t4)ntatag_sip_t4_ref, tag_uint_vr(&(sip_t4)),
1534#if HAVE_SOFIA_SMIME0
1535 NTATAG_SMIME_REF(smime)ntatag_smime_ref, tag_ptr_vr(&(smime), (smime)),
1536#endif
1537 NTATAG_STATELESS_REF(stateless)ntatag_stateless_ref, tag_bool_vr(&(stateless)),
1538 NTATAG_TCP_RPORT_REF(tcp_rport)ntatag_tcp_rport_ref, tag_bool_vr(&(tcp_rport)),
1539 NTATAG_TLS_RPORT_REF(tls_rport)ntatag_tls_rport_ref, tag_bool_vr(&(tls_rport)),
1540 NTATAG_TLS_ORQ_CONNECT_TIMEOUT_REF(tls_orq_connect_timeout)ntatag_tls_orq_connect_timeout_ref, tag_uint_vr(&(tls_orq_connect_timeout
))
,
1541 NTATAG_TIMEOUT_408_REF(timeout_408)ntatag_timeout_408_ref, tag_bool_vr(&(timeout_408)),
1542 NTATAG_UA_REF(ua)ntatag_ua_ref, tag_bool_vr(&(ua)),
1543 NTATAG_UDP_MTU_REF(udp_mtu)ntatag_udp_mtu_ref, tag_uint_vr(&(udp_mtu)),
1544 NTATAG_USER_VIA_REF(user_via)ntatag_user_via_ref, tag_bool_vr(&(user_via)),
1545 NTATAG_USE_NAPTR_REF(use_naptr)ntatag_use_naptr_ref, tag_bool_vr(&(use_naptr)),
1546 NTATAG_USE_SRV_REF(use_srv)ntatag_use_srv_ref, tag_bool_vr(&(use_srv)),
1547 NTATAG_USE_TIMESTAMP_REF(use_timestamp)ntatag_use_timestamp_ref, tag_bool_vr(&(use_timestamp)),
1548#ifdef TPTAG_THRPSIZE
1549 /* If threadpool is enabled, start a separate "reaper thread" */
1550 TPTAG_THRPSIZE_REF(threadpool)tptag_thrpsize_ref, tag_uint_vr(&(threadpool)),
1551#endif
1552 NTATAG_SRV_503_REF(srv_503)ntatag_srv_503_ref, tag_bool_vr(&(srv_503)),
1553 TAG_END()(tag_type_t)0, (tag_value_t)0);
1554 nC = tl_gets(tags,
1555 NTATAG_TIMER_C_REF(timer_c)ntatag_timer_c_ref, tag_uint_vr(&(timer_c)),
1556 TAG_END()(tag_type_t)0, (tag_value_t)0);
1557 n += nC;
1558
1559 if (mclass != NONE((void *)-1))
1560 agent->sa_mclass = mclass ? mclass : sip_default_mclass();
1561
1562 m = 0;
1563 for (tport = agent->sa_tports; tport; tport = tport_next(tport)) {
1564 int m0 = tport_set_params(tport, TAG_NEXT(tags)tag_next, (tag_value_t)(tags));
1565 if (m0 < 0)
1566 return m0;
1567 if (m0 > m)
1568 m = m0;
1569 }
1570
1571 n += m;
1572
1573 if (aliases != NONE((void *)-1)) {
1574 sip_contact_t const *m, *m_next;
1575
1576 m = agent->sa_aliases;
1577 agent->sa_aliases = sip_contact_dup(home, aliases);
1578
1579 for (; m; m = m_next) { /* Free old aliases */
1580 m_next = m->m_next;
1581 su_free(home, (void *)m);
1582 }
1583 }
1584
1585 if (proxy != NONE((void *)-1)) {
1586 url_t *dp = url_hdup(home, proxy->us_url);
1587
1588 url_sanitize(dp);
1589
1590 if (dp == NULL((void*)0) || dp->url_type == url_sip || dp->url_type == url_sips || dp->url_type == url_urn) {
1591 if (agent->sa_default_proxy)
1592 su_free(home, agent->sa_default_proxy);
1593 agent->sa_default_proxy = dp;
1594 }
1595 else
1596 n = -1;
1597 }
1598
1599 if (algorithm != NONE((void *)-1))
1600 agent->sa_algorithm = su_strdup(home, algorithm);
1601
1602 if (!su_strmatch(sigcomp, agent->sa_sigcomp_options)) {
1603 msg_param_t const *l = NULL((void*)0);
1604 char *s = su_strdup(home, sigcomp);
1605 char *s1 = su_strdup(home, s), *s2 = s1;
1606
1607 if (s && s2 && msg_avlist_d(home, &s2, &l) == 0 && *s2 == '\0') {
1608 su_free(home, (void *)agent->sa_sigcomp_options);
1609 su_free(home, (void *)agent->sa_sigcomp_option_list);
1610 agent->sa_sigcomp_options = s;
1611 agent->sa_sigcomp_option_free = s1;
1612 agent->sa_sigcomp_option_list = l;
1613 } else {
1614 su_free(home, s);
1615 su_free(home, s1);
1616 su_free(home, (void *)l);
1617 n = -1;
1618 }
1619 }
1620
1621 if (maxsize == 0) maxsize = 2 * 1024 * 1024;
1622 if (maxsize > UINT32_MAX(4294967295U)) maxsize = UINT32_MAX(4294967295U);
1623 agent->sa_maxsize = maxsize;
1624
1625 if (max_proceeding == 0) max_proceeding = USIZE_MAX(2147483647 *2U +1U);
1626 agent->sa_max_proceeding = max_proceeding;
1627
1628 if (max_forwards == 0) max_forwards = 70; /* Default value */
1629 agent->sa_max_forwards->mf_count = max_forwards;
1630
1631 if (udp_mtu == 0) udp_mtu = 1300;
1632 if (udp_mtu > 65535) udp_mtu = 65535;
1633 if (agent->sa_udp_mtu != udp_mtu) {
1634 agent->sa_udp_mtu = udp_mtu;
1635 agent_set_udp_params(agent, udp_mtu);
1636 }
1637
1638 if (sip_t1 == 0) sip_t1 = NTA_SIP_T1;
1639 if (sip_t1 > NTA_TIME_MAX) sip_t1 = NTA_TIME_MAX;
1640 agent->sa_t1 = sip_t1;
1641
1642 if (sip_t2 == 0) sip_t2 = NTA_SIP_T2;
1643 if (sip_t2 > NTA_TIME_MAX) sip_t2 = NTA_TIME_MAX;
1644 agent->sa_t2 = sip_t2;
1645
1646 if (sip_t4 == 0) sip_t4 = NTA_SIP_T4;
1647 if (sip_t4 > NTA_TIME_MAX) sip_t4 = NTA_TIME_MAX;
1648 if (agent->sa_t4 != sip_t4) {
1649 incoming_queue_adjust(agent, agent->sa_in.inv_confirmed, sip_t4);
1650 outgoing_queue_adjust(agent, agent->sa_out.completed, sip_t4);
1651 }
1652 agent->sa_t4 = sip_t4;
1653
1654 if (sip_t1x64 == 0) sip_t1x64 = NTA_SIP_T1 * 64;
1655 if (sip_t1x64 > NTA_TIME_MAX) sip_t1x64 = NTA_TIME_MAX;
1656 if (agent->sa_t1x64 != sip_t1x64) {
1657 incoming_queue_adjust(agent, agent->sa_in.preliminary, sip_t1x64);
1658 incoming_queue_adjust(agent, agent->sa_in.completed, sip_t1x64);
1659 incoming_queue_adjust(agent, agent->sa_in.inv_completed, sip_t1x64);
1660 outgoing_queue_adjust(agent, agent->sa_out.trying, sip_t1x64);
1661 outgoing_queue_adjust(agent, agent->sa_out.inv_calling, sip_t1x64);
1662 }
1663 agent->sa_t1x64 = sip_t1x64;
1664 if (nC == 1) {
1665 agent->sa_use_timer_c = 1;
1666 if (timer_c == 0)
1667 timer_c = 185 * 1000;
1668 agent->sa_timer_c = timer_c;
1669 outgoing_queue_adjust(agent, agent->sa_out.inv_proceeding, timer_c);
1670 }
1671 if (timer_d < sip_t1x64)
1672 timer_d = sip_t1x64;
1673 outgoing_queue_adjust(agent, agent->sa_out.inv_completed, timer_d);
1674
1675 if (tls_orq_connect_timeout > NTA_TIME_MAX) tls_orq_connect_timeout = NTA_TIME_MAX;
1676 agent->sa_tls_orq_connect_timeout = tls_orq_connect_timeout;
1677
1678 if (graylist > 24 * 60 * 60)
1679 graylist = 24 * 60 * 60;
1680 agent->sa_graylist = graylist;
1681
1682 if (blacklist > 24 * 60 * 60)
1683 blacklist = 24 * 60 * 60;
1684 agent->sa_blacklist = blacklist;
1685
1686 if (progress == 0)
1687 progress = 60 * 1000;
1688 agent->sa_progress = progress;
1689
1690 if (server_rport > 3)
1691 server_rport = 1;
1692 else if (server_rport < 0)
1693 server_rport = 1;
1694 agent->sa_server_rport = server_rport;
1695
1696 agent->sa_bad_req_mask = bad_req_mask;
1697 agent->sa_bad_resp_mask = bad_resp_mask;
1698
1699 agent->sa_is_a_uas = ua != 0;
1700 agent->sa_is_stateless = stateless != 0;
1701 agent->sa_drop_prob = drop_prob < 1000 ? drop_prob : 1000;
1702 agent->sa_user_via = user_via != 0;
1703 agent->sa_extra_100 = extra_100 != 0;
1704 agent->sa_pass_100 = pass_100 != 0;
1705 agent->sa_timeout_408 = timeout_408 != 0;
1706 agent->sa_pass_408 = pass_408 != 0;
1707 agent->sa_merge_482 = merge_482 != 0;
1708 agent->sa_cancel_2543 = cancel_2543 != 0;
1709 agent->sa_cancel_487 = cancel_487 != 0;
1710 agent->sa_invite_100rel = invite_100rel != 0;
1711 agent->sa_timestamp = use_timestamp != 0;
1712 agent->sa_use_naptr = use_naptr != 0;
1713 agent->sa_use_srv = use_srv != 0;
1714 agent->sa_srv_503 = srv_503 != 0;
1715 agent->sa_smime = smime;
1716 agent->sa_flags = flags & MSG_FLG_USERMASK;
1717 agent->sa_rport = rport != 0;
1718 agent->sa_tcp_rport = tcp_rport != 0;
1719 agent->sa_tls_rport = tls_rport != 0;
1720 agent->sa_preload = preload;
1721 agent->sa_tport_threadpool = threadpool;
1722
1723 return n;
1724}
1725
1726static
1727void agent_set_udp_params(nta_agent_t *self, usize_t udp_mtu)
1728{
1729 tport_t *tp;
1730
1731 /* Set via fields for the tports */
1732 for (tp = tport_primaries(self->sa_tports); tp; tp = tport_next(tp)) {
1733 if (tport_is_udp(tp))
1734 tport_set_params(tp,
1735 TPTAG_TIMEOUT(2 * self->sa_t1x64)tptag_timeout, tag_uint_v((2 * self->sa_t1x64)),
1736 TPTAG_MTU(udp_mtu)tptag_mtu, tag_usize_v((udp_mtu)),
1737 TAG_END()(tag_type_t)0, (tag_value_t)0);
1738 }
1739}
1740
1741/**Get NTA Parameters.
1742 *
1743 * The nta_agent_get_params() function retrieves the stack parameters. The
1744 * parameters determine the way NTA handles the retransmissions, how long
1745 * NTA keeps transactions alive, does NTA apply proxy or user-agent logic to
1746 * INVITE transactions, or how the @Via headers are generated.
1747 *
1748 * @TAGS
1749 * NTATAG_ALIASES_REF(), NTATAG_BLACKLIST_REF(),
1750 * NTATAG_CANCEL_2543_REF(), NTATAG_CANCEL_487_REF(),
1751 * NTATAG_CLIENT_RPORT_REF(), NTATAG_CONTACT_REF(),
1752 * NTATAG_DEBUG_DROP_PROB_REF(), NTATAG_DEFAULT_PROXY_REF(),
1753 * NTATAG_EXTRA_100_REF(), NTATAG_GRAYLIST_REF(),
1754 * NTATAG_MAXSIZE_REF(), NTATAG_MAX_FORWARDS_REF(), NTATAG_MCLASS_REF(),
1755 * NTATAG_MERGE_482_REF(), NTATAG_MAX_PROCEEDING_REF(),
1756 * NTATAG_PASS_100_REF(), NTATAG_PASS_408_REF(), NTATAG_PRELOAD_REF(),
1757 * NTATAG_PROGRESS_REF(),
1758 * NTATAG_REL100_REF(),
1759 * NTATAG_SERVER_RPORT_REF(),
1760 * NTATAG_SIGCOMP_ALGORITHM_REF(), NTATAG_SIGCOMP_OPTIONS_REF(),
1761 * NTATAG_SIPFLAGS_REF(),
1762 * NTATAG_SIP_T1_REF(), NTATAG_SIP_T1X64_REF(), NTATAG_SIP_T2_REF(),
1763 * NTATAG_SIP_T4_REF(), NTATAG_SMIME_REF(), NTATAG_STATELESS_REF(),
1764 * NTATAG_TAG_3261_REF(), NTATAG_TIMEOUT_408_REF(), NTATAG_TIMER_C_REF(),
1765 * NTATAG_UA_REF(), NTATAG_UDP_MTU_REF(), NTATAG_USER_VIA_REF(),
1766 * NTATAG_USE_NAPTR_REF(), NTATAG_USE_SRV_REF(),
1767 * and NTATAG_USE_TIMESTAMP_REF().
1768 *
1769 */
1770int nta_agent_get_params(nta_agent_t *agent,
1771 tag_type_t tag, tag_value_t value, ...)
1772{
1773 int n;
1774 ta_list ta;
1775
1776 if (agent) {
1777 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)
;
1778 n = agent_get_params(agent, ta_args(ta)(ta).tl);
1779 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))
;
1780 return n;
1781 }
1782
1783 su_seterrno(EINVAL22);
1784 return -1;
1785}
1786
1787/** Get NTA parameters */
1788static
1789int agent_get_params(nta_agent_t *agent, tagi_t *tags)
1790{
1791 return
1792 tl_tgets(tags,
1793 NTATAG_ALIASES(agent->sa_aliases)ntatag_aliases, siptag_contact_v((agent->sa_aliases)),
1794 NTATAG_BLACKLIST(agent->sa_blacklist)ntatag_blacklist, tag_uint_v((agent->sa_blacklist)),
1795 NTATAG_CANCEL_2543(agent->sa_cancel_2543)ntatag_cancel_2543, tag_bool_v((agent->sa_cancel_2543)),
1796 NTATAG_CANCEL_487(agent->sa_cancel_487)ntatag_cancel_487, tag_bool_v((agent->sa_cancel_487)),
1797 NTATAG_CLIENT_RPORT(agent->sa_rport)ntatag_client_rport, tag_bool_v((agent->sa_rport)),
1798 NTATAG_CONTACT(agent->sa_contact)ntatag_contact, siptag_contact_v((agent->sa_contact)),
1799 NTATAG_DEBUG_DROP_PROB(agent->sa_drop_prob)ntatag_debug_drop_prob, tag_uint_v((agent->sa_drop_prob)),
1800 NTATAG_DEFAULT_PROXY(agent->sa_default_proxy)ntatag_default_proxy, urltag_url_v((agent->sa_default_proxy
))
,
1801 NTATAG_EXTRA_100(agent->sa_extra_100)ntatag_extra_100, tag_bool_v((agent->sa_extra_100)),
1802 NTATAG_GRAYLIST(agent->sa_graylist)ntatag_graylist, tag_uint_v((agent->sa_graylist)),
1803 NTATAG_MAXSIZE(agent->sa_maxsize)ntatag_maxsize, tag_usize_v((agent->sa_maxsize)),
1804 NTATAG_MAX_PROCEEDING(agent->sa_max_proceeding)ntatag_max_proceeding, tag_usize_v((agent->sa_max_proceeding
))
,
1805 NTATAG_MAX_FORWARDS(agent->sa_max_forwards->mf_count)ntatag_max_forwards, tag_uint_v((agent->sa_max_forwards->
mf_count))
,
1806 NTATAG_MCLASS(agent->sa_mclass)ntatag_mclass, tag_cptr_v((agent->sa_mclass)),
1807 NTATAG_MERGE_482(agent->sa_merge_482)ntatag_merge_482, tag_bool_v((agent->sa_merge_482)),
1808 NTATAG_PASS_100(agent->sa_pass_100)ntatag_pass_100, tag_bool_v((agent->sa_pass_100)),
1809 NTATAG_PASS_408(agent->sa_pass_408)ntatag_pass_408, tag_bool_v((agent->sa_pass_408)),
1810 NTATAG_PRELOAD(agent->sa_preload)ntatag_preload, tag_uint_v((agent->sa_preload)),
1811 NTATAG_PROGRESS(agent->sa_progress)ntatag_progress, tag_uint_v((agent->sa_progress)),
1812 NTATAG_REL100(agent->sa_invite_100rel)ntatag_rel100, tag_bool_v((agent->sa_invite_100rel)),
1813 NTATAG_SERVER_RPORT((int)(agent->sa_server_rport))ntatag_server_rport, tag_int_v(((int)(agent->sa_server_rport
)))
,
1814 NTATAG_SIGCOMP_ALGORITHM(agent->sa_algorithm)ntatag_sigcomp_algorithm, tag_str_v((agent->sa_algorithm)),
1815 NTATAG_SIGCOMP_OPTIONS(agent->sa_sigcomp_options ?ntatag_sigcomp_options, tag_str_v((agent->sa_sigcomp_options
? agent->sa_sigcomp_options : "sip"))
1816 agent->sa_sigcomp_options :ntatag_sigcomp_options, tag_str_v((agent->sa_sigcomp_options
? agent->sa_sigcomp_options : "sip"))
1817 "sip")ntatag_sigcomp_options, tag_str_v((agent->sa_sigcomp_options
? agent->sa_sigcomp_options : "sip"))
,
1818 NTATAG_SIPFLAGS(agent->sa_flags)ntatag_sipflags, tag_uint_v((agent->sa_flags)),
1819 NTATAG_SIP_T1(agent->sa_t1)ntatag_sip_t1, tag_uint_v((agent->sa_t1)),
1820 NTATAG_SIP_T1X64(agent->sa_t1x64)ntatag_sip_t1x64, tag_uint_v((agent->sa_t1x64)),
1821 NTATAG_SIP_T2(agent->sa_t2)ntatag_sip_t2, tag_uint_v((agent->sa_t2)),
1822 NTATAG_SIP_T4(agent->sa_t4)ntatag_sip_t4, tag_uint_v((agent->sa_t4)),
1823#if HAVE_SOFIA_SMIME0
1824 NTATAG_SMIME(agent->sa_smime)ntatag_smime, tag_ptr_v((agent->sa_smime)),
1825#else
1826 NTATAG_SMIME(NULL)ntatag_smime, tag_ptr_v((((void*)0))),
1827#endif
1828 NTATAG_STATELESS(agent->sa_is_stateless)ntatag_stateless, tag_bool_v((agent->sa_is_stateless)),
1829 NTATAG_TAG_3261(1)ntatag_tag_3261, tag_bool_v((1)),
1830 NTATAG_TIMEOUT_408(agent->sa_timeout_408)ntatag_timeout_408, tag_bool_v((agent->sa_timeout_408)),
1831 NTATAG_TIMER_C(agent->sa_timer_c)ntatag_timer_c, tag_uint_v((agent->sa_timer_c)),
1832 NTATAG_UA(agent->sa_is_a_uas)ntatag_ua, tag_bool_v((agent->sa_is_a_uas)),
1833 NTATAG_UDP_MTU(agent->sa_udp_mtu)ntatag_udp_mtu, tag_uint_v((agent->sa_udp_mtu)),
1834 NTATAG_USER_VIA(agent->sa_user_via)ntatag_user_via, tag_bool_v((agent->sa_user_via)),
1835 NTATAG_USE_NAPTR(agent->sa_use_naptr)ntatag_use_naptr, tag_bool_v((agent->sa_use_naptr)),
1836 NTATAG_USE_SRV(agent->sa_use_srv)ntatag_use_srv, tag_bool_v((agent->sa_use_srv)),
1837 NTATAG_USE_TIMESTAMP(agent->sa_timestamp)ntatag_use_timestamp, tag_bool_v((agent->sa_timestamp)),
1838 NTATAG_SRV_503(agent->sa_srv_503)ntatag_srv_503, tag_bool_v((agent->sa_srv_503)),
1839 TAG_END()(tag_type_t)0, (tag_value_t)0);
1840}
1841
1842/**Get NTA statistics.
1843 *
1844 * The nta_agent_get_stats() function retrieves the stack statistics.
1845 *
1846 * @TAGS
1847 * NTATAG_S_ACKED_TR_REF(),
1848 * NTATAG_S_BAD_MESSAGE_REF(),
1849 * NTATAG_S_BAD_REQUEST_REF(),
1850 * NTATAG_S_BAD_RESPONSE_REF(),
1851 * NTATAG_S_CANCELED_TR_REF(),
1852 * NTATAG_S_CLIENT_TR_REF(),
1853 * NTATAG_S_DIALOG_TR_REF(),
1854 * NTATAG_S_DROP_REQUEST_REF(),
1855 * NTATAG_S_DROP_RESPONSE_REF(),
1856 * NTATAG_S_IRQ_HASH_REF(),
1857 * NTATAG_S_IRQ_HASH_USED_REF(),
1858 * NTATAG_S_LEG_HASH_REF(),
1859 * NTATAG_S_LEG_HASH_USED_REF(),
1860 * NTATAG_S_MERGED_REQUEST_REF(),
1861 * NTATAG_S_ORQ_HASH_REF(),
1862 * NTATAG_S_ORQ_HASH_USED_REF(),
1863 * NTATAG_S_RECV_MSG_REF(),
1864 * NTATAG_S_RECV_REQUEST_REF(),
1865 * NTATAG_S_RECV_RESPONSE_REF(),
1866 * NTATAG_S_RECV_RETRY_REF(),
1867 * NTATAG_S_RETRY_REQUEST_REF(),
1868 * NTATAG_S_RETRY_RESPONSE_REF(),
1869 * NTATAG_S_SENT_MSG_REF(),
1870 * NTATAG_S_SENT_REQUEST_REF(),
1871 * NTATAG_S_SENT_RESPONSE_REF(),
1872 * NTATAG_S_SERVER_TR_REF(),
1873 * NTATAG_S_TOUT_REQUEST_REF(),
1874 * NTATAG_S_TOUT_RESPONSE_REF(),
1875 * NTATAG_S_TRLESS_200_REF(),
1876 * NTATAG_S_TRLESS_REQUEST_REF(),
1877 * NTATAG_S_TRLESS_RESPONSE_REF(), and
1878 * NTATAG_S_TRLESS_TO_TR_REF(),
1879 */
1880int nta_agent_get_stats(nta_agent_t *agent,
1881 tag_type_t tag, tag_value_t value, ...)
1882{
1883 int n;
1884 ta_list ta;
1885
1886 if (!agent)
1887 return su_seterrno(EINVAL22), -1;
1888
1889 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)
;
1890
1891 n = tl_tgets(ta_args(ta)(ta).tl,
1892 NTATAG_S_IRQ_HASH(agent->sa_incoming->iht_size)ntatag_s_irq_hash, tag_usize_v(agent->sa_incoming->iht_size
)
,
1893 NTATAG_S_ORQ_HASH(agent->sa_outgoing->oht_size)ntatag_s_orq_hash, tag_usize_v(agent->sa_outgoing->oht_size
)
,
1894 NTATAG_S_LEG_HASH(agent->sa_dialogs->lht_size)ntatag_s_leg_hash, tag_usize_v(agent->sa_dialogs->lht_size
)
,
1895 NTATAG_S_IRQ_HASH_USED(agent->sa_incoming->iht_used)ntatag_s_irq_hash_used, tag_usize_v(agent->sa_incoming->
iht_used)
,
1896 NTATAG_S_ORQ_HASH_USED(agent->sa_outgoing->oht_used)ntatag_s_orq_hash_used, tag_usize_v(agent->sa_outgoing->
oht_used)
,
1897 NTATAG_S_LEG_HASH_USED(agent->sa_dialogs->lht_used)ntatag_s_leg_hash_used, tag_usize_v(agent->sa_dialogs->
lht_used)
,
1898 NTATAG_S_RECV_MSG(agent->sa_stats->as_recv_msg)ntatag_s_recv_msg, tag_usize_v(agent->sa_stats->as_recv_msg
)
,
1899 NTATAG_S_RECV_REQUEST(agent->sa_stats->as_recv_request)ntatag_s_recv_request, tag_usize_v(agent->sa_stats->as_recv_request
)
,
1900 NTATAG_S_RECV_RESPONSE(agent->sa_stats->as_recv_response)ntatag_s_recv_response, tag_usize_v(agent->sa_stats->as_recv_response
)
,
1901 NTATAG_S_BAD_MESSAGE(agent->sa_stats->as_bad_message)ntatag_s_bad_message, tag_usize_v(agent->sa_stats->as_bad_message
)
,
1902 NTATAG_S_BAD_REQUEST(agent->sa_stats->as_bad_request)ntatag_s_bad_request, tag_usize_v(agent->sa_stats->as_bad_request
)
,
1903 NTATAG_S_BAD_RESPONSE(agent->sa_stats->as_bad_response)ntatag_s_bad_response, tag_usize_v(agent->sa_stats->as_bad_response
)
,
1904 NTATAG_S_DROP_REQUEST(agent->sa_stats->as_drop_request)ntatag_s_drop_request, tag_usize_v(agent->sa_stats->as_drop_request
)
,
1905 NTATAG_S_DROP_RESPONSE(agent->sa_stats->as_drop_response)ntatag_s_drop_response, tag_usize_v(agent->sa_stats->as_drop_response
)
,
1906 NTATAG_S_CLIENT_TR(agent->sa_stats->as_client_tr)ntatag_s_client_tr, tag_usize_v(agent->sa_stats->as_client_tr
)
,
1907 NTATAG_S_SERVER_TR(agent->sa_stats->as_server_tr)ntatag_s_server_tr, tag_usize_v(agent->sa_stats->as_server_tr
)
,
1908 NTATAG_S_DIALOG_TR(agent->sa_stats->as_dialog_tr)ntatag_s_dialog_tr, tag_usize_v(agent->sa_stats->as_dialog_tr
)
,
1909 NTATAG_S_ACKED_TR(agent->sa_stats->as_acked_tr)ntatag_s_acked_tr, tag_usize_v(agent->sa_stats->as_acked_tr
)
,
1910 NTATAG_S_CANCELED_TR(agent->sa_stats->as_canceled_tr)ntatag_s_canceled_tr, tag_usize_v(agent->sa_stats->as_canceled_tr
)
,
1911 NTATAG_S_TRLESS_REQUEST(agent->sa_stats->as_trless_request)ntatag_s_trless_request, tag_usize_v(agent->sa_stats->as_trless_request
)
,
1912 NTATAG_S_TRLESS_TO_TR(agent->sa_stats->as_trless_to_tr)ntatag_s_trless_to_tr, tag_usize_v(agent->sa_stats->as_trless_to_tr
)
,
1913 NTATAG_S_TRLESS_RESPONSE(agent->sa_stats->as_trless_response)ntatag_s_trless_response, tag_usize_v(agent->sa_stats->
as_trless_response)
,
1914 NTATAG_S_TRLESS_200(agent->sa_stats->as_trless_200)ntatag_s_trless_200, tag_usize_v(agent->sa_stats->as_trless_200
)
,
1915 NTATAG_S_MERGED_REQUEST(agent->sa_stats->as_merged_request)ntatag_s_merged_request, tag_usize_v(agent->sa_stats->as_merged_request
)
,
1916 NTATAG_S_SENT_MSG(agent->sa_stats->as_sent_msg)ntatag_s_sent_msg, tag_usize_v(agent->sa_stats->as_sent_msg
)
,
1917 NTATAG_S_SENT_REQUEST(agent->sa_stats->as_sent_request)ntatag_s_sent_request, tag_usize_v(agent->sa_stats->as_sent_request
)
,
1918 NTATAG_S_SENT_RESPONSE(agent->sa_stats->as_sent_response)ntatag_s_sent_response, tag_usize_v(agent->sa_stats->as_sent_response
)
,
1919 NTATAG_S_RETRY_REQUEST(agent->sa_stats->as_retry_request)ntatag_s_retry_request, tag_usize_v(agent->sa_stats->as_retry_request
)
,
1920 NTATAG_S_RETRY_RESPONSE(agent->sa_stats->as_retry_response)ntatag_s_retry_response, tag_usize_v(agent->sa_stats->as_retry_response
)
,
1921 NTATAG_S_RECV_RETRY(agent->sa_stats->as_recv_retry)ntatag_s_recv_retry, tag_usize_v(agent->sa_stats->as_recv_retry
)
,
1922 NTATAG_S_TOUT_REQUEST(agent->sa_stats->as_tout_request)ntatag_s_tout_request, tag_usize_v(agent->sa_stats->as_tout_request
)
,
1923 NTATAG_S_TOUT_RESPONSE(agent->sa_stats->as_tout_response)ntatag_s_tout_response, tag_usize_v(agent->sa_stats->as_tout_response
)
,
1924 NTATAG_Q_IN_COMPLETED(agent->sa_in.completed->q_length)ntatag_q_in_completed, tag_size_v(agent->sa_in.completed->
q_length)
,
1925 NTATAG_Q_IN_FINAL_FAILED(agent->sa_in.final_failed->q_length)ntatag_q_in_final_failed, tag_size_v(agent->sa_in.final_failed
->q_length)
,
1926 NTATAG_Q_IN_INV_COMPLETED(agent->sa_in.inv_completed->q_length)ntatag_q_in_inv_completed, tag_size_v(agent->sa_in.inv_completed
->q_length)
,
1927 NTATAG_Q_IN_INV_CONFIRMED(agent->sa_in.inv_confirmed->q_length)ntatag_q_in_inv_confirmed, tag_size_v(agent->sa_in.inv_confirmed
->q_length)
,
1928 NTATAG_Q_IN_PRELIMINARY(agent->sa_in.preliminary->q_length)ntatag_q_in_preliminary, tag_size_v(agent->sa_in.preliminary
->q_length)
,
1929 NTATAG_Q_IN_PROCEEDING(agent->sa_in.proceeding->q_length)ntatag_q_in_proceeding, tag_size_v(agent->sa_in.proceeding
->q_length)
,
1930 NTATAG_Q_IN_TERMINATED(agent->sa_in.terminated->q_length)ntatag_q_in_terminated, tag_size_v(agent->sa_in.terminated
->q_length)
,
1931 NTATAG_Q_OUT_COMPLETED(agent->sa_out.completed->q_length)ntatag_q_out_completed, tag_size_v(agent->sa_out.completed
->q_length)
,
1932 NTATAG_Q_OUT_DELAYED(agent->sa_out.delayed->q_length)ntatag_q_out_delayed, tag_size_v(agent->sa_out.delayed->
q_length)
,
1933 NTATAG_Q_OUT_INV_CALLING(agent->sa_out.inv_calling->q_length)ntatag_q_out_inv_calling, tag_size_v(agent->sa_out.inv_calling
->q_length)
,
1934 NTATAG_Q_OUT_INV_COMPLETED(agent->sa_out.inv_completed->q_length)ntatag_q_out_inv_completed, tag_size_v(agent->sa_out.inv_completed
->q_length)
,
1935 NTATAG_Q_OUT_INV_PROCEEDING(agent->sa_out.inv_proceeding->q_length)ntatag_q_out_inv_proceeding, tag_size_v(agent->sa_out.inv_proceeding
->q_length)
,
1936 NTATAG_Q_OUT_RESOLVING(agent->sa_out.resolving->q_length)ntatag_q_out_resolving, tag_size_v(agent->sa_out.resolving
->q_length)
,
1937 NTATAG_Q_OUT_TERMINATED(agent->sa_out.terminated->q_length)ntatag_q_out_terminated, tag_size_v(agent->sa_out.terminated
->q_length)
,
1938 TAG_END()(tag_type_t)0, (tag_value_t)0);
1939
1940 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))
;
1941
1942 return n;
1943}
1944
1945/**Calculate a new unique tag.
1946 *
1947 * This function generates a series of 2**64 unique tags for @From or @To
1948 * headers. The start of the tag series is derived from the NTP time the NTA
1949 * agent was initialized.
1950 *
1951 */
1952char const *nta_agent_newtag(su_home_t *home, char const *fmt, nta_agent_t *sa)
1953{
1954 char tag[(8 * 8 + 4)/ 5 + 1];
1955
1956 if (sa == NULL((void*)0))
1957 return su_seterrno(EINVAL22), NULL((void*)0);
1958
1959 /* XXX - use a cryptographically safe func here? */
1960 sa->sa_tags += NTA_TAG_PRIME(uint64_t)(0xB9591D1C361C6521ULL);
1961
1962 msg_random_token(tag, sizeof(tag) - 1, &sa->sa_tags, sizeof(sa->sa_tags));
1963
1964 if (fmt && fmt[0])
1965 return su_sprintf(home, fmt, tag);
1966 else
1967 return su_strdup(home, tag);
1968}
1969
1970/**
1971 * Calculate branch value.
1972 */
1973static char const *stateful_branch(su_home_t *home, nta_agent_t *sa)
1974{
1975 char branch[(8 * 8 + 4)/ 5 + 1];
1976
1977 /* XXX - use a cryptographically safe func here? */
1978 sa->sa_branch += NTA_BRANCH_PRIME(uint64_t)(0xB9591D1C361C6521ULL);
1979
1980 msg_random_token(branch, sizeof(branch) - 1,
1981 &sa->sa_branch, sizeof(sa->sa_branch));
1982
1983 return su_sprintf(home, "branch=z9hG4bK%s", branch);
1984}
1985
1986#include <sofia-sip/su_md5.h>
1987
1988/**
1989 * Calculate branch value for stateless operation.
1990 *
1991 * XXX - should include HMAC of previous @Via line.
1992 */
1993static
1994char const *stateless_branch(nta_agent_t *sa,
1995 msg_t *msg,
1996 sip_t const *sip,
1997 tp_name_t const *tpn)
1998{
1999 su_md5_t md5[1];
2000 uint8_t digest[SU_MD5_DIGEST_SIZE16];
2001 char branch[(SU_MD5_DIGEST_SIZE16 * 8 + 4)/ 5 + 1];
2002 sip_route_t const *r;
2003
2004 assert(sip->sip_request)((void) sizeof ((sip->sip_request) ? 1 : 0), __extension__
({ if (sip->sip_request) ; else __assert_fail ("sip->sip_request"
, "nta.c", 2004, __extension__ __PRETTY_FUNCTION__); }))
;
2005
2006 if (!sip->sip_via)
2007 return stateful_branch(msg_home(msg)((su_home_t*)(msg)), sa);
2008
2009 su_md5_init(md5);
2010
2011 su_md5_str0update(md5, tpn->tpn_host);
2012 su_md5_str0update(md5, tpn->tpn_port);
2013
2014 url_update(md5, sip->sip_request->rq_url);
2015 if (sip->sip_call_id) {
2016 su_md5_str0update(md5, sip->sip_call_id->i_id);
2017 }
2018 if (sip->sip_from) {
2019 url_update(md5, sip->sip_from->a_url);
2020 su_md5_stri0update(md5, sip->sip_from->a_tag);
2021 }
2022 if (sip->sip_to) {
2023 url_update(md5, sip->sip_to->a_url);
2024 /* XXX - some broken implementations include To tag in CANCEL */
2025 /* su_md5_str0update(md5, sip->sip_to->a_tag); */
2026 }
2027 if (sip->sip_cseq) {
2028 uint32_t cseq = htonl(sip->sip_cseq->cs_seq);
2029 su_md5_update(md5, &cseq, sizeof(cseq));
2030 }
2031
2032 for (r = sip->sip_route; r; r = r->r_next)
2033 url_update(md5, r->r_url);
2034
2035 su_md5_digest(md5, digest);
2036
2037 msg_random_token(branch, sizeof(branch) - 1, digest, sizeof(digest));
2038
2039 return su_sprintf(msg_home(msg)((su_home_t*)(msg)), "branch=z9hG4bK.%s", branch);
2040}
2041
2042/* ====================================================================== */
2043/* 2) Transport interface */
2044
2045/* Local prototypes */
2046static int agent_create_master_transport(nta_agent_t *self, tagi_t *tags);
2047static int agent_init_via(nta_agent_t *self, tport_t *primaries, int use_maddr);
2048static int agent_init_contact(nta_agent_t *self);
2049static void agent_recv_message(nta_agent_t *agent,
2050 tport_t *tport,
2051 msg_t *msg,
2052 sip_via_t *tport_via,
2053 su_time_t now);
2054static void agent_tp_error(nta_agent_t *agent,
2055 tport_t *tport,
2056 int errcode,
2057 char const *remote);
2058static void agent_update_tport(nta_agent_t *agent, tport_t *);
2059
2060/**For each transport, we have name used by tport module, SRV prefixes used
2061 * for resolving, and NAPTR service/conversion.
2062 */
2063static
2064struct sipdns_tport {
2065 char name[6]; /**< Named used by tport module */
2066 char port[6]; /**< Default port number */
2067 char prefix[14]; /**< Prefix for SRV domains */
2068 char service[10]; /**< NAPTR service */
2069}
2070#define SIPDNS_TRANSPORTS(6) (6)
2071const sipdns_tports[SIPDNS_TRANSPORTS(6)] = {
2072 { "udp", "5060", "_sip._udp.", "SIP+D2U" },
2073 { "tcp", "5060", "_sip._tcp.", "SIP+D2T" },
2074 { "sctp", "5060", "_sip._sctp.", "SIP+D2S" },
2075 { "tls", "5061", "_sips._tcp.", "SIPS+D2T" },
2076 { "ws", "5080", "_sips._ws.", "SIP+D2W" },
2077 { "wss", "5081", "_sips._wss.", "SIPS+D2W" },
2078};
2079
2080static char const * const tports_sip[] =
2081 {
2082 "udp", "tcp", "sctp", "ws", NULL((void*)0)
2083 };
2084
2085static char const * const tports_sips[] =
2086 {
2087 "tls", "wss", "ws", NULL((void*)0)
2088 };
2089
2090static tport_stack_class_t nta_agent_class[1] =
2091 {{
2092 sizeof(nta_agent_class),
2093 agent_recv_message,
2094 agent_tp_error,
2095 nta_msg_create_for_transport,
2096 agent_update_tport,
2097 }};
2098
2099
2100/** Add a transport to the agent.
2101 *
2102 * Creates a new transport and binds it
2103 * to the port specified by the @a uri. The @a uri must have sip: or sips:
2104 * scheme or be a wildcard uri ("*"). The @a uri syntax allowed is as
2105 * follows:
2106 *
2107 * @code url <scheme>:<host>[:<port>]<url-params> @endcode
2108 * where <url-params> may be
2109 * @code
2110 * ;transport=<xxx>
2111 * ;maddr=<actual addr>
2112 * ;comp=sigcomp
2113 * @endcode
2114 *
2115 * The scheme part determines which transports are used. "sip" implies UDP
2116 * and TCP, "sips" TLS over TCP. In the future, more transports can be
2117 * supported, for instance, "sip" can use SCTP or DCCP, "sips" DTLS or TLS
2118 * over SCTP.
2119 *
2120 * The "host" part determines what address/domain name is used in @Contact.
2121 * An "*" in "host" part is shorthand for any local IP address. 0.0.0.0
2122 * means that the only the IPv4 addresses are used. [::] means that only
2123 * the IPv6 addresses are used. If a domain name or a specific IP address
2124 * is given as "host" part, an additional "maddr" parameter can be used to
2125 * control which addresses are used by the stack when binding listen
2126 * sockets for incoming requests.
2127 *
2128 * The "port" determines what port is used in contact, and to which port the
2129 * stack binds in order to listen for incoming requests. Empty or missing
2130 * port means that default port should be used (5060 for sip, 5061 for
2131 * sips). An "*" in "port" part means any port, i.e., the stack binds to an
2132 * ephemeral port.
2133 *
2134 * The "transport" parameter determines the transport protocol that is used
2135 * and how they are preferred. If no protocol is specified, both UDP and TCP
2136 * are used for SIP URL and TLS for SIPS URL. The preference can be
2137 * indicated with a comma-separated list of transports, for instance,
2138 * parameter @code transport=tcp,udp @endcode indicates that TCP is
2139 * preferred to UDP.
2140 *
2141 * The "maddr" parameter determines to which address the stack binds in
2142 * order to listen for incoming requests. An "*" in "maddr" parameter is
2143 * shorthand for any local IP address. 0.0.0.0 means that only IPv4 sockets
2144 * are created. [::] means that only IPv6 sockets are created.
2145 *
2146 * The "comp" parameter determines the supported compression protocol.
2147 * Currently only sigcomp is supported (with suitable library).
2148 *
2149 * @par Examples:
2150 * @code sip:172.21.40.24;maddr=* @endcode \n
2151 * @code sip:172.21.40.24:50600;transport=TCP,UDP;comp=sigcomp @endcode \n
2152 * @code sips:* @endcode
2153 *
2154 * @return
2155 * On success, zero is returned. On error, -1 is returned, and @a errno is
2156 * set appropriately.
2157 */
2158int nta_agent_add_tport(nta_agent_t *self,
2159 url_string_t const *uri,
2160 tag_type_t tag, tag_value_t value, ...)
2161{
2162 url_t *url;
2163 char tp[32];
2164 char maddr[256];
2165 char comp[32];
2166 tp_name_t tpn[1] = {{ NULL((void*)0) }};
2167 char const * const * tports = tports_sip;
2168 int error;
2169 ta_list ta;
2170 char *tps[9] = {0};
2171
2172 if (self == NULL((void*)0)) {
2173 su_seterrno(EINVAL22);
2174 return -1;
2175 }
2176
2177 if (uri == NULL((void*)0))
2178 uri = (url_string_t *)"sip:*";
2179 else if (url_string_p(uri) ?
2180 strcmp(uri->us_str, "*") == 0 :
2181 uri->us_url->url_type == url_any) {
2182 uri = (url_string_t *)"sip:*:*";
2183 }
2184
2185 if (!(url = url_hdup(self->sa_home, uri->us_url)) ||
2186 (url->url_type != url_sip && url->url_type != url_sips && url->url_type != url_urn)) {
2187 if (url_string_p(uri))
2188 SU_DEBUG_1(("nta: %s: invalid bind URL\n", uri->us_str))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 2188, "nta: %s: invalid bind URL\n", uri->us_str)) : (void
)0)
;
2189 else
2190 SU_DEBUG_1(("nta: invalid bind URL\n" VA_NONE))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 2190, "nta: invalid bind URL\n" "%s", "")) : (void)0)
;
2191 su_seterrno(EINVAL22);
2192 return -1;
2193 }
2194
2195 tpn->tpn_canon = url->url_host;
2196 tpn->tpn_host = url->url_host;
2197 tpn->tpn_port = url_port(url);
2198
2199 if (url->url_type == url_sip || url->url_type == url_urn) {
2200 tpn->tpn_proto = "*";
2201 tports = tports_sip;
2202 if (!tpn->tpn_port || !tpn->tpn_port[0])
2203 tpn->tpn_port = SIP_DEFAULT_SERV"5060";
2204 }
2205 else {
2206 assert(url->url_type == url_sips)((void) sizeof ((url->url_type == url_sips) ? 1 : 0), __extension__
({ if (url->url_type == url_sips) ; else __assert_fail ("url->url_type == url_sips"
, "nta.c", 2206, __extension__ __PRETTY_FUNCTION__); }))
;
2207 tpn->tpn_proto = "*";
2208 tports = tports_sips;
2209 if (!tpn->tpn_port || !tpn->tpn_port[0])
2210 tpn->tpn_port = SIPS_DEFAULT_SERV"5061";
2211 }
2212
2213 if (url->url_params) {
2214 if (url_param(url->url_params, "transport", tp, sizeof(tp)) > 0) {
2215 if (strchr(tp, ',')) {
2216 int i; char *t;
2217
2218 /* Split tp into transports */
2219 for (i = 0, t = tp; t && i < 8; i++) {
2220 tps[i] = t;
2221 if ((t = strchr(t, ',')))
2222 *t++ = '\0';
2223 }
2224
2225 tps[i] = NULL((void*)0);
2226 tports = (char const * const *)tps;
2227 } else {
2228 tpn->tpn_proto = tp;
2229 }
2230 }
2231 if (url_param(url->url_params, "maddr", maddr, sizeof(maddr)) > 0)
2232 tpn->tpn_host = maddr;
2233 if (url_param(url->url_params, "comp", comp, sizeof(comp)) > 0)
2234 tpn->tpn_comp = comp;
2235
2236 if (tpn->tpn_comp &&
2237 (nta_compressor_vtable == NULL((void*)0) ||
2238 !su_casematch(tpn->tpn_comp, nta_compressor_vtable->ncv_name))) {
2239 SU_DEBUG_1(("nta(%p): comp=%s not supported for " URL_PRINT_FORMAT "\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 2240, "nta(%p): comp=%s not supported for " "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
"\n", (void *)self, tpn->tpn_comp, (url)->url_scheme ?
(url)->url_scheme : "", (url)->url_type != url_any &&
(url)->url_scheme && (url)->url_scheme[0] ? ":"
: "", (url)->url_root && ((url)->url_host || (
url)->url_user) ? "//" : "", (url)->url_user ? (url)->
url_user : "", (url)->url_user && (url)->url_password
? ":" : "", (url)->url_user && (url)->url_password
? (url)->url_password : "", (url)->url_user &&
(url)->url_host ? "@" : "", (url)->url_host ? (url)->
url_host : "", (url)->url_host && (url)->url_port
? ":" : "", (url)->url_host && (url)->url_port
? (url)->url_port : "", (url)->url_root && (url
)->url_path ? "/" : "", (url)->url_path ? (url)->url_path
: "", (url)->url_params ? ";" : "", (url)->url_params ?
(url)->url_params : "", (url)->url_headers ? "?" : "",
(url)->url_headers ? (url)->url_headers : "", (url)->
url_fragment ? "#" : "", (url)->url_fragment ? (url)->url_fragment
: "")) : (void)0)
2240 (void *)self, tpn->tpn_comp, URL_PRINT_ARGS(url)))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 2240, "nta(%p): comp=%s not supported for " "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
"\n", (void *)self, tpn->tpn_comp, (url)->url_scheme ?
(url)->url_scheme : "", (url)->url_type != url_any &&
(url)->url_scheme && (url)->url_scheme[0] ? ":"
: "", (url)->url_root && ((url)->url_host || (
url)->url_user) ? "//" : "", (url)->url_user ? (url)->
url_user : "", (url)->url_user && (url)->url_password
? ":" : "", (url)->url_user && (url)->url_password
? (url)->url_password : "", (url)->url_user &&
(url)->url_host ? "@" : "", (url)->url_host ? (url)->
url_host : "", (url)->url_host && (url)->url_port
? ":" : "", (url)->url_host && (url)->url_port
? (url)->url_port : "", (url)->url_root && (url
)->url_path ? "/" : "", (url)->url_path ? (url)->url_path
: "", (url)->url_params ? ";" : "", (url)->url_params ?
(url)->url_params : "", (url)->url_headers ? "?" : "",
(url)->url_headers ? (url)->url_headers : "", (url)->
url_fragment ? "#" : "", (url)->url_fragment ? (url)->url_fragment
: "")) : (void)0)
;
2241 }
2242 }
2243
2244 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)
;
2245
2246 if (self->sa_tports == NULL((void*)0)) {
2247 if (agent_create_master_transport(self, ta_args(ta)(ta).tl) < 0) {
2248 error = su_errno();
2249 SU_DEBUG_1(("nta: cannot create master transport: %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 2250, "nta: cannot create master transport: %s\n", su_strerror
(error))) : (void)0)
2250 su_strerror(error)))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 2250, "nta: cannot create master transport: %s\n", su_strerror
(error))) : (void)0)
;
2251 goto error;
2252 }
2253 }
2254
2255 if (tport_tbind(self->sa_tports, tpn, tports, ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
) < 0) {
2256 error = su_errno();
2257 SU_DEBUG_1(("nta: bind(%s:%s;transport=%s%s%s%s%s): %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 2263, "nta: bind(%s:%s;transport=%s%s%s%s%s): %s\n", tpn->
tpn_canon, tpn->tpn_port, tpn->tpn_proto, tpn->tpn_canon
!= tpn->tpn_host ? ";maddr=" : "", tpn->tpn_canon != tpn
->tpn_host ? tpn->tpn_host : "", tpn->tpn_comp ? ";comp="
: "", tpn->tpn_comp ? tpn->tpn_comp : "", su_strerror(
error))) : (void)0)
2258 tpn->tpn_canon, tpn->tpn_port, tpn->tpn_proto,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 2263, "nta: bind(%s:%s;transport=%s%s%s%s%s): %s\n", tpn->
tpn_canon, tpn->tpn_port, tpn->tpn_proto, tpn->tpn_canon
!= tpn->tpn_host ? ";maddr=" : "", tpn->tpn_canon != tpn
->tpn_host ? tpn->tpn_host : "", tpn->tpn_comp ? ";comp="
: "", tpn->tpn_comp ? tpn->tpn_comp : "", su_strerror(
error))) : (void)0)
2259 tpn->tpn_canon != tpn->tpn_host ? ";maddr=" : "",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 2263, "nta: bind(%s:%s;transport=%s%s%s%s%s): %s\n", tpn->
tpn_canon, tpn->tpn_port, tpn->tpn_proto, tpn->tpn_canon
!= tpn->tpn_host ? ";maddr=" : "", tpn->tpn_canon != tpn
->tpn_host ? tpn->tpn_host : "", tpn->tpn_comp ? ";comp="
: "", tpn->tpn_comp ? tpn->tpn_comp : "", su_strerror(
error))) : (void)0)
2260 tpn->tpn_canon != tpn->tpn_host ? tpn->tpn_host : "",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 2263, "nta: bind(%s:%s;transport=%s%s%s%s%s): %s\n", tpn->
tpn_canon, tpn->tpn_port, tpn->tpn_proto, tpn->tpn_canon
!= tpn->tpn_host ? ";maddr=" : "", tpn->tpn_canon != tpn
->tpn_host ? tpn->tpn_host : "", tpn->tpn_comp ? ";comp="
: "", tpn->tpn_comp ? tpn->tpn_comp : "", su_strerror(
error))) : (void)0)
2261 tpn->tpn_comp ? ";comp=" : "",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 2263, "nta: bind(%s:%s;transport=%s%s%s%s%s): %s\n", tpn->
tpn_canon, tpn->tpn_port, tpn->tpn_proto, tpn->tpn_canon
!= tpn->tpn_host ? ";maddr=" : "", tpn->tpn_canon != tpn
->tpn_host ? tpn->tpn_host : "", tpn->tpn_comp ? ";comp="
: "", tpn->tpn_comp ? tpn->tpn_comp : "", su_strerror(
error))) : (void)0)
2262 tpn->tpn_comp ? tpn->tpn_comp : "",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 2263, "nta: bind(%s:%s;transport=%s%s%s%s%s): %s\n", tpn->
tpn_canon, tpn->tpn_port, tpn->tpn_proto, tpn->tpn_canon
!= tpn->tpn_host ? ";maddr=" : "", tpn->tpn_canon != tpn
->tpn_host ? tpn->tpn_host : "", tpn->tpn_comp ? ";comp="
: "", tpn->tpn_comp ? tpn->tpn_comp : "", su_strerror(
error))) : (void)0)
2263 su_strerror(error)))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 2263, "nta: bind(%s:%s;transport=%s%s%s%s%s): %s\n", tpn->
tpn_canon, tpn->tpn_port, tpn->tpn_proto, tpn->tpn_canon
!= tpn->tpn_host ? ";maddr=" : "", tpn->tpn_canon != tpn
->tpn_host ? tpn->tpn_host : "", tpn->tpn_comp ? ";comp="
: "", tpn->tpn_comp ? tpn->tpn_comp : "", su_strerror(
error))) : (void)0)
;
2264 goto error;
2265 }
2266 else
2267 SU_DEBUG_5(("nta: bound to (%s:%s;transport=%s%s%s%s%s)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 2272, "nta: bound to (%s:%s;transport=%s%s%s%s%s)\n", tpn->
tpn_canon, tpn->tpn_port, tpn->tpn_proto, tpn->tpn_canon
!= tpn->tpn_host ? ";maddr=" : "", tpn->tpn_canon != tpn
->tpn_host ? tpn->tpn_host : "", tpn->tpn_comp ? ";comp="
: "", tpn->tpn_comp ? tpn->tpn_comp : "")) : (void)0)
2268 tpn->tpn_canon, tpn->tpn_port, tpn->tpn_proto,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 2272, "nta: bound to (%s:%s;transport=%s%s%s%s%s)\n", tpn->
tpn_canon, tpn->tpn_port, tpn->tpn_proto, tpn->tpn_canon
!= tpn->tpn_host ? ";maddr=" : "", tpn->tpn_canon != tpn
->tpn_host ? tpn->tpn_host : "", tpn->tpn_comp ? ";comp="
: "", tpn->tpn_comp ? tpn->tpn_comp : "")) : (void)0)
2269 tpn->tpn_canon != tpn->tpn_host ? ";maddr=" : "",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 2272, "nta: bound to (%s:%s;transport=%s%s%s%s%s)\n", tpn->
tpn_canon, tpn->tpn_port, tpn->tpn_proto, tpn->tpn_canon
!= tpn->tpn_host ? ";maddr=" : "", tpn->tpn_canon != tpn
->tpn_host ? tpn->tpn_host : "", tpn->tpn_comp ? ";comp="
: "", tpn->tpn_comp ? tpn->tpn_comp : "")) : (void)0)
2270 tpn->tpn_canon != tpn->tpn_host ? tpn->tpn_host : "",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 2272, "nta: bound to (%s:%s;transport=%s%s%s%s%s)\n", tpn->
tpn_canon, tpn->tpn_port, tpn->tpn_proto, tpn->tpn_canon
!= tpn->tpn_host ? ";maddr=" : "", tpn->tpn_canon != tpn
->tpn_host ? tpn->tpn_host : "", tpn->tpn_comp ? ";comp="
: "", tpn->tpn_comp ? tpn->tpn_comp : "")) : (void)0)
2271 tpn->tpn_comp ? ";comp=" : "",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 2272, "nta: bound to (%s:%s;transport=%s%s%s%s%s)\n", tpn->
tpn_canon, tpn->tpn_port, tpn->tpn_proto, tpn->tpn_canon
!= tpn->tpn_host ? ";maddr=" : "", tpn->tpn_canon != tpn
->tpn_host ? tpn->tpn_host : "", tpn->tpn_comp ? ";comp="
: "", tpn->tpn_comp ? tpn->tpn_comp : "")) : (void)0)
2272 tpn->tpn_comp ? tpn->tpn_comp : ""))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 2272, "nta: bound to (%s:%s;transport=%s%s%s%s%s)\n", tpn->
tpn_canon, tpn->tpn_port, tpn->tpn_proto, tpn->tpn_canon
!= tpn->tpn_host ? ";maddr=" : "", tpn->tpn_canon != tpn
->tpn_host ? tpn->tpn_host : "", tpn->tpn_comp ? ";comp="
: "", tpn->tpn_comp ? tpn->tpn_comp : "")) : (void)0)
;
2273
2274 /* XXX - when to use maddr? */
2275 if ((agent_init_via(self, tport_primaries(self->sa_tports), 0)) < 0) {
2276 error = su_errno();
2277 SU_DEBUG_1(("nta: cannot create Via headers\n" VA_NONE))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 2277, "nta: cannot create Via headers\n" "%s", "")) : (void
)0)
;
2278 goto error;
2279 }
2280 else
2281 SU_DEBUG_9(("nta: Via fields initialized\n" VA_NONE))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__
, 2281, "nta: Via fields initialized\n" "%s", "")) : (void)0)
;
2282
2283 if ((agent_init_contact(self)) < 0) {
2284 error = su_errno();
2285 SU_DEBUG_1(("nta: cannot create Contact header\n" VA_NONE))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 2285, "nta: cannot create Contact header\n" "%s", "")) : (void
)0)
;
2286 goto error;
2287 }
2288 else
2289 SU_DEBUG_9(("nta: Contact header created\n" VA_NONE))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__
, 2289, "nta: Contact header created\n" "%s", "")) : (void)0)
;
2290
2291 su_free(self->sa_home, url);
2292 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))
;
2293
2294 return 0;
2295
2296 error:
2297 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))
;
2298 su_seterrno(error);
2299 return -1;
2300}
2301
2302static
2303int agent_create_master_transport(nta_agent_t *self, tagi_t *tags)
2304{
2305 self->sa_tports =
2306 tport_tcreate(self, nta_agent_class, self->sa_root,
2307 TPTAG_IDLE(1800000)tptag_idle, tag_uint_v((1800000)),
2308 TAG_NEXT(tags)tag_next, (tag_value_t)(tags));
2309
2310 if (!self->sa_tports)
2311 return -1;
2312
2313 SU_DEBUG_9(("nta: master transport created\n" VA_NONE))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__
, 2313, "nta: master transport created\n" "%s", "")) : (void)
0)
;
2314
2315 return 0;
2316}
2317
2318
2319/** Initialize @Via headers. */
2320static
2321int agent_init_via(nta_agent_t *self, tport_t *primaries, int use_maddr)
2322{
2323 sip_via_t *via = NULL((void*)0), *new_via, *dup_via, *v, **vv = &via;
2324 sip_via_t *new_vias, **next_new_via, *new_publics, **next_new_public;
2325 tport_t *tp;
2326 su_addrinfo_t const *ai;
2327
2328 su_home_t autohome[SU_HOME_AUTO_SIZE(2048)(((2048) + ((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))
];
2329
2330 su_home_auto(autohome, sizeof autohome);
2331
2332 self->sa_tport_ip4 = 0;
2333 self->sa_tport_ip6 = 0;
2334 self->sa_tport_udp = 0;
2335 self->sa_tport_tcp = 0;
2336 self->sa_tport_sctp = 0;
2337 self->sa_tport_tls = 0;
2338 self->sa_tport_ws = 0;
2339 self->sa_tport_wss = 0;
2340
2341 /* Set via fields for the tports */
2342 for (tp = primaries; tp; tp = tport_next(tp)) {
2343 int maddr;
2344 tp_name_t tpn[1];
2345 char const *comp = NULL((void*)0);
2346
2347 *tpn = *tport_name(tp);
2348
2349 assert(tpn->tpn_proto)((void) sizeof ((tpn->tpn_proto) ? 1 : 0), __extension__ (
{ if (tpn->tpn_proto) ; else __assert_fail ("tpn->tpn_proto"
, "nta.c", 2349, __extension__ __PRETTY_FUNCTION__); }))
;
2350 assert(tpn->tpn_canon)((void) sizeof ((tpn->tpn_canon) ? 1 : 0), __extension__ (
{ if (tpn->tpn_canon) ; else __assert_fail ("tpn->tpn_canon"
, "nta.c", 2350, __extension__ __PRETTY_FUNCTION__); }))
;
2351 assert(tpn->tpn_host)((void) sizeof ((tpn->tpn_host) ? 1 : 0), __extension__ ({
if (tpn->tpn_host) ; else __assert_fail ("tpn->tpn_host"
, "nta.c", 2351, __extension__ __PRETTY_FUNCTION__); }))
;
2352 assert(tpn->tpn_port)((void) sizeof ((tpn->tpn_port) ? 1 : 0), __extension__ ({
if (tpn->tpn_port) ; else __assert_fail ("tpn->tpn_port"
, "nta.c", 2352, __extension__ __PRETTY_FUNCTION__); }))
;
2353
2354#if 0
2355 if (getenv("SIP_UDP_CONNECT")
2356 && strcmp(tpn->tpn_proto, "udp") == 0)
2357 tport_set_params(tp, TPTAG_CONNECT(1)tptag_connect, tag_bool_v((1)), TAG_END()(tag_type_t)0, (tag_value_t)0);
2358#endif
2359
2360 if (tport_has_ip4(tp)) self->sa_tport_ip4 = 1;
2361
2362#if SU_HAVE_IN61
2363 if (tport_has_ip6(tp)) self->sa_tport_ip6 = 1;
2364#endif
2365
2366 if (su_casematch(tpn->tpn_proto, "udp"))
2367 self->sa_tport_udp = 1;
2368 else if (su_casematch(tpn->tpn_proto, "tcp"))
2369 self->sa_tport_tcp = 1;
2370 else if (su_casematch(tpn->tpn_proto, "sctp"))
2371 self->sa_tport_sctp = 1;
2372 else if (su_casematch(tpn->tpn_proto, "ws"))
2373 self->sa_tport_ws = 1;
2374 else if (su_casematch(tpn->tpn_proto, "wss"))
2375 self->sa_tport_wss = 1;
2376
2377 if (tport_has_tls(tp)) self->sa_tport_tls = 1;
2378
2379 ai = tport_get_address(tp);
2380
2381 for (; ai; ai = ai->ai_next) {
2382 char host[TPORT_HOSTPORTSIZE(55)] = "";
2383 char sport[8];
2384 char const *canon = ai->ai_canonname;
2385 su_sockaddr_t *su = (void *)ai->ai_addr;
2386 int port;
2387
2388 if (su) {
2389 su_inet_ntopinet_ntop(su->su_familysu_sa.sa_family, SU_ADDR(su)((su)->su_sa.sa_family == 2 ? (void *)&(su)->su_sin
.sin_addr : ((su)->su_sa.sa_family == 10 ? (void *)&(su
)->su_sin6.sin6_addr : (void *)&(su)->su_sa.sa_data
))
, host, sizeof host);
2390 maddr = use_maddr && !su_casematch(canon, host);
2391 port = ntohs(su->su_portsu_sin.sin_port);
2392 }
2393 else {
2394 msg_random_token(host, 16, NULL((void*)0), 0);
2395 canon = strcat(host, ".is.invalid");
2396 maddr = 0;
2397 port = 0;
2398 }
2399
2400 if (su_casenmatch(tpn->tpn_proto, "tls", 3)
2401 ? port == SIPS_DEFAULT_PORTSIPS_DEFAULT_PORT
2402 : port == SIP_DEFAULT_PORTSIP_DEFAULT_PORT)
2403 port = 0;
2404
2405 snprintf(sport, sizeof sport, ":%u", port);
2406
2407 comp = tpn->tpn_comp;
2408
2409 SU_DEBUG_9(("nta: agent_init_via: "(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__
, 2415, "nta: agent_init_via: " "%s/%s %s%s%s%s%s%s (%s)\n", sip_version_2_0
, tpn->tpn_proto, canon, port ? sport : "", maddr ? ";maddr="
: "", maddr ? host : "", comp ? ";comp=" : "", comp ? comp :
"", tpn->tpn_ident ? tpn->tpn_ident : "*")) : (void)0)
2410 "%s/%s %s%s%s%s%s%s (%s)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__
, 2415, "nta: agent_init_via: " "%s/%s %s%s%s%s%s%s (%s)\n", sip_version_2_0
, tpn->tpn_proto, canon, port ? sport : "", maddr ? ";maddr="
: "", maddr ? host : "", comp ? ";comp=" : "", comp ? comp :
"", tpn->tpn_ident ? tpn->tpn_ident : "*")) : (void)0)
2411 SIP_VERSION_CURRENT, tpn->tpn_proto,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__
, 2415, "nta: agent_init_via: " "%s/%s %s%s%s%s%s%s (%s)\n", sip_version_2_0
, tpn->tpn_proto, canon, port ? sport : "", maddr ? ";maddr="
: "", maddr ? host : "", comp ? ";comp=" : "", comp ? comp :
"", tpn->tpn_ident ? tpn->tpn_ident : "*")) : (void)0)
2412 canon, port ? sport : "",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__
, 2415, "nta: agent_init_via: " "%s/%s %s%s%s%s%s%s (%s)\n", sip_version_2_0
, tpn->tpn_proto, canon, port ? sport : "", maddr ? ";maddr="
: "", maddr ? host : "", comp ? ";comp=" : "", comp ? comp :
"", tpn->tpn_ident ? tpn->tpn_ident : "*")) : (void)0)
2413 maddr ? ";maddr=" : "", maddr ? host : "",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__
, 2415, "nta: agent_init_via: " "%s/%s %s%s%s%s%s%s (%s)\n", sip_version_2_0
, tpn->tpn_proto, canon, port ? sport : "", maddr ? ";maddr="
: "", maddr ? host : "", comp ? ";comp=" : "", comp ? comp :
"", tpn->tpn_ident ? tpn->tpn_ident : "*")) : (void)0)
2414 comp ? ";comp=" : "", comp ? comp : "",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__
, 2415, "nta: agent_init_via: " "%s/%s %s%s%s%s%s%s (%s)\n", sip_version_2_0
, tpn->tpn_proto, canon, port ? sport : "", maddr ? ";maddr="
: "", maddr ? host : "", comp ? ";comp=" : "", comp ? comp :
"", tpn->tpn_ident ? tpn->tpn_ident : "*")) : (void)0)
2415 tpn->tpn_ident ? tpn->tpn_ident : "*"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__
, 2415, "nta: agent_init_via: " "%s/%s %s%s%s%s%s%s (%s)\n", sip_version_2_0
, tpn->tpn_proto, canon, port ? sport : "", maddr ? ";maddr="
: "", maddr ? host : "", comp ? ";comp=" : "", comp ? comp :
"", tpn->tpn_ident ? tpn->tpn_ident : "*")) : (void)0)
;
2416
2417 v = sip_via_format(autohome,
2418 "%s/%s %s%s%s%s%s%s",
2419 SIP_VERSION_CURRENTsip_version_2_0, tpn->tpn_proto,
2420 canon, port ? sport : "",
2421 maddr ? ";maddr=" : "", maddr ? host : "",
2422 comp ? ";comp=" : "", comp ? comp : "");
2423 if (v == NULL((void*)0))
2424 goto error;
2425
2426 v->v_comment = tpn->tpn_ident;
2427 v->v_common->h_data = tp; /* Nasty trick */
2428 *vv = v; vv = &(*vv)->v_next;
2429 }
2430 }
2431
2432 if (!via) {
2433 SU_DEBUG_9(("nta: agent_init_via failed\n" VA_NONE))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__
, 2433, "nta: agent_init_via failed\n" "%s", "")) : (void)0)
;
2434 goto error;
2435 }
2436
2437 /* Duplicate the list bind to the transports */
2438 new_via = sip_via_dup(self->sa_home, via);
2439 /* Duplicate the complete list shown to the application */
2440 dup_via = sip_via_dup(self->sa_home, via);
2441
2442 if (via && (!new_via || !dup_via)) {
2443 msg_header_free(self->sa_home, (void *)new_via);
2444 msg_header_free(self->sa_home, (void *)dup_via);
2445 goto error;
2446 }
2447
2448 new_vias = NULL((void*)0), next_new_via = &new_vias;
2449 new_publics = NULL((void*)0), next_new_public = &new_publics;
2450
2451 /* Set via field magic for the tports */
2452 for (tp = primaries; tp; tp = tport_next(tp)) {
2453 assert(via->v_common->h_data == tp)((void) sizeof ((via->v_common->h_data == tp) ? 1 : 0),
__extension__ ({ if (via->v_common->h_data == tp) ; else
__assert_fail ("via->v_common->h_data == tp", "nta.c",
2453, __extension__ __PRETTY_FUNCTION__); }))
;
2454 v = tport_magic(tp);
2455 tport_set_magic(tp, new_via);
2456 msg_header_free(self->sa_home, (void *)v);
2457
2458 if (tport_is_public(tp))
2459 *next_new_public = dup_via;
2460 else
2461 *next_new_via = dup_via;
2462
2463 while (via->v_next && via->v_next->v_common->h_data == tp)
2464 via = via->v_next, new_via = new_via->v_next, dup_via = dup_via->v_next;
2465
2466 via = via->v_next;
2467 /* Break the link in via list between transports */
2468 vv = &new_via->v_next, new_via = *vv, *vv = NULL((void*)0);
2469 vv = &dup_via->v_next, dup_via = *vv, *vv = NULL((void*)0);
2470
2471 if (tport_is_public(tp))
2472 while (*next_new_public) next_new_public = &(*next_new_public)->v_next;
2473 else
2474 while (*next_new_via) next_new_via = &(*next_new_via)->v_next;
2475 }
2476
2477 assert(dup_via == NULL)((void) sizeof ((dup_via == ((void*)0)) ? 1 : 0), __extension__
({ if (dup_via == ((void*)0)) ; else __assert_fail ("dup_via == NULL"
, "nta.c", 2477, __extension__ __PRETTY_FUNCTION__); }))
;
2478 assert(new_via == NULL)((void) sizeof ((new_via == ((void*)0)) ? 1 : 0), __extension__
({ if (new_via == ((void*)0)) ; else __assert_fail ("new_via == NULL"
, "nta.c", 2478, __extension__ __PRETTY_FUNCTION__); }))
;
2479
2480 if (self->sa_tport_udp)
2481 agent_set_udp_params(self, self->sa_udp_mtu);
2482
2483 v = self->sa_vias;
2484 self->sa_vias = new_vias;
2485 msg_header_free(self->sa_home, (void *)v);
2486
2487 v = self->sa_public_vias;
2488 self->sa_public_vias = new_publics;
2489 msg_header_free(self->sa_home, (void *)v);
2490
2491 su_home_deinit(autohome);
2492
2493 return 0;
2494
2495 error:
2496 su_home_deinit(autohome);
2497 return -1;
2498}
2499
2500
2501/** Initialize main contact header. */
2502static
2503int agent_init_contact(nta_agent_t *self)
2504{
2505 sip_via_t const *v1, *v2;
2506 char const *tp;
2507
2508 if (self->sa_contact)
2509 return 0;
2510
2511 for (v1 = self->sa_vias ? self->sa_vias : self->sa_public_vias;
2512 v1;
2513 v1 = v1->v_next) {
2514 if (host_is_ip_address(v1->v_host)) {
2515 if (!host_is_local(v1->v_host))
2516 break;
2517 }
2518 else if (!host_has_domain_invalid(v1->v_host)) {
2519 break;
2520 }
2521 }
2522
2523 if (v1 == NULL((void*)0))
2524 v1 = self->sa_vias ? self->sa_vias : self->sa_public_vias;
2525
2526 if (!v1)
2527 return -1;
2528
2529 tp = strrchr(v1->v_protocol, '/');
2530 if (!tp++)
2531 return -1;
2532
2533 v2 = v1->v_next;
2534
2535 if (v2 &&
2536 su_casematch(v1->v_host, v2->v_host) &&
2537 su_casematch(v1->v_port, v2->v_port)) {
2538 char const *p1 = v1->v_protocol, *p2 = v2->v_protocol;
2539
2540 if (!su_casematch(p1, sip_transport_udp))
2541 p1 = v2->v_protocol, p2 = v1->v_protocol;
2542
2543 if (su_casematch(p1, sip_transport_udp) &&
2544 su_casematch(p2, sip_transport_tcp))
2545 /* Do not include transport if we have both UDP and TCP */
2546 tp = NULL((void*)0);
2547 }
2548
2549 self->sa_contact =
2550 sip_contact_create_from_via_with_transport(self->sa_home, v1, NULL((void*)0), tp);
2551
2552 if (!self->sa_contact)
2553 return -1;
2554
2555 agent_tag_init(self);
2556
2557 return 0;
2558}
2559
2560/** Return @Via line corresponging to tport. */
2561static
2562sip_via_t const *agent_tport_via(tport_t *tport)
2563{
2564 sip_via_t *v = tport_magic(tport);
2565 while (v && v->v_next)
2566 v = v->v_next;
2567 return v;
2568}
2569
2570/** Insert @Via to a request message */
2571static
2572int outgoing_insert_via(nta_outgoing_t *orq,
2573 sip_via_t const *via)
2574{
2575 nta_agent_t *self = orq->orq_agent;
2576 msg_t *msg = orq->orq_request;
2577 sip_t *sip = sip_object(msg);
2578 char const *branch = orq->orq_via_branch;
2579 int already = orq->orq_user_via || orq->orq_via_added;
2580 int user_via = orq->orq_user_via;
2581 sip_via_t *v;
2582 int clear = 0;
2583
2584 assert(sip)((void) sizeof ((sip) ? 1 : 0), __extension__ ({ if (sip) ; else
__assert_fail ("sip", "nta.c", 2584, __extension__ __PRETTY_FUNCTION__
); }))
; assert(via)((void) sizeof ((via) ? 1 : 0), __extension__ ({ if (via) ; else
__assert_fail ("via", "nta.c", 2584, __extension__ __PRETTY_FUNCTION__
); }))
;
2585
2586 if (already && sip->sip_via) {
2587 /* Use existing @Via */
2588 v = sip->sip_via;
2589 }
2590 else if (msg && via && sip->sip_request &&
2591 (v = sip_via_copy(msg_home(msg)((su_home_t*)(msg)), via))) {
2592 if (msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)v) < 0)
2593 return -1;
2594 orq->orq_via_added = 1;
2595 }
2596 else
2597 return -1;
2598
2599 if (!v->v_rport &&
2600 ((self->sa_rport && v->v_protocol == sip_transport_udp) ||
2601 (self->sa_tcp_rport && v->v_protocol == sip_transport_tcp) ||
2602 (self->sa_tls_rport && v->v_protocol == sip_transport_tls)))
2603 msg_header_add_param(msg_home(msg)((su_home_t*)(msg)), v->v_common, "rport");
2604
2605 if (!orq->orq_tpn->tpn_comp)
2606 msg_header_remove_param(v->v_common, "comp");
2607
2608 if (branch && branch != v->v_branch) {
2609 char const *bvalue = branch + strcspn(branch, "=");
2610 if (*bvalue) bvalue++;
2611 if (!v->v_branch || !su_casematch(bvalue, v->v_branch))
2612 msg_header_replace_param(msg_home(msg)((su_home_t*)(msg)), v->v_common, branch);
2613 }
2614
2615 if (!su_casematch(via->v_protocol, v->v_protocol))
2616 clear = 1, v->v_protocol = via->v_protocol;
2617
2618 /* XXX - should we do this? */
2619 if ((!user_via || !v->v_host) &&
2620 !su_strmatch(via->v_host, v->v_host))
2621 clear = 1, v->v_host = via->v_host;
2622
2623 if ((!user_via || !v->v_port ||
2624 /* Replace port in user Via only if we use udp and no rport */
2625 (v->v_protocol == sip_transport_udp && !v->v_rport &&
2626 !orq->orq_stateless)) &&
2627 !su_strmatch(via->v_port, v->v_port))
2628 clear = 1, v->v_port = via->v_port;
2629
2630 if (clear)
2631 msg_fragment_clear(v->v_common);
2632
2633 return 0;
2634}
2635
2636/** Get destination name from @Via.
2637 *
2638 * If @a using_rport is non-null, try rport.
2639 * If *using_rport is non-zero, try rport even if <protocol> is not UDP.
2640 * If <protocol> is UDP, set *using_rport to zero.
2641 */
2642static
2643int nta_tpn_by_via(tp_name_t *tpn, sip_via_t const *v, int *using_rport)
2644{
2645 if (!v)
2646 return -1;
2647
2648 tpn->tpn_proto = sip_via_transport(v);
2649 tpn->tpn_canon = v->v_host;
2650
2651 if (v->v_maddr)
2652 tpn->tpn_host = v->v_maddr;
2653 else if (v->v_received)
2654 tpn->tpn_host = v->v_received;
2655 else
2656 tpn->tpn_host = v->v_host;
2657
2658 tpn->tpn_port = sip_via_port(v, using_rport);
2659 tpn->tpn_comp = v->v_comp;
2660 tpn->tpn_ident = NULL((void*)0);
2661
2662 return 0;
2663}
2664
2665/** Get transport name from URL. */
2666static int
2667nta_tpn_by_url(su_home_t *home,
2668 tp_name_t *tpn,
2669 char const **scheme,
2670 char const **port,
2671 url_string_t const *us)
2672{
2673 url_t url[1];
2674 isize_t n;
2675 char *b;
2676
2677 n = url_xtra(us->us_url);
2678 b = su_alloc(home, n);
2679
2680 if (b == NULL((void*)0) || url_dup(b, n, url, us->us_url) < 0) {
2681 su_free(home, b);
2682 return -1;
2683 }
2684
2685 if (url->url_type != url_sip &&
2686 url->url_type != url_urn &&
2687 url->url_type != url_sips &&
2688 url->url_type != url_im &&
2689 url->url_type != url_pres) {
2690 su_free(home, b);
2691 return -1;
2692 }
2693
2694 SU_DEBUG_7(("nta: selecting scheme %s\n", url->url_scheme))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__
, 2694, "nta: selecting scheme %s\n", url->url_scheme)) : (
void)0)
;
2695
2696 *scheme = url->url_scheme;
2697
2698 tpn->tpn_proto = NULL((void*)0);
2699 tpn->tpn_canon = url->url_host;
2700 tpn->tpn_host = url->url_host;
2701
2702 if (url->url_params) {
2703 for (b = (char *)url->url_params; b[0]; b += n) {
2704 n = strcspn(b, ";");
2705
2706 if (n > 10 && su_casenmatch(b, "transport=", 10))
2707 tpn->tpn_proto = b + 10;
2708 else if (n > 5 && su_casenmatch(b, "comp=", 5))
2709 tpn->tpn_comp = b + 5;
2710 else if (n > 6 && su_casenmatch(b, "maddr=", 6))
2711 tpn->tpn_host = b + 6;
2712
2713 if (b[n])
2714 b[n++] = '\0';
2715 }
2716 }
2717
2718 if ((*port = url->url_port))
2719 tpn->tpn_port = url->url_port;
2720
2721 tpn->tpn_ident = NULL((void*)0);
2722
2723 if (tpn->tpn_proto) {
2724 if (su_casematch(url->url_scheme, "sips") && su_casematch(tpn->tpn_proto, "ws")) {
2725 tpn->tpn_proto = "wss";
2726 }
2727 return 1;
2728 }
2729
2730 if (su_casematch(url->url_scheme, "sips"))
2731 tpn->tpn_proto = "tls";
2732 else
2733 tpn->tpn_proto = "*";
2734
2735 return 0;
2736}
2737
2738/** Handle transport errors. */
2739static
2740void agent_tp_error(nta_agent_t *agent,
2741 tport_t *tport,
2742 int errcode,
2743 char const *remote)
2744{
2745 su_llog(nta_log, 1,_su_llog(nta_log, 1, "nta.c", (const char *)__func__, 2748, "nta_agent: tport: %s%s%s\n"
, remote ? remote : "", remote ? ": " : "", su_strerror(errcode
))
2746 "nta_agent: tport: %s%s%s\n",_su_llog(nta_log, 1, "nta.c", (const char *)__func__, 2748, "nta_agent: tport: %s%s%s\n"
, remote ? remote : "", remote ? ": " : "", su_strerror(errcode
))
2747 remote ? remote : "", remote ? ": " : "",_su_llog(nta_log, 1, "nta.c", (const char *)__func__, 2748, "nta_agent: tport: %s%s%s\n"
, remote ? remote : "", remote ? ": " : "", su_strerror(errcode
))
2748 su_strerror(errcode))_su_llog(nta_log, 1, "nta.c", (const char *)__func__, 2748, "nta_agent: tport: %s%s%s\n"
, remote ? remote : "", remote ? ": " : "", su_strerror(errcode
))
;
2749
2750 if (agent->sa_error_tport) {
2751 agent->sa_error_tport(agent->sa_error_magic, agent, tport);
2752 }
2753}
2754
2755/** Handle updated transport addresses */
2756static void agent_update_tport(nta_agent_t *self, tport_t *tport)
2757{
2758 /* Initialize local Vias first */
2759 agent_init_via(self, tport_primaries(self->sa_tports), 0);
2760
2761 if (self->sa_update_tport) {
2762 self->sa_update_tport(self->sa_update_magic, self);
2763 }
2764 else {
2765 /* XXX - we should do something else? */
2766 SU_DEBUG_3(("%s(%p): %s\n", "nta", (void *)self,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 2767, "%s(%p): %s\n", "nta", (void *)self, "transport address updated"
)) : (void)0)
2767 "transport address updated"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 2767, "%s(%p): %s\n", "nta", (void *)self, "transport address updated"
)) : (void)0)
;
2768 }
2769}
2770
2771/* ====================================================================== */
2772/* 3) Message dispatch */
2773
2774static void agent_recv_request(nta_agent_t *agent,
2775 msg_t *msg,
2776 sip_t *sip,
2777 tport_t *tport);
2778static int agent_check_request_via(nta_agent_t *agent,
2779 msg_t *msg,
2780 sip_t *sip,
2781 sip_via_t *v,
2782 tport_t *tport);
2783static int agent_aliases(nta_agent_t const *, url_t [], tport_t *);
2784static void agent_recv_response(nta_agent_t*, msg_t *, sip_t *,
2785 sip_via_t *, tport_t*);
2786static void agent_recv_garbage(nta_agent_t*, msg_t*, tport_t*);
2787
2788#if HAVE_SOFIA_SRESOLV1
2789static void outgoing_resolve(nta_outgoing_t *orq,
2790 int explicit_transport,
2791 enum nta_res_order_e order);
2792su_inlinestatic inline void outgoing_cancel_resolver(nta_outgoing_t *orq);
2793su_inlinestatic inline void outgoing_destroy_resolver(nta_outgoing_t *orq);
2794static int outgoing_other_destinations(nta_outgoing_t const *orq);
2795static int outgoing_try_another(nta_outgoing_t *orq);
2796#else
2797#define outgoing_other_destinations(orq) (0)
2798#define outgoing_try_another(orq) (0)
2799#endif
2800
2801/** Handle incoming message. */
2802static
2803void agent_recv_message(nta_agent_t *agent,
2804 tport_t *tport,
2805 msg_t *msg,
2806 sip_via_t *tport_via,
2807 su_time_t now)
2808{
2809 sip_t *sip = sip_object(msg);
2810
2811 if (sip && sip->sip_request) {
2812 agent_recv_request(agent, msg, sip, tport);
2813 }
2814 else if (sip && sip->sip_status) {
2815 agent_recv_response(agent, msg, sip, tport_via, tport);
2816 }
2817 else {
2818 agent_recv_garbage(agent, msg, tport);
2819 }
2820}
2821
2822#ifdef HAVE_ZLIB_COMPRESS1
2823int sip_content_encoding_Xflate(msg_t *msg, sip_t *sip, int inflate, int check)
2824{
2825 char const *method_name;
2826 unsigned cseq = sip->sip_cseq ? sip->sip_cseq->cs_seq : 0;
13
'?' condition is false
2827 int ok = !check;
2828
2829 if (!sip->sip_payload) {
14
Assuming the condition is true
15
Taking true branch
2830 return 0;
16
Returning without writing to 'sip->sip_cseq'
2831 }
2832
2833 if (sip->sip_request) {
2834 method_name = sip->sip_request->rq_method_name;
2835 } else if (sip->sip_cseq) {
2836 method_name = sip->sip_cseq->cs_method_name;
2837 } else {
2838 method_name = "Unknown";
2839 }
2840
2841 if (!ok) {
2842 if (sip->sip_content_encoding && sip->sip_content_encoding->k_items) {
2843 const char *val = sip->sip_content_encoding->k_items[0];
2844 if (val && (!strcasecmp(val, "gzip") || !strcasecmp(val, "deflate"))) {
2845 ok = 1;
2846 }
2847 }
2848 }
2849
2850 if (ok) {
2851 unsigned long n = 0;
2852 void *decoded = NULL((void*)0);
2853 const char *id = "N/A";
2854 const char *orig_payload = sip->sip_payload->pl_data;
2855
2856 n = sip->sip_payload->pl_len * 10;
2857
2858 decoded = su_alloc(msg_home(msg)((su_home_t*)(msg)), n);
2859 assert(decoded)((void) sizeof ((decoded) ? 1 : 0), __extension__ ({ if (decoded
) ; else __assert_fail ("decoded", "nta.c", 2859, __extension__
__PRETTY_FUNCTION__); }))
;
2860
2861 if (inflate) {
2862 uncompress(decoded, &n, (void *)sip->sip_payload->pl_data, (unsigned long)sip->sip_payload->pl_len);
2863 } else {
2864 compress(decoded, &n, (void *)sip->sip_payload->pl_data, (unsigned long)sip->sip_payload->pl_len);
2865 }
2866
2867 sip->sip_payload = sip_payload_create(msg_home(msg)((su_home_t*)(msg)), decoded, n);
2868 sip->sip_content_encoding = sip_content_encoding_make(msg_home(msg)((su_home_t*)(msg)), "deflate");
2869
2870 if (sip->sip_call_id) {
2871 id = sip->sip_call_id->i_id;
2872 }
2873
2874 if (inflate) {
2875 SU_DEBUG_1(("nta: %s (%u) (%s) Inflating compressed body:\n%s\n", method_name, cseq, id, (char *)decoded))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 2875, "nta: %s (%u) (%s) Inflating compressed body:\n%s\n",
method_name, cseq, id, (char *)decoded)) : (void)0)
;
2876 } else {
2877 SU_DEBUG_1(("nta: %s (%u) (%s) Deflating compressed body:\n%s\n", method_name, cseq, id, orig_payload))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 2877, "nta: %s (%u) (%s) Deflating compressed body:\n%s\n",
method_name, cseq, id, orig_payload)) : (void)0)
;
2878 }
2879
2880 return 1;
2881 }
2882
2883 return 0;
2884}
2885#endif
2886
2887/** @internal Handle incoming requests. */
2888static
2889void agent_recv_request(nta_agent_t *agent,
2890 msg_t *msg,
2891 sip_t *sip,
2892 tport_t *tport)
2893{
2894 nta_leg_t *leg;
2895 nta_incoming_t *irq, *merge = NULL((void*)0), *ack = NULL((void*)0), *cancel = NULL((void*)0);
2896 sip_method_t method = sip->sip_request->rq_method;
2897 char const *method_name = sip->sip_request->rq_method_name;
2898 url_t url[1];
2899 unsigned cseq = sip->sip_cseq ? sip->sip_cseq->cs_seq : 0;
2900 int insane, errors, stream;
2901 unsigned compressed = 0;
2902
2903 agent->sa_stats->as_recv_msg++;
2904 agent->sa_stats->as_recv_request++;
2905
2906 SU_DEBUG_5(("nta: received %s " URL_PRINT_FORMAT " %s (CSeq %u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 2909, "nta: received %s " "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
" %s (CSeq %u)\n", method_name, (sip->sip_request->rq_url
)->url_scheme ? (sip->sip_request->rq_url)->url_scheme
: "", (sip->sip_request->rq_url)->url_type != url_any
&& (sip->sip_request->rq_url)->url_scheme &&
(sip->sip_request->rq_url)->url_scheme[0] ? ":" : ""
, (sip->sip_request->rq_url)->url_root && ((
sip->sip_request->rq_url)->url_host || (sip->sip_request
->rq_url)->url_user) ? "//" : "", (sip->sip_request->
rq_url)->url_user ? (sip->sip_request->rq_url)->url_user
: "", (sip->sip_request->rq_url)->url_user &&
(sip->sip_request->rq_url)->url_password ? ":" : ""
, (sip->sip_request->rq_url)->url_user && (sip
->sip_request->rq_url)->url_password ? (sip->sip_request
->rq_url)->url_password : "", (sip->sip_request->
rq_url)->url_user && (sip->sip_request->rq_url
)->url_host ? "@" : "", (sip->sip_request->rq_url)->
url_host ? (sip->sip_request->rq_url)->url_host : ""
, (sip->sip_request->rq_url)->url_host && (sip
->sip_request->rq_url)->url_port ? ":" : "", (sip->
sip_request->rq_url)->url_host && (sip->sip_request
->rq_url)->url_port ? (sip->sip_request->rq_url)->
url_port : "", (sip->sip_request->rq_url)->url_root &&
(sip->sip_request->rq_url)->url_path ? "/" : "", (sip
->sip_request->rq_url)->url_path ? (sip->sip_request
->rq_url)->url_path : "", (sip->sip_request->rq_url
)->url_params ? ";" : "", (sip->sip_request->rq_url)
->url_params ? (sip->sip_request->rq_url)->url_params
: "", (sip->sip_request->rq_url)->url_headers ? "?"
: "", (sip->sip_request->rq_url)->url_headers ? (sip
->sip_request->rq_url)->url_headers : "", (sip->sip_request
->rq_url)->url_fragment ? "#" : "", (sip->sip_request
->rq_url)->url_fragment ? (sip->sip_request->rq_url
)->url_fragment : "", sip->sip_request->rq_version, cseq
)) : (void)0)
2907 method_name,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 2909, "nta: received %s " "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
" %s (CSeq %u)\n", method_name, (sip->sip_request->rq_url
)->url_scheme ? (sip->sip_request->rq_url)->url_scheme
: "", (sip->sip_request->rq_url)->url_type != url_any
&& (sip->sip_request->rq_url)->url_scheme &&
(sip->sip_request->rq_url)->url_scheme[0] ? ":" : ""
, (sip->sip_request->rq_url)->url_root && ((
sip->sip_request->rq_url)->url_host || (sip->sip_request
->rq_url)->url_user) ? "//" : "", (sip->sip_request->
rq_url)->url_user ? (sip->sip_request->rq_url)->url_user
: "", (sip->sip_request->rq_url)->url_user &&
(sip->sip_request->rq_url)->url_password ? ":" : ""
, (sip->sip_request->rq_url)->url_user && (sip
->sip_request->rq_url)->url_password ? (sip->sip_request
->rq_url)->url_password : "", (sip->sip_request->
rq_url)->url_user && (sip->sip_request->rq_url
)->url_host ? "@" : "", (sip->sip_request->rq_url)->
url_host ? (sip->sip_request->rq_url)->url_host : ""
, (sip->sip_request->rq_url)->url_host && (sip
->sip_request->rq_url)->url_port ? ":" : "", (sip->
sip_request->rq_url)->url_host && (sip->sip_request
->rq_url)->url_port ? (sip->sip_request->rq_url)->
url_port : "", (sip->sip_request->rq_url)->url_root &&
(sip->sip_request->rq_url)->url_path ? "/" : "", (sip
->sip_request->rq_url)->url_path ? (sip->sip_request
->rq_url)->url_path : "", (sip->sip_request->rq_url
)->url_params ? ";" : "", (sip->sip_request->rq_url)
->url_params ? (sip->sip_request->rq_url)->url_params
: "", (sip->sip_request->rq_url)->url_headers ? "?"
: "", (sip->sip_request->rq_url)->url_headers ? (sip
->sip_request->rq_url)->url_headers : "", (sip->sip_request
->rq_url)->url_fragment ? "#" : "", (sip->sip_request
->rq_url)->url_fragment ? (sip->sip_request->rq_url
)->url_fragment : "", sip->sip_request->rq_version, cseq
)) : (void)0)
2908 URL_PRINT_ARGS(sip->sip_request->rq_url),(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 2909, "nta: received %s " "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
" %s (CSeq %u)\n", method_name, (sip->sip_request->rq_url
)->url_scheme ? (sip->sip_request->rq_url)->url_scheme
: "", (sip->sip_request->rq_url)->url_type != url_any
&& (sip->sip_request->rq_url)->url_scheme &&
(sip->sip_request->rq_url)->url_scheme[0] ? ":" : ""
, (sip->sip_request->rq_url)->url_root && ((
sip->sip_request->rq_url)->url_host || (sip->sip_request
->rq_url)->url_user) ? "//" : "", (sip->sip_request->
rq_url)->url_user ? (sip->sip_request->rq_url)->url_user
: "", (sip->sip_request->rq_url)->url_user &&
(sip->sip_request->rq_url)->url_password ? ":" : ""
, (sip->sip_request->rq_url)->url_user && (sip
->sip_request->rq_url)->url_password ? (sip->sip_request
->rq_url)->url_password : "", (sip->sip_request->
rq_url)->url_user && (sip->sip_request->rq_url
)->url_host ? "@" : "", (sip->sip_request->rq_url)->
url_host ? (sip->sip_request->rq_url)->url_host : ""
, (sip->sip_request->rq_url)->url_host && (sip
->sip_request->rq_url)->url_port ? ":" : "", (sip->
sip_request->rq_url)->url_host && (sip->sip_request
->rq_url)->url_port ? (sip->sip_request->rq_url)->
url_port : "", (sip->sip_request->rq_url)->url_root &&
(sip->sip_request->rq_url)->url_path ? "/" : "", (sip
->sip_request->rq_url)->url_path ? (sip->sip_request
->rq_url)->url_path : "", (sip->sip_request->rq_url
)->url_params ? ";" : "", (sip->sip_request->rq_url)
->url_params ? (sip->sip_request->rq_url)->url_params
: "", (sip->sip_request->rq_url)->url_headers ? "?"
: "", (sip->sip_request->rq_url)->url_headers ? (sip
->sip_request->rq_url)->url_headers : "", (sip->sip_request
->rq_url)->url_fragment ? "#" : "", (sip->sip_request
->rq_url)->url_fragment ? (sip->sip_request->rq_url
)->url_fragment : "", sip->sip_request->rq_version, cseq
)) : (void)0)
2909 sip->sip_request->rq_version, cseq))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 2909, "nta: received %s " "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
" %s (CSeq %u)\n", method_name, (sip->sip_request->rq_url
)->url_scheme ? (sip->sip_request->rq_url)->url_scheme
: "", (sip->sip_request->rq_url)->url_type != url_any
&& (sip->sip_request->rq_url)->url_scheme &&
(sip->sip_request->rq_url)->url_scheme[0] ? ":" : ""
, (sip->sip_request->rq_url)->url_root && ((
sip->sip_request->rq_url)->url_host || (sip->sip_request
->rq_url)->url_user) ? "//" : "", (sip->sip_request->
rq_url)->url_user ? (sip->sip_request->rq_url)->url_user
: "", (sip->sip_request->rq_url)->url_user &&
(sip->sip_request->rq_url)->url_password ? ":" : ""
, (sip->sip_request->rq_url)->url_user && (sip
->sip_request->rq_url)->url_password ? (sip->sip_request
->rq_url)->url_password : "", (sip->sip_request->
rq_url)->url_user && (sip->sip_request->rq_url
)->url_host ? "@" : "", (sip->sip_request->rq_url)->
url_host ? (sip->sip_request->rq_url)->url_host : ""
, (sip->sip_request->rq_url)->url_host && (sip
->sip_request->rq_url)->url_port ? ":" : "", (sip->
sip_request->rq_url)->url_host && (sip->sip_request
->rq_url)->url_port ? (sip->sip_request->rq_url)->
url_port : "", (sip->sip_request->rq_url)->url_root &&
(sip->sip_request->rq_url)->url_path ? "/" : "", (sip
->sip_request->rq_url)->url_path ? (sip->sip_request
->rq_url)->url_path : "", (sip->sip_request->rq_url
)->url_params ? ";" : "", (sip->sip_request->rq_url)
->url_params ? (sip->sip_request->rq_url)->url_params
: "", (sip->sip_request->rq_url)->url_headers ? "?"
: "", (sip->sip_request->rq_url)->url_headers ? (sip
->sip_request->rq_url)->url_headers : "", (sip->sip_request
->rq_url)->url_fragment ? "#" : "", (sip->sip_request
->rq_url)->url_fragment ? (sip->sip_request->rq_url
)->url_fragment : "", sip->sip_request->rq_version, cseq
)) : (void)0)
;
2910
2911 if (agent->sa_drop_prob && !tport_is_reliable(tport)) {
2912 if ((unsigned)su_randint(0, 1000) < agent->sa_drop_prob) {
2913 SU_DEBUG_5(("nta: %s (%u) is %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 2914, "nta: %s (%u) is %s\n", method_name, cseq, "dropped simulating packet loss"
)) : (void)0)
2914 method_name, cseq, "dropped simulating packet loss"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 2914, "nta: %s (%u) is %s\n", method_name, cseq, "dropped simulating packet loss"
)) : (void)0)
;
2915 agent->sa_stats->as_drop_request++;
2916 msg_destroy(msg);
2917 return;
2918 }
2919 }
2920
2921 stream = tport_is_stream(tport);
2922
2923 /* Try to use compression on reverse direction if @Via has comp=sigcomp */
2924 if (stream &&
2925 sip->sip_via && sip->sip_via->v_comp &&
2926 tport_can_send_sigcomp(tport) &&
2927 tport_name(tport)->tpn_comp == NULL((void*)0) &&
2928 tport_has_compression(tport_parent(tport), sip->sip_via->v_comp)) {
2929 tport_set_compression(tport, sip->sip_via->v_comp);
2930 }
2931
2932 if (sip->sip_flags & MSG_FLG_TOOLARGE) {
2933 SU_DEBUG_5(("nta: %s (%u) is %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 2934, "nta: %s (%u) is %s\n", method_name, cseq, sip_413_Request_too_large
)) : (void)0)
2934 method_name, cseq, sip_413_Request_too_large))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 2934, "nta: %s (%u) is %s\n", method_name, cseq, sip_413_Request_too_large
)) : (void)0)
;
2935 agent->sa_stats->as_bad_request++;
2936 mreply(agent, NULL((void*)0), SIP_413_REQUEST_TOO_LARGE413, sip_413_Request_too_large, msg,
2937 tport, 1, stream, NULL((void*)0),
2938 TAG_END()(tag_type_t)0, (tag_value_t)0);
2939 return;
2940 }
2941
2942 insane = 0;
2943
2944 if (agent->sa_bad_req_mask != ~0U)
2945 errors = msg_extract_errors(msg) & agent->sa_bad_req_mask;
2946 else
2947 errors = sip->sip_error != NULL((void*)0);
2948
2949 if (errors ||
2950 (sip->sip_flags & MSG_FLG_ERROR) /* Fatal error */ ||
2951 (insane = (sip_sanity_check(sip) < 0))) {
2952 sip_header_t const *h;
2953 char const *badname = NULL((void*)0), *phrase;
2954
2955 agent->sa_stats->as_bad_message++;
2956 agent->sa_stats->as_bad_request++;
2957
2958 if (insane)
2959 SU_DEBUG_5(("nta: %s (%u) %s\n", method_name, cseq,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 2960, "nta: %s (%u) %s\n", method_name, cseq, "failed sanity check"
)) : (void)0)
2960 "failed sanity check"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 2960, "nta: %s (%u) %s\n", method_name, cseq, "failed sanity check"
)) : (void)0)
;
2961
2962 for (h = (sip_header_t const *)sip->sip_error; h; h = h->sh_nextsh_header_next->shn_next) {
2963 char const *bad;
2964
2965 if (h->sh_classsh_common->h_class == sip_error_class)
2966 bad = h->sh_error->er_name;
2967 else
2968 bad = h->sh_classsh_common->h_class->hc_name;
2969
2970 if (bad)
2971 SU_DEBUG_5(("nta: %s has bad %s header\n", method_name, bad))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 2971, "nta: %s has bad %s header\n", method_name, bad)) : (
void)0)
;
2972
2973 if (!badname)
2974 badname = bad;
2975 }
2976
2977 if (sip->sip_via && method != sip_method_ack) {
2978 msg_t *reply = nta_msg_create(agent, 0);
2979
2980 agent_check_request_via(agent, msg, sip, sip->sip_via, tport);
2981
2982 if (badname && reply)
2983 phrase = su_sprintf(msg_home(reply)((su_home_t*)(reply)), "Bad %s Header", badname);
2984 else
2985 phrase = sip_400_Bad_request;
2986
2987 SU_DEBUG_5(("nta: %s (%u) is %s\n", method_name, cseq, phrase))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 2987, "nta: %s (%u) is %s\n", method_name, cseq, phrase)) :
(void)0)
;
2988
2989 mreply(agent, reply, 400, phrase, msg,
2990 tport, 1, stream, NULL((void*)0),
2991 TAG_END()(tag_type_t)0, (tag_value_t)0);
2992 }
2993 else {
2994 msg_destroy(msg);
2995 if (stream) /* Send FIN */
2996 tport_shutdown(tport, 1);
2997 }
2998
2999 return;
3000 }
3001
3002 if (!su_casematch(sip->sip_request->rq_version, sip_version_2_0)) {
3003 agent->sa_stats->as_bad_request++;
3004 agent->sa_stats->as_bad_message++;
3005
3006 SU_DEBUG_5(("nta: bad version %s for %s (%u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3007, "nta: bad version %s for %s (%u)\n", sip->sip_request
->rq_version, method_name, cseq)) : (void)0)
3007 sip->sip_request->rq_version, method_name, cseq))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3007, "nta: bad version %s for %s (%u)\n", sip->sip_request
->rq_version, method_name, cseq)) : (void)0)
;
3008
3009 mreply(agent, NULL((void*)0), SIP_505_VERSION_NOT_SUPPORTED505, sip_505_Version_not_supported, msg,
3010 tport, 0, stream, NULL((void*)0),
3011 TAG_END()(tag_type_t)0, (tag_value_t)0);
3012
3013 return;
3014 }
3015
3016 if (agent_check_request_via(agent, msg, sip, sip->sip_via, tport) < 0) {
3017 agent->sa_stats->as_bad_message++;
3018 agent->sa_stats->as_bad_request++;
3019 SU_DEBUG_5(("nta: %s (%u) %s\n", method_name, cseq, "has invalid Via"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3019, "nta: %s (%u) %s\n", method_name, cseq, "has invalid Via"
)) : (void)0)
;
3020 msg_destroy(msg);
3021 return;
3022 }
3023
3024#ifdef HAVE_ZLIB_COMPRESS1
3025 compressed = sip_content_encoding_Xflate(msg, sip, 1, 1);
3026#endif
3027
3028 /* First, try existing incoming requests */
3029 irq = incoming_find(agent, sip, sip->sip_via,
3030 agent->sa_merge_482 &&
3031 !sip->sip_to->a_tag &&
3032 method != sip_method_ack
3033 ? &merge
3034 : NULL((void*)0),
3035 method == sip_method_ack ? &ack : NULL((void*)0),
3036 method == sip_method_cancel ? &cancel : NULL((void*)0));
3037
3038 if (irq) {
3039 /* Match - this is a retransmission */
3040 SU_DEBUG_5(("nta: %s (%u) going to existing %s transaction\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3041, "nta: %s (%u) going to existing %s transaction\n", method_name
, cseq, irq->irq_rq->rq_method_name)) : (void)0)
3041 method_name, cseq, irq->irq_rq->rq_method_name))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3041, "nta: %s (%u) going to existing %s transaction\n", method_name
, cseq, irq->irq_rq->rq_method_name)) : (void)0)
;
3042 if (incoming_recv(irq, msg, sip, tport) >= 0)
3043 return;
3044 }
3045 else if (ack) {
3046 SU_DEBUG_5(("nta: %s (%u) is going to %s (%u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3048, "nta: %s (%u) is going to %s (%u)\n", method_name, cseq
, ack->irq_cseq->cs_method_name, ack->irq_cseq->cs_seq
)) : (void)0)
3047 method_name, cseq,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3048, "nta: %s (%u) is going to %s (%u)\n", method_name, cseq
, ack->irq_cseq->cs_method_name, ack->irq_cseq->cs_seq
)) : (void)0)
3048 ack->irq_cseq->cs_method_name, ack->irq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3048, "nta: %s (%u) is going to %s (%u)\n", method_name, cseq
, ack->irq_cseq->cs_method_name, ack->irq_cseq->cs_seq
)) : (void)0)
;
3049 if (incoming_ack(ack, msg, sip, tport) >= 0)
3050 return;
3051 }
3052 else if (cancel) {
3053 SU_DEBUG_5(("nta: %s (%u) is going to %s (%u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3055, "nta: %s (%u) is going to %s (%u)\n", method_name, cseq
, cancel->irq_cseq->cs_method_name, cancel->irq_cseq
->cs_seq)) : (void)0)
3054 method_name, cseq,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3055, "nta: %s (%u) is going to %s (%u)\n", method_name, cseq
, cancel->irq_cseq->cs_method_name, cancel->irq_cseq
->cs_seq)) : (void)0)
3055 cancel->irq_cseq->cs_method_name, cancel->irq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3055, "nta: %s (%u) is going to %s (%u)\n", method_name, cseq
, cancel->irq_cseq->cs_method_name, cancel->irq_cseq
->cs_seq)) : (void)0)
;
3056 if (incoming_cancel(cancel, msg, sip, tport) >= 0)
3057 return;
3058 }
3059 else if (merge) {
3060 SU_DEBUG_5(("nta: %s (%u) %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3061, "nta: %s (%u) %s\n", method_name, cseq, "is a merged request"
)) : (void)0)
3061 method_name, cseq, "is a merged request"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3061, "nta: %s (%u) %s\n", method_name, cseq, "is a merged request"
)) : (void)0)
;
3062 request_merge(agent, msg, sip, tport, merge->irq_tag);
3063 return;
3064 }
3065
3066 if (method == sip_method_prack && sip->sip_rack) {
3067 nta_reliable_t *rel = reliable_find(agent, sip);
3068 if (rel) {
3069 SU_DEBUG_5(("nta: %s (%u) is going to %s (%u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3072, "nta: %s (%u) is going to %s (%u)\n", method_name, cseq
, rel->rel_irq->irq_cseq->cs_method_name, rel->rel_irq
->irq_cseq->cs_seq)) : (void)0)
3070 method_name, cseq,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3072, "nta: %s (%u) is going to %s (%u)\n", method_name, cseq
, rel->rel_irq->irq_cseq->cs_method_name, rel->rel_irq
->irq_cseq->cs_seq)) : (void)0)
3071 rel->rel_irq->irq_cseq->cs_method_name,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3072, "nta: %s (%u) is going to %s (%u)\n", method_name, cseq
, rel->rel_irq->irq_cseq->cs_method_name, rel->rel_irq
->irq_cseq->cs_seq)) : (void)0)
3072 rel->rel_irq->irq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3072, "nta: %s (%u) is going to %s (%u)\n", method_name, cseq
, rel->rel_irq->irq_cseq->cs_method_name, rel->rel_irq
->irq_cseq->cs_seq)) : (void)0)
;
3073 reliable_recv(rel, msg, sip, tport);
3074 return;
3075 }
3076 }
3077
3078 *url = *sip->sip_request->rq_url;
3079 url->url_params = NULL((void*)0);
3080 agent_aliases(agent, url, tport); /* canonize urls */
3081
3082 if (method != sip_method_subscribe && (leg = leg_find(agent,
3083 method_name, url,
3084 sip->sip_call_id,
3085 sip->sip_from->a_tag,
3086 sip->sip_to->a_tag))) {
3087 /* Try existing dialog */
3088 SU_DEBUG_5(("nta: %s (%u) %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3089, "nta: %s (%u) %s\n", method_name, cseq, "going to existing leg"
)) : (void)0)
3089 method_name, cseq, "going to existing leg"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3089, "nta: %s (%u) %s\n", method_name, cseq, "going to existing leg"
)) : (void)0)
;
3090 leg->leg_compressed = compressed;
3091 leg_recv(leg, msg, sip, tport);
3092 return;
3093 }
3094 else if (!agent->sa_is_stateless &&
3095 (leg = dst_find(agent, url, method_name))) {
3096 /* Dialogless legs - let application process transactions statefully */
3097 SU_DEBUG_5(("nta: %s (%u) %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3098, "nta: %s (%u) %s\n", method_name, cseq, "going to a dialogless leg"
)) : (void)0)
3098 method_name, cseq, "going to a dialogless leg"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3098, "nta: %s (%u) %s\n", method_name, cseq, "going to a dialogless leg"
)) : (void)0)
;
3099 leg->leg_compressed = compressed;
3100 leg_recv(leg, msg, sip, tport);
3101 }
3102 else if (!agent->sa_is_stateless && (leg = agent->sa_default_leg)) {
3103 if (method == sip_method_invite &&
3104 agent->sa_in.proceeding->q_length >= agent->sa_max_proceeding) {
3105 SU_DEBUG_5(("nta: proceeding queue full for %s (%u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3106, "nta: proceeding queue full for %s (%u)\n", method_name
, cseq)) : (void)0)
3106 method_name, cseq))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3106, "nta: proceeding queue full for %s (%u)\n", method_name
, cseq)) : (void)0)
;
3107 mreply(agent, NULL((void*)0), SIP_503_SERVICE_UNAVAILABLE503, sip_503_Service_unavailable, msg,
3108 tport, 0, 0, NULL((void*)0),
3109 TAG_END()(tag_type_t)0, (tag_value_t)0);
3110 return;
3111 }
3112 else {
3113 SU_DEBUG_5(("nta: %s (%u) %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3114, "nta: %s (%u) %s\n", method_name, cseq, "going to a default leg"
)) : (void)0)
3114 method_name, cseq, "going to a default leg"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3114, "nta: %s (%u) %s\n", method_name, cseq, "going to a default leg"
)) : (void)0)
;
3115 leg->leg_compressed = compressed;
3116 leg_recv(leg, msg, sip, tport);
3117 }
3118 }
3119 else if (agent->sa_callback) {
3120 /* Stateless processing for request */
3121 agent->sa_stats->as_trless_request++;
3122 SU_DEBUG_5(("nta: %s (%u) %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3123, "nta: %s (%u) %s\n", method_name, cseq, "to message callback"
)) : (void)0)
3123 method_name, cseq, "to message callback"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3123, "nta: %s (%u) %s\n", method_name, cseq, "to message callback"
)) : (void)0)
;
3124 (void)agent->sa_callback(agent->sa_magic, agent, msg, sip);
3125 }
3126 else {
3127 agent->sa_stats->as_trless_request++;
3128 SU_DEBUG_5(("nta: %s (%u) %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3130, "nta: %s (%u) %s\n", method_name, cseq, "not processed by application: returning 501"
)) : (void)0)
3129 method_name, cseq,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3130, "nta: %s (%u) %s\n", method_name, cseq, "not processed by application: returning 501"
)) : (void)0)
3130 "not processed by application: returning 501"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3130, "nta: %s (%u) %s\n", method_name, cseq, "not processed by application: returning 501"
)) : (void)0)
;
3131 if (method != sip_method_ack)
3132 mreply(agent, NULL((void*)0), SIP_501_NOT_IMPLEMENTED501, sip_501_Not_implemented, msg,
3133 tport, 0, 0, NULL((void*)0),
3134 TAG_END()(tag_type_t)0, (tag_value_t)0);
3135 else
3136 msg_destroy(msg);
3137 }
3138}
3139
3140/** Check @Via header.
3141 *
3142 */
3143static
3144int agent_check_request_via(nta_agent_t *agent,
3145 msg_t *msg,
3146 sip_t *sip,
3147 sip_via_t *v,
3148 tport_t *tport)
3149{
3150 enum { receivedlen = sizeof("received=") - 1 };
3151 char received[receivedlen + TPORT_HOSTPORTSIZE(55)];
3152 char *hostport = received + receivedlen;
3153 char const *rport;
3154 su_sockaddr_t const *from;
3155 sip_via_t const *tpv = agent_tport_via(tport);
3156
3157 assert(tport)((void) sizeof ((tport) ? 1 : 0), __extension__ ({ if (tport)
; else __assert_fail ("tport", "nta.c", 3157, __extension__ __PRETTY_FUNCTION__
); }))
; assert(msg)((void) sizeof ((msg) ? 1 : 0), __extension__ ({ if (msg) ; else
__assert_fail ("msg", "nta.c", 3157, __extension__ __PRETTY_FUNCTION__
); }))
; assert(sip)((void) sizeof ((sip) ? 1 : 0), __extension__ ({ if (sip) ; else
__assert_fail ("sip", "nta.c", 3157, __extension__ __PRETTY_FUNCTION__
); }))
;
3158 assert(sip->sip_request)((void) sizeof ((sip->sip_request) ? 1 : 0), __extension__
({ if (sip->sip_request) ; else __assert_fail ("sip->sip_request"
, "nta.c", 3158, __extension__ __PRETTY_FUNCTION__); }))
; assert(tpv)((void) sizeof ((tpv) ? 1 : 0), __extension__ ({ if (tpv) ; else
__assert_fail ("tpv", "nta.c", 3158, __extension__ __PRETTY_FUNCTION__
); }))
;
3159
3160 from = msg_addr(msg);
3161
3162 if (v == NULL((void*)0)) {
3163 /* Make up a via line */
3164 v = sip_via_format(msg_home(msg)((su_home_t*)(msg)), "SIP/2.0/%s %s",
3165 tport_name(tport)->tpn_proto,
3166 tport_hostport(hostport, TPORT_HOSTPORTSIZE(55), from, 1));
3167 msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)v);
3168
3169 return v ? 0 : -1;
3170 }
3171
3172 if (!su_strmatch(v->v_protocol, tpv->v_protocol)) {
3173 tport_hostport(hostport, TPORT_HOSTPORTSIZE(55), from, 1);
3174 SU_DEBUG_1(("nta: Via check: invalid transport \"%s\" from %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 3175, "nta: Via check: invalid transport \"%s\" from %s\n",
v->v_protocol, hostport)) : (void)0)
3175 v->v_protocol, hostport))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 3175, "nta: Via check: invalid transport \"%s\" from %s\n",
v->v_protocol, hostport)) : (void)0)
;
3176 return -1;
3177 }
3178
3179 if (v->v_received) {
3180 /* Nasty, nasty */
3181 tport_hostport(hostport, TPORT_HOSTPORTSIZE(55), from, 1);
3182 SU_DEBUG_1(("nta: Via check: extra received=%s from %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 3183, "nta: Via check: extra received=%s from %s\n", v->
v_received, hostport)) : (void)0)
3183 v->v_received, hostport))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 3183, "nta: Via check: extra received=%s from %s\n", v->
v_received, hostport)) : (void)0)
;
3184 msg_header_remove_param(v->v_common, "received");
3185 }
3186
3187 if (!tport_hostport(hostport, TPORT_HOSTPORTSIZE(55), from, 0))
3188 return -1;
3189
3190 if (!su_casematch(hostport, v->v_host)) {
3191 size_t rlen;
3192 /* Add the "received" field */
3193 memcpy(received, "received=", receivedlen);
3194
3195 if (hostport[0] == '[') {
3196 rlen = strlen(hostport + 1) - 1;
3197 memmove(hostport, hostport + 1, rlen);
3198 hostport[rlen] = '\0';
3199 }
3200
3201 msg_header_replace_param(msg_home(msg)((su_home_t*)(msg)), v->v_common,
3202 su_strdup(msg_home(msg)((su_home_t*)(msg)), received));
3203 SU_DEBUG_5(("nta: Via check: %s\n", received))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3203, "nta: Via check: %s\n", received)) : (void)0)
;
3204 }
3205
3206 if (!agent->sa_server_rport) {
3207 /*Xyzzy*/;
3208 }
3209 else if (v->v_rport) {
3210 rport = su_sprintf(msg_home(msg)((su_home_t*)(msg)), "rport=%u", ntohs(from->su_portsu_sin.sin_port));
3211 msg_header_replace_param(msg_home(msg)((su_home_t*)(msg)), v->v_common, rport);
3212 }
3213 else if (tport_is_tcp(tport)) {
3214 rport = su_sprintf(msg_home(msg)((su_home_t*)(msg)), "rport=%u", ntohs(from->su_portsu_sin.sin_port));
3215 msg_header_replace_param(msg_home(msg)((su_home_t*)(msg)), v->v_common, rport);
3216 }
3217 else if (agent->sa_server_rport == 2 ||
3218 (agent->sa_server_rport == 3 && sip && sip->sip_user_agent &&
3219 sip->sip_user_agent->g_string &&
3220 (!strncasecmp(sip->sip_user_agent->g_string, "Polycom", 7) ||
3221 !strncasecmp(sip->sip_user_agent->g_string, "KIRK Wireless Server", 20) ||
3222 !strncasecmp(sip->sip_user_agent->g_string, "ADTRAN_Total_Access", 19)))) {
3223 rport = su_sprintf(msg_home(msg)((su_home_t*)(msg)), "rport=%u", ntohs(from->su_portsu_sin.sin_port));
3224 msg_header_replace_param(msg_home(msg)((su_home_t*)(msg)), v->v_common, rport);
3225 }
3226
3227 return 0;
3228}
3229
3230/** @internal Handle aliases of local node.
3231 *
3232 * Return true if @a url is modified.
3233 */
3234static
3235int agent_aliases(nta_agent_t const *agent, url_t url[], tport_t *tport)
3236{
3237 sip_contact_t *m;
3238 sip_via_t const *lv;
3239 char const *tport_port = "";
3240
3241 if (!url->url_host)
3242 return 0;
3243
3244 if (tport)
3245 tport_port = tport_name(tport)->tpn_port;
3246
3247 assert(tport_port)((void) sizeof ((tport_port) ? 1 : 0), __extension__ ({ if (tport_port
) ; else __assert_fail ("tport_port", "nta.c", 3247, __extension__
__PRETTY_FUNCTION__); }))
;
3248
3249 for (m = agent->sa_aliases ? agent->sa_aliases : agent->sa_contact;
3250 m;
3251 m = m->m_next) {
3252 if (url->url_type != m->m_url->url_type)
3253 continue;
3254
3255 if (host_cmp(url->url_host, m->m_url->url_host))
3256 continue;
3257
3258 if (url->url_port == NULL((void*)0))
3259 break;
3260
3261 if (m->m_url->url_port) {
3262 if (strcmp(url->url_port, m->m_url->url_port))
3263 continue;
3264 } else {
3265 if (strcmp(url->url_port, tport_port))
3266 continue;
3267 }
3268
3269 break;
3270 }
3271
3272 if (!m)
3273 return 0;
3274
3275 SU_DEBUG_7(("nta: canonizing " URL_PRINT_FORMAT " with %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__
, 3277, "nta: canonizing " "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
" with %s\n", (url)->url_scheme ? (url)->url_scheme : ""
, (url)->url_type != url_any && (url)->url_scheme
&& (url)->url_scheme[0] ? ":" : "", (url)->url_root
&& ((url)->url_host || (url)->url_user) ? "//"
: "", (url)->url_user ? (url)->url_user : "", (url)->
url_user && (url)->url_password ? ":" : "", (url)->
url_user && (url)->url_password ? (url)->url_password
: "", (url)->url_user && (url)->url_host ? "@"
: "", (url)->url_host ? (url)->url_host : "", (url)->
url_host && (url)->url_port ? ":" : "", (url)->
url_host && (url)->url_port ? (url)->url_port :
"", (url)->url_root && (url)->url_path ? "/" :
"", (url)->url_path ? (url)->url_path : "", (url)->
url_params ? ";" : "", (url)->url_params ? (url)->url_params
: "", (url)->url_headers ? "?" : "", (url)->url_headers
? (url)->url_headers : "", (url)->url_fragment ? "#" :
"", (url)->url_fragment ? (url)->url_fragment : "", agent
->sa_aliases ? "aliases" : "contact")) : (void)0)
3276 URL_PRINT_ARGS(url),(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__
, 3277, "nta: canonizing " "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
" with %s\n", (url)->url_scheme ? (url)->url_scheme : ""
, (url)->url_type != url_any && (url)->url_scheme
&& (url)->url_scheme[0] ? ":" : "", (url)->url_root
&& ((url)->url_host || (url)->url_user) ? "//"
: "", (url)->url_user ? (url)->url_user : "", (url)->
url_user && (url)->url_password ? ":" : "", (url)->
url_user && (url)->url_password ? (url)->url_password
: "", (url)->url_user && (url)->url_host ? "@"
: "", (url)->url_host ? (url)->url_host : "", (url)->
url_host && (url)->url_port ? ":" : "", (url)->
url_host && (url)->url_port ? (url)->url_port :
"", (url)->url_root && (url)->url_path ? "/" :
"", (url)->url_path ? (url)->url_path : "", (url)->
url_params ? ";" : "", (url)->url_params ? (url)->url_params
: "", (url)->url_headers ? "?" : "", (url)->url_headers
? (url)->url_headers : "", (url)->url_fragment ? "#" :
"", (url)->url_fragment ? (url)->url_fragment : "", agent
->sa_aliases ? "aliases" : "contact")) : (void)0)
3277 agent->sa_aliases ? "aliases" : "contact"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__
, 3277, "nta: canonizing " "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
" with %s\n", (url)->url_scheme ? (url)->url_scheme : ""
, (url)->url_type != url_any && (url)->url_scheme
&& (url)->url_scheme[0] ? ":" : "", (url)->url_root
&& ((url)->url_host || (url)->url_user) ? "//"
: "", (url)->url_user ? (url)->url_user : "", (url)->
url_user && (url)->url_password ? ":" : "", (url)->
url_user && (url)->url_password ? (url)->url_password
: "", (url)->url_user && (url)->url_host ? "@"
: "", (url)->url_host ? (url)->url_host : "", (url)->
url_host && (url)->url_port ? ":" : "", (url)->
url_host && (url)->url_port ? (url)->url_port :
"", (url)->url_root && (url)->url_path ? "/" :
"", (url)->url_path ? (url)->url_path : "", (url)->
url_params ? ";" : "", (url)->url_params ? (url)->url_params
: "", (url)->url_headers ? "?" : "", (url)->url_headers
? (url)->url_headers : "", (url)->url_fragment ? "#" :
"", (url)->url_fragment ? (url)->url_fragment : "", agent
->sa_aliases ? "aliases" : "contact")) : (void)0)
;
3278
3279 url->url_host = "%";
3280
3281 if (agent->sa_aliases) {
3282 url->url_type = agent->sa_aliases->m_url->url_type;
3283 url->url_scheme = agent->sa_aliases->m_url->url_scheme;
3284 url->url_port = agent->sa_aliases->m_url->url_port;
3285 return 1;
3286 }
3287 else {
3288 /* Canonize the request URL port */
3289 if (tport) {
3290 lv = agent_tport_via(tport_parent(tport)); assert(lv)((void) sizeof ((lv) ? 1 : 0), __extension__ ({ if (lv) ; else
__assert_fail ("lv", "nta.c", 3290, __extension__ __PRETTY_FUNCTION__
); }))
;
3291 if (lv->v_port)
3292 /* Add non-default port */
3293 url->url_port = lv->v_port;
3294 return 1;
3295 }
3296 if (su_strmatch(url->url_port, url_port_default((enum url_type_e)url->url_type)) ||
3297 su_strmatch(url->url_port, ""))
3298 /* Remove default or empty port */
3299 url->url_port = NULL((void*)0);
3300
3301 return 0;
3302 }
3303}
3304
3305/** @internal Handle incoming responses. */
3306static
3307void agent_recv_response(nta_agent_t *agent,
3308 msg_t *msg,
3309 sip_t *sip,
3310 sip_via_t *tport_via,
3311 tport_t *tport)
3312{
3313 int status = sip->sip_status->st_status;
3314 int errors;
3315 char const *phrase = sip->sip_status->st_phrase;
3316 char const *method =
3317 sip->sip_cseq ? sip->sip_cseq->cs_method_name : "<UNKNOWN>";
1
Assuming pointer value is null
2
'?' condition is false
3318 uint32_t cseq = sip->sip_cseq ? sip->sip_cseq->cs_seq : 0;
3
'?' condition is false
3319 nta_outgoing_t *orq;
3320 su_home_t *home;
3321 char const *branch = NONE((void *)-1);
3322
3323
3324 agent->sa_stats->as_recv_msg++;
3325 agent->sa_stats->as_recv_response++;
3326
3327 SU_DEBUG_5(("nta: received %03d %s for %s (%u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3328, "nta: received %03d %s for %s (%u)\n", status, phrase
, method, cseq)) : (void)0)
3328 status, phrase, method, cseq))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3328, "nta: received %03d %s for %s (%u)\n", status, phrase
, method, cseq)) : (void)0)
;
3329
3330 if (agent->sa_drop_prob && !tport_is_reliable(tport)) {
4
Assuming the condition is false
3331 if ((unsigned)su_randint(0, 1000) < agent->sa_drop_prob) {
3332 SU_DEBUG_5(("nta: %03d %s %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3333, "nta: %03d %s %s\n", status, phrase, "dropped simulating packet loss"
)) : (void)0)
3333 status, phrase, "dropped simulating packet loss"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3333, "nta: %03d %s %s\n", status, phrase, "dropped simulating packet loss"
)) : (void)0)
;
3334 agent->sa_stats->as_drop_response++;
3335 msg_destroy(msg);
3336 return;
3337 }
3338 }
3339
3340 if (agent->sa_bad_resp_mask)
5
Assuming the condition is false
6
Taking false branch
3341 errors = msg_extract_errors(msg) & agent->sa_bad_resp_mask;
3342 else
3343 errors = sip->sip_error != NULL((void*)0);
7
Assuming the condition is false
3344
3345 if (errors ||
9
Taking false branch
3346 sip_sanity_check(sip) < 0) {
8
Assuming the condition is false
3347 sip_header_t const *h;
3348
3349 agent->sa_stats->as_bad_response++;
3350 agent->sa_stats->as_bad_message++;
3351
3352 SU_DEBUG_5(("nta: %03d %s %s\n", status, phrase,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3355, "nta: %03d %s %s\n", status, phrase, errors ? "has fatal syntax errors"
: "failed sanity check")) : (void)0)
3353 errors(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3355, "nta: %03d %s %s\n", status, phrase, errors ? "has fatal syntax errors"
: "failed sanity check")) : (void)0)
3354 ? "has fatal syntax errors"(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3355, "nta: %03d %s %s\n", status, phrase, errors ? "has fatal syntax errors"
: "failed sanity check")) : (void)0)
3355 : "failed sanity check"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3355, "nta: %03d %s %s\n", status, phrase, errors ? "has fatal syntax errors"
: "failed sanity check")) : (void)0)
;
3356
3357 for (h = (sip_header_t const *)sip->sip_error; h; h = h->sh_nextsh_header_next->shn_next) {
3358 if (h->sh_classsh_common->h_class->hc_name) {
3359 SU_DEBUG_5(("nta: %03d has bad %s header\n", status,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3360, "nta: %03d has bad %s header\n", status, h->sh_common
->h_class->hc_name)) : (void)0)
3360 h->sh_class->hc_name))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3360, "nta: %03d has bad %s header\n", status, h->sh_common
->h_class->hc_name)) : (void)0)
;
3361 }
3362 }
3363
3364 msg_destroy(msg);
3365 return;
3366 }
3367
3368 if (!su_casematch(sip->sip_status->st_version, sip_version_2_0)) {
10
Assuming the condition is false
11
Taking false branch
3369 agent->sa_stats->as_bad_response++;
3370 agent->sa_stats->as_bad_message++;
3371
3372 SU_DEBUG_5(("nta: bad version %s %03d %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3373, "nta: bad version %s %03d %s\n", sip->sip_status->
st_version, status, phrase)) : (void)0)
3373 sip->sip_status->st_version, status, phrase))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3373, "nta: bad version %s %03d %s\n", sip->sip_status->
st_version, status, phrase)) : (void)0)
;
3374 msg_destroy(msg);
3375 return;
3376 }
3377
3378 if (sip->sip_cseq && sip->sip_cseq->cs_method == sip_method_ack) {
3379 /* Drop response messages to ACK */
3380 agent->sa_stats->as_bad_response++;
3381 agent->sa_stats->as_bad_message++;
3382 SU_DEBUG_5(("nta: %03d %s %s\n", status, phrase, "is response to ACK"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3382, "nta: %03d %s %s\n", status, phrase, "is response to ACK"
)) : (void)0)
;
3383 msg_destroy(msg);
3384 return;
3385 }
3386
3387 /* XXX - should check if msg should be discarded based on via? */
3388
3389#ifdef HAVE_ZLIB_COMPRESS1
3390 sip_content_encoding_Xflate(msg, sip, 1, 1);
12
Calling 'sip_content_encoding_Xflate'
17
Returning from 'sip_content_encoding_Xflate'
3391#endif
3392
3393 if ((orq = outgoing_find(agent, msg, sip, sip->sip_via))) {
18
Taking false branch
3394 SU_DEBUG_5(("nta: %03d %s %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3395, "nta: %03d %s %s\n", status, phrase, "is going to a transaction"
)) : (void)0)
3395 status, phrase, "is going to a transaction"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3395, "nta: %03d %s %s\n", status, phrase, "is going to a transaction"
)) : (void)0)
;
3396 /* RFC3263 4.3 "503 error response" */
3397 if(agent->sa_srv_503 && status == 503 && outgoing_other_destinations(orq)) {
3398 SU_DEBUG_5(("%s(%p): <%03d> for <%s>, %s\n", "nta", (void *)orq, status, method, "try next after timeout"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3398, "%s(%p): <%03d> for <%s>, %s\n", "nta", (
void *)orq, status, method, "try next after timeout")) : (void
)0)
;
3399 home = msg_home(msg)((su_home_t*)(msg));
3400 if (agent->sa_is_stateless)
3401 branch = stateless_branch(agent, msg, sip, orq->orq_tpn);
3402 else
3403 branch = stateful_branch(home, agent);
3404
3405 orq->orq_branch = branch;
3406 orq->orq_via_branch = branch;
3407 outgoing_try_another(orq);
3408 return;
3409 }
3410
3411 if (outgoing_recv(orq, status, msg, sip) == 0)
3412 return;
3413 }
3414
3415
3416 agent->sa_stats->as_trless_response++;
3417
3418 if ((orq = agent->sa_default_outgoing)) {
19
Assuming 'orq' is null
20
Taking false branch
3419 SU_DEBUG_5(("nta: %03d %s %s\n", status, phrase,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3420, "nta: %03d %s %s\n", status, phrase, "to the default transaction"
)) : (void)0)
3420 "to the default transaction"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3420, "nta: %03d %s %s\n", status, phrase, "to the default transaction"
)) : (void)0)
;
3421 outgoing_default_recv(orq, status, msg, sip);
3422 return;
3423 }
3424 else if (agent->sa_callback) {
21
Assuming the condition is false
22
Taking false branch
3425 SU_DEBUG_5(("nta: %03d %s %s\n", status, phrase, "to message callback"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3425, "nta: %03d %s %s\n", status, phrase, "to message callback"
)) : (void)0)
;
3426 /*
3427 * Store message and transport to hook for the duration of the callback
3428 * so that the transport can be obtained by nta_transport().
3429 */
3430 (void)agent->sa_callback(agent->sa_magic, agent, msg, sip);
3431 return;
3432 }
3433
3434 if (sip->sip_cseq->cs_method == sip_method_invite
23
Access to field 'cs_method' results in a dereference of a null pointer (loaded from field 'sip_cseq')
3435 && 200 <= sip->sip_status->st_status
3436 && sip->sip_status->st_status < 300
3437 /* Exactly one Via header, belonging to us */
3438 && sip->sip_via && !sip->sip_via->v_next
3439 && agent_has_via(agent, sip->sip_via)) {
3440 agent->sa_stats->as_trless_200++;
3441 }
3442
3443 SU_DEBUG_5(("nta: %03d %s %s\n", status, phrase, "was discarded"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3443, "nta: %03d %s %s\n", status, phrase, "was discarded")
) : (void)0)
;
3444 msg_destroy(msg);
3445}
3446
3447/** @internal Agent receives garbage */
3448static
3449void agent_recv_garbage(nta_agent_t *agent,
3450 msg_t *msg,
3451 tport_t *tport)
3452{
3453 agent->sa_stats->as_recv_msg++;
3454 agent->sa_stats->as_bad_message++;
3455
3456#if SU_DEBUG0 >= 3
3457 if (nta_log->log_level >= 3) {
3458 tp_name_t tpn[1];
3459
3460 tport_delivered_from(tport, msg, tpn);
3461
3462 SU_DEBUG_3(("nta_agent: received garbage from " TPN_FORMAT "\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 3463, "nta_agent: received garbage from " "%s/%s:%s%s%s%s%s"
"\n", (tpn)->tpn_proto, (tpn)->tpn_host, (tpn)->tpn_port
, (tpn)->tpn_comp ? ";comp=" : "", (tpn)->tpn_comp ? (tpn
)->tpn_comp : "", (tpn)->tpn_ident ? "/" : "", (tpn)->
tpn_ident ? (tpn)->tpn_ident : "")) : (void)0)
3463 TPN_ARGS(tpn)))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 3463, "nta_agent: received garbage from " "%s/%s:%s%s%s%s%s"
"\n", (tpn)->tpn_proto, (tpn)->tpn_host, (tpn)->tpn_port
, (tpn)->tpn_comp ? ";comp=" : "", (tpn)->tpn_comp ? (tpn
)->tpn_comp : "", (tpn)->tpn_ident ? "/" : "", (tpn)->
tpn_ident ? (tpn)->tpn_ident : "")) : (void)0)
;
3464 }
3465#endif
3466
3467 msg_destroy(msg);
3468}
3469
3470/* ====================================================================== */
3471/* 4) Message handling - create, complete, destroy */
3472
3473/** Create a new message belonging to the agent */
3474msg_t *nta_msg_create(nta_agent_t *agent, int flags)
3475{
3476 msg_t *msg;
3477
3478 if (agent == NULL((void*)0))
3479 return su_seterrno(EINVAL22), NULL((void*)0);
3480
3481 msg = msg_create(agent->sa_mclass, agent->sa_flags | flags);
3482
3483 if (agent->sa_preload)
3484 su_home_preload(msg_home(msg)((su_home_t*)(msg)), 1, agent->sa_preload);
3485
3486 return msg;
3487}
3488
3489/** Create a new message for transport */
3490msg_t *nta_msg_create_for_transport(nta_agent_t *agent, int flags,
3491 char const data[], usize_t dlen,
3492 tport_t const *tport, tp_client_t *via)
3493{
3494 msg_t *msg = msg_create(agent->sa_mclass, agent->sa_flags | flags);
3495
3496 msg_maxsize(msg, agent->sa_maxsize);
3497
3498 if (agent->sa_preload)
3499 su_home_preload(msg_home(msg)((su_home_t*)(msg)), 1, dlen + agent->sa_preload);
3500
3501 return msg;
3502}
3503
3504/** Complete a message. */
3505int nta_msg_complete(msg_t *msg)
3506{
3507 return sip_complete_message(msg);
3508}
3509
3510/** Discard a message */
3511void nta_msg_discard(nta_agent_t *agent, msg_t *msg)
3512{
3513 msg_destroy(msg);
3514}
3515
3516/** Check if the headers are from response generated locally by NTA. */
3517int nta_sip_is_internal(sip_t const *sip)
3518{
3519 return
3520 sip == NULL((void*)0) /* No message generated */
3521 || (sip->sip_flags & NTA_INTERNAL_MSG(1<<15)) == NTA_INTERNAL_MSG(1<<15);
3522}
3523
3524/** Check if the message is internally generated by NTA. */
3525int nta_msg_is_internal(msg_t const *msg)
3526{
3527 return msg_get_flags(msg, NTA_INTERNAL_MSG(1<<15)) == NTA_INTERNAL_MSG(1<<15);
3528}
3529
3530/** Check if the message is internally generated by NTA.
3531 *
3532 * @deprecated Use nta_msg_is_internal() instead
3533 */
3534int nta_is_internal_msg(msg_t const *msg) { return nta_msg_is_internal(msg); }
3535
3536/* ====================================================================== */
3537/* 5) Stateless operation */
3538
3539/**Forward a request or response message.
3540 *
3541 * @note
3542 * The ownership of @a msg is taken over by the function even if the
3543 * function fails.
3544 */
3545int nta_msg_tsend(nta_agent_t *agent, msg_t *msg, url_string_t const *u,
3546 tag_type_t tag, tag_value_t value, ...)
3547{
3548 int retval = -1;
3549 ta_list ta;
3550 sip_t *sip = sip_object(msg);
3551 tp_name_t tpn[1] = {{ NULL((void*)0) }};
3552 char const *what;
3553
3554 if (!sip) {
3555 msg_destroy(msg);
3556 return -1;
3557 }
3558
3559 what =
3560 sip->sip_status ? "nta_msg_tsend(response)" :
3561 sip->sip_request ? "nta_msg_tsend(request)" :
3562 "nta_msg_tsend()";
3563
3564 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)
;
3565
3566 if (sip_add_tl(msg, sip, ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
) < 0)
3567 SU_DEBUG_3(("%s: cannot add headers\n", what))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 3567, "%s: cannot add headers\n", what)) : (void)0)
;
3568 else if (sip->sip_status) {
3569 tport_t *tport = NULL((void*)0);
3570 int *use_rport = NULL((void*)0);
3571 int retry_without_rport = 0;
3572
3573 struct sigcomp_compartment *cc; cc = NONE((void *)-1);
3574
3575 if (agent->sa_server_rport)
3576 use_rport = &retry_without_rport, retry_without_rport = 1;
3577
3578 tl_gets(ta_args(ta)(ta).tl,
3579 NTATAG_TPORT_REF(tport)ntatag_tport_ref, tag_ptr_vr(&(tport), (tport)),
3580 IF_SIGCOMP_TPTAG_COMPARTMENT_REF(cc)tptag_compartment_ref, tag_ptr_vr(&(cc), cc),
3581 /* NTATAG_INCOMPLETE_REF(incomplete), */
3582 TAG_END()(tag_type_t)0, (tag_value_t)0);
3583
3584 if (!sip->sip_separator &&
3585 !(sip->sip_separator = sip_separator_create(msg_home(msg)((su_home_t*)(msg)))))
3586 SU_DEBUG_3(("%s: cannot create sip_separator\n", what))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 3586, "%s: cannot create sip_separator\n", what)) : (void)0
)
;
3587 else if (msg_serialize(msg, (msg_pub_t *)sip) != 0)
3588 SU_DEBUG_3(("%s: sip_serialize() failed\n", what))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 3588, "%s: sip_serialize() failed\n", what)) : (void)0)
;
3589 else if (!sip_via_remove(msg, sip))
3590 SU_DEBUG_3(("%s: cannot remove Via\n", what))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 3590, "%s: cannot remove Via\n", what)) : (void)0)
;
3591 else if (nta_tpn_by_via(tpn, sip->sip_via, use_rport) < 0)
3592 SU_DEBUG_3(("%s: bad via\n", what))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 3592, "%s: bad via\n", what)) : (void)0)
;
3593 else {
3594 if (!tport)
3595 tport = tport_by_name(agent->sa_tports, tpn);
3596 if (!tport)
3597 tport = tport_by_protocol(agent->sa_tports, tpn->tpn_proto);
3598
3599 if (retry_without_rport)
3600 tpn->tpn_port = sip_via_port(sip->sip_via, NULL((void*)0));
3601
3602 if (tport && tpn->tpn_comp && cc == NONE((void *)-1))
3603 cc = agent_compression_compartment(agent, tport, tpn, -1);
3604
3605 if (tport_tsend(tport, msg, tpn,
3606 IF_SIGCOMP_TPTAG_COMPARTMENT(cc)!(cc && cc != ((void *)-1)) ? tag_skip : tptag_compartment
, tag_ptr_v((cc)),
3607 TPTAG_MTU(INT_MAX)tptag_mtu, tag_usize_v((2147483647)), ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
, TAG_END()(tag_type_t)0, (tag_value_t)0)) {
3608 agent->sa_stats->as_sent_msg++;
3609 agent->sa_stats->as_sent_response++;
3610 retval = 0;
3611 }
3612 else {
3613 SU_DEBUG_3(("%s: send fails\n", what))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 3613, "%s: send fails\n", what)) : (void)0)
;
3614 }
3615 }
3616 }
3617 else {
3618 /* Send request */
3619 if (outgoing_create(agent, NULL((void*)0), NULL((void*)0), u, NULL((void*)0), msg_ref_create(msg),
3620 NTATAG_STATELESS(1)ntatag_stateless, tag_bool_v((1)),
3621 ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
))
3622 retval = 0;
3623 }
3624
3625 if (retval == 0)
3626 SU_DEBUG_5(("%s\n", what))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 3626, "%s\n", what)) : (void)0)
;
3627
3628 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))
;
3629
3630 msg_destroy(msg);
3631
3632 return retval;
3633}
3634
3635/** Reply to a request message.
3636 *
3637 * @param agent nta agent object
3638 * @param req_msg request message
3639 * @param status status code
3640 * @param phrase status phrase (may be NULL if status code is well-known)
3641 * @param tag, value, ... optional additional headers terminated by TAG_END()
3642 *
3643 * @retval 0 when succesful
3644 * @retval -1 upon an error
3645 *
3646 * @note
3647 * The ownership of @a msg is taken over by the function even if the
3648 * function fails.
3649 */
3650int nta_msg_treply(nta_agent_t *agent,
3651 msg_t *req_msg,
3652 int status, char const *phrase,
3653 tag_type_t tag, tag_value_t value, ...)
3654{
3655 int retval;
3656 ta_list ta;
3657
3658 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)
;
3659
3660 retval = mreply(agent, NULL((void*)0), status, phrase, req_msg,
3661 NULL((void*)0), 0, 0, NULL((void*)0),
3662 ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
);
3663 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))
;
3664
3665 return retval;
3666}
3667
3668/**Reply to the request message.
3669 *
3670 * @note
3671 * The ownership of @a msg is taken over by the function even if the
3672 * function fails.
3673 */
3674int nta_msg_mreply(nta_agent_t *agent,
3675 msg_t *reply, sip_t *sip,
3676 int status, char const *phrase,
3677 msg_t *req_msg,
3678 tag_type_t tag, tag_value_t value, ...)
3679{
3680 int retval = -1;
3681 ta_list ta;
3682
3683 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)
;
3684
3685 retval = mreply(agent, reply, status, phrase, req_msg,
3686 NULL((void*)0), 0, 0, NULL((void*)0),
3687 ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
);
3688 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))
;
3689
3690 return retval;
3691}
3692
3693static
3694int mreply(nta_agent_t *agent,
3695 msg_t *reply,
3696 int status, char const *phrase,
3697 msg_t *req_msg,
3698 tport_t *tport,
3699 int incomplete,
3700 int sdwn_after,
3701 char const *to_tag,
3702 tag_type_t tag, tag_value_t value, ...)
3703{
3704 ta_list ta;
3705 sip_t *sip;
3706 int *use_rport = NULL((void*)0);
3707 int retry_without_rport = 0;
3708 tp_name_t tpn[1];
3709 int retval = -1;
3710
3711 if (!agent)
3712 return -1;
3713
3714 if (agent->sa_server_rport)
3715 use_rport = &retry_without_rport, retry_without_rport = 1;
3716
3717 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)
;
3718
3719 tl_gets(ta_args(ta)(ta).tl, NTATAG_TPORT_REF(tport)ntatag_tport_ref, tag_ptr_vr(&(tport), (tport)), TAG_END()(tag_type_t)0, (tag_value_t)0);
3720
3721 if (reply == NULL((void*)0)) {
3722 reply = nta_msg_create(agent, 0);
3723 }
3724 sip = sip_object(reply);
3725
3726 if (!sip) {
3727 SU_DEBUG_3(("%s: cannot create response msg\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 3727, "%s: cannot create response msg\n", __func__)) : (void
)0)
;
3728 }
3729 else if (sip_add_tl(reply, sip, ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
) < 0) {
3730 SU_DEBUG_3(("%s: cannot add user headers\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 3730, "%s: cannot add user headers\n", __func__)) : (void)0
)
;
3731 }
3732 else if (complete_response(reply, status, phrase, req_msg) < 0 &&
3733 !incomplete) {
3734 SU_DEBUG_3(("%s: cannot complete message\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 3734, "%s: cannot complete message\n", __func__)) : (void)0
)
;
3735 }
3736 else if (sip->sip_status && sip->sip_status->st_status > 100 &&
3737 sip->sip_to && !sip->sip_to->a_tag &&
3738 (to_tag == NONE((void *)-1) ? 0 :
3739 to_tag != NULL((void*)0)
3740 ? sip_to_tag(msg_home(reply)((su_home_t*)(reply)), sip->sip_to, to_tag) < 0
3741 : sip_to_tag(msg_home(reply)((su_home_t*)(reply)), sip->sip_to,
3742 nta_agent_newtag(msg_home(reply)((su_home_t*)(reply)), "tag=%s", agent)) < 0)) {
3743 SU_DEBUG_3(("%s: cannot add To tag\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 3743, "%s: cannot add To tag\n", __func__)) : (void)0)
;
3744 }
3745 else if (nta_tpn_by_via(tpn, sip->sip_via, use_rport) < 0) {
3746 SU_DEBUG_3(("%s: no Via\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 3746, "%s: no Via\n", __func__)) : (void)0)
;
3747 }
3748 else {
3749 struct sigcomp_compartment *cc = NONE((void *)-1);
3750
3751 if (tport == NULL((void*)0))
3752 tport = tport_delivered_by(agent->sa_tports, req_msg);
3753
3754 if (!tport) {
3755 tport_t *primary = tport_by_protocol(agent->sa_tports, tpn->tpn_proto);
3756
3757 tport = tport_by_name(primary, tpn);
3758
3759 if (!tport)
3760 tport = primary;
3761 }
3762
3763 if (retry_without_rport)
3764 tpn->tpn_port = sip_via_port(sip->sip_via, NULL((void*)0));
3765
3766 if (tport && tpn->tpn_comp) {
3767 tl_gets(ta_args(ta)(ta).tl, TPTAG_COMPARTMENT_REF(cc)tptag_compartment_ref, tag_ptr_vr(&(cc), cc),
3768 /* XXX - should also check ntatag_sigcomp_close() */
3769 TAG_END()(tag_type_t)0, (tag_value_t)0);
3770 if (cc == NONE((void *)-1))
3771 cc = agent_compression_compartment(agent, tport, tpn, -1);
3772
3773 if (cc != NULL((void*)0) && cc != NONE((void *)-1) &&
3774 tport_delivered_with_comp(tport, req_msg, NULL((void*)0)) != -1) {
3775 agent_accept_compressed(agent, req_msg, cc);
3776 }
3777 }
3778
3779 if (tport_tsend(tport, reply, tpn,
3780 IF_SIGCOMP_TPTAG_COMPARTMENT(cc)!(cc && cc != ((void *)-1)) ? tag_skip : tptag_compartment
, tag_ptr_v((cc)),
3781 TPTAG_MTU(INT_MAX)tptag_mtu, tag_usize_v((2147483647)),
3782 TPTAG_SDWN_AFTER(sdwn_after)tptag_sdwn_after, tag_bool_v((sdwn_after)),
3783 ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
)) {
3784 agent->sa_stats->as_sent_msg++;
3785 agent->sa_stats->as_sent_response++;
3786 retval = 0; /* Success! */
3787 }
3788 else {
3789 SU_DEBUG_3(("%s: send fails\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 3789, "%s: send fails\n", __func__)) : (void)0)
;
3790 }
3791 }
3792
3793 msg_destroy(reply);
3794 msg_destroy(req_msg);
3795
3796 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))
;
3797
3798 return retval;
3799}
3800
3801/** Add headers from the request to the response message. */
3802static
3803int complete_response(msg_t *response,
3804 int status, char const *phrase,
3805 msg_t *request)
3806{
3807 su_home_t *home = msg_home(response)((su_home_t*)(response));
3808 sip_t *response_sip = sip_object(response);
3809 sip_t const *request_sip = sip_object(request);
3810
3811 int incomplete = 0;
3812
3813 if (!response_sip || !request_sip || !request_sip->sip_request)
3814 return -1;
3815
3816 if (!response_sip->sip_status)
3817 response_sip->sip_status = sip_status_create(home, status, phrase, NULL((void*)0));
3818 if (!response_sip->sip_via)
3819 response_sip->sip_via = sip_via_dup(home, request_sip->sip_via);
3820 if (!response_sip->sip_from)
3821 response_sip->sip_from = sip_from_dup(home, request_sip->sip_from);
3822 if (!response_sip->sip_to)
3823 response_sip->sip_to = sip_to_dup(home, request_sip->sip_to);
3824 if (!response_sip->sip_call_id)
3825 response_sip->sip_call_id =
3826 sip_call_id_dup(home, request_sip->sip_call_id);
3827 if (!response_sip->sip_cseq)
3828 response_sip->sip_cseq = sip_cseq_dup(home, request_sip->sip_cseq);
3829
3830 if (!response_sip->sip_record_route && request_sip->sip_record_route)
3831 sip_add_dup(response, response_sip, (void*)request_sip->sip_record_route);
3832
3833 incomplete = sip_complete_message(response) < 0;
3834
3835 msg_serialize(response, (msg_pub_t *)response_sip);
3836
3837 if (incomplete ||
3838 !response_sip->sip_status ||
3839 !response_sip->sip_via ||
3840 !response_sip->sip_from ||
3841 !response_sip->sip_to ||
3842 !response_sip->sip_call_id ||
3843 !response_sip->sip_cseq ||
3844 !response_sip->sip_content_length ||
3845 !response_sip->sip_separator ||
3846 (request_sip->sip_record_route && !response_sip->sip_record_route))
3847 return -1;
3848
3849 return 0;
3850}
3851
3852/** ACK and BYE an unknown 200 OK response to INVITE.
3853 *
3854 * A UAS may still return a 2XX series response to client request after the
3855 * client transactions has been terminated. In that case, the UAC can not
3856 * really accept the call. This function was used to accept and immediately
3857 * terminate such a call.
3858 *
3859 * @deprecated This was a bad idea: see sf.net bug #1750691. It can be used
3860 * to amplify DoS attacks. Let UAS take care of retransmission timeout and
3861 * let it terminate the session. As of @VERSION_1_12_7, this function just
3862 * returns -1.
3863 */
3864int nta_msg_ackbye(nta_agent_t *agent, msg_t *msg)
3865{
3866 sip_t *sip = sip_object(msg);
3867 msg_t *amsg = nta_msg_create(agent, 0);
3868 sip_t *asip = sip_object(amsg);
3869 msg_t *bmsg = NULL((void*)0);
3870 sip_t *bsip;
3871 url_string_t const *ruri;
3872 nta_outgoing_t *ack = NULL((void*)0), *bye = NULL((void*)0);
3873 sip_cseq_t *cseq;
3874 sip_request_t *rq;
3875 sip_route_t *route = NULL((void*)0), *r, r0[1];
3876 su_home_t *home = msg_home(amsg)((su_home_t*)(amsg));
3877
3878 if (asip == NULL((void*)0))
3879 return -1;
3880
3881 sip_add_tl(amsg, asip,
3882 SIPTAG_TO(sip->sip_to)siptag_to, siptag_to_v(sip->sip_to),
3883 SIPTAG_FROM(sip->sip_from)siptag_from, siptag_from_v(sip->sip_from),
3884 SIPTAG_CALL_ID(sip->sip_call_id)siptag_call_id, siptag_call_id_v(sip->sip_call_id),
3885 TAG_END()(tag_type_t)0, (tag_value_t)0);
3886
3887 if (sip->sip_contact) {
3888 ruri = (url_string_t const *)sip->sip_contact->m_url;
3889 } else {
3890 ruri = (url_string_t const *)sip->sip_to->a_url;
3891 }
3892
3893 /* Reverse (and fix) record route */
3894 route = sip_route_reverse(home, sip->sip_record_route);
3895
3896 if (route && !url_has_param(route->r_url, "lr")) {
3897 for (r = route; r->r_next; r = r->r_next)
3898 ;
3899
3900 /* Append r-uri */
3901 *sip_route_init(r0)->r_url = *ruri->us_url;
3902 r->r_next = sip_route_dup(home, r0);
3903
3904 /* Use topmost route as request-uri */
3905 ruri = (url_string_t const *)route->r_url;
3906 route = route->r_next;
3907 }
3908
3909 msg_header_insert(amsg, (msg_pub_t *)asip, (msg_header_t *)route);
3910
3911 bmsg = msg_copy(amsg); bsip = sip_object(bmsg);
3912
3913 if (!(cseq = sip_cseq_create(home, sip->sip_cseq->cs_seq, SIP_METHOD_ACKsip_method_ack, "ACK")))
3914 goto err;
3915 else
3916 msg_header_insert(amsg, (msg_pub_t *)asip, (msg_header_t *)cseq);
3917
3918 if (!(rq = sip_request_create(home, SIP_METHOD_ACKsip_method_ack, "ACK", ruri, NULL((void*)0))))
3919 goto err;
3920 else
3921 msg_header_insert(amsg, (msg_pub_t *)asip, (msg_header_t *)rq);
3922
3923 if (!(ack = nta_outgoing_mcreate(agent, NULL((void*)0), NULL((void*)0), NULL((void*)0), amsg,
3924 NTATAG_ACK_BRANCH(sip->sip_via->v_branch)ntatag_ack_branch, tag_str_v((sip->sip_via->v_branch)),
3925 NTATAG_STATELESS(1)ntatag_stateless, tag_bool_v((1)),
3926 TAG_END()(tag_type_t)0, (tag_value_t)0)))
3927 goto err;
3928 else
3929 nta_outgoing_destroy(ack);
3930
3931 home = msg_home(bmsg)((su_home_t*)(bmsg));
3932
3933 if (!(cseq = sip_cseq_create(home, 0x7fffffff, SIP_METHOD_BYEsip_method_bye, "BYE")))
3934 goto err;
3935 else
3936 msg_header_insert(bmsg, (msg_pub_t *)bsip, (msg_header_t *)cseq);
3937
3938 if (!(rq = sip_request_create(home, SIP_METHOD_BYEsip_method_bye, "BYE", ruri, NULL((void*)0))))
3939 goto err;
3940 else
3941 msg_header_insert(bmsg, (msg_pub_t *)bsip, (msg_header_t *)rq);
3942
3943 if (!(bye = nta_outgoing_mcreate(agent, NULL((void*)0), NULL((void*)0), NULL((void*)0), bmsg,
3944 NTATAG_STATELESS(1)ntatag_stateless, tag_bool_v((1)),
3945 TAG_END()(tag_type_t)0, (tag_value_t)0)))
3946 goto err;
3947
3948 msg_destroy(msg);
3949 return 0;
3950
3951 err:
3952
3953 msg_destroy(bmsg);
3954 msg_destroy(amsg);
3955
3956 return -1;
3957}
3958
3959/**Complete a request with values from dialog.
3960 *
3961 * Complete a request message @a msg belonging to a dialog associated with
3962 * @a leg. It increments the local @CSeq value, adds @CallID, @To, @From and
3963 * @Route headers (if there is such headers present in @a leg), and creates
3964 * a new request line object from @a method, @a method_name and @a
3965 * request_uri.
3966 *
3967 * @param msg pointer to a request message object
3968 * @param leg pointer to a #nta_leg_t object
3969 * @param method request method number or #sip_method_unknown
3970 * @param method_name method name (if @a method == #sip_method_unknown)
3971 * @param request_uri request URI
3972 *
3973 * If @a request_uri contains query part, the query part is converted as SIP
3974 * headers and added to the request.
3975 *
3976 * @retval 0 when successful
3977 * @retval -1 upon an error
3978 *
3979 * @sa nta_outgoing_mcreate(), nta_outgoing_tcreate()
3980 */
3981int nta_msg_request_complete(msg_t *msg,
3982 nta_leg_t *leg,
3983 sip_method_t method,
3984 char const *method_name,
3985 url_string_t const *request_uri)
3986{
3987 su_home_t *home = msg_home(msg)((su_home_t*)(msg));
3988 sip_t *sip = sip_object(msg);
3989 sip_to_t const *to;
3990 uint32_t seq;
3991 url_t reg_url[1];
3992 url_string_t const *original = request_uri;
3993
3994 if (!leg || !msg || !sip)
3995 return -1;
3996
3997 if (!sip->sip_route && leg->leg_route) {
3998 if (leg->leg_loose_route) {
3999 if (leg->leg_target) {
4000 request_uri = (url_string_t *)leg->leg_target->m_url;
4001 }
4002 sip->sip_route = sip_route_dup(home, leg->leg_route);
4003 }
4004 else {
4005 sip_route_t **rr;
4006
4007 request_uri = (url_string_t *)leg->leg_route->r_url;
4008 sip->sip_route = sip_route_dup(home, leg->leg_route->r_next);
4009
4010 for (rr = &sip->sip_route; *rr; rr = &(*rr)->r_next)
4011 ;
4012
4013 if (leg->leg_target)
4014 *rr = sip_route_dup(home, (sip_route_t *)leg->leg_target);
4015 }
4016 }
4017 else if (leg->leg_target)
4018 request_uri = (url_string_t *)leg->leg_target->m_url;
4019
4020 if (!request_uri && sip->sip_request)
4021 request_uri = (url_string_t *)sip->sip_request->rq_url;
4022
4023 to = sip->sip_to ? sip->sip_to : leg->leg_remote;
4024
4025 if (!request_uri && to) {
4026 if (method != sip_method_register)
4027 request_uri = (url_string_t *)to->a_url;
4028 else {
4029 /* Remove user part from REGISTER requests */
4030 *reg_url = *to->a_url;
4031 reg_url->url_user = reg_url->url_password = NULL((void*)0);
4032 request_uri = (url_string_t *)reg_url;
4033 }
4034 }
4035
4036 if (!request_uri)
4037 return -1;
4038
4039 if (method || method_name) {
4040 sip_request_t *rq = sip->sip_request;
4041 int use_headers =
4042 request_uri == original || (url_t *)request_uri == rq->rq_url;
4043
4044 if (!rq
4045 || request_uri != (url_string_t *)rq->rq_url
4046 || method != rq->rq_method
4047 || !su_strmatch(method_name, rq->rq_method_name))
4048 rq = NULL((void*)0);
4049
4050 if (rq == NULL((void*)0)) {
4051 rq = sip_request_create(home, method, method_name, request_uri, NULL((void*)0));
4052 if (msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)rq) < 0)
4053 return -1;
4054 }
4055
4056 /* @RFC3261 table 1 (page 152):
4057 * Req-URI cannot contain method parameter or headers
4058 */
4059 if (rq->rq_url->url_params) {
4060 rq->rq_url->url_params =
4061 url_strip_param_string((char *)rq->rq_url->url_params, "method");
4062 sip_fragment_clear(rq->rq_common)((rq->rq_common)->h_data = ((void*)0), (rq->rq_common
)->h_len = 0)
;
4063 }
4064
4065 if (rq->rq_url->url_headers) {
4066 if (use_headers) {
4067 char *s = url_query_as_header_string(msg_home(msg)((su_home_t*)(msg)),
4068 rq->rq_url->url_headers);
4069 if (!s)
4070 return -1;
4071 msg_header_parse_str(msg, (msg_pub_t*)sip, s);
4072 }
4073 rq->rq_url->url_headers = NULL((void*)0), sip_fragment_clear(rq->rq_common)((rq->rq_common)->h_data = ((void*)0), (rq->rq_common
)->h_len = 0)
;
4074 }
4075 }
4076
4077 if (!sip->sip_request)
4078 return -1;
4079
4080 if (!sip->sip_max_forwards)
4081 sip_add_dup(msg, sip, (sip_header_t *)leg->leg_agent->sa_max_forwards);
4082
4083 if (!sip->sip_from)
4084 sip->sip_from = sip_from_dup(home, leg->leg_local);
4085 else if (leg->leg_local && leg->leg_local->a_tag &&
4086 (!sip->sip_from->a_tag ||
4087 !su_casematch(sip->sip_from->a_tag, leg->leg_local->a_tag)))
4088 sip_from_tag(home, sip->sip_from, leg->leg_local->a_tag);
4089
4090 if (sip->sip_from && !sip->sip_from->a_tag) {
4091 sip_fragment_clear(sip->sip_from->a_common)((sip->sip_from->a_common)->h_data = ((void*)0), (sip
->sip_from->a_common)->h_len = 0)
;
4092 sip_from_add_param(home, sip->sip_from,
4093 nta_agent_newtag(home, "tag=%s", leg->leg_agent));
4094 }
4095
4096 if (sip->sip_to) {
4097 if (leg->leg_remote && leg->leg_remote->a_tag)
4098 sip_to_tag(home, sip->sip_to, leg->leg_remote->a_tag);
4099 }
4100 else if (leg->leg_remote) {
4101 sip->sip_to = sip_to_dup(home, leg->leg_remote);
4102 }
4103 else {
4104 sip_to_t *to = sip_to_create(home, request_uri);
4105 if (to) sip_aor_strip(to->a_url);
4106 sip->sip_to = to;
4107 }
4108
4109 if (!sip->sip_from || !sip->sip_from || !sip->sip_to)
4110 return -1;
4111
4112 method = sip->sip_request->rq_method;
4113 method_name = sip->sip_request->rq_method_name;
4114
4115 if (!leg->leg_id && sip->sip_cseq)
4116 seq = sip->sip_cseq->cs_seq;
4117 else if (method == sip_method_ack || method == sip_method_cancel)
4118 /* Dangerous - we may do PRACK/UPDATE meanwhile */
4119 seq = sip->sip_cseq ? sip->sip_cseq->cs_seq : leg->leg_seq;
4120 else if (leg->leg_seq)
4121 seq = ++leg->leg_seq;
4122 else if (sip->sip_cseq) /* Obtain initial value from existing CSeq header */
4123 seq = leg->leg_seq = sip->sip_cseq->cs_seq;
4124 else
4125 seq = leg->leg_seq = (sip_now() >> 1) & 0x7ffffff;
4126
4127 if (!sip->sip_call_id) {
4128 if (leg->leg_id)
4129 sip->sip_call_id = sip_call_id_dup(home, leg->leg_id);
4130 else
4131 sip->sip_call_id = sip_call_id_create(home, NULL((void*)0));
4132 }
4133
4134 if (!sip->sip_cseq ||
4135 seq != sip->sip_cseq->cs_seq ||
4136 method != sip->sip_cseq->cs_method ||
4137 !su_strmatch(method_name, sip->sip_cseq->cs_method_name)) {
4138 sip_cseq_t *cseq = sip_cseq_create(home, seq, method, method_name);
4139 if (msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)cseq) < 0)
4140 return -1;
4141 }
4142
4143 return 0;
4144}
4145
4146/* ====================================================================== */
4147/* 6) Dialogs (legs) */
4148
4149static void leg_insert(nta_agent_t *agent, nta_leg_t *leg);
4150static int leg_route(nta_leg_t *leg,
4151 sip_record_route_t const *route,
4152 sip_record_route_t const *reverse,
4153 sip_contact_t const *contact,
4154 int reroute);
4155static int leg_callback_default(nta_leg_magic_t*, nta_leg_t*,
4156 nta_incoming_t*, sip_t const *);
4157#define HTABLE_HASH_LEG(leg)((leg)->leg_hash) ((leg)->leg_hash)
4158
4159#ifdef __clang__1
4160#pragma clang diagnostic push
4161#pragma clang diagnostic ignored "-Wunused-function"
4162#endif
4163
4164HTABLE_BODIES_WITH(leg_htable, lht, nta_leg_t, HTABLE_HASH_LEG, size_t, hash_value_t)static inline int leg_htable_resize(su_home_t *home, leg_htable_t
lht[], size_t new_size) { nta_leg_t **new_hash; nta_leg_t **
old_hash = lht->lht_table; size_t old_size; size_t i, j, i0
; unsigned again = 0; size_t used = 0, collisions = 0; if (new_size
== 0) new_size = 2 * lht->lht_size + 1; if (new_size <
31) new_size = 31; if (new_size < 5 * lht->lht_used / 4
) new_size = 5 * lht->lht_used / 4; if (!(new_hash = su_zalloc
(home, sizeof(*new_hash) * new_size))) return -1; old_size = lht
->lht_size; do for (j = 0; j < old_size; j++) { if (!old_hash
[j]) continue; if (again < 2 && ((old_hash[j])->
leg_hash) % old_size > j) { again = 1; continue; } i0 = ((
old_hash[j])->leg_hash) % new_size; for (i = i0; new_hash[
i]; i = (i + 1) % new_size, ((void) sizeof ((i != i0) ? 1 : 0
), __extension__ ({ if (i != i0) ; else __assert_fail ("i != i0"
, "nta.c", 4164, __extension__ __PRETTY_FUNCTION__); }))) collisions
++; new_hash[i] = old_hash[j], old_hash[j] = ((void*)0); used
++; } while (again++ == 1); lht->lht_table = new_hash, lht
->lht_size = new_size; ((void) sizeof ((lht->lht_used ==
used) ? 1 : 0), __extension__ ({ if (lht->lht_used == used
) ; else __assert_fail ("lht->lht_used == used", "nta.c", 4164
, __extension__ __PRETTY_FUNCTION__); })); su_free(home, old_hash
); return 0; } static inline int leg_htable_is_full(leg_htable_t
const *lht) { return lht->lht_table == ((void*)0) || 3 * lht
->lht_used > 2 * lht->lht_size; } static inline nta_leg_t
**leg_htable_hash(leg_htable_t const *lht, hash_value_t hv) {
return lht->lht_table + hv % lht->lht_size; } static inline
nta_leg_t **leg_htable_next(leg_htable_t const *lht, nta_leg_t
* const *ee) { if (++ee < lht->lht_table + lht->lht_size
&& ee >= lht->lht_table) return (nta_leg_t **)
ee; else return lht->lht_table; } static inline void leg_htable_append
(leg_htable_t *lht, nta_leg_t const *e) { nta_leg_t **ee; lht
->lht_used++; for (ee = leg_htable_hash(lht, ((e)->leg_hash
)); *ee; ee = leg_htable_next(lht, ee)) ; *ee = (nta_leg_t *)
e; } static inline void leg_htable_insert(leg_htable_t *lht, nta_leg_t
const *e) { nta_leg_t *e0, **ee; lht->lht_used++; for (ee
= leg_htable_hash(lht, ((e)->leg_hash)); (e0 = *ee); ee =
leg_htable_next(lht, ee)) *ee = (nta_leg_t *)e, e = e0; *ee =
(nta_leg_t *)e; } static inline int leg_htable_remove(leg_htable_t
*lht, nta_leg_t const *e) { size_t i, j, k; size_t size = lht
->lht_size; nta_leg_t **htable = lht->lht_table; if (!e
) return -1; for (i = ((e)->leg_hash) % size; htable[i]; i
= (i + 1) % size) if (e == htable[i]) break; if (!htable[i])
return -1; for (j = (i + 1) % size; htable[j]; j = (j + 1) %
size) { k = ((htable[j])->leg_hash) % size; if (k == j) continue
; if (j > i ? (i < k && k < j) : (i < k ||
k < j)) continue; htable[i] = htable[j], i = j; } lht->
lht_used--; htable[i] = ((void*)0); return 0; } extern int leg_htable_dummy
;
4165
4166#ifdef __clang__1
4167#pragma clang diagnostic pop
4168#endif
4169
4170su_inlinestatic inline
4171hash_value_t hash_istring(char const *, char const *, hash_value_t);
4172
4173/**@typedef nta_request_f
4174 *
4175 * Callback for incoming requests
4176 *
4177 * This is a callback function invoked by NTA for each incoming SIP request.
4178 *
4179 * @param lmagic call leg context
4180 * @param leg call leg handle
4181 * @param ireq incoming request
4182 * @param sip incoming request contents
4183 *
4184 * @retval 100..699
4185 * NTA constructs a reply message with given error code and corresponding
4186 * standard phrase, then sends the reply.
4187 *
4188 * @retval 0
4189 * The application takes care of sending (or not sending) the reply.
4190 *
4191 * @retval other
4192 * All other return values will be interpreted as
4193 * @e 500 @e Internal @e server @e error.
4194 */
4195
4196
4197/**
4198 * Create a new leg object.
4199 *
4200 * Creates a leg object, which is used to represent dialogs, partial dialogs
4201 * (for example, in case of REGISTER), and destinations within a particular
4202 * NTA object.
4203 *
4204 * When a leg is created, a callback pointer and a application context is
4205 * provided. All other parameters are optional.
4206 *
4207 * @param agent agent object
4208 * @param callback function which is called for each
4209 * incoming request belonging to this leg
4210 * @param magic call leg context
4211 * @param tag,value,... optional extra headers in taglist
4212 *
4213 * When a leg representing dialog is created, the tags SIPTAG_CALL_ID(),
4214 * SIPTAG_FROM(), SIPTAG_TO(), and SIPTAG_CSEQ() (for local @CSeq number) are used
4215 * to establish dialog context. The SIPTAG_FROM() is used to pass local
4216 * address (@From header when making a call, @To header when answering
4217 * to a call) to the newly created leg. Respectively, the SIPTAG_TO() is
4218 * used to pass remote address (@To header when making a call, @From
4219 * header when answering to a call).
4220 *
4221 * If there is a (preloaded) route associated with the leg, SIPTAG_ROUTE()
4222 * and NTATAG_TARGET() can be used. A client or server can also set the
4223 * route using @RecordRoute and @Contact headers from a response or
4224 * request message with the functions nta_leg_client_route() and
4225 * nta_leg_server_route(), respectively.
4226 *
4227 * When a leg representing a local destination is created, the tags
4228 * NTATAG_NO_DIALOG(1), NTATAG_METHOD(), and URLTAG_URL() are used. When a
4229 * request with matching request-URI (URLTAG_URL()) and method
4230 * (NTATAG_METHOD()) is received, it is passed to the callback function
4231 * provided with the leg.
4232 *
4233 * @sa nta_leg_stateful(), nta_leg_bind(),
4234 * nta_leg_tag(), nta_leg_rtag(),
4235 * nta_leg_client_route(), nta_leg_server_route(),
4236 * nta_leg_destroy(), nta_outgoing_tcreate(), and nta_request_f().
4237 *
4238 * @TAGS
4239 * NTATAG_NO_DIALOG(), NTATAG_STATELESS(), NTATAG_METHOD(),
4240 * URLTAG_URL(), SIPTAG_CALL_ID(), SIPTAG_CALL_ID_STR(), SIPTAG_FROM(),
4241 * SIPTAG_FROM_STR(), SIPTAG_TO(), SIPTAG_TO_STR(), SIPTAG_ROUTE(),
4242 * NTATAG_TARGET() and SIPTAG_CSEQ().
4243 *
4244 */
4245nta_leg_t *nta_leg_tcreate(nta_agent_t *agent,
4246 nta_request_f *callback,
4247 nta_leg_magic_t *magic,
4248 tag_type_t tag, tag_value_t value, ...)
4249{
4250 sip_route_t const *route = NULL((void*)0);
4251 sip_contact_t const *contact = NULL((void*)0);
4252 sip_cseq_t const *cs = NULL((void*)0);
4253 sip_call_id_t const *i = NULL((void*)0);
4254 sip_from_t const *from = NULL((void*)0);
4255 sip_to_t const *to = NULL((void*)0);
4256 char const *method = NULL((void*)0);
4257 char const *i_str = NULL((void*)0), *to_str = NULL((void*)0), *from_str = NULL((void*)0), *cs_str = NULL((void*)0);
4258 url_string_t const *url_string = NULL((void*)0);
4259 int no_dialog = 0;
4260 unsigned rseq = 0;
4261 /* RFC 3261 section 12.2.1.1 */
4262 uint32_t seq = 0;
4263 ta_list ta;
4264 nta_leg_t *leg;
4265 su_home_t *home;
4266 url_t *url;
4267 char const *what = NULL((void*)0);
4268
4269 if (agent == NULL((void*)0))
4270 return su_seterrno(EINVAL22), NULL((void*)0);
4271
4272 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)
;
4273
4274 tl_gets(ta_args(ta)(ta).tl,
4275 NTATAG_NO_DIALOG_REF(no_dialog)ntatag_no_dialog_ref, tag_bool_vr(&(no_dialog)),
4276 NTATAG_METHOD_REF(method)ntatag_method_ref, tag_str_vr(&(method)),
4277 URLTAG_URL_REF(url_string)urltag_url_ref, urltag_url_vr(&(url_string)),
4278 SIPTAG_CALL_ID_REF(i)siptag_call_id_ref, siptag_call_id_vr(&(i)),
4279 SIPTAG_CALL_ID_STR_REF(i_str)siptag_call_id_str_ref, tag_str_vr(&(i_str)),
4280 SIPTAG_FROM_REF(from)siptag_from_ref, siptag_from_vr(&(from)),
4281 SIPTAG_FROM_STR_REF(from_str)siptag_from_str_ref, tag_str_vr(&(from_str)),
4282 SIPTAG_TO_REF(to)siptag_to_ref, siptag_to_vr(&(to)),
4283 SIPTAG_TO_STR_REF(to_str)siptag_to_str_ref, tag_str_vr(&(to_str)),
4284 SIPTAG_ROUTE_REF(route)siptag_route_ref, siptag_route_vr(&(route)),
4285 NTATAG_TARGET_REF(contact)ntatag_target_ref, siptag_contact_vr(&(contact)),
4286 NTATAG_REMOTE_CSEQ_REF(rseq)ntatag_remote_cseq_ref, tag_uint_vr(&(rseq)),
4287 SIPTAG_CSEQ_REF(cs)siptag_cseq_ref, siptag_cseq_vr(&(cs)),
4288 SIPTAG_CSEQ_STR_REF(cs_str)siptag_cseq_str_ref, tag_str_vr(&(cs_str)),
4289 TAG_END()(tag_type_t)0, (tag_value_t)0);
4290
4291 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))
;
4292
4293 if (cs)
4294 seq = cs->cs_seq;
4295 else if (cs_str)
4296 seq = strtoul(cs_str, (char **)&cs_str, 10);
4297
4298 if (i == NONE((void *)-1)) /* Magic value, used for compatibility */
4299 no_dialog = 1;
4300
4301 if (!(leg = su_home_clone(NULL((void*)0), sizeof(*leg))))
4302 return NULL((void*)0);
4303 home = leg->leg_home;
4304
4305 leg->leg_agent = agent;
4306 nta_leg_bind(leg, callback, magic);
4307
4308 if (from) {
4309 /* Now this is kludge */
4310 leg->leg_local_is_to = sip_is_to((sip_header_t*)from);
4311 leg->leg_local = sip_to_dup(home, from);
4312 }
4313 else if (from_str)
4314 leg->leg_local = sip_to_make(home, from_str);
4315
4316 if (to && no_dialog) {
4317 /* Remove tag, if any */
4318 sip_to_t to0[1]; *to0 = *to; to0->a_params = NULL((void*)0);
4319 leg->leg_remote = sip_from_dup(home, to0);
4320 }
4321 else if (to)
4322 leg->leg_remote = sip_from_dup(home, to);
4323 else if (to_str)
4324 leg->leg_remote = sip_from_make(home, to_str);
4325
4326 if (route && route != NONE((void *)-1))
4327 leg->leg_route = sip_route_dup(home, route), leg->leg_route_set = 1;
4328
4329 if (contact && contact != NONE((void *)-1)) {
4330 sip_contact_t m[1];
4331 sip_contact_init(m);
4332 *m->m_url = *contact->m_url;
4333 m->m_url->url_headers = NULL((void*)0);
4334 leg->leg_target = sip_contact_dup(home, m);
4335 }
4336
4337 url = url_hdup(home, url_string->us_url);
4338
4339 /* Match to local hosts */
4340 if (url && agent_aliases(agent, url, NULL((void*)0))) {
4341 url_t *changed = url_hdup(home, url);
4342 su_free(home, url);
4343 url = changed;
4344 }
4345
4346 leg->leg_rseq = rseq;
4347 leg->leg_seq = seq;
4348 leg->leg_url = url;
4349
4350 if (from && from != NONE((void *)-1) && leg->leg_local == NULL((void*)0)) {
4351 what = "cannot duplicate local address";
4352 goto err;
4353 }
4354 else if (to && to != NONE((void *)-1) && leg->leg_remote == NULL((void*)0)) {
4355 what = "cannot duplicate remote address";
4356 goto err;
4357 }
4358 else if (route && route != NONE((void *)-1) && leg->leg_route == NULL((void*)0)) {
4359 what = "cannot duplicate route";
4360 goto err;
4361 }
4362 else if (contact && contact != NONE((void *)-1) && leg->leg_target == NULL((void*)0)) {
4363 what = "cannot duplicate target";
4364 goto err;
4365 }
4366 else if (url_string && leg->leg_url == NULL((void*)0)) {
4367 what = "cannot duplicate local destination";
4368 goto err;
4369 }
4370
4371 if (!no_dialog) {
4372 if (!leg->leg_local || !leg->leg_remote) {
4373 /* To and/or From header missing */
4374 if (leg->leg_remote)
4375 what = "Missing local dialog address";
4376 else if (leg->leg_local)
4377 what = "Missing remote dialog address";
4378 else
4379 what = "Missing dialog addresses";
4380 goto err;
4381 }
4382
4383 leg->leg_dialog = 1;
4384
4385 if (i != NULL((void*)0))
4386 leg->leg_id = sip_call_id_dup(home, i);
4387 else if (i_str != NULL((void*)0))
4388 leg->leg_id = sip_call_id_make(home, i_str);
4389 else
4390 leg->leg_id = sip_call_id_create(home, NULL((void*)0));
4391
4392 if (!leg->leg_id) {
4393 what = "cannot create Call-ID";
4394 goto err;
4395 }
4396
4397 leg->leg_hash = leg->leg_id->i_hash;
4398 }
4399 else if (url) {
4400 /* This is "default leg" with a destination URL. */
4401 hash_value_t hash = 0;
4402
4403 if (method) {
4404 leg->leg_method = su_strdup(home, method);
4405 }
4406#if 0
4407 else if (url->url_params) {
4408 int len = url_param(url->url_params, "method", NULL((void*)0), 0);
4409 if (len) {
4410 char *tmp = su_alloc(home, len);
4411 leg->leg_method = tmp;
4412 url_param(url->url_params, "method", tmp, len);
4413 }
4414 }
4415#endif
4416
4417 if (url->url_user && strcmp(url->url_user, "") == 0)
4418 url->url_user = "%"; /* Match to any user */
4419
4420 hash = hash_istring(url->url_scheme, ":", 0);
4421 hash = hash_istring(url->url_host, "", hash);
4422 hash = hash_istring(url->url_user, "@", hash);
4423
4424 leg->leg_hash = hash;
4425 }
4426 else {
4427 /* This is "default leg" without a destination URL. */
4428 if (agent->sa_default_leg) {
4429 SU_DEBUG_1(("%s(): %s\n", "nta_leg_tcreate", "tried to create second default leg"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 4429, "%s(): %s\n", "nta_leg_tcreate", "tried to create second default leg"
)) : (void)0)
;
4430 su_seterrno(EEXIST17);
4431 goto err;
4432 }
4433 else {
4434 agent->sa_default_leg = leg;
4435 }
4436 return leg;
4437 }
4438
4439 if (url) {
4440 /* Parameters are ignored when comparing incoming URLs */
4441 url->url_params = NULL((void*)0);
4442 }
4443
4444 leg_insert(agent, leg);
4445
4446 SU_DEBUG_9(("%s(%p)\n", "nta_leg_tcreate", (void *)leg))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__
, 4446, "%s(%p)\n", "nta_leg_tcreate", (void *)leg)) : (void)
0)
;
4447
4448 return leg;
4449
4450 err:
4451 if (what)
4452 SU_DEBUG_9(("%s(): %s\n", "nta_leg_tcreate", what))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__
, 4452, "%s(): %s\n", "nta_leg_tcreate", what)) : (void)0)
;
4453
4454 su_home_zap(leg->leg_home)su_home_unref((leg->leg_home));
4455
4456 return NULL((void*)0);
4457}
4458
4459/** Return the default leg, if any */
4460nta_leg_t *nta_default_leg(nta_agent_t const *agent)
4461{
4462 return agent ? agent->sa_default_leg : NULL((void*)0);
4463}
4464
4465
4466/**
4467 * Insert a call leg to agent.
4468 */
4469static
4470void leg_insert(nta_agent_t *sa, nta_leg_t *leg)
4471{
4472 leg_htable_t *leg_hash;
4473 assert(leg)((void) sizeof ((leg) ? 1 : 0), __extension__ ({ if (leg) ; else
__assert_fail ("leg", "nta.c", 4473, __extension__ __PRETTY_FUNCTION__
); }))
;
4474 assert(sa)((void) sizeof ((sa) ? 1 : 0), __extension__ ({ if (sa) ; else
__assert_fail ("sa", "nta.c", 4474, __extension__ __PRETTY_FUNCTION__
); }))
;
4475
4476 if (leg->leg_dialog)
4477 leg_hash = sa->sa_dialogs;
4478 else
4479 leg_hash = sa->sa_defaults;
4480
4481 if (leg_htable_is_full(leg_hash)) {
4482 leg_htable_resize(sa->sa_home, leg_hash, 0);
4483 assert(leg_hash->lht_table)((void) sizeof ((leg_hash->lht_table) ? 1 : 0), __extension__
({ if (leg_hash->lht_table) ; else __assert_fail ("leg_hash->lht_table"
, "nta.c", 4483, __extension__ __PRETTY_FUNCTION__); }))
;
4484 SU_DEBUG_7(("nta: resized%s leg hash to "MOD_ZU"\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__
, 4485, "nta: resized%s leg hash to ""%zu""\n", leg->leg_dialog
? "" : " default", leg_hash->lht_size)) : (void)0)
4485 leg->leg_dialog ? "" : " default", leg_hash->lht_size))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__
, 4485, "nta: resized%s leg hash to ""%zu""\n", leg->leg_dialog
? "" : " default", leg_hash->lht_size)) : (void)0)
;
4486 }
4487
4488 /* Insert entry into hash table (before other legs with same hash) */
4489 leg_htable_insert(leg_hash, leg);
4490}
4491
4492/**
4493 * Destroy a leg.
4494 *
4495 * @param leg leg to be destroyed
4496 */
4497void nta_leg_destroy(nta_leg_t *leg)
4498{
4499 SU_DEBUG_9(("nta_leg_destroy(%p)\n", (void *)leg))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__
, 4499, "nta_leg_destroy(%p)\n", (void *)leg)) : (void)0)
;
4500
4501 if (leg) {
4502 leg_htable_t *leg_hash;
4503 nta_agent_t *sa = leg->leg_agent;
4504
4505 assert(sa)((void) sizeof ((sa) ? 1 : 0), __extension__ ({ if (sa) ; else
__assert_fail ("sa", "nta.c", 4505, __extension__ __PRETTY_FUNCTION__
); }))
;
4506
4507 if (leg->leg_dialog) {
4508 assert(sa->sa_dialogs)((void) sizeof ((sa->sa_dialogs) ? 1 : 0), __extension__ (
{ if (sa->sa_dialogs) ; else __assert_fail ("sa->sa_dialogs"
, "nta.c", 4508, __extension__ __PRETTY_FUNCTION__); }))
;
4509 leg_hash = sa->sa_dialogs;
4510 }
4511 else if (leg != sa->sa_default_leg) {
4512 assert(sa->sa_defaults)((void) sizeof ((sa->sa_defaults) ? 1 : 0), __extension__ (
{ if (sa->sa_defaults) ; else __assert_fail ("sa->sa_defaults"
, "nta.c", 4512, __extension__ __PRETTY_FUNCTION__); }))
;
4513 leg_hash = sa->sa_defaults;
4514 }
4515 else {
4516 sa->sa_default_leg = NULL((void*)0);
4517 leg_hash = NULL((void*)0);
4518 }
4519
4520 if (leg_hash)
4521 leg_htable_remove(leg_hash, leg);
4522
4523 leg_free(sa, leg);
4524 }
4525}
4526
4527static
4528void leg_free(nta_agent_t *sa, nta_leg_t *leg)
4529{
4530 //su_free(sa->sa_home, leg);
4531 su_home_unref((su_home_t *)leg);
4532}
4533
4534/** Return application context for the leg */
4535nta_leg_magic_t *nta_leg_magic(nta_leg_t const *leg,
4536 nta_request_f *callback)
4537{
4538 if (leg)
4539 if (!callback || leg->leg_callback == callback)
4540 return leg->leg_magic;
4541
4542 return NULL((void*)0);
4543}
4544
4545/**Bind a callback function and context to a leg object.
4546 *
4547 * Change the callback function and context pointer attached to a leg
4548 * object.
4549 *
4550 * @param leg leg object to be bound
4551 * @param callback new callback function (or NULL if no callback is desired)
4552 * @param magic new context pointer
4553 */
4554void nta_leg_bind(nta_leg_t *leg,
4555 nta_request_f *callback,
4556 nta_leg_magic_t *magic)
4557{
4558 if (leg) {
4559 if (callback)
4560 leg->leg_callback = callback;
4561 else
4562 leg->leg_callback = leg_callback_default;
4563 leg->leg_magic = magic;
4564 }
4565}
4566
4567/** Add a local tag to the leg.
4568 *
4569 * @param leg leg to be tagged
4570 * @param tag tag to be added (if NULL, a tag generated by @b NTA is added)
4571 *
4572 * @return
4573 * Pointer to tag if successful, NULL otherwise.
4574 */
4575char const *nta_leg_tag(nta_leg_t *leg, char const *tag)
4576{
4577 if (!leg || !leg->leg_local)
4578 return su_seterrno(EINVAL22), NULL((void*)0);
4579
4580 if (tag && strchr(tag, '='))
4581 tag = strchr(tag, '=') + 1;
4582
4583 /* If there already is a tag,
4584 return NULL if it does not match with new one */
4585 if (leg->leg_local->a_tag) {
4586 if (tag == NULL((void*)0) || su_casematch(tag, leg->leg_local->a_tag))
4587 return leg->leg_local->a_tag;
4588 else
4589 return NULL((void*)0);
4590 }
4591
4592 if (tag) {
4593 if (sip_to_tag(leg->leg_home, leg->leg_local, tag) < 0)
4594 return NULL((void*)0);
4595 leg->leg_tagged = 1;
4596 return leg->leg_local->a_tag;
4597 }
4598
4599 tag = nta_agent_newtag(leg->leg_home, "tag=%s", leg->leg_agent);
4600
4601 if (!tag || sip_to_add_param(leg->leg_home, leg->leg_local, tag) < 0)
4602 return NULL((void*)0);
4603
4604 leg->leg_tagged = 1;
4605
4606 return leg->leg_local->a_tag;
4607}
4608
4609/** Get local tag. */
4610char const *nta_leg_get_tag(nta_leg_t const *leg)
4611{
4612 if (leg && leg->leg_local)
4613 return leg->leg_local->a_tag;
4614 else
4615 return NULL((void*)0);
4616}
4617
4618/** Add a remote tag to the leg.
4619 *
4620 * @note No remote tag is ever generated.
4621 *
4622 * @param leg leg to be tagged
4623 * @param tag tag to be added (@b must be non-NULL)
4624 *
4625 * @return
4626 * Pointer to tag if successful, NULL otherwise.
4627 */
4628char const *nta_leg_rtag(nta_leg_t *leg, char const *tag)
4629{
4630 /* Add a tag parameter, unless there already is a tag */
4631 if (leg && leg->leg_remote && tag) {
4632 if (sip_from_tag(leg->leg_home, leg->leg_remote, tag) < 0)
4633 return NULL((void*)0);
4634 }
4635
4636 if (leg && leg->leg_remote)
4637 return leg->leg_remote->a_tag;
4638 else
4639 return NULL((void*)0);
4640}
4641
4642/** Get remote tag. */
4643char const *nta_leg_get_rtag(nta_leg_t const *leg)
4644{
4645 if (leg && leg->leg_remote)
4646 return leg->leg_remote->a_tag;
4647 else
4648 return NULL((void*)0);
4649}
4650
4651/** Get local request sequence number. */
4652uint32_t nta_leg_get_seq(nta_leg_t const *leg)
4653{
4654 return leg ? leg->leg_seq : 0;
4655}
4656
4657/** Get remote request sequence number. */
4658uint32_t nta_leg_get_rseq(nta_leg_t const *leg)
4659{
4660 return leg ? leg->leg_rseq : 0;
4661}
4662
4663/** Save target and route set at UAC side.
4664 *
4665 * @sa nta_leg_client_reroute(), nta_leg_server_route(), @RFC3261 section 12.1.2
4666 *
4667 * @bug Allows modifying the route set after initial transaction, if initial
4668 * transaction had no @RecordRoute headers.
4669 *
4670 * @deprecated Use nta_leg_client_reroute() instead.
4671 */
4672int nta_leg_client_route(nta_leg_t *leg,
4673 sip_record_route_t const *route,
4674 sip_contact_t const *contact)
4675{
4676 return leg_route(leg, NULL((void*)0), route, contact, 0);
4677}
4678
4679/** Save target and route set at UAC side.
4680 *
4681 * If @a initial is true, the route set is modified even if it has been set
4682 * earlier.
4683 *
4684 * @param leg pointer to dialog leg
4685 * @param route @RecordRoute headers from response
4686 * @param contact @Contact header from response
4687 * @param initial true if response to initial transaction
4688 *
4689 * @sa nta_leg_client_route(), nta_leg_server_route(), @RFC3261 section 12.1.2
4690 *
4691 * @NEW_1_12_11
4692 */
4693int nta_leg_client_reroute(nta_leg_t *leg,
4694 sip_record_route_t const *route,
4695 sip_contact_t const *contact,
4696 int initial)
4697{
4698 return leg_route(leg, NULL((void*)0), route, contact, initial ? 2 : 1);
4699}
4700
4701/** Save target and route set at UAS side.
4702 *
4703 * @param leg pointer to dialog leg
4704 * @param route @RecordRoute headers from request
4705 * @param contact @Contact header from request
4706 *
4707 * @sa nta_leg_client_reroute(), @RFC3261 section 12.1.1
4708 */
4709int nta_leg_server_route(nta_leg_t *leg,
4710 sip_record_route_t const *route,
4711 sip_contact_t const *contact)
4712{
4713 return leg_route(leg, route, NULL((void*)0), contact, 1);
4714}
4715
4716/** Return route components. */
4717int nta_leg_get_route(nta_leg_t *leg,
4718 sip_route_t const **return_route,
4719 sip_contact_t const **return_target)
4720{
4721 if (!leg)
4722 return -1;
4723
4724 if (return_route)
4725 *return_route = leg->leg_route;
4726
4727 if (return_target)
4728 *return_target = leg->leg_target;
4729
4730 return 0;
4731}
4732
4733/** Generate @Replaces header.
4734 *
4735 * @since New in @VERSION_1_12_2.
4736 */
4737sip_replaces_t *
4738nta_leg_make_replaces(nta_leg_t *leg,
4739 su_home_t *home,
4740 int early_only)
4741{
4742 char const *from_tag, *to_tag;
4743
4744 if (!leg)
4745 return NULL((void*)0);
4746 if (!leg->leg_dialog || !leg->leg_local || !leg->leg_remote || !leg->leg_id)
4747 return NULL((void*)0);
4748
4749 from_tag = leg->leg_local->a_tag; if (!from_tag) from_tag = "0";
4750 to_tag = leg->leg_remote->a_tag; if (!to_tag) to_tag = "0";
4751
4752 return sip_replaces_format(home, "%s;from-tag=%s;to-tag=%s%s",
4753 leg->leg_id->i_id, from_tag, to_tag,
4754 early_only ? ";early-only" : "");
4755}
4756
4757/** Get dialog leg by @Replaces header.
4758 *
4759 * @since New in @VERSION_1_12_2.
4760 */
4761nta_leg_t *
4762nta_leg_by_replaces(nta_agent_t *sa, sip_replaces_t const *rp)
4763{
4764 nta_leg_t *leg = NULL((void*)0);
4765
4766 if (sa && rp && rp->rp_call_id && rp->rp_from_tag && rp->rp_to_tag) {
4767 char const *from_tag = rp->rp_from_tag, *to_tag = rp->rp_to_tag;
4768 sip_call_id_t id[1];
4769 sip_call_id_init(id);
4770
4771 id->i_hash = msg_hash_string(id->i_id = rp->rp_call_id);
4772
4773 leg = leg_find(sa, NULL((void*)0), NULL((void*)0), id, from_tag, to_tag);
4774
4775 if (leg == NULL((void*)0) && strcmp(from_tag, "0") == 0)
4776 leg = leg_find(sa, NULL((void*)0), NULL((void*)0), id, NULL((void*)0), to_tag);
4777 if (leg == NULL((void*)0) && strcmp(to_tag, "0") == 0)
4778 leg = leg_find(sa, NULL((void*)0), NULL((void*)0), id, from_tag, NULL((void*)0));
4779 }
4780
4781 return leg;
4782}
4783
4784/**@internal
4785 * Find a leg corresponding to the request message.
4786 *
4787 */
4788static nta_leg_t *
4789leg_find_call_id(nta_agent_t const *sa,
4790 sip_call_id_t const *i)
4791{
4792 hash_value_t hash = i->i_hash;
4793 leg_htable_t const *lht = sa->sa_dialogs;
4794 nta_leg_t **ll, *leg = NULL((void*)0);
4795
4796 for (ll = leg_htable_hash(lht, hash);
4797 (leg = *ll);
4798 ll = leg_htable_next(lht, ll)) {
4799 sip_call_id_t const *leg_i = leg->leg_id;
4800
4801 if (leg->leg_hash != hash)
4802 continue;
4803 if (strcmp(leg_i->i_id, i->i_id) != 0)
4804 continue;
4805
4806 return leg;
4807 }
4808
4809 return leg;
4810}
4811
4812/** Get dialog leg by @CallID.
4813 *
4814 * @note Usually there should be only single dialog per @CallID on
4815 * User-Agents. However, proxies may fork requests initiating the dialog and
4816 * result in multiple calls per @CallID.
4817 *
4818 * @since New in @VERSION_1_12_9.
4819 */
4820nta_leg_t *
4821nta_leg_by_call_id(nta_agent_t *sa, const char *call_id)
4822{
4823 nta_leg_t *leg = NULL((void*)0);
4824
4825 if (call_id) {
4826 sip_call_id_t id[1];
4827 sip_call_id_init(id);
4828
4829 id->i_hash = msg_hash_string(id->i_id = call_id);
4830
4831 leg = leg_find_call_id(sa, id);
4832 }
4833
4834 return leg;
4835}
4836
4837/** Calculate a simple case-insensitive hash over a string */
4838su_inlinestatic inline
4839hash_value_t hash_istring(char const *s, char const *term, hash_value_t hash)
4840{
4841 if (s) {
4842 for (; *s; s++) {
4843 unsigned char c = *s;
4844 if ('A' <= c && c <= 'Z')
4845 c += 'a' - 'A';
4846 hash = 38501U * (hash + c);
4847 }
4848 for (s = term; *s; s++) {
4849 unsigned char c = *s;
4850 hash = 38501U * (hash + c);
4851 }
4852 }
4853
4854 return hash;
4855}
4856
4857/** @internal Handle requests intended for this leg. */
4858static
4859void leg_recv(nta_leg_t *leg, msg_t *msg, sip_t *sip, tport_t *tport)
4860{
4861 nta_agent_t *agent = leg->leg_agent;
4862 nta_incoming_t *irq;
4863 sip_method_t method = sip->sip_request->rq_method;
4864 char const *method_name = sip->sip_request->rq_method_name;
4865 char const *tag = NULL((void*)0);
4866 int status;
4867
4868 if (leg->leg_local)
4869 tag = leg->leg_local->a_tag;
4870
4871 if (leg->leg_dialog)
4872 agent->sa_stats->as_dialog_tr++;
4873
4874 /* RFC-3262 section 3 (page 4) */
4875 if (agent->sa_is_a_uas && method == sip_method_prack) {
4876 mreply(agent, NULL((void*)0), 481, "No such response", msg,
4877 tport, 0, 0, NULL((void*)0),
4878 TAG_END()(tag_type_t)0, (tag_value_t)0);
4879 return;
4880 }
4881
4882 if (!(irq = incoming_create(agent, msg, sip, tport, tag))) {
4883 SU_DEBUG_3(("nta: leg_recv(%p): cannot create transaction for %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 4884, "nta: leg_recv(%p): cannot create transaction for %s\n"
, (void *)leg, method_name)) : (void)0)
4884 (void *)leg, method_name))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 4884, "nta: leg_recv(%p): cannot create transaction for %s\n"
, (void *)leg, method_name)) : (void)0)
;
4885 mreply(agent, NULL((void*)0), SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error, msg,
4886 tport, 0, 0, NULL((void*)0),
4887 TAG_END()(tag_type_t)0, (tag_value_t)0);
4888 return;
4889 }
4890
4891 irq->irq_compressed = leg->leg_compressed;
4892 irq->irq_in_callback = 1;
4893 status = incoming_callback(leg, irq, sip);
4894 irq->irq_in_callback = 0;
4895
4896 if (irq->irq_destroyed) {
4897 if (irq->irq_terminated) {
4898 incoming_free(irq);
4899 return;
4900 }
4901 if (status < 200)
4902 status = 500;
4903 }
4904
4905 if (status == 0)
4906 return;
4907
4908 if (status < 100 || status > 699) {
4909 SU_DEBUG_3(("nta_leg(%p): invalid status %03d from callback\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 4910, "nta_leg(%p): invalid status %03d from callback\n", (
void *)leg, status)) : (void)0)
4910 (void *)leg, status))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 4910, "nta_leg(%p): invalid status %03d from callback\n", (
void *)leg, status)) : (void)0)
;
4911 status = 500;
4912 }
4913 else if (method == sip_method_invite && status >= 200 && status < 300) {
4914 SU_DEBUG_3(("nta_leg(%p): invalid INVITE status %03d from callback\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 4915, "nta_leg(%p): invalid INVITE status %03d from callback\n"
, (void *)leg, status)) : (void)0)
4915 (void *)leg, status))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 4915, "nta_leg(%p): invalid INVITE status %03d from callback\n"
, (void *)leg, status)) : (void)0)
;
4916 status = 500;
4917 }
4918
4919 if (status >= 100 && irq->irq_status < 200)
4920 nta_incoming_treply(irq, status, NULL((void*)0), TAG_END()(tag_type_t)0, (tag_value_t)0);
4921
4922 if (status >= 200)
4923 nta_incoming_destroy(irq);
4924}
4925
4926#if 0
4927/**Compare two SIP from/to fields.
4928 *
4929 * @retval nonzero if matching.
4930 * @retval zero if not matching.
4931 */
4932su_inlinestatic inline
4933int addr_cmp(url_t const *a, url_t const *b)
4934{
4935 if (b == NULL((void*)0))
4936 return 0;
4937 else
4938 return
4939 host_cmp(a->url_host, b->url_host) ||
4940 su_strcmp(a->url_port, b->url_port) ||
4941 su_strcmp(a->url_user, b->url_user);
4942}
4943#endif
4944
4945/** Get a leg by dialog.
4946 *
4947 * Search for a dialog leg from agent's hash table. The matching rules based
4948 * on parameters are as follows:
4949 *
4950 * @param agent pointer to agent object
4951 * @param request_uri if non-NULL, and there is destination URI
4952 * associated with the dialog, these URIs must match
4953 * @param call_id if non-NULL, must match with @CallID header contents
4954 * @param remote_tag if there is remote tag
4955 * associated with dialog, @a remote_tag must match
4956 * @param remote_uri ignored
4957 * @param local_tag if non-NULL and there is local tag associated with leg,
4958 * it must math
4959 * @param local_uri ignored
4960 *
4961 * @note
4962 * If @a remote_tag or @a local_tag is an empty string (""), the tag is
4963 * ignored when matching legs.
4964 */
4965nta_leg_t *nta_leg_by_dialog(nta_agent_t const *agent,
4966 url_t const *request_uri,
4967 sip_call_id_t const *call_id,
4968 char const *remote_tag,
4969 url_t const *remote_uri,
4970 char const *local_tag,
4971 url_t const *local_uri)
4972{
4973 void *to_be_freed = NULL((void*)0);
4974 url_t *url;
4975 url_t url0[1];
4976 nta_leg_t *leg;
4977
4978 if (!agent || !call_id)
4979 return su_seterrno(EINVAL22), NULL((void*)0);
4980
4981 if (request_uri == NULL((void*)0)) {
4982 url = NULL((void*)0);
4983 }
4984 else if (URL_IS_STRING(request_uri)((request_uri) && *((url_string_t*)(request_uri))->
us_str != 0)
) {
4985 /* accept a string as URL */
4986 to_be_freed = url = url_hdup(NULL((void*)0), request_uri);
4987 }
4988 else {
4989 *url0 = *request_uri, url = url0;
4990 }
4991
4992 if (url) {
4993 url->url_params = NULL((void*)0);
4994 agent_aliases(agent, url, NULL((void*)0)); /* canonize url */
4995 }
4996
4997 if (remote_tag && remote_tag[0] == '\0')
4998 remote_tag = NULL((void*)0);
4999 if (local_tag && local_tag[0] == '\0')
5000 local_tag = NULL((void*)0);
5001
5002 leg = leg_find(agent,
5003 NULL((void*)0), url,
5004 call_id,
5005 remote_tag,
5006 local_tag);
5007
5008 if (to_be_freed) su_free(NULL((void*)0), to_be_freed);
5009
5010 return leg;
5011}
5012
5013/**@internal
5014 * Find a leg corresponding to the request message.
5015 *
5016 * A leg matches to message if leg_match_request() returns true ("Call-ID",
5017 * "To"-tag, and "From"-tag match).
5018 */
5019static
5020nta_leg_t *leg_find(nta_agent_t const *sa,
5021 char const *method_name,
5022 url_t const *request_uri,
5023 sip_call_id_t const *i,
5024 char const *from_tag,
5025 char const *to_tag)
5026{
5027 hash_value_t hash = i->i_hash;
5028 leg_htable_t const *lht = sa->sa_dialogs;
5029 nta_leg_t **ll, *leg, *loose_match = NULL((void*)0);
5030
5031 for (ll = leg_htable_hash(lht, hash);
5032 (leg = *ll);
5033 ll = leg_htable_next(lht, ll)) {
5034 sip_call_id_t const *leg_i = leg->leg_id;
5035 char const *remote_tag = leg->leg_remote->a_tag;
5036 char const *local_tag = leg->leg_local->a_tag;
5037
5038 url_t const *leg_url = leg->leg_url;
5039 char const *leg_method = leg->leg_method;
5040
5041 if (leg->leg_hash != hash)
5042 continue;
5043 if (strcmp(leg_i->i_id, i->i_id) != 0)
5044 continue;
5045
5046 /* Do not match if the incoming To has tag, but the local does not */
5047 if (!local_tag && to_tag)
5048 continue;
5049
5050 /*
5051 * Do not match if incoming To has no tag and we have local tag
5052 * and the tag has been there from the beginning.
5053 */
5054 if (local_tag && !to_tag && !leg->leg_tagged)
5055 continue;
5056
5057 /* Do not match if incoming From has no tag but remote has a tag */
5058 if (remote_tag && !from_tag)
5059 continue;
5060
5061 /* Avoid matching with itself */
5062 if (!remote_tag != !from_tag && !local_tag != !to_tag)
5063 continue;
5064
5065 if (local_tag && to_tag && !su_casematch(local_tag, to_tag) && to_tag[0])
5066 continue;
5067 if (remote_tag && from_tag && !su_casematch(remote_tag, from_tag) && from_tag[0])
5068 continue;
5069
5070 if (leg_url && request_uri && url_cmp(leg_url, request_uri))
5071 continue;
5072 if (leg_method && method_name && !su_casematch(method_name, leg_method))
5073 continue;
5074
5075 /* Perfect match if both local and To have tag
5076 * or local does not have tag.
5077 */
5078 if ((!local_tag || to_tag))
5079 return leg;
5080
5081 if (loose_match == NULL((void*)0))
5082 loose_match = leg;
5083 }
5084
5085 return loose_match;
5086}
5087
5088/** Get leg by destination */
5089nta_leg_t *nta_leg_by_uri(nta_agent_t const *agent, url_string_t const *us)
5090{
5091 url_t *url;
5092 nta_leg_t *leg = NULL((void*)0);
5093
5094 if (!agent)
5095 return NULL((void*)0);
5096
5097 if (!us)
5098 return agent->sa_default_leg;
5099
5100 url = url_hdup(NULL((void*)0), us->us_url);
5101
5102 if (url) {
5103 agent_aliases(agent, url, NULL((void*)0));
5104 leg = dst_find(agent, url, NULL((void*)0));
5105 su_free(NULL((void*)0), url);
5106 }
5107
5108 return leg;
5109}
5110
5111/** Find a non-dialog leg corresponding to the request uri u0 */
5112static
5113nta_leg_t *dst_find(nta_agent_t const *sa,
5114 url_t const *u0,
5115 char const *method_name)
5116{
5117 hash_value_t hash, hash2;
5118 leg_htable_t const *lht = sa->sa_defaults;
5119 nta_leg_t **ll, *leg, *loose_match = NULL((void*)0);
5120 int again;
5121 url_t url[1];
5122
5123 *url = *u0;
5124 hash = hash_istring(url->url_scheme, ":", 0);
5125 hash = hash_istring(url->url_host, "", hash);
5126 hash2 = hash_istring("%", "@", hash);
5127 hash = hash_istring(url->url_user, "@", hash);
5128
5129 /* First round, search with user name */
5130 /* Second round, search without user name */
5131 do {
5132 for (ll = leg_htable_hash(lht, hash);
5133 (leg = *ll);
5134 ll = leg_htable_next(lht, ll)) {
5135 if (leg->leg_hash != hash)
5136 continue;
5137 if (url_cmp(url, leg->leg_url))
5138 continue;
5139 if (!method_name) {
5140 if (leg->leg_method)
5141 continue;
5142 return leg;
5143 }
5144 else if (leg->leg_method) {
5145 if (!su_casematch(method_name, leg->leg_method))
5146 continue;
5147 return leg;
5148 }
5149 loose_match = leg;
5150 }
5151 if (loose_match)
5152 return loose_match;
5153
5154 again = 0;
5155
5156 if (url->url_user && strcmp(url->url_user, "%")) {
5157 url->url_user = "%";
5158 hash = hash2;
5159 again = 1;
5160 }
5161 } while (again);
5162
5163 return NULL((void*)0);
5164}
5165
5166/** Set leg route and target URL.
5167 *
5168 * Sets the leg route and contact using the @RecordRoute and @Contact
5169 * headers.
5170 *
5171 * @param reroute - allow rerouting
5172 * - if 1, follow @RFC3261 semantics
5173 * - if 2, response to initial transaction)
5174 */
5175static
5176int leg_route(nta_leg_t *leg,
5177 sip_record_route_t const *route,
5178 sip_record_route_t const *reverse,
5179 sip_contact_t const *contact,
5180 int reroute)
5181{
5182 su_home_t *home = leg->leg_home;
5183 sip_route_t *r, r0[1], *old;
5184 int route_is_set;
5185
5186 if (!leg)
5187 return -1;
5188
5189 if (route == NULL((void*)0) && reverse == NULL((void*)0) && contact == NULL((void*)0))
5190 return 0;
5191
5192 sip_route_init(r0);
5193
5194 route_is_set = reroute ? leg->leg_route_set : leg->leg_route != NULL((void*)0);
5195
5196 if (route_is_set && reroute <= 1) {
5197 r = leg->leg_route;
5198 }
5199 else if (route) {
5200 r = sip_route_fixdup(home, route); if (!r) return -1;
5201 }
5202 else if (reverse) {
5203 r = sip_route_reverse(home, reverse); if (!r) return -1;
5204 }
5205 else
5206 r = NULL((void*)0);
5207
5208#ifdef NTA_STRICT_ROUTING
5209 /*
5210 * Handle Contact according to the RFC2543bis04 sections 16.1, 16.2 and 16.4.
5211 */
5212 if (contact) {
5213 *r0->r_url = *contact->m_url;
5214
5215 if (!(m_r = sip_route_dup(leg->leg_home, r0)))
5216 return -1;
5217
5218 /* Append, but replace last entry if it was generated from contact */
5219 for (rr = &r; *rr; rr = &(*rr)->r_next)
5220 if (leg->leg_contact_set && (*rr)->r_next == NULL((void*)0))
5221 break;
5222 }
5223 else
5224 rr = NULL((void*)0);
5225
5226 if (rr) {
5227 if (*rr)
5228 su_free(leg->leg_home, *rr);
5229 *rr = m_r;
5230 }
5231 if (m_r != NULL((void*)0))
5232 leg->leg_contact_set = 1;
5233
5234#else
5235 if (r && r->r_url->url_params)
5236 leg->leg_loose_route = url_has_param(r->r_url, "lr");
5237
5238 if (contact) {
5239 sip_contact_t *target, m[1], *m0;
5240
5241 sip_contact_init(m);
5242 *m->m_url = *contact->m_url;
5243 m->m_url->url_headers = NULL((void*)0);
5244 target = sip_contact_dup(leg->leg_home, m);
5245
5246 if (target && target->m_url->url_params) {
5247 /* Remove ttl, method. @RFC3261 table 1, page 152 */
5248 char *p = (char *)target->m_url->url_params;
5249 p = url_strip_param_string(p, "method");
5250 p = url_strip_param_string(p, "ttl");
5251 target->m_url->url_params = p;
5252 }
5253
5254 m0 = leg->leg_target, leg->leg_target = target;
5255
5256 if (m0)
5257 su_free(leg->leg_home, m0);
5258 }
5259#endif
5260
5261 old = leg->leg_route;
5262 leg->leg_route = r;
5263
5264 if (old && old != r)
5265 msg_header_free(leg->leg_home, (msg_header_t *)old);
5266
5267 leg->leg_route_set = 1;
5268
5269 return 0;
5270}
5271
5272/** @internal Default leg callback. */
5273static int
5274leg_callback_default(nta_leg_magic_t *magic,
5275 nta_leg_t *leg,
5276 nta_incoming_t *irq,
5277 sip_t const *sip)
5278{
5279 nta_incoming_treply(irq,
5280 SIP_501_NOT_IMPLEMENTED501, sip_501_Not_implemented,
5281 TAG_END()(tag_type_t)0, (tag_value_t)0);
5282 return 501;
5283}
5284
5285/* ====================================================================== */
5286/* 7) Server-side (incoming) transactions */
5287
5288#define HTABLE_HASH_IRQ(irq)((irq)->irq_hash) ((irq)->irq_hash)
5289HTABLE_BODIES_WITH(incoming_htable, iht, nta_incoming_t, HTABLE_HASH_IRQ,static inline int incoming_htable_resize(su_home_t *home, incoming_htable_t
iht[], size_t new_size) { nta_incoming_t **new_hash; nta_incoming_t
**old_hash = iht->iht_table; size_t old_size; size_t i, j
, i0; unsigned again = 0; size_t used = 0, collisions = 0; if
(new_size == 0) new_size = 2 * iht->iht_size + 1; if (new_size
< 31) new_size = 31; if (new_size < 5 * iht->iht_used
/ 4) new_size = 5 * iht->iht_used / 4; if (!(new_hash = su_zalloc
(home, sizeof(*new_hash) * new_size))) return -1; old_size = iht
->iht_size; do for (j = 0; j < old_size; j++) { if (!old_hash
[j]) continue; if (again < 2 && ((old_hash[j])->
irq_hash) % old_size > j) { again = 1; continue; } i0 = ((
old_hash[j])->irq_hash) % new_size; for (i = i0; new_hash[
i]; i = (i + 1) % new_size, ((void) sizeof ((i != i0) ? 1 : 0
), __extension__ ({ if (i != i0) ; else __assert_fail ("i != i0"
, "nta.c", 5290, __extension__ __PRETTY_FUNCTION__); }))) collisions
++; new_hash[i] = old_hash[j], old_hash[j] = ((void*)0); used
++; } while (again++ == 1); iht->iht_table = new_hash, iht
->iht_size = new_size; ((void) sizeof ((iht->iht_used ==
used) ? 1 : 0), __extension__ ({ if (iht->iht_used == used
) ; else __assert_fail ("iht->iht_used == used", "nta.c", 5290
, __extension__ __PRETTY_FUNCTION__); })); su_free(home, old_hash
); return 0; } static inline int incoming_htable_is_full(incoming_htable_t
const *iht) { return iht->iht_table == ((void*)0) || 3 * iht
->iht_used > 2 * iht->iht_size; } static inline nta_incoming_t
**incoming_htable_hash(incoming_htable_t const *iht, hash_value_t
hv) { return iht->iht_table + hv % iht->iht_size; } static
inline nta_incoming_t **incoming_htable_next(incoming_htable_t
const *iht, nta_incoming_t * const *ee) { if (++ee < iht->
iht_table + iht->iht_size && ee >= iht->iht_table
) return (nta_incoming_t **)ee; else return iht->iht_table
; } static inline void incoming_htable_append(incoming_htable_t
*iht, nta_incoming_t const *e) { nta_incoming_t **ee; iht->
iht_used++; for (ee = incoming_htable_hash(iht, ((e)->irq_hash
)); *ee; ee = incoming_htable_next(iht, ee)) ; *ee = (nta_incoming_t
*)e; } static inline void incoming_htable_insert(incoming_htable_t
*iht, nta_incoming_t const *e) { nta_incoming_t *e0, **ee; iht
->iht_used++; for (ee = incoming_htable_hash(iht, ((e)->
irq_hash)); (e0 = *ee); ee = incoming_htable_next(iht, ee)) *
ee = (nta_incoming_t *)e, e = e0; *ee = (nta_incoming_t *)e; }
static inline int incoming_htable_remove(incoming_htable_t *
iht, nta_incoming_t const *e) { size_t i, j, k; size_t size =
iht->iht_size; nta_incoming_t **htable = iht->iht_table
; if (!e) return -1; for (i = ((e)->irq_hash) % size; htable
[i]; i = (i + 1) % size) if (e == htable[i]) break; if (!htable
[i]) return -1; for (j = (i + 1) % size; htable[j]; j = (j + 1
) % size) { k = ((htable[j])->irq_hash) % size; if (k == j
) continue; if (j > i ? (i < k && k < j) : (
i < k || k < j)) continue; htable[i] = htable[j], i = j
; } iht->iht_used--; htable[i] = ((void*)0); return 0; } extern
int incoming_htable_dummy
5290 size_t, hash_value_t)static inline int incoming_htable_resize(su_home_t *home, incoming_htable_t
iht[], size_t new_size) { nta_incoming_t **new_hash; nta_incoming_t
**old_hash = iht->iht_table; size_t old_size; size_t i, j
, i0; unsigned again = 0; size_t used = 0, collisions = 0; if
(new_size == 0) new_size = 2 * iht->iht_size + 1; if (new_size
< 31) new_size = 31; if (new_size < 5 * iht->iht_used
/ 4) new_size = 5 * iht->iht_used / 4; if (!(new_hash = su_zalloc
(home, sizeof(*new_hash) * new_size))) return -1; old_size = iht
->iht_size; do for (j = 0; j < old_size; j++) { if (!old_hash
[j]) continue; if (again < 2 && ((old_hash[j])->
irq_hash) % old_size > j) { again = 1; continue; } i0 = ((
old_hash[j])->irq_hash) % new_size; for (i = i0; new_hash[
i]; i = (i + 1) % new_size, ((void) sizeof ((i != i0) ? 1 : 0
), __extension__ ({ if (i != i0) ; else __assert_fail ("i != i0"
, "nta.c", 5290, __extension__ __PRETTY_FUNCTION__); }))) collisions
++; new_hash[i] = old_hash[j], old_hash[j] = ((void*)0); used
++; } while (again++ == 1); iht->iht_table = new_hash, iht
->iht_size = new_size; ((void) sizeof ((iht->iht_used ==
used) ? 1 : 0), __extension__ ({ if (iht->iht_used == used
) ; else __assert_fail ("iht->iht_used == used", "nta.c", 5290
, __extension__ __PRETTY_FUNCTION__); })); su_free(home, old_hash
); return 0; } static inline int incoming_htable_is_full(incoming_htable_t
const *iht) { return iht->iht_table == ((void*)0) || 3 * iht
->iht_used > 2 * iht->iht_size; } static inline nta_incoming_t
**incoming_htable_hash(incoming_htable_t const *iht, hash_value_t
hv) { return iht->iht_table + hv % iht->iht_size; } static
inline nta_incoming_t **incoming_htable_next(incoming_htable_t
const *iht, nta_incoming_t * const *ee) { if (++ee < iht->
iht_table + iht->iht_size && ee >= iht->iht_table
) return (nta_incoming_t **)ee; else return iht->iht_table
; } static inline void incoming_htable_append(incoming_htable_t
*iht, nta_incoming_t const *e) { nta_incoming_t **ee; iht->
iht_used++; for (ee = incoming_htable_hash(iht, ((e)->irq_hash
)); *ee; ee = incoming_htable_next(iht, ee)) ; *ee = (nta_incoming_t
*)e; } static inline void incoming_htable_insert(incoming_htable_t
*iht, nta_incoming_t const *e) { nta_incoming_t *e0, **ee; iht
->iht_used++; for (ee = incoming_htable_hash(iht, ((e)->
irq_hash)); (e0 = *ee); ee = incoming_htable_next(iht, ee)) *
ee = (nta_incoming_t *)e, e = e0; *ee = (nta_incoming_t *)e; }
static inline int incoming_htable_remove(incoming_htable_t *
iht, nta_incoming_t const *e) { size_t i, j, k; size_t size =
iht->iht_size; nta_incoming_t **htable = iht->iht_table
; if (!e) return -1; for (i = ((e)->irq_hash) % size; htable
[i]; i = (i + 1) % size) if (e == htable[i]) break; if (!htable
[i]) return -1; for (j = (i + 1) % size; htable[j]; j = (j + 1
) % size) { k = ((htable[j])->irq_hash) % size; if (k == j
) continue; if (j > i ? (i < k && k < j) : (
i < k || k < j)) continue; htable[i] = htable[j], i = j
; } iht->iht_used--; htable[i] = ((void*)0); return 0; } extern
int incoming_htable_dummy
;
5291
5292static void incoming_insert(nta_agent_t *agent,
5293 incoming_queue_t *queue,
5294 nta_incoming_t *irq);
5295
5296su_inlinestatic inline int incoming_is_queued(nta_incoming_t const *irq);
5297su_inlinestatic inline void incoming_queue(incoming_queue_t *queue, nta_incoming_t *);
5298su_inlinestatic inline void incoming_remove(nta_incoming_t *irq);
5299su_inlinestatic inline void incoming_set_timer(nta_incoming_t *, uint32_t interval);
5300su_inlinestatic inline void incoming_reset_timer(nta_incoming_t *);
5301su_inlinestatic inline size_t incoming_mass_destroy(nta_agent_t *, incoming_queue_t *);
5302
5303static int incoming_set_params(nta_incoming_t *irq, tagi_t const *tags);
5304su_inlinestatic inline
5305int incoming_set_compartment(nta_incoming_t *irq, tport_t *tport, msg_t *msg,
5306 int create_if_needed);
5307
5308su_inlinestatic inline nta_incoming_t
5309 *incoming_call_callback(nta_incoming_t *, msg_t *, sip_t *);
5310su_inlinestatic inline int incoming_final_failed(nta_incoming_t *irq, msg_t *);
5311static void incoming_retransmit_reply(nta_incoming_t *irq, tport_t *tport);
5312
5313/** Create a default server transaction.
5314 *
5315 * The default server transaction is used by a proxy to forward responses
5316 * statelessly.
5317 *
5318 * @param agent pointer to agent object
5319 *
5320 * @retval pointer to default server transaction object
5321 * @retval NULL if failed
5322 */
5323nta_incoming_t *nta_incoming_default(nta_agent_t *agent)
5324{
5325 msg_t *msg;
5326 su_home_t *home;
5327 nta_incoming_t *irq;
5328
5329 if (agent == NULL((void*)0))
5330 return su_seterrno(EFAULT14), NULL((void*)0);
5331 if (agent->sa_default_incoming)
5332 return su_seterrno(EEXIST17), NULL((void*)0);
5333
5334 msg = nta_msg_create(agent, 0);
5335 if (!msg)
5336 return NULL((void*)0);
5337
5338 irq = su_zalloc(home = msg_home(msg)((su_home_t*)(msg)), sizeof(*irq));
5339 if (!irq)
5340 return (void)msg_destroy(msg), NULL((void*)0);
5341
5342 irq->irq_home = home;
5343 irq->irq_request = NULL((void*)0);
5344 irq->irq_agent = agent;
5345 irq->irq_received = agent_now(agent);
5346 irq->irq_method = sip_method_invalid;
5347
5348 irq->irq_default = 1;
5349 agent->sa_default_incoming = irq;
5350
5351 return irq;
5352}
5353
5354/** Create a server transaction.
5355 *
5356 * Create a server transaction for a request message. This function is used
5357 * when an element processing requests statelessly wants to process a
5358 * particular request statefully.
5359 *
5360 * @param agent pointer to agent object
5361 * @param leg pointer to leg object (either @a agent or @a leg may be NULL)
5362 * @param msg pointer to message object
5363 * @param sip pointer to SIP structure (may be NULL)
5364 * @param tag,value,... optional tagged parameters
5365 *
5366 * @note
5367 * The ownership of @a msg is taken over by the function even if the
5368 * function fails.
5369 *
5370 * @TAGS
5371 * @TAG NTATAG_TPORT() specifies the transport used to receive the request
5372 * and also default transport for sending the response.
5373 *
5374 * @retval nta_incoming_t pointer to the newly created server transaction
5375 * @retval NULL if failed
5376 */
5377nta_incoming_t *nta_incoming_create(nta_agent_t *agent,
5378 nta_leg_t *leg,
5379 msg_t *msg,
5380 sip_t *sip,
5381 tag_type_t tag, tag_value_t value, ...)
5382{
5383 char const *to_tag = NULL((void*)0);
5384 tport_t *tport = NULL((void*)0);
5385 ta_list ta;
5386 nta_incoming_t *irq;
5387
5388 if (msg == NULL((void*)0))
5389 return NULL((void*)0);
5390
5391 if (agent == NULL((void*)0) && leg != NULL((void*)0))
5392 agent = leg->leg_agent;
5393
5394 if (sip == NULL((void*)0))
5395 sip = sip_object(msg);
5396
5397 if (agent == NULL((void*)0) || sip == NULL((void*)0) || !sip->sip_request || !sip->sip_cseq)
5398 return msg_destroy(msg), NULL((void*)0);
5399
5400 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)
;
5401
5402 tl_gets(ta_args(ta)(ta).tl,
5403 NTATAG_TPORT_REF(tport)ntatag_tport_ref, tag_ptr_vr(&(tport), (tport)),
5404 TAG_END()(tag_type_t)0, (tag_value_t)0);
5405 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))
;
5406
5407 if (leg && leg->leg_local)
5408 to_tag = leg->leg_local->a_tag;
5409
5410 if (tport == NULL((void*)0))
5411 tport = tport_delivered_by(agent->sa_tports, msg);
5412
5413 irq = incoming_create(agent, msg, sip, tport, to_tag);
5414
5415 if (!irq)
5416 msg_destroy(msg);
5417
5418 return irq;
5419}
5420
5421/** @internal Create a new incoming transaction object. */
5422static
5423nta_incoming_t *incoming_create(nta_agent_t *agent,
5424 msg_t *msg,
5425 sip_t *sip,
5426 tport_t *tport,
5427 char const *tag)
5428{
5429 nta_incoming_t *irq = su_zalloc(msg_home(msg)((su_home_t*)(msg)), sizeof(*irq));
5430
5431 agent->sa_stats->as_server_tr++;
5432
5433 if (irq) {
5434 su_home_t *home;
5435 incoming_queue_t *queue;
5436 sip_method_t method = sip->sip_request->rq_method;
5437
5438 irq->irq_request = msg;
5439 irq->irq_home = home = msg_home(msg_ref_create(msg))((su_home_t*)(msg_ref_create(msg)));
5440 irq->irq_agent = agent;
5441
5442 irq->irq_received = agent_now(agent); /* Timestamp originally from tport */
5443
5444 irq->irq_method = method;
5445 irq->irq_rq = sip_request_copy(home, sip->sip_request);
5446 irq->irq_from = sip_from_copy(home, sip->sip_from);
5447 irq->irq_to = sip_to_copy(home, sip->sip_to);
5448 irq->irq_call_id = sip_call_id_copy(home, sip->sip_call_id);
5449 irq->irq_cseq = sip_cseq_copy(home, sip->sip_cseq);
5450 irq->irq_via = sip_via_copy(home, sip->sip_via);
5451 switch (method) {
5452 case sip_method_ack:
5453 case sip_method_cancel:
5454 case sip_method_bye:
5455 case sip_method_options:
5456 case sip_method_register: /* Handling Path is up to application */
5457 case sip_method_info:
5458 case sip_method_prack:
5459 case sip_method_publish:
5460 break;
5461 default:
5462 irq->irq_record_route =
5463 sip_record_route_copy(home, sip->sip_record_route);
5464 }
5465 irq->irq_branch = sip->sip_via->v_branch;
5466 irq->irq_reliable_tp = tport_is_reliable(tport);
5467 irq->irq_extra_100 = 0; /* Sending extra 100 trying false by default */
5468
5469 if (sip->sip_timestamp)
5470 irq->irq_timestamp = sip_timestamp_copy(home, sip->sip_timestamp);
5471
5472 /* Tag transaction */
5473 if (tag)
5474 sip_to_tag(home, irq->irq_to, tag);
5475 irq->irq_tag = irq->irq_to->a_tag;
5476
5477 if (method != sip_method_ack) {
5478 int *use_rport = NULL((void*)0);
5479 int retry_without_rport = 0;
5480
5481 if (agent->sa_server_rport)
5482 use_rport = &retry_without_rport, retry_without_rport = 1;
5483
5484 if (nta_tpn_by_via(irq->irq_tpn, irq->irq_via, use_rport) < 0)
5485 SU_DEBUG_1(("%s: bad via\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 5485, "%s: bad via\n", __func__)) : (void)0)
;
5486 }
5487
5488 incoming_set_compartment(irq, tport, msg, 0);
5489
5490 if (method == sip_method_invite) {
5491 irq->irq_must_100rel =
5492 sip->sip_require && sip_has_feature(sip->sip_require, "100rel");
5493
5494 if (irq->irq_must_100rel ||
5495 (sip->sip_supported &&
5496 sip_has_feature(sip->sip_supported, "100rel"))) {
5497 irq->irq_rseq = su_randint(1, 0x7fffffff); /* Initialize rseq */
5498 }
5499
5500 queue = agent->sa_in.proceeding;
5501
5502 if (irq->irq_reliable_tp)
5503 incoming_set_timer(irq, agent->sa_t2 / 2); /* N1 = T2 / 2 */
5504 else
5505 incoming_set_timer(irq, 200); /* N1 = 200 ms */
5506
5507 irq->irq_tport = tport_ref(tport);
5508 }
5509 else if (method == sip_method_ack) {
5510 irq->irq_status = 700; /* Never send reply to ACK */
5511 irq->irq_completed = 1;
5512 if (irq->irq_reliable_tp || !agent->sa_is_a_uas) {
5513 queue = agent->sa_in.terminated;
5514 irq->irq_terminated = 1;
5515 }
5516 else {
5517 queue = agent->sa_in.completed; /* Timer J */
5518 }
5519 }
5520 else {
5521 queue = agent->sa_in.proceeding;
5522 /* RFC 4320 (nit-actions-03):
5523
5524 Blacklisting on a late response occurs even over reliable transports.
5525 Thus, if an element processing a request received over a reliable
5526 transport is delaying its final response at all, sending a 100 Trying
5527 well in advance of the timeout will prevent blacklisting. Sending a
5528 100 Trying immediately will not harm the transaction as it would over
5529 UDP, but a policy of always sending such a message results in
5530 unneccessary traffic. A policy of sending a 100 Trying after the
5531 period of time in which Timer E reaches T2 had this been a UDP hop is
5532 one reasonable compromise.
5533
5534 */
5535 if (agent->sa_extra_100 && irq->irq_reliable_tp)
5536 incoming_set_timer(irq, agent->sa_t2 / 2); /* T2 / 2 */
5537
5538 irq->irq_tport = tport_ref(tport);
5539 }
5540
5541 irq->irq_hash = NTA_HASH(irq->irq_call_id, irq->irq_cseq->cs_seq)((irq->irq_call_id)->i_hash + 26839U * (uint32_t)(irq->
irq_cseq->cs_seq))
;
5542
5543 incoming_insert(agent, queue, irq);
5544 }
5545
5546 return irq;
5547}
5548
5549/** @internal
5550 * Insert incoming transaction to hash table.
5551 */
5552static void
5553incoming_insert(nta_agent_t *agent,
5554 incoming_queue_t *queue,
5555 nta_incoming_t *irq)
5556{
5557 incoming_queue(queue, irq);
5558
5559 if (incoming_htable_is_full(agent->sa_incoming))
5560 incoming_htable_resize(agent->sa_home, agent->sa_incoming, 0);
5561
5562 if (irq->irq_method != sip_method_ack)
5563 incoming_htable_insert(agent->sa_incoming, irq);
5564 else
5565 /* ACK is appended - final response with tags match with it,
5566 * not with the original INVITE transaction */
5567 /* XXX - what about rfc2543 servers, which do not add tag? */
5568 incoming_htable_append(agent->sa_incoming, irq);
5569}
5570
5571/** Call callback for incoming request */
5572static
5573int incoming_callback(nta_leg_t *leg, nta_incoming_t *irq, sip_t *sip)
5574{
5575 sip_method_t method = sip->sip_request->rq_method;
5576 char const *method_name = sip->sip_request->rq_method_name;
5577
5578 /* RFC-3261 section 12.2.2 (page 76) */
5579 if (leg->leg_dialog &&
5580 irq->irq_agent->sa_is_a_uas &&
5581 method != sip_method_ack) {
5582 uint32_t seq = sip->sip_cseq->cs_seq;
5583
5584 if (leg->leg_rseq > sip->sip_cseq->cs_seq) {
5585 SU_DEBUG_3(("nta_leg(%p): out-of-order %s (%u < %u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 5586, "nta_leg(%p): out-of-order %s (%u < %u)\n", (void *
)leg, method_name, seq, leg->leg_rseq)) : (void)0)
5586 (void *)leg, method_name, seq, leg->leg_rseq))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 5586, "nta_leg(%p): out-of-order %s (%u < %u)\n", (void *
)leg, method_name, seq, leg->leg_rseq)) : (void)0)
;
5587 return 500;
5588 }
5589
5590 leg->leg_rseq = seq;
5591 }
5592
5593 return leg->leg_callback(leg->leg_magic, leg, irq, sip);
5594}
5595
5596/**
5597 * Destroy an incoming transaction.
5598 *
5599 * This function does not actually free transaction object, but marks it as
5600 * disposable. The object is freed after a timeout.
5601 *
5602 * @param irq incoming request object to be destroyed
5603 */
5604void nta_incoming_destroy(nta_incoming_t *irq)
5605{
5606 if (irq) {
5607 irq->irq_callback = NULL((void*)0);
5608 irq->irq_magic = NULL((void*)0);
5609 irq->irq_destroyed = 1;
5610 if (!irq->irq_in_callback) {
5611 if (irq->irq_terminated || irq->irq_default)
5612 incoming_free(irq);
5613 else if (irq->irq_status < 200)
5614 nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error, TAG_END()(tag_type_t)0, (tag_value_t)0);
5615 }
5616 }
5617}
5618
5619/** @internal
5620 * Initialize a queue for incoming transactions.
5621 */
5622static void
5623incoming_queue_init(incoming_queue_t *queue, unsigned timeout)
5624{
5625 memset(queue, 0, sizeof *queue);
5626 queue->q_tail = &queue->q_head;
5627 queue->q_timeout = timeout;
5628}
5629
5630/** Change the timeout value of a queue */
5631static void
5632incoming_queue_adjust(nta_agent_t *sa,
5633 incoming_queue_t *queue,
5634 uint32_t timeout)
5635{
5636 nta_incoming_t *irq;
5637 uint32_t latest;
5638
5639 if (timeout >= queue->q_timeout || !queue->q_head) {
5640 queue->q_timeout = timeout;
5641 return;
5642 }
5643
5644 latest = set_timeout(sa, queue->q_timeout = timeout);
5645
5646 for (irq = queue->q_head; irq; irq = irq->irq_next) {
5647 if ((int32_t)(irq->irq_timeout - latest) > 0)
5648 irq->irq_timeout = latest;
5649 }
5650}
5651
5652/** @internal
5653 * Test if an incoming transaction is in a queue.
5654 */
5655su_inlinestatic inline
5656int incoming_is_queued(nta_incoming_t const *irq)
5657{
5658 return irq && irq->irq_queue;
5659}
5660
5661/** @internal
5662 * Insert an incoming transaction into a queue.
5663 *
5664 * Insert a server transaction into a queue, and sets the corresponding
5665 * timeout at the same time.
5666 */
5667su_inlinestatic inline
5668void incoming_queue(incoming_queue_t *queue,
5669 nta_incoming_t *irq)
5670{
5671 if (irq->irq_queue == queue) {
5672 assert(queue && queue->q_timeout == 0)((void) sizeof ((queue && queue->q_timeout == 0) ?
1 : 0), __extension__ ({ if (queue && queue->q_timeout
== 0) ; else __assert_fail ("queue && queue->q_timeout == 0"
, "nta.c", 5672, __extension__ __PRETTY_FUNCTION__); }))
;
5673 return;
5674 }
5675
5676 if (incoming_is_queued(irq))
5677 incoming_remove(irq);
5678
5679 assert(queue && *queue->q_tail == NULL)((void) sizeof ((queue && *queue->q_tail == ((void
*)0)) ? 1 : 0), __extension__ ({ if (queue && *queue->
q_tail == ((void*)0)) ; else __assert_fail ("queue && *queue->q_tail == NULL"
, "nta.c", 5679, __extension__ __PRETTY_FUNCTION__); }))
;
5680
5681 irq->irq_timeout = set_timeout(irq->irq_agent, queue->q_timeout);
5682
5683 irq->irq_queue = queue;
5684 irq->irq_prev = queue->q_tail;
5685 *queue->q_tail = irq;
5686 queue->q_tail = &irq->irq_next;
5687 queue->q_length++;
5688}
5689
5690/** @internal
5691 * Remove an incoming transaction from a queue.
5692 */
5693su_inlinestatic inline
5694void incoming_remove(nta_incoming_t *irq)
5695{
5696 assert(incoming_is_queued(irq))((void) sizeof ((incoming_is_queued(irq)) ? 1 : 0), __extension__
({ if (incoming_is_queued(irq)) ; else __assert_fail ("incoming_is_queued(irq)"
, "nta.c", 5696, __extension__ __PRETTY_FUNCTION__); }))
;
5697 assert(irq->irq_queue->q_length > 0)((void) sizeof ((irq->irq_queue->q_length > 0) ? 1 :
0), __extension__ ({ if (irq->irq_queue->q_length >
0) ; else __assert_fail ("irq->irq_queue->q_length > 0"
, "nta.c", 5697, __extension__ __PRETTY_FUNCTION__); }))
;
5698
5699 if ((*irq->irq_prev = irq->irq_next))
5700 irq->irq_next->irq_prev = irq->irq_prev;
5701 else
5702 irq->irq_queue->q_tail = irq->irq_prev, assert(!*irq->irq_queue->q_tail)((void) sizeof ((!*irq->irq_queue->q_tail) ? 1 : 0), __extension__
({ if (!*irq->irq_queue->q_tail) ; else __assert_fail (
"!*irq->irq_queue->q_tail", "nta.c", 5702, __extension__
__PRETTY_FUNCTION__); }))
;
5703
5704 irq->irq_queue->q_length--;
5705 irq->irq_next = NULL((void*)0);
5706 irq->irq_prev = NULL((void*)0);
5707 irq->irq_queue = NULL((void*)0);
5708 irq->irq_timeout = 0;
5709}
5710
5711su_inlinestatic inline
5712void incoming_set_timer(nta_incoming_t *irq, uint32_t interval)
5713{
5714 nta_incoming_t **rq;
5715
5716 assert(irq)((void) sizeof ((irq) ? 1 : 0), __extension__ ({ if (irq) ; else
__assert_fail ("irq", "nta.c", 5716, __extension__ __PRETTY_FUNCTION__
); }))
;
5717
5718 if (interval == 0) {
5719 incoming_reset_timer(irq);
5720 return;
5721 }
5722
5723 if (irq->irq_rprev) {
5724 if ((*irq->irq_rprev = irq->irq_rnext))
5725 irq->irq_rnext->irq_rprev = irq->irq_rprev;
5726 if (irq->irq_agent->sa_in.re_t1 == &irq->irq_rnext)
5727 irq->irq_agent->sa_in.re_t1 = irq->irq_rprev;
5728 } else {
5729 irq->irq_agent->sa_in.re_length++;
5730 }
5731
5732 irq->irq_retry = set_timeout(irq->irq_agent, irq->irq_interval = interval);
5733
5734 rq = irq->irq_agent->sa_in.re_t1;
5735
5736 if (!(*rq) || (int32_t)((*rq)->irq_retry - irq->irq_retry) > 0)
5737 rq = &irq->irq_agent->sa_in.re_list;
5738
5739 while (*rq && (int32_t)((*rq)->irq_retry - irq->irq_retry) <= 0)
5740 rq = &(*rq)->irq_rnext;
5741
5742 if ((irq->irq_rnext = *rq))
5743 irq->irq_rnext->irq_rprev = &irq->irq_rnext;
5744 *rq = irq;
5745 irq->irq_rprev = rq;
5746
5747 /* Optimization: keep special place for transactions with T1 interval */
5748 if (interval == irq->irq_agent->sa_t1)
5749 irq->irq_agent->sa_in.re_t1 = rq;
5750}
5751
5752su_inlinestatic inline
5753void incoming_reset_timer(nta_incoming_t *irq)
5754{
5755 if (irq->irq_rprev) {
5756 if ((*irq->irq_rprev = irq->irq_rnext))
5757 irq->irq_rnext->irq_rprev = irq->irq_rprev;
5758 if (irq->irq_agent->sa_in.re_t1 == &irq->irq_rnext)
5759 irq->irq_agent->sa_in.re_t1 = irq->irq_rprev;
5760 irq->irq_agent->sa_in.re_length--;
5761 }
5762
5763 irq->irq_interval = 0, irq->irq_retry = 0;
5764 irq->irq_rnext = NULL((void*)0), irq->irq_rprev = NULL((void*)0);
5765}
5766
5767/** @internal
5768 * Free an incoming transaction.
5769 */
5770static
5771void incoming_free(nta_incoming_t *irq)
5772{
5773 SU_DEBUG_9(("nta: incoming_free(%p)\n", (void *)irq))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__
, 5773, "nta: incoming_free(%p)\n", (void *)irq)) : (void)0)
;
5774
5775 incoming_cut_off(irq);
5776 incoming_reclaim(irq);
5777}
5778
5779/** Remove references to the irq */
5780su_inlinestatic inline
5781void incoming_cut_off(nta_incoming_t *irq)
5782{
5783 nta_agent_t *agent = irq->irq_agent;
5784
5785 assert(agent)((void) sizeof ((agent) ? 1 : 0), __extension__ ({ if (agent)
; else __assert_fail ("agent", "nta.c", 5785, __extension__ __PRETTY_FUNCTION__
); }))
;
5786
5787 if (irq->irq_default) {
5788 if (irq == agent->sa_default_incoming)
5789 agent->sa_default_incoming = NULL((void*)0);
5790 irq->irq_default = 0;
5791 return;
5792 }
5793
5794 if (incoming_is_queued(irq))
5795 incoming_remove(irq);
5796
5797 incoming_reset_timer(irq);
5798
5799 incoming_htable_remove(agent->sa_incoming, irq);
5800
5801 if (irq->irq_cc)
5802 nta_compartment_decref(&irq->irq_cc);
5803
5804 if (irq->irq_tport)
5805 tport_decref(&irq->irq_tport);
5806}
5807
5808/** Reclaim the memory used by irq */
5809su_inlinestatic inline
5810void incoming_reclaim(nta_incoming_t *irq)
5811{
5812 su_home_t *home = irq->irq_home;
5813 nta_reliable_t *rel, *rel_next;
5814
5815 if (irq->irq_request)
5816 msg_destroy(irq->irq_request), irq->irq_request = NULL((void*)0);
5817 if (irq->irq_request2)
5818 msg_destroy(irq->irq_request2), irq->irq_request2 = NULL((void*)0);
5819 if (irq->irq_response)
5820 msg_destroy(irq->irq_response), irq->irq_response = NULL((void*)0);
5821
5822 for (rel = irq->irq_reliable; rel; rel = rel_next) {
5823 rel_next = rel->rel_next;
5824 if (rel->rel_unsent)
5825 msg_destroy(rel->rel_unsent);
5826 su_free(irq->irq_agent->sa_home, rel);
5827 }
5828
5829 irq->irq_home = NULL((void*)0);
5830
5831 su_free(home, irq);
5832
5833 msg_destroy((msg_t *)home);
5834}
5835
5836/** Queue request to be freed */
5837su_inlinestatic inline
5838void incoming_free_queue(incoming_queue_t *q, nta_incoming_t *irq)
5839{
5840 incoming_cut_off(irq);
5841 incoming_queue(q, irq);
5842}
5843
5844/** Reclaim memory used by queue of requests */
5845static
5846void incoming_reclaim_queued(su_root_magic_t *rm,
5847 su_msg_r msg,
5848 union sm_arg_u *u)
5849{
5850 incoming_queue_t *q = u->a_incoming_queue;
5851 nta_incoming_t *irq, *irq_next;
5852
5853 SU_DEBUG_9(("incoming_reclaim_all(%p, %p, %p)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__
, 5854, "incoming_reclaim_all(%p, %p, %p)\n", (void *)rm, (void
*)msg, (void *)u)) : (void)0)
5854 (void *)rm, (void *)msg, (void *)u))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__
, 5854, "incoming_reclaim_all(%p, %p, %p)\n", (void *)rm, (void
*)msg, (void *)u)) : (void)0)
;
5855
5856 for (irq = q->q_head; irq; irq = irq_next) {
5857 irq_next = irq->irq_next;
5858 incoming_reclaim(irq);
5859 }
5860}
5861
5862/**Bind a callback and context to an incoming transaction object
5863 *
5864 * Set the callback function and context pointer attached to an incoming
5865 * request object. The callback function will be invoked if the incoming
5866 * request is cancelled, or if the final response to an incoming @b INVITE
5867 * request has been acknowledged.
5868 *
5869 * If the callback is NULL, or no callback has been bound, NTA invokes the
5870 * request callback of the call leg.
5871 *
5872 * @param irq incoming transaction
5873 * @param callback callback function
5874 * @param magic application context
5875 */
5876void nta_incoming_bind(nta_incoming_t *irq,
5877 nta_ack_cancel_f *callback,
5878 nta_incoming_magic_t *magic)
5879{
5880 if (irq) {
5881 irq->irq_callback = callback;
5882 irq->irq_magic = magic;
5883 }
5884}
5885
5886/** Add a @To tag to incoming request if needed.
5887 *
5888 * If @a tag is NULL, a new tag is generated.
5889 */
5890char const *nta_incoming_tag(nta_incoming_t *irq, char const *tag)
5891{
5892 if (!irq)
5893 return su_seterrno(EFAULT14), NULL((void*)0);
5894
5895 if (irq->irq_default)
5896 return su_seterrno(EINVAL22), NULL((void*)0);
5897
5898 if (tag && strchr(tag, '='))
5899 tag = strchr(tag, '=') + 1;
5900
5901 if (tag && irq->irq_tag && !su_casematch(tag, irq->irq_tag))
5902 return NULL((void*)0);
5903
5904 if (!irq->irq_tag) {
5905 if (tag)
5906 tag = su_strdup(irq->irq_home, tag);
5907 else
5908 tag = nta_agent_newtag(irq->irq_home, NULL((void*)0), irq->irq_agent);
5909
5910 if (!tag)
5911 return tag;
5912
5913 irq->irq_tag = tag;
5914 irq->irq_tag_set = 1;
5915 }
5916
5917 return irq->irq_tag;
5918}
5919
5920
5921/**Get request message.
5922 *
5923 * Retrieve the incoming request message of the incoming transaction. Note
5924 * that the message is not copied, but a new reference to it is created.
5925 *
5926 * @param irq incoming transaction handle
5927 *
5928 * @retval
5929 * A pointer to request message is returned.
5930 */
5931msg_t *nta_incoming_getrequest(nta_incoming_t *irq)
5932{
5933 msg_t *msg = NULL((void*)0);
5934
5935 if (irq && !irq->irq_default)
5936 msg = msg_ref_create(irq->irq_request);
5937
5938 return msg;
5939}
5940
5941/**Get ACK or CANCEL message.
5942 *
5943 * Retrieve the incoming ACK or CANCEL request message of the incoming
5944 * transaction. Note that the ACK or CANCEL message is not copied, but a new
5945 * reference to it is created.
5946 *
5947 * @param irq incoming transaction handle
5948 *
5949 * @retval A pointer to request message is returned, or NULL if there is no
5950 * CANCEL or ACK received.
5951 */
5952msg_t *nta_incoming_getrequest_ackcancel(nta_incoming_t *irq)
5953{
5954 msg_t *msg = NULL((void*)0);
5955
5956 if (irq && irq->irq_request2)
5957 msg = msg_ref_create(irq->irq_request2);
5958
5959 return msg;
5960}
5961
5962/**Get response message.
5963 *
5964 * Retrieve the response message latest sent by the server transaction. Note
5965 * that the message is not copied, but a new reference to it is created. Use
5966 * msg_dup() or msg_copy() to make a copy of it.
5967 *
5968 * @param irq incoming transaction handle
5969 *
5970 * @retval
5971 * A pointer to a response message is returned.
5972 */
5973msg_t *nta_incoming_getresponse(nta_incoming_t *irq)
5974{
5975 msg_t *msg = NULL((void*)0);
5976
5977 if (irq && irq->irq_response)
5978 msg = msg_ref_create(irq->irq_response);
5979
5980 return msg;
5981}
5982
5983/** Get method of a server transaction. */
5984sip_method_t nta_incoming_method(nta_incoming_t const *irq)
5985{
5986 return irq ? irq->irq_method : sip_method_invalid;
5987}
5988
5989/** Get method name of a server transaction. */
5990char const *nta_incoming_method_name(nta_incoming_t const *irq)
5991{
5992 if (irq == NULL((void*)0))
5993 return NULL((void*)0);
5994 else if (irq->irq_rq)
5995 return irq->irq_rq->rq_method_name;
5996 else
5997 return "*";
5998}
5999
6000/** Get Request-URI of a server transaction */
6001url_t const *nta_incoming_url(nta_incoming_t const *irq)
6002{
6003 return irq && irq->irq_rq ? irq->irq_rq->rq_url : NULL((void*)0);
6004}
6005
6006/** Get sequence number of a server transaction.
6007 */
6008uint32_t nta_incoming_cseq(nta_incoming_t const *irq)
6009{
6010 return irq && irq->irq_cseq ? irq->irq_cseq->cs_seq : 0;
6011}
6012
6013/** Get local tag for incoming request */
6014char const *nta_incoming_gettag(nta_incoming_t const *irq)
6015{
6016 return irq ? irq->irq_tag : 0;
6017}
6018
6019/**
6020 * Get status code of a server transaction.
6021 */
6022int nta_incoming_status(nta_incoming_t const *irq)
6023{
6024 return irq ? irq->irq_status : 400;
6025}
6026
6027/** Get application context for a server transaction.
6028 *
6029 * @param irq server transaction
6030 * @param callback callback pointer
6031 *
6032 * Return the application context bound to the server transaction. If the @a
6033 * callback function pointer is given, return application context only if
6034 * the callback matches with the callback bound to the server transaction.
6035 *
6036 */
6037nta_incoming_magic_t *nta_incoming_magic(nta_incoming_t *irq,
6038 nta_ack_cancel_f *callback)
6039{
6040 return irq && (callback == NULL((void*)0) || irq->irq_callback == callback)
6041 ? irq->irq_magic : NULL((void*)0);
6042}
6043
6044/** When received.
6045 *
6046 * Return timestamp from the reception of the initial request.
6047 *
6048 * @NEW_1_12_7.
6049 */
6050sip_time_t nta_incoming_received(nta_incoming_t *irq,
6051 su_nanotime_t *return_nano)
6052{
6053 su_time_t tv = { 0, 0 };
6054
6055 if (irq)
6056 tv = irq->irq_received;
6057
6058 if (return_nano)
6059 *return_nano = (su_nanotime_t)tv.tv_sec * 1000000000 + tv.tv_usec * 1000;
6060
6061 return tv.tv_sec;
6062}
6063
6064/** Find incoming transaction. */
6065nta_incoming_t *nta_incoming_find(nta_agent_t const *agent,
6066 sip_t const *sip,
6067 sip_via_t const *v)
6068{
6069 if (agent && sip && v)
6070 return incoming_find(agent, sip, v, NULL((void*)0), NULL((void*)0), NULL((void*)0));
6071 else
6072 return NULL((void*)0);
6073}
6074
6075/** Find a matching server transaction object.
6076 *
6077 * Check also for requests to merge, to ACK, or to CANCEL.
6078 */
6079static nta_incoming_t *incoming_find(nta_agent_t const *agent,
6080 sip_t const *sip,
6081 sip_via_t const *v,
6082 nta_incoming_t **return_merge,
6083 nta_incoming_t **return_ack,
6084 nta_incoming_t **return_cancel)
6085{
6086 sip_cseq_t const *cseq = sip->sip_cseq;
6087 sip_call_id_t const *i = sip->sip_call_id;
6088 sip_to_t const *to = sip->sip_to;
6089 sip_from_t const *from = sip->sip_from;
6090 sip_request_t *rq = sip->sip_request;
6091 incoming_htable_t const *iht = agent->sa_incoming;
6092 hash_value_t hash = NTA_HASH(i, cseq->cs_seq)((i)->i_hash + 26839U * (uint32_t)(cseq->cs_seq));
6093 char const *magic_branch;
6094
6095 nta_incoming_t **ii, *irq;
6096
6097 int is_uas_ack = return_ack && agent->sa_is_a_uas;
6098
6099 if (v->v_branch && su_casenmatch(v->v_branch, "z9hG4bK", 7))
6100 magic_branch = v->v_branch + 7;
6101 else
6102 magic_branch = NULL((void*)0);
6103
6104 for (ii = incoming_htable_hash(iht, hash);
6105 (irq = *ii);
6106 ii = incoming_htable_next(iht, ii)) {
6107 if (hash != irq->irq_hash ||
6108 irq->irq_call_id->i_hash != i->i_hash ||
6109 strcmp(irq->irq_call_id->i_id, i->i_id))
6110 continue;
6111 if (irq->irq_cseq->cs_seq != cseq->cs_seq)
6112 continue;
6113 if (su_strcasecmp(irq->irq_from->a_tag, from->a_tag))
6114 continue;
6115
6116 if (is_uas_ack &&
6117 irq->irq_method == sip_method_invite &&
6118 200 <= irq->irq_status && irq->irq_status < 300 &&
6119 su_casematch(irq->irq_tag, to->a_tag)) {
6120 *return_ack = irq;
6121 return NULL((void*)0);
6122 }
6123
6124 if (magic_branch) {
6125 /* RFC3261 17.2.3:
6126 *
6127 * The request matches a transaction if branch and sent-by in topmost
6128 * the method of the request matches the one that created the
6129 * transaction, except for ACK, where the method of the request
6130 * that created the transaction is INVITE.
6131 */
6132 if (irq->irq_via->v_branch &&
6133 su_casematch(irq->irq_via->v_branch + 7, magic_branch) &&
6134 su_casematch(irq->irq_via->v_host, v->v_host) &&
6135 su_strmatch(irq->irq_via->v_port, v->v_port)) {
6136 if (irq->irq_method == cseq->cs_method &&
6137 strcmp(irq->irq_cseq->cs_method_name,
6138 cseq->cs_method_name) == 0)
6139 return irq;
6140 if (return_ack && irq->irq_method == sip_method_invite)
6141 return *return_ack = irq, NULL((void*)0);
6142 if (return_cancel && irq->irq_method != sip_method_ack)
6143 return *return_cancel = irq, NULL((void*)0);
6144 }
6145 }
6146 else {
6147 /* No magic branch */
6148
6149 /* INVITE request matches a transaction if
6150 the Request-URI, To tag, From tag, Call-ID, CSeq, and
6151 top Via header match */
6152
6153 /* From tag, Call-ID, and CSeq number has been matched above */
6154
6155 /* Match top Via header field */
6156 if (!su_casematch(irq->irq_via->v_branch, v->v_branch) ||
6157 !su_casematch(irq->irq_via->v_host, v->v_host) ||
6158 !su_strmatch(irq->irq_via->v_port, v->v_port))
6159 ;
6160 /* Match Request-URI */
6161 else if (url_cmp(irq->irq_rq->rq_url, rq->rq_url))
6162 ;
6163 else {
6164 /* Match CSeq */
6165 if (irq->irq_method == cseq->cs_method &&
6166 su_strmatch(irq->irq_cseq->cs_method_name, cseq->cs_method_name)) {
6167 /* Match To tag */
6168 if (!su_strcasecmp(irq->irq_to->a_tag, to->a_tag))
6169 return irq; /* found */
6170 }
6171 else if (
6172 /* Tag set by UAS */
6173 su_strcasecmp(irq->irq_tag, to->a_tag) &&
6174 /* Original tag */
6175 su_strcasecmp(irq->irq_to->a_tag, to->a_tag))
6176 ;
6177 else if (return_ack && irq->irq_method == sip_method_invite)
6178 return *return_ack = irq, NULL((void*)0);
6179 else if (return_cancel && irq->irq_method != sip_method_ack)
6180 return *return_cancel = irq, NULL((void*)0);
6181 }
6182 }
6183
6184 /* RFC3261 - section 8.2.2.2 Merged Requests */
6185 if (return_merge) {
6186 if (irq->irq_cseq->cs_method == cseq->cs_method &&
6187 strcmp(irq->irq_cseq->cs_method_name,
6188 cseq->cs_method_name) == 0)
6189 *return_merge = irq, return_merge = NULL((void*)0);
6190 }
6191 }
6192
6193 return NULL((void*)0);
6194}
6195
6196/** Process retransmitted requests. */
6197su_inlinestatic inline
6198int
6199incoming_recv(nta_incoming_t *irq, msg_t *msg, sip_t *sip, tport_t *tport)
6200{
6201 nta_agent_t *agent = irq->irq_agent;
6202
6203 agent->sa_stats->as_recv_retry++;
6204
6205 if (irq->irq_status >= 100) {
6206 SU_DEBUG_5(("nta: re-received %s request, retransmitting %u reply\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 6207, "nta: re-received %s request, retransmitting %u reply\n"
, sip->sip_request->rq_method_name, irq->irq_status)
) : (void)0)
6207 sip->sip_request->rq_method_name, irq->irq_status))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 6207, "nta: re-received %s request, retransmitting %u reply\n"
, sip->sip_request->rq_method_name, irq->irq_status)
) : (void)0)
;
6208 incoming_retransmit_reply(irq, tport);
6209 }
6210 else if (irq->irq_agent->sa_extra_100 &&
6211 irq->irq_extra_100) {
6212 /* Agent and Irq configured to answer automatically with 100 Trying */
6213 if (irq->irq_method == sip_method_invite ||
6214 /*
6215 * Send 100 trying to non-invite if at least half of T2 has expired
6216 * since the transaction was created.
6217 */
6218 su_duration(agent_now(irq->irq_agent), irq->irq_received) * 2U >
6219 irq->irq_agent->sa_t2) {
6220 SU_DEBUG_5(("nta: re-received %s request, sending 100 Trying\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 6221, "nta: re-received %s request, sending 100 Trying\n", sip
->sip_request->rq_method_name)) : (void)0)
6221 sip->sip_request->rq_method_name))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 6221, "nta: re-received %s request, sending 100 Trying\n", sip
->sip_request->rq_method_name)) : (void)0)
;
6222 nta_incoming_treply(irq, SIP_100_TRYING100, sip_100_Trying, NTATAG_TPORT(tport)ntatag_tport, tag_ptr_v((tport)), TAG_END()(tag_type_t)0, (tag_value_t)0);
6223 }
6224 }
6225
6226 msg_destroy(msg);
6227
6228 return 0;
6229}
6230
6231su_inlinestatic inline
6232int incoming_ack(nta_incoming_t *irq, msg_t *msg, sip_t *sip, tport_t *tport)
6233{
6234 nta_agent_t *agent = irq->irq_agent;
6235
6236 /* Process ACK separately? */
6237 if (irq->irq_status >= 200 && irq->irq_status < 300 && !agent->sa_is_a_uas)
6238 return -1;
6239
6240 if (irq->irq_queue == agent->sa_in.inv_completed) {
6241 if (!irq->irq_confirmed)
6242 agent->sa_stats->as_acked_tr++;
6243
6244 irq->irq_confirmed = 1;
6245 incoming_reset_timer(irq); /* Reset timer G */
6246
6247 if (!irq->irq_reliable_tp) {
6248 incoming_queue(agent->sa_in.inv_confirmed, irq); /* Timer I */
6249 }
6250 else {
6251 irq->irq_terminated = 1;
6252 incoming_queue(agent->sa_in.terminated, irq);
6253 }
6254
6255 if (!irq->irq_destroyed) {
6256 if (!irq->irq_callback) /* Process ACK normally */
6257 return -1;
6258
6259 incoming_call_callback(irq, msg, sip); /* ACK callback */
6260 }
6261 } else if (irq->irq_queue == agent->sa_in.proceeding ||
6262 irq->irq_queue == agent->sa_in.preliminary)
6263 return -1;
6264 else
6265 assert(irq->irq_queue == agent->sa_in.inv_confirmed ||((void) sizeof ((irq->irq_queue == agent->sa_in.inv_confirmed
|| irq->irq_queue == agent->sa_in.terminated) ? 1 : 0)
, __extension__ ({ if (irq->irq_queue == agent->sa_in.inv_confirmed
|| irq->irq_queue == agent->sa_in.terminated) ; else __assert_fail
("irq->irq_queue == agent->sa_in.inv_confirmed || irq->irq_queue == agent->sa_in.terminated"
, "nta.c", 6266, __extension__ __PRETTY_FUNCTION__); }))
6266 irq->irq_queue == agent->sa_in.terminated)((void) sizeof ((irq->irq_queue == agent->sa_in.inv_confirmed
|| irq->irq_queue == agent->sa_in.terminated) ? 1 : 0)
, __extension__ ({ if (irq->irq_queue == agent->sa_in.inv_confirmed
|| irq->irq_queue == agent->sa_in.terminated) ; else __assert_fail
("irq->irq_queue == agent->sa_in.inv_confirmed || irq->irq_queue == agent->sa_in.terminated"
, "nta.c", 6266, __extension__ __PRETTY_FUNCTION__); }))
;
6267
6268 msg_destroy(msg);
6269
6270 return 0;
6271}
6272
6273/** Respond to the CANCEL. */
6274su_inlinestatic inline
6275int incoming_cancel(nta_incoming_t *irq, msg_t *msg, sip_t *sip,
6276 tport_t *tport)
6277{
6278 nta_agent_t *agent = irq->irq_agent;
6279
6280 /* According to the RFC 3261, this INVITE has been destroyed */
6281 if (irq->irq_method == sip_method_invite &&
6282 200 <= irq->irq_status && irq->irq_status < 300) {
6283 mreply(agent, NULL((void*)0), SIP_481_NO_TRANSACTION481, sip_481_No_transaction, msg,
6284 tport, 0, 0, NULL((void*)0),
6285 TAG_END()(tag_type_t)0, (tag_value_t)0);
6286 return 0;
6287 }
6288
6289 /* UAS MUST use same tag in final response to CANCEL and INVITE */
6290 if (agent->sa_is_a_uas && irq->irq_tag == NULL((void*)0)) {
6291 nta_incoming_tag(irq, NULL((void*)0));
6292 }
6293
6294 mreply(agent, NULL((void*)0), SIP_200_OK200, sip_200_OK, msg_ref_create(msg),
6295 tport, 0, 0, irq->irq_tag,
6296 TAG_END()(tag_type_t)0, (tag_value_t)0);
6297
6298 /* We have already sent final response */
6299 if (irq->irq_completed || irq->irq_method != sip_method_invite) {
6300 msg_destroy(msg);
6301 return 0;
6302 }
6303
6304 if (!irq->irq_canceled) {
6305 irq->irq_canceled = 1;
6306 agent->sa_stats->as_canceled_tr++;
6307 irq = incoming_call_callback(irq, msg, sip);
6308 }
6309
6310 if (irq && !irq->irq_completed && agent->sa_cancel_487)
6311 /* Respond to the cancelled request */
6312 nta_incoming_treply(irq, SIP_487_REQUEST_CANCELLED487, sip_487_Request_terminated, TAG_END()(tag_type_t)0, (tag_value_t)0);
6313
6314 msg_destroy(msg);
6315
6316 return 0;
6317}
6318
6319/** Merge request */
6320static
6321void request_merge(nta_agent_t *agent,
6322 msg_t *msg, sip_t *sip, tport_t *tport,
6323 char const *to_tag)
6324{
6325 nta_incoming_t *irq;
6326
6327 agent->sa_stats->as_merged_request++;
6328
6329 irq = incoming_create(agent, msg, sip, tport, to_tag);
6330
6331 if (irq) {
6332 nta_incoming_treply(irq, 482, "Request merged", TAG_END()(tag_type_t)0, (tag_value_t)0);
6333 nta_incoming_destroy(irq);
6334 } else {
6335 SU_DEBUG_3(("nta: request_merge(): cannot create transaction for %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 6336, "nta: request_merge(): cannot create transaction for %s\n"
, sip->sip_request->rq_method_name)) : (void)0)
6336 sip->sip_request->rq_method_name))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 6336, "nta: request_merge(): cannot create transaction for %s\n"
, sip->sip_request->rq_method_name)) : (void)0)
;
6337 mreply(agent, NULL((void*)0), 482, "Request merged", msg,
6338 tport, 0, 0, NULL((void*)0),
6339 TAG_END()(tag_type_t)0, (tag_value_t)0);
6340 }
6341}
6342
6343/**@typedef nta_ack_cancel_f
6344 *
6345 * Callback function prototype for CANCELed/ACKed requests
6346 *
6347 * This is a callback function is invoked by NTA when an incoming request
6348 * has been cancelled or an response to an incoming INVITE request has been
6349 * acknowledged.
6350 *
6351 * @param magic incoming request context
6352 * @param ireq incoming request
6353 * @param sip ACK/CANCEL message
6354 *
6355 * @retval 0
6356 * This callback function should return always 0.
6357 */
6358
6359/** Call callback of incoming transaction */
6360su_inlinestatic inline
6361nta_incoming_t *
6362incoming_call_callback(nta_incoming_t *irq, msg_t *msg, sip_t *sip)
6363{
6364 if (irq->irq_callback) {
6365 irq->irq_in_callback = 1;
6366 irq->irq_request2 = msg;
6367 irq->irq_callback(irq->irq_magic, irq, sip);
6368 irq->irq_request2 = NULL((void*)0);
6369 irq->irq_in_callback = 0;
6370
6371 if (irq->irq_terminated && irq->irq_destroyed)
6372 incoming_free(irq), irq = NULL((void*)0);
6373 }
6374 return irq;
6375}
6376
6377/**Set server transaction parameters.
6378 *
6379 * Sets the server transaction parameters. Among others, parameters determine the way
6380 * the SigComp compression is handled.
6381 *
6382 * @TAGS
6383 * NTATAG_COMP(), NTATAG_SIGCOMP_CLOSE() and NTATAG_EXTRA_100().
6384 *
6385 * @retval number of set parameters when succesful
6386 * @retval -1 upon an error
6387 */
6388int nta_incoming_set_params(nta_incoming_t *irq,
6389 tag_type_t tag, tag_value_t value, ...)
6390{
6391 int retval = -1;
6392
6393 if (irq) {
6394 ta_list ta;
6395 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)
;
6396 retval = incoming_set_params(irq, ta_args(ta)(ta).tl);
6397 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))
;
6398 }
6399 else {
6400 su_seterrno(EINVAL22);
6401 }
6402
6403 return retval;
6404}
6405
6406static
6407int incoming_set_params(nta_incoming_t *irq, tagi_t const *tags)
6408{
6409 int retval = 0;
6410
6411 tagi_t const *t;
6412 char const *comp = NONE((void *)-1);
6413 struct sigcomp_compartment *cc = NONE((void *)-1);
6414
6415 if (irq->irq_default)
6416 return retval;
6417
6418 for (t = tags; t; t = tl_next(t)) {
6419 tag_type_t tt = t->t_tag;
6420
6421 if (ntatag_comp == tt)
6422 comp = (char const *)t->t_value, retval++;
6423
6424 else if (ntatag_sigcomp_close == tt)
6425 irq->irq_sigcomp_zap = t->t_value != 0, retval++;
6426
6427 else if (tptag_compartment == tt)
6428 cc = (void *)t->t_value, retval++;
6429
6430 else if (ntatag_extra_100 == tt)
6431 irq->irq_extra_100 = t->t_value != 0, retval++;
6432 }
6433
6434 if (cc != NONE((void *)-1)) {
6435 if (cc)
6436 agent_accept_compressed(irq->irq_agent, irq->irq_request, cc);
6437 if (irq->irq_cc)
6438 nta_compartment_decref(&irq->irq_cc);
6439 irq->irq_cc = nta_compartment_ref(cc);
6440 }
6441 else if (comp != NULL((void*)0) && comp != NONE((void *)-1) && irq->irq_cc == NULL((void*)0)) {
6442 incoming_set_compartment(irq, irq->irq_tport, irq->irq_request, 1);
6443 }
6444
6445 else if (comp == NULL((void*)0)) {
6446 irq->irq_tpn->tpn_comp = NULL((void*)0);
6447 }
6448
6449 return retval;
6450}
6451
6452su_inlinestatic inline
6453int incoming_set_compartment(nta_incoming_t *irq, tport_t *tport, msg_t *msg,
6454 int create_if_needed)
6455{
6456 if (!nta_compressor_vtable)
6457 return 0;
6458
6459 if (irq->irq_cc == NULL((void*)0)
6460 || irq->irq_tpn->tpn_comp
6461 || tport_delivered_with_comp(tport, msg, NULL((void*)0)) != -1) {
6462 struct sigcomp_compartment *cc;
6463
6464 cc = agent_compression_compartment(irq->irq_agent, tport, irq->irq_tpn,
6465 create_if_needed);
6466
6467 if (cc)
6468 agent_accept_compressed(irq->irq_agent, msg, cc);
6469
6470 irq->irq_cc = cc;
6471 }
6472
6473 return 0;
6474}
6475
6476/** Add essential headers to the response message */
6477static int nta_incoming_response_headers(nta_incoming_t *irq,
6478 msg_t *msg,
6479 sip_t *sip)
6480{
6481 int clone = 0;
6482 su_home_t *home = msg_home(msg)((su_home_t*)(msg));
6483
6484 if (!sip->sip_from)
6485 clone = 1, sip->sip_from = sip_from_copy(home, irq->irq_from);
6486 if (!sip->sip_to)
6487 clone = 1, sip->sip_to = sip_to_copy(home, irq->irq_to);
6488 if (!sip->sip_call_id)
6489 clone = 1, sip->sip_call_id = sip_call_id_copy(home, irq->irq_call_id);
6490 if (!sip->sip_cseq)
6491 clone = 1, sip->sip_cseq = sip_cseq_copy(home, irq->irq_cseq);
6492 if (!sip->sip_via) {
6493 clone = 1;
6494 /* 100 responses are not forwarded by proxies, so only include the topmost Via header */
6495 if (sip->sip_status && sip->sip_status->st_status == 100)
6496 sip->sip_via = (sip_via_t *)msg_header_copy_one(home, (msg_header_t const *)irq->irq_via);
6497 else
6498 sip->sip_via = sip_via_copy(home, irq->irq_via);
6499 }
6500
6501 if (clone)
6502 msg_set_parent(msg, (msg_t *)irq->irq_home);
6503
6504 if (!sip->sip_from || !sip->sip_to || !sip->sip_call_id || !sip->sip_cseq || !sip->sip_via)
6505 return -1;
6506
6507 return 0;
6508}
6509
6510/** Complete a response message.
6511 *
6512 * @param irq server transaction object
6513 * @param msg response message to be completed
6514 * @param status status code (in range 100 - 699)
6515 * @param phrase status phrase (may be NULL)
6516 * @param tag,value,... taged argument list
6517 *
6518 * Generate status structure based on @a status and @a phrase.
6519 * Add essential headers to the response message:
6520 * @From, @To, @CallID, @CSeq, @Via, and optionally
6521 * @RecordRoute.
6522 */
6523int nta_incoming_complete_response(nta_incoming_t *irq,
6524 msg_t *msg,
6525 int status,
6526 char const *phrase,
6527 tag_type_t tag, tag_value_t value, ...)
6528{
6529 su_home_t *home = msg_home(msg)((su_home_t*)(msg));
6530 sip_t *sip = sip_object(msg);
6531 int retval;
6532 ta_list ta;
6533
6534 if (irq == NULL((void*)0) || sip == NULL((void*)0))
6535 return su_seterrno(EFAULT14), -1;
6536
6537 if (status != 0 && (status < 100 || status > 699))
6538 return su_seterrno(EINVAL22), -1;
6539
6540 if (status != 0 && !sip->sip_status)
6541 sip->sip_status = sip_status_create(home, status, phrase, NULL((void*)0));
6542
6543 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)
;
6544 retval = sip_add_tl(msg, sip, ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
);
6545 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))
;
6546
6547 if (retval < 0)
6548 return -1;
6549
6550 if (irq->irq_default)
6551 return sip_complete_message(msg);
6552
6553 if (status > 100 && !irq->irq_tag) {
6554 if (sip->sip_to)
6555 nta_incoming_tag(irq, sip->sip_to->a_tag);
6556 else
6557 nta_incoming_tag(irq, NULL((void*)0));
6558 }
6559
6560 if (nta_incoming_response_headers(irq, msg, sip) < 0)
6561 return -1;
6562
6563 if (sip->sip_status && sip->sip_status->st_status > 100 &&
6564 irq->irq_tag && sip->sip_to && !sip->sip_to->a_tag)
6565 if (sip_to_tag(home, sip->sip_to, irq->irq_tag) < 0)
6566 return -1;
6567
6568 if (status > 100 && status < 300 && !sip->sip_record_route && irq->irq_record_route)
6569 if (sip_add_dup(msg, sip, (sip_header_t *)irq->irq_record_route) < 0)
6570 return -1;
6571
6572 return sip_complete_message(msg);
6573}
6574
6575
6576/** Create a response message for request.
6577 *
6578 * @NEW_1_12_5.
6579 */
6580msg_t *nta_incoming_create_response(nta_incoming_t *irq,
6581 int status, char const *phrase)
6582{
6583 msg_t *msg = NULL((void*)0);
6584 sip_t *sip;
6585
6586 if (irq) {
6587 msg = nta_msg_create(irq->irq_agent, 0);
6588 sip = sip_object(msg);
6589
6590 if (sip) {
6591 if (status != 0)
6592 sip->sip_status = sip_status_create(msg_home(msg)((su_home_t*)(msg)), status, phrase, NULL((void*)0));
6593
6594 if (nta_incoming_response_headers(irq, msg, sip) < 0)
6595 msg_destroy(msg), msg = NULL((void*)0);
6596 }
6597 }
6598
6599 return msg;
6600}
6601
6602
6603/**Reply to an incoming transaction request.
6604 *
6605 * This function creates a response message to an incoming request and sends
6606 * it to the client.
6607 *
6608 * @note
6609 * It is possible to send several non-final (1xx) responses, but only one
6610 * final response.
6611 *
6612 * @param irq incoming request
6613 * @param status status code
6614 * @param phrase status phrase (may be NULL if status code is well-known)
6615 * @param tag,value,... optional additional headers terminated by TAG_END()
6616 *
6617 * @retval 0 when succesful
6618 * @retval -1 upon an error
6619 */
6620int nta_incoming_treply(nta_incoming_t *irq,
6621 int status,
6622 char const *phrase,
6623 tag_type_t tag, tag_value_t value, ...)
6624{
6625 int retval = -1;
6626
6627 if (irq &&
6628 (irq->irq_status < 200 || status < 200 ||
6629 (irq->irq_method == sip_method_invite && status < 300))) {
6630 ta_list ta;
6631 msg_t *msg = nta_msg_create(irq->irq_agent, 0);
6632
6633 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)
;
6634
6635 if (!msg)
6636 ;
6637 else if (nta_incoming_complete_response(irq, msg, status, phrase,
6638 ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
) < 0)
6639 msg_destroy(msg);
6640 else if (incoming_set_params(irq, ta_args(ta)(ta).tl) < 0)
6641 msg_destroy(msg);
6642 else
6643 retval = nta_incoming_mreply(irq, msg);
6644
6645 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))
;
6646
6647 if (retval < 0 && status >= 200)
6648 incoming_final_failed(irq, NULL((void*)0));
6649 }
6650
6651 return retval;
6652}
6653
6654/**
6655 * Return a response message to client.
6656 *
6657 * @note
6658 * The ownership of @a msg is taken over by the function even if the
6659 * function fails.
6660 *
6661 * @retval 0 when succesful
6662 * @retval -1 upon an error
6663 */
6664int nta_incoming_mreply(nta_incoming_t *irq, msg_t *msg)
6665{
6666 sip_t *sip = sip_object(msg);
6667
6668 int status;
6669
6670 if (irq == NULL((void*)0)) {
6671 msg_destroy(msg);
6672 return -1;
6673 }
6674
6675 if (msg == NULL((void*)0) || sip == NULL((void*)0))
6676 return -1;
6677
6678 if (msg == irq->irq_response)
6679 return 0;
6680
6681 if (!sip->sip_status || !sip->sip_via || !sip->sip_cseq)
6682 return incoming_final_failed(irq, msg);
6683
6684 assert (sip->sip_cseq->cs_method == irq->irq_method || irq->irq_default)((void) sizeof ((sip->sip_cseq->cs_method == irq->irq_method
|| irq->irq_default) ? 1 : 0), __extension__ ({ if (sip->
sip_cseq->cs_method == irq->irq_method || irq->irq_default
) ; else __assert_fail ("sip->sip_cseq->cs_method == irq->irq_method || irq->irq_default"
, "nta.c", 6684, __extension__ __PRETTY_FUNCTION__); }))
;
6685
6686 status = sip->sip_status->st_status;
6687
6688 if (!irq->irq_tag && status > 100 && !irq->irq_default)
6689 nta_incoming_tag(irq, NULL((void*)0));
6690
6691 if (/* (irq->irq_confirmed && status >= 200) || */
6692 (irq->irq_completed && status >= 300)) {
6693 SU_DEBUG_3(("%s: already %s transaction\n", __func__,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 6694, "%s: already %s transaction\n", __func__, irq->irq_confirmed
? "confirmed" : "completed")) : (void)0)
6694 irq->irq_confirmed ? "confirmed" : "completed"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 6694, "%s: already %s transaction\n", __func__, irq->irq_confirmed
? "confirmed" : "completed")) : (void)0)
;
6695 msg_destroy(msg);
6696 return -1;
6697 }
6698
6699#ifdef HAVE_ZLIB_COMPRESS1
6700 if (irq->irq_compressed) {
6701 sip_content_encoding_Xflate(msg, sip, 0, 0);
6702 }
6703#endif
6704
6705 if (irq->irq_must_100rel && !sip->sip_rseq && status > 100 && status < 200) {
6706 /* This nta_reliable_t object will be destroyed by PRACK or timeout */
6707 if (nta_reliable_mreply(irq, NULL((void*)0), NULL((void*)0), msg))
6708 return 0;
6709
6710 return -1;
6711 }
6712
6713 if (status >= 200 && irq->irq_reliable && irq->irq_reliable->rel_unsent) {
6714 if (reliable_final(irq, msg, sip) == 0)
6715 return 0;
6716 }
6717
6718 return incoming_reply(irq, msg, sip);
6719}
6720
6721
6722
6723/** Send the response message.
6724 *
6725 * @note The ownership of msg is handled to incoming_reply().
6726 */
6727int incoming_reply(nta_incoming_t *irq, msg_t *msg, sip_t *sip)
6728{
6729 nta_agent_t *agent = irq->irq_agent;
6730 int status = sip->sip_status->st_status;
6731 int sending = 1;
6732 int *use_rport = NULL((void*)0);
6733 int retry_without_rport = 0;
6734 tp_name_t *tpn, default_tpn[1];
6735
6736 if (status == 408 &&
6737 irq->irq_method != sip_method_invite &&
6738 !agent->sa_pass_408 &&
6739 !irq->irq_default) {
6740 /* RFC 4320 nit-actions-03 Action 2:
6741
6742 A transaction-stateful SIP element MUST NOT send a response with
6743 Status-Code of 408 to a non-INVITE request. As a consequence, an
6744 element that can not respond before the transaction expires will not
6745 send a final response at all.
6746 */
6747 sending = 0;
6748 }
6749
6750 if (irq->irq_status == 0 && irq->irq_timestamp && !sip->sip_timestamp)
6751 incoming_timestamp(irq, msg, sip);
6752
6753 if (irq->irq_default) {
6754 if (agent->sa_server_rport)
6755 use_rport = &retry_without_rport, retry_without_rport = 1;
6756 tpn = default_tpn;
6757 if (nta_tpn_by_via(tpn, sip->sip_via, use_rport) < 0)
6758 tpn = NULL((void*)0);
6759 }
6760 else {
6761 tpn = irq->irq_tpn;
6762 }
6763
6764 if (sip_complete_message(msg) < 0)
6765 SU_DEBUG_1(("%s: sip_complete_message() failed\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 6765, "%s: sip_complete_message() failed\n", __func__)) : (
void)0)
;
6766 else if (msg_serialize(msg, (msg_pub_t *)sip) < 0)
6767 SU_DEBUG_1(("%s: sip_serialize() failed\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 6767, "%s: sip_serialize() failed\n", __func__)) : (void)0)
;
6768 else if (!(irq->irq_tport) &&
6769 !(tport_decref(&irq->irq_tport),
6770 irq->irq_tport = tpn ? tport_by_name(agent->sa_tports, tpn) : 0))
6771 SU_DEBUG_1(("%s: no tport\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 6771, "%s: no tport\n", __func__)) : (void)0)
;
6772 else {
6773 int i, err = 0;
6774 tport_t *tp = NULL((void*)0);
6775 incoming_queue_t *queue;
6776
6777 char const *method_name;
6778 uint32_t cseq;
6779
6780 if (irq->irq_default) {
6781 assert(sip->sip_cseq)((void) sizeof ((sip->sip_cseq) ? 1 : 0), __extension__ ({
if (sip->sip_cseq) ; else __assert_fail ("sip->sip_cseq"
, "nta.c", 6781, __extension__ __PRETTY_FUNCTION__); }))
;
6782 method_name = sip->sip_cseq->cs_method_name, cseq = sip->sip_cseq->cs_seq;
6783 }
6784 else {
6785 method_name = irq->irq_rq->rq_method_name, cseq = irq->irq_cseq->cs_seq;
6786 }
6787
6788 if (sending) {
6789 for (i = 0; i < 3; i++) {
6790 tp = tport_tsend(irq->irq_tport, msg, tpn,
6791 IF_SIGCOMP_TPTAG_COMPARTMENT(irq->irq_cc)!(irq->irq_cc && irq->irq_cc != ((void *)-1)) ?
tag_skip : tptag_compartment, tag_ptr_v((irq->irq_cc)),
6792 TPTAG_MTU(INT_MAX)tptag_mtu, tag_usize_v((2147483647)),
6793 TAG_END()(tag_type_t)0, (tag_value_t)0);
6794 if (tp)
6795 break;
6796
6797 err = msg_errno(msg);
6798 SU_DEBUG_5(("%s: tport_tsend: %s%s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 6800, "%s: tport_tsend: %s%s\n", __func__, su_strerror(err)
, err == 32 ? "(retrying)" : "")) : (void)0)
6799 __func__, su_strerror(err),(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 6800, "%s: tport_tsend: %s%s\n", __func__, su_strerror(err)
, err == 32 ? "(retrying)" : "")) : (void)0)
6800 err == EPIPE ? "(retrying)" : ""))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 6800, "%s: tport_tsend: %s%s\n", __func__, su_strerror(err)
, err == 32 ? "(retrying)" : "")) : (void)0)
;
6801
6802 if (err != EPIPE32 && err != ECONNREFUSED111)
6803 break;
6804 tport_decref(&irq->irq_tport);
6805 irq->irq_tport = tport_ref(tport_by_name(agent->sa_tports, tpn));
6806 }
6807
6808 if (!tp) {
6809 SU_DEBUG_3(("%s: tport_tsend: "(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 6812, "%s: tport_tsend: " "error (%s) while sending %u %s for %s (%u)\n"
, __func__, su_strerror(err), status, sip->sip_status->
st_phrase, method_name, cseq)) : (void)0)
6810 "error (%s) while sending %u %s for %s (%u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 6812, "%s: tport_tsend: " "error (%s) while sending %u %s for %s (%u)\n"
, __func__, su_strerror(err), status, sip->sip_status->
st_phrase, method_name, cseq)) : (void)0)
6811 __func__, su_strerror(err),(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 6812, "%s: tport_tsend: " "error (%s) while sending %u %s for %s (%u)\n"
, __func__, su_strerror(err), status, sip->sip_status->
st_phrase, method_name, cseq)) : (void)0)
6812 status, sip->sip_status->st_phrase, method_name, cseq))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 6812, "%s: tport_tsend: " "error (%s) while sending %u %s for %s (%u)\n"
, __func__, su_strerror(err), status, sip->sip_status->
st_phrase, method_name, cseq)) : (void)0)
;
6813 if (status < 200)
6814 msg_destroy(msg);
6815 else
6816 incoming_final_failed(irq, msg);
6817 return 0;
6818 }
6819
6820 agent->sa_stats->as_sent_msg++;
6821 agent->sa_stats->as_sent_response++;
6822 }
6823
6824 SU_DEBUG_5(("nta: %s %u %s for %s (%u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 6826, "nta: %s %u %s for %s (%u)\n", sending ? "sent" : "not sending"
, status, sip->sip_status->st_phrase, method_name, cseq
)) : (void)0)
6825 sending ? "sent" : "not sending",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 6826, "nta: %s %u %s for %s (%u)\n", sending ? "sent" : "not sending"
, status, sip->sip_status->st_phrase, method_name, cseq
)) : (void)0)
6826 status, sip->sip_status->st_phrase, method_name, cseq))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 6826, "nta: %s %u %s for %s (%u)\n", sending ? "sent" : "not sending"
, status, sip->sip_status->st_phrase, method_name, cseq
)) : (void)0)
;
6827
6828 if (irq->irq_default) {
6829 msg_destroy(msg);
6830 return 0;
6831 }
6832
6833 incoming_reset_timer(irq);
6834
6835 if (status < 200) {
6836 queue = agent->sa_in.proceeding;
6837
6838 if (irq->irq_method == sip_method_invite && status > 100 &&
6839 agent->sa_progress != UINT_MAX(2147483647 *2U +1U) && agent->sa_is_a_uas) {
6840 /* Retransmit preliminary responses in regular intervals */
6841 incoming_set_timer(irq, agent->sa_progress); /* N2 */
6842 }
6843 }
6844 else {
6845 irq->irq_completed = 1;
6846
6847 /* XXX - we should do this only after message has actually been sent! */
6848 if (irq->irq_sigcomp_zap && irq->irq_cc)
6849 agent_close_compressor(irq->irq_agent, irq->irq_cc);
6850
6851 if (irq->irq_method != sip_method_invite) {
6852 irq->irq_confirmed = 1;
6853
6854 if (irq->irq_reliable_tp) {
6855 irq->irq_terminated = 1;
6856 queue = agent->sa_in.terminated ; /* J - set for 0 seconds */
6857 } else {
6858 queue = agent->sa_in.completed; /* J */
6859 }
6860
6861 tport_decref(&irq->irq_tport);
6862 }
6863 else if (status >= 300 || agent->sa_is_a_uas) {
6864 if (status < 300 || !irq->irq_reliable_tp)
6865 incoming_set_timer(irq, agent->sa_t1); /* G */
6866 queue = agent->sa_in.inv_completed; /* H */
6867 }
6868 else {
6869#if 1
6870 /* Avoid bug in @RFC3261:
6871 Keep INVITE transaction around in order to catch
6872 retransmitted INVITEs
6873 */
6874 irq->irq_confirmed = 1;
6875 queue = agent->sa_in.inv_confirmed; /* H */
6876#else
6877 irq->irq_terminated = 1;
6878 queue = agent->sa_in.terminated;
6879#endif
6880 }
6881 }
6882
6883 if (irq->irq_queue != queue)
6884 incoming_queue(queue, irq);
6885
6886 if (status >= 200 || irq->irq_status < 200) {
6887 if (irq->irq_response)
6888 msg_destroy(irq->irq_response);
6889 assert(msg_home(msg) != irq->irq_home)((void) sizeof ((((su_home_t*)(msg)) != irq->irq_home) ? 1
: 0), __extension__ ({ if (((su_home_t*)(msg)) != irq->irq_home
) ; else __assert_fail ("msg_home(msg) != irq->irq_home", "nta.c"
, 6889, __extension__ __PRETTY_FUNCTION__); }))
;
6890 irq->irq_response = msg;
6891 }
6892 else {
6893 msg_destroy(msg);
6894 }
6895
6896 if (sip->sip_cseq->cs_method == irq->irq_method &&
6897 irq->irq_status < 200 && status > irq->irq_status)
6898 irq->irq_status = status;
6899
6900 return 0;
6901 }
6902
6903 /*
6904 * XXX - handling error is very problematic.
6905 * Nobody checks return code from nta_incoming_*reply()
6906 */
6907 if (status < 200) {
6908 msg_destroy(msg);
6909 return -1;
6910 }
6911
6912 /* We could not send final response. */
6913 return incoming_final_failed(irq, msg);
6914}
6915
6916
6917/** @internal Sending final response has failed.
6918 *
6919 * Put transaction into its own queue, try later to send the response.
6920 */
6921su_inlinestatic inline
6922int incoming_final_failed(nta_incoming_t *irq, msg_t *msg)
6923{
6924 msg_destroy(msg);
6925
6926 if (!irq->irq_default) {
6927 irq->irq_final_failed = 1;
6928 incoming_queue(irq->irq_agent->sa_in.final_failed, irq);
6929 }
6930
6931 return -1;
6932}
6933
6934/** @internal Retransmit the reply */
6935static
6936void incoming_retransmit_reply(nta_incoming_t *irq, tport_t *tport)
6937{
6938 msg_t *msg = NULL((void*)0);
6939
6940 if (irq->irq_final_failed)
6941 return;
6942
6943 if (tport == NULL((void*)0))
6944 tport = irq->irq_tport;
6945
6946 /* Answer with existing reply */
6947 if (irq->irq_reliable && !irq->irq_reliable->rel_pracked)
6948 msg = reliable_response(irq);
6949 else
6950 msg = irq->irq_response;
6951
6952 if (msg && tport) {
6953 irq->irq_retries++;
6954
6955 if (irq->irq_retries == 2 && irq->irq_tpn->tpn_comp) {
6956 irq->irq_tpn->tpn_comp = NULL((void*)0);
6957
6958 if (irq->irq_cc) {
6959 agent_close_compressor(irq->irq_agent, irq->irq_cc);
6960 nta_compartment_decref(&irq->irq_cc);
6961 }
6962 }
6963
6964 tport_tsend(tport, msg, irq->irq_tpn,
6965 IF_SIGCOMP_TPTAG_COMPARTMENT(irq->irq_cc)!(irq->irq_cc && irq->irq_cc != ((void *)-1)) ?
tag_skip : tptag_compartment, tag_ptr_v((irq->irq_cc)),
6966 TPTAG_MTU(INT_MAX)tptag_mtu, tag_usize_v((2147483647)), TAG_END()(tag_type_t)0, (tag_value_t)0);
6967 irq->irq_agent->sa_stats->as_sent_msg++;
6968 irq->irq_agent->sa_stats->as_sent_response++;
6969 }
6970}
6971
6972/** @internal Create timestamp header for response */
6973static
6974int incoming_timestamp(nta_incoming_t *irq, msg_t *msg, sip_t *sip)
6975{
6976 sip_timestamp_t ts[1];
6977 su_time_t now = su_now();
6978 char delay[32];
6979 double diff = su_time_diff(now, irq->irq_received);
6980
6981 snprintf(delay, sizeof delay, "%.06f", diff);
6982
6983 *ts = *irq->irq_timestamp;
6984 ts->ts_delay = delay;
6985
6986 return sip_add_dup(msg, sip, (sip_header_t *)ts);
6987}
6988
6989enum {
6990 timer_max_retransmit = 30,
6991 timer_max_terminate = 100000,
6992 timer_max_timeout = 100
6993};
6994
6995/** @internal Timer routine for the incoming request. */
6996static void
6997_nta_incoming_timer(nta_agent_t *sa)
6998{
6999 uint32_t now;
7000 nta_incoming_t *irq, *irq_next;
7001 size_t retransmitted = 0, timeout = 0, terminated = 0, destroyed = 0;
7002 size_t unconfirmed =
7003 sa->sa_in.inv_completed->q_length +
7004 sa->sa_in.preliminary->q_length;
7005 size_t unterminated =
7006 sa->sa_in.inv_confirmed->q_length +
7007 sa->sa_in.completed->q_length;
7008 size_t total = sa->sa_incoming->iht_used;
7009
7010 incoming_queue_t rq[1];
7011
7012 incoming_queue_init(rq, 0);
7013
7014 /* Handle retry queue */
7015 while ((irq = sa->sa_in.re_list)) {
7016
7017 now = su_time_ms(su_now());
7018
7019 if ((int32_t)(irq->irq_retry - now) > 0)
7020 break;
7021 if (retransmitted >= timer_max_retransmit)
7022 break;
7023
7024 if (irq->irq_method == sip_method_invite && irq->irq_status >= 200) {
7025 /* Timer G */
7026 assert(irq->irq_queue == sa->sa_in.inv_completed)((void) sizeof ((irq->irq_queue == sa->sa_in.inv_completed
) ? 1 : 0), __extension__ ({ if (irq->irq_queue == sa->
sa_in.inv_completed) ; else __assert_fail ("irq->irq_queue == sa->sa_in.inv_completed"
, "nta.c", 7026, __extension__ __PRETTY_FUNCTION__); }))
;
7027
7028 retransmitted++;
7029
7030 SU_DEBUG_5(("nta: timer %s fired, retransmitting %u reply\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 7031, "nta: timer %s fired, retransmitting %u reply\n", "G"
, irq->irq_status)) : (void)0)
7031 "G", irq->irq_status))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 7031, "nta: timer %s fired, retransmitting %u reply\n", "G"
, irq->irq_status)) : (void)0)
;
7032
7033 incoming_retransmit_reply(irq, irq->irq_tport);
7034
7035 if (2U * irq->irq_interval < sa->sa_t2)
7036 incoming_set_timer(irq, 2U * irq->irq_interval); /* G */
7037 else
7038 incoming_set_timer(irq, sa->sa_t2); /* G */
7039 }
7040 else if (irq->irq_method == sip_method_invite && irq->irq_status >= 100) {
7041 if (irq->irq_queue == sa->sa_in.preliminary) {
7042 /* Timer P1 - PRACK timer */
7043 retransmitted++;
7044 SU_DEBUG_5(("nta: timer %s fired, retransmitting %u reply\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 7045, "nta: timer %s fired, retransmitting %u reply\n", "P1"
, irq->irq_status)) : (void)0)
7045 "P1", irq->irq_status))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 7045, "nta: timer %s fired, retransmitting %u reply\n", "P1"
, irq->irq_status)) : (void)0)
;
7046
7047 incoming_retransmit_reply(irq, irq->irq_tport);
7048
7049 incoming_set_timer(irq, 2 * irq->irq_interval); /* P1 */
7050 }
7051 else {
7052 /* Retransmitting provisional responses */
7053 SU_DEBUG_5(("nta: timer %s fired, retransmitting %u reply\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 7054, "nta: timer %s fired, retransmitting %u reply\n", "N2"
, irq->irq_status)) : (void)0)
7054 "N2", irq->irq_status))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 7054, "nta: timer %s fired, retransmitting %u reply\n", "N2"
, irq->irq_status)) : (void)0)
;
7055 incoming_set_timer(irq, sa->sa_progress);
7056 retransmitted++;
7057 incoming_retransmit_reply(irq, irq->irq_tport);
7058 }
7059 }
7060 else {
7061 /* Timer N1 */
7062 incoming_reset_timer(irq);
7063
7064 if(irq->irq_extra_100) {
7065 SU_DEBUG_5(("nta: timer N1 fired, sending %u %s\n", SIP_100_TRYING))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 7065, "nta: timer N1 fired, sending %u %s\n", 100, sip_100_Trying
)) : (void)0)
;
7066 nta_incoming_treply(irq, SIP_100_TRYING100, sip_100_Trying, TAG_END()(tag_type_t)0, (tag_value_t)0);
7067 }
7068 else {
7069 SU_DEBUG_5(("nta: timer N1 fired, but avoided sending %u %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 7070, "nta: timer N1 fired, but avoided sending %u %s\n", 100
, sip_100_Trying)) : (void)0)
7070 SIP_100_TRYING))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 7070, "nta: timer N1 fired, but avoided sending %u %s\n", 100
, sip_100_Trying)) : (void)0)
;
7071 }
7072 }
7073 }
7074
7075 while ((irq = sa->sa_in.final_failed->q_head)) {
7076
7077
7078 incoming_remove(irq);
7079 irq->irq_final_failed = 0;
7080
7081 /* Report error to application */
7082 SU_DEBUG_5(("nta: sending final response failed, timeout %u response\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 7083, "nta: sending final response failed, timeout %u response\n"
, irq->irq_status)) : (void)0)
7083 irq->irq_status))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 7083, "nta: sending final response failed, timeout %u response\n"
, irq->irq_status)) : (void)0)
;
7084 reliable_timeout(irq, 0);
7085
7086 nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error, TAG_END()(tag_type_t)0, (tag_value_t)0);
7087
7088 if (!irq->irq_final_failed) /* We have taken care of the error... */
7089 continue;
7090
7091 if (irq->irq_destroyed) {
7092 incoming_free_queue(rq, irq);
7093 continue;
7094 }
7095
7096 incoming_reset_timer(irq);
7097 irq->irq_confirmed = 1;
7098 irq->irq_terminated = 1;
7099 incoming_queue(sa->sa_in.terminated, irq);
7100 }
7101
7102 /* Timeouts.
7103 * For each state the request is in, there is always a queue of its own
7104 */
7105 while ((irq = sa->sa_in.preliminary->q_head)) {
7106 assert(irq->irq_status < 200)((void) sizeof ((irq->irq_status < 200) ? 1 : 0), __extension__
({ if (irq->irq_status < 200) ; else __assert_fail ("irq->irq_status < 200"
, "nta.c", 7106, __extension__ __PRETTY_FUNCTION__); }))
;
7107 assert(irq->irq_timeout)((void) sizeof ((irq->irq_timeout) ? 1 : 0), __extension__
({ if (irq->irq_timeout) ; else __assert_fail ("irq->irq_timeout"
, "nta.c", 7107, __extension__ __PRETTY_FUNCTION__); }))
;
7108
7109 now = su_time_ms(su_now());
7110
7111 if ((int32_t)(irq->irq_timeout - now) > 0)
7112 break;
7113 if (timeout >= timer_max_timeout)
7114 break;
7115
7116 timeout++;
7117
7118 /* Timer P2 - PRACK timer */
7119 SU_DEBUG_5(("nta: timer %s fired, %s %u response\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 7120, "nta: timer %s fired, %s %u response\n", "P2", "timeout"
, irq->irq_status)) : (void)0)
7120 "P2", "timeout", irq->irq_status))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 7120, "nta: timer %s fired, %s %u response\n", "P2", "timeout"
, irq->irq_status)) : (void)0)
;
7121 incoming_reset_timer(irq);
7122 irq->irq_timeout = 0;
7123 reliable_timeout(irq, 1);
7124 }
7125
7126 while ((irq = sa->sa_in.inv_completed->q_head)) {
7127 assert(irq->irq_status >= 200)((void) sizeof ((irq->irq_status >= 200) ? 1 : 0), __extension__
({ if (irq->irq_status >= 200) ; else __assert_fail ("irq->irq_status >= 200"
, "nta.c", 7127, __extension__ __PRETTY_FUNCTION__); }))
;
7128 assert(irq->irq_timeout)((void) sizeof ((irq->irq_timeout) ? 1 : 0), __extension__
({ if (irq->irq_timeout) ; else __assert_fail ("irq->irq_timeout"
, "nta.c", 7128, __extension__ __PRETTY_FUNCTION__); }))
;
7129 assert(irq->irq_method == sip_method_invite)((void) sizeof ((irq->irq_method == sip_method_invite) ? 1
: 0), __extension__ ({ if (irq->irq_method == sip_method_invite
) ; else __assert_fail ("irq->irq_method == sip_method_invite"
, "nta.c", 7129, __extension__ __PRETTY_FUNCTION__); }))
;
7130
7131 now = su_time_ms(su_now());
7132
7133 if ((int32_t)(irq->irq_timeout - now) > 0 ||
7134 timeout >= timer_max_timeout ||
7135 terminated >= timer_max_terminate)
7136 break;
7137
7138 /* Timer H */
7139 SU_DEBUG_5(("nta: timer %s fired, %s %u response\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 7140, "nta: timer %s fired, %s %u response\n", "H", "timeout and terminate"
, irq->irq_status)) : (void)0)
7140 "H", "timeout and terminate", irq->irq_status))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 7140, "nta: timer %s fired, %s %u response\n", "H", "timeout and terminate"
, irq->irq_status)) : (void)0)
;
7141 irq->irq_confirmed = 1;
7142 irq->irq_terminated = 1;
7143 incoming_reset_timer(irq);
7144 if (!irq->irq_destroyed) {
7145 timeout++;
7146 incoming_queue(sa->sa_in.terminated, irq);
7147 /* report timeout error to user */
7148 incoming_call_callback(irq, NULL((void*)0), NULL((void*)0));
7149 } else {
7150 timeout++;
7151 terminated++;
7152 incoming_free_queue(rq, irq);
7153 }
7154 }
7155
7156 while ((irq = sa->sa_in.inv_confirmed->q_head)) {
7157 assert(irq->irq_timeout)((void) sizeof ((irq->irq_timeout) ? 1 : 0), __extension__
({ if (irq->irq_timeout) ; else __assert_fail ("irq->irq_timeout"
, "nta.c", 7157, __extension__ __PRETTY_FUNCTION__); }))
;
7158 assert(irq->irq_status >= 200)((void) sizeof ((irq->irq_status >= 200) ? 1 : 0), __extension__
({ if (irq->irq_status >= 200) ; else __assert_fail ("irq->irq_status >= 200"
, "nta.c", 7158, __extension__ __PRETTY_FUNCTION__); }))
;
7159 assert(irq->irq_method == sip_method_invite)((void) sizeof ((irq->irq_method == sip_method_invite) ? 1
: 0), __extension__ ({ if (irq->irq_method == sip_method_invite
) ; else __assert_fail ("irq->irq_method == sip_method_invite"
, "nta.c", 7159, __extension__ __PRETTY_FUNCTION__); }))
;
7160
7161 now = su_time_ms(su_now());
7162
7163 if ((int32_t)(irq->irq_timeout - now) > 0 ||
7164 terminated >= timer_max_terminate)
7165 break;
7166
7167 /* Timer I */
7168 SU_DEBUG_5(("nta: timer %s fired, %s %u response\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 7169, "nta: timer %s fired, %s %u response\n", "I", "terminate"
, irq->irq_status)) : (void)0)
7169 "I", "terminate", irq->irq_status))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 7169, "nta: timer %s fired, %s %u response\n", "I", "terminate"
, irq->irq_status)) : (void)0)
;
7170
7171 terminated++;
7172 irq->irq_terminated = 1;
7173
7174 if (!irq->irq_destroyed)
7175 incoming_queue(sa->sa_in.terminated, irq);
7176 else
7177 incoming_free_queue(rq, irq);
7178 }
7179
7180 while ((irq = sa->sa_in.completed->q_head)) {
7181 assert(irq->irq_status >= 200)((void) sizeof ((irq->irq_status >= 200) ? 1 : 0), __extension__
({ if (irq->irq_status >= 200) ; else __assert_fail ("irq->irq_status >= 200"
, "nta.c", 7181, __extension__ __PRETTY_FUNCTION__); }))
;
7182 assert(irq->irq_timeout)((void) sizeof ((irq->irq_timeout) ? 1 : 0), __extension__
({ if (irq->irq_timeout) ; else __assert_fail ("irq->irq_timeout"
, "nta.c", 7182, __extension__ __PRETTY_FUNCTION__); }))
;
7183 assert(irq->irq_method != sip_method_invite)((void) sizeof ((irq->irq_method != sip_method_invite) ? 1
: 0), __extension__ ({ if (irq->irq_method != sip_method_invite
) ; else __assert_fail ("irq->irq_method != sip_method_invite"
, "nta.c", 7183, __extension__ __PRETTY_FUNCTION__); }))
;
7184
7185 now = su_time_ms(su_now());
7186
7187 if ((int32_t)(irq->irq_timeout - now) > 0 ||
7188 terminated >= timer_max_terminate)
7189 break;
7190
7191 /* Timer J */
7192
7193 SU_DEBUG_5(("nta: timer %s fired, %s %u response\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 7194, "nta: timer %s fired, %s %u response\n", "J", "terminate"
, irq->irq_status)) : (void)0)
7194 "J", "terminate", irq->irq_status))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 7194, "nta: timer %s fired, %s %u response\n", "J", "terminate"
, irq->irq_status)) : (void)0)
;
7195
7196 terminated++;
7197 irq->irq_terminated = 1;
7198
7199 if (!irq->irq_destroyed)
7200 incoming_queue(sa->sa_in.terminated, irq);
7201 else
7202 incoming_free_queue(rq, irq);
7203 }
7204
7205 for (irq = sa->sa_in.terminated->q_head; irq; irq = irq_next) {
7206
7207 irq_next = irq->irq_next;
7208 if (irq->irq_destroyed)
7209 incoming_free_queue(rq, irq);
7210 }
7211
7212 destroyed = incoming_mass_destroy(sa, rq);
7213
7214 if (retransmitted || timeout || terminated || destroyed)
7215 SU_DEBUG_5(("nta_incoming_timer: "(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 7223, "nta_incoming_timer: " "%zu""/""%zu"" resent, " "%zu"
"/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n"
, retransmitted, unconfirmed, timeout, unconfirmed, terminated
, unterminated, destroyed, total)) : (void)0)
7216 MOD_ZU"/"MOD_ZU" resent, "(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 7223, "nta_incoming_timer: " "%zu""/""%zu"" resent, " "%zu"
"/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n"
, retransmitted, unconfirmed, timeout, unconfirmed, terminated
, unterminated, destroyed, total)) : (void)0)
7217 MOD_ZU"/"MOD_ZU" tout, "(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 7223, "nta_incoming_timer: " "%zu""/""%zu"" resent, " "%zu"
"/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n"
, retransmitted, unconfirmed, timeout, unconfirmed, terminated
, unterminated, destroyed, total)) : (void)0)
7218 MOD_ZU"/"MOD_ZU" term, "(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 7223, "nta_incoming_timer: " "%zu""/""%zu"" resent, " "%zu"
"/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n"
, retransmitted, unconfirmed, timeout, unconfirmed, terminated
, unterminated, destroyed, total)) : (void)0)
7219 MOD_ZU"/"MOD_ZU" free\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 7223, "nta_incoming_timer: " "%zu""/""%zu"" resent, " "%zu"
"/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n"
, retransmitted, unconfirmed, timeout, unconfirmed, terminated
, unterminated, destroyed, total)) : (void)0)
7220 retransmitted, unconfirmed,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 7223, "nta_incoming_timer: " "%zu""/""%zu"" resent, " "%zu"
"/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n"
, retransmitted, unconfirmed, timeout, unconfirmed, terminated
, unterminated, destroyed, total)) : (void)0)
7221 timeout, unconfirmed,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 7223, "nta_incoming_timer: " "%zu""/""%zu"" resent, " "%zu"
"/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n"
, retransmitted, unconfirmed, timeout, unconfirmed, terminated
, unterminated, destroyed, total)) : (void)0)
7222 terminated, unterminated,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 7223, "nta_incoming_timer: " "%zu""/""%zu"" resent, " "%zu"
"/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n"
, retransmitted, unconfirmed, timeout, unconfirmed, terminated
, unterminated, destroyed, total)) : (void)0)
7223 destroyed, total))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 7223, "nta_incoming_timer: " "%zu""/""%zu"" resent, " "%zu"
"/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n"
, retransmitted, unconfirmed, timeout, unconfirmed, terminated
, unterminated, destroyed, total)) : (void)0)
;
7224}
7225
7226/** Mass destroy server transactions */
7227su_inlinestatic inline
7228size_t incoming_mass_destroy(nta_agent_t *sa, incoming_queue_t *q)
7229{
7230 size_t destroyed = q->q_length;
7231
7232 if (destroyed > 2 && *sa->sa_terminator) {
7233 su_msg_r m = SU_MSG_R_INIT{ ((void*)0) };
7234
7235 if (su_msg_create(m,
7236 su_clone_task(sa->sa_terminator),
7237 su_root_task(sa->sa_root),
7238 incoming_reclaim_queued,
7239 sizeof(incoming_queue_t)) == SU_SUCCESSsu_success) {
7240 incoming_queue_t *mq = su_msg_data(m)->a_incoming_queue;
7241
7242 *mq = *q;
7243
7244 if (su_msg_send(m) == SU_SUCCESSsu_success)
7245 q->q_length = 0;
7246 }
7247 }
7248
7249 if (q->q_length > 0)
7250 incoming_reclaim_queued(NULL((void*)0), NULL((void*)0), (void *)q);
7251
7252 return destroyed;
7253}
7254
7255/* ====================================================================== */
7256/* 8) Client-side (outgoing) transactions */
7257
7258#define HTABLE_HASH_ORQ(orq)((orq)->orq_hash) ((orq)->orq_hash)
7259
7260#ifdef __clang__1
7261#pragma clang diagnostic push
7262#pragma clang diagnostic ignored "-Wunused-function"
7263#endif
7264
7265HTABLE_BODIES_WITH(outgoing_htable, oht, nta_outgoing_t, HTABLE_HASH_ORQ,static inline int outgoing_htable_resize(su_home_t *home, outgoing_htable_t
oht[], size_t new_size) { nta_outgoing_t **new_hash; nta_outgoing_t
**old_hash = oht->oht_table; size_t old_size; size_t i, j
, i0; unsigned again = 0; size_t used = 0, collisions = 0; if
(new_size == 0) new_size = 2 * oht->oht_size + 1; if (new_size
< 31) new_size = 31; if (new_size < 5 * oht->oht_used
/ 4) new_size = 5 * oht->oht_used / 4; if (!(new_hash = su_zalloc
(home, sizeof(*new_hash) * new_size))) return -1; old_size = oht
->oht_size; do for (j = 0; j < old_size; j++) { if (!old_hash
[j]) continue; if (again < 2 && ((old_hash[j])->
orq_hash) % old_size > j) { again = 1; continue; } i0 = ((
old_hash[j])->orq_hash) % new_size; for (i = i0; new_hash[
i]; i = (i + 1) % new_size, ((void) sizeof ((i != i0) ? 1 : 0
), __extension__ ({ if (i != i0) ; else __assert_fail ("i != i0"
, "nta.c", 7266, __extension__ __PRETTY_FUNCTION__); }))) collisions
++; new_hash[i] = old_hash[j], old_hash[j] = ((void*)0); used
++; } while (again++ == 1); oht->oht_table = new_hash, oht
->oht_size = new_size; ((void) sizeof ((oht->oht_used ==
used) ? 1 : 0), __extension__ ({ if (oht->oht_used == used
) ; else __assert_fail ("oht->oht_used == used", "nta.c", 7266
, __extension__ __PRETTY_FUNCTION__); })); su_free(home, old_hash
); return 0; } static inline int outgoing_htable_is_full(outgoing_htable_t
const *oht) { return oht->oht_table == ((void*)0) || 3 * oht
->oht_used > 2 * oht->oht_size; } static inline nta_outgoing_t
**outgoing_htable_hash(outgoing_htable_t const *oht, hash_value_t
hv) { return oht->oht_table + hv % oht->oht_size; } static
inline nta_outgoing_t **outgoing_htable_next(outgoing_htable_t
const *oht, nta_outgoing_t * const *ee) { if (++ee < oht->
oht_table + oht->oht_size && ee >= oht->oht_table
) return (nta_outgoing_t **)ee; else return oht->oht_table
; } static inline void outgoing_htable_append(outgoing_htable_t
*oht, nta_outgoing_t const *e) { nta_outgoing_t **ee; oht->
oht_used++; for (ee = outgoing_htable_hash(oht, ((e)->orq_hash
)); *ee; ee = outgoing_htable_next(oht, ee)) ; *ee = (nta_outgoing_t
*)e; } static inline void outgoing_htable_insert(outgoing_htable_t
*oht, nta_outgoing_t const *e) { nta_outgoing_t *e0, **ee; oht
->oht_used++; for (ee = outgoing_htable_hash(oht, ((e)->
orq_hash)); (e0 = *ee); ee = outgoing_htable_next(oht, ee)) *
ee = (nta_outgoing_t *)e, e = e0; *ee = (nta_outgoing_t *)e; }
static inline int outgoing_htable_remove(outgoing_htable_t *
oht, nta_outgoing_t const *e) { size_t i, j, k; size_t size =
oht->oht_size; nta_outgoing_t **htable = oht->oht_table
; if (!e) return -1; for (i = ((e)->orq_hash) % size; htable
[i]; i = (i + 1) % size) if (e == htable[i]) break; if (!htable
[i]) return -1; for (j = (i + 1) % size; htable[j]; j = (j + 1
) % size) { k = ((htable[j])->orq_hash) % size; if (k == j
) continue; if (j > i ? (i < k && k < j) : (
i < k || k < j)) continue; htable[i] = htable[j], i = j
; } oht->oht_used--; htable[i] = ((void*)0); return 0; } extern
int outgoing_htable_dummy
7266 size_t, hash_value_t)static inline int outgoing_htable_resize(su_home_t *home, outgoing_htable_t
oht[], size_t new_size) { nta_outgoing_t **new_hash; nta_outgoing_t
**old_hash = oht->oht_table; size_t old_size; size_t i, j
, i0; unsigned again = 0; size_t used = 0, collisions = 0; if
(new_size == 0) new_size = 2 * oht->oht_size + 1; if (new_size
< 31) new_size = 31; if (new_size < 5 * oht->oht_used
/ 4) new_size = 5 * oht->oht_used / 4; if (!(new_hash = su_zalloc
(home, sizeof(*new_hash) * new_size))) return -1; old_size = oht
->oht_size; do for (j = 0; j < old_size; j++) { if (!old_hash
[j]) continue; if (again < 2 && ((old_hash[j])->
orq_hash) % old_size > j) { again = 1; continue; } i0 = ((
old_hash[j])->orq_hash) % new_size; for (i = i0; new_hash[
i]; i = (i + 1) % new_size, ((void) sizeof ((i != i0) ? 1 : 0
), __extension__ ({ if (i != i0) ; else __assert_fail ("i != i0"
, "nta.c", 7266, __extension__ __PRETTY_FUNCTION__); }))) collisions
++; new_hash[i] = old_hash[j], old_hash[j] = ((void*)0); used
++; } while (again++ == 1); oht->oht_table = new_hash, oht
->oht_size = new_size; ((void) sizeof ((oht->oht_used ==
used) ? 1 : 0), __extension__ ({ if (oht->oht_used == used
) ; else __assert_fail ("oht->oht_used == used", "nta.c", 7266
, __extension__ __PRETTY_FUNCTION__); })); su_free(home, old_hash
); return 0; } static inline int outgoing_htable_is_full(outgoing_htable_t
const *oht) { return oht->oht_table == ((void*)0) || 3 * oht
->oht_used > 2 * oht->oht_size; } static inline nta_outgoing_t
**outgoing_htable_hash(outgoing_htable_t const *oht, hash_value_t
hv) { return oht->oht_table + hv % oht->oht_size; } static
inline nta_outgoing_t **outgoing_htable_next(outgoing_htable_t
const *oht, nta_outgoing_t * const *ee) { if (++ee < oht->
oht_table + oht->oht_size && ee >= oht->oht_table
) return (nta_outgoing_t **)ee; else return oht->oht_table
; } static inline void outgoing_htable_append(outgoing_htable_t
*oht, nta_outgoing_t const *e) { nta_outgoing_t **ee; oht->
oht_used++; for (ee = outgoing_htable_hash(oht, ((e)->orq_hash
)); *ee; ee = outgoing_htable_next(oht, ee)) ; *ee = (nta_outgoing_t
*)e; } static inline void outgoing_htable_insert(outgoing_htable_t
*oht, nta_outgoing_t const *e) { nta_outgoing_t *e0, **ee; oht
->oht_used++; for (ee = outgoing_htable_hash(oht, ((e)->
orq_hash)); (e0 = *ee); ee = outgoing_htable_next(oht, ee)) *
ee = (nta_outgoing_t *)e, e = e0; *ee = (nta_outgoing_t *)e; }
static inline int outgoing_htable_remove(outgoing_htable_t *
oht, nta_outgoing_t const *e) { size_t i, j, k; size_t size =
oht->oht_size; nta_outgoing_t **htable = oht->oht_table
; if (!e) return -1; for (i = ((e)->orq_hash) % size; htable
[i]; i = (i + 1) % size) if (e == htable[i]) break; if (!htable
[i]) return -1; for (j = (i + 1) % size; htable[j]; j = (j + 1
) % size) { k = ((htable[j])->orq_hash) % size; if (k == j
) continue; if (j > i ? (i < k && k < j) : (
i < k || k < j)) continue; htable[i] = htable[j], i = j
; } oht->oht_used--; htable[i] = ((void*)0); return 0; } extern
int outgoing_htable_dummy
;
7267
7268#ifdef __clang__1
7269#pragma clang diagnostic pop
7270#endif
7271
7272static int outgoing_features(nta_agent_t *agent, nta_outgoing_t *orq,
7273 msg_t *msg, sip_t *sip,
7274 tagi_t *tags);
7275static void outgoing_prepare_send(nta_outgoing_t *orq);
7276static void outgoing_send_via(nta_outgoing_t *orq, tport_t *tp);
7277static void outgoing_send(nta_outgoing_t *orq, int retransmit);
7278static void outgoing_try_tcp_instead(nta_outgoing_t *orq);
7279static void outgoing_try_udp_instead(nta_outgoing_t *orq, int timeout);
7280static void outgoing_tport_error(nta_agent_t *agent, nta_outgoing_t *orq,
7281 tport_t *tp, msg_t *msg, int error);
7282static void outgoing_print_tport_error(nta_outgoing_t *orq,
7283 int level, char *todo,
7284 tp_name_t const *, msg_t *, int error);
7285static void outgoing_insert(nta_agent_t *sa, nta_outgoing_t *orq);
7286static void outgoing_destroy(nta_outgoing_t *orq);
7287su_inlinestatic inline int outgoing_is_queued(nta_outgoing_t const *orq);
7288su_inlinestatic inline void outgoing_queue(outgoing_queue_t *queue,
7289 nta_outgoing_t *orq);
7290su_inlinestatic inline void outgoing_remove(nta_outgoing_t *orq);
7291su_inlinestatic inline void outgoing_set_timer(nta_outgoing_t *orq, uint32_t interval);
7292static void outgoing_reset_timer(nta_outgoing_t *orq);
7293static size_t outgoing_timer_dk(outgoing_queue_t *q,
7294 char const *timer,
7295 uint32_t now);
7296static size_t outgoing_timer_bf(outgoing_queue_t *q,
7297 char const *timer,
7298 uint32_t now);
7299static size_t outgoing_timer_c(outgoing_queue_t *q,
7300 char const *timer,
7301 uint32_t now);
7302
7303static void outgoing_ack(nta_outgoing_t *orq, sip_t *sip);
7304static msg_t *outgoing_ackmsg(nta_outgoing_t *, sip_method_t, char const *,
7305 tag_type_t tag, tag_value_t value, ...);
7306static void outgoing_retransmit(nta_outgoing_t *orq);
7307static void outgoing_trying(nta_outgoing_t *orq);
7308static void outgoing_timeout(nta_outgoing_t *orq, uint32_t now);
7309static int outgoing_complete(nta_outgoing_t *orq);
7310static void outgoing_terminate_invite(nta_outgoing_t *);
7311static void outgoing_remove_fork(nta_outgoing_t *orq);
7312static int outgoing_terminate(nta_outgoing_t *orq);
7313static size_t outgoing_mass_destroy(nta_agent_t *sa, outgoing_queue_t *q);
7314static void outgoing_estimate_delay(nta_outgoing_t *orq, sip_t *sip);
7315static int outgoing_duplicate(nta_outgoing_t *orq,
7316 msg_t *msg,
7317 sip_t *sip);
7318static int outgoing_reply(nta_outgoing_t *orq,
7319 int status, char const *phrase,
7320 int delayed);
7321
7322static int outgoing_default_cb(nta_outgoing_magic_t *magic,
7323 nta_outgoing_t *request,
7324 sip_t const *sip);
7325
7326
7327/** Create a default outgoing transaction.
7328 *
7329 * The default outgoing transaction is used when agent receives responses
7330 * not belonging to any transaction.
7331 *
7332 * @sa nta_leg_default(), nta_incoming_default().
7333 */
7334nta_outgoing_t *nta_outgoing_default(nta_agent_t *agent,
7335 nta_response_f *callback,
7336 nta_outgoing_magic_t *magic)
7337{
7338 nta_outgoing_t *orq;
7339
7340 if (agent == NULL((void*)0))
7341 return NULL((void*)0);
7342
7343 if (agent->sa_default_outgoing)
7344 return NULL((void*)0);
7345
7346 orq = su_zalloc(agent->sa_home, sizeof *orq);
7347 if (!orq)
7348 return NULL((void*)0);
7349
7350 orq->orq_agent = agent;
7351 orq->orq_callback = callback;
7352 orq->orq_magic = magic;
7353 orq->orq_method = sip_method_invalid;
7354 orq->orq_method_name = "*";
7355 orq->orq_default = 1;
7356 orq->orq_stateless = 1;
7357 orq->orq_delay = UINT_MAX(2147483647 *2U +1U);
7358
7359 return agent->sa_default_outgoing = orq;
7360}
7361
7362/**Create an outgoing request and client transaction belonging to the leg.
7363 *
7364 * Create a request message and pass the request message to an outgoing
7365 * client transaction object. The request is sent to the @a route_url (if
7366 * non-NULL), default proxy (if defined by NTATAG_DEFAULT_PROXY()), or to
7367 * the address specified by @a request_uri. If no @a request_uri is
7368 * specified, it is taken from route-set target or from the @To header.
7369 *
7370 * When NTA receives response to the request, it invokes the @a callback
7371 * function.
7372 *
7373 * @param leg call leg object
7374 * @param callback callback function (may be @c NULL)
7375 * @param magic application context pointer
7376 * @param route_url optional URL used to route transaction requests
7377 * @param method method type
7378 * @param name method name
7379 * @param request_uri Request-URI
7380 * @param tag, value, ... list of tagged arguments
7381 *
7382 * @return
7383 * A pointer to a newly created outgoing transaction object if successful,
7384 * and NULL otherwise.
7385 *
7386 * @note If NTATAG_STATELESS(1) tag is given and the @a callback is NULL,
7387 * the transaction object is marked as destroyed from the beginning. In that
7388 * case, the function may return @code (nta_outgoing_t *)-1 @endcode if the
7389 * transaction is freed before returning from the function.
7390 *
7391 * @sa
7392 * nta_outgoing_mcreate(), nta_outgoing_tcancel(), nta_outgoing_destroy().
7393 *
7394 * @TAGS
7395 * NTATAG_STATELESS(), NTATAG_DELAY_SENDING(), NTATAG_BRANCH_KEY(),
7396 * NTATAG_ACK_BRANCH(), NTATAG_DEFAULT_PROXY(), NTATAG_PASS_100(),
7397 * NTATAG_USE_TIMESTAMP(), NTATAG_USER_VIA(), TPTAG_IDENT(), NTATAG_TPORT(). All
7398 * SIP tags from <sofia-sip/sip_tag.h> can be used to manipulate the request message.
7399 * SIP tags after SIPTAG_END() are ignored, however.
7400 */
7401nta_outgoing_t *nta_outgoing_tcreate(nta_leg_t *leg,
7402 nta_response_f *callback,
7403 nta_outgoing_magic_t *magic,
7404 url_string_t const *route_url,
7405 sip_method_t method,
7406 char const *name,
7407 url_string_t const *request_uri,
7408 tag_type_t tag, tag_value_t value, ...)
7409{
7410 nta_agent_t *agent;
7411 msg_t *msg;
7412 sip_t *sip;
7413 nta_outgoing_t *orq = NULL((void*)0);
7414 ta_list ta;
7415 tagi_t const *tagi;
7416
7417 if (leg == NULL((void*)0))
7418 return NULL((void*)0);
7419
7420 agent = leg->leg_agent;
7421 msg = nta_msg_create(agent, 0);
7422 sip = sip_object(msg);
7423
7424 if (route_url == NULL((void*)0))
7425 route_url = (url_string_t *)agent->sa_default_proxy;
7426
7427 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)
;
7428
7429 tagi = ta_args(ta)(ta).tl;
7430
7431 if (sip_add_tagis(msg, sip, &tagi) < 0) {
7432 if (tagi && tagi->t_tag) {
7433 tag_type_t t = tagi->t_tag;
7434 SU_DEBUG_5(("%s(): bad tag %s::%s\n", __func__,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 7435, "%s(): bad tag %s::%s\n", __func__, t->tt_ns ? t->
tt_ns : "", t->tt_name ? t->tt_name : "")) : (void)0)
7435 t->tt_ns ? t->tt_ns : "", t->tt_name ? t->tt_name : ""))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 7435, "%s(): bad tag %s::%s\n", __func__, t->tt_ns ? t->
tt_ns : "", t->tt_name ? t->tt_name : "")) : (void)0)
;
7436 }
7437 }
7438 else if (route_url == NULL((void*)0) && leg->leg_route &&
7439 leg->leg_loose_route &&
7440 !(route_url = (url_string_t *)leg->leg_route->r_url))
7441 ;
7442 else if (nta_msg_request_complete(msg, leg, method, name, request_uri) < 0)
7443 ;
7444 else
7445 orq = outgoing_create(agent, callback, magic, route_url, NULL((void*)0), msg,
7446 ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
);
7447
7448 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))
;
7449
7450 if (!orq)
7451 msg_destroy(msg);
7452
7453 return orq;
7454}
7455
7456/**Create an outgoing client transaction.
7457 *
7458 * Create an outgoing transaction object. The request message is passed to
7459 * the transaction object, which sends the request to the network. The
7460 * request is sent to the @a route_url (if non-NULL), default proxy (if
7461 * defined by NTATAG_DEFAULT_PROXY()), or to the address specified by @a
7462 * request_uri. If no @a request_uri is specified, it is taken from
7463 * route-set target or from the @To header.
7464 *
7465 * When NTA receives response to the request, it invokes the @a callback
7466 * function.
7467 *
7468 * @param agent NTA agent object
7469 * @param callback callback function (may be @c NULL)
7470 * @param magic application context pointer
7471 * @param route_url optional URL used to route transaction requests
7472 * @param msg request message
7473 * @param tag, value, ... tagged parameter list
7474 *
7475 * @return
7476 * Returns a pointer to newly created outgoing transaction object if
7477 * successful, and NULL otherwise.
7478 *
7479 * @note The caller is responsible for destroying the request message @a msg
7480 * upon failure.
7481 *
7482 * @note If NTATAG_STATELESS(1) tag is given and the @a callback is NULL,
7483 * the transaction object is marked as destroyed from the beginning. In that
7484 * case, the function may return @code (nta_outgoing_t *)-1 @endcode if the
7485 * transaction is freed before returning from the function.
7486 *
7487 * @sa
7488 * nta_outgoing_tcreate(), nta_outgoing_tcancel(), nta_outgoing_destroy().
7489 *
7490 * @TAGS
7491 * NTATAG_STATELESS(), NTATAG_DELAY_SENDING(), NTATAG_BRANCH_KEY(),
7492 * NTATAG_ACK_BRANCH(), NTATAG_DEFAULT_PROXY(), NTATAG_PASS_100(),
7493 * NTATAG_USE_TIMESTAMP(), NTATAG_USER_VIA(), TPTAG_IDENT(), NTATAG_TPORT(). All
7494 * SIP tags from <sofia-sip/sip_tag.h> can be used to manipulate the request message.
7495 * SIP tags after SIPTAG_END() are ignored, however.
7496 */
7497nta_outgoing_t *nta_outgoing_mcreate(nta_agent_t *agent,
7498 nta_response_f *callback,
7499 nta_outgoing_magic_t *magic,
7500 url_string_t const *route_url,
7501 msg_t *msg,
7502 tag_type_t tag, tag_value_t value, ...)
7503{
7504 nta_outgoing_t *orq = NULL((void*)0);
7505 int cleanup = 0;
7506
7507 if (msg == NONE((void *)-1))
7508 msg = nta_msg_create(agent, 0), cleanup = 1;
7509
7510 if (msg && agent) {
7511 ta_list ta;
7512 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)
;
7513 if (sip_add_tl(msg, sip_object(msg), ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
) >= 0)
7514 orq = outgoing_create(agent, callback, magic, route_url, NULL((void*)0), msg,
7515 ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
);
7516 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))
;
7517 }
7518
7519 if (!orq && cleanup)
7520 msg_destroy(msg);
7521
7522 return orq;
7523}
7524
7525/** Cancel the request. */
7526int nta_outgoing_cancel(nta_outgoing_t *orq)
7527{
7528 nta_outgoing_t *cancel =
7529 nta_outgoing_tcancel(orq, NULL((void*)0), NULL((void*)0), TAG_NULL()(tag_type_t)0, (tag_value_t)0);
7530
7531 return (cancel != NULL((void*)0)) - 1;
7532}
7533
7534/** Cancel the request.
7535 *
7536 * Initiate a cancel transaction for client transaction @a orq.
7537 *
7538 * @param orq client transaction to cancel
7539 * @param callback callback function (may be @c NULL)
7540 * @param magic application context pointer
7541 * @param tag, value, ... list of extra arguments
7542 *
7543 * @note The function may return @code (nta_outgoing_t *)-1 @endcode (NONE)
7544 * if callback is NULL.
7545 *
7546 * @TAGS
7547 * NTATAG_CANCEL_2534(), NTATAG_CANCEL_408() and all the tags that are
7548 * accepted by nta_outgoing_tcreate().
7549 *
7550 * If NTATAG_CANCEL_408(1) or NTATAG_CANCEL_2543(1) is given, the stack
7551 * generates a 487 response to the request internally. If
7552 * NTATAG_CANCEL_408(1) is given, no CANCEL request is actually sent.
7553 *
7554 * @note
7555 * nta_outgoing_tcancel() refuses to send a CANCEL request for non-INVITE
7556 * requests.
7557 */
7558nta_outgoing_t *nta_outgoing_tcancel(nta_outgoing_t *orq,
7559 nta_response_f *callback,
7560 nta_outgoing_magic_t *magic,
7561 tag_type_t tag, tag_value_t value, ...)
7562{
7563 msg_t *msg;
7564 int cancel_2543, cancel_408;
7565 ta_list ta;
7566 int delay_sending;
7567
7568 if (orq == NULL((void*)0) || orq == NONE((void *)-1))
7569 return NULL((void*)0);
7570
7571 if (orq->orq_destroyed) {
7572 SU_DEBUG_3(("%s: trying to cancel destroyed request\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 7572, "%s: trying to cancel destroyed request\n", __func__)
) : (void)0)
;
7573 return NULL((void*)0);
7574 }
7575 if (orq->orq_method != sip_method_invite) {
7576 SU_DEBUG_3(("%s: trying to cancel non-INVITE request\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 7576, "%s: trying to cancel non-INVITE request\n", __func__
)) : (void)0)
;
7577 return NULL((void*)0);
7578 }
7579
7580 if (orq->orq_forking)
7581 orq = orq->orq_forking;
7582
7583 if (orq->orq_status >= 200
7584 /* && orq->orq_method != sip_method_invite ... !multicast */) {
7585 SU_DEBUG_3(("%s: trying to cancel completed request\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 7585, "%s: trying to cancel completed request\n", __func__)
) : (void)0)
;
7586 return NULL((void*)0);
7587 }
7588 if (orq->orq_canceled) {
7589 SU_DEBUG_3(("%s: trying to cancel cancelled request\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 7589, "%s: trying to cancel cancelled request\n", __func__)
) : (void)0)
;
7590 return NULL((void*)0);
7591 }
7592 orq->orq_canceled = 1;
7593
7594#if HAVE_SOFIA_SRESOLV1
7595 if (!orq->orq_resolved) {
7596 outgoing_destroy_resolver(orq);
7597 outgoing_reply(orq, SIP_487_REQUEST_CANCELLED487, sip_487_Request_terminated, 1);
7598 return NULL((void*)0); /* XXX - Does anyone care about reply? */
7599 }
7600#endif
7601
7602 cancel_408 = 0; /* Don't really CANCEL, this is timeout. */
7603 cancel_2543 = orq->orq_agent->sa_cancel_2543;
7604 /* CANCEL may be sent only after a provisional response has been received. */
7605 delay_sending = orq->orq_status < 100;
7606
7607 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)
;
7608
7609 tl_gets(ta_args(ta)(ta).tl,
7610 NTATAG_CANCEL_408_REF(cancel_408)ntatag_cancel_408_ref, tag_bool_vr(&(cancel_408)),
7611 NTATAG_CANCEL_2543_REF(cancel_2543)ntatag_cancel_2543_ref, tag_bool_vr(&(cancel_2543)),
7612 TAG_END()(tag_type_t)0, (tag_value_t)0);
7613
7614 if (!cancel_408)
7615 msg = outgoing_ackmsg(orq, SIP_METHOD_CANCELsip_method_cancel, "CANCEL", ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
);
7616 else
7617 msg = NULL((void*)0);
7618
7619 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))
;
7620
7621 if ((cancel_2543 || cancel_408) && !orq->orq_stateless)
7622 outgoing_reply(orq, SIP_487_REQUEST_CANCELLED487, sip_487_Request_terminated, 1);
7623
7624 if (msg) {
7625 nta_outgoing_t *cancel;
7626 if (cancel_2543) /* Follow RFC 2543 semantics for CANCEL */
7627 delay_sending = 0;
7628
7629 cancel = outgoing_create(orq->orq_agent, callback, magic,
7630 NULL((void*)0), orq->orq_tpn, msg,
7631 NTATAG_BRANCH_KEY(orq->orq_branch)ntatag_branch_key, tag_str_v((orq->orq_branch)),
7632 NTATAG_DELAY_SENDING(delay_sending)ntatag_delay_sending, tag_bool_v((delay_sending)),
7633 NTATAG_USER_VIA(1)ntatag_user_via, tag_bool_v((1)),
7634 TAG_END()(tag_type_t)0, (tag_value_t)0);
7635
7636 if (delay_sending)
7637 orq->orq_cancel = cancel;
7638
7639 if (cancel) {
7640 if (!delay_sending)
7641 outgoing_complete(orq);
7642 return cancel;
7643 }
7644
7645 msg_destroy(msg);
7646 }
7647
7648 return NULL((void*)0);
7649}
7650
7651/**Bind callback and application context to a client transaction.
7652 *
7653 * @param orq outgoing client transaction
7654 * @param callback callback function (may be NULL)
7655 * @param magic application context pointer
7656 * (given as argument to @a callback)
7657 *
7658 * @NEW_1_12_9
7659 */
7660int
7661nta_outgoing_bind(nta_outgoing_t *orq,
7662 nta_response_f *callback,
7663 nta_outgoing_magic_t *magic)
7664{
7665 if (orq && !orq->orq_destroyed) {
7666 if (callback == NULL((void*)0))
7667 callback = outgoing_default_cb;
7668 orq->orq_callback = callback;
7669 orq->orq_magic = magic;
7670 return 0;
7671 }
7672 return -1;
7673}
7674
7675/**Get application context bound to a client transaction.
7676 *
7677 * @param orq outgoing client transaction
7678 * @param callback callback function (may be NULL)
7679 *
7680 * Return the application context bound to a client transaction. If the @a
7681 * callback function pointer is given, return application context only if
7682 * the callback matches with the callback bound to the client transaction.
7683 *
7684 * @NEW_1_12_11
7685 */
7686nta_outgoing_magic_t *
7687nta_outgoing_magic(nta_outgoing_t const *orq,
7688 nta_response_f *callback)
7689{
7690 if (orq && (callback == NULL((void*)0) || callback == orq->orq_callback))
7691 return orq->orq_magic;
7692 else
7693 return NULL((void*)0);
7694}
7695
7696
7697/**
7698 * Destroy a request object.
7699 *
7700 * @note
7701 * This function does not actually free the object, but marks it as
7702 * disposable. The object is freed after a timeout.
7703 */
7704void nta_outgoing_destroy(nta_outgoing_t *orq)
7705{
7706 if (orq == NULL((void*)0) || orq == NONE((void *)-1))
7707 return;
7708
7709 if (orq->orq_destroyed) {
7710 SU_DEBUG_1(("%s(%p): %s\n", "nta_outgoing_destroy", (void *)orq,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 7711, "%s(%p): %s\n", "nta_outgoing_destroy", (void *)orq, "already destroyed"
)) : (void)0)
7711 "already destroyed"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 7711, "%s(%p): %s\n", "nta_outgoing_destroy", (void *)orq, "already destroyed"
)) : (void)0)
;
7712 return;
7713 }
7714
7715 outgoing_destroy(orq);
7716}
7717
7718/** Return the request URI */
7719url_t const *nta_outgoing_request_uri(nta_outgoing_t const *orq)
7720{
7721 return orq != NULL((void*)0) && orq != NONE((void *)-1) ? orq->orq_url : NULL((void*)0);
7722}
7723
7724/** Return the URI used to route the request */
7725url_t const *nta_outgoing_route_uri(nta_outgoing_t const *orq)
7726{
7727 return orq != NULL((void*)0) && orq != NONE((void *)-1) ? orq->orq_route : NULL((void*)0);
7728}
7729
7730/** Return method of the client transaction */
7731sip_method_t nta_outgoing_method(nta_outgoing_t const *orq)
7732{
7733 return orq != NULL((void*)0) && orq != NONE((void *)-1) ? orq->orq_method : sip_method_invalid;
7734}
7735
7736/** Return method name of the client transaction */
7737char const *nta_outgoing_method_name(nta_outgoing_t const *orq)
7738{
7739 return orq != NULL((void*)0) && orq != NONE((void *)-1) ? orq->orq_method_name : NULL((void*)0);
7740}
7741
7742/** Get sequence number of a client transaction.
7743 */
7744uint32_t nta_outgoing_cseq(nta_outgoing_t const *orq)
7745{
7746 return orq != NULL((void*)0) && orq != NONE((void *)-1) && orq->orq_cseq
7747 ? orq->orq_cseq->cs_seq : 0;
7748}
7749
7750/**
7751 * Get the status code of a client transaction.
7752 */
7753int nta_outgoing_status(nta_outgoing_t const *orq)
7754{
7755 /* Return 500 Internal server error for invalid handles. */
7756 return orq != NULL((void*)0) && orq != NONE((void *)-1) ? orq->orq_status : 500;
7757}
7758
7759/** Get the RTT delay measured using @Timestamp header. */
7760unsigned nta_outgoing_delay(nta_outgoing_t const *orq)
7761{
7762 return orq != NULL((void*)0) && orq != NONE((void *)-1) ? orq->orq_delay : UINT_MAX(2147483647 *2U +1U);
7763}
7764
7765/** Get the branch parameter. @NEW_1_12_7. */
7766char const *nta_outgoing_branch(nta_outgoing_t const *orq)
7767{
7768 return orq != NULL((void*)0) && orq != NONE((void *)-1) && orq->orq_branch
7769 ? orq->orq_branch + strlen("branch=")
7770 : NULL((void*)0);
7771}
7772
7773/**Get reference to response message.
7774 *
7775 * Retrieve the latest incoming response message to the outgoing
7776 * transaction. Note that the message is not copied, but a new reference to
7777 * it is created instead.
7778 *
7779 * @param orq outgoing transaction handle
7780 *
7781 * @retval
7782 * A pointer to response message is returned, or NULL if no response message
7783 * has been received.
7784 */
7785msg_t *nta_outgoing_getresponse(nta_outgoing_t *orq)
7786{
7787 if (orq != NULL((void*)0) && orq != NONE((void *)-1))
7788 return msg_ref_create(orq->orq_response);
7789 else
7790 return NULL((void*)0);
7791}
7792
7793/**Get request message.
7794 *
7795 * Retrieves the request message sent to the network. Note that the request
7796 * message is @b not copied, but a new reference to it is created.
7797 *
7798 * @retval
7799 * A pointer to the request message is returned, or NULL if an error
7800 * occurred.
7801 */
7802msg_t *nta_outgoing_getrequest(nta_outgoing_t *orq)
7803{
7804 if (orq != NULL((void*)0) && orq != NONE((void *)-1))
7805 return msg_ref_create(orq->orq_request);
7806 else
7807 return NULL((void*)0);
7808}
7809
7810/**Create an outgoing request.
7811 *
7812 * Create an outgoing transaction object and send the request to the
7813 * network. The request is sent to the @a route_url (if non-NULL), default
7814 * proxy (if defined by NTATAG_DEFAULT_PROXY()), or to the address specified
7815 * by @a sip->sip_request->rq_url.
7816 *
7817 * When NTA receives response to the request, it invokes the @a callback
7818 * function.
7819 *
7820 * @param agent nta agent object
7821 * @param callback callback function (may be @c NULL)
7822 * @param magic application context pointer
7823 * @param route_url optional URL used to route transaction requests
7824 * @param msg request message
7825 * @param tpn (optional) transport name
7826 * @param msg request message to
7827 * @param tag, value, ... tagged arguments
7828 *
7829 * @return
7830 * Returns a pointer to newly created outgoing transaction object if
7831 * successful, and NULL otherwise.
7832 *
7833 * @note If NTATAG_STATELESS(1) tag is given and the @a callback is NULL,
7834 * the transaction object is marked as destroyed from the beginning. In that
7835 * case, the function may return @code (nta_outgoing_t *)-1 @endcode if the
7836 * transaction is freed before returning from the function.
7837 *
7838 * @TAG NTATAG_TPORT must point to an existing transport object for
7839 * 'agent' (the passed tport is otherwise ignored).
7840 *
7841 * @sa
7842 * nta_outgoing_tcreate(), nta_outgoing_tcancel(), nta_outgoing_destroy().
7843 */
7844nta_outgoing_t *outgoing_create(nta_agent_t *agent,
7845 nta_response_f *callback,
7846 nta_outgoing_magic_t *magic,
7847 url_string_t const *route_url,
7848 tp_name_t const *tpn,
7849 msg_t *msg,
7850 tag_type_t tag, tag_value_t value, ...)
7851{
7852 nta_outgoing_t *orq;
7853 sip_t *sip;
7854 su_home_t *home;
7855 char const *comp = NONE((void *)-1);
7856 char const *branch = NONE((void *)-1);
7857 char const *ack_branch = NONE((void *)-1);
7858 char const *tp_ident;
7859 int delay_sending = 0, sigcomp_zap = 0;
7860 int pass_100 = agent->sa_pass_100, use_timestamp = agent->sa_timestamp;
7861 enum nta_res_order_e res_order = agent->sa_res_order;
7862 struct sigcomp_compartment *cc = NULL((void*)0);
7863 ta_list ta;
7864 char const *scheme = NULL((void*)0);
7865 char const *port = NULL((void*)0);
7866 int invalid, resolved = 0, stateless = 0, user_via = agent->sa_user_via;
7867 int invite_100rel = agent->sa_invite_100rel;
7868 int explicit_transport = 1;
7869 int call_tls_orq_connect_timeout_is_set = 0;
7870 int call_tls_orq_connect_timeout = 0;
7871
7872 tagi_t const *t;
7873 tport_t *override_tport = NULL((void*)0);
7874
7875 if (!agent->sa_tport_ip6)
7876 res_order = nta_res_ip4_only;
7877 else if (!agent->sa_tport_ip4)
7878 res_order = nta_res_ip6_only;
7879
7880 if (!callback)
7881 callback = outgoing_default_cb;
7882 if (!route_url)
7883 route_url = (url_string_t *)agent->sa_default_proxy;
7884
7885 sip = sip_object(msg);
7886 home = msg_home(msg)((su_home_t*)(msg));
7887
7888#ifdef HAVE_ZLIB_COMPRESS1
7889 sip_content_encoding_Xflate(msg, sip_object(msg), 0, 1);
7890#endif
7891
7892 if (!sip->sip_request || sip_complete_message(msg) < 0) {
7893 SU_DEBUG_3(("nta: outgoing_create: incomplete request\n" VA_NONE))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 7893, "nta: outgoing_create: incomplete request\n" "%s", ""
)) : (void)0)
;
7894 return NULL((void*)0);
7895 }
7896
7897 if (!route_url && !tpn && sip->sip_route &&
7898 sip->sip_route->r_url->url_params &&
7899 url_param(sip->sip_route->r_url->url_params, "lr", NULL((void*)0), 0))
7900 route_url = (url_string_t *)sip->sip_route->r_url;
7901
7902 if (!(orq = su_zalloc(agent->sa_home, sizeof(*orq))))
7903 return NULL((void*)0);
7904
7905 tp_ident = tpn ? tpn->tpn_ident : NULL((void*)0);
7906
7907 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)
;
7908
7909 /* tl_gets() is a bit too slow here... */
7910 for (t = ta_args(ta)(ta).tl; t; t = tl_next(t)) {
7911 tag_type_t tt = t->t_tag;
7912
7913 if (ntatag_stateless == tt)
7914 stateless = t->t_value != 0;
7915 else if (ntatag_delay_sending == tt)
7916 delay_sending = t->t_value != 0;
7917 else if (ntatag_branch_key == tt)
7918 branch = (void *)t->t_value;
7919 else if (ntatag_pass_100 == tt)
7920 pass_100 = t->t_value != 0;
7921 else if (ntatag_use_timestamp == tt)
7922 use_timestamp = t->t_value != 0;
7923 else if (ntatag_user_via == tt)
7924 user_via = t->t_value != 0;
7925 else if (ntatag_ack_branch == tt)
7926 ack_branch = (void *)t->t_value;
7927 else if (ntatag_default_proxy == tt)
7928 route_url = (void *)t->t_value;
7929 else if (tptag_ident == tt)
7930 tp_ident = (void *)t->t_value;
7931 else if (ntatag_comp == tt)
7932 comp = (char const *)t->t_value;
7933 else if (ntatag_sigcomp_close == tt)
7934 sigcomp_zap = t->t_value != 0;
7935 else if (tptag_compartment == tt)
7936 cc = (void *)t->t_value;
7937 else if (ntatag_tport == tt) {
7938 override_tport = (tport_t *)t->t_value;
7939 }
7940 else if (ntatag_rel100 == tt) {
7941 invite_100rel = t->t_value != 0;
7942 }
7943 else if (ntatag_tls_orq_connect_timeout == tt) {
7944 call_tls_orq_connect_timeout_is_set = 1;
7945 call_tls_orq_connect_timeout = t->t_value;
7946 if (call_tls_orq_connect_timeout > NTA_TIME_MAX) call_tls_orq_connect_timeout = NTA_TIME_MAX;
7947 }
7948 }
7949
7950 orq->orq_agent = agent;
7951 orq->orq_callback = callback;
7952 orq->orq_magic = magic;
7953 orq->orq_method = sip->sip_request->rq_method;
7954 orq->orq_method_name = sip->sip_request->rq_method_name;
7955 orq->orq_cseq = sip->sip_cseq;
7956 orq->orq_to = sip->sip_to;
7957 orq->orq_from = sip->sip_from;
7958 orq->orq_call_id = sip->sip_call_id;
7959 orq->orq_tags = tl_afilter(home, tport_tags, ta_args(ta)(ta).tl);
7960 orq->orq_delayed = delay_sending != 0;
7961 orq->orq_pass_100 = pass_100 != 0;
7962 orq->orq_sigcomp_zap = sigcomp_zap;
7963 orq->orq_sigcomp_new = comp != NONE((void *)-1) && comp != NULL((void*)0);
7964 orq->orq_timestamp = use_timestamp;
7965 orq->orq_delay = UINT_MAX(2147483647 *2U +1U);
7966 orq->orq_stateless = stateless != 0;
7967 orq->orq_user_via = user_via != 0 && sip->sip_via;
7968 orq->orq_100rel = invite_100rel;
7969 orq->orq_uas = !stateless && agent->sa_is_a_uas;
7970 orq->orq_call_tls_connect_timeout_is_set = call_tls_orq_connect_timeout_is_set;
7971 orq->orq_call_tls_connect_timeout = (call_tls_orq_connect_timeout > 0) ? call_tls_orq_connect_timeout : 0;
7972
7973 if (cc)
7974 orq->orq_cc = nta_compartment_ref(cc);
7975
7976 /* Add supported features */
7977 outgoing_features(agent, orq, msg, sip, ta_args(ta)(ta).tl);
7978
7979 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))
;
7980
7981 /* select the tport to use for the outgoing message */
7982 if (override_tport) {
7983 /* note: no ref taken to the tport as its only used once here */
7984 if (tport_is_secondary(override_tport)) {
7985 tpn = tport_name(override_tport);
7986 orq->orq_user_tport = 1;
7987 }
7988 }
7989
7990 if (tpn) {
7991 /* CANCEL or ACK to [3456]XX */
7992 invalid = tport_name_dup(home, orq->orq_tpn, tpn);
7993#if 0 //HAVE_SOFIA_SRESOLV
7994 /* We send ACK or CANCEL only if original request was really sent */
7995 assert(tport_name_is_resolved(orq->orq_tpn))((void) sizeof ((tport_name_is_resolved(orq->orq_tpn)) ? 1
: 0), __extension__ ({ if (tport_name_is_resolved(orq->orq_tpn
)) ; else __assert_fail ("tport_name_is_resolved(orq->orq_tpn)"
, "nta.c", 7995, __extension__ __PRETTY_FUNCTION__); }))
;
7996#endif
7997 resolved = tport_name_is_resolved(orq->orq_tpn);
7998 orq->orq_url = url_hdup(home, sip->sip_request->rq_url);
7999 }
8000 else if (route_url && !orq->orq_user_tport) {
8001 invalid = nta_tpn_by_url(home, orq->orq_tpn, &scheme, &port, route_url);
8002 if (invalid >= 0) {
8003 explicit_transport = invalid > 0;
8004 if (override_tport) { /* Use transport protocol name from transport */
8005 if (strcmp(orq->orq_tpn->tpn_proto, "*") == 0)
8006 orq->orq_tpn->tpn_proto = tport_name(override_tport)->tpn_proto;
8007 }
8008
8009 resolved = tport_name_is_resolved(orq->orq_tpn);
8010 orq->orq_url = url_hdup(home, sip->sip_request->rq_url);
8011 if (route_url != (url_string_t *)agent->sa_default_proxy)
8012 orq->orq_route = url_hdup(home, route_url->us_url);
8013 }
8014 }
8015 else {
8016 invalid = nta_tpn_by_url(home, orq->orq_tpn, &scheme, &port,
8017 (url_string_t *)sip->sip_request->rq_url);
8018 if (invalid >= 0) {
8019 explicit_transport = invalid > 0;
8020 resolved = tport_name_is_resolved(orq->orq_tpn);
8021 sip_fragment_clear(sip->sip_request->rq_common)((sip->sip_request->rq_common)->h_data = ((void*)0),
(sip->sip_request->rq_common)->h_len = 0)
;
8022 }
8023 orq->orq_url = url_hdup(home, sip->sip_request->rq_url);
8024 }
8025
8026 if (!override_tport)
8027 orq->orq_tpn->tpn_ident = tp_ident;
8028 else
8029 orq->orq_tpn->tpn_ident = tport_name(override_tport)->tpn_ident;
8030
8031 if (comp == NULL((void*)0))
8032 orq->orq_tpn->tpn_comp = comp;
8033
8034 if (orq->orq_user_via && su_strmatch(orq->orq_tpn->tpn_proto, "*")) {
8035 char const *proto = sip_via_transport(sip->sip_via);
8036 if (proto) orq->orq_tpn->tpn_proto = proto;
8037 }
8038
8039 if (branch && branch != NONE((void *)-1)) {
8040 if (su_casenmatch(branch, "branch=", 7))
8041 branch = su_strdup(home, branch);
8042 else
8043 branch = su_sprintf(home, "branch=%s", branch);
8044 }
8045 else if (orq->orq_user_via && sip->sip_via->v_branch && orq->orq_method != sip_method_invite )
8046 branch = su_sprintf(home, "branch=%s", sip->sip_via->v_branch);
8047 else if (stateless)
8048 branch = stateless_branch(agent, msg, sip, orq->orq_tpn);
8049 else
8050 branch = stateful_branch(home, agent);
8051
8052 orq->orq_branch = branch;
8053 orq->orq_via_branch = branch;
8054
8055 if (orq->orq_method == sip_method_ack) {
8056 /* Find the original INVITE which we are ACKing */
8057 if (ack_branch != NULL((void*)0) && ack_branch != NONE((void *)-1)) {
8058 if (su_casenmatch(ack_branch, "branch=", 7))
8059 orq->orq_branch = su_strdup(home, ack_branch);
8060 else
8061 orq->orq_branch = su_sprintf(home, "branch=%s", ack_branch);
8062 }
8063 else if (orq->orq_uas) {
8064 /*
8065 * ACK redirects further 2XX messages to it.
8066 *
8067 * Use orq_branch from INVITE, but put a different branch in topmost Via.
8068 */
8069 nta_outgoing_t *invite = outgoing_find(agent, msg, sip, NULL((void*)0));
8070
8071 if (invite) {
8072 sip_t const *inv = sip_object(invite->orq_request);
8073
8074 orq->orq_branch = su_strdup(home, invite->orq_branch);
8075
8076 /* @RFC3261 section 13.2.2.4 -
8077 * The ACK MUST contain the same credentials as the INVITE.
8078 */
8079 if (!sip->sip_proxy_authorization && !sip->sip_authorization) {
8080 if (inv->sip_proxy_authorization)
8081 sip_add_dup(msg, sip, (void *)inv->sip_proxy_authorization);
8082 if (inv->sip_authorization)
8083 sip_add_dup(msg, sip, (void *)inv->sip_authorization);
8084 }
8085 }
8086 else {
8087 SU_DEBUG_1(("outgoing_create: ACK without INVITE\n" VA_NONE))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 8087, "outgoing_create: ACK without INVITE\n" "%s", "")) : (
void)0)
;
8088 assert(!"INVITE found for ACK")((void) sizeof ((!"INVITE found for ACK") ? 1 : 0), __extension__
({ if (!"INVITE found for ACK") ; else __assert_fail ("!\"INVITE found for ACK\""
, "nta.c", 8088, __extension__ __PRETTY_FUNCTION__); }))
;
8089 }
8090 }
8091 }
8092
8093#if HAVE_SOFIA_SRESOLV1
8094 if (!resolved)
8095 orq->orq_tpn->tpn_port = port;
8096 orq->orq_resolved = resolved;
8097#else
8098 orq->orq_resolved = resolved = 1;
8099#endif
8100 orq->orq_sips = su_casematch(scheme, "sips");
8101
8102 if (invalid < 0 || !orq->orq_branch || msg_serialize(msg, (void *)sip) < 0) {
8103 SU_DEBUG_3(("nta outgoing create: %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 8105, "nta outgoing create: %s\n", invalid < 0 ? "invalid URI"
: !orq->orq_branch ? "no branch" : "invalid message")) : (
void)0)
8104 invalid < 0 ? "invalid URI" :(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 8105, "nta outgoing create: %s\n", invalid < 0 ? "invalid URI"
: !orq->orq_branch ? "no branch" : "invalid message")) : (
void)0)
8105 !orq->orq_branch ? "no branch" : "invalid message"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 8105, "nta outgoing create: %s\n", invalid < 0 ? "invalid URI"
: !orq->orq_branch ? "no branch" : "invalid message")) : (
void)0)
;
8106 outgoing_free(orq);
8107 return NULL((void*)0);
8108 }
8109
8110 /* Now we are committed in sending the transaction */
8111 orq->orq_request = msg;
8112 agent->sa_stats->as_client_tr++;
8113 orq->orq_hash = NTA_HASH(sip->sip_call_id, sip->sip_cseq->cs_seq)((sip->sip_call_id)->i_hash + 26839U * (uint32_t)(sip->
sip_cseq->cs_seq))
;
8114
8115 if (orq->orq_user_tport)
8116 outgoing_send_via(orq, override_tport);
8117 else if (resolved)
8118 outgoing_prepare_send(orq);
8119#if HAVE_SOFIA_SRESOLV1
8120 else
8121 outgoing_resolve(orq, explicit_transport, res_order);
8122#endif
8123
8124 if (stateless &&
8125 orq->orq_status >= 200 &&
8126 callback == outgoing_default_cb) {
8127 void *retval;
8128
8129 if (orq->orq_status < 300)
8130 retval = (void *)-1; /* NONE */
8131 else
8132 retval = NULL((void*)0), orq->orq_request = NULL((void*)0);
8133
8134 outgoing_free(orq);
8135
8136 return retval;
8137 }
8138
8139 assert(orq->orq_queue)((void) sizeof ((orq->orq_queue) ? 1 : 0), __extension__ (
{ if (orq->orq_queue) ; else __assert_fail ("orq->orq_queue"
, "nta.c", 8139, __extension__ __PRETTY_FUNCTION__); }))
;
8140
8141 outgoing_insert(agent, orq);
8142
8143 return orq;
8144}
8145
8146/** Prepare sending a request */
8147static void
8148outgoing_prepare_send(nta_outgoing_t *orq)
8149{
8150 nta_agent_t *sa = orq->orq_agent;
8151 tport_t *tp;
8152 tp_name_t *tpn = orq->orq_tpn;
8153
8154 /* Select transport by scheme */
8155 if (orq->orq_sips && strcmp(tpn->tpn_proto, "*") == 0)
8156 tpn->tpn_proto = "tls";
8157
8158 if (!tpn->tpn_port)
8159 tpn->tpn_port = "";
8160
8161 tp = tport_by_name(sa->sa_tports, tpn);
8162
8163 if (tpn->tpn_port[0] == '\0') {
8164 if (orq->orq_sips || tport_has_tls(tp))
8165 tpn->tpn_port = "5061";
8166 else
8167 tpn->tpn_port = "5060";
8168 }
8169
8170 if (tp) {
8171 outgoing_send_via(orq, tp);
8172 }
8173 else if (orq->orq_sips) {
8174 SU_DEBUG_3(("nta outgoing create: no secure transport\n" VA_NONE))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 8174, "nta outgoing create: no secure transport\n" "%s", ""
)) : (void)0)
;
8175 outgoing_reply(orq, SIP_416_UNSUPPORTED_URI416, sip_416_Unsupported_uri, 1);
8176 }
8177 else {
8178 SU_DEBUG_3(("nta outgoing create: no transport protocol\n" VA_NONE))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 8178, "nta outgoing create: no transport protocol\n" "%s", ""
)) : (void)0)
;
8179 outgoing_reply(orq, 503, "No transport", 1);
8180 }
8181}
8182
8183/** Send request using given transport */
8184static void
8185outgoing_send_via(nta_outgoing_t *orq, tport_t *tp)
8186{
8187 tport_t *old_tp = orq->orq_tport;
8188
8189 orq->orq_tport = tport_ref(tp);
8190
8191 if (orq->orq_pending && tp != old_tp) {
8192 tport_release(old_tp, orq->orq_pending,
8193 orq->orq_request, NULL((void*)0), orq, 0);
8194 orq->orq_pending = 0;
8195 }
8196
8197 if (old_tp) tport_unref(old_tp);
8198
8199 if (outgoing_insert_via(orq, agent_tport_via(tp)) < 0) {
8200 SU_DEBUG_3(("nta outgoing create: cannot insert Via line\n" VA_NONE))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 8200, "nta outgoing create: cannot insert Via line\n" "%s",
"")) : (void)0)
;
8201 outgoing_reply(orq, 503, "Cannot insert Via", 1);
8202 return;
8203 }
8204
8205#if HAVE_SOFIA_SMIME0
8206 {
8207 sm_object_t *smime = sa->sa_smime;
8208 sip_t *sip = sip_object(orq->orq_request);
8209
8210 if (sa->sa_smime &&
8211 (sip->sip_request->rq_method == sip_method_invite ||
8212 sip->sip_request->rq_method == sip_method_message)) {
8213 msg_prepare(orq->orq_request);
8214 if (sm_encode_message(smime, msg, sip, SM_ID_NULL) < 0) {
8215 outgoing_tport_error(sa, orq, NULL((void*)0),
8216 orq->orq_request, su_errno());
8217 return;
8218 }
8219 }
8220 }
8221#endif
8222
8223 orq->orq_prepared = 1;
8224
8225 if (orq->orq_delayed) {
8226 SU_DEBUG_5(("nta: delayed sending %s (%u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8227, "nta: delayed sending %s (%u)\n", orq->orq_method_name
, orq->orq_cseq->cs_seq)) : (void)0)
8227 orq->orq_method_name, orq->orq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8227, "nta: delayed sending %s (%u)\n", orq->orq_method_name
, orq->orq_cseq->cs_seq)) : (void)0)
;
8228 outgoing_queue(orq->orq_agent->sa_out.delayed, orq);
8229 return;
8230 }
8231
8232 outgoing_send(orq, 0);
8233}
8234
8235
8236/** Send a request */
8237static void
8238outgoing_send(nta_outgoing_t *orq, int retransmit)
8239{
8240 int err;
8241 tp_name_t const *tpn = orq->orq_tpn;
8242 msg_t *msg = orq->orq_request;
8243 nta_agent_t *agent = orq->orq_agent;
8244 tport_t *tp;
8245 int once = 0;
8246 su_time_t now = su_now();
8247 tag_type_t tag = tag_skip;
8248 tag_value_t value = 0;
8249 struct sigcomp_compartment *cc; cc = NULL((void*)0);
8250
8251 /* tport can be NULL if we are just switching network */
8252 if (orq->orq_tport == NULL((void*)0)) {
8253 outgoing_tport_error(agent, orq, NULL((void*)0), orq->orq_request, ENETRESET102);
8254 return;
8255 }
8256
8257 if (orq->orq_user_tport && !tport_is_clear_to_send(orq->orq_tport)) {
8258 outgoing_tport_error(agent, orq, NULL((void*)0), orq->orq_request, EPIPE32);
8259 return;
8260 }
8261
8262 if (!retransmit)
8263 orq->orq_sent = now;
8264
8265 if (orq->orq_timestamp) {
8266 sip_t *sip = sip_object(msg);
8267 sip_timestamp_t *ts =
8268 sip_timestamp_format(msg_home(msg)((su_home_t*)(msg)), "%lu.%06lu",
8269 now.tv_sec, now.tv_usec);
8270
8271 if (ts) {
8272 if (sip->sip_timestamp)
8273 msg_header_remove(msg, (msg_pub_t *)sip, (msg_header_t *)sip->sip_timestamp);
8274 msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)ts);
8275 }
8276 }
8277
8278 for (;;) {
8279 if (tpn->tpn_comp == NULL((void*)0)) {
8280 /* xyzzy */
8281 }
8282 else if (orq->orq_cc) {
8283 cc = orq->orq_cc, orq->orq_cc = NULL((void*)0);
8284 }
8285 else {
8286 cc = agent_compression_compartment(agent, orq->orq_tport, tpn,
8287 orq->orq_sigcomp_new);
8288 }
8289
8290 if (orq->orq_try_udp_instead)
8291 tag = tptag_mtu, value = 65535;
8292
8293 if (orq->orq_pending) {
8294 tport_release(orq->orq_tport, orq->orq_pending,
8295 orq->orq_request, NULL((void*)0), orq, 0);
8296 orq->orq_pending = 0;
8297 }
8298
8299 tp = tport_tsend(orq->orq_tport, msg, tpn,
8300 tag, value,
8301 IF_SIGCOMP_TPTAG_COMPARTMENT(cc)!(cc && cc != ((void *)-1)) ? tag_skip : tptag_compartment
, tag_ptr_v((cc)),
8302 TAG_NEXT(orq->orq_tags)tag_next, (tag_value_t)(orq->orq_tags));
8303 if (tp)
8304 break;
8305
8306 err = msg_errno(orq->orq_request);
8307
8308 if (cc)
8309 nta_compartment_decref(&cc);
8310
8311 if (orq->orq_user_tport)
8312 /* No retries */;
8313 /* RFC3261, 18.1.1 */
8314 else if (err == EMSGSIZE90 && !orq->orq_try_tcp_instead) {
8315 if (su_casematch(tpn->tpn_proto, "udp") ||
8316 su_casematch(tpn->tpn_proto, "*")) {
8317 outgoing_try_tcp_instead(orq);
8318 continue;
8319 }
8320 }
8321 else if (err == ECONNREFUSED111 && orq->orq_try_tcp_instead) {
8322 if (su_casematch(tpn->tpn_proto, "tcp") && msg_size(msg) <= 65535) {
8323 outgoing_try_udp_instead(orq, 0);
8324 continue;
8325 }
8326 }
8327 else if (err == EPIPE32) {
8328 /* Connection was closed */
8329 if (!once++) {
8330 orq->orq_retries++;
8331 continue;
8332 }
8333 }
8334
8335 outgoing_tport_error(agent, orq, NULL((void*)0), orq->orq_request, err);
8336
8337 return;
8338 }
8339
8340 agent->sa_stats->as_sent_msg++;
8341 agent->sa_stats->as_sent_request++;
8342 if (retransmit)
8343 agent->sa_stats->as_retry_request++;
8344
8345 SU_DEBUG_5(("nta: %ssent %s (%u) to " TPN_FORMAT "\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8348, "nta: %ssent %s (%u) to " "%s/%s:%s%s%s%s%s" "\n", retransmit
? "re" : "", orq->orq_method_name, orq->orq_cseq->cs_seq
, (tpn)->tpn_proto, (tpn)->tpn_host, (tpn)->tpn_port
, (tpn)->tpn_comp ? ";comp=" : "", (tpn)->tpn_comp ? (tpn
)->tpn_comp : "", (tpn)->tpn_ident ? "/" : "", (tpn)->
tpn_ident ? (tpn)->tpn_ident : "")) : (void)0)
8346 retransmit ? "re" : "",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8348, "nta: %ssent %s (%u) to " "%s/%s:%s%s%s%s%s" "\n", retransmit
? "re" : "", orq->orq_method_name, orq->orq_cseq->cs_seq
, (tpn)->tpn_proto, (tpn)->tpn_host, (tpn)->tpn_port
, (tpn)->tpn_comp ? ";comp=" : "", (tpn)->tpn_comp ? (tpn
)->tpn_comp : "", (tpn)->tpn_ident ? "/" : "", (tpn)->
tpn_ident ? (tpn)->tpn_ident : "")) : (void)0)
8347 orq->orq_method_name, orq->orq_cseq->cs_seq,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8348, "nta: %ssent %s (%u) to " "%s/%s:%s%s%s%s%s" "\n", retransmit
? "re" : "", orq->orq_method_name, orq->orq_cseq->cs_seq
, (tpn)->tpn_proto, (tpn)->tpn_host, (tpn)->tpn_port
, (tpn)->tpn_comp ? ";comp=" : "", (tpn)->tpn_comp ? (tpn
)->tpn_comp : "", (tpn)->tpn_ident ? "/" : "", (tpn)->
tpn_ident ? (tpn)->tpn_ident : "")) : (void)0)
8348 TPN_ARGS(tpn)))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8348, "nta: %ssent %s (%u) to " "%s/%s:%s%s%s%s%s" "\n", retransmit
? "re" : "", orq->orq_method_name, orq->orq_cseq->cs_seq
, (tpn)->tpn_proto, (tpn)->tpn_host, (tpn)->tpn_port
, (tpn)->tpn_comp ? ";comp=" : "", (tpn)->tpn_comp ? (tpn
)->tpn_comp : "", (tpn)->tpn_ident ? "/" : "", (tpn)->
tpn_ident ? (tpn)->tpn_ident : "")) : (void)0)
;
8349
8350 if (cc) {
8351 if (orq->orq_cc)
8352 nta_compartment_decref(&orq->orq_cc);
8353 }
8354
8355 if (orq->orq_pending) {
8356 assert(orq->orq_tport)((void) sizeof ((orq->orq_tport) ? 1 : 0), __extension__ (
{ if (orq->orq_tport) ; else __assert_fail ("orq->orq_tport"
, "nta.c", 8356, __extension__ __PRETTY_FUNCTION__); }))
;
8357 tport_release(orq->orq_tport, orq->orq_pending,
8358 orq->orq_request, NULL((void*)0), orq, 0);
8359 orq->orq_pending = 0;
8360 }
8361
8362 if (orq->orq_stateless) {
8363 outgoing_reply(orq, 202, NULL((void*)0), 202);
8364 return;
8365 }
8366
8367 if (orq->orq_method != sip_method_ack) {
8368 orq->orq_pending = tport_pend(tp, orq->orq_request,
8369 outgoing_tport_error, orq);
8370 if (orq->orq_pending < 0)
8371 orq->orq_pending = 0;
8372 }
8373
8374 if (tp != orq->orq_tport) {
8375 tport_decref(&orq->orq_tport);
8376 orq->orq_tport = tport_ref(tp);
8377 }
8378
8379 orq->orq_reliable = tport_is_reliable(tp);
8380
8381 if (retransmit)
8382 return;
8383
8384 outgoing_trying(orq); /* Timer B / F */
8385
8386 if (orq->orq_method == sip_method_ack)
8387 ;
8388 else if (!orq->orq_reliable) {
8389 /* race condition on initial t1 timer timeout, set minimum initial timeout to 1000ms */
8390 unsigned t1_timer = agent->sa_t1;
8391 if (t1_timer < 1000) t1_timer = 1000;
8392 outgoing_set_timer(orq, t1_timer); /* Timer A/E */
8393 } else if (orq->orq_try_tcp_instead && !tport_is_connected(tp)) {
8394 outgoing_set_timer(orq, agent->sa_t4); /* Timer N3 */
8395 } else if (su_casenmatch(orq->orq_tpn->tpn_proto, "tls", 3) && !tport_is_connected(tp)) {
8396 unsigned tls_reconect_interval = (orq->orq_call_tls_connect_timeout_is_set) ?
8397 orq->orq_call_tls_connect_timeout : agent->sa_tls_orq_connect_timeout;
8398 if (tls_reconect_interval) {
8399 if (tls_reconect_interval < 1000) tls_reconect_interval = 1000;
8400 outgoing_set_timer(orq, tls_reconect_interval); /* Timer N3 set to (min 1000 ms if set) */
8401 }
8402 }
8403}
8404
8405static void
8406outgoing_try_tcp_instead(nta_outgoing_t *orq)
8407{
8408 tport_t *tp;
8409 tp_name_t tpn[1];
8410
8411 assert(orq->orq_pending == 0)((void) sizeof ((orq->orq_pending == 0) ? 1 : 0), __extension__
({ if (orq->orq_pending == 0) ; else __assert_fail ("orq->orq_pending == 0"
, "nta.c", 8411, __extension__ __PRETTY_FUNCTION__); }))
;
8412
8413 *tpn = *orq->orq_tpn;
8414 tpn->tpn_proto = "tcp";
8415 orq->orq_try_tcp_instead = 1;
8416
8417 tp = tport_by_name(orq->orq_agent->sa_tports, tpn);
8418 if (tp && tp != orq->orq_tport) {
8419 sip_t *sip = sip_object(orq->orq_request);
8420 sip_fragment_clear(sip->sip_via->v_common)((sip->sip_via->v_common)->h_data = ((void*)0), (sip
->sip_via->v_common)->h_len = 0)
;
8421 sip->sip_via->v_protocol = sip_transport_tcp;
8422
8423 SU_DEBUG_5(("nta: %s (%u) too large for UDP, trying TCP\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8424, "nta: %s (%u) too large for UDP, trying TCP\n", orq->
orq_method_name, orq->orq_cseq->cs_seq)) : (void)0)
8424 orq->orq_method_name, orq->orq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8424, "nta: %s (%u) too large for UDP, trying TCP\n", orq->
orq_method_name, orq->orq_cseq->cs_seq)) : (void)0)
;
8425
8426 orq->orq_tpn->tpn_proto = "tcp";
8427 tport_decref(&orq->orq_tport);
8428 orq->orq_tport = tport_ref(tp);
8429
8430 return;
8431 }
8432
8433 /* No TCP - try again with UDP without SIP MTU limit */
8434 tpn->tpn_proto = "udp";
8435 orq->orq_try_udp_instead = 1;
8436
8437 tp = tport_by_name(orq->orq_agent->sa_tports, tpn);
8438 if (tp && tp != orq->orq_tport) {
8439 SU_DEBUG_5(("nta: %s (%u) exceed normal UDP size limit\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8440, "nta: %s (%u) exceed normal UDP size limit\n", orq->
orq_method_name, orq->orq_cseq->cs_seq)) : (void)0)
8440 orq->orq_method_name, orq->orq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8440, "nta: %s (%u) exceed normal UDP size limit\n", orq->
orq_method_name, orq->orq_cseq->cs_seq)) : (void)0)
;
8441
8442 tport_decref(&orq->orq_tport);
8443 orq->orq_tport = tport_ref(tp);
8444 }
8445}
8446
8447static void
8448outgoing_try_udp_instead(nta_outgoing_t *orq, int timeout)
8449{
8450 tport_t *tp;
8451 tp_name_t tpn[1];
8452
8453 if (orq->orq_pending) {
8454 tport_release(orq->orq_tport, orq->orq_pending,
8455 orq->orq_request, NULL((void*)0), orq, 0);
8456 orq->orq_pending = 0;
8457 }
8458
8459 *tpn = *orq->orq_tpn;
8460 tpn->tpn_proto = "udp";
8461 orq->orq_try_udp_instead = 1;
8462
8463 tp = tport_by_name(orq->orq_agent->sa_tports, tpn);
8464 if (tp && tp != orq->orq_tport) {
8465 sip_t *sip = sip_object(orq->orq_request);
8466
8467 sip_fragment_clear(sip->sip_via->v_common)((sip->sip_via->v_common)->h_data = ((void*)0), (sip
->sip_via->v_common)->h_len = 0)
;
8468 sip->sip_via->v_protocol = sip_transport_udp;
8469
8470 SU_DEBUG_5(("nta: %s (%u) TCP %s, trying UDP\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8472, "nta: %s (%u) TCP %s, trying UDP\n", orq->orq_method_name
, orq->orq_cseq->cs_seq, timeout ? "times out" : "refused"
)) : (void)0)
8471 orq->orq_method_name, orq->orq_cseq->cs_seq,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8472, "nta: %s (%u) TCP %s, trying UDP\n", orq->orq_method_name
, orq->orq_cseq->cs_seq, timeout ? "times out" : "refused"
)) : (void)0)
8472 timeout ? "times out" : "refused"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8472, "nta: %s (%u) TCP %s, trying UDP\n", orq->orq_method_name
, orq->orq_cseq->cs_seq, timeout ? "times out" : "refused"
)) : (void)0)
;
8473
8474 orq->orq_tpn->tpn_proto = "udp";
8475 tport_decref(&orq->orq_tport);
8476 orq->orq_tport = tport_ref(tp);
8477 }
8478}
8479
8480
8481/** @internal Report transport errors. */
8482void
8483outgoing_tport_error(nta_agent_t *agent, nta_outgoing_t *orq,
8484 tport_t *tp, msg_t *msg, int error)
8485{
8486 tp_name_t const *tpn = tp ? tport_name(tp) : orq->orq_tpn;
8487
8488 if (orq->orq_pending) {
8489 assert(orq->orq_tport)((void) sizeof ((orq->orq_tport) ? 1 : 0), __extension__ (
{ if (orq->orq_tport) ; else __assert_fail ("orq->orq_tport"
, "nta.c", 8489, __extension__ __PRETTY_FUNCTION__); }))
;
8490 tport_release(orq->orq_tport, orq->orq_pending, orq->orq_request,
8491 NULL((void*)0), orq, 0);
8492 orq->orq_pending = 0;
8493 }
8494
8495 if (error == EPIPE32 && orq->orq_retries++ == 0) {
8496 /* XXX - we should retry only if the transport is not newly created */
8497 outgoing_print_tport_error(orq, 5, "retrying once after ",
8498 tpn, msg, error);
8499 outgoing_send(orq, 1);
8500 return;
8501 }
8502 else if (error == ECONNREFUSED111 && orq->orq_try_tcp_instead) {
8503 /* RFC3261, 18.1.1 */
8504 if (su_casematch(tpn->tpn_proto, "tcp") && msg_size(msg) <= 65535) {
8505 outgoing_print_tport_error(orq, 5, "retrying with UDP after ",
8506 tpn, msg, error);
8507 outgoing_try_udp_instead(orq, 0);
8508 outgoing_remove(orq); /* Reset state - this is no resend! */
8509 outgoing_send(orq, 0); /* Send */
8510 return;
8511 }
8512 }
8513 else if (error == 0) {
8514 /*
8515 * Server closed connection. RFC3261:
8516 * "there is no coupling between TCP connection state and SIP
8517 * processing."
8518 */
8519 return;
8520 }
8521
8522 if (outgoing_other_destinations(orq)) {
8523 outgoing_print_tport_error(orq, 5, "trying alternative server after ",
8524 tpn, msg, error);
8525 outgoing_try_another(orq);
8526 return;
8527 }
8528
8529 outgoing_print_tport_error(orq, 3, "", tpn, msg, error);
8530
8531 outgoing_reply(orq, SIP_503_SERVICE_UNAVAILABLE503, sip_503_Service_unavailable, 0);
8532}
8533
8534static
8535void
8536outgoing_print_tport_error(nta_outgoing_t *orq, int level, char *todo,
8537 tp_name_t const *tpn, msg_t *msg, int error)
8538{
8539 su_sockaddr_t const *su = msg_addr(msg);
8540 char addr[SU_ADDRSIZE(48)];
8541
8542 su_llog(nta_log, level,_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8548
, "nta: %s (%u): %s%s (%u) with %s/[%s]:%u\n", orq->orq_method_name
, orq->orq_cseq->cs_seq, todo, su_strerror(error), error
, tpn->tpn_proto, inet_ntop(su->su_sa.sa_family, ((su)->
su_sa.sa_family == 2 ? (void *)&(su)->su_sin.sin_addr :
((su)->su_sa.sa_family == 10 ? (void *)&(su)->su_sin6
.sin6_addr : (void *)&(su)->su_sa.sa_data)), addr, sizeof
(addr)), htons(su->su_sin.sin_port))
8543 "nta: %s (%u): %s%s (%u) with %s/[%s]:%u\n",_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8548
, "nta: %s (%u): %s%s (%u) with %s/[%s]:%u\n", orq->orq_method_name
, orq->orq_cseq->cs_seq, todo, su_strerror(error), error
, tpn->tpn_proto, inet_ntop(su->su_sa.sa_family, ((su)->
su_sa.sa_family == 2 ? (void *)&(su)->su_sin.sin_addr :
((su)->su_sa.sa_family == 10 ? (void *)&(su)->su_sin6
.sin6_addr : (void *)&(su)->su_sa.sa_data)), addr, sizeof
(addr)), htons(su->su_sin.sin_port))
8544 orq->orq_method_name, orq->orq_cseq->cs_seq,_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8548
, "nta: %s (%u): %s%s (%u) with %s/[%s]:%u\n", orq->orq_method_name
, orq->orq_cseq->cs_seq, todo, su_strerror(error), error
, tpn->tpn_proto, inet_ntop(su->su_sa.sa_family, ((su)->
su_sa.sa_family == 2 ? (void *)&(su)->su_sin.sin_addr :
((su)->su_sa.sa_family == 10 ? (void *)&(su)->su_sin6
.sin6_addr : (void *)&(su)->su_sa.sa_data)), addr, sizeof
(addr)), htons(su->su_sin.sin_port))
8545 todo, su_strerror(error), error,_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8548
, "nta: %s (%u): %s%s (%u) with %s/[%s]:%u\n", orq->orq_method_name
, orq->orq_cseq->cs_seq, todo, su_strerror(error), error
, tpn->tpn_proto, inet_ntop(su->su_sa.sa_family, ((su)->
su_sa.sa_family == 2 ? (void *)&(su)->su_sin.sin_addr :
((su)->su_sa.sa_family == 10 ? (void *)&(su)->su_sin6
.sin6_addr : (void *)&(su)->su_sa.sa_data)), addr, sizeof
(addr)), htons(su->su_sin.sin_port))
8546 tpn->tpn_proto,_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8548
, "nta: %s (%u): %s%s (%u) with %s/[%s]:%u\n", orq->orq_method_name
, orq->orq_cseq->cs_seq, todo, su_strerror(error), error
, tpn->tpn_proto, inet_ntop(su->su_sa.sa_family, ((su)->
su_sa.sa_family == 2 ? (void *)&(su)->su_sin.sin_addr :
((su)->su_sa.sa_family == 10 ? (void *)&(su)->su_sin6
.sin6_addr : (void *)&(su)->su_sa.sa_data)), addr, sizeof
(addr)), htons(su->su_sin.sin_port))
8547 su_inet_ntop(su->su_family, SU_ADDR(su), addr, sizeof(addr)),_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8548
, "nta: %s (%u): %s%s (%u) with %s/[%s]:%u\n", orq->orq_method_name
, orq->orq_cseq->cs_seq, todo, su_strerror(error), error
, tpn->tpn_proto, inet_ntop(su->su_sa.sa_family, ((su)->
su_sa.sa_family == 2 ? (void *)&(su)->su_sin.sin_addr :
((su)->su_sa.sa_family == 10 ? (void *)&(su)->su_sin6
.sin6_addr : (void *)&(su)->su_sa.sa_data)), addr, sizeof
(addr)), htons(su->su_sin.sin_port))
8548 htons(su->su_port))_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8548
, "nta: %s (%u): %s%s (%u) with %s/[%s]:%u\n", orq->orq_method_name
, orq->orq_cseq->cs_seq, todo, su_strerror(error), error
, tpn->tpn_proto, inet_ntop(su->su_sa.sa_family, ((su)->
su_sa.sa_family == 2 ? (void *)&(su)->su_sin.sin_addr :
((su)->su_sa.sa_family == 10 ? (void *)&(su)->su_sin6
.sin6_addr : (void *)&(su)->su_sa.sa_data)), addr, sizeof
(addr)), htons(su->su_sin.sin_port))
;
8549}
8550
8551/**@internal
8552 * Add features supported.
8553 */
8554static
8555int outgoing_features(nta_agent_t *agent, nta_outgoing_t *orq,
8556 msg_t *msg, sip_t *sip,
8557 tagi_t *tags)
8558{
8559 char const *supported[8];
8560 int i;
8561
8562 if (orq->orq_method != sip_method_invite) /* fast path for now */
8563 return 0;
8564
8565 supported[i = 0] = NULL((void*)0);
8566
8567 if (orq->orq_method == sip_method_invite) {
8568 int require_100rel = sip_has_feature(sip->sip_require, "100rel");
8569
8570 if (require_100rel) {
8571 orq->orq_must_100rel = 1;
8572 orq->orq_100rel = 1;
8573 }
8574 else if (sip_has_feature(sip->sip_supported, "100rel")) {
8575 orq->orq_100rel = 1;
8576 }
8577 else if (orq->orq_100rel) {
8578 supported[i++] = "100rel";
8579 }
8580 }
8581
8582 if (i) {
8583 supported[i] = NULL((void*)0);
8584
8585 if (sip->sip_supported) {
8586 su_home_t *home = msg_home(msg)((su_home_t*)(msg));
8587 return msg_list_append_items(home, sip->sip_supported, supported);
8588 }
8589 else {
8590 sip_supported_t s[1];
8591 sip_supported_init(s);
8592 s->k_items = supported;
8593 return sip_add_dup(msg, sip, (sip_header_t *)s);
8594 }
8595 }
8596
8597 return 0;
8598}
8599
8600
8601/**@internal
8602 * Insert outgoing request to agent hash table
8603 */
8604static
8605void outgoing_insert(nta_agent_t *agent, nta_outgoing_t *orq)
8606{
8607 if (outgoing_htable_is_full(agent->sa_outgoing))
8608 outgoing_htable_resize(agent->sa_home, agent->sa_outgoing, 0);
8609 outgoing_htable_insert(agent->sa_outgoing, orq);
8610 orq->orq_inserted = 1;
8611}
8612
8613/** @internal
8614 * Initialize a queue for outgoing transactions.
8615 */
8616static void
8617outgoing_queue_init(outgoing_queue_t *queue, unsigned timeout)
8618{
8619 memset(queue, 0, sizeof *queue);
8620 queue->q_tail = &queue->q_head;
8621 queue->q_timeout = timeout;
8622}
8623
8624/** Change the timeout value of a queue */
8625static void
8626outgoing_queue_adjust(nta_agent_t *sa,
8627 outgoing_queue_t *queue,
8628 unsigned timeout)
8629{
8630 nta_outgoing_t *orq;
8631 uint32_t latest;
8632
8633 if (timeout >= queue->q_timeout || !queue->q_head) {
8634 queue->q_timeout = timeout;
8635 return;
8636 }
8637
8638 latest = set_timeout(sa, queue->q_timeout = timeout);
8639
8640 for (orq = queue->q_head; orq; orq = orq->orq_next) {
8641 if (orq->orq_timeout == 0 ||
8642 (int32_t)(orq->orq_timeout - latest) > 0)
8643 orq->orq_timeout = latest;
8644 }
8645}
8646
8647/** @internal
8648 * Test if an outgoing transaction is in a queue.
8649 */
8650su_inlinestatic inline int
8651outgoing_is_queued(nta_outgoing_t const *orq)
8652{
8653 return orq && orq->orq_queue;
8654}
8655
8656/** @internal
8657 * Insert an outgoing transaction into a queue.
8658 *
8659 * Insert a client transaction into a queue and set the corresponding
8660 * timeout at the same time.
8661 */
8662static void
8663outgoing_queue(outgoing_queue_t *queue,
8664 nta_outgoing_t *orq)
8665{
8666 if (orq->orq_queue == queue) {
8667 //assert(queue->q_timeout == 0);
8668 return;
8669 }
8670
8671 assert(!orq->orq_forked)((void) sizeof ((!orq->orq_forked) ? 1 : 0), __extension__
({ if (!orq->orq_forked) ; else __assert_fail ("!orq->orq_forked"
, "nta.c", 8671, __extension__ __PRETTY_FUNCTION__); }))
;
8672
8673 if (outgoing_is_queued(orq))
8674 outgoing_remove(orq);
8675
8676 orq->orq_timeout = set_timeout(orq->orq_agent, queue->q_timeout);
8677
8678 orq->orq_queue = queue;
8679 orq->orq_prev = queue->q_tail;
8680 *queue->q_tail = orq;
8681 queue->q_tail = &orq->orq_next;
8682 queue->q_length++;
8683}
8684
8685/** @internal
8686 * Remove an outgoing transaction from a queue.
8687 */
8688su_inlinestatic inline
8689void outgoing_remove(nta_outgoing_t *orq)
8690{
8691 assert(outgoing_is_queued(orq))((void) sizeof ((outgoing_is_queued(orq)) ? 1 : 0), __extension__
({ if (outgoing_is_queued(orq)) ; else __assert_fail ("outgoing_is_queued(orq)"
, "nta.c", 8691, __extension__ __PRETTY_FUNCTION__); }))
;
8692 assert(orq->orq_queue->q_length > 0)((void) sizeof ((orq->orq_queue->q_length > 0) ? 1 :
0), __extension__ ({ if (orq->orq_queue->q_length >
0) ; else __assert_fail ("orq->orq_queue->q_length > 0"
, "nta.c", 8692, __extension__ __PRETTY_FUNCTION__); }))
;
8693
8694 if ((*orq->orq_prev = orq->orq_next))
8695 orq->orq_next->orq_prev = orq->orq_prev;
8696 else
8697 orq->orq_queue->q_tail = orq->orq_prev;
8698
8699 orq->orq_queue->q_length--;
8700 orq->orq_next = NULL((void*)0);
8701 orq->orq_prev = NULL((void*)0);
8702 orq->orq_queue = NULL((void*)0);
8703 orq->orq_timeout = 0;
8704}
8705
8706/** Set retransmit timer (orq_retry).
8707 *
8708 * Set the retry timer (B/D) on the outgoing request (client transaction).
8709 */
8710su_inlinestatic inline
8711void outgoing_set_timer(nta_outgoing_t *orq, uint32_t interval)
8712{
8713 nta_outgoing_t **rq;
8714
8715 assert(orq)((void) sizeof ((orq) ? 1 : 0), __extension__ ({ if (orq) ; else
__assert_fail ("orq", "nta.c", 8715, __extension__ __PRETTY_FUNCTION__
); }))
;
8716
8717 if (interval == 0) {
8718 outgoing_reset_timer(orq);
8719 return;
8720 }
8721
8722 if (orq->orq_rprev) {
8723 /* Remove transaction from retry dequeue, re-insert it later. */
8724 if ((*orq->orq_rprev = orq->orq_rnext))
8725 orq->orq_rnext->orq_rprev = orq->orq_rprev;
8726 if (orq->orq_agent->sa_out.re_t1 == &orq->orq_rnext)
8727 orq->orq_agent->sa_out.re_t1 = orq->orq_rprev;
8728 }
8729 else {
8730 orq->orq_agent->sa_out.re_length++;
8731 }
8732
8733 orq->orq_retry = set_timeout(orq->orq_agent, orq->orq_interval = interval);
8734
8735 /* Shortcut into queue at SIP T1 */
8736 rq = orq->orq_agent->sa_out.re_t1;
8737
8738 if (!(*rq) || (int32_t)((*rq)->orq_retry - orq->orq_retry) > 0)
8739 rq = &orq->orq_agent->sa_out.re_list;
8740
8741 while (*rq && (int32_t)((*rq)->orq_retry - orq->orq_retry) <= 0)
8742 rq = &(*rq)->orq_rnext;
8743
8744 if ((orq->orq_rnext = *rq))
8745 orq->orq_rnext->orq_rprev = &orq->orq_rnext;
8746 *rq = orq;
8747 orq->orq_rprev = rq;
8748
8749 if (interval == orq->orq_agent->sa_t1)
8750 orq->orq_agent->sa_out.re_t1 = rq;
8751}
8752
8753static
8754void outgoing_reset_timer(nta_outgoing_t *orq)
8755{
8756 if (orq->orq_rprev) {
8757 if ((*orq->orq_rprev = orq->orq_rnext))
8758 orq->orq_rnext->orq_rprev = orq->orq_rprev;
8759 if (orq->orq_agent->sa_out.re_t1 == &orq->orq_rnext)
8760 orq->orq_agent->sa_out.re_t1 = orq->orq_rprev;
8761 orq->orq_agent->sa_out.re_length--;
8762 }
8763
8764 orq->orq_interval = 0, orq->orq_retry = 0;
8765 orq->orq_rnext = NULL((void*)0), orq->orq_rprev = NULL((void*)0);
8766}
8767
8768/** @internal
8769 * Free resources associated with the request.
8770 */
8771static
8772void outgoing_free(nta_outgoing_t *orq)
8773{
8774 SU_DEBUG_9(("nta: outgoing_free(%p)\n", (void *)orq))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__
, 8774, "nta: outgoing_free(%p)\n", (void *)orq)) : (void)0)
;
8775 assert(orq->orq_forks == NULL && orq->orq_forking == NULL)((void) sizeof ((orq->orq_forks == ((void*)0) && orq
->orq_forking == ((void*)0)) ? 1 : 0), __extension__ ({ if
(orq->orq_forks == ((void*)0) && orq->orq_forking
== ((void*)0)) ; else __assert_fail ("orq->orq_forks == NULL && orq->orq_forking == NULL"
, "nta.c", 8775, __extension__ __PRETTY_FUNCTION__); }))
;
8776 outgoing_cut_off(orq);
8777 outgoing_reclaim(orq);
8778}
8779
8780/** Remove outgoing request from hash tables */
8781su_inlinestatic inline void
8782outgoing_cut_off(nta_outgoing_t *orq)
8783{
8784 nta_agent_t *agent = orq->orq_agent;
8785
8786 if (orq->orq_default)
8787 agent->sa_default_outgoing = NULL((void*)0);
8788
8789 if (orq->orq_inserted)
8790 outgoing_htable_remove(agent->sa_outgoing, orq), orq->orq_inserted = 0;
8791
8792 if (outgoing_is_queued(orq))
8793 outgoing_remove(orq);
8794
8795#if 0
8796 if (orq->orq_forked)
8797 outgoing_remove_fork(orq);
8798#endif
8799
8800 outgoing_reset_timer(orq);
8801
8802 if (orq->orq_pending) {
8803 tport_release(orq->orq_tport, orq->orq_pending,
8804 orq->orq_request, NULL((void*)0), orq, 0);
8805 }
8806 orq->orq_pending = 0;
8807
8808 if (orq->orq_cc)
8809 nta_compartment_decref(&orq->orq_cc);
8810
8811 if (orq->orq_tport)
8812 tport_decref(&orq->orq_tport);
8813}
8814
8815/** Reclaim outgoing request */
8816su_inlinestatic inline
8817void outgoing_reclaim(nta_outgoing_t *orq)
8818{
8819 if (orq->orq_status2b)
8820 *orq->orq_status2b = -1;
8821
8822 if (orq->orq_request)
8823 msg_destroy(orq->orq_request), orq->orq_request = NULL((void*)0);
8824 if (orq->orq_response)
8825 msg_destroy(orq->orq_response), orq->orq_response = NULL((void*)0);
8826#if HAVE_SOFIA_SRESOLV1
8827 if (orq->orq_resolver)
8828 outgoing_destroy_resolver(orq);
8829#endif
8830 su_free(orq->orq_agent->sa_home, orq);
8831}
8832
8833/** Queue request to be freed */
8834su_inlinestatic inline
8835void outgoing_free_queue(outgoing_queue_t *q, nta_outgoing_t *orq)
8836{
8837 outgoing_cut_off(orq);
8838 outgoing_queue(q, orq);
8839}
8840
8841/** Reclaim memory used by queue of requests */
8842static
8843void outgoing_reclaim_queued(su_root_magic_t *rm,
8844 su_msg_r msg,
8845 union sm_arg_u *u)
8846{
8847 outgoing_queue_t *q = u->a_outgoing_queue;
8848 nta_outgoing_t *orq, *orq_next;
8849
8850 SU_DEBUG_9(("outgoing_reclaim_all(%p, %p, %p)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__
, 8851, "outgoing_reclaim_all(%p, %p, %p)\n", (void *)rm, (void
*)msg, (void *)u)) : (void)0)
8851 (void *)rm, (void *)msg, (void *)u))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__
, 8851, "outgoing_reclaim_all(%p, %p, %p)\n", (void *)rm, (void
*)msg, (void *)u)) : (void)0)
;
8852
8853 for (orq = q->q_head; orq; orq = orq_next) {
8854 orq_next = orq->orq_next;
8855 outgoing_reclaim(orq);
8856 }
8857}
8858
8859/** @internal Default callback for request */
8860int outgoing_default_cb(nta_outgoing_magic_t *magic,
8861 nta_outgoing_t *orq,
8862 sip_t const *sip)
8863{
8864 if (sip == NULL((void*)0) || sip->sip_status->st_status >= 200)
8865 outgoing_destroy(orq);
8866 return 0;
8867}
8868
8869/** @internal Destroy an outgoing transaction */
8870void outgoing_destroy(nta_outgoing_t *orq)
8871{
8872 if (orq->orq_terminated || orq->orq_default) {
8873 if (!orq->orq_forking && !orq->orq_forks) {
8874 outgoing_free(orq);
8875 return;
8876 }
8877 }
8878 /* Application is expected to handle 200 OK statelessly
8879 => kill transaction immediately */
8880 else if (orq->orq_method == sip_method_invite && !orq->orq_completed
8881 /* (unless transaction has been canceled) */
8882 && !orq->orq_canceled
8883 /* or it has been forked */
8884 && !orq->orq_forking && !orq->orq_forks) {
8885 orq->orq_destroyed = 1;
8886 outgoing_terminate(orq);
8887 return;
8888 }
8889
8890 orq->orq_destroyed = 1;
8891 orq->orq_callback = outgoing_default_cb;
8892 orq->orq_magic = NULL((void*)0);
8893}
8894
8895/** @internal Outgoing transaction timer routine.
8896 *
8897 */
8898static void
8899_nta_outgoing_timer(nta_agent_t *sa)
8900{
8901 uint32_t now = su_time_ms(su_now());
8902 nta_outgoing_t *orq;
8903 outgoing_queue_t rq[1];
8904 size_t retransmitted = 0, terminated = 0, timeout = 0, destroyed;
8905 size_t total = sa->sa_outgoing->oht_used;
8906 size_t trying = sa->sa_out.re_length;
8907 size_t pending = sa->sa_out.trying->q_length +
8908 sa->sa_out.inv_calling->q_length;
8909 size_t completed = sa->sa_out.completed->q_length +
8910 sa->sa_out.inv_completed->q_length;
8911
8912 outgoing_queue_init(sa->sa_out.free = rq, 0);
8913
8914 while ((orq = sa->sa_out.re_list)) {
8915
8916 now = su_time_ms(su_now());
8917
8918 if ((int32_t)(orq->orq_retry - now) > 0)
8919 break;
8920 if (retransmitted >= timer_max_retransmit)
8921 break;
8922
8923 if (orq->orq_reliable) {
8924 outgoing_reset_timer(orq);
8925
8926 if (!tport_is_connected(orq->orq_tport)) {
8927 uint32_t tls_connect_timeout = (orq->orq_call_tls_connect_timeout_is_set) ?
8928 orq->orq_call_tls_connect_timeout : sa->sa_tls_orq_connect_timeout;
8929 if (su_casenmatch(orq->orq_tpn->tpn_proto, "tls", 3) && tls_connect_timeout) {
8930 outgoing_remove(orq); /* Reset state - this is no resend! */
8931 if (outgoing_other_destinations(orq)) {
8932 SU_DEBUG_5(("nta: timer %s fired (proto: %s), %s %s (%u)\n", "N3",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8934, "nta: timer %s fired (proto: %s), %s %s (%u)\n", "N3"
, orq->orq_tpn->tpn_proto, "trying alternative server for"
, orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void
)0)
8933 orq->orq_tpn->tpn_proto, "trying alternative server for",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8934, "nta: timer %s fired (proto: %s), %s %s (%u)\n", "N3"
, orq->orq_tpn->tpn_proto, "trying alternative server for"
, orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void
)0)
8934 orq->orq_method_name, orq->orq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8934, "nta: timer %s fired (proto: %s), %s %s (%u)\n", "N3"
, orq->orq_tpn->tpn_proto, "trying alternative server for"
, orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void
)0)
;
8935 outgoing_try_another(orq);
8936 } else {
8937 SU_DEBUG_5(("nta: timer %s fired (proto: %s), %s %s (%u)\n", "N3",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8939, "nta: timer %s fired (proto: %s), %s %s (%u)\n", "N3"
, orq->orq_tpn->tpn_proto, "retrying for", orq->orq_method_name
, orq->orq_cseq->cs_seq)) : (void)0)
8938 orq->orq_tpn->tpn_proto, "retrying for",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8939, "nta: timer %s fired (proto: %s), %s %s (%u)\n", "N3"
, orq->orq_tpn->tpn_proto, "retrying for", orq->orq_method_name
, orq->orq_cseq->cs_seq)) : (void)0)
8939 orq->orq_method_name, orq->orq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8939, "nta: timer %s fired (proto: %s), %s %s (%u)\n", "N3"
, orq->orq_tpn->tpn_proto, "retrying for", orq->orq_method_name
, orq->orq_cseq->cs_seq)) : (void)0)
;
8940 outgoing_send(orq, 0); /* Send */
8941 }
8942 } else {
8943 /*
8944 * Timer N3: try to use UDP if trying to send via TCP
8945 * but no connection is established within SIP T4
8946 */
8947 SU_DEBUG_5(("nta: timer %s fired, %s %s (%u)\n", "N3",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8949, "nta: timer %s fired, %s %s (%u)\n", "N3", "try UDP instead for"
, orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void
)0)
8948 "try UDP instead for",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8949, "nta: timer %s fired, %s %s (%u)\n", "N3", "try UDP instead for"
, orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void
)0)
8949 orq->orq_method_name, orq->orq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8949, "nta: timer %s fired, %s %s (%u)\n", "N3", "try UDP instead for"
, orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void
)0)
;
8950 outgoing_try_udp_instead(orq, 1);
8951 outgoing_remove(orq); /* Reset state - this is no resend! */
8952 outgoing_send(orq, 0); /* Send */
8953 }
8954 }
8955 continue;
8956 }
8957
8958 assert(!orq->orq_reliable && orq->orq_interval != 0)((void) sizeof ((!orq->orq_reliable && orq->orq_interval
!= 0) ? 1 : 0), __extension__ ({ if (!orq->orq_reliable &&
orq->orq_interval != 0) ; else __assert_fail ("!orq->orq_reliable && orq->orq_interval != 0"
, "nta.c", 8958, __extension__ __PRETTY_FUNCTION__); }))
;
8959
8960 SU_DEBUG_5(("nta: timer %s fired, %s %s (%u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8962, "nta: timer %s fired, %s %s (%u)\n", orq->orq_method
== sip_method_invite ? "A" : "E", "retransmit", orq->orq_method_name
, orq->orq_cseq->cs_seq)) : (void)0)
8961 orq->orq_method == sip_method_invite ? "A" : "E",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8962, "nta: timer %s fired, %s %s (%u)\n", orq->orq_method
== sip_method_invite ? "A" : "E", "retransmit", orq->orq_method_name
, orq->orq_cseq->cs_seq)) : (void)0)
8962 "retransmit", orq->orq_method_name, orq->orq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8962, "nta: timer %s fired, %s %s (%u)\n", orq->orq_method
== sip_method_invite ? "A" : "E", "retransmit", orq->orq_method_name
, orq->orq_cseq->cs_seq)) : (void)0)
;
8963
8964 outgoing_retransmit(orq);
8965
8966 if (orq->orq_method == sip_method_invite ||
8967 2U * orq->orq_interval < sa->sa_t2)
8968 outgoing_set_timer(orq, 2U * orq->orq_interval);
8969 else
8970 outgoing_set_timer(orq, sa->sa_t2);
8971
8972 if (++retransmitted % 5 == 0)
8973 su_root_yield(sa->sa_root); /* Handle received packets */
8974 }
8975
8976 terminated
8977 = outgoing_timer_dk(sa->sa_out.inv_completed, "D", now)
8978 + outgoing_timer_dk(sa->sa_out.completed, "K", now);
8979
8980 timeout
8981 = outgoing_timer_bf(sa->sa_out.inv_calling, "B", now)
8982 + outgoing_timer_c(sa->sa_out.inv_proceeding, "C", now)
8983 + outgoing_timer_bf(sa->sa_out.trying, "F", now);
8984
8985 destroyed = outgoing_mass_destroy(sa, rq);
8986
8987 sa->sa_out.free = NULL((void*)0);
8988
8989 if (retransmitted || timeout || terminated || destroyed) {
8990 SU_DEBUG_5(("nta_outgoing_timer: "(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8998, "nta_outgoing_timer: " "%zu""/""%zu"" resent, " "%zu"
"/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n"
, retransmitted, trying, timeout, pending, terminated, completed
, destroyed, total)) : (void)0)
8991 MOD_ZU"/"MOD_ZU" resent, "(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8998, "nta_outgoing_timer: " "%zu""/""%zu"" resent, " "%zu"
"/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n"
, retransmitted, trying, timeout, pending, terminated, completed
, destroyed, total)) : (void)0)
8992 MOD_ZU"/"MOD_ZU" tout, "(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8998, "nta_outgoing_timer: " "%zu""/""%zu"" resent, " "%zu"
"/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n"
, retransmitted, trying, timeout, pending, terminated, completed
, destroyed, total)) : (void)0)
8993 MOD_ZU"/"MOD_ZU" term, "(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8998, "nta_outgoing_timer: " "%zu""/""%zu"" resent, " "%zu"
"/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n"
, retransmitted, trying, timeout, pending, terminated, completed
, destroyed, total)) : (void)0)
8994 MOD_ZU"/"MOD_ZU" free\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8998, "nta_outgoing_timer: " "%zu""/""%zu"" resent, " "%zu"
"/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n"
, retransmitted, trying, timeout, pending, terminated, completed
, destroyed, total)) : (void)0)
8995 retransmitted, trying,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8998, "nta_outgoing_timer: " "%zu""/""%zu"" resent, " "%zu"
"/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n"
, retransmitted, trying, timeout, pending, terminated, completed
, destroyed, total)) : (void)0)
8996 timeout, pending,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8998, "nta_outgoing_timer: " "%zu""/""%zu"" resent, " "%zu"
"/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n"
, retransmitted, trying, timeout, pending, terminated, completed
, destroyed, total)) : (void)0)
8997 terminated, completed,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8998, "nta_outgoing_timer: " "%zu""/""%zu"" resent, " "%zu"
"/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n"
, retransmitted, trying, timeout, pending, terminated, completed
, destroyed, total)) : (void)0)
8998 destroyed, total))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 8998, "nta_outgoing_timer: " "%zu""/""%zu"" resent, " "%zu"
"/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n"
, retransmitted, trying, timeout, pending, terminated, completed
, destroyed, total)) : (void)0)
;
8999 }
9000}
9001
9002/** @internal Retransmit the outgoing request. */
9003void outgoing_retransmit(nta_outgoing_t *orq)
9004{
9005 if (orq->orq_prepared && !orq->orq_delayed) {
9006 orq->orq_retries++;
9007
9008 if (orq->orq_retries >= 4 && orq->orq_cc) {
9009 orq->orq_tpn->tpn_comp = NULL((void*)0);
9010 if (orq->orq_retries == 4) {
9011 agent_close_compressor(orq->orq_agent, orq->orq_cc);
9012 nta_compartment_decref(&orq->orq_cc);
9013 }
9014 }
9015
9016 outgoing_send(orq, 1);
9017 }
9018}
9019
9020/** Trying a client transaction. */
9021static
9022void outgoing_trying(nta_outgoing_t *orq)
9023{
9024 if (orq->orq_forked)
9025 ;
9026 else if (orq->orq_method == sip_method_invite) {
9027 if (!orq->orq_completed) {
9028 outgoing_queue(orq->orq_agent->sa_out.inv_calling, orq);
9029 } else {
9030 SU_DEBUG_5(("nta(%p): completed request can not be put into inv_calling queue (%u)\n", (void *)orq, orq->orq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 9030, "nta(%p): completed request can not be put into inv_calling queue (%u)\n"
, (void *)orq, orq->orq_cseq->cs_seq)) : (void)0)
;
9031 if (orq->orq_queue != orq->orq_agent->sa_out.inv_completed) {
9032 /* Put back into inv_completed if it's not there by any reason */
9033 outgoing_queue(orq->orq_agent->sa_out.inv_completed, orq); /* Timer D */
9034 }
9035 }
9036 }
9037 else
9038 outgoing_queue(orq->orq_agent->sa_out.trying, orq);
9039}
9040
9041/** Handle timers B and F */
9042static
9043size_t outgoing_timer_bf(outgoing_queue_t *q,
9044 char const *timer,
9045 uint32_t now)
9046{
9047 nta_outgoing_t *orq;
9048 size_t timeout = 0;
9049
9050 while ((orq = q->q_head)) {
9051 if ((int32_t)(orq->orq_timeout - now) > 0 ||
9052 timeout >= timer_max_timeout)
9053 break;
9054
9055 timeout++;
9056
9057 SU_DEBUG_5(("nta: timer %s fired, %s %s (%u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 9060, "nta: timer %s fired, %s %s (%u)\n", timer, orq->orq_method
!= sip_method_ack ? "timeout" : "terminating", orq->orq_method_name
, orq->orq_cseq->cs_seq)) : (void)0)
9058 timer,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 9060, "nta: timer %s fired, %s %s (%u)\n", timer, orq->orq_method
!= sip_method_ack ? "timeout" : "terminating", orq->orq_method_name
, orq->orq_cseq->cs_seq)) : (void)0)
9059 orq->orq_method != sip_method_ack ? "timeout" : "terminating",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 9060, "nta: timer %s fired, %s %s (%u)\n", timer, orq->orq_method
!= sip_method_ack ? "timeout" : "terminating", orq->orq_method_name
, orq->orq_cseq->cs_seq)) : (void)0)
9060 orq->orq_method_name, orq->orq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 9060, "nta: timer %s fired, %s %s (%u)\n", timer, orq->orq_method
!= sip_method_ack ? "timeout" : "terminating", orq->orq_method_name
, orq->orq_cseq->cs_seq)) : (void)0)
;
9061
9062 if (orq->orq_method != sip_method_ack)
9063 outgoing_timeout(orq, now);
9064 else
9065 outgoing_terminate(orq);
9066
9067 assert(q->q_head != orq || (int32_t)(orq->orq_timeout - now) > 0)((void) sizeof ((q->q_head != orq || (int32_t)(orq->orq_timeout
- now) > 0) ? 1 : 0), __extension__ ({ if (q->q_head !=
orq || (int32_t)(orq->orq_timeout - now) > 0) ; else __assert_fail
("q->q_head != orq || (int32_t)(orq->orq_timeout - now) > 0"
, "nta.c", 9067, __extension__ __PRETTY_FUNCTION__); }))
;
9068 }
9069
9070 return timeout;
9071}
9072
9073/** Handle timer C */
9074static
9075size_t outgoing_timer_c(outgoing_queue_t *q,
9076 char const *timer,
9077 uint32_t now)
9078{
9079 nta_outgoing_t *orq;
9080 size_t timeout = 0;
9081
9082 if (q->q_timeout == 0)
9083 return 0;
9084
9085 while ((orq = q->q_head)) {
9086 if ((int32_t)(orq->orq_timeout - now) > 0 || timeout >= timer_max_timeout)
9087 break;
9088
9089 timeout++;
9090
9091 SU_DEBUG_5(("nta: timer %s fired, %s %s (%u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 9093, "nta: timer %s fired, %s %s (%u)\n", timer, "CANCEL and timeout"
, orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void
)0)
9092 timer, "CANCEL and timeout",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 9093, "nta: timer %s fired, %s %s (%u)\n", timer, "CANCEL and timeout"
, orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void
)0)
9093 orq->orq_method_name, orq->orq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 9093, "nta: timer %s fired, %s %s (%u)\n", timer, "CANCEL and timeout"
, orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void
)0)
;
9094 /*
9095 * If the client transaction has received a provisional response, the
9096 * proxy MUST generate a CANCEL request matching that transaction.
9097 */
9098 nta_outgoing_tcancel(orq, NULL((void*)0), NULL((void*)0), TAG_NULL()(tag_type_t)0, (tag_value_t)0);
9099 }
9100
9101 return timeout;
9102}
9103
9104/** @internal Signal transaction timeout to the application. */
9105void outgoing_timeout(nta_outgoing_t *orq, uint32_t now)
9106{
9107 nta_outgoing_t *cancel = NULL((void*)0);
9108
9109 if (orq->orq_status || orq->orq_canceled)
9110 ;
9111 else if (outgoing_other_destinations(orq)) {
9112 SU_DEBUG_5(("%s(%p): %s\n", "nta", (void *)orq,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 9113, "%s(%p): %s\n", "nta", (void *)orq, "try next after timeout"
)) : (void)0)
9113 "try next after timeout"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 9113, "%s(%p): %s\n", "nta", (void *)orq, "try next after timeout"
)) : (void)0)
;
9114 outgoing_try_another(orq);
9115 return;
9116 }
9117
9118 cancel = orq->orq_cancel, orq->orq_cancel = NULL((void*)0);
9119 orq->orq_agent->sa_stats->as_tout_request++;
9120
9121 outgoing_reply(orq, SIP_408_REQUEST_TIMEOUT408, sip_408_Request_timeout, 0);
9122
9123 if (cancel)
9124 outgoing_timeout(cancel, now);
9125}
9126
9127/** Complete a client transaction.
9128 *
9129 * @return True if transaction was free()d.
9130 */
9131static int
9132outgoing_complete(nta_outgoing_t *orq)
9133{
9134 orq->orq_completed = 1;
9135
9136 outgoing_reset_timer(orq); /* Timer A / Timer E */
9137
9138 if (orq->orq_stateless)
9139 return outgoing_terminate(orq);
9140
9141 if (orq->orq_forked) {
9142 outgoing_remove_fork(orq);
9143 return outgoing_terminate(orq);
9144 }
9145
9146 if (orq->orq_reliable) {
9147 if (orq->orq_method != sip_method_invite || !orq->orq_uas)
9148 return outgoing_terminate(orq);
9149 }
9150
9151 if (orq->orq_method == sip_method_invite) {
9152 if (orq->orq_queue != orq->orq_agent->sa_out.inv_completed)
9153 outgoing_queue(orq->orq_agent->sa_out.inv_completed, orq); /* Timer D */
9154 }
9155 else {
9156 outgoing_queue(orq->orq_agent->sa_out.completed, orq); /* Timer K */
9157 }
9158
9159 return 0;
9160}
9161
9162/** Handle timers D and K */
9163static
9164size_t outgoing_timer_dk(outgoing_queue_t *q,
9165 char const *timer,
9166 uint32_t now)
9167{
9168 nta_outgoing_t *orq;
9169 size_t terminated = 0;
9170
9171 while ((orq = q->q_head)) {
9172 if ((int32_t)(orq->orq_timeout - now) > 0 ||
9173 terminated >= timer_max_terminate)
9174 break;
9175
9176 terminated++;
9177
9178 SU_DEBUG_5(("nta: timer %s fired, %s %s (%u)\n", timer,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 9179, "nta: timer %s fired, %s %s (%u)\n", timer, "terminate"
, orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void
)0)
9179 "terminate", orq->orq_method_name, orq->orq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 9179, "nta: timer %s fired, %s %s (%u)\n", timer, "terminate"
, orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void
)0)
;
9180
9181 if (orq->orq_method == sip_method_invite)
9182 outgoing_terminate_invite(orq);
9183 else
9184 outgoing_terminate(orq);
9185 }
9186
9187 return terminated;
9188}
9189
9190
9191/** Terminate an INVITE client transaction. */
9192static void
9193outgoing_terminate_invite(nta_outgoing_t *original)
9194{
9195 nta_outgoing_t *orq = original;
9196
9197 while (original->orq_forks) {
9198 orq = original->orq_forks;
9199 original->orq_forks = orq->orq_forks;
9200
9201 assert(orq->orq_forking == original)((void) sizeof ((orq->orq_forking == original) ? 1 : 0), __extension__
({ if (orq->orq_forking == original) ; else __assert_fail
("orq->orq_forking == original", "nta.c", 9201, __extension__
__PRETTY_FUNCTION__); }))
;
9202
9203 SU_DEBUG_5(("nta: timer %s fired, %s %s (%u);tag=%s\n", "D",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 9205, "nta: timer %s fired, %s %s (%u);tag=%s\n", "D", "terminate"
, orq->orq_method_name, orq->orq_cseq->cs_seq, orq->
orq_tag)) : (void)0)
9204 "terminate", orq->orq_method_name, orq->orq_cseq->cs_seq,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 9205, "nta: timer %s fired, %s %s (%u);tag=%s\n", "D", "terminate"
, orq->orq_method_name, orq->orq_cseq->cs_seq, orq->
orq_tag)) : (void)0)
9205 orq->orq_tag))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 9205, "nta: timer %s fired, %s %s (%u);tag=%s\n", "D", "terminate"
, orq->orq_method_name, orq->orq_cseq->cs_seq, orq->
orq_tag)) : (void)0)
;
9206
9207 orq->orq_forking = NULL((void*)0), orq->orq_forks = NULL((void*)0), orq->orq_forked = 0;
9208
9209 if (outgoing_terminate(orq))
9210 continue;
9211
9212 if (orq->orq_status < 200) {
9213 /* Fork has timed out */
9214 orq->orq_agent->sa_stats->as_tout_request++;
9215 outgoing_reply(orq, SIP_408_REQUEST_TIMEOUT408, sip_408_Request_timeout, 0);
9216 }
9217 }
9218
9219 if (outgoing_terminate(orq = original))
9220 return;
9221
9222 if (orq->orq_status < 200) {
9223 /* Original INVITE has timed out */
9224 orq->orq_agent->sa_stats->as_tout_request++;
9225 outgoing_reply(orq, SIP_408_REQUEST_TIMEOUT408, sip_408_Request_timeout, 0);
9226 }
9227}
9228
9229static void
9230outgoing_remove_fork(nta_outgoing_t *orq)
9231{
9232 nta_outgoing_t **slot;
9233
9234 for (slot = &orq->orq_forking->orq_forks;
9235 slot && *slot;
9236 slot = &(*slot)->orq_forks) {
9237 if (orq == *slot) {
9238 *slot = orq->orq_forks;
9239 orq->orq_forks = NULL((void*)0);
9240 orq->orq_forking = NULL((void*)0);
9241 orq->orq_forked = 0;
9242 }
9243 }
9244
9245 assert(orq == NULL)((void) sizeof ((orq == ((void*)0)) ? 1 : 0), __extension__ (
{ if (orq == ((void*)0)) ; else __assert_fail ("orq == NULL",
"nta.c", 9245, __extension__ __PRETTY_FUNCTION__); }))
;
9246}
9247
9248/** Terminate a client transaction. */
9249static
9250int outgoing_terminate(nta_outgoing_t *orq)
9251{
9252 orq->orq_terminated = 1;
9253
9254 if (!orq->orq_destroyed) {
9255 outgoing_queue(orq->orq_agent->sa_out.terminated, orq);
9256 return 0;
9257 }
9258 else if (orq->orq_agent->sa_out.free) {
9259 outgoing_free_queue(orq->orq_agent->sa_out.free, orq);
9260 return 1;
9261 }
9262 else {
9263 outgoing_free(orq);
9264 return 1;
9265 }
9266}
9267
9268/** Mass destroy client transactions */
9269static
9270size_t outgoing_mass_destroy(nta_agent_t *sa, outgoing_queue_t *q)
9271{
9272 size_t destroyed = q->q_length;
9273
9274 if (destroyed > 2 && *sa->sa_terminator) {
9275 su_msg_r m = SU_MSG_R_INIT{ ((void*)0) };
9276
9277 if (su_msg_create(m,
9278 su_clone_task(sa->sa_terminator),
9279 su_root_task(sa->sa_root),
9280 outgoing_reclaim_queued,
9281 sizeof(outgoing_queue_t)) == SU_SUCCESSsu_success) {
9282 outgoing_queue_t *mq = su_msg_data(m)->a_outgoing_queue;
9283
9284 *mq = *q;
9285
9286 if (su_msg_send(m) == SU_SUCCESSsu_success)
9287 q->q_length = 0;
9288 }
9289 }
9290
9291 if (q->q_length)
9292 outgoing_reclaim_queued(NULL((void*)0), NULL((void*)0), (void*)q);
9293
9294 return destroyed;
9295}
9296
9297/** Find an outgoing request corresponging to a message and @Via line.
9298 *
9299 * Return an outgoing request object based on a message and the @Via line
9300 * given as argument. This function is used when doing loop checking: if we
9301 * have sent the request and it has been routed back to us.
9302 *
9303 * @param agent
9304 * @param msg
9305 * @param sip
9306 * @param v
9307 */
9308nta_outgoing_t *nta_outgoing_find(nta_agent_t const *agent,
9309 msg_t const *msg,
9310 sip_t const *sip,
9311 sip_via_t const *v)
9312{
9313 if (agent == NULL((void*)0) || msg == NULL((void*)0) || sip == NULL((void*)0) || v == NULL((void*)0)) {
9314 su_seterrno(EFAULT14);
9315 return NULL((void*)0);
9316 }
9317
9318 return outgoing_find(agent, msg, sip, v);
9319}
9320
9321/**@internal
9322 *
9323 * Find an outgoing request corresponging to a message and @Via line.
9324 *
9325 */
9326nta_outgoing_t *outgoing_find(nta_agent_t const *sa,
9327 msg_t const *msg,
9328 sip_t const *sip,
9329 sip_via_t const *v)
9330{
9331 nta_outgoing_t **oo, *orq;
9332 outgoing_htable_t const *oht = sa->sa_outgoing;
9333 sip_cseq_t const *cseq = sip->sip_cseq;
9334 sip_call_id_t const *i = sip->sip_call_id;
9335 hash_value_t hash;
9336 sip_method_t method, method2;
9337 unsigned short status = sip->sip_status ? sip->sip_status->st_status : 0;
9338
9339 if (cseq == NULL((void*)0))
9340 return NULL((void*)0);
9341
9342 hash = NTA_HASH(i, cseq->cs_seq)((i)->i_hash + 26839U * (uint32_t)(cseq->cs_seq));
9343
9344 method = cseq->cs_method;
9345
9346 /* Get original invite when ACKing */
9347 if (sip->sip_request && method == sip_method_ack && v == NULL((void*)0))
9348 method = sip_method_invite, method2 = sip_method_invalid;
9349 else if (sa->sa_is_a_uas && 200 <= status && status < 300 && method == sip_method_invite)
9350 method2 = sip_method_ack;
9351 else
9352 method2 = method;
9353
9354 for (oo = outgoing_htable_hash(oht, hash);
9355 (orq = *oo);
9356 oo = outgoing_htable_next(oht, oo)) {
9357 if (orq->orq_stateless)
9358 continue;
9359 /* Accept terminated transactions when looking for original INVITE */
9360 if (orq->orq_terminated && method2 != sip_method_invalid)
9361 continue;
9362 if (hash != orq->orq_hash)
9363 continue;
9364 if (orq->orq_call_id->i_hash != i->i_hash ||
9365 strcmp(orq->orq_call_id->i_id, i->i_id))
9366 continue;
9367 if (orq->orq_cseq->cs_seq != cseq->cs_seq)
9368 continue;
9369 if (method == sip_method_unknown &&
9370 strcmp(orq->orq_cseq->cs_method_name, cseq->cs_method_name))
9371 continue;
9372 if (orq->orq_method != method && orq->orq_method != method2)
9373 continue;
9374 if (su_strcasecmp(orq->orq_from->a_tag, sip->sip_from->a_tag))
9375 continue;
9376 if (orq->orq_to->a_tag &&
9377 su_strcasecmp(orq->orq_to->a_tag, sip->sip_to->a_tag))
9378 continue;
9379
9380 if (orq->orq_method == sip_method_ack && 300 <= status)
9381 continue;
9382
9383 if (v && !su_casematch(orq->orq_branch + strlen("branch="), v->v_branch))
9384 continue;
9385
9386 break; /* match */
9387 }
9388
9389 return orq;
9390}
9391
9392/** Process a response message. */
9393int outgoing_recv(nta_outgoing_t *_orq,
9394 int status,
9395 msg_t *msg,
9396 sip_t *sip)
9397{
9398 nta_outgoing_t *orq = _orq->orq_forking ? _orq->orq_forking : _orq;
9399 nta_agent_t *sa = orq->orq_agent;
9400 int internal = sip == NULL((void*)0) || (sip->sip_flags & NTA_INTERNAL_MSG(1<<15)) != 0;
9401
9402 assert(!internal || status >= 300)((void) sizeof ((!internal || status >= 300) ? 1 : 0), __extension__
({ if (!internal || status >= 300) ; else __assert_fail (
"!internal || status >= 300", "nta.c", 9402, __extension__
__PRETTY_FUNCTION__); }))
;
9403 assert(orq == _orq || orq->orq_method == sip_method_invite)((void) sizeof ((orq == _orq || orq->orq_method == sip_method_invite
) ? 1 : 0), __extension__ ({ if (orq == _orq || orq->orq_method
== sip_method_invite) ; else __assert_fail ("orq == _orq || orq->orq_method == sip_method_invite"
, "nta.c", 9403, __extension__ __PRETTY_FUNCTION__); }))
;
9404
9405 if (status < 100) status = 100;
9406
9407 if (!internal && orq->orq_delay == UINT_MAX(2147483647 *2U +1U))
9408 outgoing_estimate_delay(orq, sip);
9409
9410 if (orq->orq_cc)
9411 agent_accept_compressed(orq->orq_agent, msg, orq->orq_cc);
9412
9413 if (orq->orq_cancel) {
9414 nta_outgoing_t *cancel;
9415 cancel = orq->orq_cancel; orq->orq_cancel = NULL((void*)0);
9416 cancel->orq_delayed = 0;
9417
9418 if (status < 200) {
9419 outgoing_send(cancel, 0);
9420 outgoing_complete(orq);
9421 }
9422 else {
9423 outgoing_reply(cancel, SIP_481_NO_TRANSACTION481, sip_481_No_transaction, 0);
9424 }
9425 }
9426
9427 if (orq->orq_pending) {
9428 tport_release(orq->orq_tport, orq->orq_pending, orq->orq_request,
9429 msg, orq, status < 200);
9430 if (status >= 200)
9431 orq->orq_pending = 0;
9432 }
9433
9434 /* The state machines */
9435 if (orq->orq_method == sip_method_invite) {
9436 nta_outgoing_t *original = orq;
9437
9438 orq = _orq;
9439
9440 if (orq->orq_destroyed && 200 <= status && status < 300) {
9441 if (orq->orq_uas && su_strcasecmp(sip->sip_to->a_tag, orq->orq_tag) != 0) {
9442 /* Orphan 200 Ok to INVITE. ACK and BYE it */
9443 SU_DEBUG_5(("nta: Orphan 200 Ok send ACK&BYE %p\n", (void *)orq))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 9443, "nta: Orphan 200 Ok send ACK&BYE %p\n", (void *)orq
)) : (void)0)
;
9444 return nta_msg_ackbye(sa, msg);
9445 }
9446 return -1; /* Proxy statelessly (RFC3261 section 16.11) */
9447 }
9448
9449 outgoing_reset_timer(original); /* Retransmission */
9450
9451 if (status < 200) {
9452 if (original->orq_status < 200)
9453 original->orq_status = status;
9454 if (orq->orq_status < 200)
9455 orq->orq_status = status;
9456
9457 if (original->orq_queue == sa->sa_out.inv_calling) {
9458 outgoing_queue(sa->sa_out.inv_proceeding, original);
9459 }
9460 else if (original->orq_queue == sa->sa_out.inv_proceeding) {
9461 if (sa->sa_out.inv_proceeding->q_timeout) {
9462 outgoing_remove(original);
9463 outgoing_queue(sa->sa_out.inv_proceeding, original);
9464 }
9465 }
9466
9467 /* Handle 100rel */
9468 if (sip && sip->sip_rseq) {
9469 if (outgoing_recv_reliable(orq, msg, sip) < 0) {
9470 msg_destroy(msg);
9471 return 0;
9472 }
9473 }
9474 }
9475 else {
9476 /* Final response */
9477 if (status >= 300 && !internal)
9478 outgoing_ack(original, sip);
9479
9480 if (!original->orq_completed) {
9481 if (outgoing_complete(original))
9482 return 0;
9483
9484 if (orq->orq_uas && sip && orq == original) {
9485 /*
9486 * We silently discard duplicate final responses to INVITE below
9487 * with outgoing_duplicate()
9488 */
9489 su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request));
9490 orq->orq_tag = su_strdup(home, sip->sip_to->a_tag);
9491 }
9492 }
9493 /* Retransmission or response from another fork */
9494 else if (orq->orq_status >= 200) {
9495 /* Once 2xx has been received, non-2xx will not be forwarded */
9496 if (status >= 300)
9497 return outgoing_duplicate(orq, msg, sip);
9498
9499 if (orq->orq_uas) {
9500 if (su_strcasecmp(sip->sip_to->a_tag, orq->orq_tag) == 0)
9501 /* Catch retransmission */
9502 return outgoing_duplicate(orq, msg, sip);
9503
9504 /* Orphan 200 Ok to INVITE. ACK and BYE it */
9505 SU_DEBUG_5(("nta: Orphan 200 Ok send ACK&BYE" VA_NONE))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 9505, "nta: Orphan 200 Ok send ACK&BYE" "%s", "")) : (void
)0)
;
9506 return nta_msg_ackbye(sa, msg);
9507 }
9508 }
9509
9510 orq->orq_status = status;
9511 }
9512 }
9513 else if (orq->orq_method != sip_method_ack) {
9514 /* Non-INVITE */
9515 if (orq->orq_queue == sa->sa_out.trying ||
9516 orq->orq_queue == sa->sa_out.resolving) {
9517 /* hacked by freeswitch, this is being hit by options 404 status with 404 orq->orq_status and orq_destroyed = 1, orq_completed = 1 */
9518 /* assert(orq->orq_status < 200); */
9519 if (orq->orq_status >= 200) {msg_destroy(msg); return 0;}
9520
9521 if (status < 200) {
9522 /* @RFC3261 17.1.2.1:
9523 * retransmissions continue for unreliable transports,
9524 * but at an interval of T2.
9525 *
9526 * @RFC4321 1.2:
9527 * Note that Timer E is not altered during the transition
9528 * to Proceeding.
9529 */
9530 if (!orq->orq_reliable)
9531 orq->orq_interval = sa->sa_t2;
9532 }
9533 else if (!outgoing_complete(orq)) {
9534 if (orq->orq_sigcomp_zap && orq->orq_tport && orq->orq_cc)
9535 agent_zap_compressor(orq->orq_agent, orq->orq_cc);
9536 }
9537 else /* outgoing_complete */ {
9538 msg_destroy(msg);
9539 return 0;
9540 }
9541 }
9542 else {
9543 /* Already completed or terminated */
9544 assert(orq->orq_queue == sa->sa_out.completed ||((void) sizeof ((orq->orq_queue == sa->sa_out.completed
|| orq->orq_queue == sa->sa_out.terminated) ? 1 : 0), __extension__
({ if (orq->orq_queue == sa->sa_out.completed || orq->
orq_queue == sa->sa_out.terminated) ; else __assert_fail (
"orq->orq_queue == sa->sa_out.completed || orq->orq_queue == sa->sa_out.terminated"
, "nta.c", 9545, __extension__ __PRETTY_FUNCTION__); }))
9545 orq->orq_queue == sa->sa_out.terminated)((void) sizeof ((orq->orq_queue == sa->sa_out.completed
|| orq->orq_queue == sa->sa_out.terminated) ? 1 : 0), __extension__
({ if (orq->orq_queue == sa->sa_out.completed || orq->
orq_queue == sa->sa_out.terminated) ; else __assert_fail (
"orq->orq_queue == sa->sa_out.completed || orq->orq_queue == sa->sa_out.terminated"
, "nta.c", 9545, __extension__ __PRETTY_FUNCTION__); }))
;
9546 assert(orq->orq_status >= 200)((void) sizeof ((orq->orq_status >= 200) ? 1 : 0), __extension__
({ if (orq->orq_status >= 200) ; else __assert_fail ("orq->orq_status >= 200"
, "nta.c", 9546, __extension__ __PRETTY_FUNCTION__); }))
;
9547 return outgoing_duplicate(orq, msg, sip);
9548 }
9549
9550 orq->orq_status = status;
9551 }
9552 else {
9553 /* ACK */
9554 if (sip && (sip->sip_flags & NTA_INTERNAL_MSG(1<<15)) == 0)
9555 /* Received re-transmitted final reply to INVITE, retransmit ACK */
9556 outgoing_retransmit(orq);
9557 msg_destroy(msg);
9558 return 0;
9559 }
9560
9561 if (100 >= status + orq->orq_pass_100) {
9562 msg_destroy(msg);
9563 return 0;
9564 }
9565
9566 if (orq->orq_destroyed) {
9567 msg_destroy(msg);
9568 return 0;
9569 }
9570
9571 if (orq->orq_response)
9572 msg_destroy(orq->orq_response);
9573 orq->orq_response = msg;
9574 /* Call callback */
9575 orq->orq_callback(orq->orq_magic, orq, sip);
9576 return 0;
9577}
9578
9579static void outgoing_default_recv(nta_outgoing_t *orq,
9580 int status,
9581 msg_t *msg,
9582 sip_t *sip)
9583{
9584 assert(sip->sip_cseq)((void) sizeof ((sip->sip_cseq) ? 1 : 0), __extension__ ({
if (sip->sip_cseq) ; else __assert_fail ("sip->sip_cseq"
, "nta.c", 9584, __extension__ __PRETTY_FUNCTION__); }))
;
9585
9586 orq->orq_status = status;
9587 orq->orq_response = msg;
9588 orq->orq_callback(orq->orq_magic, orq, sip);
9589 orq->orq_response = NULL((void*)0);
9590 orq->orq_status = 0;
9591 msg_destroy(msg);
9592}
9593
9594static void outgoing_estimate_delay(nta_outgoing_t *orq, sip_t *sip)
9595{
9596 su_time_t now = su_now();
9597 double diff = 1000 * su_time_diff(now, orq->orq_sent);
9598
9599 if (orq->orq_timestamp && sip->sip_timestamp) {
9600 double diff2, delay = 0.0;
9601 su_time_t timestamp = { 0, 0 };
9602 char const *bad;
9603
9604 sscanf(sip->sip_timestamp->ts_stamp, "%lu.%lu",
9605 &timestamp.tv_sec, &timestamp.tv_usec);
9606
9607 diff2 = 1000 * su_time_diff(now, timestamp);
9608
9609 if (diff2 < 0)
9610 bad = "negative";
9611 else if (diff2 > diff + 1e-3)
9612 bad = "too large";
9613 else {
9614 if (sip->sip_timestamp->ts_delay)
9615 sscanf(sip->sip_timestamp->ts_delay, "%lg", &delay);
9616
9617 if (1000 * delay <= diff2) {
9618 diff = diff2 - 1000 * delay;
9619 orq->orq_delay = (unsigned)diff;
9620 SU_DEBUG_7(("nta_outgoing: RTT is %g ms, now is %lu.%06lu, "(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__
, 9625, "nta_outgoing: RTT is %g ms, now is %lu.%06lu, " "Timestamp was %s %s\n"
, diff, now.tv_sec, now.tv_usec, sip->sip_timestamp->ts_stamp
, sip->sip_timestamp->ts_delay ? sip->sip_timestamp->
ts_delay : "")) : (void)0)
9621 "Timestamp was %s %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__
, 9625, "nta_outgoing: RTT is %g ms, now is %lu.%06lu, " "Timestamp was %s %s\n"
, diff, now.tv_sec, now.tv_usec, sip->sip_timestamp->ts_stamp
, sip->sip_timestamp->ts_delay ? sip->sip_timestamp->
ts_delay : "")) : (void)0)
9622 diff, now.tv_sec, now.tv_usec,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__
, 9625, "nta_outgoing: RTT is %g ms, now is %lu.%06lu, " "Timestamp was %s %s\n"
, diff, now.tv_sec, now.tv_usec, sip->sip_timestamp->ts_stamp
, sip->sip_timestamp->ts_delay ? sip->sip_timestamp->
ts_delay : "")) : (void)0)
9623 sip->sip_timestamp->ts_stamp,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__
, 9625, "nta_outgoing: RTT is %g ms, now is %lu.%06lu, " "Timestamp was %s %s\n"
, diff, now.tv_sec, now.tv_usec, sip->sip_timestamp->ts_stamp
, sip->sip_timestamp->ts_delay ? sip->sip_timestamp->
ts_delay : "")) : (void)0)
9624 sip->sip_timestamp->ts_delay ?(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__
, 9625, "nta_outgoing: RTT is %g ms, now is %lu.%06lu, " "Timestamp was %s %s\n"
, diff, now.tv_sec, now.tv_usec, sip->sip_timestamp->ts_stamp
, sip->sip_timestamp->ts_delay ? sip->sip_timestamp->
ts_delay : "")) : (void)0)
9625 sip->sip_timestamp->ts_delay : ""))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__
, 9625, "nta_outgoing: RTT is %g ms, now is %lu.%06lu, " "Timestamp was %s %s\n"
, diff, now.tv_sec, now.tv_usec, sip->sip_timestamp->ts_stamp
, sip->sip_timestamp->ts_delay ? sip->sip_timestamp->
ts_delay : "")) : (void)0)
;
9626 return;
9627 }
9628 bad = "delay";
9629 }
9630
9631 SU_DEBUG_3(("nta_outgoing: %s Timestamp %lu.%06lu %g "(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 9637, "nta_outgoing: %s Timestamp %lu.%06lu %g " "(sent %lu.%06lu, now is %lu.%06lu)\n"
, bad, timestamp.tv_sec, timestamp.tv_usec, delay, orq->orq_sent
.tv_sec, orq->orq_sent.tv_usec, now.tv_sec, now.tv_usec)) :
(void)0)
9632 "(sent %lu.%06lu, now is %lu.%06lu)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 9637, "nta_outgoing: %s Timestamp %lu.%06lu %g " "(sent %lu.%06lu, now is %lu.%06lu)\n"
, bad, timestamp.tv_sec, timestamp.tv_usec, delay, orq->orq_sent
.tv_sec, orq->orq_sent.tv_usec, now.tv_sec, now.tv_usec)) :
(void)0)
9633 bad,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 9637, "nta_outgoing: %s Timestamp %lu.%06lu %g " "(sent %lu.%06lu, now is %lu.%06lu)\n"
, bad, timestamp.tv_sec, timestamp.tv_usec, delay, orq->orq_sent
.tv_sec, orq->orq_sent.tv_usec, now.tv_sec, now.tv_usec)) :
(void)0)
9634 timestamp.tv_sec, timestamp.tv_usec,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 9637, "nta_outgoing: %s Timestamp %lu.%06lu %g " "(sent %lu.%06lu, now is %lu.%06lu)\n"
, bad, timestamp.tv_sec, timestamp.tv_usec, delay, orq->orq_sent
.tv_sec, orq->orq_sent.tv_usec, now.tv_sec, now.tv_usec)) :
(void)0)
9635 delay,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 9637, "nta_outgoing: %s Timestamp %lu.%06lu %g " "(sent %lu.%06lu, now is %lu.%06lu)\n"
, bad, timestamp.tv_sec, timestamp.tv_usec, delay, orq->orq_sent
.tv_sec, orq->orq_sent.tv_usec, now.tv_sec, now.tv_usec)) :
(void)0)
9636 orq->orq_sent.tv_sec, orq->orq_sent.tv_usec,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 9637, "nta_outgoing: %s Timestamp %lu.%06lu %g " "(sent %lu.%06lu, now is %lu.%06lu)\n"
, bad, timestamp.tv_sec, timestamp.tv_usec, delay, orq->orq_sent
.tv_sec, orq->orq_sent.tv_usec, now.tv_sec, now.tv_usec)) :
(void)0)
9637 now.tv_sec, now.tv_usec))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 9637, "nta_outgoing: %s Timestamp %lu.%06lu %g " "(sent %lu.%06lu, now is %lu.%06lu)\n"
, bad, timestamp.tv_sec, timestamp.tv_usec, delay, orq->orq_sent
.tv_sec, orq->orq_sent.tv_usec, now.tv_sec, now.tv_usec)) :
(void)0)
;
9638 }
9639
9640 if (diff >= 0 && diff < (double)UINT_MAX(2147483647 *2U +1U)) {
9641 orq->orq_delay = (unsigned)diff;
9642 SU_DEBUG_7(("nta_outgoing: RTT is %g ms\n", diff))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__
, 9642, "nta_outgoing: RTT is %g ms\n", diff)) : (void)0)
;
9643 }
9644}
9645
9646/**@typedef nta_response_f
9647 *
9648 * Callback for replies to outgoing requests.
9649 *
9650 * This is a callback function invoked by NTA when it has received a new
9651 * reply to an outgoing request.
9652 *
9653 * @param magic request context
9654 * @param request request handle
9655 * @param sip received status message
9656 *
9657 * @return
9658 * This callback function should return always 0.
9659 *
9660 */
9661
9662/** Process duplicate responses */
9663static int outgoing_duplicate(nta_outgoing_t *orq,
9664 msg_t *msg,
9665 sip_t *sip)
9666{
9667 sip_via_t *v;
9668
9669 if (sip && (sip->sip_flags & NTA_INTERNAL_MSG(1<<15)) == 0) {
9670 v = sip->sip_via;
9671
9672 SU_DEBUG_5(("nta: %u %s is duplicate response to %d %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 9674, "nta: %u %s is duplicate response to %d %s\n", sip->
sip_status->st_status, sip->sip_status->st_phrase, orq
->orq_cseq->cs_seq, orq->orq_cseq->cs_method_name
)) : (void)0)
9673 sip->sip_status->st_status, sip->sip_status->st_phrase,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 9674, "nta: %u %s is duplicate response to %d %s\n", sip->
sip_status->st_status, sip->sip_status->st_phrase, orq
->orq_cseq->cs_seq, orq->orq_cseq->cs_method_name
)) : (void)0)
9674 orq->orq_cseq->cs_seq, orq->orq_cseq->cs_method_name))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 9674, "nta: %u %s is duplicate response to %d %s\n", sip->
sip_status->st_status, sip->sip_status->st_phrase, orq
->orq_cseq->cs_seq, orq->orq_cseq->cs_method_name
)) : (void)0)
;
9675 if (v)
9676 SU_DEBUG_5(("\tVia: %s %s%s%s%s%s%s%s%s%s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 9681, "\tVia: %s %s%s%s%s%s%s%s%s%s\n", v->v_protocol, v
->v_host, ((v->v_port) ? (":") : ""), ((v->v_port) ?
(v->v_port) : ""), ((v->v_received) ? (" ;received=") :
""), ((v->v_received) ? (v->v_received) : ""), ((v->
v_maddr) ? (" ;maddr=") : ""), ((v->v_maddr) ? (v->v_maddr
) : ""), ((v->v_branch) ? (" ;branch=") : ""), ((v->v_branch
) ? (v->v_branch) : ""))) : (void)0)
9677 v->v_protocol, v->v_host,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 9681, "\tVia: %s %s%s%s%s%s%s%s%s%s\n", v->v_protocol, v
->v_host, ((v->v_port) ? (":") : ""), ((v->v_port) ?
(v->v_port) : ""), ((v->v_received) ? (" ;received=") :
""), ((v->v_received) ? (v->v_received) : ""), ((v->
v_maddr) ? (" ;maddr=") : ""), ((v->v_maddr) ? (v->v_maddr
) : ""), ((v->v_branch) ? (" ;branch=") : ""), ((v->v_branch
) ? (v->v_branch) : ""))) : (void)0)
9678 SIP_STRLOG(":", v->v_port),(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 9681, "\tVia: %s %s%s%s%s%s%s%s%s%s\n", v->v_protocol, v
->v_host, ((v->v_port) ? (":") : ""), ((v->v_port) ?
(v->v_port) : ""), ((v->v_received) ? (" ;received=") :
""), ((v->v_received) ? (v->v_received) : ""), ((v->
v_maddr) ? (" ;maddr=") : ""), ((v->v_maddr) ? (v->v_maddr
) : ""), ((v->v_branch) ? (" ;branch=") : ""), ((v->v_branch
) ? (v->v_branch) : ""))) : (void)0)
9679 SIP_STRLOG(" ;received=", v->v_received),(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 9681, "\tVia: %s %s%s%s%s%s%s%s%s%s\n", v->v_protocol, v
->v_host, ((v->v_port) ? (":") : ""), ((v->v_port) ?
(v->v_port) : ""), ((v->v_received) ? (" ;received=") :
""), ((v->v_received) ? (v->v_received) : ""), ((v->
v_maddr) ? (" ;maddr=") : ""), ((v->v_maddr) ? (v->v_maddr
) : ""), ((v->v_branch) ? (" ;branch=") : ""), ((v->v_branch
) ? (v->v_branch) : ""))) : (void)0)
9680 SIP_STRLOG(" ;maddr=", v->v_maddr),(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 9681, "\tVia: %s %s%s%s%s%s%s%s%s%s\n", v->v_protocol, v
->v_host, ((v->v_port) ? (":") : ""), ((v->v_port) ?
(v->v_port) : ""), ((v->v_received) ? (" ;received=") :
""), ((v->v_received) ? (v->v_received) : ""), ((v->
v_maddr) ? (" ;maddr=") : ""), ((v->v_maddr) ? (v->v_maddr
) : ""), ((v->v_branch) ? (" ;branch=") : ""), ((v->v_branch
) ? (v->v_branch) : ""))) : (void)0)
9681 SIP_STRLOG(" ;branch=", v->v_branch)))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 9681, "\tVia: %s %s%s%s%s%s%s%s%s%s\n", v->v_protocol, v
->v_host, ((v->v_port) ? (":") : ""), ((v->v_port) ?
(v->v_port) : ""), ((v->v_received) ? (" ;received=") :
""), ((v->v_received) ? (v->v_received) : ""), ((v->
v_maddr) ? (" ;maddr=") : ""), ((v->v_maddr) ? (v->v_maddr
) : ""), ((v->v_branch) ? (" ;branch=") : ""), ((v->v_branch
) ? (v->v_branch) : ""))) : (void)0)
;
9682 }
9683
9684 msg_destroy(msg);
9685 return 0;
9686}
9687
9688/** @internal ACK to a final response (300..699).
9689 * These messages are ACK'ed via the original URL (and tport)
9690 */
9691void outgoing_ack(nta_outgoing_t *orq, sip_t *sip)
9692{
9693 msg_t *ackmsg;
9694
9695 assert(orq)((void) sizeof ((orq) ? 1 : 0), __extension__ ({ if (orq) ; else
__assert_fail ("orq", "nta.c", 9695, __extension__ __PRETTY_FUNCTION__
); }))
;
9696
9697 /* Do not ack internally generated messages... */
9698 if (sip == NULL((void*)0) || sip->sip_flags & NTA_INTERNAL_MSG(1<<15))
9699 return;
9700
9701 assert(sip)((void) sizeof ((sip) ? 1 : 0), __extension__ ({ if (sip) ; else
__assert_fail ("sip", "nta.c", 9701, __extension__ __PRETTY_FUNCTION__
); }))
; assert(sip->sip_status)((void) sizeof ((sip->sip_status) ? 1 : 0), __extension__ (
{ if (sip->sip_status) ; else __assert_fail ("sip->sip_status"
, "nta.c", 9701, __extension__ __PRETTY_FUNCTION__); }))
;
9702 assert(sip->sip_status->st_status >= 300)((void) sizeof ((sip->sip_status->st_status >= 300) ?
1 : 0), __extension__ ({ if (sip->sip_status->st_status
>= 300) ; else __assert_fail ("sip->sip_status->st_status >= 300"
, "nta.c", 9702, __extension__ __PRETTY_FUNCTION__); }))
;
9703 assert(orq->orq_tport)((void) sizeof ((orq->orq_tport) ? 1 : 0), __extension__ (
{ if (orq->orq_tport) ; else __assert_fail ("orq->orq_tport"
, "nta.c", 9703, __extension__ __PRETTY_FUNCTION__); }))
;
9704
9705 ackmsg = outgoing_ackmsg(orq, SIP_METHOD_ACKsip_method_ack, "ACK", SIPTAG_TO(sip->sip_to)siptag_to, siptag_to_v(sip->sip_to), TAG_END()(tag_type_t)0, (tag_value_t)0);
9706 if (!ackmsg)
9707 return;
9708
9709 if (!outgoing_create(orq->orq_agent, NULL((void*)0), NULL((void*)0),
9710 NULL((void*)0), orq->orq_tpn, ackmsg,
9711 NTATAG_BRANCH_KEY(sip->sip_via->v_branch)ntatag_branch_key, tag_str_v((sip->sip_via->v_branch)),
9712 NTATAG_USER_VIA(1)ntatag_user_via, tag_bool_v((1)),
9713 NTATAG_STATELESS(1)ntatag_stateless, tag_bool_v((1)),
9714 TAG_END()(tag_type_t)0, (tag_value_t)0))
9715 msg_destroy(ackmsg);
9716}
9717
9718/** Generate messages for hop-by-hop ACK or CANCEL.
9719 */
9720msg_t *outgoing_ackmsg(nta_outgoing_t *orq, sip_method_t m, char const *mname,
9721 tag_type_t tag, tag_value_t value, ...)
9722{
9723 msg_t *msg = nta_msg_create(orq->orq_agent, 0);
9724 su_home_t *home = msg_home(msg)((su_home_t*)(msg));
9725 sip_t *sip = sip_object(msg);
9726 sip_t *old = sip_object(orq->orq_request);
9727 sip_via_t via[1];
9728
9729 if (!sip)
9730 return NULL((void*)0);
9731
9732 if (tag) {
9733 ta_list ta;
9734
9735 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)
;
9736
9737 sip_add_tl(msg, sip, ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
);
9738 /* Bug sf.net # 173323:
9739 * Ensure that request-URI, topmost Via, From, To, Call-ID, CSeq,
9740 * Max-Forward, Route, Accept-Contact, Reject-Contact and
9741 * Request-Disposition are copied from original request
9742 */
9743 if (sip->sip_from)
9744 sip_header_remove(msg, sip, (void *)sip->sip_from);
9745 if (sip->sip_to && m != sip_method_ack)
9746 sip_header_remove(msg, sip, (void *)sip->sip_to);
9747 if (sip->sip_call_id)
9748 sip_header_remove(msg, sip, (void *)sip->sip_call_id);
9749 while (sip->sip_route)
9750 sip_header_remove(msg, sip, (void *)sip->sip_route);
9751 while (sip->sip_accept_contact)
9752 sip_header_remove(msg, sip, (void *)sip->sip_accept_contact);
9753 while (sip->sip_reject_contact)
9754 sip_header_remove(msg, sip, (void *)sip->sip_reject_contact);
9755 if (sip->sip_request_disposition)
9756 sip_header_remove(msg, sip, (void *)sip->sip_request_disposition);
9757 while (sip->sip_via)
9758 sip_header_remove(msg, sip, (void *)sip->sip_via);
9759 if (sip->sip_max_forwards)
9760 sip_header_remove(msg, sip, (void *)sip->sip_max_forwards);
9761
9762 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))
;
9763 }
9764
9765 sip->sip_request =
9766 sip_request_create(home, m, mname, (url_string_t *)orq->orq_url, NULL((void*)0));
9767
9768 if (sip->sip_to == NULL((void*)0))
9769 sip_add_dup(msg, sip, (sip_header_t *)old->sip_to);
9770 sip_add_dup(msg, sip, (sip_header_t *)old->sip_from);
9771 sip_add_dup(msg, sip, (sip_header_t *)old->sip_call_id);
9772 sip_add_dup(msg, sip, (sip_header_t *)old->sip_route);
9773 /* @RFC3841. Bug #1326727. */
9774 sip_add_dup(msg, sip, (sip_header_t *)old->sip_accept_contact);
9775 sip_add_dup(msg, sip, (sip_header_t *)old->sip_reject_contact);
9776 sip_add_dup(msg, sip, (sip_header_t *)old->sip_request_disposition);
9777 sip_add_dup(msg, sip, (sip_header_t *)old->sip_max_forwards);
9778
9779 if (old->sip_via) {
9780 /* Add only the topmost Via header */
9781 *via = *old->sip_via; via->v_next = NULL((void*)0);
9782 sip_add_dup(msg, sip, (sip_header_t *)via);
9783 }
9784
9785 sip->sip_cseq = sip_cseq_create(home, old->sip_cseq->cs_seq, m, mname);
9786
9787 if (sip->sip_request &&
9788 sip->sip_to &&
9789 sip->sip_from &&
9790 sip->sip_call_id &&
9791 (!old->sip_route || sip->sip_route) &&
9792 sip->sip_cseq)
9793 return msg;
9794
9795 msg_destroy(msg);
9796
9797 return NULL((void*)0);
9798}
9799
9800static
9801void outgoing_delayed_recv(su_root_magic_t *rm,
9802 su_msg_r msg,
9803 union sm_arg_u *u);
9804
9805/** Respond internally to a transaction. */
9806int outgoing_reply(nta_outgoing_t *orq, int status, char const *phrase,
9807 int delayed)
9808{
9809 nta_agent_t *agent = orq->orq_agent;
9810 msg_t *msg = NULL((void*)0);
9811 sip_t *sip = NULL((void*)0);
9812
9813 assert(status == 202 || status >= 400)((void) sizeof ((status == 202 || status >= 400) ? 1 : 0),
__extension__ ({ if (status == 202 || status >= 400) ; else
__assert_fail ("status == 202 || status >= 400", "nta.c",
9813, __extension__ __PRETTY_FUNCTION__); }))
;
9814
9815 if (orq->orq_pending)
9816 tport_release(orq->orq_tport, orq->orq_pending,
9817 orq->orq_request, NULL((void*)0), orq, 0);
9818 orq->orq_pending = 0;
9819
9820 orq->orq_delayed = 0;
9821
9822 if (orq->orq_method == sip_method_ack) {
9823 if (status != delayed)
9824 SU_DEBUG_3(("nta(%p): responding %u %s to ACK!\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 9825, "nta(%p): responding %u %s to ACK!\n", (void *)orq, status
, phrase)) : (void)0)
9825 (void *)orq, status, phrase))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 9825, "nta(%p): responding %u %s to ACK!\n", (void *)orq, status
, phrase)) : (void)0)
;
9826 orq->orq_status = status;
9827 if (orq->orq_queue == NULL((void*)0))
9828 outgoing_trying(orq); /* Timer F */
9829 return 0;
9830 }
9831
9832 if (orq->orq_destroyed) {
9833 if (orq->orq_status < 200)
9834 orq->orq_status = status;
9835 outgoing_complete(orq); /* Timer D / Timer K */
9836 return 0;
9837 }
9838
9839 if (orq->orq_stateless)
9840 ;
9841 else if (orq->orq_queue == NULL((void*)0) ||
9842 orq->orq_queue == orq->orq_agent->sa_out.resolving ||
9843 orq->orq_queue == orq->orq_agent->sa_out.delayed)
9844 outgoing_trying(orq);
9845
9846 /** Insert a dummy Via header */
9847 if (!orq->orq_prepared) {
9848 tport_t *tp = tport_primaries(orq->orq_agent->sa_tports);
9849 outgoing_insert_via(orq, agent_tport_via(tp));
9850 }
9851
9852 /* Create response message, if needed */
9853 if (!orq->orq_stateless &&
9854 !(orq->orq_callback == outgoing_default_cb) &&
9855 !(status == 408 &&
9856 orq->orq_method != sip_method_invite &&
9857 !orq->orq_agent->sa_timeout_408)) {
9858 char const *to_tag;
9859
9860 msg = nta_msg_create(agent, NTA_INTERNAL_MSG(1<<15));
9861
9862 if (complete_response(msg, status, phrase, orq->orq_request) < 0) {
9863 assert(!"complete message")((void) sizeof ((!"complete message") ? 1 : 0), __extension__
({ if (!"complete message") ; else __assert_fail ("!\"complete message\""
, "nta.c", 9863, __extension__ __PRETTY_FUNCTION__); }))
;
9864 return -1;
9865 }
9866
9867 sip = sip_object(msg); assert(sip->sip_flags & NTA_INTERNAL_MSG)((void) sizeof ((sip->sip_flags & (1<<15)) ? 1 :
0), __extension__ ({ if (sip->sip_flags & (1<<15
)) ; else __assert_fail ("sip->sip_flags & NTA_INTERNAL_MSG"
, "nta.c", 9867, __extension__ __PRETTY_FUNCTION__); }))
;
9868 to_tag = nta_agent_newtag(msg_home(msg)((su_home_t*)(msg)), "tag=%s", agent);
9869
9870 if (status > 100 &&
9871 sip->sip_to && !sip->sip_to->a_tag &&
9872 sip->sip_cseq->cs_method != sip_method_cancel &&
9873 sip_to_tag(msg_home(msg)((su_home_t*)(msg)), sip->sip_to, to_tag) < 0) {
9874 assert(!"adding tag")((void) sizeof ((!"adding tag") ? 1 : 0), __extension__ ({ if
(!"adding tag") ; else __assert_fail ("!\"adding tag\"", "nta.c"
, 9874, __extension__ __PRETTY_FUNCTION__); }))
;
9875 return -1;
9876 }
9877
9878 if (status > 400 && agent->sa_blacklist) {
9879 sip_retry_after_t af[1];
9880 sip_retry_after_init(af)->af_delta = agent->sa_blacklist;
9881
9882 sip_add_dup(msg, sip, (sip_header_t *)af);
9883 }
9884 }
9885
9886 if (orq->orq_inserted && !delayed) {
9887 outgoing_recv(orq, status, msg, sip);
9888 return 0;
9889 }
9890 else if (orq->orq_stateless && orq->orq_callback == outgoing_default_cb) {
9891 /* Xyzzy */
9892 orq->orq_status = status;
9893 outgoing_complete(orq);
9894 }
9895 else {
9896 /*
9897 * The thread creating outgoing transaction must return to application
9898 * before transaction callback can be invoked. Therefore processing an
9899 * internally generated response message must be delayed until
9900 * transaction creation is completed.
9901 *
9902 * The internally generated message is transmitted using su_msg_send()
9903 * and it is delivered back to NTA when the application next time
9904 * executes the su_root_t event loop.
9905 */
9906 nta_agent_t *agent = orq->orq_agent;
9907 su_root_t *root = agent->sa_root;
9908 su_msg_r su_msg = SU_MSG_R_INIT{ ((void*)0) };
9909
9910 if (su_msg_create(su_msg,
9911 su_root_task(root),
9912 su_root_task(root),
9913 outgoing_delayed_recv,
9914 sizeof(struct outgoing_recv_s)) == SU_SUCCESSsu_success) {
9915 struct outgoing_recv_s *a = su_msg_data(su_msg)->a_outgoing_recv;
9916
9917 a->orq = orq;
9918 a->msg = msg;
9919 a->sip = sip;
9920 a->status = status;
9921
9922 orq->orq_status2b = &a->status;
9923
9924 if (su_msg_send(su_msg) == SU_SUCCESSsu_success) {
9925 return 0;
9926 }
9927 }
9928 }
9929
9930 if (msg)
9931 msg_destroy(msg);
9932
9933 return -1;
9934}
9935
9936static
9937void outgoing_delayed_recv(su_root_magic_t *rm,
9938 su_msg_r msg,
9939 union sm_arg_u *u)
9940{
9941 struct outgoing_recv_s *a = u->a_outgoing_recv;
9942
9943 if (a->status > 0) {
9944 a->orq->orq_status2b = 0;
9945 if (outgoing_recv(a->orq, a->status, a->msg, a->sip) >= 0)
9946 return;
9947 }
9948
9949 msg_destroy(a->msg);
9950}
9951
9952
9953/* ====================================================================== */
9954/* 9) Resolving (SIP) URL */
9955
9956#if HAVE_SOFIA_SRESOLV1
9957
9958struct sipdns_query;
9959
9960/** DNS resolving for (SIP) URLs */
9961struct sipdns_resolver
9962{
9963 tp_name_t sr_tpn[1]; /**< Copy of original transport name */
9964 sres_query_t *sr_query; /**< Current DNS Query */
9965 char const *sr_target; /**< Target for current query */
9966
9967 struct sipdns_query *sr_current; /**< Current query (with results) */
9968 char **sr_results; /**< A/AAAA results to be used */
9969
9970 struct sipdns_query *sr_head; /**< List of intermediate results */
9971 struct sipdns_query **sr_tail; /**< End of intermediate result list */
9972
9973 struct sipdns_query *sr_done; /**< Completed intermediate results */
9974
9975 struct sipdns_tport const *sr_tport; /**< Selected transport */
9976
9977 /** Transports to consider for this request */
9978 struct sipdns_tport const *sr_tports[SIPDNS_TRANSPORTS(6) + 1];
9979
9980 uint16_t sr_a_aaaa1, sr_a_aaaa2; /**< Order of A and/or AAAA queries. */
9981
9982 unsigned
9983 sr_use_naptr:1,
9984 sr_use_srv:1,
9985 sr_use_a_aaaa:1;
9986};
9987
9988/** Intermediate queries */
9989struct sipdns_query
9990{
9991 struct sipdns_query *sq_next;
9992
9993 char const *sq_proto;
9994 char const *sq_domain;
9995 char sq_port[6]; /* port number */
9996 uint16_t sq_otype; /* origin type of query data (0 means request) */
9997 uint16_t sq_type; /* query type */
9998 uint16_t sq_priority; /* priority or preference */
9999 uint16_t sq_weight; /* preference or weight */
10000 uint16_t sq_grayish; /* candidate for graylisting */
10001};
10002
10003static int outgoing_resolve_next(nta_outgoing_t *orq);
10004static int outgoing_resolving(nta_outgoing_t *orq);
10005static int outgoing_resolving_error(nta_outgoing_t *,
10006 int status, char const *phrase);
10007static void outgoing_graylist(nta_outgoing_t *orq, struct sipdns_query *sq);
10008static int outgoing_query_naptr(nta_outgoing_t *orq, char const *domain);
10009static void outgoing_answer_naptr(sres_context_t *orq, sres_query_t *q,
10010 sres_record_t *answers[]);
10011struct sipdns_tport const *outgoing_naptr_tport(nta_outgoing_t *orq,
10012 sres_record_t *answers[]);
10013
10014static int outgoing_make_srv_query(nta_outgoing_t *orq);
10015static int outgoing_make_a_aaaa_query(nta_outgoing_t *orq);
10016
10017static void outgoing_query_all(nta_outgoing_t *orq);
10018
10019static int outgoing_query_srv(nta_outgoing_t *orq, struct sipdns_query *);
10020static void outgoing_answer_srv(sres_context_t *orq, sres_query_t *q,
10021 sres_record_t *answers[]);
10022
10023#if SU_HAVE_IN61
10024static int outgoing_query_aaaa(nta_outgoing_t *orq, struct sipdns_query *);
10025static void outgoing_answer_aaaa(sres_context_t *orq, sres_query_t *q,
10026 sres_record_t *answers[]);
10027#endif
10028
10029static int outgoing_query_a(nta_outgoing_t *orq, struct sipdns_query *);
10030static void outgoing_answer_a(sres_context_t *orq, sres_query_t *q,
10031 sres_record_t *answers[]);
10032
10033#ifdef __clang_analyzer__1
10034#define FUNC_ATTR_NONNULL(...)__attribute__((nonnull(...))) __attribute__((nonnull(__VA_ARGS__)))
10035#else
10036#define FUNC_ATTR_NONNULL(...)__attribute__((nonnull(...)))
10037#endif
10038
10039static void outgoing_query_results(nta_outgoing_t *orq,
10040 struct sipdns_query *sq,
10041 char *results[],
10042 size_t rlen) FUNC_ATTR_NONNULL(3)__attribute__((nonnull(3)));
10043
10044
10045#define SIPDNS_503_ERROR503, "DNS Error" 503, "DNS Error"
10046
10047/** Resolve a request destination */
10048static void
10049outgoing_resolve(nta_outgoing_t *orq,
10050 int explicit_transport,
10051 enum nta_res_order_e res_order)
10052{
10053 struct sipdns_resolver *sr = NULL((void*)0);
10054 char const *tpname = orq->orq_tpn->tpn_proto;
10055 int tport_known = strcmp(tpname, "*") != 0;
10056
10057 if (orq->orq_agent->sa_resolver)
10058 orq->orq_resolver = sr = su_zalloc(orq->orq_agent->sa_home, (sizeof *sr));
10059
10060 if (!sr) {
10061 outgoing_resolving_error(orq, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error);
10062 return;
10063 }
10064
10065 *sr->sr_tpn = *orq->orq_tpn;
10066 sr->sr_use_srv = orq->orq_agent->sa_use_srv;
10067 sr->sr_use_naptr = orq->orq_agent->sa_use_naptr && sr->sr_use_srv;
10068 sr->sr_use_a_aaaa = 1;
10069 sr->sr_tail = &sr->sr_head;
10070
10071 /* RFC 3263:
10072 If the TARGET was not a numeric IP address, but a port is present in
10073 the URI, the client performs an A or AAAA record lookup of the domain
10074 name. The result will be a list of IP addresses, each of which can
10075 be contacted at the specific port from the URI and transport protocol
10076 determined previously. The client SHOULD try the first record. If
10077 an attempt should fail, based on the definition of failure in Section
10078 4.3, the next SHOULD be tried, and if that should fail, the next
10079 SHOULD be tried, and so on.
10080
10081 This is a change from RFC 2543. Previously, if the port was
10082 explicit, but with a value of 5060, SRV records were used. Now, A
10083 or AAAA records will be used.
10084 */
10085 if (sr->sr_tpn->tpn_port)
10086 sr->sr_use_naptr = 0, sr->sr_use_srv = 0;
10087
10088 /* RFC3263:
10089 If [...] a transport was specified explicitly, the client performs an
10090 SRV query for that specific transport,
10091 */
10092 if (explicit_transport)
10093 sr->sr_use_naptr = 0;
10094
10095 {
10096 /* Initialize sr_tports */
10097 tport_t *tport;
10098 char const *ident = sr->sr_tpn->tpn_ident;
10099 int i, j;
10100
10101 for (tport = tport_primary_by_name(orq->orq_agent->sa_tports, orq->orq_tpn);
10102 tport;
10103 tport = tport_next(tport)) {
10104 tp_name_t const *tpn = tport_name(tport);
10105 if (tport_known && !su_casematch(tpn->tpn_proto, tpname))
10106 continue;
10107 if (ident && (tpn->tpn_ident == NULL((void*)0) || strcmp(ident, tpn->tpn_ident)))
10108 continue;
10109
10110 for (j = 0; j < SIPDNS_TRANSPORTS(6); j++)
10111 if (su_casematch(tpn->tpn_proto, sipdns_tports[j].name))
10112 break;
10113
10114 assert(j < SIPDNS_TRANSPORTS)((void) sizeof ((j < (6)) ? 1 : 0), __extension__ ({ if (j
< (6)) ; else __assert_fail ("j < SIPDNS_TRANSPORTS", "nta.c"
, 10114, __extension__ __PRETTY_FUNCTION__); }))
;
10115 if (j == SIPDNS_TRANSPORTS(6))
10116 /* Someone added transport but did not update sipdns_tports */
10117 continue;
10118
10119 for (i = 0; i < SIPDNS_TRANSPORTS(6); i++) {
10120 if (sipdns_tports + j == sr->sr_tports[i] || sr->sr_tports[i] == NULL((void*)0))
10121 break;
10122 }
10123 sr->sr_tports[i] = sipdns_tports + j;
10124
10125 if (tport_known) /* Looking for only one transport */ {
10126 sr->sr_tport = sipdns_tports + j;
10127 break;
10128 }
10129 }
10130
10131 /* Nothing found */
10132 if (!sr->sr_tports[0]) {
10133 SU_DEBUG_3(("nta(%p): transport %s is not supported%s%s\n", (void *)orq,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 10134, "nta(%p): transport %s is not supported%s%s\n", (void
*)orq, tpname, ident ? " by interface " : "", ident ? ident :
"")) : (void)0)
10134 tpname, ident ? " by interface " : "", ident ? ident : ""))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 10134, "nta(%p): transport %s is not supported%s%s\n", (void
*)orq, tpname, ident ? " by interface " : "", ident ? ident :
"")) : (void)0)
;
10135 outgoing_resolving_error(orq, SIPDNS_503_ERROR503, "DNS Error");
10136 return;
10137 }
10138 }
10139
10140 switch (res_order) {
10141 default:
10142 case nta_res_ip6_ip4:
10143 sr->sr_a_aaaa1 = sres_type_aaaa, sr->sr_a_aaaa2 = sres_type_a;
10144 break;
10145 case nta_res_ip4_ip6:
10146 sr->sr_a_aaaa1 = sres_type_a, sr->sr_a_aaaa2 = sres_type_aaaa;
10147 break;
10148 case nta_res_ip6_only:
10149 sr->sr_a_aaaa1 = sres_type_aaaa, sr->sr_a_aaaa2 = sres_type_aaaa;
10150 break;
10151 case nta_res_ip4_only:
10152 sr->sr_a_aaaa1 = sres_type_a, sr->sr_a_aaaa2 = sres_type_a;
10153 break;
10154 }
10155
10156 outgoing_resolve_next(orq);
10157}
10158
10159/** Resolve next destination. */
10160static int
10161outgoing_resolve_next(nta_outgoing_t *orq)
10162{
10163 struct sipdns_resolver *sr = orq->orq_resolver;
10164
10165 if (sr == NULL((void*)0)) {
10166 outgoing_resolving_error(orq, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error);
10167 return 0;
10168 }
10169
10170 if (sr->sr_results) {
10171 /* Use existing A/AAAA results */
10172 su_free(msg_home(orq->orq_request)((su_home_t*)(orq->orq_request)), sr->sr_results[0]);
10173 sr->sr_results++;
10174 if (sr->sr_results[0]) {
10175 struct sipdns_query *sq = sr->sr_current; assert(sq)((void) sizeof ((sq) ? 1 : 0), __extension__ ({ if (sq) ; else
__assert_fail ("sq", "nta.c", 10175, __extension__ __PRETTY_FUNCTION__
); }))
;
10176
10177 if (sq->sq_proto)
10178 orq->orq_tpn->tpn_proto = sq->sq_proto;
10179 if (sq->sq_port[0])
10180 orq->orq_tpn->tpn_port = sq->sq_port;
10181
10182 orq->orq_tpn->tpn_host = sr->sr_results[0];
10183
10184 outgoing_reset_timer(orq);
10185 outgoing_queue(orq->orq_agent->sa_out.resolving, orq);
10186 outgoing_prepare_send(orq);
10187 return 1;
10188 }
10189 else {
10190 sr->sr_current = NULL((void*)0);
10191 sr->sr_results = NULL((void*)0);
10192 }
10193 }
10194
10195 if (sr->sr_head)
10196 outgoing_query_all(orq);
10197 else if (sr->sr_use_naptr)
10198 outgoing_query_naptr(orq, sr->sr_tpn->tpn_host); /* NAPTR */
10199 else if (sr->sr_use_srv)
10200 outgoing_make_srv_query(orq); /* SRV */
10201 else if (sr->sr_use_a_aaaa)
10202 outgoing_make_a_aaaa_query(orq); /* A/AAAA */
10203 else
10204 return outgoing_resolving_error(orq, SIPDNS_503_ERROR503, "DNS Error");
10205
10206 return 1;
10207}
10208
10209/** Check if can we retry other destinations? */
10210static int
10211outgoing_other_destinations(nta_outgoing_t const *orq)
10212{
10213 struct sipdns_resolver *sr = orq->orq_resolver;
10214
10215 if (!sr)
10216 return 0;
10217
10218 if (sr->sr_use_a_aaaa || sr->sr_use_srv || sr->sr_use_naptr)
10219 return 1;
10220
10221 if (sr->sr_results && sr->sr_results[1])
10222 return 1;
10223
10224 if (sr->sr_head)
10225 return 1;
10226
10227 return 0;
10228}
10229
10230/** Resolve a request destination */
10231static int
10232outgoing_try_another(nta_outgoing_t *orq)
10233{
10234 struct sipdns_resolver *sr = orq->orq_resolver;
10235
10236 if (sr == NULL((void*)0))
10237 return 0;
10238
10239 *orq->orq_tpn = *sr->sr_tpn;
10240 orq->orq_try_tcp_instead = 0, orq->orq_try_udp_instead = 0;
10241 outgoing_reset_timer(orq);
10242 outgoing_queue(orq->orq_agent->sa_out.resolving, orq);
10243
10244 if (orq->orq_status > 0)
10245 /* PP: don't hack priority if a preliminary response has been received */
10246 ;
10247 else if (orq->orq_agent->sa_graylist == 0)
10248 /* PP: priority hacking disabled */
10249 ;
10250 /* NetModule hack:
10251 * Move server that did not work to end of queue in sres cache
10252 *
10253 * the next request does not try to use the server that is currently down
10254 *
10255 * @TODO: fix cases with only A or AAAA answering, or all servers down.
10256 */
10257 else if (sr && sr->sr_target) {
10258 struct sipdns_query *sq;
10259
10260 /* find latest A/AAAA record */
10261 sq = sr->sr_head;
10262 if (sq && sq->sq_type == sr->sr_a_aaaa2 && sr->sr_a_aaaa1 != sr->sr_a_aaaa2) {
10263 sq->sq_grayish = 1;
10264 }
10265 else {
10266 outgoing_graylist(orq, sr->sr_done);
10267 }
10268 }
10269
10270 return outgoing_resolve_next(orq);
10271}
10272
10273/** Graylist SRV records */
10274static void outgoing_graylist(nta_outgoing_t *orq, struct sipdns_query *sq)
10275{
10276 struct sipdns_resolver *sr = orq->orq_resolver;
10277 char const *target = sq->sq_domain, *proto = sq->sq_proto;
10278 unsigned prio = sq->sq_priority, maxprio = prio;
10279
10280 /* Don't know how to graylist but SRV records */
10281 if (sq->sq_otype != sres_type_srv)
10282 return;
10283
10284 SU_DEBUG_5(("nta: graylisting %s:%s;transport=%s\n", target, sq->sq_port, proto))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 10284, "nta: graylisting %s:%s;transport=%s\n", target, sq->
sq_port, proto)) : (void)0)
;
10285
10286 for (sq = sr->sr_head; sq; sq = sq->sq_next)
10287 if (sq->sq_otype == sres_type_srv && sq->sq_priority > maxprio)
10288 maxprio = sq->sq_priority;
10289
10290 for (sq = sr->sr_done; sq; sq = sq->sq_next)
10291 if (sq->sq_otype == sres_type_srv && sq->sq_priority > maxprio)
10292 maxprio = sq->sq_priority;
10293
10294 for (sq = sr->sr_done; sq; sq = sq->sq_next) {
10295 int modified;
10296
10297 if (sq->sq_type != sres_type_srv || strcmp(proto, sq->sq_proto))
10298 continue;
10299
10300 /* modify the SRV record(s) corresponding to the latest A/AAAA record */
10301 modified = sres_set_cached_srv_priority(
10302 orq->orq_agent->sa_resolver,
10303 sq->sq_domain,
10304 target,
10305 sq->sq_port[0] ? (uint16_t)strtoul(sq->sq_port, NULL((void*)0), 10) : 0,
10306 orq->orq_agent->sa_graylist,
10307 maxprio + 1);
10308
10309 if (modified >= 0)
10310 SU_DEBUG_3(("nta: reduced priority of %d %s SRV records (increase value to %u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 10311, "nta: reduced priority of %d %s SRV records (increase value to %u)\n"
, modified, sq->sq_domain, maxprio + 1)) : (void)0)
10311 modified, sq->sq_domain, maxprio + 1))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 10311, "nta: reduced priority of %d %s SRV records (increase value to %u)\n"
, modified, sq->sq_domain, maxprio + 1)) : (void)0)
;
10312 else
10313 SU_DEBUG_3(("nta: failed to reduce %s SRV priority\n", sq->sq_domain))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 10313, "nta: failed to reduce %s SRV priority\n", sq->sq_domain
)) : (void)0)
;
10314 }
10315}
10316
10317/** Cancel resolver query */
10318su_inlinestatic inline void outgoing_cancel_resolver(nta_outgoing_t *orq)
10319{
10320 struct sipdns_resolver *sr = orq->orq_resolver;
10321
10322 assert(orq->orq_resolver)((void) sizeof ((orq->orq_resolver) ? 1 : 0), __extension__
({ if (orq->orq_resolver) ; else __assert_fail ("orq->orq_resolver"
, "nta.c", 10322, __extension__ __PRETTY_FUNCTION__); }))
;
10323
10324 if (sr->sr_query) /* Cancel resolver query */
10325 sres_query_bind(sr->sr_query, NULL((void*)0), NULL((void*)0)), sr->sr_query = NULL((void*)0);
10326}
10327
10328/** Destroy resolver */
10329su_inlinestatic inline void outgoing_destroy_resolver(nta_outgoing_t *orq)
10330{
10331 struct sipdns_resolver *sr = orq->orq_resolver;
10332
10333 assert(orq->orq_resolver)((void) sizeof ((orq->orq_resolver) ? 1 : 0), __extension__
({ if (orq->orq_resolver) ; else __assert_fail ("orq->orq_resolver"
, "nta.c", 10333, __extension__ __PRETTY_FUNCTION__); }))
;
10334
10335 outgoing_cancel_resolver(orq);
10336
10337 su_free(orq->orq_agent->sa_home, sr);
10338
10339 orq->orq_resolver = NULL((void*)0);
10340}
10341
10342/** Check if we are resolving. If not, return 503 response. */
10343static
10344int outgoing_resolving(nta_outgoing_t *orq)
10345{
10346 struct sipdns_resolver *sr = orq->orq_resolver;
10347
10348 assert(orq->orq_resolver)((void) sizeof ((orq->orq_resolver) ? 1 : 0), __extension__
({ if (orq->orq_resolver) ; else __assert_fail ("orq->orq_resolver"
, "nta.c", 10348, __extension__ __PRETTY_FUNCTION__); }))
;
10349
10350 if (!sr->sr_query) {
10351 return outgoing_resolving_error(orq, SIPDNS_503_ERROR503, "DNS Error");
10352 }
10353 else {
10354 outgoing_queue(orq->orq_agent->sa_out.resolving, orq);
10355 return 0;
10356 }
10357}
10358
10359/** Return 503 response */
10360static
10361int outgoing_resolving_error(nta_outgoing_t *orq, int status, char const *phrase)
10362{
10363 orq->orq_resolved = 1;
10364 outgoing_reply(orq, status, phrase, 0);
10365 return -1;
10366}
10367
10368/* Query SRV records (with the given tport). */
10369static
10370int outgoing_make_srv_query(nta_outgoing_t *orq)
10371{
10372 struct sipdns_resolver *sr = orq->orq_resolver;
10373 su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request));
10374 struct sipdns_query *sq;
10375 char const *host, *prefix;
10376 int i;
10377 size_t hlen, plen;
10378
10379 sr->sr_use_srv = 0;
10380
10381 host = sr->sr_tpn->tpn_host;
10382 hlen = strlen(host) + 1;
10383
10384 for (i = 0; sr->sr_tports[i]; i++) {
10385 if (sr->sr_tport && sr->sr_tports[i] != sr->sr_tport)
10386 continue;
10387
10388 prefix = sr->sr_tports[i]->prefix;
10389 plen = strlen(prefix);
10390
10391 sq = su_zalloc(home, (sizeof *sq) + plen + hlen);
10392 if (sq) {
10393 *sr->sr_tail = sq, sr->sr_tail = &sq->sq_next;
10394 sq->sq_domain = memcpy(sq + 1, prefix, plen);
10395 memcpy((char *)sq->sq_domain + plen, host, hlen);
10396 sq->sq_proto = sr->sr_tports[i]->name;
10397 sq->sq_type = sres_type_srv;
10398 sq->sq_priority = 1;
10399 sq->sq_weight = 1;
10400 }
10401 }
10402
10403 outgoing_query_all(orq);
10404
10405 return 0;
10406}
10407
10408/* Query A/AAAA records. */
10409static
10410int outgoing_make_a_aaaa_query(nta_outgoing_t *orq)
10411{
10412 struct sipdns_resolver *sr = orq->orq_resolver;
10413 su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request));
10414 tp_name_t *tpn = orq->orq_tpn;
10415 struct sipdns_query *sq;
10416
10417 assert(sr)((void) sizeof ((sr) ? 1 : 0), __extension__ ({ if (sr) ; else
__assert_fail ("sr", "nta.c", 10417, __extension__ __PRETTY_FUNCTION__
); }))
;
10418
10419 sr->sr_use_a_aaaa = 0;
10420
10421 sq = su_zalloc(home, 2 * (sizeof *sq));
10422 if (!sq)
10423 return outgoing_resolving(orq);
10424
10425 sq->sq_type = sr->sr_a_aaaa1;
10426 sq->sq_domain = tpn->tpn_host;
10427 sq->sq_priority = 1;
10428
10429 /* Append */
10430 *sr->sr_tail = sq, sr->sr_tail = &sq->sq_next;
10431
10432 outgoing_query_all(orq);
10433
10434 return 0;
10435}
10436
10437
10438/** Start SRV/A/AAAA queries */
10439static
10440void outgoing_query_all(nta_outgoing_t *orq)
10441{
10442 struct sipdns_resolver *sr = orq->orq_resolver;
10443 struct sipdns_query *sq = sr->sr_head;
10444
10445 if (sq == NULL((void*)0)) {
10446 outgoing_resolving_error(orq, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error);
10447 return;
10448 }
10449
10450 /* Remove from intermediate list */
10451 if (!(sr->sr_head = sq->sq_next))
10452 sr->sr_tail = &sr->sr_head;
10453
10454 if (sq->sq_type == sres_type_srv)
10455 outgoing_query_srv(orq, sq);
10456#if SU_HAVE_IN61
10457 else if (sq->sq_type == sres_type_aaaa)
10458 outgoing_query_aaaa(orq, sq);
10459#endif
10460 else if (sq->sq_type == sres_type_a)
10461 outgoing_query_a(orq, sq);
10462 else
10463 outgoing_resolving_error(orq, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error);
10464}
10465
10466/** Query NAPTR record. */
10467static
10468int outgoing_query_naptr(nta_outgoing_t *orq, char const *domain)
10469{
10470 struct sipdns_resolver *sr = orq->orq_resolver;
10471 sres_record_t **answers;
10472
10473 sr->sr_use_naptr = 0;
10474
10475 sr->sr_target = domain;
10476
10477 answers = sres_cached_answers(orq->orq_agent->sa_resolver,
10478 sres_type_naptr, domain);
10479
10480 SU_DEBUG_5(("nta: for \"%s\" query \"%s\" %s%s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 10482, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, domain, "NAPTR", answers ? " (cached)" : "")) :
(void)0)
10481 orq->orq_tpn->tpn_host, domain, "NAPTR",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 10482, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, domain, "NAPTR", answers ? " (cached)" : "")) :
(void)0)
10482 answers ? " (cached)" : ""))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 10482, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, domain, "NAPTR", answers ? " (cached)" : "")) :
(void)0)
;
10483
10484 if (answers) {
10485 outgoing_answer_naptr(orq, NULL((void*)0), answers);
10486 return 0;
10487 }
10488 else {
10489 sr->sr_query = sres_query(orq->orq_agent->sa_resolver,
10490 outgoing_answer_naptr, orq,
10491 sres_type_naptr, domain);
10492 return outgoing_resolving(orq);
10493 }
10494}
10495
10496/* Process NAPTR records */
10497static
10498void outgoing_answer_naptr(sres_context_t *orq,
10499 sres_query_t *q,
10500 sres_record_t *answers[])
10501{
10502 int i, order = -1;
10503 size_t rlen;
10504 su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request));
10505 struct sipdns_resolver *sr = orq->orq_resolver;
10506 tp_name_t tpn[1];
10507 struct sipdns_query *sq, *selected = NULL((void*)0), **tail = &selected, **at;
10508
10509 assert(sr)((void) sizeof ((sr) ? 1 : 0), __extension__ ({ if (sr) ; else
__assert_fail ("sr", "nta.c", 10509, __extension__ __PRETTY_FUNCTION__
); }))
;
10510
10511 sr->sr_query = NULL((void*)0);
10512
10513 *tpn = *sr->sr_tpn;
10514
10515 /* The NAPTR results are sorted first by Order then by Preference */
10516 sres_sort_answers(orq->orq_agent->sa_resolver, answers);
10517
10518 if (sr->sr_tport == NULL((void*)0))
10519 sr->sr_tport = outgoing_naptr_tport(orq, answers);
10520
10521 for (i = 0; answers && answers[i]; i++) {
10522 sres_naptr_record_t const *na = answers[i]->sr_naptr;
10523 uint16_t type;
10524 int valid_tport;
10525
10526 if (na->na_record->r_status)
10527 continue;
10528 if (na->na_record->r_type != sres_type_naptr)
10529 continue;
10530
10531 /* Check if NAPTR matches our target */
10532 if (!su_casenmatch(na->na_services, "SIP+", 4) &&
10533 !su_casenmatch(na->na_services, "SIPS+", 5))
10534 /* Not a SIP/SIPS service */
10535 continue;
10536
10537 /* Use NAPTR results, don't try extra SRV/A/AAAA records */
10538 sr->sr_use_srv = 0, sr->sr_use_a_aaaa = 0;
10539
10540 valid_tport = sr->sr_tport &&
10541 su_casematch(na->na_services, sr->sr_tport->service);
10542
10543 SU_DEBUG_5(("nta: %s IN NAPTR %u %u \"%s\" \"%s\" \"%s\" %s%s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 10549, "nta: %s IN NAPTR %u %u \"%s\" \"%s\" \"%s\" %s%s\n"
, na->na_record->r_name, na->na_order, na->na_prefer
, na->na_flags, na->na_services, na->na_regexp, na->
na_replace, order >= 0 && order != na->na_order
? " (out of order)" : valid_tport ? "" : " (tport not used)"
)) : (void)0)
10544 na->na_record->r_name,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 10549, "nta: %s IN NAPTR %u %u \"%s\" \"%s\" \"%s\" %s%s\n"
, na->na_record->r_name, na->na_order, na->na_prefer
, na->na_flags, na->na_services, na->na_regexp, na->
na_replace, order >= 0 && order != na->na_order
? " (out of order)" : valid_tport ? "" : " (tport not used)"
)) : (void)0)
10545 na->na_order, na->na_prefer,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 10549, "nta: %s IN NAPTR %u %u \"%s\" \"%s\" \"%s\" %s%s\n"
, na->na_record->r_name, na->na_order, na->na_prefer
, na->na_flags, na->na_services, na->na_regexp, na->
na_replace, order >= 0 && order != na->na_order
? " (out of order)" : valid_tport ? "" : " (tport not used)"
)) : (void)0)
10546 na->na_flags, na->na_services,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 10549, "nta: %s IN NAPTR %u %u \"%s\" \"%s\" \"%s\" %s%s\n"
, na->na_record->r_name, na->na_order, na->na_prefer
, na->na_flags, na->na_services, na->na_regexp, na->
na_replace, order >= 0 && order != na->na_order
? " (out of order)" : valid_tport ? "" : " (tport not used)"
)) : (void)0)
10547 na->na_regexp, na->na_replace,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 10549, "nta: %s IN NAPTR %u %u \"%s\" \"%s\" \"%s\" %s%s\n"
, na->na_record->r_name, na->na_order, na->na_prefer
, na->na_flags, na->na_services, na->na_regexp, na->
na_replace, order >= 0 && order != na->na_order
? " (out of order)" : valid_tport ? "" : " (tport not used)"
)) : (void)0)
10548 order >= 0 && order != na->na_order ? " (out of order)" :(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 10549, "nta: %s IN NAPTR %u %u \"%s\" \"%s\" \"%s\" %s%s\n"
, na->na_record->r_name, na->na_order, na->na_prefer
, na->na_flags, na->na_services, na->na_regexp, na->
na_replace, order >= 0 && order != na->na_order
? " (out of order)" : valid_tport ? "" : " (tport not used)"
)) : (void)0)
10549 valid_tport ? "" : " (tport not used)"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 10549, "nta: %s IN NAPTR %u %u \"%s\" \"%s\" \"%s\" %s%s\n"
, na->na_record->r_name, na->na_order, na->na_prefer
, na->na_flags, na->na_services, na->na_regexp, na->
na_replace, order >= 0 && order != na->na_order
? " (out of order)" : valid_tport ? "" : " (tport not used)"
)) : (void)0)
;
10550
10551 /* RFC 2915 p 4:
10552 * Order
10553 * A 16-bit unsigned integer specifying the order in which the
10554 * NAPTR records MUST be processed to ensure the correct ordering
10555 * of rules. Low numbers are processed before high numbers, and
10556 * once a NAPTR is found whose rule "matches" the target, the
10557 * client MUST NOT consider any NAPTRs with a higher value for
10558 * order (except as noted below for the Flags field).
10559 */
10560 if (order >= 0 && order != na->na_order)
10561 continue;
10562 if (!valid_tport)
10563 continue;
10564
10565 /* OK, we found matching NAPTR */
10566 order = na->na_order;
10567
10568 /*
10569 * The "S" flag means that the next lookup should be for SRV records
10570 * ... "A" means that the next lookup should be for either an A, AAAA,
10571 * or A6 record.
10572 */
10573 if (na->na_flags[0] == 's' || na->na_flags[0] == 'S')
10574 type = sres_type_srv; /* SRV */
10575 else if (na->na_flags[0] == 'a' || na->na_flags[0] == 'A')
10576 type = sr->sr_a_aaaa1; /* A / AAAA */
10577 else
10578 continue;
10579
10580 rlen = strlen(na->na_replace) + 1;
10581 sq = su_zalloc(home, (sizeof *sq) + rlen);
10582
10583 if (sq == NULL((void*)0))
10584 continue;
10585
10586 *tail = sq, tail = &sq->sq_next;
10587 sq->sq_otype = sres_type_naptr;
10588 sq->sq_priority = na->na_prefer;
10589 sq->sq_weight = 1;
10590 sq->sq_type = type;
10591 sq->sq_domain = memcpy(sq + 1, na->na_replace, rlen);
10592 sq->sq_proto = sr->sr_tport->name;
10593 }
10594
10595 sres_free_answers(orq->orq_agent->sa_resolver, answers);
10596
10597 /* RFC2915:
10598 Preference [...] specifies the order in which NAPTR
10599 records with equal "order" values SHOULD be processed, low
10600 numbers being processed before high numbers. */
10601 at = sr->sr_tail;
10602 while (selected) {
10603 sq = selected, selected = sq->sq_next;
10604
10605 for (tail = at; *tail; tail = &(*tail)->sq_next) {
10606 if (sq->sq_priority < (*tail)->sq_priority)
10607 break;
10608 if (sq->sq_priority == (*tail)->sq_priority &&
10609 sq->sq_weight < (*tail)->sq_weight)
10610 break;
10611 }
10612 /* Insert */
10613 sq->sq_next = *tail, *tail = sq;
10614
10615 if (!sq->sq_next) /* Last one */
10616 sr->sr_tail = &sq->sq_next;
10617 }
10618
10619 outgoing_resolve_next(orq);
10620}
10621
10622/* Find first supported protocol in order and preference */
10623struct sipdns_tport const *
10624outgoing_naptr_tport(nta_outgoing_t *orq, sres_record_t *answers[])
10625{
10626 int i, j, order, pref;
10627 int orders[SIPDNS_TRANSPORTS(6)] = {0}, prefs[SIPDNS_TRANSPORTS(6)] = {0};
10628 struct sipdns_tport const *tport;
10629
10630 struct sipdns_resolver *sr = orq->orq_resolver;
10631
10632 prefs[0] = 0;
10633 for (j = 0; sr->sr_tports[j]; j++) {
10634 tport = sr->sr_tports[j];
10635
10636 orders[j] = 65536, prefs[j] = 65536;
10637
10638 /* Find transport order */
10639 for (i = 0; answers && answers[i]; i++) {
10640 sres_naptr_record_t const *na = answers[i]->sr_naptr;
10641 if (na->na_record->r_status)
10642 continue;
10643 if (na->na_record->r_type != sres_type_naptr)
10644 continue;
10645 /* Check if NAPTR matches transport */
10646 if (!su_casematch(na->na_services, tport->service))
10647 continue;
10648 orders[j] = na->na_order;
10649 prefs[j] = na->na_prefer;
10650 break;
10651 }
10652 }
10653
10654 tport = sr->sr_tports[0], order = orders[0], pref = prefs[0];
10655
10656 for (j = 1; sr->sr_tports[j]; j++) {
10657 if (orders[j] <= order && prefs[j] < pref) {
10658 tport = sr->sr_tports[j], order = orders[j], pref = prefs[j];
10659 }
10660 }
10661
10662 return tport;
10663}
10664
10665
10666/* Query SRV records */
10667static
10668int outgoing_query_srv(nta_outgoing_t *orq,
10669 struct sipdns_query *sq)
10670{
10671 struct sipdns_resolver *sr = orq->orq_resolver;
10672
10673 sres_record_t **answers;
10674
10675 sr->sr_target = sq->sq_domain;
10676 sr->sr_current = sq;
10677
10678 answers = sres_cached_answers(orq->orq_agent->sa_resolver,
10679 sres_type_srv, sq->sq_domain);
10680
10681 SU_DEBUG_5(("nta: for \"%s\" query \"%s\" %s%s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 10683, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, sq->sq_domain, "SRV", answers ? " (cached)"
: "")) : (void)0)
10682 orq->orq_tpn->tpn_host, sq->sq_domain, "SRV",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 10683, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, sq->sq_domain, "SRV", answers ? " (cached)"
: "")) : (void)0)
10683 answers ? " (cached)" : ""))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 10683, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, sq->sq_domain, "SRV", answers ? " (cached)"
: "")) : (void)0)
;
10684
10685 if (answers) {
10686 outgoing_answer_srv(orq, NULL((void*)0), answers);
10687 return 0;
10688 }
10689 else {
10690 sr->sr_query = sres_query(orq->orq_agent->sa_resolver,
10691 outgoing_answer_srv, orq,
10692 sres_type_srv, sq->sq_domain);
10693 return outgoing_resolving(orq);
10694 }
10695}
10696
10697/* Process SRV records */
10698static
10699void
10700outgoing_answer_srv(sres_context_t *orq, sres_query_t *q,
10701 sres_record_t *answers[])
10702{
10703 struct sipdns_resolver *sr = orq->orq_resolver;
10704 su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request));
10705 struct sipdns_query *sq0, *sq, *selected = NULL((void*)0), **tail = &selected, **at;
10706 int i;
10707 size_t tlen;
10708
10709 sr->sr_query = NULL((void*)0);
10710
10711 sq0 = sr->sr_current;
10712 assert(sq0 && sq0->sq_type == sres_type_srv)((void) sizeof ((sq0 && sq0->sq_type == sres_type_srv
) ? 1 : 0), __extension__ ({ if (sq0 && sq0->sq_type
== sres_type_srv) ; else __assert_fail ("sq0 && sq0->sq_type == sres_type_srv"
, "nta.c", 10712, __extension__ __PRETTY_FUNCTION__); }))
;
10713 assert(sq0->sq_domain)((void) sizeof ((sq0->sq_domain) ? 1 : 0), __extension__ (
{ if (sq0->sq_domain) ; else __assert_fail ("sq0->sq_domain"
, "nta.c", 10713, __extension__ __PRETTY_FUNCTION__); }))
; assert(sq0->sq_proto)((void) sizeof ((sq0->sq_proto) ? 1 : 0), __extension__ ({
if (sq0->sq_proto) ; else __assert_fail ("sq0->sq_proto"
, "nta.c", 10713, __extension__ __PRETTY_FUNCTION__); }))
;
10714
10715 /* Sort by priority, weight? */
10716 sres_sort_answers(orq->orq_agent->sa_resolver, answers);
10717
10718 for (i = 0; answers && answers[i]; i++) {
10719 sres_srv_record_t const *srv = answers[i]->sr_srv;
10720
10721 if (srv->srv_record->r_status /* There was an error */ ||
10722 srv->srv_record->r_type != sres_type_srv)
10723 continue;
10724
10725 tlen = strlen(srv->srv_target) + 1;
10726
10727 sq = su_zalloc(home, (sizeof *sq) + tlen);
10728
10729 if (sq) {
10730 *tail = sq, tail = &sq->sq_next;
10731
10732 sq->sq_otype = sres_type_srv;
10733 sq->sq_type = sr->sr_a_aaaa1;
10734 sq->sq_proto = sq0->sq_proto;
10735 sq->sq_domain = memcpy(sq + 1, srv->srv_target, tlen);
10736 snprintf(sq->sq_port, sizeof(sq->sq_port), "%u", srv->srv_port);
10737 sq->sq_priority = srv->srv_priority;
10738 sq->sq_weight = srv->srv_weight;
10739 }
10740 }
10741
10742 sres_free_answers(orq->orq_agent->sa_resolver, answers);
10743
10744 at = &sr->sr_head;
10745
10746 /* Insert sorted by priority, randomly select by weigth */
10747 while (selected) {
10748 unsigned long weight = 0;
10749 unsigned N = 0;
10750 uint16_t priority = selected->sq_priority;
10751
10752 /* Total weight of entries with same priority */
10753 for (sq = selected; sq && priority == sq->sq_priority; sq = sq->sq_next) {
10754 weight += sq->sq_weight;
10755 N ++;
10756 }
10757
10758 tail = &selected;
10759
10760 /* Select by weighted random. Entries with weight 0 are kept in order */
10761 if (N > 1 && weight > 0) {
10762 unsigned rand = su_randint(0, weight - 1);
10763
10764 while (*tail && rand >= (*tail)->sq_weight) {
10765 rand -= (*tail)->sq_weight;
10766 tail = &(*tail)->sq_next;
10767 }
10768 }
10769
10770 /* Remove selected */
10771 if (*tail) {
10772 sq = *tail; *tail = sq->sq_next; assert(sq->sq_priority == priority)((void) sizeof ((sq->sq_priority == priority) ? 1 : 0), __extension__
({ if (sq->sq_priority == priority) ; else __assert_fail (
"sq->sq_priority == priority", "nta.c", 10772, __extension__
__PRETTY_FUNCTION__); }))
;
10773
10774 /* Append at *at */
10775 sq->sq_next = *at; *at = sq; at = &sq->sq_next; if (!*at) sr->sr_tail = at;
10776
10777 SU_DEBUG_5(("nta: %s IN SRV %u %u %s %s (%s)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 10780, "nta: %s IN SRV %u %u %s %s (%s)\n", sq0->sq_domain
, (unsigned)sq->sq_priority, (unsigned)sq->sq_weight, sq
->sq_port, sq->sq_domain, sq->sq_proto)) : (void)0)
10778 sq0->sq_domain,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 10780, "nta: %s IN SRV %u %u %s %s (%s)\n", sq0->sq_domain
, (unsigned)sq->sq_priority, (unsigned)sq->sq_weight, sq
->sq_port, sq->sq_domain, sq->sq_proto)) : (void)0)
10779 (unsigned)sq->sq_priority, (unsigned)sq->sq_weight,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 10780, "nta: %s IN SRV %u %u %s %s (%s)\n", sq0->sq_domain
, (unsigned)sq->sq_priority, (unsigned)sq->sq_weight, sq
->sq_port, sq->sq_domain, sq->sq_proto)) : (void)0)
10780 sq->sq_port, sq->sq_domain, sq->sq_proto))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 10780, "nta: %s IN SRV %u %u %s %s (%s)\n", sq0->sq_domain
, (unsigned)sq->sq_priority, (unsigned)sq->sq_weight, sq
->sq_port, sq->sq_domain, sq->sq_proto)) : (void)0)
;
10781 }
10782 }
10783
10784 /* This is not needed anymore (?) */
10785 sr->sr_current = NULL((void*)0);
10786 sq0->sq_next = sr->sr_done; sr->sr_done = sq0;
10787
10788 outgoing_resolve_next(orq);
10789}
10790
10791#if SU_HAVE_IN61
10792/* Query AAAA records */
10793static
10794int outgoing_query_aaaa(nta_outgoing_t *orq, struct sipdns_query *sq)
10795{
10796 struct sipdns_resolver *sr = orq->orq_resolver;
10797 sres_record_t **answers;
10798
10799 sr->sr_target = sq->sq_domain;
10800 sr->sr_current = sq;
10801
10802 answers = sres_cached_answers(orq->orq_agent->sa_resolver,
10803 sres_type_aaaa, sq->sq_domain);
10804
10805 SU_DEBUG_5(("nta: for \"%s\" query \"%s\" %s%s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 10807, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, sq->sq_domain, "AAAA", answers ? " (cached)"
: "")) : (void)0)
10806 orq->orq_tpn->tpn_host, sq->sq_domain, "AAAA",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 10807, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, sq->sq_domain, "AAAA", answers ? " (cached)"
: "")) : (void)0)
10807 answers ? " (cached)" : ""))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 10807, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, sq->sq_domain, "AAAA", answers ? " (cached)"
: "")) : (void)0)
;
10808
10809 if (answers) {
10810 outgoing_answer_aaaa(orq, NULL((void*)0), answers);
10811 return 0;
10812 }
10813
10814 sr->sr_query = sres_query(orq->orq_agent->sa_resolver,
10815 outgoing_answer_aaaa, orq,
10816 sres_type_aaaa, sq->sq_domain);
10817
10818 return outgoing_resolving(orq);
10819}
10820
10821/* Process AAAA records */
10822static
10823void outgoing_answer_aaaa(sres_context_t *orq, sres_query_t *q,
10824 sres_record_t *answers[])
10825{
10826 struct sipdns_resolver *sr = orq->orq_resolver;
10827 su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request));
10828 struct sipdns_query *sq = sr->sr_current;
10829
10830 size_t i, j, found;
10831 char *result, **results = NULL((void*)0);
10832
10833 assert(sq)((void) sizeof ((sq) ? 1 : 0), __extension__ ({ if (sq) ; else
__assert_fail ("sq", "nta.c", 10833, __extension__ __PRETTY_FUNCTION__
); }))
; assert(sq->sq_type == sres_type_aaaa)((void) sizeof ((sq->sq_type == sres_type_aaaa) ? 1 : 0), __extension__
({ if (sq->sq_type == sres_type_aaaa) ; else __assert_fail
("sq->sq_type == sres_type_aaaa", "nta.c", 10833, __extension__
__PRETTY_FUNCTION__); }))
;
10834
10835 sr->sr_query = NULL((void*)0);
10836
10837 for (i = 0, found = 0; answers && answers[i]; i++) {
10838 sres_aaaa_record_t const *aaaa = answers[i]->sr_aaaa;
10839 if (aaaa->aaaa_record->r_status == 0 &&
10840 aaaa->aaaa_record->r_type == sres_type_aaaa)
10841 found++;
10842 }
10843
10844 if (found > 1)
10845 results = su_zalloc(home, (found + 1) * (sizeof *results));
10846 else if (found)
10847 results = &result;
10848
10849 for (i = j = 0; results && answers && answers[i]; i++) {
10850 char addr[SU_ADDRSIZE(48)];
10851 sres_aaaa_record_t const *aaaa = answers[i]->sr_aaaa;
10852
10853 if (aaaa->aaaa_record->r_status ||
10854 aaaa->aaaa_record->r_type != sres_type_aaaa)
10855 continue; /* There was an error */
10856
10857 su_inet_ntopinet_ntop(AF_INET610, &aaaa->aaaa_addr, addr, sizeof(addr));
10858
10859 if (j == 0)
10860 SU_DEBUG_5(("nta(%p): %s IN AAAA %s\n", (void *)orq,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 10861, "nta(%p): %s IN AAAA %s\n", (void *)orq, aaaa->aaaa_record
->r_name, addr)) : (void)0)
10861 aaaa->aaaa_record->r_name, addr))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 10861, "nta(%p): %s IN AAAA %s\n", (void *)orq, aaaa->aaaa_record
->r_name, addr)) : (void)0)
;
10862 else
10863 SU_DEBUG_5(("nta(%p): AAAA %s\n", (void *)orq, addr))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 10863, "nta(%p): AAAA %s\n", (void *)orq, addr)) : (void)0
)
;
10864
10865 assert(j < found)((void) sizeof ((j < found) ? 1 : 0), __extension__ ({ if (
j < found) ; else __assert_fail ("j < found", "nta.c", 10865
, __extension__ __PRETTY_FUNCTION__); }))
;
10866 results[j++] = su_strdup(home, addr);
10867 }
10868
10869 sres_free_answers(orq->orq_agent->sa_resolver, answers);
10870
10871 if (results)
10872 outgoing_query_results(orq, sq, results, found);
10873}
10874#endif /* SU_HAVE_IN6 */
10875
10876/* Query A records */
10877static
10878int outgoing_query_a(nta_outgoing_t *orq, struct sipdns_query *sq)
10879{
10880 struct sipdns_resolver *sr = orq->orq_resolver;
10881 sres_record_t **answers;
10882
10883 sr->sr_target = sq->sq_domain;
10884 sr->sr_current = sq;
10885
10886 answers = sres_cached_answers(orq->orq_agent->sa_resolver,
10887 sres_type_a, sq->sq_domain);
10888
10889 SU_DEBUG_5(("nta: for \"%s\" query \"%s\" %s%s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 10891, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, sq->sq_domain, "A", answers ? " (cached)" :
"")) : (void)0)
10890 orq->orq_tpn->tpn_host, sq->sq_domain, "A",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 10891, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, sq->sq_domain, "A", answers ? " (cached)" :
"")) : (void)0)
10891 answers ? " (cached)" : ""))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 10891, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, sq->sq_domain, "A", answers ? " (cached)" :
"")) : (void)0)
;
10892
10893 if (answers) {
10894 outgoing_answer_a(orq, NULL((void*)0), answers);
10895 return 0;
10896 }
10897
10898 sr->sr_query = sres_query(orq->orq_agent->sa_resolver,
10899 outgoing_answer_a, orq,
10900 sres_type_a, sq->sq_domain);
10901
10902 return outgoing_resolving(orq);
10903}
10904
10905/* Process A records */
10906static
10907void outgoing_answer_a(sres_context_t *orq, sres_query_t *q,
10908 sres_record_t *answers[])
10909{
10910 struct sipdns_resolver *sr = orq->orq_resolver;
10911 su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request));
10912 struct sipdns_query *sq = sr->sr_current;
10913
10914 int i, j, found;
10915 char *result, **results = NULL((void*)0);
10916
10917 assert(sq)((void) sizeof ((sq) ? 1 : 0), __extension__ ({ if (sq) ; else
__assert_fail ("sq", "nta.c", 10917, __extension__ __PRETTY_FUNCTION__
); }))
; assert(sq->sq_type == sres_type_a)((void) sizeof ((sq->sq_type == sres_type_a) ? 1 : 0), __extension__
({ if (sq->sq_type == sres_type_a) ; else __assert_fail (
"sq->sq_type == sres_type_a", "nta.c", 10917, __extension__
__PRETTY_FUNCTION__); }))
;
10918
10919 sr->sr_query = NULL((void*)0);
10920
10921 for (i = 0, found = 0; answers && answers[i]; i++) {
10922 sres_a_record_t const *a = answers[i]->sr_a;
10923 if (a->a_record->r_status == 0 &&
10924 a->a_record->r_type == sres_type_a)
10925 found++;
10926 }
10927
10928 if (found > 1)
10929 results = su_zalloc(home, (found + 1) * (sizeof *results));
10930 else if (found)
10931 results = &result;
10932
10933 for (i = j = 0; answers && answers[i]; i++) {
10934 char addr[SU_ADDRSIZE(48)];
10935 sres_a_record_t const *a = answers[i]->sr_a;
10936
10937 if (a->a_record->r_status ||
10938 a->a_record->r_type != sres_type_a)
10939 continue; /* There was an error */
10940
10941 su_inet_ntopinet_ntop(AF_INET2, &a->a_addr, addr, sizeof(addr));
10942
10943 if (j == 0)
10944 SU_DEBUG_5(("nta: %s IN A %s\n", a->a_record->r_name, addr))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 10944, "nta: %s IN A %s\n", a->a_record->r_name, addr
)) : (void)0)
;
10945 else
10946 SU_DEBUG_5(("nta(%p): A %s\n", (void *)orq, addr))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 10946, "nta(%p): A %s\n", (void *)orq, addr)) : (void)0)
;
10947
10948 assert(j < found)((void) sizeof ((j < found) ? 1 : 0), __extension__ ({ if (
j < found) ; else __assert_fail ("j < found", "nta.c", 10948
, __extension__ __PRETTY_FUNCTION__); }))
;
10949 results[j++] = su_strdup(home, addr);
10950 }
10951
10952 sres_free_answers(orq->orq_agent->sa_resolver, answers);
10953
10954 if (results)
10955 outgoing_query_results(orq, sq, results, found);
10956 else if (!q)
10957 outgoing_resolving_error(orq, SIPDNS_503_ERROR503, "DNS Error");
10958}
10959
10960/** Store A/AAAA query results */
10961static void
10962outgoing_query_results(nta_outgoing_t *orq,
10963 struct sipdns_query *sq,
10964 char *results[],
10965 size_t rlen)
10966{
10967 struct sipdns_resolver *sr = orq->orq_resolver;
10968
10969 if (sq->sq_type == sr->sr_a_aaaa1 &&
10970 sq->sq_type != sr->sr_a_aaaa2) {
10971 sq->sq_type = sr->sr_a_aaaa2;
10972
10973 SU_DEBUG_7(("nta(%p): %s %s record still unresolved\n", (void *)orq,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__
, 10974, "nta(%p): %s %s record still unresolved\n", (void *)
orq, sq->sq_domain, sq->sq_type == sres_type_a ? "A" : "AAAA"
)) : (void)0)
10974 sq->sq_domain, sq->sq_type == sres_type_a ? "A" : "AAAA"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__
, 10974, "nta(%p): %s %s record still unresolved\n", (void *)
orq, sq->sq_domain, sq->sq_type == sres_type_a ? "A" : "AAAA"
)) : (void)0)
;
10975
10976 /*
10977 * Three possible policies:
10978 * 1) try each host for AAAA/A, then A/AAAA
10979 * 2) try everything first for AAAA/A, then everything for A/AAAA
10980 * 3) try one SRV record results for AAAA/A, then for A/AAAA,
10981 * then next SRV record
10982 */
10983
10984 /* We use now policy #1 */
10985 if (!(sq->sq_next = sr->sr_head))
10986 sr->sr_tail = &sq->sq_next;
10987 sr->sr_head = sq;
10988 }
10989 else {
10990 sq->sq_next = sr->sr_done, sr->sr_done = sq;
10991
10992 if (rlen == 0 && sq->sq_grayish)
10993 outgoing_graylist(orq, sq);
10994 }
10995
10996 if (rlen > 1)
10997 sr->sr_results = results;
10998 else
10999 sr->sr_current = NULL((void*)0);
11000
11001 if (rlen > 0) {
11002 orq->orq_resolved = 1;
11003 orq->orq_tpn->tpn_host = results[0];
11004 if (sq->sq_proto) orq->orq_tpn->tpn_proto = sq->sq_proto;
11005 if (sq->sq_port[0]) orq->orq_tpn->tpn_port = sq->sq_port;
11006 outgoing_prepare_send(orq);
11007 } else {
11008 outgoing_resolve_next(orq);
11009 }
11010}
11011
11012
11013#endif
11014
11015/* ====================================================================== */
11016/* 10) Reliable responses */
11017
11018static nta_prack_f nta_reliable_destroyed;
11019
11020/**
11021 * Check that server transaction can be used to send reliable provisional
11022 * responses.
11023 */
11024su_inlinestatic inline
11025int reliable_check(nta_incoming_t *irq)
11026{
11027 if (irq == NULL((void*)0) || irq->irq_status >= 200 || !irq->irq_agent)
11028 return 0;
11029
11030 if (irq->irq_reliable && irq->irq_reliable->rel_status >= 200)
11031 return 0;
11032
11033 /* @RSeq is initialized to nonzero when request requires/supports 100rel */
11034 if (irq->irq_rseq == 0)
11035 return 0;
11036
11037 if (irq->irq_rseq == 0xffffffffU) /* already sent >> 2**31 responses */
11038 return 0;
11039
11040 return 1;
11041}
11042
11043/** Respond reliably.
11044 *
11045 * @param irq
11046 * @param callback
11047 * @param rmagic
11048 * @param status
11049 * @param phrase
11050 * @param tag, value, ..
11051 */
11052nta_reliable_t *nta_reliable_treply(nta_incoming_t *irq,
11053 nta_prack_f *callback,
11054 nta_reliable_magic_t *rmagic,
11055 int status, char const *phrase,
11056 tag_type_t tag,
11057 tag_value_t value, ...)
11058{
11059 ta_list ta;
11060 msg_t *msg;
11061 sip_t *sip;
11062 nta_reliable_t *retval = NULL((void*)0);
11063
11064 if (!reliable_check(irq) || (status <= 100 || status >= 200))
11065 return NULL((void*)0);
11066
11067 msg = nta_msg_create(irq->irq_agent, 0);
11068 sip = sip_object(msg);
11069
11070 if (!sip)
11071 return NULL((void*)0);
11072
11073 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)
;
11074
11075 if (0 > nta_incoming_complete_response(irq, msg, status, phrase,
11076 ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
))
11077 msg_destroy(msg);
11078 else if (!(retval = reliable_mreply(irq, callback, rmagic, msg, sip)))
11079 msg_destroy(msg);
11080
11081 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))
;
11082
11083 return retval;
11084}
11085
11086/** Respond reliably with @a msg.
11087 *
11088 * @note
11089 * The stack takes over the ownership of @a msg. (It is destroyed even if
11090 * sending the response fails.)
11091 *
11092 * @param irq
11093 * @param callback
11094 * @param rmagic
11095 * @param msg
11096 */
11097nta_reliable_t *nta_reliable_mreply(nta_incoming_t *irq,
11098 nta_prack_f *callback,
11099 nta_reliable_magic_t *rmagic,
11100 msg_t *msg)
11101{
11102 sip_t *sip = sip_object(msg);
11103
11104 if (!reliable_check(irq)) {
11105 msg_destroy(msg);
11106 return NULL((void*)0);
11107 }
11108
11109 if (sip == NULL((void*)0) || !sip->sip_status || sip->sip_status->st_status <= 100) {
11110 msg_destroy(msg);
11111 return NULL((void*)0);
11112 }
11113
11114 if (sip->sip_status->st_status >= 200) {
11115 incoming_final_failed(irq, msg);
11116 return NULL((void*)0);
11117 }
11118
11119 return reliable_mreply(irq, callback, rmagic, msg, sip);
11120}
11121
11122static
11123nta_reliable_t *reliable_mreply(nta_incoming_t *irq,
11124 nta_prack_f *callback,
11125 nta_reliable_magic_t *rmagic,
11126 msg_t *msg,
11127 sip_t *sip)
11128{
11129 nta_reliable_t *rel;
11130 nta_agent_t *agent;
11131
11132 agent = irq->irq_agent;
11133
11134 if (callback == NULL((void*)0))
11135 callback = nta_reliable_destroyed;
11136
11137 rel = su_zalloc(agent->sa_home, sizeof(*rel));
11138 if (rel) {
11139 rel->rel_irq = irq;
11140 rel->rel_callback = callback;
11141 rel->rel_magic = rmagic;
11142 rel->rel_unsent = msg;
11143 rel->rel_status = sip->sip_status->st_status;
11144 rel->rel_precious = sip->sip_payload != NULL((void*)0);
11145 rel->rel_next = irq->irq_reliable;
11146
11147 /*
11148 * If there already is a un-pr-acknowledged response, queue this one
11149 * until at least one response is pr-acknowledged.
11150 */
11151 if (irq->irq_reliable &&
11152 (irq->irq_reliable->rel_next == NULL((void*)0) ||
11153 irq->irq_reliable->rel_rseq == 0)) {
11154 return irq->irq_reliable = rel;
11155 }
11156
11157 if (reliable_send(irq, rel, msg_ref_create(msg), sip) < 0) {
11158 msg_destroy(msg);
11159 su_free(agent->sa_home, rel);
11160 return NULL((void*)0);
11161 }
11162
11163 irq->irq_reliable = rel;
11164
11165 return callback ? rel : (nta_reliable_t *)-1;
11166 }
11167
11168 msg_destroy(msg);
11169 return NULL((void*)0);
11170}
11171
11172static
11173int reliable_send(nta_incoming_t *irq,
11174 nta_reliable_t *rel,
11175 msg_t *msg,
11176 sip_t *sip)
11177{
11178 nta_agent_t *sa = irq->irq_agent;
11179 su_home_t *home = msg_home(msg)((su_home_t*)(msg));
11180 sip_rseq_t rseq[1];
11181 sip_rseq_init(rseq);
11182
11183 if (sip->sip_require)
11184 msg_header_replace_param(home, sip->sip_require->k_common, "100rel");
11185 else
11186 sip_add_make(msg, sip, sip_require_class, "100rel");
11187
11188 rel->rel_rseq = rseq->rs_response = irq->irq_rseq;
11189 sip_add_dup(msg, sip, (sip_header_t *)rseq);
11190
11191 if (!sip->sip_rseq || incoming_reply(irq, msg, sip) < 0) {
11192 msg_destroy(msg);
11193 return -1;
11194 }
11195
11196 irq->irq_rseq++;
11197
11198 if (irq->irq_queue == sa->sa_in.preliminary)
11199 /* Make sure we are moved to the tail */
11200 incoming_remove(irq);
11201
11202 incoming_queue(sa->sa_in.preliminary, irq); /* P1 */
11203 incoming_set_timer(irq, sa->sa_t1); /* P2 */
11204
11205 return 0;
11206}
11207
11208/** Queue final response when there are unsent precious preliminary responses */
11209static
11210int reliable_final(nta_incoming_t *irq, msg_t *msg, sip_t *sip)
11211{
11212 nta_reliable_t *r;
11213 unsigned already_in_callback;
11214 /*
11215 * We delay sending final response if it's 2XX and
11216 * an unpracked reliable response contains session description
11217 */
11218 /* Get last unpracked response from queue */
11219 if (sip->sip_status->st_status < 300)
11220 for (r = irq->irq_reliable; r; r = r->rel_next)
11221 if (r->rel_unsent && r->rel_precious) {
11222 /* Delay sending 2XX */
11223 reliable_mreply(irq, NULL((void*)0), NULL((void*)0), msg, sip);
11224 return 0;
11225 }
11226
11227 /* Flush unsent responses. */
11228 already_in_callback = irq->irq_in_callback;
11229 irq->irq_in_callback = 1;
11230 reliable_flush(irq);
11231 irq->irq_in_callback = already_in_callback;
11232
11233 if (!already_in_callback && irq->irq_terminated && irq->irq_destroyed) {
11234 incoming_free(irq);
11235 msg_destroy(msg);
11236 return 0;
11237 }
11238
11239 return 1;
11240}
11241
11242/** Get latest reliably sent response */
11243static
11244msg_t *reliable_response(nta_incoming_t *irq)
11245{
11246 nta_reliable_t *r, *rel;
11247
11248 /* Get last unpracked response from queue */
11249 for (rel = NULL((void*)0), r = irq->irq_reliable; r; r = r->rel_next)
11250 if (!r->rel_pracked)
11251 rel = r;
11252
11253 assert(rel)((void) sizeof ((rel) ? 1 : 0), __extension__ ({ if (rel) ; else
__assert_fail ("rel", "nta.c", 11253, __extension__ __PRETTY_FUNCTION__
); }))
;
11254
11255 return rel->rel_unsent;
11256}
11257
11258/* Find un-PRACKed responses */
11259static
11260nta_reliable_t *reliable_find(nta_agent_t const *agent,
11261 sip_t const *sip)
11262{
11263 incoming_htable_t const *iht = agent->sa_incoming;
11264 nta_incoming_t *irq, **ii;
11265 sip_call_id_t const *i = sip->sip_call_id;
11266 sip_rack_t const *rack = sip->sip_rack;
11267 hash_value_t hash = NTA_HASH(i, rack->ra_cseq)((i)->i_hash + 26839U * (uint32_t)(rack->ra_cseq));
11268
11269 /* XXX - add own hash table for 100rel */
11270
11271 for (ii = incoming_htable_hash(iht, hash);
11272 (irq = *ii);
11273 ii = incoming_htable_next(iht, ii)) {
11274
11275 if (hash == irq->irq_hash &&
11276 irq->irq_call_id->i_hash == i->i_hash &&
11277 irq->irq_cseq->cs_seq == rack->ra_cseq &&
11278 irq->irq_method == sip_method_invite &&
11279 strcmp(irq->irq_call_id->i_id, i->i_id) == 0 &&
11280 (irq->irq_to->a_tag == NULL((void*)0) ||
11281 su_casematch(irq->irq_to->a_tag, sip->sip_to->a_tag)) &&
11282 su_casematch(irq->irq_from->a_tag, sip->sip_from->a_tag)) {
11283
11284 nta_reliable_t const *rel;
11285
11286 /* Found matching INVITE */
11287 for (rel = irq->irq_reliable; rel; rel = rel->rel_next)
11288 if (rel->rel_rseq == rack->ra_response)
11289 return (nta_reliable_t *)rel;
11290
11291 }
11292 }
11293
11294 return NULL((void*)0);
11295}
11296
11297/** Process incoming PRACK with matching @RAck field */
11298static
11299int reliable_recv(nta_reliable_t *rel, msg_t *msg, sip_t *sip, tport_t *tp)
11300{
11301 nta_incoming_t *irq = rel->rel_irq;
11302 nta_incoming_t *pr_irq;
11303 int status;
11304
11305 rel->rel_pracked = 1;
11306 msg_ref_destroy(rel->rel_unsent), rel->rel_unsent = NULL((void*)0);
11307
11308 pr_irq = incoming_create(irq->irq_agent, msg, sip, tp, irq->irq_tag);
11309 if (!pr_irq) {
11310 mreply(irq->irq_agent, NULL((void*)0),
11311 SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error, msg,
11312 tp, 0, 0, NULL((void*)0),
11313 TAG_END()(tag_type_t)0, (tag_value_t)0);
11314 return 0;
11315 }
11316
11317 if (irq->irq_status < 200) {
11318 incoming_queue(irq->irq_agent->sa_in.proceeding, irq); /* Reset P1 */
11319 incoming_reset_timer(irq); /* Reset P2 */
11320 }
11321
11322 irq->irq_in_callback = pr_irq->irq_in_callback = 1;
11323 status = rel->rel_callback(rel->rel_magic, rel, pr_irq, sip); rel = NULL((void*)0);
11324 irq->irq_in_callback = pr_irq->irq_in_callback = 0;
11325
11326 if (pr_irq->irq_completed) { /* Already sent final response */
11327 if (pr_irq->irq_terminated && pr_irq->irq_destroyed)
11328 incoming_free(pr_irq);
11329 }
11330 else if (status != 0) {
11331 if (status < 200 || status > 299) {
11332 SU_DEBUG_3(("nta_reliable(): invalid status %03d from callback\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 11333, "nta_reliable(): invalid status %03d from callback\n"
, status)) : (void)0)
11333 status))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 11333, "nta_reliable(): invalid status %03d from callback\n"
, status)) : (void)0)
;
11334 status = 200;
11335 }
11336 nta_incoming_treply(pr_irq, status, "OK", TAG_END()(tag_type_t)0, (tag_value_t)0);
11337 nta_incoming_destroy(pr_irq);
11338 }
11339
11340 /* If there are queued unsent reliable responses, send them all. */
11341 while (irq->irq_reliable && irq->irq_reliable->rel_rseq == 0) {
11342 nta_reliable_t *r;
11343
11344 for (r = irq->irq_reliable; r; r = r->rel_next)
11345 if (r->rel_rseq == 0)
11346 rel = r;
11347
11348 msg = rel->rel_unsent, sip = sip_object(msg);
11349
11350 if (sip->sip_status->st_status < 200) {
11351 if (reliable_send(irq, rel, msg_ref_create(msg), sip) < 0) {
11352 assert(!"send reliable response")((void) sizeof ((!"send reliable response") ? 1 : 0), __extension__
({ if (!"send reliable response") ; else __assert_fail ("!\"send reliable response\""
, "nta.c", 11352, __extension__ __PRETTY_FUNCTION__); }))
;
11353 }
11354 }
11355 else {
11356 /*
11357 * XXX
11358 * Final response should be delayed until a reliable provisional
11359 * response has been pracked
11360 */
11361 rel->rel_unsent = NULL((void*)0), rel->rel_rseq = (uint32_t)-1;
11362 if (incoming_reply(irq, msg, sip) < 0) {
11363 assert(!"send delayed final response")((void) sizeof ((!"send delayed final response") ? 1 : 0), __extension__
({ if (!"send delayed final response") ; else __assert_fail (
"!\"send delayed final response\"", "nta.c", 11363, __extension__
__PRETTY_FUNCTION__); }))
;
11364 }
11365 }
11366 }
11367
11368 return 0;
11369}
11370
11371/** Flush unacknowledged and unsent reliable responses */
11372void reliable_flush(nta_incoming_t *irq)
11373{
11374 nta_reliable_t *r, *rel;
11375
11376 do {
11377 for (r = irq->irq_reliable, rel = NULL((void*)0); r; r = r->rel_next)
11378 if (r->rel_unsent)
11379 rel = r;
11380
11381 if (rel) {
11382 rel->rel_pracked = 1;
11383 msg_ref_destroy(rel->rel_unsent), rel->rel_unsent = NULL((void*)0);
11384 rel->rel_callback(rel->rel_magic, rel, NULL((void*)0), NULL((void*)0));
11385 }
11386 } while (rel);
11387}
11388
11389void reliable_timeout(nta_incoming_t *irq, int timeout)
11390{
11391 if (timeout)
11392 SU_DEBUG_5(("nta: response timeout with %u\n", irq->irq_status))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 11392, "nta: response timeout with %u\n", irq->irq_status
)) : (void)0)
;
11393
11394 irq->irq_in_callback = 1;
11395
11396 reliable_flush(irq);
11397
11398 if (irq->irq_callback)
11399 irq->irq_callback(irq->irq_magic, irq, NULL((void*)0));
11400
11401 irq->irq_in_callback = 0;
11402
11403 if (!timeout)
11404 return;
11405
11406 if (irq->irq_completed && irq->irq_destroyed)
11407 incoming_free(irq), irq = NULL((void*)0);
11408 else if (irq->irq_status < 200)
11409 nta_incoming_treply(irq, 503, "Reliable Response Time-Out", TAG_END()(tag_type_t)0, (tag_value_t)0);
11410}
11411
11412#if 0 /* Not needed, yet. */
11413/** Use this callback when normal leg callback is supposed to
11414 * process incoming PRACK requests
11415 */
11416int nta_reliable_leg_prack(nta_reliable_magic_t *magic,
11417 nta_reliable_t *rel,
11418 nta_incoming_t *irq,
11419 sip_t const *sip)
11420{
11421 nta_agent_t *agent;
11422 nta_leg_t *leg;
11423 char const *method_name;
11424 url_t url[1];
11425 int retval;
11426
11427 if (irq == NULL((void*)0) || sip == NULL((void*)0) || rel == NULL((void*)0) ||
11428 sip_object(irq->irq_request) != sip)
11429 return 500;
11430
11431 agent = irq->irq_agent;
11432 method_name = sip->sip_request->rq_method_name;
11433 *url = *sip->sip_request->rq_url; url->url_params = NULL((void*)0);
11434 agent_aliases(agent, url, irq->irq_tport); /* canonize urls */
11435
11436 if ((leg = leg_find(irq->irq_agent,
11437 method_name, url,
11438 sip->sip_call_id,
11439 sip->sip_from->a_tag,
11440 sip->sip_to->a_tag))) {
11441 /* Use existing dialog */
11442 SU_DEBUG_5(("nta: %s (%u) %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 11444, "nta: %s (%u) %s\n", method_name, sip->sip_cseq->
cs_seq, "PRACK processed by default callback, too")) : (void)
0)
11443 method_name, sip->sip_cseq->cs_seq,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 11444, "nta: %s (%u) %s\n", method_name, sip->sip_cseq->
cs_seq, "PRACK processed by default callback, too")) : (void)
0)
11444 "PRACK processed by default callback, too"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 11444, "nta: %s (%u) %s\n", method_name, sip->sip_cseq->
cs_seq, "PRACK processed by default callback, too")) : (void)
0)
;
11445 retval = leg->leg_callback(leg->leg_magic, leg, irq, sip);
11446 }
11447 else {
11448 retval = 500;
11449 }
11450
11451 nta_reliable_destroy(rel);
11452
11453 return retval;
11454}
11455#endif
11456
11457/** Destroy a reliable response.
11458 *
11459 * Mark a reliable response object for destroyal and free it if possible.
11460 */
11461void nta_reliable_destroy(nta_reliable_t *rel)
11462{
11463 if (rel == NULL((void*)0) || rel == NONE((void *)-1))
11464 return;
11465
11466 if (rel->rel_callback == nta_reliable_destroyed)
11467 SU_DEBUG_1(("%s(%p): %s\n", __func__, (void *)rel, "already destroyed"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 11467, "%s(%p): %s\n", __func__, (void *)rel, "already destroyed"
)) : (void)0)
;
11468
11469 rel->rel_callback = nta_reliable_destroyed;
11470
11471 if (rel->rel_response)
11472 return;
11473
11474 nta_reliable_destroyed(NULL((void*)0), rel, NULL((void*)0), NULL((void*)0));
11475}
11476
11477/** Free and unallocate the nta_reliable_t structure. */
11478static
11479int nta_reliable_destroyed(nta_reliable_magic_t *rmagic,
11480 nta_reliable_t *rel,
11481 nta_incoming_t *prack,
11482 sip_t const *sip)
11483{
11484 nta_reliable_t **prev;
11485
11486 assert(rel)((void) sizeof ((rel) ? 1 : 0), __extension__ ({ if (rel) ; else
__assert_fail ("rel", "nta.c", 11486, __extension__ __PRETTY_FUNCTION__
); }))
; assert(rel->rel_irq)((void) sizeof ((rel->rel_irq) ? 1 : 0), __extension__ ({ if
(rel->rel_irq) ; else __assert_fail ("rel->rel_irq", "nta.c"
, 11486, __extension__ __PRETTY_FUNCTION__); }))
;
11487
11488 for (prev = &rel->rel_irq->irq_reliable; *prev; prev = &(*prev)->rel_next)
11489 if (*prev == rel)
11490 break;
11491
11492 if (!*prev) {
11493 assert(*prev)((void) sizeof ((*prev) ? 1 : 0), __extension__ ({ if (*prev)
; else __assert_fail ("*prev", "nta.c", 11493, __extension__
__PRETTY_FUNCTION__); }))
;
11494 SU_DEBUG_1(("%s(%p): %s\n", __func__, (void *)rel, "not linked"))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 11494, "%s(%p): %s\n", __func__, (void *)rel, "not linked")
) : (void)0)
;
11495 return 200;
11496 }
11497
11498 *prev = rel->rel_next;
11499
11500 if (rel->rel_unsent)
11501 msg_destroy(rel->rel_unsent), rel->rel_unsent = NULL((void*)0);
11502
11503 su_free(rel->rel_irq->irq_agent->sa_home, rel);
11504
11505 return 200;
11506}
11507
11508/** Validate a reliable response. */
11509int outgoing_recv_reliable(nta_outgoing_t *orq,
11510 msg_t *msg,
11511 sip_t *sip)
11512{
11513 short status = sip->sip_status->st_status;
11514 char const *phrase = sip->sip_status->st_phrase;
11515 uint32_t rseq = sip->sip_rseq->rs_response;
11516
11517 SU_DEBUG_7(("nta: %03u %s is reliably received with RSeq: %u\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__
, 11518, "nta: %03u %s is reliably received with RSeq: %u\n",
status, phrase, rseq)) : (void)0)
11518 status, phrase, rseq))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__
, 11518, "nta: %03u %s is reliably received with RSeq: %u\n",
status, phrase, rseq)) : (void)0)
;
11519
11520 /* Cannot handle reliable responses unless we have a full dialog */
11521 if (orq->orq_rseq == 0 && !orq->orq_to->a_tag) {
11522 SU_DEBUG_5(("nta: %03u %s with initial RSeq: %u outside dialog\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 11523, "nta: %03u %s with initial RSeq: %u outside dialog\n"
, status, phrase, rseq)) : (void)0)
11523 status, phrase, rseq))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 11523, "nta: %03u %s with initial RSeq: %u outside dialog\n"
, status, phrase, rseq)) : (void)0)
;
11524 return 0;
11525 }
11526
11527 if (rseq <= orq->orq_rseq) {
11528 SU_DEBUG_3(("nta: %03u %s already received (RSeq: %u, expecting %u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 11529, "nta: %03u %s already received (RSeq: %u, expecting %u)\n"
, status, phrase, rseq, orq->orq_rseq + 1)) : (void)0)
11529 status, phrase, rseq, orq->orq_rseq + 1))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 11529, "nta: %03u %s already received (RSeq: %u, expecting %u)\n"
, status, phrase, rseq, orq->orq_rseq + 1)) : (void)0)
;
11530 return -1;
11531 }
11532
11533 if (orq->orq_rseq && orq->orq_rseq + 1 != rseq) {
11534 SU_DEBUG_3(("nta: %03d %s is not expected (RSeq: %u, expecting %u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 11536, "nta: %03d %s is not expected (RSeq: %u, expecting %u)\n"
, status, sip->sip_status->st_phrase, rseq, orq->orq_rseq
+ 1)) : (void)0)
11535 status, sip->sip_status->st_phrase,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 11536, "nta: %03d %s is not expected (RSeq: %u, expecting %u)\n"
, status, sip->sip_status->st_phrase, rseq, orq->orq_rseq
+ 1)) : (void)0)
11536 rseq, orq->orq_rseq + 1))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__
, 11536, "nta: %03d %s is not expected (RSeq: %u, expecting %u)\n"
, status, sip->sip_status->st_phrase, rseq, orq->orq_rseq
+ 1)) : (void)0)
;
11537 return -1;
11538 }
11539
11540 return 0;
11541}
11542
11543/** Create a tagged fork of outgoing request.
11544 *
11545 * When a dialog-creating INVITE request is forked, each response from
11546 * diffent fork will create an early dialog with a distinct tag in @To
11547 * header. When each fork should be handled separately, a tagged INVITE
11548 * request can be used. It will only receive responses from the specified
11549 * fork. Please note that the tagged transaction should be terminated with
11550 * the final response from another fork, too.
11551 *
11552 * @param orq
11553 * @param callback
11554 * @param magic
11555 * @param to_tag
11556 * @param rseq
11557 *
11558 * @bug Fix the memory leak - either one of the requests is left unreleased
11559 * for ever.
11560 */
11561nta_outgoing_t *nta_outgoing_tagged(nta_outgoing_t *orq,
11562 nta_response_f *callback,
11563 nta_outgoing_magic_t *magic,
11564 char const *to_tag,
11565 sip_rseq_t const *rseq)
11566{
11567 nta_agent_t *agent;
11568 su_home_t *home;
11569 nta_outgoing_t *tagged;
11570 sip_to_t *to;
11571
11572 if (orq == NULL((void*)0) || to_tag == NULL((void*)0))
11573 return NULL((void*)0);
11574
11575 if (orq->orq_to->a_tag) {
11576 SU_DEBUG_1(("%s: transaction %p (CSeq: %s %u) already in dialog\n", __func__,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 11577, "%s: transaction %p (CSeq: %s %u) already in dialog\n"
, __func__, (void *)orq, orq->orq_cseq->cs_method_name,
orq->orq_cseq->cs_seq)) : (void)0)
11577 (void *)orq, orq->orq_cseq->cs_method_name, orq->orq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 11577, "%s: transaction %p (CSeq: %s %u) already in dialog\n"
, __func__, (void *)orq, orq->orq_cseq->cs_method_name,
orq->orq_cseq->cs_seq)) : (void)0)
;
11578 return NULL((void*)0);
11579 }
11580 if (orq->orq_method != sip_method_invite) {
11581 SU_DEBUG_1(("%s: transaction %p (CSeq: %s %u) cannot be tagged\n", __func__,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 11582, "%s: transaction %p (CSeq: %s %u) cannot be tagged\n"
, __func__, (void *)orq, orq->orq_cseq->cs_method_name,
orq->orq_cseq->cs_seq)) : (void)0)
11582 (void *)orq, orq->orq_cseq->cs_method_name, orq->orq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 11582, "%s: transaction %p (CSeq: %s %u) cannot be tagged\n"
, __func__, (void *)orq, orq->orq_cseq->cs_method_name,
orq->orq_cseq->cs_seq)) : (void)0)
;
11583 return NULL((void*)0);
11584 }
11585 if (orq->orq_status < 100) {
11586 SU_DEBUG_1(("%s: transaction %p (CSeq: %s %u) still calling\n", __func__,(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 11587, "%s: transaction %p (CSeq: %s %u) still calling\n", __func__
, (void *)orq, orq->orq_cseq->cs_method_name, orq->orq_cseq
->cs_seq)) : (void)0)
11587 (void *)orq, orq->orq_cseq->cs_method_name, orq->orq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 11587, "%s: transaction %p (CSeq: %s %u) still calling\n", __func__
, (void *)orq, orq->orq_cseq->cs_method_name, orq->orq_cseq
->cs_seq)) : (void)0)
;
11588 return NULL((void*)0);
11589 }
11590
11591 assert(orq->orq_agent)((void) sizeof ((orq->orq_agent) ? 1 : 0), __extension__ (
{ if (orq->orq_agent) ; else __assert_fail ("orq->orq_agent"
, "nta.c", 11591, __extension__ __PRETTY_FUNCTION__); }))
; assert(orq->orq_request)((void) sizeof ((orq->orq_request) ? 1 : 0), __extension__
({ if (orq->orq_request) ; else __assert_fail ("orq->orq_request"
, "nta.c", 11591, __extension__ __PRETTY_FUNCTION__); }))
;
11592
11593 agent = orq->orq_agent;
11594 tagged = su_zalloc(agent->sa_home, sizeof(*tagged));
11595
11596 home = msg_home((msg_t *)orq->orq_request)((su_home_t*)((msg_t *)orq->orq_request));
11597
11598 tagged->orq_hash = orq->orq_hash;
11599 tagged->orq_agent = orq->orq_agent;
11600 tagged->orq_callback = callback;
11601 tagged->orq_magic = magic;
11602
11603 tagged->orq_method = orq->orq_method;
11604 tagged->orq_method_name = orq->orq_method_name;
11605 tagged->orq_url = orq->orq_url;
11606 tagged->orq_from = orq->orq_from;
11607
11608 sip_to_tag(home, to = sip_to_copy(home, orq->orq_to), to_tag);
11609
11610 tagged->orq_to = to;
11611 tagged->orq_tag = to->a_tag;
11612 tagged->orq_cseq = orq->orq_cseq;
11613 tagged->orq_call_id = orq->orq_call_id;
11614
11615 tagged->orq_request = msg_ref_create(orq->orq_request);
11616 tagged->orq_response = msg_ref_create(orq->orq_response);
11617
11618 tagged->orq_status = orq->orq_status;
11619 tagged->orq_via_added = orq->orq_via_added;
11620 tagged->orq_prepared = orq->orq_prepared;
11621 tagged->orq_reliable = orq->orq_reliable;
11622 tagged->orq_sips = orq->orq_sips;
11623 tagged->orq_uas = orq->orq_uas;
11624 tagged->orq_pass_100 = orq->orq_pass_100;
11625 tagged->orq_must_100rel = orq->orq_must_100rel;
11626 tagged->orq_100rel = orq->orq_100rel;
11627 tagged->orq_route = orq->orq_route;
11628 *tagged->orq_tpn = *orq->orq_tpn;
11629 tagged->orq_tport = tport_ref(orq->orq_tport);
11630 if (orq->orq_cc)
11631 tagged->orq_cc = nta_compartment_ref(orq->orq_cc);
11632 tagged->orq_branch = orq->orq_branch;
11633 tagged->orq_via_branch = orq->orq_via_branch;
11634
11635 if (tagged->orq_uas) {
11636 tagged->orq_forking = orq;
11637 tagged->orq_forks = orq->orq_forks;
11638 tagged->orq_forked = 1;
11639 orq->orq_forks = tagged;
11640 }
11641
11642 outgoing_insert(agent, tagged);
11643
11644 return tagged;
11645}
11646
11647/**PRACK a provisional response.
11648 *
11649 * Create and send a PRACK request used to acknowledge a provisional
11650 * response.
11651 *
11652 * The request is sent using the route of the original request @a oorq.
11653 *
11654 * When NTA receives response to the prack request, it invokes the @a
11655 * callback function.
11656 *
11657 * @param leg dialog object
11658 * @param oorq original transaction request
11659 * @param callback callback function (may be @c NULL)
11660 * @param magic application context pointer
11661 * @param route_url optional URL used to route transaction requests
11662 * @param resp (optional) response message to be acknowledged
11663 * @param tag,value,... optional
11664 *
11665 * @return
11666 * If successful, return a pointer to newly created client transaction
11667 * object for PRACK request, NULL otherwise.
11668 *
11669 * @sa
11670 * nta_outgoing_tcreate(), nta_outgoing_tcancel(), nta_outgoing_destroy().
11671 */
11672nta_outgoing_t *nta_outgoing_prack(nta_leg_t *leg,
11673 nta_outgoing_t *oorq,
11674 nta_response_f *callback,
11675 nta_outgoing_magic_t *magic,
11676 url_string_t const *route_url,
11677 sip_t const *resp,
11678 tag_type_t tag, tag_value_t value, ...)
11679{
11680 ta_list ta;
11681 msg_t *msg;
11682 su_home_t *home;
11683 sip_t *sip;
11684 sip_to_t const *to = NULL((void*)0);
11685 sip_route_t *route = NULL((void*)0), r0[1];
11686 nta_outgoing_t *orq = NULL((void*)0);
11687 sip_rack_t *rack = NULL((void*)0), rack0[1];
11688
11689 if (!leg || !oorq) {
11690 SU_DEBUG_1(("%s: invalid arguments\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 11690, "%s: invalid arguments\n", __func__)) : (void)0)
;
11691 return NULL((void*)0);
11692 }
11693
11694 sip_rack_init(rack0);
11695
11696 if (resp) {
11697 if (!resp->sip_status) {
11698 SU_DEBUG_1(("%s: invalid arguments\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 11698, "%s: invalid arguments\n", __func__)) : (void)0)
;
11699 return NULL((void*)0);
11700 }
11701
11702 if (resp->sip_status->st_status <= 100 ||
11703 resp->sip_status->st_status >= 200) {
11704 SU_DEBUG_1(("%s: %u response cannot be PRACKed\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 11705, "%s: %u response cannot be PRACKed\n", __func__, resp
->sip_status->st_status)) : (void)0)
11705 __func__, resp->sip_status->st_status))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 11705, "%s: %u response cannot be PRACKed\n", __func__, resp
->sip_status->st_status)) : (void)0)
;
11706 return NULL((void*)0);
11707 }
11708
11709 if (!resp->sip_rseq) {
11710 SU_DEBUG_1(("%s: %u response missing RSeq\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 11711, "%s: %u response missing RSeq\n", __func__, resp->
sip_status->st_status)) : (void)0)
11711 __func__, resp->sip_status->st_status))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 11711, "%s: %u response missing RSeq\n", __func__, resp->
sip_status->st_status)) : (void)0)
;
11712 return NULL((void*)0);
11713 }
11714
11715 if (resp->sip_rseq->rs_response <= oorq->orq_rseq) {
11716 SU_DEBUG_1(("%s: %u response RSeq does not match received RSeq\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 11717, "%s: %u response RSeq does not match received RSeq\n"
, __func__, resp->sip_status->st_status)) : (void)0)
11717 __func__, resp->sip_status->st_status))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 11717, "%s: %u response RSeq does not match received RSeq\n"
, __func__, resp->sip_status->st_status)) : (void)0)
;
11718 return NULL((void*)0);
11719 }
11720 if (!oorq->orq_must_100rel &&
11721 !sip_has_feature(resp->sip_require, "100rel")) {
11722 SU_DEBUG_1(("%s: %u response does not require 100rel\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 11723, "%s: %u response does not require 100rel\n", __func__
, resp->sip_status->st_status)) : (void)0)
11723 __func__, resp->sip_status->st_status))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 11723, "%s: %u response does not require 100rel\n", __func__
, resp->sip_status->st_status)) : (void)0)
;
11724 return NULL((void*)0);
11725 }
11726
11727 if (!resp->sip_to->a_tag) {
11728 SU_DEBUG_1(("%s: %u response has no To tag\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 11729, "%s: %u response has no To tag\n", __func__, resp->
sip_status->st_status)) : (void)0)
11729 __func__, resp->sip_status->st_status))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 11729, "%s: %u response has no To tag\n", __func__, resp->
sip_status->st_status)) : (void)0)
;
11730 return NULL((void*)0);
11731 }
11732 if (su_strcasecmp(resp->sip_to->a_tag, leg->leg_remote->a_tag) ||
11733 su_strcasecmp(resp->sip_to->a_tag, oorq->orq_to->a_tag)) {
11734 SU_DEBUG_1(("%s: %u response To tag does not agree with dialog tag\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 11735, "%s: %u response To tag does not agree with dialog tag\n"
, __func__, resp->sip_status->st_status)) : (void)0)
11735 __func__, resp->sip_status->st_status))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 11735, "%s: %u response To tag does not agree with dialog tag\n"
, __func__, resp->sip_status->st_status)) : (void)0)
;
11736 return NULL((void*)0);
11737 }
11738
11739 to = resp->sip_to;
11740 rack = rack0;
11741
11742 rack->ra_response = resp->sip_rseq->rs_response;
11743 rack->ra_cseq = resp->sip_cseq->cs_seq;
11744 rack->ra_method = resp->sip_cseq->cs_method;
11745 rack->ra_method_name = resp->sip_cseq->cs_method_name;
11746 }
11747
11748 msg = nta_msg_create(leg->leg_agent, 0);
11749 sip = sip_object(msg); home = msg_home(msg)((su_home_t*)(msg));
11750
11751 if (!sip)
11752 return NULL((void*)0);
11753
11754 if (!leg->leg_route && resp) {
11755 /* Insert contact into route */
11756 if (resp->sip_contact) {
11757 sip_route_init(r0)->r_url[0] = resp->sip_contact->m_url[0];
11758 route = sip_route_dup(home, r0);
11759 }
11760
11761 /* Reverse record route */
11762 if (resp->sip_record_route) {
11763 sip_route_t *r, *r_next;
11764 for (r = sip_route_dup(home, resp->sip_record_route); r; r = r_next) {
11765 r_next = r->r_next, r->r_next = route, route = r;
11766 }
11767 }
11768 }
11769
11770 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)
;
11771
11772 if (!resp) {
11773 tagi_t const *t;
11774
11775 if ((t = tl_find(ta_args(ta)(ta).tl, ntatag_rseq)) && t->t_value) {
11776 rack = rack0;
11777 rack->ra_response = (uint32_t)t->t_value;
11778 }
11779
11780 if (rack) {
11781 rack->ra_cseq = oorq->orq_cseq->cs_seq;
11782 rack->ra_method = oorq->orq_cseq->cs_method;
11783 rack->ra_method_name = oorq->orq_cseq->cs_method_name;
11784 }
11785 }
11786
11787 if (sip_add_tl(msg, sip,
11788 TAG_IF(rack, SIPTAG_RACK(rack))!(rack) ? tag_skip : siptag_rack, siptag_rack_v(rack),
11789 TAG_IF(to, SIPTAG_TO(to))!(to) ? tag_skip : siptag_to, siptag_to_v(to),
11790 ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
) < 0)
11791 ;
11792 else if (route && sip_add_dup(msg, sip, (sip_header_t *)route) < 0)
11793 ;
11794 else if (!sip->sip_rack)
11795 SU_DEBUG_1(("%s: RAck header missing\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__
, 11795, "%s: RAck header missing\n", __func__)) : (void)0)
;
11796 else if (nta_msg_request_complete(msg, leg,
11797 SIP_METHOD_PRACKsip_method_prack, "PRACK",
11798 (url_string_t *)oorq->orq_url) < 0)
11799 ;
11800 else
11801 orq = outgoing_create(leg->leg_agent, callback, magic,
11802 route_url, NULL((void*)0), msg, ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
);
11803
11804 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))
;
11805
11806 if (!orq)
11807 msg_destroy(msg);
11808 else if (rack)
11809 oorq->orq_rseq = rack->ra_response;
11810 else if (sip->sip_rack)
11811 oorq->orq_rseq = sip->sip_rack->ra_response;
11812
11813 return orq;
11814}
11815
11816/** Get @RSeq value stored with client transaction. */
11817uint32_t nta_outgoing_rseq(nta_outgoing_t const *orq)
11818{
11819 return orq ? orq->orq_rseq : 0;
11820}
11821
11822/** Set @RSeq value stored with client transaction.
11823 *
11824 * @return 0 if rseq was set successfully
11825 * @return -1 if rseq is invalid or orq is NULL.
11826 */
11827int nta_outgoing_setrseq(nta_outgoing_t *orq, uint32_t rseq)
11828{
11829 if (orq && orq->orq_rseq <= rseq) {
11830 orq->orq_rseq = rseq;
11831 return 0;
11832 }
11833
11834 return -1;
11835}
11836
11837/* ------------------------------------------------------------------------ */
11838/* 11) SigComp handling and public transport interface */
11839
11840#include <sofia-sip/nta_tport.h>
11841
11842/** Return the master transport for the agent.
11843 *
11844 * @NEW_1_12_11
11845 */
11846tport_t *
11847nta_agent_tports(nta_agent_t *agent)
11848{
11849 return agent ? agent->sa_tports : NULL((void*)0);
11850}
11851
11852su_inlinestatic inline tport_t *
11853nta_transport_(nta_agent_t *agent,
11854 nta_incoming_t *irq,
11855 msg_t *msg)
11856{
11857 if (irq)
11858 return irq->irq_tport;
11859 else if (agent && msg)
11860 return tport_delivered_by(agent->sa_tports, msg);
11861
11862 errno(*__errno_location ()) = EINVAL22;
11863 return NULL((void*)0);
11864}
11865
11866
11867/** Return a new reference to the transaction transport.
11868 *
11869 * @note The referenced transport must be unreferenced with tport_unref()
11870 */
11871tport_t *
11872nta_incoming_transport(nta_agent_t *agent,
11873 nta_incoming_t *irq,
11874 msg_t *msg)
11875{
11876 return tport_ref(nta_transport_(agent, irq, msg));
11877}
11878
11879nta_compressor_t *nta_agent_init_sigcomp(nta_agent_t *sa)
11880{
11881 if (!nta_compressor_vtable || !sa)
11882 return NULL((void*)0);
11883
11884 if (sa->sa_compressor == NULL((void*)0)) {
11885 char const * const *l = sa->sa_sigcomp_option_list;
11886 nta_compressor_t *comp;
11887 comp = nta_compressor_vtable->ncv_init_agent(sa, l);
11888 sa->sa_compressor = comp;
11889 }
11890
11891 return sa->sa_compressor;
11892}
11893
11894void nta_agent_deinit_sigcomp(nta_agent_t *sa)
11895{
11896 if (nta_compressor_vtable && sa && sa->sa_compressor) {
11897 nta_compressor_vtable->ncv_deinit_agent(sa, sa->sa_compressor);
11898 sa->sa_compressor = NULL((void*)0);
11899 }
11900}
11901
11902struct sigcomp_compartment *
11903nta_incoming_compartment(nta_incoming_t *irq)
11904{
11905 if (nta_compressor_vtable && irq && irq->irq_cc)
11906 return nta_compressor_vtable->ncv_compartment_ref(irq->irq_cc);
11907 else
11908 return NULL((void*)0);
11909}
11910
11911tport_t *
11912nta_outgoing_transport(nta_outgoing_t *orq)
11913{
11914 if (orq)
11915 return tport_ref(orq->orq_tport);
11916 else
11917 return NULL((void*)0);
11918}
11919
11920
11921struct sigcomp_compartment *
11922nta_outgoing_compartment(nta_outgoing_t *orq)
11923{
11924 if (nta_compressor_vtable && orq && orq->orq_cc)
11925 return nta_compressor_vtable->ncv_compartment_ref(orq->orq_cc);
11926 else
11927 return NULL((void*)0);
11928}
11929
11930
11931struct sigcomp_compartment *
11932nta_compartment_ref(struct sigcomp_compartment *cc)
11933{
11934 if (nta_compressor_vtable)
11935 return nta_compressor_vtable->ncv_compartment_ref(cc);
11936 else
11937 return NULL((void*)0);
11938}
11939
11940void
11941nta_compartment_decref(struct sigcomp_compartment **pcc)
11942{
11943 if (nta_compressor_vtable && pcc && *pcc)
11944 nta_compressor_vtable->ncv_compartment_unref(*pcc), *pcc = NULL((void*)0);
11945}
11946
11947
11948/** Get compartment for connection, create it when needed. */
11949static
11950struct sigcomp_compartment *
11951agent_compression_compartment(nta_agent_t *sa,
11952 tport_t *tp,
11953 tp_name_t const *tpn,
11954 int new_if_needed)
11955{
11956 if (nta_compressor_vtable) {
11957 char const * const *l = sa->sa_sigcomp_option_list;
11958 return nta_compressor_vtable->
11959 ncv_compartment(sa, tp, sa->sa_compressor, tpn, l, new_if_needed);
11960 }
11961 else
11962 return NULL((void*)0);
11963}
11964
11965static
11966int agent_accept_compressed(nta_agent_t *sa, msg_t *msg,
11967 struct sigcomp_compartment *cc)
11968{
11969 if (nta_compressor_vtable) {
11970 nta_compressor_t *msc = sa->sa_compressor;
11971 tport_compressor_t *sc = NULL((void*)0);
11972 if (tport_delivered_with_comp(sa->sa_tports, msg, &sc) < 0)
11973 return 0;
11974 return nta_compressor_vtable->ncv_accept_compressed(sa, msc, sc, msg, cc);
11975 }
11976 else
11977 return 0;
11978}
11979
11980/** Close compressor (lose its state). */
11981static
11982int agent_close_compressor(nta_agent_t *sa,
11983 struct sigcomp_compartment *cc)
11984{
11985 if (nta_compressor_vtable)
11986 return nta_compressor_vtable->ncv_close_compressor(sa, cc);
11987 return 0;
11988}
11989
11990/** Close both compressor and decompressor */
11991static
11992int agent_zap_compressor(nta_agent_t *sa,
11993 struct sigcomp_compartment *cc)
11994{
11995 if (nta_compressor_vtable)
11996 return nta_compressor_vtable->ncv_zap_compressor(sa, cc);
11997 return 0;
11998}
11999
12000/** Bind transport update callback */
12001int nta_agent_bind_tport_update(nta_agent_t *agent,
12002 nta_update_magic_t *magic,
12003 nta_update_tport_f *callback)
12004{
12005 if (!agent)
12006 return su_seterrno(EFAULT14), -1;
12007 agent->sa_update_magic = magic;
12008 agent->sa_update_tport = callback;
12009 return 0;
12010}
12011
12012/** Bind transport error callback */
12013int nta_agent_bind_tport_error(nta_agent_t *agent,
12014 nta_error_magic_t *magic,
12015 nta_error_tport_f *callback)
12016{
12017 if (!agent)
12018 return su_seterrno(EFAULT14), -1;
12019 agent->sa_error_magic = magic;
12020 agent->sa_error_tport = callback;
12021 return 0;
12022}
12023
12024/** Check if public transport binding is in progress */
12025int nta_agent_tport_is_updating(nta_agent_t *agent)
12026{
12027 return agent && tport_is_updating(agent->sa_tports);
12028}
12029
12030/** Initiate STUN keepalive controller to TPORT */
12031int nta_tport_keepalive(nta_outgoing_t *orq)
12032{
12033 assert(orq)((void) sizeof ((orq) ? 1 : 0), __extension__ ({ if (orq) ; else
__assert_fail ("orq", "nta.c", 12033, __extension__ __PRETTY_FUNCTION__
); }))
;
12034
12035#if HAVE_SOFIA_STUN
12036 return tport_keepalive(orq->orq_tport, msg_addrinfo(orq->orq_request),
12037 TAG_END()(tag_type_t)0, (tag_value_t)0);
12038#else
12039 return -1;
12040#endif
12041}
12042
12043/** Close all transports. @since Experimental in @VERSION_1_12_2. */
12044int nta_agent_close_tports(nta_agent_t *agent)
12045{
12046 size_t i;
12047 outgoing_htable_t *oht = agent->sa_outgoing;
12048 incoming_htable_t *iht = agent->sa_incoming;
12049
12050 for (i = oht->oht_size; i-- > 0;)
12051 /* while */ if (oht->oht_table[i]) {
12052 nta_outgoing_t *orq = oht->oht_table[i];
12053
12054 if (orq->orq_pending && orq->orq_tport)
12055 tport_release(orq->orq_tport, orq->orq_pending, orq->orq_request,
12056 NULL((void*)0), orq, 0);
12057
12058 orq->orq_pending = 0;
12059 tport_unref(orq->orq_tport), orq->orq_tport = NULL((void*)0);
12060 }
12061
12062
12063 for (i = iht->iht_size; i-- > 0;)
12064 /* while */ if (iht->iht_table[i]) {
12065 nta_incoming_t *irq = iht->iht_table[i];
12066 tport_unref(irq->irq_tport), irq->irq_tport = NULL((void*)0);
12067 }
12068
12069 tport_destroy(agent->sa_tports), agent->sa_tports = NULL((void*)0);
12070
12071 msg_header_free(agent->sa_home, (void *)agent->sa_vias);
12072 agent->sa_vias = NULL((void*)0);
12073 msg_header_free(agent->sa_home, (void *)agent->sa_public_vias);
12074 agent->sa_public_vias = NULL((void*)0);
12075
12076 return 0;
12077}