Bug Summary

File:libsofia-sip-ua/nta/nta.c
Warning:line 5721, column 3
Access to field 'q_tail' results in a dereference of a null pointer (loaded from variable 'queue')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -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-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 -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib/llvm-11/lib/clang/11.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-11/lib/clang/11.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 -fgnuc-version=4.2.1 -analyzer-output=html -faddrsig -o /drone/src/scan-build/2022-06-23-181620-12-1 -x c nta.c
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.8";
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 usize_t sa_max_recv_requests_per_second; /**< Maximum receiving requests per second */
183
184 unsigned sa_udp_mtu; /**< Maximum size of outgoing UDP requests */
185
186 unsigned sa_t1; /**< SIP T1 - initial retransmit interval (500 ms) */
187 unsigned sa_t2; /**< SIP T2 - maximum retransmit interval (4000 ms) */
188 unsigned sa_t4; /**< SIP T4 - clear message time (5000 ms) */
189
190
191 unsigned sa_t1x64; /**< SIP T1X64 - transaction lifetime (32 s) */
192
193 unsigned sa_tls_orq_connect_timeout; /**< Connect Timeout for outgoing requests using TLS (ms) */
194
195 unsigned sa_progress; /**< Progress timer.
196 Interval between retransmitting
197 provisional responses. */
198
199 unsigned sa_timer_c; /**< SIP timer C.
200 Maximum interval between receiving
201 provisional responses. */
202
203 unsigned sa_graylist; /**< Graylisting period */
204 unsigned sa_blacklist; /**< Blacklisting period */
205
206 unsigned sa_drop_prob : 10; /**< NTA is used to test packet drop */
207 unsigned sa_is_a_uas : 1; /**< NTA is acting as an User Agent server */
208 unsigned sa_is_stateless : 1; /**< Process requests statelessly
209 * unless they match existing dialog.
210 */
211 unsigned sa_user_via:1; /**< Let application provide @Via headers */
212 unsigned sa_extra_100:1; /**< Allow NTA to return "100 Trying" response
213 * even if application has not responded.
214 */
215 unsigned sa_pass_100:1; /**< Pass the "100 Trying"
216 * provisional responses to the application
217 */
218 unsigned sa_timeout_408:1; /**< A "408 Request Timeout" message
219 * is generated when outgoing request expires.
220 */
221 unsigned sa_pass_408:1; /**< A "408 Request Timeout" responses
222 * are passed to client.
223 */
224 unsigned sa_merge_482 : 1; /**< A "482 Request Merged" response is returned
225 * to merged requests.
226 */
227 unsigned sa_cancel_2543 : 1; /**< Send a CANCEL to an INVITE without
228 * waiting for an provisional response.
229 */
230 unsigned sa_cancel_487 : 1; /**< Return 487 response automatically when
231 * a CANCEL is received.
232 */
233
234 unsigned sa_invite_100rel:1; /**< Include 100rel in INVITE requests. */
235 unsigned sa_timestamp : 1; /**< Insert @Timestamp in requests. */
236
237 unsigned sa_tport_ip4 : 1; /**< Transports support IPv4. */
238 unsigned sa_tport_ip6 : 1; /**< Transports support IPv6. */
239 unsigned sa_tport_udp : 1; /**< Transports support UDP. */
240 unsigned sa_tport_tcp : 1; /**< Transports support TCP. */
241 unsigned sa_tport_sctp : 1; /**< Transports support SCTP. */
242 unsigned sa_tport_tls : 1; /**< Transports support TLS. */
243 unsigned sa_tport_ws : 1; /**< Transports support WS. */
244 unsigned sa_tport_wss : 1; /**< Transports support WSS. */
245
246 unsigned sa_use_naptr : 1; /**< Use NAPTR lookup */
247 unsigned sa_use_srv : 1; /**< Use SRV lookup */
248
249 unsigned sa_srv_503 : 1; /**< SRV: choice another destination on 503 RFC 3263 */
250
251 unsigned sa_tport_threadpool:1; /**< Transports use threadpool */
252
253 unsigned sa_rport:1; /**< Use rport at client */
254 unsigned sa_server_rport:2; /**< Use rport at server */
255 unsigned sa_tcp_rport:1; /**< Use rport with tcp, too */
256 unsigned sa_tls_rport:1; /**< Use rport with tls, too */
257
258 unsigned sa_auto_comp:1; /**< Automatically create compartments */
259 unsigned sa_in_timer:1; /**< Set when executing timers */
260 unsigned sa_use_timer_c:1; /**< Application has set value for timer C */
261
262 unsigned :0;
263
264#if HAVE_SMIME
265 sm_object_t *sa_smime;
266#else
267 void *sa_smime;
268#endif
269
270 /** @MaxForwards */
271 sip_max_forwards_t sa_max_forwards[1];
272
273 /** Name of SigComp algorithm */
274 char const *sa_algorithm;
275 /** Options for SigComp. */
276 char const *sa_sigcomp_options;
277 char const* const *sa_sigcomp_option_list;
278 char const *sa_sigcomp_option_free;
279
280 nta_compressor_t *sa_compressor;
281
282 /* Statistics */
283 struct {
284 usize_t as_recv_msg;
285 usize_t as_recv_request;
286 usize_t as_recv_response;
287 usize_t as_bad_message;
288 usize_t as_bad_request;
289 usize_t as_bad_response;
290 usize_t as_drop_request;
291 usize_t as_drop_response;
292 usize_t as_client_tr;
293 usize_t as_server_tr;
294 usize_t as_dialog_tr;
295 usize_t as_acked_tr;
296 usize_t as_canceled_tr;
297 usize_t as_trless_request;
298 usize_t as_trless_to_tr;
299 usize_t as_trless_response;
300 usize_t as_trless_200;
301 usize_t as_merged_request;
302 usize_t as_sent_msg;
303 usize_t as_sent_request;
304 usize_t as_sent_response;
305 usize_t as_retry_request;
306 usize_t as_retry_response;
307 usize_t as_recv_retry;
308 usize_t as_tout_request;
309 usize_t as_tout_response;
310 } sa_stats[1];
311
312 /** Current load in receiving messages per second */
313 struct {
314 usize_t as_recv_request_last;
315 su_time_t last_time;
316 unsigned requests_per_second;
317 } sa_load[1];
318
319 /** Hash of dialogs. */
320 leg_htable_t sa_dialogs[1];
321 /** Default leg */
322 nta_leg_t *sa_default_leg;
323 /** Hash of legs without dialogs. */
324 leg_htable_t sa_defaults[1];
325 /** Hash table for outgoing transactions */
326 outgoing_htable_t sa_outgoing[1];
327 nta_outgoing_t *sa_default_outgoing;
328 /** Hash table for incoming transactions */
329 incoming_htable_t sa_incoming[1];
330 nta_incoming_t *sa_default_incoming;
331
332 /* Queues (states) for outgoing client transactions */
333 struct {
334 /** Queue for retrying client transactions */
335 nta_outgoing_t *re_list;
336 nta_outgoing_t **re_t1; /**< Special place for T1 timer */
337 size_t re_length; /**< Length of sa_out.re_list */
338
339 outgoing_queue_t delayed[1];
340 outgoing_queue_t resolving[1];
341
342 outgoing_queue_t trying[1]; /* Timer F / Timer E */
343 outgoing_queue_t completed[1]; /* Timer K */
344 outgoing_queue_t terminated[1];
345
346 /* Special queues (states) for outgoing INVITE transactions */
347 outgoing_queue_t inv_calling[1]; /* Timer B/A */
348 outgoing_queue_t inv_proceeding[1]; /* Timer C */
349 outgoing_queue_t inv_completed[1]; /* Timer D */
350
351 /* Temporary queue for transactions waiting to be freed */
352 outgoing_queue_t *free;
353 } sa_out;
354
355 /* Queues (states) for incoming server transactions */
356 struct {
357 /** Queue for retransmitting response of server transactions */
358 nta_incoming_t *re_list;
359 nta_incoming_t **re_t1; /**< Special place for T1 timer */
360 size_t re_length; /**< Length of sa_in.re_list */
361
362 incoming_queue_t proceeding[1]; /**< Request received */
363 incoming_queue_t preliminary[1]; /**< 100rel sent */
364 incoming_queue_t completed[1]; /**< Final answer sent (non-invite). */
365 incoming_queue_t inv_completed[1]; /**< Final answer sent (INVITE). */
366 incoming_queue_t inv_confirmed[1]; /**< Final answer sent, ACK recvd. */
367 incoming_queue_t terminated[1]; /**< Terminated, ready to free. */
368 incoming_queue_t final_failed[1];
369 } sa_in;
370
371 /* Special task for freeing memory */
372 su_clone_r sa_terminator;
373};
374
375struct nta_leg_s
376{
377 su_home_t leg_home[1];
378 hash_value_t leg_hash;
379
380 unsigned leg_dialog : 1;
381 unsigned leg_stateless : 1; /**< Process requests statelessly */
382#ifdef NTA_STRICT_ROUTING
383 unsigned leg_contact_set : 1;
384#else
385 unsigned leg_loose_route : 1; /**< Topmost route in set is LR */
386#endif
387 unsigned leg_route_set : 1; /**< Route set has been saved */
388 unsigned leg_local_is_to : 1; /**< Backwards-compatibility. */
389 unsigned leg_tagged : 1; /**< Tagged after creation.
390 *
391 * Request missing @To tag matches
392 * a tagged leg even after tagging.
393 */
394 unsigned leg_compressed:1;
395 unsigned:0;
396 nta_request_f *leg_callback;
397 nta_leg_magic_t *leg_magic;
398 nta_agent_t *leg_agent;
399
400 url_t const *leg_url; /**< Match incoming requests. */
401 char const *leg_method; /**< Match incoming requests. */
402
403 uint32_t leg_seq; /**< Sequence number for next transaction */
404 uint32_t leg_rseq; /**< Remote sequence number */
405 sip_call_id_t *leg_id; /**< Call ID */
406 sip_from_t *leg_remote; /**< Remote address (@To/@From) */
407 sip_to_t *leg_local; /**< Local address (@From/@To) */
408
409 sip_route_t *leg_route; /**< @Route for outgoing requests. */
410 sip_contact_t *leg_target; /**< Remote destination (from @Contact). */
411};
412
413struct nta_incoming_s
414{
415 su_home_t *irq_home;
416 hash_value_t irq_hash;
417 nta_agent_t *irq_agent;
418 nta_ack_cancel_f *irq_callback;
419 nta_incoming_magic_t *irq_magic;
420
421 /* Timeout/state queue */
422 nta_incoming_t **irq_prev;
423 nta_incoming_t *irq_next;
424 incoming_queue_t *irq_queue;
425
426 /* Retry queue */
427 nta_incoming_t **irq_rprev;
428 nta_incoming_t *irq_rnext;
429
430 sip_method_t irq_method;
431 sip_request_t *irq_rq;
432 sip_from_t *irq_from;
433 sip_to_t *irq_to;
434 char const *irq_tag;
435 sip_cseq_t *irq_cseq;
436 sip_call_id_t *irq_call_id;
437 sip_via_t *irq_via;
438 sip_record_route_t *irq_record_route;
439 char const *irq_branch;
440
441 uint32_t irq_rseq;
442
443 sip_timestamp_t *irq_timestamp;
444 su_time_t irq_received;
445
446 uint32_t irq_timeout; /**< Timer H, I, J */
447 uint32_t irq_retry; /**< Timer G */
448 unsigned short irq_interval; /**< Next timer */
449
450 short irq_status;
451
452 unsigned irq_retries:8;
453 unsigned irq_default:1; /**< Default transaction */
454 unsigned irq_canceled:1; /**< Transaction is canceled */
455 unsigned irq_completed:1; /**< Transaction is completed */
456 unsigned irq_confirmed:1; /**< Response has been acked */
457 unsigned irq_terminated:1; /**< Transaction is terminated */
458 unsigned irq_final_failed:1; /**< Sending final response failed */
459 unsigned irq_destroyed :1; /**< Transaction is destroyed */
460 unsigned irq_in_callback:1; /**< Callback is being invoked */
461 unsigned irq_reliable_tp:1; /**< Transport is reliable */
462 unsigned irq_sigcomp_zap:1; /**< Reset SigComp */
463 unsigned irq_must_100rel:1; /**< 100rel is required */
464 unsigned irq_extra_100:1; /**< 100 Trying should be sent */
465 unsigned irq_tag_set:1; /**< Tag is not from request */
466 unsigned irq_compressed:1;
467 unsigned :0;
468
469 tp_name_t irq_tpn[1];
470 tport_t *irq_tport;
471 struct sigcomp_compartment *irq_cc;
472 msg_t *irq_request;
473 msg_t *irq_request2; /**< ACK/CANCEL */
474 msg_t *irq_response;
475
476 nta_reliable_t *irq_reliable; /**< List of reliable responses */
477};
478
479struct nta_reliable_s
480{
481 nta_reliable_t *rel_next;
482 nta_incoming_t *rel_irq;
483 nta_prack_f *rel_callback;
484 nta_reliable_magic_t *rel_magic;
485 uint32_t rel_rseq;
486 unsigned short rel_status;
487 unsigned rel_pracked:1;
488 unsigned rel_precious:1;
489 msg_t *rel_response;
490 msg_t *rel_unsent;
491};
492
493typedef struct sipdns_resolver sipdns_resolver_t;
494
495struct nta_outgoing_s
496{
497 hash_value_t orq_hash; /**< Hash value */
498 nta_agent_t *orq_agent;
499 nta_response_f *orq_callback;
500 nta_outgoing_magic_t *orq_magic;
501
502 /* Timeout/state queue */
503 nta_outgoing_t **orq_prev;
504 nta_outgoing_t *orq_next;
505 outgoing_queue_t *orq_queue;
506
507 /* Retry queue */
508 nta_outgoing_t **orq_rprev;
509 nta_outgoing_t *orq_rnext;
510
511 sip_method_t orq_method;
512 char const *orq_method_name;
513 url_t const *orq_url; /**< Original RequestURI */
514
515 sip_from_t const *orq_from;
516 sip_to_t const *orq_to;
517 char const *orq_tag; /**< Tag from final response. */
518
519 sip_cseq_t const *orq_cseq;
520 sip_call_id_t const *orq_call_id;
521
522 msg_t *orq_request;
523 msg_t *orq_response;
524
525 su_time_t orq_sent; /**< When request was sent? */
526 unsigned orq_delay; /**< RTT estimate */
527
528 uint32_t orq_retry; /**< Timer A, E */
529 uint32_t orq_timeout; /**< Timer B, D, F, K */
530
531 unsigned short orq_interval; /**< Next timer A/E */
532
533 unsigned short orq_status;
534 unsigned char orq_retries; /**< Number of tries this far */
535
536 unsigned orq_default:1; /**< This is default transaction */
537 unsigned orq_inserted:1;
538 unsigned orq_resolved:1;
539 unsigned orq_via_added:1;
540 unsigned orq_prepared:1;
541 unsigned orq_canceled:1;
542 unsigned orq_terminated:1;
543 unsigned orq_destroyed:1;
544 unsigned orq_completed:1;
545 unsigned orq_delayed:1;
546 unsigned orq_user_tport:1; /**< Application provided tport - don't retry */
547 unsigned orq_try_tcp_instead:1;
548 unsigned orq_try_udp_instead:1;
549 unsigned orq_reliable:1; /**< Transport is reliable */
550 unsigned orq_call_tls_connect_timeout_is_set:1; /** Per Call connect timeout for outgoing requests using TLS set flag*/
551
552 unsigned orq_forked:1; /**< Tagged fork */
553
554 /* Attributes */
555 unsigned orq_sips:1;
556 unsigned orq_uas:1; /**< Running this transaction as UAS */
557 unsigned orq_user_via:1;
558 unsigned orq_stateless:1;
559 unsigned orq_pass_100:1;
560 unsigned orq_sigcomp_new:1; /**< Create compartment if needed */
561 unsigned orq_sigcomp_zap:1; /**< Reset SigComp after completing */
562 unsigned orq_must_100rel:1;
563 unsigned orq_timestamp:1; /**< Insert @Timestamp header. */
564 unsigned orq_100rel:1; /**< Support 100rel */
565 unsigned:0; /* pad */
566
567#if HAVE_SOFIA_SRESOLV1
568 sipdns_resolver_t *orq_resolver;
569#endif
570 url_t *orq_route; /**< Route URL */
571 tp_name_t orq_tpn[1]; /**< Where to send request */
572
573 tport_t *orq_tport;
574 struct sigcomp_compartment *orq_cc;
575 tagi_t *orq_tags; /**< Tport tag items */
576
577 char const *orq_branch; /**< Transaction branch */
578 char const *orq_via_branch; /**< @Via branch */
579
580 int *orq_status2b; /**< Delayed response */
581
582 nta_outgoing_t *orq_cancel; /**< Delayed CANCEL transaction */
583
584 nta_outgoing_t *orq_forking; /**< Untagged transaction */
585 nta_outgoing_t *orq_forks; /**< Tagged transactions */
586 uint32_t orq_rseq; /**< Latest incoming rseq */
587 int orq_pending; /**< Request is pending in tport */
588 uint32_t orq_call_tls_connect_timeout; /** Per Call connect timeout for outgoing requests using TLS */
589};
590
591/* ------------------------------------------------------------------------- */
592
593/* Internal tags */
594
595/* Delay sending of request */
596#define NTATAG_DELAY_SENDING(x)ntatag_delay_sending, tag_bool_v((x)) ntatag_delay_sending, tag_bool_v((x))
597#define NTATAG_DELAY_SENDING_REF(x)ntatag_delay_sending_ref, tag_bool_vr(&(x)) \
598ntatag_delay_sending_ref, tag_bool_vr(&(x))
599
600extern tag_typedef_t ntatag_delay_sending;
601extern tag_typedef_t ntatag_delay_sending_ref;
602
603/* Allow sending incomplete responses */
604#define NTATAG_INCOMPLETE(x)ntatag_incomplete, tag_bool_v((x)) ntatag_incomplete, tag_bool_v((x))
605#define NTATAG_INCOMPLETE_REF(x)ntatag_incomplete_ref, tag_bool_vr(&(x)) \
606ntatag_incomplete_ref, tag_bool_vr(&(x))
607
608extern tag_typedef_t ntatag_incomplete;
609extern tag_typedef_t ntatag_incomplete_ref;
610
611nta_compressor_vtable_t *nta_compressor_vtable = NULL((void*)0);
612
613/* Agent */
614static int agent_tag_init(nta_agent_t *self);
615static int agent_timer_init(nta_agent_t *agent);
616static void agent_timer(su_root_magic_t *rm, su_timer_t *, nta_agent_t *);
617static int agent_launch_terminator(nta_agent_t *agent);
618static void agent_kill_terminator(nta_agent_t *agent);
619static int agent_set_params(nta_agent_t *agent, tagi_t *tags);
620static void agent_set_udp_params(nta_agent_t *self, usize_t udp_mtu);
621static int agent_get_params(nta_agent_t *agent, tagi_t *tags);
622
623/* Transport interface */
624static sip_via_t const *agent_tport_via(tport_t *tport);
625static int outgoing_insert_via(nta_outgoing_t *orq, sip_via_t const *);
626static int nta_tpn_by_via(tp_name_t *tpn, sip_via_t const *v, int *using_rport);
627
628static msg_t *nta_msg_create_for_transport(nta_agent_t *agent, int flags,
629 char const data[], usize_t dlen,
630 tport_t const *tport,
631 tp_client_t *via);
632
633static int complete_response(msg_t *response,
634 int status, char const *phrase,
635 msg_t *request);
636
637static int mreply(nta_agent_t *agent,
638 msg_t *reply,
639 int status, char const *phrase,
640 msg_t *req_msg,
641 tport_t *tport,
642 int incomplete,
643 int sdwn_after,
644 char const *to_tag,
645 tag_type_t tag, tag_value_t value, ...);
646
647#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))
,
648#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),
649
650struct sigcomp_compartment;
651
652struct sigcomp_compartment *
653nta_compartment_ref(struct sigcomp_compartment *cc);
654
655static
656struct sigcomp_compartment *
657agent_compression_compartment(nta_agent_t *sa, tport_t *tp, tp_name_t const *tpn,
658 int new_if_needed);
659
660static
661int agent_accept_compressed(nta_agent_t *sa, msg_t *msg,
662 struct sigcomp_compartment *cc);
663
664static int agent_close_compressor(nta_agent_t *sa,
665 struct sigcomp_compartment *cc);
666
667static int agent_zap_compressor(nta_agent_t *sa,
668 struct sigcomp_compartment *cc);
669
670
671static char const * stateful_branch(su_home_t *home, nta_agent_t *);
672static char const * stateless_branch(nta_agent_t *, msg_t *, sip_t const *,
673 tp_name_t const *tp);
674
675#define NTA_BRANCH_PRIME(uint64_t)(0xB9591D1C361C6521ULL) SU_U64_C(0xB9591D1C361C6521)(uint64_t)(0xB9591D1C361C6521ULL)
676#define NTA_TAG_PRIME(uint64_t)(0xB9591D1C361C6521ULL) SU_U64_C(0xB9591D1C361C6521)(uint64_t)(0xB9591D1C361C6521ULL)
677
678#ifndef UINT32_MAX(4294967295U)
679#define UINT32_MAX(4294967295U) (0xffffffffU)
680#endif
681
682HTABLE_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)
;
683static nta_leg_t *leg_find(nta_agent_t const *sa,
684 char const *method_name,
685 url_t const *request_uri,
686 sip_call_id_t const *i,
687 char const *from_tag,
688 char const *to_tag);
689static nta_leg_t *dst_find(nta_agent_t const *sa, url_t const *u0,
690 char const *method);
691static void leg_recv(nta_leg_t *, msg_t *, sip_t *, tport_t *);
692static void leg_free(nta_agent_t *sa, nta_leg_t *leg);
693
694#define NTA_HASH(i, cs)((i)->i_hash + 26839U * (uint32_t)(cs)) ((i)->i_hash + 26839U * (uint32_t)(cs))
695
696HTABLE_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)
;
697static nta_incoming_t *incoming_create(nta_agent_t *agent,
698 msg_t *request,
699 sip_t *sip,
700 tport_t *tport,
701 char const *tag);
702static int incoming_callback(nta_leg_t *leg, nta_incoming_t *irq, sip_t *sip);
703static void incoming_free(nta_incoming_t *irq);
704su_inlinestatic inline void incoming_cut_off(nta_incoming_t *irq);
705su_inlinestatic inline void incoming_reclaim(nta_incoming_t *irq);
706static void incoming_queue_init(incoming_queue_t *,
707 unsigned timeout);
708static void incoming_queue_adjust(nta_agent_t *sa,
709 incoming_queue_t *queue,
710 unsigned timeout);
711
712static nta_incoming_t *incoming_find(nta_agent_t const *agent,
713 sip_t const *sip,
714 sip_via_t const *v,
715 nta_incoming_t **merge,
716 nta_incoming_t **ack,
717 nta_incoming_t **cancel);
718static int incoming_reply(nta_incoming_t *irq, msg_t *msg, sip_t *sip);
719su_inlinestatic inline int incoming_recv(nta_incoming_t *irq, msg_t *msg, sip_t *sip,
720 tport_t *tport);
721su_inlinestatic inline int incoming_ack(nta_incoming_t *irq, msg_t *msg, sip_t *sip,
722 tport_t *tport);
723su_inlinestatic inline int incoming_cancel(nta_incoming_t *irq, msg_t *msg, sip_t *sip,
724 tport_t *tport);
725static void request_merge(nta_agent_t *,
726 msg_t *msg, sip_t *sip, tport_t *tport,
727 char const *to_tag);
728su_inlinestatic inline int incoming_timestamp(nta_incoming_t *, msg_t *, sip_t *);
729static void _nta_incoming_timer(nta_agent_t *);
730
731static nta_reliable_t *reliable_mreply(nta_incoming_t *,
732 nta_prack_f *, nta_reliable_magic_t *,
733 msg_t *, sip_t *);
734static int reliable_send(nta_incoming_t *, nta_reliable_t *, msg_t *, sip_t *);
735static int reliable_final(nta_incoming_t *irq, msg_t *msg, sip_t *sip);
736static msg_t *reliable_response(nta_incoming_t *irq);
737static nta_reliable_t *reliable_find(nta_agent_t const *, sip_t const *);
738static int reliable_recv(nta_reliable_t *rel, msg_t *, sip_t *, tport_t *);
739static void reliable_flush(nta_incoming_t *irq);
740static void reliable_timeout(nta_incoming_t *irq, int timeout);
741
742HTABLE_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)
;
743static nta_outgoing_t *outgoing_create(nta_agent_t *agent,
744 nta_response_f *callback,
745 nta_outgoing_magic_t *magic,
746 url_string_t const *route_url,
747 tp_name_t const *tpn,
748 msg_t *msg,
749 tag_type_t tag, tag_value_t value, ...);
750static void outgoing_queue_init(outgoing_queue_t *,
751 unsigned timeout);
752static void outgoing_queue_adjust(nta_agent_t *sa,
753 outgoing_queue_t *queue,
754 unsigned timeout);
755static void outgoing_free(nta_outgoing_t *orq);
756su_inlinestatic inline void outgoing_cut_off(nta_outgoing_t *orq);
757su_inlinestatic inline void outgoing_reclaim(nta_outgoing_t *orq);
758static nta_outgoing_t *outgoing_find(nta_agent_t const *sa,
759 msg_t const *msg,
760 sip_t const *sip,
761 sip_via_t const *v);
762static int outgoing_recv(nta_outgoing_t *orq, int status, msg_t *, sip_t *);
763static void outgoing_default_recv(nta_outgoing_t *, int, msg_t *, sip_t *);
764static void _nta_outgoing_timer(nta_agent_t *);
765static int outgoing_recv_reliable(nta_outgoing_t *orq, msg_t *msg, sip_t *sip);
766
767/* Internal message passing */
768union sm_arg_u {
769 struct outgoing_recv_s {
770 nta_outgoing_t *orq;
771 msg_t *msg;
772 sip_t *sip;
773 int status;
774 } a_outgoing_recv[1];
775
776 incoming_queue_t a_incoming_queue[1];
777 outgoing_queue_t a_outgoing_queue[1];
778};
779
780/* Global module data */
781
782/**@var char const NTA_DEBUG[];
783 *
784 * Environment variable determining the default debug log level.
785 *
786 * The NTA_DEBUG environment variable is used to determine the default
787 * debug logging level. The normal level is 3.
788 *
789 * @sa <sofia-sip/su_debug.h>, #su_log_global, #SOFIA_DEBUG
790 */
791#ifdef DOXYGEN
792extern char const NTA_DEBUG[]; /* dummy declaration for Doxygen */
793#endif
794
795#ifndef SU_DEBUG0
796#define SU_DEBUG0 3
797#endif
798
799/**Debug log for @b nta module.
800 *
801 * The nta_log is the log object used by @b nta module. The level of
802 * nta_log is set using #NTA_DEBUG environment variable.
803 */
804su_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), }
};
805
806/* ====================================================================== */
807/* 1) Agent */
808
809/**
810 * Create an NTA agent object.
811 *
812 * Create an NTA agent object. The agent
813 * object creates and binds a server socket with address specified in @e url.
814 * If the @e host portion of the @e url is @c "*", the agent listens to all
815 * addresses available on the host.
816 *
817 * When a message is received, the agent object parses it. If the result is
818 * a valid SIP message, the agent object passes the message to the
819 * application by invoking the nta_message_f @e callback function.
820 *
821 * @note
822 * The @e url can be either parsed url (of type url_t ()), or a valid
823 * SIP URL as a string.
824 *
825 * @note
826 * If @e url is @c NULL, the default @e url @c "sip:*" is used.
827 * @par
828 * If @e url is @c NONE (iow, (void*)-1), no server sockets are bound.
829 * @par
830 * If @p transport parameters are specified in @a url, agent uses only
831 * specified transport type.
832 *
833 * @par
834 * If an @p maddr parameter is specified in @e url, agent binds to the
835 * specified address, but uses @e host part of @e url when it generates
836 * @Contact and @Via headers. The @p maddr parameter is also included,
837 * unless it equals to @c INADDR_ANY (@p 0.0.0.0 or @p [::]).
838 *
839 * @param root pointer to a su_root_t used for synchronization
840 * @param contact_url URL that agent uses to bind the server sockets
841 * @param callback pointer to callback function
842 * @param magic pointer to user data
843 * @param tag,value,... tagged arguments
844 *
845 * @TAGS
846 * NTATAG_ALIASES(),
847 * NTATAG_BAD_REQ_MASK(), NTATAG_BAD_RESP_MASK(), NTATAG_BLACKLIST(),
848 * NTATAG_CANCEL_2543(), NTATAG_CANCEL_487(), NTATAG_CLIENT_RPORT(),
849 * NTATAG_DEBUG_DROP_PROB(), NTATAG_DEFAULT_PROXY(),
850 * NTATAG_EXTRA_100(), NTATAG_GRAYLIST(),
851 * NTATAG_MAXSIZE(), NTATAG_MAX_FORWARDS(), NTATAG_MERGE_482(), NTATAG_MCLASS()
852 * NTATAG_PASS_100(), NTATAG_PASS_408(), NTATAG_PRELOAD(), NTATAG_PROGRESS(),
853 * NTATAG_REL100(),
854 * NTATAG_SERVER_RPORT(),
855 * NTATAG_SIPFLAGS(),
856 * NTATAG_SIP_T1X64(), NTATAG_SIP_T1(), NTATAG_SIP_T2(), NTATAG_SIP_T4(),
857 * NTATAG_STATELESS(),
858 * NTATAG_TAG_3261(), NTATAG_TCP_RPORT(), NTATAG_TIMEOUT_408(),
859 * NTATAG_TLS_RPORT(), NTATAG_TLS_ORQ_CONNECT_TIMEOUT(),
860 * NTATAG_TIMER_C(), NTATAG_MAX_PROCEEDING(),
861 * NTATAG_UA(), NTATAG_UDP_MTU(), NTATAG_USER_VIA(),
862 * NTATAG_USE_NAPTR(), NTATAG_USE_SRV() and NTATAG_USE_TIMESTAMP().
863 *
864 * @note The value from following tags are stored, but they currently do nothing:
865 * NTATAG_SIGCOMP_ALGORITHM(), NTATAG_SIGCOMP_OPTIONS(), NTATAG_SMIME()
866 *
867 * @note It is possible to provide @c (url_string_t*)-1 as @a contact_url.
868 * In that case, no server sockets are bound.
869 *
870 * @retval handle to the agent when successful,
871 * @retval NULL upon an error.
872 *
873 * @sa NUTAG_
874 */
875nta_agent_t *nta_agent_create(su_root_t *root,
876 url_string_t const *contact_url,
877 nta_message_f *callback,
878 nta_agent_magic_t *magic,
879 tag_type_t tag, tag_value_t value, ...)
880{
881 nta_agent_t *agent;
882 ta_list ta;
883
884 if (root == NULL((void*)0))
885 return su_seterrno(EINVAL22), NULL((void*)0);
886
887 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)
;
888
889 if ((agent = su_home_new(sizeof(*agent)))) {
890 unsigned timer_c = 0, timer_d = 32000;
891
892 agent->sa_root = root;
893 agent->sa_callback = callback;
894 agent->sa_magic = magic;
895 agent->sa_flags = MSG_DO_CANONICMSG_FLG_CANONIC;
896
897 agent->sa_maxsize = 2 * 1024 * 1024; /* 2 MB */
898 agent->sa_bad_req_mask =
899 /*
900 * Bit-wise not of these - what is left is suitable for UAs with
901 * 100rel, timer, events, publish
902 */
903 (unsigned) ~(sip_mask_response | sip_mask_proxy | sip_mask_registrar |
904 sip_mask_pref | sip_mask_privacy);
905 agent->sa_bad_resp_mask =
906 (unsigned) ~(sip_mask_request | sip_mask_proxy | sip_mask_registrar |
907 sip_mask_pref | sip_mask_privacy);
908 agent->sa_t1 = NTA_SIP_T1;
909 agent->sa_t2 = NTA_SIP_T2;
910 agent->sa_t4 = NTA_SIP_T4;
911 agent->sa_t1x64 = 64 * NTA_SIP_T1;
912 agent->sa_timer_c = 185 * 1000;
913 agent->sa_graylist = 600;
914 agent->sa_drop_prob = 0;
915 agent->sa_is_a_uas = 0;
916 agent->sa_progress = 60 * 1000;
917 agent->sa_user_via = 0;
918 agent->sa_extra_100 = 0;
919 agent->sa_pass_100 = 0;
920 agent->sa_timeout_408 = 1;
921 agent->sa_pass_408 = 0;
922 agent->sa_merge_482 = 0;
923 agent->sa_cancel_2543 = 0;
924 agent->sa_cancel_487 = 1;
925 agent->sa_invite_100rel = 0;
926 agent->sa_timestamp = 0;
927 agent->sa_use_naptr = 1;
928 agent->sa_use_srv = 1;
929 agent->sa_srv_503 = 1;
930 agent->sa_auto_comp = 0;
931 agent->sa_server_rport = 1;
932
933 /* RFC 3261 section 8.1.1.6 */
934 sip_max_forwards_init(agent->sa_max_forwards);
935
936 if (getenv("SIPCOMPACT"))
937 agent->sa_flags |= MSG_DO_COMPACTMSG_FLG_COMPACT;
938
939 agent_set_params(agent, ta_args(ta)(ta).tl);
940
941 if (agent->sa_mclass == NULL((void*)0))
942 agent->sa_mclass = sip_default_mclass();
943
944 agent->sa_in.re_t1 = &agent->sa_in.re_list;
945
946 incoming_queue_init(agent->sa_in.proceeding, 0);
947 incoming_queue_init(agent->sa_in.preliminary, agent->sa_t1x64); /* P1 */
948 incoming_queue_init(agent->sa_in.inv_completed, agent->sa_t1x64); /* H */
949 incoming_queue_init(agent->sa_in.inv_confirmed, agent->sa_t4); /* I */
950 incoming_queue_init(agent->sa_in.completed, agent->sa_t1x64); /* J */
951 incoming_queue_init(agent->sa_in.terminated, 0);
952 incoming_queue_init(agent->sa_in.final_failed, 0);
953
954 agent->sa_out.re_t1 = &agent->sa_out.re_list;
955
956 if (agent->sa_use_timer_c || !agent->sa_is_a_uas)
957 timer_c = agent->sa_timer_c;
958 if (timer_d < agent->sa_t1x64)
959 timer_d = agent->sa_t1x64;
960
961 outgoing_queue_init(agent->sa_out.delayed, 0);
962 outgoing_queue_init(agent->sa_out.resolving, 0);
963 outgoing_queue_init(agent->sa_out.trying, agent->sa_t1x64); /* F */
964 outgoing_queue_init(agent->sa_out.completed, agent->sa_t4); /* K */
965 outgoing_queue_init(agent->sa_out.terminated, 0);
966 /* Special queues (states) for outgoing INVITE transactions */
967 outgoing_queue_init(agent->sa_out.inv_calling, agent->sa_t1x64); /* B */
968 outgoing_queue_init(agent->sa_out.inv_proceeding, timer_c); /* C */
969 outgoing_queue_init(agent->sa_out.inv_completed, timer_d); /* D */
970
971 if (leg_htable_resize(agent->sa_home, agent->sa_dialogs, 0) < 0 ||
972 leg_htable_resize(agent->sa_home, agent->sa_defaults, 0) < 0 ||
973 outgoing_htable_resize(agent->sa_home, agent->sa_outgoing, 0) < 0 ||
974 incoming_htable_resize(agent->sa_home, agent->sa_incoming, 0) < 0) {
975 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__
, 975, "nta_agent_create: failure with %s\n", "hash tables"))
: (void)0)
;
976 goto deinit;
977 }
978 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__
, 978, "nta_agent_create: initialized %s\n", "hash tables")) :
(void)0)
;
979
980 if (contact_url != (url_string_t *)-1 &&
981 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) {
982 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__
, 982, "nta_agent_create: failure with %s\n", "transport")) :
(void)0)
;
983 goto deinit;
984 }
985 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__
, 985, "nta_agent_create: initialized %s\n", "transports")) :
(void)0)
;
986
987 if (agent_tag_init(agent) < 0) {
988 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__
, 988, "nta_agent_create: failure with %s\n", "random identifiers"
)) : (void)0)
;
989 goto deinit;
990 }
991 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__
, 991, "nta_agent_create: initialized %s\n", "random identifiers"
)) : (void)0)
;
992
993 if (agent_timer_init(agent) < 0) {
994 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__
, 994, "nta_agent_create: failure with %s\n", "timer")) : (void
)0)
;
995 goto deinit;
996 }
997 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__
, 997, "nta_agent_create: initialized %s\n", "timer")) : (void
)0)
;
998
999 if (agent_launch_terminator(agent) == 0)
1000 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__
, 1000, "nta_agent_create: initialized %s\n", "threads")) : (
void)0)
;
1001
1002#if HAVE_SOFIA_SRESOLV1
1003 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
);
1004 if (!agent->sa_resolver) {
1005 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__
, 1005, "nta_agent_create: failure with %s\n", "resolver")) :
(void)0)
;
1006 }
1007 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__
, 1007, "nta_agent_create: initialized %s\n", "resolver")) : (
void)0)
;
1008#endif
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 agent;
1013
1014 deinit:
1015 nta_agent_destroy(agent);
1016 }
1017
1018 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))
;
1019
1020 return NULL((void*)0);
1021}
1022
1023/**
1024 * Destroy an NTA agent object.
1025 *
1026 * @param agent the NTA agent object to be destroyed.
1027 *
1028 */
1029void nta_agent_destroy(nta_agent_t *agent)
1030{
1031 if (agent) {
1032 size_t i;
1033 outgoing_htable_t *oht = agent->sa_outgoing;
1034 incoming_htable_t *iht = agent->sa_incoming;
1035 /* Currently, this is pretty pointless, as legs don't keep any resources */
1036 leg_htable_t *lht;
1037 nta_leg_t *leg;
1038
1039 for (i = 0, lht = agent->sa_dialogs; i < lht->lht_size; i++) {
1040 if ((leg = lht->lht_table[i])) {
1041 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__
, 1043, "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)
1042 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__
, 1043, "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)
1043 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__
, 1043, "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)
;
1044 leg_free(agent, leg);
1045 }
1046 }
1047
1048 for (i = 0, lht = agent->sa_defaults; i < lht->lht_size; i++) {
1049 if ((leg = lht->lht_table[i])) {
1050 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__
, 1052, "%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)
1051 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__
, 1052, "%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)
1052 __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__
, 1052, "%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)
;
1053 leg_free(agent, leg);
1054 }
1055 }
1056
1057 if (agent->sa_default_leg)
1058 leg_free(agent, agent->sa_default_leg);
1059
1060 for (i = iht->iht_size; i-- > 0; )
1061 while (iht->iht_table[i]) {
1062 nta_incoming_t *irq = iht->iht_table[i];
1063
1064 if (!irq->irq_destroyed)
1065 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__
, 1068, "%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
)
1066 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__
, 1068, "%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
)
1067 __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__
, 1068, "%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
)
1068 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__
, 1068, "%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
)
;
1069
1070 incoming_free(irq);
1071 }
1072
1073 for (i = oht->oht_size; i-- > 0;)
1074 while (oht->oht_table[i]) {
1075 nta_outgoing_t *orq = oht->oht_table[i];
1076
1077 if (!orq->orq_destroyed)
1078 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__
, 1083, "%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)
1079 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__
, 1083, "%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)
1080 __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__
, 1083, "%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)
1081 (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__
, 1083, "%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)
1082 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__
, 1083, "%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)
1083 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__
, 1083, "%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)
;
1084
1085 orq->orq_forks = NULL((void*)0), orq->orq_forking = NULL((void*)0);
1086 outgoing_free(orq);
1087 }
1088
1089 su_timer_destroy(agent->sa_timer), agent->sa_timer = NULL((void*)0);
1090
1091# if HAVE_SOFIA_SRESOLV1
1092 sres_resolver_destroy(agent->sa_resolver), agent->sa_resolver = NULL((void*)0);
1093# endif
1094
1095 tport_destroy(agent->sa_tports), agent->sa_tports = NULL((void*)0);
1096
1097 agent_kill_terminator(agent);
1098
1099 su_home_unref(agent->sa_home);
1100 }
1101}
1102
1103/** Return agent context. */
1104nta_agent_magic_t *nta_agent_magic(nta_agent_t const *agent)
1105{
1106 return agent ? agent->sa_magic : NULL((void*)0);
1107}
1108
1109/** Return @Contact header.
1110 *
1111 * Get a @Contact header, which can be used to reach @a agent.
1112 *
1113 * @param agent NTA agent object
1114 *
1115 * User agents can insert the @Contact header in the outgoing REGISTER,
1116 * INVITE, and ACK requests and replies to incoming INVITE and OPTIONS
1117 * transactions.
1118 *
1119 * Proxies can use the @Contact header to create appropriate @RecordRoute
1120 * headers:
1121 * @code
1122 * r_r = sip_record_route_create(msg_home(msg),
1123 * sip->sip_request->rq_url,
1124 * contact->m_url);
1125 * @endcode
1126 *
1127 * @return A sip_contact_t object corresponding to the @a agent.
1128 */
1129sip_contact_t *nta_agent_contact(nta_agent_t const *agent)
1130{
1131 return agent ? agent->sa_contact : NULL((void*)0);
1132}
1133
1134/** Return a list of @Via headers.
1135 *
1136 * Get @Via headers for all activated transport.
1137 *
1138 * @param agent NTA agent object
1139 *
1140 * @return A list of #sip_via_t objects used by the @a agent.
1141 */
1142sip_via_t *nta_agent_via(nta_agent_t const *agent)
1143{
1144 return agent ? agent->sa_vias : NULL((void*)0);
1145}
1146
1147/** Return a list of public (UPnP, STUN) @Via headers.
1148 *
1149 * Get public @Via headers for all activated transports.
1150 *
1151 * @param agent NTA agent object
1152 *
1153 * @return A list of #sip_via_t objects used by the @a agent.
1154 */
1155sip_via_t *nta_agent_public_via(nta_agent_t const *agent)
1156{
1157 return agent ? agent->sa_public_vias : NULL((void*)0);
1158}
1159
1160/** Match a @Via header @a v with @Via headers in @a agent.
1161 *
1162 */
1163static
1164sip_via_t *agent_has_via(nta_agent_t const *agent, sip_via_t const *via)
1165{
1166 sip_via_t const *v;
1167
1168 for (v = agent->sa_public_vias; v; v = v->v_next) {
1169 if (!su_casematch(via->v_host, v->v_host))
1170 continue;
1171 if (!su_strmatch(via->v_port, v->v_port))
1172 continue;
1173 if (!su_casematch(via->v_protocol, v->v_protocol))
1174 continue;
1175 return (sip_via_t *)v;
1176 }
1177
1178 for (v = agent->sa_vias; v; v = v->v_next) {
1179 if (!su_casematch(via->v_host, v->v_host))
1180 continue;
1181 if (!su_strmatch(via->v_port, v->v_port))
1182 continue;
1183 if (!su_casematch(via->v_protocol, v->v_protocol))
1184 continue;
1185 return (sip_via_t *)v;
1186 }
1187
1188 return NULL((void*)0);
1189}
1190
1191/** Return @UserAgent header.
1192 *
1193 * Get @UserAgent information with NTA version.
1194 *
1195 * @param agent NTA agent object (may be NULL)
1196 *
1197 * @return A string containing the @a agent version.
1198 */
1199char const *nta_agent_version(nta_agent_t const *agent)
1200{
1201 return "nta" "/" VERSION"1.13.8";
1202}
1203
1204/** Initialize default tag */
1205static int agent_tag_init(nta_agent_t *self)
1206{
1207 sip_contact_t *m = self->sa_contact;
1208 uint32_t hash = su_random();
1209
1210 if (m) {
1211 if (m->m_url->url_user)
1212 hash = 914715421U * hash + msg_hash_string(m->m_url->url_user);
1213 if (m->m_url->url_host)
1214 hash = 914715421U * hash + msg_hash_string(m->m_url->url_host);
1215 if (m->m_url->url_port)
1216 hash = 914715421U * hash + msg_hash_string(m->m_url->url_port);
1217 if (m->m_url->url_params)
1218 hash = 914715421U * hash + msg_hash_string(m->m_url->url_params);
1219 }
1220
1221 if (hash == 0)
1222 hash = 914715421U;
1223
1224 self->sa_branch = NTA_BRANCH_PRIME(uint64_t)(0xB9591D1C361C6521ULL) * (uint64_t)su_nanotime(NULL((void*)0));
1225 self->sa_branch *= hash;
1226
1227 self->sa_tags = NTA_TAG_PRIME(uint64_t)(0xB9591D1C361C6521ULL) * self->sa_branch;
1228
1229 return 0;
1230}
1231
1232/** Initialize agent timer. */
1233static
1234int agent_timer_init(nta_agent_t *agent)
1235{
1236 agent->sa_timer = su_timer_create(su_root_task(agent->sa_root),
1237 NTA_SIP_T1 / 8);
1238#if 0
1239 return su_timer_set(agent->sa_timer,
1240 agent_timer,
1241 agent);
1242#endif
1243 return -(agent->sa_timer == NULL((void*)0));
1244}
1245
1246/**
1247 * Agent timer routine.
1248 */
1249static
1250void agent_timer(su_root_magic_t *rm, su_timer_t *timer, nta_agent_t *agent)
1251{
1252 su_time_t stamp = su_now();
1253 uint32_t now = su_time_ms(stamp), next, latest;
1254
1255 now += now == 0;
1256
1257 agent->sa_next = 0;
1258
1259 agent->sa_in_timer = 1;
1260
1261
1262 _nta_outgoing_timer(agent);
1263 _nta_incoming_timer(agent);
1264
1265 agent->sa_in_timer = 0;
1266
1267 /* Calculate next timeout */
1268 next = latest = now + NTA_TIME_MAX + 1;
1269
1270#define NEXT_TIMEOUT(next, p, f, now) \
1271 (void)(p && (int32_t)(p->f - (next)) < 0 && \
1272 ((next) = ((int32_t)(p->f - (now)) > 0 ? p->f : (now))))
1273
1274 NEXT_TIMEOUT(next, agent->sa_out.re_list, orq_retry, now);
1275 NEXT_TIMEOUT(next, agent->sa_out.inv_completed->q_head, orq_timeout, now);
1276 NEXT_TIMEOUT(next, agent->sa_out.completed->q_head, orq_timeout, now);
1277 NEXT_TIMEOUT(next, agent->sa_out.inv_calling->q_head, orq_timeout, now);
1278 if (agent->sa_out.inv_proceeding->q_timeout)
1279 NEXT_TIMEOUT(next, agent->sa_out.inv_proceeding->q_head, orq_timeout, now);
1280 NEXT_TIMEOUT(next, agent->sa_out.trying->q_head, orq_timeout, now);
1281
1282 NEXT_TIMEOUT(next, agent->sa_in.preliminary->q_head, irq_timeout, now);
1283 NEXT_TIMEOUT(next, agent->sa_in.inv_completed->q_head, irq_timeout, now);
1284 NEXT_TIMEOUT(next, agent->sa_in.inv_confirmed->q_head, irq_timeout, now);
1285 NEXT_TIMEOUT(next, agent->sa_in.completed->q_head, irq_timeout, now);
1286 NEXT_TIMEOUT(next, agent->sa_in.re_list, irq_retry, now);
1287
1288 if (agent->sa_next)
1289 NEXT_TIMEOUT(next, agent, sa_next, now);
1290
1291#undef NEXT_TIMEOUT
1292
1293 if (next == latest) {
1294 /* Do not set timer? */
1295 /* check it there are still things queued, if there are, that means everything scheduled is > 15 days in the future */
1296 /* in this case, we had a large time shift, we should schedule for 15 days in the future (which is probably still before now) */
1297 /* and this should sort itself out on the next run through */
1298 if ( !agent->sa_out.completed->q_head && !agent->sa_out.trying->q_head && !agent->sa_out.inv_calling->q_head &&
1299 !agent->sa_out.re_list && !agent->sa_in.inv_confirmed->q_head && !agent->sa_in.preliminary->q_head &&
1300 !agent->sa_in.completed->q_head && !agent->sa_in.inv_completed->q_head && !agent->sa_in.re_list ) {
1301 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__
, 1301, "nta: timer not set\n" "%s", "")) : (void)0)
;
1302 return;
1303 }
1304 }
1305
1306 if (next == now) if (++next == 0) ++next;
1307
1308 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__
, 1308, "nta: timer %s to %ld ms\n", "set next", (long)(next -
now))) : (void)0)
;
1309
1310 agent->sa_next = next;
1311
1312 su_timer_set_at(timer, agent_timer, agent, su_time_add(stamp, next - now));
1313}
1314
1315/** Add uin32_t milliseconds to the time. */
1316static su_time_t add_milliseconds(su_time_t t0, uint32_t ms)
1317{
1318 unsigned long sec = ms / 1000, usec = (ms % 1000) * 1000;
1319
1320 t0.tv_usec += usec;
1321 t0.tv_sec += sec;
1322
1323 if (t0.tv_usec >= 1000000) {
1324 t0.tv_sec += 1;
1325 t0.tv_usec -= 1000000;
1326 }
1327
1328 return t0;
1329}
1330
1331/** Calculate nonzero value for timeout.
1332 *
1333 * Sets or adjusts agent timer when needed.
1334 *
1335 * @retval 0 if offset is 0
1336 * @retval timeout (millisecond counter) otherwise
1337 */
1338static
1339uint32_t set_timeout(nta_agent_t *agent, uint32_t offset)
1340{
1341 su_time_t now;
1342 uint32_t next, ms;
1343
1344 if (offset == 0)
1345 return 0;
1346
1347 now = su_now();
1348 ms = su_time_ms(now);
1349
1350 next = ms + offset;
1351
1352 if (next == 0) next = 1;
1353
1354 if (agent->sa_in_timer) /* Currently executing timer */
1355 return next;
1356
1357 if (agent->sa_next == 0 || (int32_t)(agent->sa_next - next - 5L) > 0) {
1358 /* Set timer */
1359 if (agent->sa_next)
1360 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__
, 1360, "nta: timer %s to %ld ms\n", "shortened", (long)offset
)) : (void)0)
;
1361 else
1362 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__
, 1362, "nta: timer %s to %ld ms\n", "set", (long)offset)) : (
void)0)
;
1363
1364 su_timer_set_at(agent->sa_timer, agent_timer, agent,
1365 add_milliseconds(now, offset));
1366 agent->sa_next = next;
1367 }
1368
1369 return next;
1370}
1371
1372
1373/** Return current timeval. */
1374static
1375su_time_t agent_now(nta_agent_t const *agent)
1376{
1377 return su_now();
1378}
1379
1380
1381/** Launch transaction terminator task */
1382static
1383int agent_launch_terminator(nta_agent_t *agent)
1384{
1385#ifdef TPTAG_THRPSIZE
1386 if (agent->sa_tport_threadpool) {
1387 su_home_threadsafe(agent->sa_home);
1388 return su_clone_start(agent->sa_root,
1389 agent->sa_terminator,
1390 NULL((void*)0),
1391 NULL((void*)0),
1392 NULL((void*)0));
1393 }
1394#endif
1395 return -1;
1396}
1397
1398/** Kill transaction terminator task */
1399static
1400void agent_kill_terminator(nta_agent_t *agent)
1401{
1402 su_clone_wait(agent->sa_root, agent->sa_terminator);
1403}
1404
1405
1406/**Set NTA Parameters.
1407 *
1408 * The nta_agent_set_params() function sets the stack parameters. The
1409 * parameters determine the way NTA handles the retransmissions, how long
1410 * NTA keeps transactions alive, does NTA apply proxy or user-agent logic to
1411 * INVITE transactions, or how the @Via headers are generated.
1412 *
1413 * @note
1414 * Setting the parameters NTATAG_MAXSIZE(), NTATAG_UDP_MTU(), NTATAG_MAX_PROCEEDING(),
1415 * NTATAG_SIP_T1X64(), NTATAG_SIP_T1(), NTATAG_SIP_T2(), NTATAG_SIP_T4() to
1416 * 0 selects the default value.
1417 *
1418 * @TAGS
1419 * NTATAG_ALIASES(),
1420 * NTATAG_BAD_REQ_MASK(), NTATAG_BAD_RESP_MASK(), NTATAG_BLACKLIST(),
1421 * NTATAG_CANCEL_2543(), NTATAG_CANCEL_487(), NTATAG_CLIENT_RPORT(),
1422 * NTATAG_DEBUG_DROP_PROB(), NTATAG_DEFAULT_PROXY(),
1423 * NTATAG_EXTRA_100(), NTATAG_GRAYLIST(),
1424 * NTATAG_MAXSIZE(), NTATAG_MAX_FORWARDS(), NTATAG_MERGE_482(), NTATAG_MCLASS()
1425 * NTATAG_PASS_100(), NTATAG_PASS_408(), NTATAG_PRELOAD(), NTATAG_PROGRESS(),
1426 * NTATAG_REL100(),
1427 * NTATAG_SERVER_RPORT(),
1428 * NTATAG_SIPFLAGS(),
1429 * NTATAG_SIP_T1X64(), NTATAG_SIP_T1(), NTATAG_SIP_T2(), NTATAG_SIP_T4(),
1430 * NTATAG_STATELESS(),
1431 * NTATAG_TAG_3261(), NTATAG_TCP_RPORT(), NTATAG_TIMEOUT_408(),
1432 * NTATAG_TLS_RPORT(), NTATAG_TLS_ORQ_CONNECT_TIMEOUT(),
1433 * NTATAG_TIMER_C(), NTATAG_MAX_PROCEEDING(),
1434 * NTATAG_UA(), NTATAG_UDP_MTU(), NTATAG_USER_VIA(),
1435 * NTATAG_USE_NAPTR(), NTATAG_USE_SRV() and NTATAG_USE_TIMESTAMP().
1436 *
1437 * @note The value from following tags are stored, but they currently do nothing:
1438 * NTATAG_SIGCOMP_ALGORITHM(), NTATAG_SIGCOMP_OPTIONS(), NTATAG_SMIME()
1439 */
1440int nta_agent_set_params(nta_agent_t *agent,
1441 tag_type_t tag, tag_value_t value, ...)
1442{
1443 int retval;
1444
1445 if (agent) {
1446 ta_list ta;
1447 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)
;
1448 retval = agent_set_params(agent, ta_args(ta)(ta).tl);
1449 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))
;
1450 } else {
1451 su_seterrno(EINVAL22);
1452 retval = -1;
1453 }
1454
1455 return retval;
1456}
1457
1458/** Internal function for setting tags */
1459static
1460int agent_set_params(nta_agent_t *agent, tagi_t *tags)
1461{
1462 int n, nC, m;
1463 unsigned bad_req_mask = agent->sa_bad_req_mask;
1464 unsigned bad_resp_mask = agent->sa_bad_resp_mask;
1465 usize_t maxsize = agent->sa_maxsize;
1466 usize_t max_proceeding = agent->sa_max_proceeding;
1467 usize_t max_recv_requests_per_second = agent->sa_max_recv_requests_per_second;
1468 unsigned max_forwards = agent->sa_max_forwards->mf_count;
1469 unsigned udp_mtu = agent->sa_udp_mtu;
1470 unsigned sip_t1 = agent->sa_t1;
1471 unsigned sip_t2 = agent->sa_t2;
1472 unsigned sip_t4 = agent->sa_t4;
1473 unsigned sip_t1x64 = agent->sa_t1x64;
1474 unsigned tls_orq_connect_timeout = agent->sa_tls_orq_connect_timeout;
1475 unsigned timer_c = agent->sa_timer_c;
1476 unsigned timer_d = 32000;
1477 unsigned graylist = agent->sa_graylist;
1478 unsigned blacklist = agent->sa_blacklist;
1479 int ua = agent->sa_is_a_uas;
1480 unsigned progress = agent->sa_progress;
1481 int stateless = agent->sa_is_stateless;
1482 unsigned drop_prob = agent->sa_drop_prob;
1483 int user_via = agent->sa_user_via;
1484 int extra_100 = agent->sa_extra_100;
1485 int pass_100 = agent->sa_pass_100;
1486 int timeout_408 = agent->sa_timeout_408;
1487 int pass_408 = agent->sa_pass_408;
1488 int merge_482 = agent->sa_merge_482;
1489 int cancel_2543 = agent->sa_cancel_2543;
1490 int cancel_487 = agent->sa_cancel_487;
1491 int invite_100rel = agent->sa_invite_100rel;
1492 int use_timestamp = agent->sa_timestamp;
1493 int use_naptr = agent->sa_use_naptr;
1494 int use_srv = agent->sa_use_srv;
1495 int srv_503 = agent->sa_srv_503;
1496 void *smime = agent->sa_smime;
1497 uint32_t flags = agent->sa_flags;
1498 int rport = agent->sa_rport;
1499 int server_rport = agent->sa_server_rport;
1500 int tcp_rport = agent->sa_tcp_rport;
1501 int tls_rport = agent->sa_tls_rport;
1502 unsigned preload = agent->sa_preload;
1503 unsigned threadpool = agent->sa_tport_threadpool;
1504 char const *sigcomp = agent->sa_sigcomp_options;
1505 char const *algorithm = NONE((void *)-1);
1506 msg_mclass_t const *mclass = NONE((void *)-1);
1507 sip_contact_t const *aliases = NONE((void *)-1);
1508 url_string_t const *proxy = NONE((void *)-1);
1509 tport_t *tport;
1510
1511 su_home_t *home = agent->sa_home;
1512
1513 n = tl_gets(tags,
1514 NTATAG_ALIASES_REF(aliases)ntatag_aliases_ref, siptag_contact_vr(&(aliases)),
1515 NTATAG_BAD_REQ_MASK_REF(bad_req_mask)ntatag_bad_req_mask_ref, tag_uint_vr(&(bad_req_mask)),
1516 NTATAG_BAD_RESP_MASK_REF(bad_resp_mask)ntatag_bad_resp_mask_ref, tag_uint_vr(&(bad_resp_mask)),
1517 NTATAG_BLACKLIST_REF(blacklist)ntatag_blacklist_ref, tag_uint_vr(&(blacklist)),
1518 NTATAG_CANCEL_2543_REF(cancel_2543)ntatag_cancel_2543_ref, tag_bool_vr(&(cancel_2543)),
1519 NTATAG_CANCEL_487_REF(cancel_487)ntatag_cancel_487_ref, tag_bool_vr(&(cancel_487)),
1520 NTATAG_DEBUG_DROP_PROB_REF(drop_prob)ntatag_debug_drop_prob_ref, tag_uint_vr(&(drop_prob)),
1521 NTATAG_DEFAULT_PROXY_REF(proxy)ntatag_default_proxy_ref, urltag_url_vr(&(proxy)),
1522 NTATAG_EXTRA_100_REF(extra_100)ntatag_extra_100_ref, tag_bool_vr(&(extra_100)),
1523 NTATAG_GRAYLIST_REF(graylist)ntatag_graylist_ref, tag_uint_vr(&(graylist)),
1524 NTATAG_MAXSIZE_REF(maxsize)ntatag_maxsize_ref, tag_usize_vr(&(maxsize)),
1525 NTATAG_MAX_PROCEEDING_REF(max_proceeding)ntatag_max_proceeding_ref, tag_usize_vr(&(max_proceeding)
)
,
1526 NTATAG_MAX_RECV_REQUESTS_PER_SECOND_REF(max_recv_requests_per_second)ntatag_max_recv_requests_per_second_ref, tag_usize_vr(&(max_recv_requests_per_second
))
,
1527 NTATAG_MAX_FORWARDS_REF(max_forwards)ntatag_max_forwards_ref, tag_uint_vr(&(max_forwards)),
1528 NTATAG_MCLASS_REF(mclass)ntatag_mclass_ref, tag_cptr_vr(&(mclass), (mclass)),
1529 NTATAG_MERGE_482_REF(merge_482)ntatag_merge_482_ref, tag_bool_vr(&(merge_482)),
1530 NTATAG_PASS_100_REF(pass_100)ntatag_pass_100_ref, tag_bool_vr(&(pass_100)),
1531 NTATAG_PASS_408_REF(pass_408)ntatag_pass_408_ref, tag_bool_vr(&(pass_408)),
1532 NTATAG_PRELOAD_REF(preload)ntatag_preload_ref, tag_uint_vr(&(preload)),
1533 NTATAG_PROGRESS_REF(progress)ntatag_progress_ref, tag_uint_vr(&(progress)),
1534 NTATAG_REL100_REF(invite_100rel)ntatag_rel100_ref, tag_bool_vr(&(invite_100rel)),
1535 NTATAG_RPORT_REF(rport)ntatag_client_rport_ref, tag_bool_vr(&(rport)),
1536 NTATAG_SERVER_RPORT_REF(server_rport)ntatag_server_rport_ref, tag_int_vr(&(server_rport)),
1537 NTATAG_SIGCOMP_ALGORITHM_REF(algorithm)ntatag_sigcomp_algorithm_ref, tag_str_vr(&(algorithm)),
1538 NTATAG_SIGCOMP_OPTIONS_REF(sigcomp)ntatag_sigcomp_options_ref, tag_str_vr(&(sigcomp)),
1539 NTATAG_SIPFLAGS_REF(flags)ntatag_sipflags_ref, tag_uint_vr(&(flags)),
1540 NTATAG_SIP_T1X64_REF(sip_t1x64)ntatag_sip_t1x64_ref, tag_uint_vr(&(sip_t1x64)),
1541 NTATAG_SIP_T1_REF(sip_t1)ntatag_sip_t1_ref, tag_uint_vr(&(sip_t1)),
1542 NTATAG_SIP_T2_REF(sip_t2)ntatag_sip_t2_ref, tag_uint_vr(&(sip_t2)),
1543 NTATAG_SIP_T4_REF(sip_t4)ntatag_sip_t4_ref, tag_uint_vr(&(sip_t4)),
1544#if HAVE_SOFIA_SMIME0
1545 NTATAG_SMIME_REF(smime)ntatag_smime_ref, tag_ptr_vr(&(smime), (smime)),
1546#endif
1547 NTATAG_STATELESS_REF(stateless)ntatag_stateless_ref, tag_bool_vr(&(stateless)),
1548 NTATAG_TCP_RPORT_REF(tcp_rport)ntatag_tcp_rport_ref, tag_bool_vr(&(tcp_rport)),
1549 NTATAG_TLS_RPORT_REF(tls_rport)ntatag_tls_rport_ref, tag_bool_vr(&(tls_rport)),
1550 NTATAG_TLS_ORQ_CONNECT_TIMEOUT_REF(tls_orq_connect_timeout)ntatag_tls_orq_connect_timeout_ref, tag_uint_vr(&(tls_orq_connect_timeout
))
,
1551 NTATAG_TIMEOUT_408_REF(timeout_408)ntatag_timeout_408_ref, tag_bool_vr(&(timeout_408)),
1552 NTATAG_UA_REF(ua)ntatag_ua_ref, tag_bool_vr(&(ua)),
1553 NTATAG_UDP_MTU_REF(udp_mtu)ntatag_udp_mtu_ref, tag_uint_vr(&(udp_mtu)),
1554 NTATAG_USER_VIA_REF(user_via)ntatag_user_via_ref, tag_bool_vr(&(user_via)),
1555 NTATAG_USE_NAPTR_REF(use_naptr)ntatag_use_naptr_ref, tag_bool_vr(&(use_naptr)),
1556 NTATAG_USE_SRV_REF(use_srv)ntatag_use_srv_ref, tag_bool_vr(&(use_srv)),
1557 NTATAG_USE_TIMESTAMP_REF(use_timestamp)ntatag_use_timestamp_ref, tag_bool_vr(&(use_timestamp)),
1558#ifdef TPTAG_THRPSIZE
1559 /* If threadpool is enabled, start a separate "reaper thread" */
1560 TPTAG_THRPSIZE_REF(threadpool)tptag_thrpsize_ref, tag_uint_vr(&(threadpool)),
1561#endif
1562 NTATAG_SRV_503_REF(srv_503)ntatag_srv_503_ref, tag_bool_vr(&(srv_503)),
1563 TAG_END()(tag_type_t)0, (tag_value_t)0);
1564 nC = tl_gets(tags,
1565 NTATAG_TIMER_C_REF(timer_c)ntatag_timer_c_ref, tag_uint_vr(&(timer_c)),
1566 TAG_END()(tag_type_t)0, (tag_value_t)0);
1567 n += nC;
1568
1569 if (mclass != NONE((void *)-1))
1570 agent->sa_mclass = mclass ? mclass : sip_default_mclass();
1571
1572 m = 0;
1573 for (tport = agent->sa_tports; tport; tport = tport_next(tport)) {
1574 int m0 = tport_set_params(tport, TAG_NEXT(tags)tag_next, (tag_value_t)(tags));
1575 if (m0 < 0)
1576 return m0;
1577 if (m0 > m)
1578 m = m0;
1579 }
1580
1581 n += m;
1582
1583 if (aliases != NONE((void *)-1)) {
1584 sip_contact_t const *m, *m_next;
1585
1586 m = agent->sa_aliases;
1587 agent->sa_aliases = sip_contact_dup(home, aliases);
1588
1589 for (; m; m = m_next) { /* Free old aliases */
1590 m_next = m->m_next;
1591 su_free(home, (void *)m);
1592 }
1593 }
1594
1595 if (proxy != NONE((void *)-1)) {
1596 url_t *dp = url_hdup(home, proxy->us_url);
1597
1598 url_sanitize(dp);
1599
1600 if (dp == NULL((void*)0) || dp->url_type == url_sip || dp->url_type == url_sips || dp->url_type == url_urn) {
1601 if (agent->sa_default_proxy)
1602 su_free(home, agent->sa_default_proxy);
1603 agent->sa_default_proxy = dp;
1604 }
1605 else
1606 n = -1;
1607 }
1608
1609 if (algorithm != NONE((void *)-1))
1610 agent->sa_algorithm = su_strdup(home, algorithm);
1611
1612 if (!su_strmatch(sigcomp, agent->sa_sigcomp_options)) {
1613 msg_param_t const *l = NULL((void*)0);
1614 char *s = su_strdup(home, sigcomp);
1615 char *s1 = su_strdup(home, s), *s2 = s1;
1616
1617 if (s && s2 && msg_avlist_d(home, &s2, &l) == 0 && *s2 == '\0') {
1618 su_free(home, (void *)agent->sa_sigcomp_options);
1619 su_free(home, (void *)agent->sa_sigcomp_option_list);
1620 agent->sa_sigcomp_options = s;
1621 agent->sa_sigcomp_option_free = s1;
1622 agent->sa_sigcomp_option_list = l;
1623 } else {
1624 su_free(home, s);
1625 su_free(home, s1);
1626 su_free(home, (void *)l);
1627 n = -1;
1628 }
1629 }
1630
1631 if (maxsize == 0) maxsize = 2 * 1024 * 1024;
1632 if (maxsize > UINT32_MAX(4294967295U)) maxsize = UINT32_MAX(4294967295U);
1633 agent->sa_maxsize = maxsize;
1634
1635 if (max_proceeding == 0) max_proceeding = USIZE_MAX(2147483647 *2U +1U);
1636 agent->sa_max_proceeding = max_proceeding;
1637
1638 agent->sa_max_recv_requests_per_second = max_recv_requests_per_second;
1639
1640 if (max_forwards == 0) max_forwards = 70; /* Default value */
1641 agent->sa_max_forwards->mf_count = max_forwards;
1642
1643 if (udp_mtu == 0) udp_mtu = 1300;
1644 if (udp_mtu > 65535) udp_mtu = 65535;
1645 if (agent->sa_udp_mtu != udp_mtu) {
1646 agent->sa_udp_mtu = udp_mtu;
1647 agent_set_udp_params(agent, udp_mtu);
1648 }
1649
1650 if (sip_t1 == 0) sip_t1 = NTA_SIP_T1;
1651 if (sip_t1 > NTA_TIME_MAX) sip_t1 = NTA_TIME_MAX;
1652 agent->sa_t1 = sip_t1;
1653
1654 if (sip_t2 == 0) sip_t2 = NTA_SIP_T2;
1655 if (sip_t2 > NTA_TIME_MAX) sip_t2 = NTA_TIME_MAX;
1656 agent->sa_t2 = sip_t2;
1657
1658 if (sip_t4 == 0) sip_t4 = NTA_SIP_T4;
1659 if (sip_t4 > NTA_TIME_MAX) sip_t4 = NTA_TIME_MAX;
1660 if (agent->sa_t4 != sip_t4) {
1661 incoming_queue_adjust(agent, agent->sa_in.inv_confirmed, sip_t4);
1662 outgoing_queue_adjust(agent, agent->sa_out.completed, sip_t4);
1663 }
1664 agent->sa_t4 = sip_t4;
1665
1666 if (sip_t1x64 == 0) sip_t1x64 = NTA_SIP_T1 * 64;
1667 if (sip_t1x64 > NTA_TIME_MAX) sip_t1x64 = NTA_TIME_MAX;
1668 if (agent->sa_t1x64 != sip_t1x64) {
1669 incoming_queue_adjust(agent, agent->sa_in.preliminary, sip_t1x64);
1670 incoming_queue_adjust(agent, agent->sa_in.completed, sip_t1x64);
1671 incoming_queue_adjust(agent, agent->sa_in.inv_completed, sip_t1x64);
1672 outgoing_queue_adjust(agent, agent->sa_out.trying, sip_t1x64);
1673 outgoing_queue_adjust(agent, agent->sa_out.inv_calling, sip_t1x64);
1674 }
1675 agent->sa_t1x64 = sip_t1x64;
1676 if (nC == 1) {
1677 agent->sa_use_timer_c = 1;
1678 if (timer_c == 0)
1679 timer_c = 185 * 1000;
1680 agent->sa_timer_c = timer_c;
1681 outgoing_queue_adjust(agent, agent->sa_out.inv_proceeding, timer_c);
1682 }
1683 if (timer_d < sip_t1x64)
1684 timer_d = sip_t1x64;
1685 outgoing_queue_adjust(agent, agent->sa_out.inv_completed, timer_d);
1686
1687 if (tls_orq_connect_timeout > NTA_TIME_MAX) tls_orq_connect_timeout = NTA_TIME_MAX;
1688 agent->sa_tls_orq_connect_timeout = tls_orq_connect_timeout;
1689
1690 if (graylist > 24 * 60 * 60)
1691 graylist = 24 * 60 * 60;
1692 agent->sa_graylist = graylist;
1693
1694 if (blacklist > 24 * 60 * 60)
1695 blacklist = 24 * 60 * 60;
1696 agent->sa_blacklist = blacklist;
1697
1698 if (progress == 0)
1699 progress = 60 * 1000;
1700 agent->sa_progress = progress;
1701
1702 if (server_rport > 3)
1703 server_rport = 1;
1704 else if (server_rport < 0)
1705 server_rport = 1;
1706 agent->sa_server_rport = server_rport;
1707
1708 agent->sa_bad_req_mask = bad_req_mask;
1709 agent->sa_bad_resp_mask = bad_resp_mask;
1710
1711 agent->sa_is_a_uas = ua != 0;
1712 agent->sa_is_stateless = stateless != 0;
1713 agent->sa_drop_prob = drop_prob < 1000 ? drop_prob : 1000;
1714 agent->sa_user_via = user_via != 0;
1715 agent->sa_extra_100 = extra_100 != 0;
1716 agent->sa_pass_100 = pass_100 != 0;
1717 agent->sa_timeout_408 = timeout_408 != 0;
1718 agent->sa_pass_408 = pass_408 != 0;
1719 agent->sa_merge_482 = merge_482 != 0;
1720 agent->sa_cancel_2543 = cancel_2543 != 0;
1721 agent->sa_cancel_487 = cancel_487 != 0;
1722 agent->sa_invite_100rel = invite_100rel != 0;
1723 agent->sa_timestamp = use_timestamp != 0;
1724 agent->sa_use_naptr = use_naptr != 0;
1725 agent->sa_use_srv = use_srv != 0;
1726 agent->sa_srv_503 = srv_503 != 0;
1727 agent->sa_smime = smime;
1728 agent->sa_flags = flags & MSG_FLG_USERMASK;
1729 agent->sa_rport = rport != 0;
1730 agent->sa_tcp_rport = tcp_rport != 0;
1731 agent->sa_tls_rport = tls_rport != 0;
1732 agent->sa_preload = preload;
1733 agent->sa_tport_threadpool = threadpool;
1734
1735 return n;
1736}
1737
1738static
1739void agent_set_udp_params(nta_agent_t *self, usize_t udp_mtu)
1740{
1741 tport_t *tp;
1742
1743 /* Set via fields for the tports */
1744 for (tp = tport_primaries(self->sa_tports); tp; tp = tport_next(tp)) {
1745 if (tport_is_udp(tp))
1746 tport_set_params(tp,
1747 TPTAG_TIMEOUT(2 * self->sa_t1x64)tptag_timeout, tag_uint_v((2 * self->sa_t1x64)),
1748 TPTAG_MTU(udp_mtu)tptag_mtu, tag_usize_v((udp_mtu)),
1749 TAG_END()(tag_type_t)0, (tag_value_t)0);
1750 }
1751}
1752
1753/**Get NTA Parameters.
1754 *
1755 * The nta_agent_get_params() function retrieves the stack parameters. The
1756 * parameters determine the way NTA handles the retransmissions, how long
1757 * NTA keeps transactions alive, does NTA apply proxy or user-agent logic to
1758 * INVITE transactions, or how the @Via headers are generated.
1759 *
1760 * @TAGS
1761 * NTATAG_ALIASES_REF(), NTATAG_BLACKLIST_REF(),
1762 * NTATAG_CANCEL_2543_REF(), NTATAG_CANCEL_487_REF(),
1763 * NTATAG_CLIENT_RPORT_REF(), NTATAG_CONTACT_REF(),
1764 * NTATAG_DEBUG_DROP_PROB_REF(), NTATAG_DEFAULT_PROXY_REF(),
1765 * NTATAG_EXTRA_100_REF(), NTATAG_GRAYLIST_REF(),
1766 * NTATAG_MAXSIZE_REF(), NTATAG_MAX_FORWARDS_REF(), NTATAG_MCLASS_REF(),
1767 * NTATAG_MERGE_482_REF(), NTATAG_MAX_PROCEEDING_REF(),
1768 * NTATAG_PASS_100_REF(), NTATAG_PASS_408_REF(), NTATAG_PRELOAD_REF(),
1769 * NTATAG_PROGRESS_REF(),
1770 * NTATAG_REL100_REF(),
1771 * NTATAG_SERVER_RPORT_REF(),
1772 * NTATAG_SIGCOMP_ALGORITHM_REF(), NTATAG_SIGCOMP_OPTIONS_REF(),
1773 * NTATAG_SIPFLAGS_REF(),
1774 * NTATAG_SIP_T1_REF(), NTATAG_SIP_T1X64_REF(), NTATAG_SIP_T2_REF(),
1775 * NTATAG_SIP_T4_REF(), NTATAG_SMIME_REF(), NTATAG_STATELESS_REF(),
1776 * NTATAG_TAG_3261_REF(), NTATAG_TIMEOUT_408_REF(), NTATAG_TIMER_C_REF(),
1777 * NTATAG_UA_REF(), NTATAG_UDP_MTU_REF(), NTATAG_USER_VIA_REF(),
1778 * NTATAG_USE_NAPTR_REF(), NTATAG_USE_SRV_REF(),
1779 * and NTATAG_USE_TIMESTAMP_REF().
1780 *
1781 */
1782int nta_agent_get_params(nta_agent_t *agent,
1783 tag_type_t tag, tag_value_t value, ...)
1784{
1785 int n;
1786 ta_list ta;
1787
1788 if (agent) {
1789 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)
;
1790 n = agent_get_params(agent, ta_args(ta)(ta).tl);
1791 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))
;
1792 return n;
1793 }
1794
1795 su_seterrno(EINVAL22);
1796 return -1;
1797}
1798
1799/** Get NTA parameters */
1800static
1801int agent_get_params(nta_agent_t *agent, tagi_t *tags)
1802{
1803 return
1804 tl_tgets(tags,
1805 NTATAG_ALIASES(agent->sa_aliases)ntatag_aliases, siptag_contact_v((agent->sa_aliases)),
1806 NTATAG_BLACKLIST(agent->sa_blacklist)ntatag_blacklist, tag_uint_v((agent->sa_blacklist)),
1807 NTATAG_CANCEL_2543(agent->sa_cancel_2543)ntatag_cancel_2543, tag_bool_v((agent->sa_cancel_2543)),
1808 NTATAG_CANCEL_487(agent->sa_cancel_487)ntatag_cancel_487, tag_bool_v((agent->sa_cancel_487)),
1809 NTATAG_CLIENT_RPORT(agent->sa_rport)ntatag_client_rport, tag_bool_v((agent->sa_rport)),
1810 NTATAG_CONTACT(agent->sa_contact)ntatag_contact, siptag_contact_v((agent->sa_contact)),
1811 NTATAG_DEBUG_DROP_PROB(agent->sa_drop_prob)ntatag_debug_drop_prob, tag_uint_v((agent->sa_drop_prob)),
1812 NTATAG_DEFAULT_PROXY(agent->sa_default_proxy)ntatag_default_proxy, urltag_url_v((agent->sa_default_proxy
))
,
1813 NTATAG_EXTRA_100(agent->sa_extra_100)ntatag_extra_100, tag_bool_v((agent->sa_extra_100)),
1814 NTATAG_GRAYLIST(agent->sa_graylist)ntatag_graylist, tag_uint_v((agent->sa_graylist)),
1815 NTATAG_MAXSIZE(agent->sa_maxsize)ntatag_maxsize, tag_usize_v((agent->sa_maxsize)),
1816 NTATAG_MAX_PROCEEDING(agent->sa_max_proceeding)ntatag_max_proceeding, tag_usize_v((agent->sa_max_proceeding
))
,
1817 NTATAG_MAX_RECV_REQUESTS_PER_SECOND(agent->sa_max_recv_requests_per_second)ntatag_max_recv_requests_per_second, tag_usize_v((agent->sa_max_recv_requests_per_second
))
,
1818 NTATAG_MAX_FORWARDS(agent->sa_max_forwards->mf_count)ntatag_max_forwards, tag_uint_v((agent->sa_max_forwards->
mf_count))
,
1819 NTATAG_MCLASS(agent->sa_mclass)ntatag_mclass, tag_cptr_v((agent->sa_mclass)),
1820 NTATAG_MERGE_482(agent->sa_merge_482)ntatag_merge_482, tag_bool_v((agent->sa_merge_482)),
1821 NTATAG_PASS_100(agent->sa_pass_100)ntatag_pass_100, tag_bool_v((agent->sa_pass_100)),
1822 NTATAG_PASS_408(agent->sa_pass_408)ntatag_pass_408, tag_bool_v((agent->sa_pass_408)),
1823 NTATAG_PRELOAD(agent->sa_preload)ntatag_preload, tag_uint_v((agent->sa_preload)),
1824 NTATAG_PROGRESS(agent->sa_progress)ntatag_progress, tag_uint_v((agent->sa_progress)),
1825 NTATAG_REL100(agent->sa_invite_100rel)ntatag_rel100, tag_bool_v((agent->sa_invite_100rel)),
1826 NTATAG_SERVER_RPORT((int)(agent->sa_server_rport))ntatag_server_rport, tag_int_v(((int)(agent->sa_server_rport
)))
,
1827 NTATAG_SIGCOMP_ALGORITHM(agent->sa_algorithm)ntatag_sigcomp_algorithm, tag_str_v((agent->sa_algorithm)),
1828 NTATAG_SIGCOMP_OPTIONS(agent->sa_sigcomp_options ?ntatag_sigcomp_options, tag_str_v((agent->sa_sigcomp_options
? agent->sa_sigcomp_options : "sip"))
1829 agent->sa_sigcomp_options :ntatag_sigcomp_options, tag_str_v((agent->sa_sigcomp_options
? agent->sa_sigcomp_options : "sip"))
1830 "sip")ntatag_sigcomp_options, tag_str_v((agent->sa_sigcomp_options
? agent->sa_sigcomp_options : "sip"))
,
1831 NTATAG_SIPFLAGS(agent->sa_flags)ntatag_sipflags, tag_uint_v((agent->sa_flags)),
1832 NTATAG_SIP_T1(agent->sa_t1)ntatag_sip_t1, tag_uint_v((agent->sa_t1)),
1833 NTATAG_SIP_T1X64(agent->sa_t1x64)ntatag_sip_t1x64, tag_uint_v((agent->sa_t1x64)),
1834 NTATAG_SIP_T2(agent->sa_t2)ntatag_sip_t2, tag_uint_v((agent->sa_t2)),
1835 NTATAG_SIP_T4(agent->sa_t4)ntatag_sip_t4, tag_uint_v((agent->sa_t4)),
1836#if HAVE_SOFIA_SMIME0
1837 NTATAG_SMIME(agent->sa_smime)ntatag_smime, tag_ptr_v((agent->sa_smime)),
1838#else
1839 NTATAG_SMIME(NULL)ntatag_smime, tag_ptr_v((((void*)0))),
1840#endif
1841 NTATAG_STATELESS(agent->sa_is_stateless)ntatag_stateless, tag_bool_v((agent->sa_is_stateless)),
1842 NTATAG_TAG_3261(1)ntatag_tag_3261, tag_bool_v((1)),
1843 NTATAG_TIMEOUT_408(agent->sa_timeout_408)ntatag_timeout_408, tag_bool_v((agent->sa_timeout_408)),
1844 NTATAG_TIMER_C(agent->sa_timer_c)ntatag_timer_c, tag_uint_v((agent->sa_timer_c)),
1845 NTATAG_UA(agent->sa_is_a_uas)ntatag_ua, tag_bool_v((agent->sa_is_a_uas)),
1846 NTATAG_UDP_MTU(agent->sa_udp_mtu)ntatag_udp_mtu, tag_uint_v((agent->sa_udp_mtu)),
1847 NTATAG_USER_VIA(agent->sa_user_via)ntatag_user_via, tag_bool_v((agent->sa_user_via)),
1848 NTATAG_USE_NAPTR(agent->sa_use_naptr)ntatag_use_naptr, tag_bool_v((agent->sa_use_naptr)),
1849 NTATAG_USE_SRV(agent->sa_use_srv)ntatag_use_srv, tag_bool_v((agent->sa_use_srv)),
1850 NTATAG_USE_TIMESTAMP(agent->sa_timestamp)ntatag_use_timestamp, tag_bool_v((agent->sa_timestamp)),
1851 NTATAG_SRV_503(agent->sa_srv_503)ntatag_srv_503, tag_bool_v((agent->sa_srv_503)),
1852 TAG_END()(tag_type_t)0, (tag_value_t)0);
1853}
1854
1855/**Get NTA statistics.
1856 *
1857 * The nta_agent_get_stats() function retrieves the stack statistics.
1858 *
1859 * @TAGS
1860 * NTATAG_S_ACKED_TR_REF(),
1861 * NTATAG_S_BAD_MESSAGE_REF(),
1862 * NTATAG_S_BAD_REQUEST_REF(),
1863 * NTATAG_S_BAD_RESPONSE_REF(),
1864 * NTATAG_S_CANCELED_TR_REF(),
1865 * NTATAG_S_CLIENT_TR_REF(),
1866 * NTATAG_S_DIALOG_TR_REF(),
1867 * NTATAG_S_DROP_REQUEST_REF(),
1868 * NTATAG_S_DROP_RESPONSE_REF(),
1869 * NTATAG_S_IRQ_HASH_REF(),
1870 * NTATAG_S_IRQ_HASH_USED_REF(),
1871 * NTATAG_S_LEG_HASH_REF(),
1872 * NTATAG_S_LEG_HASH_USED_REF(),
1873 * NTATAG_S_MERGED_REQUEST_REF(),
1874 * NTATAG_S_ORQ_HASH_REF(),
1875 * NTATAG_S_ORQ_HASH_USED_REF(),
1876 * NTATAG_S_RECV_MSG_REF(),
1877 * NTATAG_S_RECV_REQUEST_REF(),
1878 * NTATAG_S_RECV_RESPONSE_REF(),
1879 * NTATAG_S_RECV_RETRY_REF(),
1880 * NTATAG_S_RETRY_REQUEST_REF(),
1881 * NTATAG_S_RETRY_RESPONSE_REF(),
1882 * NTATAG_S_SENT_MSG_REF(),
1883 * NTATAG_S_SENT_REQUEST_REF(),
1884 * NTATAG_S_SENT_RESPONSE_REF(),
1885 * NTATAG_S_SERVER_TR_REF(),
1886 * NTATAG_S_TOUT_REQUEST_REF(),
1887 * NTATAG_S_TOUT_RESPONSE_REF(),
1888 * NTATAG_S_TRLESS_200_REF(),
1889 * NTATAG_S_TRLESS_REQUEST_REF(),
1890 * NTATAG_S_TRLESS_RESPONSE_REF(), and
1891 * NTATAG_S_TRLESS_TO_TR_REF(),
1892 */
1893int nta_agent_get_stats(nta_agent_t *agent,
1894 tag_type_t tag, tag_value_t value, ...)
1895{
1896 int n;
1897 ta_list ta;
1898
1899 if (!agent)
1900 return su_seterrno(EINVAL22), -1;
1901
1902 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)
;
1903
1904 n = tl_tgets(ta_args(ta)(ta).tl,
1905 NTATAG_S_IRQ_HASH(agent->sa_incoming->iht_size)ntatag_s_irq_hash, tag_usize_v(agent->sa_incoming->iht_size
)
,
1906 NTATAG_S_ORQ_HASH(agent->sa_outgoing->oht_size)ntatag_s_orq_hash, tag_usize_v(agent->sa_outgoing->oht_size
)
,
1907 NTATAG_S_LEG_HASH(agent->sa_dialogs->lht_size)ntatag_s_leg_hash, tag_usize_v(agent->sa_dialogs->lht_size
)
,
1908 NTATAG_S_IRQ_HASH_USED(agent->sa_incoming->iht_used)ntatag_s_irq_hash_used, tag_usize_v(agent->sa_incoming->
iht_used)
,
1909 NTATAG_S_ORQ_HASH_USED(agent->sa_outgoing->oht_used)ntatag_s_orq_hash_used, tag_usize_v(agent->sa_outgoing->
oht_used)
,
1910 NTATAG_S_LEG_HASH_USED(agent->sa_dialogs->lht_used)ntatag_s_leg_hash_used, tag_usize_v(agent->sa_dialogs->
lht_used)
,
1911 NTATAG_S_RECV_MSG(agent->sa_stats->as_recv_msg)ntatag_s_recv_msg, tag_usize_v(agent->sa_stats->as_recv_msg
)
,
1912 NTATAG_S_RECV_REQUEST(agent->sa_stats->as_recv_request)ntatag_s_recv_request, tag_usize_v(agent->sa_stats->as_recv_request
)
,
1913 NTATAG_S_RECV_RESPONSE(agent->sa_stats->as_recv_response)ntatag_s_recv_response, tag_usize_v(agent->sa_stats->as_recv_response
)
,
1914 NTATAG_S_BAD_MESSAGE(agent->sa_stats->as_bad_message)ntatag_s_bad_message, tag_usize_v(agent->sa_stats->as_bad_message
)
,
1915 NTATAG_S_BAD_REQUEST(agent->sa_stats->as_bad_request)ntatag_s_bad_request, tag_usize_v(agent->sa_stats->as_bad_request
)
,
1916 NTATAG_S_BAD_RESPONSE(agent->sa_stats->as_bad_response)ntatag_s_bad_response, tag_usize_v(agent->sa_stats->as_bad_response
)
,
1917 NTATAG_S_DROP_REQUEST(agent->sa_stats->as_drop_request)ntatag_s_drop_request, tag_usize_v(agent->sa_stats->as_drop_request
)
,
1918 NTATAG_S_DROP_RESPONSE(agent->sa_stats->as_drop_response)ntatag_s_drop_response, tag_usize_v(agent->sa_stats->as_drop_response
)
,
1919 NTATAG_S_CLIENT_TR(agent->sa_stats->as_client_tr)ntatag_s_client_tr, tag_usize_v(agent->sa_stats->as_client_tr
)
,
1920 NTATAG_S_SERVER_TR(agent->sa_stats->as_server_tr)ntatag_s_server_tr, tag_usize_v(agent->sa_stats->as_server_tr
)
,
1921 NTATAG_S_DIALOG_TR(agent->sa_stats->as_dialog_tr)ntatag_s_dialog_tr, tag_usize_v(agent->sa_stats->as_dialog_tr
)
,
1922 NTATAG_S_ACKED_TR(agent->sa_stats->as_acked_tr)ntatag_s_acked_tr, tag_usize_v(agent->sa_stats->as_acked_tr
)
,
1923 NTATAG_S_CANCELED_TR(agent->sa_stats->as_canceled_tr)ntatag_s_canceled_tr, tag_usize_v(agent->sa_stats->as_canceled_tr
)
,
1924 NTATAG_S_TRLESS_REQUEST(agent->sa_stats->as_trless_request)ntatag_s_trless_request, tag_usize_v(agent->sa_stats->as_trless_request
)
,
1925 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
)
,
1926 NTATAG_S_TRLESS_RESPONSE(agent->sa_stats->as_trless_response)ntatag_s_trless_response, tag_usize_v(agent->sa_stats->
as_trless_response)
,
1927 NTATAG_S_TRLESS_200(agent->sa_stats->as_trless_200)ntatag_s_trless_200, tag_usize_v(agent->sa_stats->as_trless_200
)
,
1928 NTATAG_S_MERGED_REQUEST(agent->sa_stats->as_merged_request)ntatag_s_merged_request, tag_usize_v(agent->sa_stats->as_merged_request
)
,
1929 NTATAG_S_SENT_MSG(agent->sa_stats->as_sent_msg)ntatag_s_sent_msg, tag_usize_v(agent->sa_stats->as_sent_msg
)
,
1930 NTATAG_S_SENT_REQUEST(agent->sa_stats->as_sent_request)ntatag_s_sent_request, tag_usize_v(agent->sa_stats->as_sent_request
)
,
1931 NTATAG_S_SENT_RESPONSE(agent->sa_stats->as_sent_response)ntatag_s_sent_response, tag_usize_v(agent->sa_stats->as_sent_response
)
,
1932 NTATAG_S_RETRY_REQUEST(agent->sa_stats->as_retry_request)ntatag_s_retry_request, tag_usize_v(agent->sa_stats->as_retry_request
)
,
1933 NTATAG_S_RETRY_RESPONSE(agent->sa_stats->as_retry_response)ntatag_s_retry_response, tag_usize_v(agent->sa_stats->as_retry_response
)
,
1934 NTATAG_S_RECV_RETRY(agent->sa_stats->as_recv_retry)ntatag_s_recv_retry, tag_usize_v(agent->sa_stats->as_recv_retry
)
,
1935 NTATAG_S_TOUT_REQUEST(agent->sa_stats->as_tout_request)ntatag_s_tout_request, tag_usize_v(agent->sa_stats->as_tout_request
)
,
1936 NTATAG_S_TOUT_RESPONSE(agent->sa_stats->as_tout_response)ntatag_s_tout_response, tag_usize_v(agent->sa_stats->as_tout_response
)
,
1937 NTATAG_Q_IN_COMPLETED(agent->sa_in.completed->q_length)ntatag_q_in_completed, tag_size_v(agent->sa_in.completed->
q_length)
,
1938 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)
,
1939 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)
,
1940 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)
,
1941 NTATAG_Q_IN_PRELIMINARY(agent->sa_in.preliminary->q_length)ntatag_q_in_preliminary, tag_size_v(agent->sa_in.preliminary
->q_length)
,
1942 NTATAG_Q_IN_PROCEEDING(agent->sa_in.proceeding->q_length)ntatag_q_in_proceeding, tag_size_v(agent->sa_in.proceeding
->q_length)
,
1943 NTATAG_Q_IN_TERMINATED(agent->sa_in.terminated->q_length)ntatag_q_in_terminated, tag_size_v(agent->sa_in.terminated
->q_length)
,
1944 NTATAG_Q_OUT_COMPLETED(agent->sa_out.completed->q_length)ntatag_q_out_completed, tag_size_v(agent->sa_out.completed
->q_length)
,
1945 NTATAG_Q_OUT_DELAYED(agent->sa_out.delayed->q_length)ntatag_q_out_delayed, tag_size_v(agent->sa_out.delayed->
q_length)
,
1946 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)
,
1947 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)
,
1948 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)
,
1949 NTATAG_Q_OUT_RESOLVING(agent->sa_out.resolving->q_length)ntatag_q_out_resolving, tag_size_v(agent->sa_out.resolving
->q_length)
,
1950 NTATAG_Q_OUT_TERMINATED(agent->sa_out.terminated->q_length)ntatag_q_out_terminated, tag_size_v(agent->sa_out.terminated
->q_length)
,
1951 TAG_END()(tag_type_t)0, (tag_value_t)0);
1952
1953 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))
;
1954
1955 return n;
1956}
1957
1958/**Calculate a new unique tag.
1959 *
1960 * This function generates a series of 2**64 unique tags for @From or @To
1961 * headers. The start of the tag series is derived from the NTP time the NTA
1962 * agent was initialized.
1963 *
1964 */
1965char const *nta_agent_newtag(su_home_t *home, char const *fmt, nta_agent_t *sa)
1966{
1967 char tag[(8 * 8 + 4)/ 5 + 1];
1968
1969 if (sa == NULL((void*)0))
1970 return su_seterrno(EINVAL22), NULL((void*)0);
1971
1972 /* XXX - use a cryptographically safe func here? */
1973 sa->sa_tags += NTA_TAG_PRIME(uint64_t)(0xB9591D1C361C6521ULL);
1974
1975 msg_random_token(tag, sizeof(tag) - 1, &sa->sa_tags, sizeof(sa->sa_tags));
1976
1977 if (fmt && fmt[0])
1978 return su_sprintf(home, fmt, tag);
1979 else
1980 return su_strdup(home, tag);
1981}
1982
1983/**
1984 * Calculate branch value.
1985 */
1986static char const *stateful_branch(su_home_t *home, nta_agent_t *sa)
1987{
1988 char branch[(8 * 8 + 4)/ 5 + 1];
1989
1990 /* XXX - use a cryptographically safe func here? */
1991 sa->sa_branch += NTA_BRANCH_PRIME(uint64_t)(0xB9591D1C361C6521ULL);
1992
1993 msg_random_token(branch, sizeof(branch) - 1,
1994 &sa->sa_branch, sizeof(sa->sa_branch));
1995
1996 return su_sprintf(home, "branch=z9hG4bK%s", branch);
1997}
1998
1999#include <sofia-sip/su_md5.h>
2000
2001/**
2002 * Calculate branch value for stateless operation.
2003 *
2004 * XXX - should include HMAC of previous @Via line.
2005 */
2006static
2007char const *stateless_branch(nta_agent_t *sa,
2008 msg_t *msg,
2009 sip_t const *sip,
2010 tp_name_t const *tpn)
2011{
2012 su_md5_t md5[1];
2013 uint8_t digest[SU_MD5_DIGEST_SIZE16];
2014 char branch[(SU_MD5_DIGEST_SIZE16 * 8 + 4)/ 5 + 1];
2015 sip_route_t const *r;
2016
2017 assert(sip->sip_request)((void) sizeof ((sip->sip_request) ? 1 : 0), __extension__
({ if (sip->sip_request) ; else __assert_fail ("sip->sip_request"
, "nta.c", 2017, __extension__ __PRETTY_FUNCTION__); }))
;
2018
2019 if (!sip->sip_via)
2020 return stateful_branch(msg_home(msg)((su_home_t*)(msg)), sa);
2021
2022 su_md5_init(md5);
2023
2024 su_md5_str0update(md5, tpn->tpn_host);
2025 su_md5_str0update(md5, tpn->tpn_port);
2026
2027 url_update(md5, sip->sip_request->rq_url);
2028 if (sip->sip_call_id) {
2029 su_md5_str0update(md5, sip->sip_call_id->i_id);
2030 }
2031 if (sip->sip_from) {
2032 url_update(md5, sip->sip_from->a_url);
2033 su_md5_stri0update(md5, sip->sip_from->a_tag);
2034 }
2035 if (sip->sip_to) {
2036 url_update(md5, sip->sip_to->a_url);
2037 /* XXX - some broken implementations include To tag in CANCEL */
2038 /* su_md5_str0update(md5, sip->sip_to->a_tag); */
2039 }
2040 if (sip->sip_cseq) {
2041 uint32_t cseq = htonl(sip->sip_cseq->cs_seq);
2042 su_md5_update(md5, &cseq, sizeof(cseq));
2043 }
2044
2045 for (r = sip->sip_route; r; r = r->r_next)
2046 url_update(md5, r->r_url);
2047
2048 su_md5_digest(md5, digest);
2049
2050 msg_random_token(branch, sizeof(branch) - 1, digest, sizeof(digest));
2051
2052 return su_sprintf(msg_home(msg)((su_home_t*)(msg)), "branch=z9hG4bK.%s", branch);
2053}
2054
2055/* ====================================================================== */
2056/* 2) Transport interface */
2057
2058/* Local prototypes */
2059static int agent_create_master_transport(nta_agent_t *self, tagi_t *tags);
2060static int agent_init_via(nta_agent_t *self, tport_t *primaries, int use_maddr);
2061static int agent_init_contact(nta_agent_t *self);
2062static void agent_recv_message(nta_agent_t *agent,
2063 tport_t *tport,
2064 msg_t *msg,
2065 sip_via_t *tport_via,
2066 su_time_t now);
2067static void agent_tp_error(nta_agent_t *agent,
2068 tport_t *tport,
2069 int errcode,
2070 char const *remote);
2071static void agent_update_tport(nta_agent_t *agent, tport_t *);
2072
2073/**For each transport, we have name used by tport module, SRV prefixes used
2074 * for resolving, and NAPTR service/conversion.
2075 */
2076static
2077struct sipdns_tport {
2078 char name[6]; /**< Named used by tport module */
2079 char port[6]; /**< Default port number */
2080 char prefix[14]; /**< Prefix for SRV domains */
2081 char service[10]; /**< NAPTR service */
2082}
2083#define SIPDNS_TRANSPORTS(6) (6)
2084const sipdns_tports[SIPDNS_TRANSPORTS(6)] = {
2085 { "udp", "5060", "_sip._udp.", "SIP+D2U" },
2086 { "tcp", "5060", "_sip._tcp.", "SIP+D2T" },
2087 { "sctp", "5060", "_sip._sctp.", "SIP+D2S" },
2088 { "tls", "5061", "_sips._tcp.", "SIPS+D2T" },
2089 { "ws", "5080", "_sips._ws.", "SIP+D2W" },
2090 { "wss", "5081", "_sips._wss.", "SIPS+D2W" },
2091};
2092
2093static char const * const tports_sip[] =
2094 {
2095 "udp", "tcp", "sctp", "ws", NULL((void*)0)
2096 };
2097
2098static char const * const tports_sips[] =
2099 {
2100 "tls", "wss", "ws", NULL((void*)0)
2101 };
2102
2103static tport_stack_class_t nta_agent_class[1] =
2104 {{
2105 sizeof(nta_agent_class),
2106 agent_recv_message,
2107 agent_tp_error,
2108 nta_msg_create_for_transport,
2109 agent_update_tport,
2110 }};
2111
2112
2113/** Add a transport to the agent.
2114 *
2115 * Creates a new transport and binds it
2116 * to the port specified by the @a uri. The @a uri must have sip: or sips:
2117 * scheme or be a wildcard uri ("*"). The @a uri syntax allowed is as
2118 * follows:
2119 *
2120 * @code url <scheme>:<host>[:<port>]<url-params> @endcode
2121 * where <url-params> may be
2122 * @code
2123 * ;transport=<xxx>
2124 * ;maddr=<actual addr>
2125 * ;comp=sigcomp
2126 * @endcode
2127 *
2128 * The scheme part determines which transports are used. "sip" implies UDP
2129 * and TCP, "sips" TLS over TCP. In the future, more transports can be
2130 * supported, for instance, "sip" can use SCTP or DCCP, "sips" DTLS or TLS
2131 * over SCTP.
2132 *
2133 * The "host" part determines what address/domain name is used in @Contact.
2134 * An "*" in "host" part is shorthand for any local IP address. 0.0.0.0
2135 * means that the only the IPv4 addresses are used. [::] means that only
2136 * the IPv6 addresses are used. If a domain name or a specific IP address
2137 * is given as "host" part, an additional "maddr" parameter can be used to
2138 * control which addresses are used by the stack when binding listen
2139 * sockets for incoming requests.
2140 *
2141 * The "port" determines what port is used in contact, and to which port the
2142 * stack binds in order to listen for incoming requests. Empty or missing
2143 * port means that default port should be used (5060 for sip, 5061 for
2144 * sips). An "*" in "port" part means any port, i.e., the stack binds to an
2145 * ephemeral port.
2146 *
2147 * The "transport" parameter determines the transport protocol that is used
2148 * and how they are preferred. If no protocol is specified, both UDP and TCP
2149 * are used for SIP URL and TLS for SIPS URL. The preference can be
2150 * indicated with a comma-separated list of transports, for instance,
2151 * parameter @code transport=tcp,udp @endcode indicates that TCP is
2152 * preferred to UDP.
2153 *
2154 * The "maddr" parameter determines to which address the stack binds in
2155 * order to listen for incoming requests. An "*" in "maddr" parameter is
2156 * shorthand for any local IP address. 0.0.0.0 means that only IPv4 sockets
2157 * are created. [::] means that only IPv6 sockets are created.
2158 *
2159 * The "comp" parameter determines the supported compression protocol.
2160 * Currently only sigcomp is supported (with suitable library).
2161 *
2162 * @par Examples:
2163 * @code sip:172.21.40.24;maddr=* @endcode \n
2164 * @code sip:172.21.40.24:50600;transport=TCP,UDP;comp=sigcomp @endcode \n
2165 * @code sips:* @endcode
2166 *
2167 * @return
2168 * On success, zero is returned. On error, -1 is returned, and @a errno is
2169 * set appropriately.
2170 */
2171int nta_agent_add_tport(nta_agent_t *self,
2172 url_string_t const *uri,
2173 tag_type_t tag, tag_value_t value, ...)
2174{
2175 url_t *url;
2176 char tp[32];
2177 char maddr[256];
2178 char comp[32];
2179 tp_name_t tpn[1] = {{ NULL((void*)0) }};
2180 char const * const * tports = tports_sip;
2181 int error;
2182 ta_list ta;
2183 char *tps[9] = {0};
2184
2185 if (self == NULL((void*)0)) {
2186 su_seterrno(EINVAL22);
2187 return -1;
2188 }
2189
2190 if (uri == NULL((void*)0))
2191 uri = (url_string_t *)"sip:*";
2192 else if (url_string_p(uri) ?
2193 strcmp(uri->us_str, "*") == 0 :
2194 uri->us_url->url_type == url_any) {
2195 uri = (url_string_t *)"sip:*:*";
2196 }
2197
2198 if (!(url = url_hdup(self->sa_home, uri->us_url)) ||
2199 (url->url_type != url_sip && url->url_type != url_sips && url->url_type != url_urn)) {
2200 if (url_string_p(uri))
2201 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__
, 2201, "nta: %s: invalid bind URL\n", uri->us_str)) : (void
)0)
;
2202 else
2203 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__
, 2203, "nta: invalid bind URL\n" "%s", "")) : (void)0)
;
2204 su_seterrno(EINVAL22);
2205 return -1;
2206 }
2207
2208 tpn->tpn_canon = url->url_host;
2209 tpn->tpn_host = url->url_host;
2210 tpn->tpn_port = url_port(url);
2211
2212 if (url->url_type == url_sip || url->url_type == url_urn) {
2213 tpn->tpn_proto = "*";
2214 tports = tports_sip;
2215 if (!tpn->tpn_port || !tpn->tpn_port[0])
2216 tpn->tpn_port = SIP_DEFAULT_SERV"5060";
2217 }
2218 else {
2219 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", 2219, __extension__ __PRETTY_FUNCTION__); }))
;
2220 tpn->tpn_proto = "*";
2221 tports = tports_sips;
2222 if (!tpn->tpn_port || !tpn->tpn_port[0])
2223 tpn->tpn_port = SIPS_DEFAULT_SERV"5061";
2224 }
2225
2226 if (url->url_params) {
2227 if (url_param(url->url_params, "transport", tp, sizeof(tp)) > 0) {
2228 if (strchr(tp, ',')) {
2229 int i; char *t;
2230
2231 /* Split tp into transports */
2232 for (i = 0, t = tp; t && i < 8; i++) {
2233 tps[i] = t;
2234 if ((t = strchr(t, ',')))
2235 *t++ = '\0';
2236 }
2237
2238 tps[i] = NULL((void*)0);
2239 tports = (char const * const *)tps;
2240 } else {
2241 tpn->tpn_proto = tp;
2242 }
2243 }
2244 if (url_param(url->url_params, "maddr", maddr, sizeof(maddr)) > 0)
2245 tpn->tpn_host = maddr;
2246 if (url_param(url->url_params, "comp", comp, sizeof(comp)) > 0)
2247 tpn->tpn_comp = comp;
2248
2249 if (tpn->tpn_comp &&
2250 (nta_compressor_vtable == NULL((void*)0) ||
2251 !su_casematch(tpn->tpn_comp, nta_compressor_vtable->ncv_name))) {
2252 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__
, 2253, "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)
2253 (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__
, 2253, "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)
;
2254 }
2255 }
2256
2257 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)
;
2258
2259 if (self->sa_tports == NULL((void*)0)) {
2260 if (agent_create_master_transport(self, ta_args(ta)(ta).tl) < 0) {
2261 error = su_errno();
2262 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__
, 2263, "nta: cannot create master transport: %s\n", 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: cannot create master transport: %s\n", su_strerror
(error))) : (void)0)
;
2264 goto error;
2265 }
2266 }
2267
2268 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) {
2269 error = su_errno();
2270 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__
, 2276, "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)
2271 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__
, 2276, "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)
2272 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__
, 2276, "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)
2273 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__
, 2276, "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)
2274 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__
, 2276, "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)
2275 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__
, 2276, "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)
2276 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__
, 2276, "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)
;
2277 goto error;
2278 }
2279 else
2280 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__
, 2285, "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)
2281 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__
, 2285, "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)
2282 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__
, 2285, "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)
2283 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__
, 2285, "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)
2284 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__
, 2285, "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)
2285 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__
, 2285, "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)
;
2286
2287 /* XXX - when to use maddr? */
2288 if ((agent_init_via(self, tport_primaries(self->sa_tports), 0)) < 0) {
2289 error = su_errno();
2290 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__
, 2290, "nta: cannot create Via headers\n" "%s", "")) : (void
)0)
;
2291 goto error;
2292 }
2293 else
2294 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__
, 2294, "nta: Via fields initialized\n" "%s", "")) : (void)0)
;
2295
2296 if ((agent_init_contact(self)) < 0) {
2297 error = su_errno();
2298 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__
, 2298, "nta: cannot create Contact header\n" "%s", "")) : (void
)0)
;
2299 goto error;
2300 }
2301 else
2302 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__
, 2302, "nta: Contact header created\n" "%s", "")) : (void)0)
;
2303
2304 su_free(self->sa_home, url);
2305 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))
;
2306
2307 return 0;
2308
2309 error:
2310 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))
;
2311 su_seterrno(error);
2312 return -1;
2313}
2314
2315static
2316int agent_create_master_transport(nta_agent_t *self, tagi_t *tags)
2317{
2318 self->sa_tports =
2319 tport_tcreate(self, nta_agent_class, self->sa_root,
2320 TPTAG_IDLE(1800000)tptag_idle, tag_uint_v((1800000)),
2321 TAG_NEXT(tags)tag_next, (tag_value_t)(tags));
2322
2323 if (!self->sa_tports)
2324 return -1;
2325
2326 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__
, 2326, "nta: master transport created\n" "%s", "")) : (void)
0)
;
2327
2328 return 0;
2329}
2330
2331
2332/** Initialize @Via headers. */
2333static
2334int agent_init_via(nta_agent_t *self, tport_t *primaries, int use_maddr)
2335{
2336 sip_via_t *via = NULL((void*)0), *new_via, *dup_via, *v, **vv = &via;
2337 sip_via_t *new_vias, **next_new_via, *new_publics, **next_new_public;
2338 tport_t *tp;
2339 su_addrinfo_t const *ai;
2340
2341 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))
];
2342
2343 su_home_auto(autohome, sizeof autohome);
2344
2345 self->sa_tport_ip4 = 0;
2346 self->sa_tport_ip6 = 0;
2347 self->sa_tport_udp = 0;
2348 self->sa_tport_tcp = 0;
2349 self->sa_tport_sctp = 0;
2350 self->sa_tport_tls = 0;
2351 self->sa_tport_ws = 0;
2352 self->sa_tport_wss = 0;
2353
2354 /* Set via fields for the tports */
2355 for (tp = primaries; tp; tp = tport_next(tp)) {
2356 int maddr;
2357 tp_name_t tpn[1];
2358 char const *comp = NULL((void*)0);
2359
2360 *tpn = *tport_name(tp);
2361
2362 assert(tpn->tpn_proto)((void) sizeof ((tpn->tpn_proto) ? 1 : 0), __extension__ (
{ if (tpn->tpn_proto) ; else __assert_fail ("tpn->tpn_proto"
, "nta.c", 2362, __extension__ __PRETTY_FUNCTION__); }))
;
2363 assert(tpn->tpn_canon)((void) sizeof ((tpn->tpn_canon) ? 1 : 0), __extension__ (
{ if (tpn->tpn_canon) ; else __assert_fail ("tpn->tpn_canon"
, "nta.c", 2363, __extension__ __PRETTY_FUNCTION__); }))
;
2364 assert(tpn->tpn_host)((void) sizeof ((tpn->tpn_host) ? 1 : 0), __extension__ ({
if (tpn->tpn_host) ; else __assert_fail ("tpn->tpn_host"
, "nta.c", 2364, __extension__ __PRETTY_FUNCTION__); }))
;
2365 assert(tpn->tpn_port)((void) sizeof ((tpn->tpn_port) ? 1 : 0), __extension__ ({
if (tpn->tpn_port) ; else __assert_fail ("tpn->tpn_port"
, "nta.c", 2365, __extension__ __PRETTY_FUNCTION__); }))
;
2366
2367#if 0
2368 if (getenv("SIP_UDP_CONNECT")
2369 && strcmp(tpn->tpn_proto, "udp") == 0)
2370 tport_set_params(tp, TPTAG_CONNECT(1)tptag_connect, tag_bool_v((1)), TAG_END()(tag_type_t)0, (tag_value_t)0);
2371#endif
2372
2373 if (tport_has_ip4(tp)) self->sa_tport_ip4 = 1;
2374
2375#if SU_HAVE_IN61
2376 if (tport_has_ip6(tp)) self->sa_tport_ip6 = 1;
2377#endif
2378
2379 if (su_casematch(tpn->tpn_proto, "udp"))
2380 self->sa_tport_udp = 1;
2381 else if (su_casematch(tpn->tpn_proto, "tcp"))
2382 self->sa_tport_tcp = 1;
2383 else if (su_casematch(tpn->tpn_proto, "sctp"))
2384 self->sa_tport_sctp = 1;
2385 else if (su_casematch(tpn->tpn_proto, "ws"))
2386 self->sa_tport_ws = 1;
2387 else if (su_casematch(tpn->tpn_proto, "wss"))
2388 self->sa_tport_wss = 1;
2389
2390 if (tport_has_tls(tp)) self->sa_tport_tls = 1;
2391
2392 ai = tport_get_address(tp);
2393
2394 for (; ai; ai = ai->ai_next) {
2395 char host[TPORT_HOSTPORTSIZE(55)] = "";
2396 char sport[8];
2397 char const *canon = ai->ai_canonname;
2398 su_sockaddr_t *su = (void *)ai->ai_addr;
2399 int port;
2400
2401 if (su) {
2402 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);
2403 maddr = use_maddr && !su_casematch(canon, host);
2404 port = ntohs(su->su_portsu_sin.sin_port);
2405 }
2406 else {
2407 msg_random_token(host, 16, NULL((void*)0), 0);
2408 canon = strcat(host, ".is.invalid");
2409 maddr = 0;
2410 port = 0;
2411 }
2412
2413 if (su_casenmatch(tpn->tpn_proto, "tls", 3)
2414 ? port == SIPS_DEFAULT_PORTSIPS_DEFAULT_PORT
2415 : port == SIP_DEFAULT_PORTSIP_DEFAULT_PORT)
2416 port = 0;
2417
2418 snprintf(sport, sizeof sport, ":%u", port);
2419
2420 comp = tpn->tpn_comp;
2421
2422 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__
, 2428, "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)
2423 "%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__
, 2428, "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)
2424 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__
, 2428, "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)
2425 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__
, 2428, "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)
2426 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__
, 2428, "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)
2427 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__
, 2428, "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)
2428 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__
, 2428, "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)
;
2429
2430 v = sip_via_format(autohome,
2431 "%s/%s %s%s%s%s%s%s",
2432 SIP_VERSION_CURRENTsip_version_2_0, tpn->tpn_proto,
2433 canon, port ? sport : "",
2434 maddr ? ";maddr=" : "", maddr ? host : "",
2435 comp ? ";comp=" : "", comp ? comp : "");
2436 if (v == NULL((void*)0))
2437 goto error;
2438
2439 v->v_comment = tpn->tpn_ident;
2440 v->v_common->h_data = tp; /* Nasty trick */
2441 *vv = v; vv = &(*vv)->v_next;
2442 }
2443 }
2444
2445 if (!via) {
2446 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__
, 2446, "nta: agent_init_via failed\n" "%s", "")) : (void)0)
;
2447 goto error;
2448 }
2449
2450 /* Duplicate the list bind to the transports */
2451 new_via = sip_via_dup(self->sa_home, via);
2452 /* Duplicate the complete list shown to the application */
2453 dup_via = sip_via_dup(self->sa_home, via);
2454
2455 if (via && (!new_via || !dup_via)) {
2456 msg_header_free(self->sa_home, (void *)new_via);
2457 msg_header_free(self->sa_home, (void *)dup_via);
2458 goto error;
2459 }
2460
2461 new_vias = NULL((void*)0), next_new_via = &new_vias;
2462 new_publics = NULL((void*)0), next_new_public = &new_publics;
2463
2464 /* Set via field magic for the tports */
2465 for (tp = primaries; tp; tp = tport_next(tp)) {
2466 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",
2466, __extension__ __PRETTY_FUNCTION__); }))
;
2467 v = tport_magic(tp);
2468 tport_set_magic(tp, new_via);
2469 msg_header_free(self->sa_home, (void *)v);
2470
2471 if (tport_is_public(tp))
2472 *next_new_public = dup_via;
2473 else
2474 *next_new_via = dup_via;
2475
2476 while (via->v_next && via->v_next->v_common->h_data == tp)
2477 via = via->v_next, new_via = new_via->v_next, dup_via = dup_via->v_next;
2478
2479 via = via->v_next;
2480 /* Break the link in via list between transports */
2481 vv = &new_via->v_next, new_via = *vv, *vv = NULL((void*)0);
2482 vv = &dup_via->v_next, dup_via = *vv, *vv = NULL((void*)0);
2483
2484 if (tport_is_public(tp))
2485 while (*next_new_public) next_new_public = &(*next_new_public)->v_next;
2486 else
2487 while (*next_new_via) next_new_via = &(*next_new_via)->v_next;
2488 }
2489
2490 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", 2490, __extension__ __PRETTY_FUNCTION__); }))
;
2491 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", 2491, __extension__ __PRETTY_FUNCTION__); }))
;
2492
2493 if (self->sa_tport_udp)
2494 agent_set_udp_params(self, self->sa_udp_mtu);
2495
2496 v = self->sa_vias;
2497 self->sa_vias = new_vias;
2498 msg_header_free(self->sa_home, (void *)v);
2499
2500 v = self->sa_public_vias;
2501 self->sa_public_vias = new_publics;
2502 msg_header_free(self->sa_home, (void *)v);
2503
2504 su_home_deinit(autohome);
2505
2506 return 0;
2507
2508 error:
2509 su_home_deinit(autohome);
2510 return -1;
2511}
2512
2513
2514/** Initialize main contact header. */
2515static
2516int agent_init_contact(nta_agent_t *self)
2517{
2518 sip_via_t const *v1, *v2;
2519 char const *tp;
2520
2521 if (self->sa_contact)
2522 return 0;
2523
2524 for (v1 = self->sa_vias ? self->sa_vias : self->sa_public_vias;
2525 v1;
2526 v1 = v1->v_next) {
2527 if (host_is_ip_address(v1->v_host)) {
2528 if (!host_is_local(v1->v_host))
2529 break;
2530 }
2531 else if (!host_has_domain_invalid(v1->v_host)) {
2532 break;
2533 }
2534 }
2535
2536 if (v1 == NULL((void*)0))
2537 v1 = self->sa_vias ? self->sa_vias : self->sa_public_vias;
2538
2539 if (!v1)
2540 return -1;
2541
2542 tp = strrchr(v1->v_protocol, '/');
2543 if (!tp++)
2544 return -1;
2545
2546 v2 = v1->v_next;
2547
2548 if (v2 &&
2549 su_casematch(v1->v_host, v2->v_host) &&
2550 su_casematch(v1->v_port, v2->v_port)) {
2551 char const *p1 = v1->v_protocol, *p2 = v2->v_protocol;
2552
2553 if (!su_casematch(p1, sip_transport_udp))
2554 p1 = v2->v_protocol, p2 = v1->v_protocol;
2555
2556 if (su_casematch(p1, sip_transport_udp) &&
2557 su_casematch(p2, sip_transport_tcp))
2558 /* Do not include transport if we have both UDP and TCP */
2559 tp = NULL((void*)0);
2560 }
2561
2562 self->sa_contact =
2563 sip_contact_create_from_via_with_transport(self->sa_home, v1, NULL((void*)0), tp);
2564
2565 if (!self->sa_contact)
2566 return -1;
2567
2568 agent_tag_init(self);
2569
2570 return 0;
2571}
2572
2573/** Return @Via line corresponging to tport. */
2574static
2575sip_via_t const *agent_tport_via(tport_t *tport)
2576{
2577 sip_via_t *v = tport_magic(tport);
2578 while (v && v->v_next)
2579 v = v->v_next;
2580 return v;
2581}
2582
2583/** Insert @Via to a request message */
2584static
2585int outgoing_insert_via(nta_outgoing_t *orq,
2586 sip_via_t const *via)
2587{
2588 nta_agent_t *self = orq->orq_agent;
2589 msg_t *msg = orq->orq_request;
2590 sip_t *sip = sip_object(msg);
2591 char const *branch = orq->orq_via_branch;
2592 int already = orq->orq_user_via || orq->orq_via_added;
2593 int user_via = orq->orq_user_via;
2594 sip_via_t *v;
2595 int clear = 0;
2596
2597 assert(sip)((void) sizeof ((sip) ? 1 : 0), __extension__ ({ if (sip) ; else
__assert_fail ("sip", "nta.c", 2597, __extension__ __PRETTY_FUNCTION__
); }))
; assert(via)((void) sizeof ((via) ? 1 : 0), __extension__ ({ if (via) ; else
__assert_fail ("via", "nta.c", 2597, __extension__ __PRETTY_FUNCTION__
); }))
;
2598
2599 if (already && sip->sip_via) {
2600 /* Use existing @Via */
2601 v = sip->sip_via;
2602 }
2603 else if (msg && via && sip->sip_request &&
2604 (v = sip_via_copy(msg_home(msg)((su_home_t*)(msg)), via))) {
2605 if (msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)v) < 0)
2606 return -1;
2607 orq->orq_via_added = 1;
2608 }
2609 else
2610 return -1;
2611
2612 if (!v->v_rport &&
2613 ((self->sa_rport && v->v_protocol == sip_transport_udp) ||
2614 (self->sa_tcp_rport && v->v_protocol == sip_transport_tcp) ||
2615 (self->sa_tls_rport && v->v_protocol == sip_transport_tls)))
2616 msg_header_add_param(msg_home(msg)((su_home_t*)(msg)), v->v_common, "rport");
2617
2618 if (!orq->orq_tpn->tpn_comp)
2619 msg_header_remove_param(v->v_common, "comp");
2620
2621 if (branch && branch != v->v_branch) {
2622 char const *bvalue = branch + strcspn(branch, "=");
2623 if (*bvalue) bvalue++;
2624 if (!v->v_branch || !su_casematch(bvalue, v->v_branch))
2625 msg_header_replace_param(msg_home(msg)((su_home_t*)(msg)), v->v_common, branch);
2626 }
2627
2628 if (!su_casematch(via->v_protocol, v->v_protocol))
2629 clear = 1, v->v_protocol = via->v_protocol;
2630
2631 /* XXX - should we do this? */
2632 if ((!user_via || !v->v_host) &&
2633 !su_strmatch(via->v_host, v->v_host))
2634 clear = 1, v->v_host = via->v_host;
2635
2636 if ((!user_via || !v->v_port ||
2637 /* Replace port in user Via only if we use udp and no rport */
2638 (v->v_protocol == sip_transport_udp && !v->v_rport &&
2639 !orq->orq_stateless)) &&
2640 !su_strmatch(via->v_port, v->v_port))
2641 clear = 1, v->v_port = via->v_port;
2642
2643 if (clear)
2644 msg_fragment_clear(v->v_common);
2645
2646 return 0;
2647}
2648
2649/** Get destination name from @Via.
2650 *
2651 * If @a using_rport is non-null, try rport.
2652 * If *using_rport is non-zero, try rport even if <protocol> is not UDP.
2653 * If <protocol> is UDP, set *using_rport to zero.
2654 */
2655static
2656int nta_tpn_by_via(tp_name_t *tpn, sip_via_t const *v, int *using_rport)
2657{
2658 if (!v)
2659 return -1;
2660
2661 tpn->tpn_proto = sip_via_transport(v);
2662 tpn->tpn_canon = v->v_host;
2663
2664 if (v->v_maddr)
2665 tpn->tpn_host = v->v_maddr;
2666 else if (v->v_received)
2667 tpn->tpn_host = v->v_received;
2668 else
2669 tpn->tpn_host = v->v_host;
2670
2671 tpn->tpn_port = sip_via_port(v, using_rport);
2672 tpn->tpn_comp = v->v_comp;
2673 tpn->tpn_ident = NULL((void*)0);
2674
2675 return 0;
2676}
2677
2678/** Get transport name from URL. */
2679static int
2680nta_tpn_by_url(su_home_t *home,
2681 tp_name_t *tpn,
2682 char const **scheme,
2683 char const **port,
2684 url_string_t const *us)
2685{
2686 url_t url[1];
2687 isize_t n;
2688 char *b;
2689
2690 n = url_xtra(us->us_url);
2691 b = su_alloc(home, n);
2692
2693 if (b == NULL((void*)0) || url_dup(b, n, url, us->us_url) < 0) {
2694 su_free(home, b);
2695 return -1;
2696 }
2697
2698 if (url->url_type != url_sip &&
2699 url->url_type != url_urn &&
2700 url->url_type != url_sips &&
2701 url->url_type != url_im &&
2702 url->url_type != url_pres) {
2703 su_free(home, b);
2704 return -1;
2705 }
2706
2707 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__
, 2707, "nta: selecting scheme %s\n", url->url_scheme)) : (
void)0)
;
2708
2709 *scheme = url->url_scheme;
2710
2711 tpn->tpn_proto = NULL((void*)0);
2712 tpn->tpn_canon = url->url_host;
2713 tpn->tpn_host = url->url_host;
2714
2715 if (url->url_params) {
2716 for (b = (char *)url->url_params; b[0]; b += n) {
2717 n = strcspn(b, ";");
2718
2719 if (n > 10 && su_casenmatch(b, "transport=", 10))
2720 tpn->tpn_proto = b + 10;
2721 else if (n > 5 && su_casenmatch(b, "comp=", 5))
2722 tpn->tpn_comp = b + 5;
2723 else if (n > 6 && su_casenmatch(b, "maddr=", 6))
2724 tpn->tpn_host = b + 6;
2725
2726 if (b[n])
2727 b[n++] = '\0';
2728 }
2729 }
2730
2731 if ((*port = url->url_port))
2732 tpn->tpn_port = url->url_port;
2733
2734 tpn->tpn_ident = NULL((void*)0);
2735
2736 if (tpn->tpn_proto) {
2737 if (su_casematch(url->url_scheme, "sips") && su_casematch(tpn->tpn_proto, "ws")) {
2738 tpn->tpn_proto = "wss";
2739 }
2740 return 1;
2741 }
2742
2743 if (su_casematch(url->url_scheme, "sips"))
2744 tpn->tpn_proto = "tls";
2745 else
2746 tpn->tpn_proto = "*";
2747
2748 return 0;
2749}
2750
2751/** Handle transport errors. */
2752static
2753void agent_tp_error(nta_agent_t *agent,
2754 tport_t *tport,
2755 int errcode,
2756 char const *remote)
2757{
2758 su_llog(nta_log, 1,_su_llog(nta_log, 1, "nta.c", (const char *)__func__, 2761, "nta_agent: tport: %s%s%s\n"
, remote ? remote : "", remote ? ": " : "", su_strerror(errcode
))
2759 "nta_agent: tport: %s%s%s\n",_su_llog(nta_log, 1, "nta.c", (const char *)__func__, 2761, "nta_agent: tport: %s%s%s\n"
, remote ? remote : "", remote ? ": " : "", su_strerror(errcode
))
2760 remote ? remote : "", remote ? ": " : "",_su_llog(nta_log, 1, "nta.c", (const char *)__func__, 2761, "nta_agent: tport: %s%s%s\n"
, remote ? remote : "", remote ? ": " : "", su_strerror(errcode
))
2761 su_strerror(errcode))_su_llog(nta_log, 1, "nta.c", (const char *)__func__, 2761, "nta_agent: tport: %s%s%s\n"
, remote ? remote : "", remote ? ": " : "", su_strerror(errcode
))
;
2762
2763 if (agent->sa_error_tport) {
2764 agent->sa_error_tport(agent->sa_error_magic, agent, tport);
2765 }
2766}
2767
2768/** Handle updated transport addresses */
2769static void agent_update_tport(nta_agent_t *self, tport_t *tport)
2770{
2771 /* Initialize local Vias first */
2772 agent_init_via(self, tport_primaries(self->sa_tports), 0);
2773
2774 if (self->sa_update_tport) {
2775 self->sa_update_tport(self->sa_update_magic, self);
2776 }
2777 else {
2778 /* XXX - we should do something else? */
2779 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__
, 2780, "%s(%p): %s\n", "nta", (void *)self, "transport address updated"
)) : (void)0)
2780 "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__
, 2780, "%s(%p): %s\n", "nta", (void *)self, "transport address updated"
)) : (void)0)
;
2781 }
2782}
2783
2784/* ====================================================================== */
2785/* 3) Message dispatch */
2786
2787static void agent_recv_request(nta_agent_t *agent,
2788 msg_t *msg,
2789 sip_t *sip,
2790 tport_t *tport);
2791static int agent_check_request_via(nta_agent_t *agent,
2792 msg_t *msg,
2793 sip_t *sip,
2794 sip_via_t *v,
2795 tport_t *tport);
2796static int agent_aliases(nta_agent_t const *, url_t [], tport_t *);
2797static void agent_recv_response(nta_agent_t*, msg_t *, sip_t *,
2798 sip_via_t *, tport_t*);
2799static void agent_recv_garbage(nta_agent_t*, msg_t*, tport_t*);
2800
2801#if HAVE_SOFIA_SRESOLV1
2802static void outgoing_resolve(nta_outgoing_t *orq,
2803 int explicit_transport,
2804 enum nta_res_order_e order);
2805su_inlinestatic inline void outgoing_cancel_resolver(nta_outgoing_t *orq);
2806su_inlinestatic inline void outgoing_destroy_resolver(nta_outgoing_t *orq);
2807static int outgoing_other_destinations(nta_outgoing_t const *orq);
2808static int outgoing_try_another(nta_outgoing_t *orq);
2809#else
2810#define outgoing_other_destinations(orq) (0)
2811#define outgoing_try_another(orq) (0)
2812#endif
2813
2814/** Handle incoming message. */
2815static
2816void agent_recv_message(nta_agent_t *agent,
2817 tport_t *tport,
2818 msg_t *msg,
2819 sip_via_t *tport_via,
2820 su_time_t now)
2821{
2822 sip_t *sip = sip_object(msg);
2823
2824 if (sip && sip->sip_request) {
2825 agent_recv_request(agent, msg, sip, tport);
2826 }
2827 else if (sip && sip->sip_status) {
2828 agent_recv_response(agent, msg, sip, tport_via, tport);
2829 }
2830 else {
2831 agent_recv_garbage(agent, msg, tport);
2832 }
2833}
2834
2835#ifdef HAVE_ZLIB_COMPRESS1
2836int sip_content_encoding_Xflate(msg_t *msg, sip_t *sip, int inflate, int check)
2837{
2838 char const *method_name;
2839 unsigned cseq = sip->sip_cseq ? sip->sip_cseq->cs_seq : 0;
2840 int ok = !check;
2841
2842 if (!sip->sip_payload) {
2843 return 0;
2844 }
2845
2846 if (sip->sip_request) {
2847 method_name = sip->sip_request->rq_method_name;
2848 } else if (sip->sip_cseq) {
2849 method_name = sip->sip_cseq->cs_method_name;
2850 } else {
2851 method_name = "Unknown";
2852 }
2853
2854 if (!ok) {
2855 if (sip->sip_content_encoding && sip->sip_content_encoding->k_items) {
2856 const char *val = sip->sip_content_encoding->k_items[0];
2857 if (val && (!strcasecmp(val, "gzip") || !strcasecmp(val, "deflate"))) {
2858 ok = 1;
2859 }
2860 }
2861 }
2862
2863 if (ok) {
2864 unsigned long n = 0;
2865 void *decoded = NULL((void*)0);
2866 const char *id = "N/A";
2867 const char *orig_payload = sip->sip_payload->pl_data;
2868
2869 n = sip->sip_payload->pl_len * 10;
2870
2871 decoded = su_alloc(msg_home(msg)((su_home_t*)(msg)), n);
2872 assert(decoded)((void) sizeof ((decoded) ? 1 : 0), __extension__ ({ if (decoded
) ; else __assert_fail ("decoded", "nta.c", 2872, __extension__
__PRETTY_FUNCTION__); }))
;
2873
2874 if (inflate) {
2875 uncompress(decoded, &n, (void *)sip->sip_payload->pl_data, (unsigned long)sip->sip_payload->pl_len);
2876 } else {
2877 compress(decoded, &n, (void *)sip->sip_payload->pl_data, (unsigned long)sip->sip_payload->pl_len);
2878 }
2879
2880 sip->sip_payload = sip_payload_create(msg_home(msg)((su_home_t*)(msg)), decoded, n);
2881 sip->sip_content_encoding = sip_content_encoding_make(msg_home(msg)((su_home_t*)(msg)), "deflate");
2882
2883 if (sip->sip_call_id) {
2884 id = sip->sip_call_id->i_id;
2885 }
2886
2887 if (inflate) {
2888 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__
, 2888, "nta: %s (%u) (%s) Inflating compressed body:\n%s\n",
method_name, cseq, id, (char *)decoded)) : (void)0)
;
2889 } else {
2890 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__
, 2890, "nta: %s (%u) (%s) Deflating compressed body:\n%s\n",
method_name, cseq, id, orig_payload)) : (void)0)
;
2891 }
2892
2893 return 1;
2894 }
2895
2896 return 0;
2897}
2898#endif
2899
2900/** @internal Handle incoming requests. */
2901static
2902void agent_recv_request(nta_agent_t *agent,
2903 msg_t *msg,
2904 sip_t *sip,
2905 tport_t *tport)
2906{
2907 nta_leg_t *leg;
2908 nta_incoming_t *irq, *merge = NULL((void*)0), *ack = NULL((void*)0), *cancel = NULL((void*)0);
2909 sip_method_t method = sip->sip_request->rq_method;
2910 char const *method_name = sip->sip_request->rq_method_name;
2911 url_t url[1];
2912 unsigned cseq = sip->sip_cseq ? sip->sip_cseq->cs_seq : 0;
2913 int insane, errors, stream;
2914 unsigned compressed = 0;
2915 su_duration_t sa_load_elapsed_ms = su_duration(su_now(), agent->sa_load->last_time);
2916
2917 agent->sa_stats->as_recv_msg++;
2918 agent->sa_stats->as_recv_request++;
2919
2920 if (agent->sa_load->requests_per_second == 0) agent->sa_load->requests_per_second = 1;
2921
2922 if (sa_load_elapsed_ms >= 1000) {
2923 if (agent->sa_load->as_recv_request_last) {
2924 agent->sa_load->requests_per_second = ((agent->sa_stats->as_recv_request - agent->sa_load->as_recv_request_last) * 1000) / sa_load_elapsed_ms;
2925 }
2926
2927 /** Update */
2928 agent->sa_load->last_time = su_now();
2929 agent->sa_load->as_recv_request_last = agent->sa_stats->as_recv_request;
2930
2931 if (agent->sa_max_recv_requests_per_second && agent->sa_load->requests_per_second > agent->sa_max_recv_requests_per_second) {
2932 SU_DEBUG_5(("SIP flood: Dropped %u incoming SIP messages, %u message / sec (of %u allowed)\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__
, 2933, "SIP flood: Dropped %u incoming SIP messages, %u message / sec (of %u allowed)\n"
, agent->sa_stats->as_drop_request + 1, agent->sa_load
->requests_per_second, agent->sa_max_recv_requests_per_second
)) : (void)0)
2933 agent->sa_stats->as_drop_request + 1, agent->sa_load->requests_per_second, agent->sa_max_recv_requests_per_second))(((nta_log != ((void*)0) && 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__
, 2933, "SIP flood: Dropped %u incoming SIP messages, %u message / sec (of %u allowed)\n"
, agent->sa_stats->as_drop_request + 1, agent->sa_load
->requests_per_second, agent->sa_max_recv_requests_per_second
)) : (void)0)
;
2934 }
2935
2936 } else if (sa_load_elapsed_ms == -SU_DURATION_MAXSU_DURATION_MAX) {
2937 /** Initialize */
2938 agent->sa_load->last_time = su_now();
2939 agent->sa_load->as_recv_request_last = agent->sa_stats->as_recv_request;
2940 }
2941
2942 if (agent->sa_max_recv_requests_per_second && agent->sa_load->requests_per_second > agent->sa_max_recv_requests_per_second) {
2943 agent->sa_stats->as_drop_request++;
2944 msg_destroy(msg);
2945 return;
2946 }
2947
2948 SU_DEBUG_5(("nta: received %s " URL_PRINT_FORMAT " %s (CSeq %u) (load: %u rps)\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__
, 2951, "nta: received %s " "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
" %s (CSeq %u) (load: %u rps)\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
, agent->sa_load->requests_per_second)) : (void)0)
2949 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__
, 2951, "nta: received %s " "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
" %s (CSeq %u) (load: %u rps)\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
, agent->sa_load->requests_per_second)) : (void)0)
2950 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__
, 2951, "nta: received %s " "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
" %s (CSeq %u) (load: %u rps)\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
, agent->sa_load->requests_per_second)) : (void)0)
2951 sip->sip_request->rq_version, cseq, agent->sa_load->requests_per_second))(((nta_log != ((void*)0) && 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__
, 2951, "nta: received %s " "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
" %s (CSeq %u) (load: %u rps)\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
, agent->sa_load->requests_per_second)) : (void)0)
;
2952
2953 if (agent->sa_drop_prob && !tport_is_reliable(tport)) {
2954 if ((unsigned)su_randint(0, 1000) < agent->sa_drop_prob) {
2955 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__
, 2956, "nta: %s (%u) is %s\n", method_name, cseq, "dropped simulating packet loss"
)) : (void)0)
2956 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__
, 2956, "nta: %s (%u) is %s\n", method_name, cseq, "dropped simulating packet loss"
)) : (void)0)
;
2957 agent->sa_stats->as_drop_request++;
2958 msg_destroy(msg);
2959 return;
2960 }
2961 }
2962
2963 stream = tport_is_stream(tport);
2964
2965 /* Try to use compression on reverse direction if @Via has comp=sigcomp */
2966 if (stream &&
2967 sip->sip_via && sip->sip_via->v_comp &&
2968 tport_can_send_sigcomp(tport) &&
2969 tport_name(tport)->tpn_comp == NULL((void*)0) &&
2970 tport_has_compression(tport_parent(tport), sip->sip_via->v_comp)) {
2971 tport_set_compression(tport, sip->sip_via->v_comp);
2972 }
2973
2974 if (sip->sip_flags & MSG_FLG_TOOLARGE) {
2975 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__
, 2976, "nta: %s (%u) is %s\n", method_name, cseq, sip_413_Request_too_large
)) : (void)0)
2976 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__
, 2976, "nta: %s (%u) is %s\n", method_name, cseq, sip_413_Request_too_large
)) : (void)0)
;
2977 agent->sa_stats->as_bad_request++;
2978 mreply(agent, NULL((void*)0), SIP_413_REQUEST_TOO_LARGE413, sip_413_Request_too_large, msg,
2979 tport, 1, stream, NULL((void*)0),
2980 TAG_END()(tag_type_t)0, (tag_value_t)0);
2981 return;
2982 }
2983
2984 insane = 0;
2985
2986 if (agent->sa_bad_req_mask != ~0U)
2987 errors = msg_extract_errors(msg) & agent->sa_bad_req_mask;
2988 else
2989 errors = sip->sip_error != NULL((void*)0);
2990
2991 if (errors ||
2992 (sip->sip_flags & MSG_FLG_ERROR) /* Fatal error */ ||
2993 (insane = (sip_sanity_check(sip) < 0))) {
2994 sip_header_t const *h;
2995 char const *badname = NULL((void*)0), *phrase;
2996
2997 agent->sa_stats->as_bad_message++;
2998 agent->sa_stats->as_bad_request++;
2999
3000 if (insane)
3001 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__
, 3002, "nta: %s (%u) %s\n", method_name, cseq, "failed sanity check"
)) : (void)0)
3002 "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__
, 3002, "nta: %s (%u) %s\n", method_name, cseq, "failed sanity check"
)) : (void)0)
;
3003
3004 for (h = (sip_header_t const *)sip->sip_error; h; h = h->sh_nextsh_header_next->shn_next) {
3005 char const *bad;
3006
3007 if (h->sh_classsh_common->h_class == sip_error_class)
3008 bad = h->sh_error->er_name;
3009 else
3010 bad = h->sh_classsh_common->h_class->hc_name;
3011
3012 if (bad)
3013 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__
, 3013, "nta: %s has bad %s header\n", method_name, bad)) : (
void)0)
;
3014
3015 if (!badname)
3016 badname = bad;
3017 }
3018
3019 if (sip->sip_via && method != sip_method_ack) {
3020 msg_t *reply = nta_msg_create(agent, 0);
3021
3022 agent_check_request_via(agent, msg, sip, sip->sip_via, tport);
3023
3024 if (badname && reply)
3025 phrase = su_sprintf(msg_home(reply)((su_home_t*)(reply)), "Bad %s Header", badname);
3026 else
3027 phrase = sip_400_Bad_request;
3028
3029 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__
, 3029, "nta: %s (%u) is %s\n", method_name, cseq, phrase)) :
(void)0)
;
3030
3031 mreply(agent, reply, 400, phrase, msg,
3032 tport, 1, stream, NULL((void*)0),
3033 TAG_END()(tag_type_t)0, (tag_value_t)0);
3034 }
3035 else {
3036 msg_destroy(msg);
3037 if (stream) /* Send FIN */
3038 tport_shutdown(tport, 1);
3039 }
3040
3041 return;
3042 }
3043
3044 if (!su_casematch(sip->sip_request->rq_version, sip_version_2_0)) {
3045 agent->sa_stats->as_bad_request++;
3046 agent->sa_stats->as_bad_message++;
3047
3048 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__
, 3049, "nta: bad version %s for %s (%u)\n", sip->sip_request
->rq_version, method_name, cseq)) : (void)0)
3049 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__
, 3049, "nta: bad version %s for %s (%u)\n", sip->sip_request
->rq_version, method_name, cseq)) : (void)0)
;
3050
3051 mreply(agent, NULL((void*)0), SIP_505_VERSION_NOT_SUPPORTED505, sip_505_Version_not_supported, msg,
3052 tport, 0, stream, NULL((void*)0),
3053 TAG_END()(tag_type_t)0, (tag_value_t)0);
3054
3055 return;
3056 }
3057
3058 if (agent_check_request_via(agent, msg, sip, sip->sip_via, tport) < 0) {
3059 agent->sa_stats->as_bad_message++;
3060 agent->sa_stats->as_bad_request++;
3061 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__
, 3061, "nta: %s (%u) %s\n", method_name, cseq, "has invalid Via"
)) : (void)0)
;
3062 msg_destroy(msg);
3063 return;
3064 }
3065
3066#ifdef HAVE_ZLIB_COMPRESS1
3067 compressed = sip_content_encoding_Xflate(msg, sip, 1, 1);
3068#endif
3069
3070 /* First, try existing incoming requests */
3071 irq = incoming_find(agent, sip, sip->sip_via,
3072 agent->sa_merge_482 &&
3073 !sip->sip_to->a_tag &&
3074 method != sip_method_ack
3075 ? &merge
3076 : NULL((void*)0),
3077 method == sip_method_ack ? &ack : NULL((void*)0),
3078 method == sip_method_cancel ? &cancel : NULL((void*)0));
3079
3080 if (irq) {
3081 /* Match - this is a retransmission */
3082 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__
, 3083, "nta: %s (%u) going to existing %s transaction\n", method_name
, cseq, irq->irq_rq->rq_method_name)) : (void)0)
3083 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__
, 3083, "nta: %s (%u) going to existing %s transaction\n", method_name
, cseq, irq->irq_rq->rq_method_name)) : (void)0)
;
3084 if (incoming_recv(irq, msg, sip, tport) >= 0)
3085 return;
3086 }
3087 else if (ack) {
3088 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__
, 3090, "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)
3089 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__
, 3090, "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)
3090 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__
, 3090, "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)
;
3091 if (incoming_ack(ack, msg, sip, tport) >= 0)
3092 return;
3093 }
3094 else if (cancel) {
3095 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__
, 3097, "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)
3096 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__
, 3097, "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)
3097 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__
, 3097, "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)
;
3098 if (incoming_cancel(cancel, msg, sip, tport) >= 0)
3099 return;
3100 }
3101 else if (merge) {
3102 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__
, 3103, "nta: %s (%u) %s\n", method_name, cseq, "is a merged request"
)) : (void)0)
3103 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__
, 3103, "nta: %s (%u) %s\n", method_name, cseq, "is a merged request"
)) : (void)0)
;
3104 request_merge(agent, msg, sip, tport, merge->irq_tag);
3105 return;
3106 }
3107
3108 if (method == sip_method_prack && sip->sip_rack) {
3109 nta_reliable_t *rel = reliable_find(agent, sip);
3110 if (rel) {
3111 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__
, 3114, "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)
3112 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__
, 3114, "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)
3113 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__
, 3114, "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)
3114 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__
, 3114, "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)
;
3115 reliable_recv(rel, msg, sip, tport);
3116 return;
3117 }
3118 }
3119
3120 *url = *sip->sip_request->rq_url;
3121 url->url_params = NULL((void*)0);
3122 agent_aliases(agent, url, tport); /* canonize urls */
3123
3124 if (method != sip_method_subscribe && (leg = leg_find(agent,
3125 method_name, url,
3126 sip->sip_call_id,
3127 sip->sip_from->a_tag,
3128 sip->sip_to->a_tag))) {
3129 /* Try existing dialog */
3130 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__
, 3131, "nta: %s (%u) %s\n", method_name, cseq, "going to existing leg"
)) : (void)0)
3131 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__
, 3131, "nta: %s (%u) %s\n", method_name, cseq, "going to existing leg"
)) : (void)0)
;
3132 leg->leg_compressed = compressed;
3133 leg_recv(leg, msg, sip, tport);
3134 return;
3135 }
3136 else if (!agent->sa_is_stateless &&
3137 (leg = dst_find(agent, url, method_name))) {
3138 /* Dialogless legs - let application process transactions statefully */
3139 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__
, 3140, "nta: %s (%u) %s\n", method_name, cseq, "going to a dialogless leg"
)) : (void)0)
3140 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__
, 3140, "nta: %s (%u) %s\n", method_name, cseq, "going to a dialogless leg"
)) : (void)0)
;
3141 leg->leg_compressed = compressed;
3142 leg_recv(leg, msg, sip, tport);
3143 }
3144 else if (!agent->sa_is_stateless && (leg = agent->sa_default_leg)) {
3145 if (method == sip_method_invite &&
3146 agent->sa_in.proceeding->q_length >= agent->sa_max_proceeding) {
3147 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__
, 3148, "nta: proceeding queue full for %s (%u)\n", method_name
, cseq)) : (void)0)
3148 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__
, 3148, "nta: proceeding queue full for %s (%u)\n", method_name
, cseq)) : (void)0)
;
3149 mreply(agent, NULL((void*)0), SIP_503_SERVICE_UNAVAILABLE503, sip_503_Service_unavailable, msg,
3150 tport, 0, 0, NULL((void*)0),
3151 TAG_END()(tag_type_t)0, (tag_value_t)0);
3152 return;
3153 }
3154 else {
3155 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__
, 3156, "nta: %s (%u) %s\n", method_name, cseq, "going to a default leg"
)) : (void)0)
3156 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__
, 3156, "nta: %s (%u) %s\n", method_name, cseq, "going to a default leg"
)) : (void)0)
;
3157 leg->leg_compressed = compressed;
3158 leg_recv(leg, msg, sip, tport);
3159 }
3160 }
3161 else if (agent->sa_callback) {
3162 /* Stateless processing for request */
3163 agent->sa_stats->as_trless_request++;
3164 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__
, 3165, "nta: %s (%u) %s\n", method_name, cseq, "to message callback"
)) : (void)0)
3165 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__
, 3165, "nta: %s (%u) %s\n", method_name, cseq, "to message callback"
)) : (void)0)
;
3166 (void)agent->sa_callback(agent->sa_magic, agent, msg, sip);
3167 }
3168 else {
3169 agent->sa_stats->as_trless_request++;
3170 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__
, 3172, "nta: %s (%u) %s\n", method_name, cseq, "not processed by application: returning 501"
)) : (void)0)
3171 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__
, 3172, "nta: %s (%u) %s\n", method_name, cseq, "not processed by application: returning 501"
)) : (void)0)
3172 "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__
, 3172, "nta: %s (%u) %s\n", method_name, cseq, "not processed by application: returning 501"
)) : (void)0)
;
3173 if (method != sip_method_ack)
3174 mreply(agent, NULL((void*)0), SIP_501_NOT_IMPLEMENTED501, sip_501_Not_implemented, msg,
3175 tport, 0, 0, NULL((void*)0),
3176 TAG_END()(tag_type_t)0, (tag_value_t)0);
3177 else
3178 msg_destroy(msg);
3179 }
3180}
3181
3182/** Check @Via header.
3183 *
3184 */
3185static
3186int agent_check_request_via(nta_agent_t *agent,
3187 msg_t *msg,
3188 sip_t *sip,
3189 sip_via_t *v,
3190 tport_t *tport)
3191{
3192 enum { receivedlen = sizeof("received=") - 1 };
3193 char received[receivedlen + TPORT_HOSTPORTSIZE(55)];
3194 char *hostport = received + receivedlen;
3195 char const *rport;
3196 su_sockaddr_t const *from;
3197 sip_via_t const *tpv = agent_tport_via(tport);
3198
3199 assert(tport)((void) sizeof ((tport) ? 1 : 0), __extension__ ({ if (tport)
; else __assert_fail ("tport", "nta.c", 3199, __extension__ __PRETTY_FUNCTION__
); }))
; assert(msg)((void) sizeof ((msg) ? 1 : 0), __extension__ ({ if (msg) ; else
__assert_fail ("msg", "nta.c", 3199, __extension__ __PRETTY_FUNCTION__
); }))
; assert(sip)((void) sizeof ((sip) ? 1 : 0), __extension__ ({ if (sip) ; else
__assert_fail ("sip", "nta.c", 3199, __extension__ __PRETTY_FUNCTION__
); }))
;
3200 assert(sip->sip_request)((void) sizeof ((sip->sip_request) ? 1 : 0), __extension__
({ if (sip->sip_request) ; else __assert_fail ("sip->sip_request"
, "nta.c", 3200, __extension__ __PRETTY_FUNCTION__); }))
; assert(tpv)((void) sizeof ((tpv) ? 1 : 0), __extension__ ({ if (tpv) ; else
__assert_fail ("tpv", "nta.c", 3200, __extension__ __PRETTY_FUNCTION__
); }))
;
3201
3202 from = msg_addr(msg);
3203
3204 if (v == NULL((void*)0)) {
3205 /* Make up a via line */
3206 v = sip_via_format(msg_home(msg)((su_home_t*)(msg)), "SIP/2.0/%s %s",
3207 tport_name(tport)->tpn_proto,
3208 tport_hostport(hostport, TPORT_HOSTPORTSIZE(55), from, 1));
3209 msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)v);
3210
3211 return v ? 0 : -1;
3212 }
3213
3214 if (!su_strmatch(v->v_protocol, tpv->v_protocol)) {
3215 tport_hostport(hostport, TPORT_HOSTPORTSIZE(55), from, 1);
3216 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__
, 3217, "nta: Via check: invalid transport \"%s\" from %s\n",
v->v_protocol, hostport)) : (void)0)
3217 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__
, 3217, "nta: Via check: invalid transport \"%s\" from %s\n",
v->v_protocol, hostport)) : (void)0)
;
3218 return -1;
3219 }
3220
3221 if (v->v_received) {
3222 /* Nasty, nasty */
3223 tport_hostport(hostport, TPORT_HOSTPORTSIZE(55), from, 1);
3224 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__
, 3225, "nta: Via check: extra received=%s from %s\n", v->
v_received, hostport)) : (void)0)
3225 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__
, 3225, "nta: Via check: extra received=%s from %s\n", v->
v_received, hostport)) : (void)0)
;
3226 msg_header_remove_param(v->v_common, "received");
3227 }
3228
3229 if (!tport_hostport(hostport, TPORT_HOSTPORTSIZE(55), from, 0))
3230 return -1;
3231
3232 if (!su_casematch(hostport, v->v_host)) {
3233 size_t rlen;
3234 /* Add the "received" field */
3235 memcpy(received, "received=", receivedlen);
3236
3237 if (hostport[0] == '[') {
3238 rlen = strlen(hostport + 1) - 1;
3239 memmove(hostport, hostport + 1, rlen);
3240 hostport[rlen] = '\0';
3241 }
3242
3243 msg_header_replace_param(msg_home(msg)((su_home_t*)(msg)), v->v_common,
3244 su_strdup(msg_home(msg)((su_home_t*)(msg)), received));
3245 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__
, 3245, "nta: Via check: %s\n", received)) : (void)0)
;
3246 }
3247
3248 if (!agent->sa_server_rport) {
3249 /*Xyzzy*/;
3250 }
3251 else if (v->v_rport) {
3252 rport = su_sprintf(msg_home(msg)((su_home_t*)(msg)), "rport=%u", ntohs(from->su_portsu_sin.sin_port));
3253 msg_header_replace_param(msg_home(msg)((su_home_t*)(msg)), v->v_common, rport);
3254 }
3255 else if (tport_is_tcp(tport)) {
3256 rport = su_sprintf(msg_home(msg)((su_home_t*)(msg)), "rport=%u", ntohs(from->su_portsu_sin.sin_port));
3257 msg_header_replace_param(msg_home(msg)((su_home_t*)(msg)), v->v_common, rport);
3258 }
3259 else if (agent->sa_server_rport == 2 ||
3260 (agent->sa_server_rport == 3 && sip && sip->sip_user_agent &&
3261 sip->sip_user_agent->g_string &&
3262 (!strncasecmp(sip->sip_user_agent->g_string, "Polycom", 7) ||
3263 !strncasecmp(sip->sip_user_agent->g_string, "KIRK Wireless Server", 20) ||
3264 !strncasecmp(sip->sip_user_agent->g_string, "ADTRAN_Total_Access", 19)))) {
3265 rport = su_sprintf(msg_home(msg)((su_home_t*)(msg)), "rport=%u", ntohs(from->su_portsu_sin.sin_port));
3266 msg_header_replace_param(msg_home(msg)((su_home_t*)(msg)), v->v_common, rport);
3267 }
3268
3269 return 0;
3270}
3271
3272/** @internal Handle aliases of local node.
3273 *
3274 * Return true if @a url is modified.
3275 */
3276static
3277int agent_aliases(nta_agent_t const *agent, url_t url[], tport_t *tport)
3278{
3279 sip_contact_t *m;
3280 sip_via_t const *lv;
3281 char const *tport_port = "";
3282
3283 if (!url->url_host)
3284 return 0;
3285
3286 if (tport)
3287 tport_port = tport_name(tport)->tpn_port;
3288
3289 assert(tport_port)((void) sizeof ((tport_port) ? 1 : 0), __extension__ ({ if (tport_port
) ; else __assert_fail ("tport_port", "nta.c", 3289, __extension__
__PRETTY_FUNCTION__); }))
;
3290
3291 for (m = agent->sa_aliases ? agent->sa_aliases : agent->sa_contact;
3292 m;
3293 m = m->m_next) {
3294 if (url->url_type != m->m_url->url_type)
3295 continue;
3296
3297 if (host_cmp(url->url_host, m->m_url->url_host))
3298 continue;
3299
3300 if (url->url_port == NULL((void*)0))
3301 break;
3302
3303 if (m->m_url->url_port) {
3304 if (strcmp(url->url_port, m->m_url->url_port))
3305 continue;
3306 } else {
3307 if (strcmp(url->url_port, tport_port))
3308 continue;
3309 }
3310
3311 break;
3312 }
3313
3314 if (!m)
3315 return 0;
3316
3317 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__
, 3319, "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)
3318 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__
, 3319, "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)
3319 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__
, 3319, "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)
;
3320
3321 url->url_host = "%";
3322
3323 if (agent->sa_aliases) {
3324 url->url_type = agent->sa_aliases->m_url->url_type;
3325 url->url_scheme = agent->sa_aliases->m_url->url_scheme;
3326 url->url_port = agent->sa_aliases->m_url->url_port;
3327 return 1;
3328 }
3329 else {
3330 /* Canonize the request URL port */
3331 if (tport) {
3332 lv = agent_tport_via(tport_parent(tport)); assert(lv)((void) sizeof ((lv) ? 1 : 0), __extension__ ({ if (lv) ; else
__assert_fail ("lv", "nta.c", 3332, __extension__ __PRETTY_FUNCTION__
); }))
;
3333 if (lv->v_port)
3334 /* Add non-default port */
3335 url->url_port = lv->v_port;
3336 return 1;
3337 }
3338 if (su_strmatch(url->url_port, url_port_default((enum url_type_e)url->url_type)) ||
3339 su_strmatch(url->url_port, ""))
3340 /* Remove default or empty port */
3341 url->url_port = NULL((void*)0);
3342
3343 return 0;
3344 }
3345}
3346
3347/** @internal Handle incoming responses. */
3348static
3349void agent_recv_response(nta_agent_t *agent,
3350 msg_t *msg,
3351 sip_t *sip,
3352 sip_via_t *tport_via,
3353 tport_t *tport)
3354{
3355 int status = sip->sip_status->st_status;
3356 int errors;
3357 char const *phrase = sip->sip_status->st_phrase;
3358 char const *method =
3359 sip->sip_cseq ? sip->sip_cseq->cs_method_name : "<UNKNOWN>";
3360 uint32_t cseq = sip->sip_cseq ? sip->sip_cseq->cs_seq : 0;
3361 nta_outgoing_t *orq;
3362 su_home_t *home;
3363 char const *branch = NONE((void *)-1);
3364
3365
3366 agent->sa_stats->as_recv_msg++;
3367 agent->sa_stats->as_recv_response++;
3368
3369 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__
, 3370, "nta: received %03d %s for %s (%u)\n", status, phrase
, method, cseq)) : (void)0)
3370 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__
, 3370, "nta: received %03d %s for %s (%u)\n", status, phrase
, method, cseq)) : (void)0)
;
3371
3372 if (agent->sa_drop_prob && !tport_is_reliable(tport)) {
3373 if ((unsigned)su_randint(0, 1000) < agent->sa_drop_prob) {
3374 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__
, 3375, "nta: %03d %s %s\n", status, phrase, "dropped simulating packet loss"
)) : (void)0)
3375 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__
, 3375, "nta: %03d %s %s\n", status, phrase, "dropped simulating packet loss"
)) : (void)0)
;
3376 agent->sa_stats->as_drop_response++;
3377 msg_destroy(msg);
3378 return;
3379 }
3380 }
3381
3382 if (agent->sa_bad_resp_mask)
3383 errors = msg_extract_errors(msg) & agent->sa_bad_resp_mask;
3384 else
3385 errors = sip->sip_error != NULL((void*)0);
3386
3387 if (errors ||
3388 sip_sanity_check(sip) < 0) {
3389 sip_header_t const *h;
3390
3391 agent->sa_stats->as_bad_response++;
3392 agent->sa_stats->as_bad_message++;
3393
3394 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__
, 3397, "nta: %03d %s %s\n", status, phrase, errors ? "has fatal syntax errors"
: "failed sanity check")) : (void)0)
3395 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__
, 3397, "nta: %03d %s %s\n", status, phrase, errors ? "has fatal syntax errors"
: "failed sanity check")) : (void)0)
3396 ? "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__
, 3397, "nta: %03d %s %s\n", status, phrase, errors ? "has fatal syntax errors"
: "failed sanity check")) : (void)0)
3397 : "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__
, 3397, "nta: %03d %s %s\n", status, phrase, errors ? "has fatal syntax errors"
: "failed sanity check")) : (void)0)
;
3398
3399 for (h = (sip_header_t const *)sip->sip_error; h; h = h->sh_nextsh_header_next->shn_next) {
3400 if (h->sh_classsh_common->h_class->hc_name) {
3401 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__
, 3402, "nta: %03d has bad %s header\n", status, h->sh_common
->h_class->hc_name)) : (void)0)
3402 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__
, 3402, "nta: %03d has bad %s header\n", status, h->sh_common
->h_class->hc_name)) : (void)0)
;
3403 }
3404 }
3405
3406 msg_destroy(msg);
3407 return;
3408 }
3409
3410 if (!su_casematch(sip->sip_status->st_version, sip_version_2_0)) {
3411 agent->sa_stats->as_bad_response++;
3412 agent->sa_stats->as_bad_message++;
3413
3414 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__
, 3415, "nta: bad version %s %03d %s\n", sip->sip_status->
st_version, status, phrase)) : (void)0)
3415 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__
, 3415, "nta: bad version %s %03d %s\n", sip->sip_status->
st_version, status, phrase)) : (void)0)
;
3416 msg_destroy(msg);
3417 return;
3418 }
3419
3420 if (sip->sip_cseq && sip->sip_cseq->cs_method == sip_method_ack) {
3421 /* Drop response messages to ACK */
3422 agent->sa_stats->as_bad_response++;
3423 agent->sa_stats->as_bad_message++;
3424 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__
, 3424, "nta: %03d %s %s\n", status, phrase, "is response to ACK"
)) : (void)0)
;
3425 msg_destroy(msg);
3426 return;
3427 }
3428
3429 /* XXX - should check if msg should be discarded based on via? */
3430
3431#ifdef HAVE_ZLIB_COMPRESS1
3432 sip_content_encoding_Xflate(msg, sip, 1, 1);
3433#endif
3434
3435 if ((orq = outgoing_find(agent, msg, sip, sip->sip_via))) {
3436 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__
, 3437, "nta: %03d %s %s\n", status, phrase, "is going to a transaction"
)) : (void)0)
3437 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__
, 3437, "nta: %03d %s %s\n", status, phrase, "is going to a transaction"
)) : (void)0)
;
3438 /* RFC3263 4.3 "503 error response" */
3439 if(agent->sa_srv_503 && status == 503 && outgoing_other_destinations(orq)) {
3440 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__
, 3440, "%s(%p): <%03d> for <%s>, %s\n", "nta", (
void *)orq, status, method, "try next after timeout")) : (void
)0)
;
3441 home = msg_home(msg)((su_home_t*)(msg));
3442 if (agent->sa_is_stateless)
3443 branch = stateless_branch(agent, msg, sip, orq->orq_tpn);
3444 else
3445 branch = stateful_branch(home, agent);
3446
3447 orq->orq_branch = branch;
3448 orq->orq_via_branch = branch;
3449 outgoing_try_another(orq);
3450 return;
3451 }
3452
3453 if (outgoing_recv(orq, status, msg, sip) == 0)
3454 return;
3455 }
3456
3457
3458 agent->sa_stats->as_trless_response++;
3459
3460 if ((orq = agent->sa_default_outgoing)) {
3461 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__
, 3462, "nta: %03d %s %s\n", status, phrase, "to the default transaction"
)) : (void)0)
3462 "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__
, 3462, "nta: %03d %s %s\n", status, phrase, "to the default transaction"
)) : (void)0)
;
3463 outgoing_default_recv(orq, status, msg, sip);
3464 return;
3465 }
3466 else if (agent->sa_callback) {
3467 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__
, 3467, "nta: %03d %s %s\n", status, phrase, "to message callback"
)) : (void)0)
;
3468 /*
3469 * Store message and transport to hook for the duration of the callback
3470 * so that the transport can be obtained by nta_transport().
3471 */
3472 (void)agent->sa_callback(agent->sa_magic, agent, msg, sip);
3473 return;
3474 }
3475
3476 if (sip->sip_cseq->cs_method == sip_method_invite
3477 && 200 <= sip->sip_status->st_status
3478 && sip->sip_status->st_status < 300
3479 /* Exactly one Via header, belonging to us */
3480 && sip->sip_via && !sip->sip_via->v_next
3481 && agent_has_via(agent, sip->sip_via)) {
3482 agent->sa_stats->as_trless_200++;
3483 }
3484
3485 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__
, 3485, "nta: %03d %s %s\n", status, phrase, "was discarded")
) : (void)0)
;
3486 msg_destroy(msg);
3487}
3488
3489/** @internal Agent receives garbage */
3490static
3491void agent_recv_garbage(nta_agent_t *agent,
3492 msg_t *msg,
3493 tport_t *tport)
3494{
3495 agent->sa_stats->as_recv_msg++;
3496 agent->sa_stats->as_bad_message++;
3497
3498#if SU_DEBUG0 >= 3
3499 if (nta_log->log_level >= 3) {
3500 tp_name_t tpn[1];
3501
3502 tport_delivered_from(tport, msg, tpn);
3503
3504 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__
, 3505, "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)
3505 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__
, 3505, "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)
;
3506 }
3507#endif
3508
3509 msg_destroy(msg);
3510}
3511
3512/* ====================================================================== */
3513/* 4) Message handling - create, complete, destroy */
3514
3515/** Create a new message belonging to the agent */
3516msg_t *nta_msg_create(nta_agent_t *agent, int flags)
3517{
3518 msg_t *msg;
3519
3520 if (agent == NULL((void*)0))
3521 return su_seterrno(EINVAL22), NULL((void*)0);
3522
3523 msg = msg_create(agent->sa_mclass, agent->sa_flags | flags);
3524
3525 if (agent->sa_preload)
3526 su_home_preload(msg_home(msg)((su_home_t*)(msg)), 1, agent->sa_preload);
3527
3528 return msg;
3529}
3530
3531/** Create a new message for transport */
3532msg_t *nta_msg_create_for_transport(nta_agent_t *agent, int flags,
3533 char const data[], usize_t dlen,
3534 tport_t const *tport, tp_client_t *via)
3535{
3536 msg_t *msg = msg_create(agent->sa_mclass, agent->sa_flags | flags);
3537
3538 msg_maxsize(msg, agent->sa_maxsize);
3539
3540 if (agent->sa_preload)
3541 su_home_preload(msg_home(msg)((su_home_t*)(msg)), 1, dlen + agent->sa_preload);
3542
3543 return msg;
3544}
3545
3546/** Complete a message. */
3547int nta_msg_complete(msg_t *msg)
3548{
3549 return sip_complete_message(msg);
3550}
3551
3552/** Discard a message */
3553void nta_msg_discard(nta_agent_t *agent, msg_t *msg)
3554{
3555 msg_destroy(msg);
3556}
3557
3558/** Check if the headers are from response generated locally by NTA. */
3559int nta_sip_is_internal(sip_t const *sip)
3560{
3561 return
3562 sip == NULL((void*)0) /* No message generated */
3563 || (sip->sip_flags & NTA_INTERNAL_MSG(1<<15)) == NTA_INTERNAL_MSG(1<<15);
3564}
3565
3566/** Check if the message is internally generated by NTA. */
3567int nta_msg_is_internal(msg_t const *msg)
3568{
3569 return msg_get_flags(msg, NTA_INTERNAL_MSG(1<<15)) == NTA_INTERNAL_MSG(1<<15);
3570}
3571
3572/** Check if the message is internally generated by NTA.
3573 *
3574 * @deprecated Use nta_msg_is_internal() instead
3575 */
3576int nta_is_internal_msg(msg_t const *msg) { return nta_msg_is_internal(msg); }
3577
3578/* ====================================================================== */
3579/* 5) Stateless operation */
3580
3581/**Forward a request or response message.
3582 *
3583 * @note
3584 * The ownership of @a msg is taken over by the function even if the
3585 * function fails.
3586 */
3587int nta_msg_tsend(nta_agent_t *agent, msg_t *msg, url_string_t const *u,
3588 tag_type_t tag, tag_value_t value, ...)
3589{
3590 int retval = -1;
3591 ta_list ta;
3592 sip_t *sip = sip_object(msg);
3593 tp_name_t tpn[1] = {{ NULL((void*)0) }};
3594 char const *what;
3595
3596 if (!sip) {
3597 msg_destroy(msg);
3598 return -1;
3599 }
3600
3601 what =
3602 sip->sip_status ? "nta_msg_tsend(response)" :
3603 sip->sip_request ? "nta_msg_tsend(request)" :
3604 "nta_msg_tsend()";
3605
3606 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)
;
3607
3608 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)
3609 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__
, 3609, "%s: cannot add headers\n", what)) : (void)0)
;
3610 else if (sip->sip_status) {
3611 tport_t *tport = NULL((void*)0);
3612 int *use_rport = NULL((void*)0);
3613 int retry_without_rport = 0;
3614
3615 struct sigcomp_compartment *cc; cc = NONE((void *)-1);
3616
3617 if (agent->sa_server_rport)
3618 use_rport = &retry_without_rport, retry_without_rport = 1;
3619
3620 tl_gets(ta_args(ta)(ta).tl,
3621 NTATAG_TPORT_REF(tport)ntatag_tport_ref, tag_ptr_vr(&(tport), (tport)),
3622 IF_SIGCOMP_TPTAG_COMPARTMENT_REF(cc)tptag_compartment_ref, tag_ptr_vr(&(cc), cc),
3623 /* NTATAG_INCOMPLETE_REF(incomplete), */
3624 TAG_END()(tag_type_t)0, (tag_value_t)0);
3625
3626 if (!sip->sip_separator &&
3627 !(sip->sip_separator = sip_separator_create(msg_home(msg)((su_home_t*)(msg)))))
3628 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__
, 3628, "%s: cannot create sip_separator\n", what)) : (void)0
)
;
3629 else if (msg_serialize(msg, (msg_pub_t *)sip) != 0)
3630 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__
, 3630, "%s: sip_serialize() failed\n", what)) : (void)0)
;
3631 else if (!sip_via_remove(msg, sip))
3632 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__
, 3632, "%s: cannot remove Via\n", what)) : (void)0)
;
3633 else if (nta_tpn_by_via(tpn, sip->sip_via, use_rport) < 0)
3634 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__
, 3634, "%s: bad via\n", what)) : (void)0)
;
3635 else {
3636 if (!tport)
3637 tport = tport_by_name(agent->sa_tports, tpn);
3638 if (!tport)
3639 tport = tport_by_protocol(agent->sa_tports, tpn->tpn_proto);
3640
3641 if (retry_without_rport)
3642 tpn->tpn_port = sip_via_port(sip->sip_via, NULL((void*)0));
3643
3644 if (tport && tpn->tpn_comp && cc == NONE((void *)-1))
3645 cc = agent_compression_compartment(agent, tport, tpn, -1);
3646
3647 if (tport_tsend(tport, msg, tpn,
3648 IF_SIGCOMP_TPTAG_COMPARTMENT(cc)!(cc && cc != ((void *)-1)) ? tag_skip : tptag_compartment
, tag_ptr_v((cc)),
3649 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)) {
3650 agent->sa_stats->as_sent_msg++;
3651 agent->sa_stats->as_sent_response++;
3652 retval = 0;
3653 }
3654 else {
3655 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__
, 3655, "%s: send fails\n", what)) : (void)0)
;
3656 }
3657 }
3658 }
3659 else {
3660 /* Send request */
3661 if (outgoing_create(agent, NULL((void*)0), NULL((void*)0), u, NULL((void*)0), msg_ref_create(msg),
3662 NTATAG_STATELESS(1)ntatag_stateless, tag_bool_v((1)),
3663 ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
))
3664 retval = 0;
3665 }
3666
3667 if (retval == 0)
3668 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__
, 3668, "%s\n", what)) : (void)0)
;
3669
3670 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))
;
3671
3672 msg_destroy(msg);
3673
3674 return retval;
3675}
3676
3677/** Reply to a request message.
3678 *
3679 * @param agent nta agent object
3680 * @param req_msg request message
3681 * @param status status code
3682 * @param phrase status phrase (may be NULL if status code is well-known)
3683 * @param tag, value, ... optional additional headers terminated by TAG_END()
3684 *
3685 * @retval 0 when succesful
3686 * @retval -1 upon an error
3687 *
3688 * @note
3689 * The ownership of @a msg is taken over by the function even if the
3690 * function fails.
3691 */
3692int nta_msg_treply(nta_agent_t *agent,
3693 msg_t *req_msg,
3694 int status, char const *phrase,
3695 tag_type_t tag, tag_value_t value, ...)
3696{
3697 int retval;
3698 ta_list ta;
3699
3700 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)
;
3701
3702 retval = mreply(agent, NULL((void*)0), status, phrase, req_msg,
3703 NULL((void*)0), 0, 0, NULL((void*)0),
3704 ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
);
3705 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))
;
3706
3707 return retval;
3708}
3709
3710/**Reply to the request message.
3711 *
3712 * @note
3713 * The ownership of @a msg is taken over by the function even if the
3714 * function fails.
3715 */
3716int nta_msg_mreply(nta_agent_t *agent,
3717 msg_t *reply, sip_t *sip,
3718 int status, char const *phrase,
3719 msg_t *req_msg,
3720 tag_type_t tag, tag_value_t value, ...)
3721{
3722 int retval = -1;
3723 ta_list ta;
3724
3725 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)
;
3726
3727 retval = mreply(agent, reply, status, phrase, req_msg,
3728 NULL((void*)0), 0, 0, NULL((void*)0),
3729 ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
);
3730 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))
;
3731
3732 return retval;
3733}
3734
3735static
3736int mreply(nta_agent_t *agent,
3737 msg_t *reply,
3738 int status, char const *phrase,
3739 msg_t *req_msg,
3740 tport_t *tport,
3741 int incomplete,
3742 int sdwn_after,
3743 char const *to_tag,
3744 tag_type_t tag, tag_value_t value, ...)
3745{
3746 ta_list ta;
3747 sip_t *sip;
3748 int *use_rport = NULL((void*)0);
3749 int retry_without_rport = 0;
3750 tp_name_t tpn[1];
3751 int retval = -1;
3752
3753 if (!agent)
3754 return -1;
3755
3756 if (agent->sa_server_rport)
3757 use_rport = &retry_without_rport, retry_without_rport = 1;
3758
3759 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)
;
3760
3761 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);
3762
3763 if (reply == NULL((void*)0)) {
3764 reply = nta_msg_create(agent, 0);
3765 }
3766 sip = sip_object(reply);
3767
3768 if (!sip) {
3769 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__
, 3769, "%s: cannot create response msg\n", __func__)) : (void
)0)
;
3770 }
3771 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) {
3772 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__
, 3772, "%s: cannot add user headers\n", __func__)) : (void)0
)
;
3773 }
3774 else if (complete_response(reply, status, phrase, req_msg) < 0 &&
3775 !incomplete) {
3776 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__
, 3776, "%s: cannot complete message\n", __func__)) : (void)0
)
;
3777 }
3778 else if (sip->sip_status && sip->sip_status->st_status > 100 &&
3779 sip->sip_to && !sip->sip_to->a_tag &&
3780 (to_tag == NONE((void *)-1) ? 0 :
3781 to_tag != NULL((void*)0)
3782 ? sip_to_tag(msg_home(reply)((su_home_t*)(reply)), sip->sip_to, to_tag) < 0
3783 : sip_to_tag(msg_home(reply)((su_home_t*)(reply)), sip->sip_to,
3784 nta_agent_newtag(msg_home(reply)((su_home_t*)(reply)), "tag=%s", agent)) < 0)) {
3785 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__
, 3785, "%s: cannot add To tag\n", __func__)) : (void)0)
;
3786 }
3787 else if (nta_tpn_by_via(tpn, sip->sip_via, use_rport) < 0) {
3788 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__
, 3788, "%s: no Via\n", __func__)) : (void)0)
;
3789 }
3790 else {
3791 struct sigcomp_compartment *cc = NONE((void *)-1);
3792
3793 if (tport == NULL((void*)0))
3794 tport = tport_delivered_by(agent->sa_tports, req_msg);
3795
3796 if (!tport) {
3797 tport_t *primary = tport_by_protocol(agent->sa_tports, tpn->tpn_proto);
3798
3799 tport = tport_by_name(primary, tpn);
3800
3801 if (!tport)
3802 tport = primary;
3803 }
3804
3805 if (retry_without_rport)
3806 tpn->tpn_port = sip_via_port(sip->sip_via, NULL((void*)0));
3807
3808 if (tport && tpn->tpn_comp) {
3809 tl_gets(ta_args(ta)(ta).tl, TPTAG_COMPARTMENT_REF(cc)tptag_compartment_ref, tag_ptr_vr(&(cc), cc),
3810 /* XXX - should also check ntatag_sigcomp_close() */
3811 TAG_END()(tag_type_t)0, (tag_value_t)0);
3812 if (cc == NONE((void *)-1))
3813 cc = agent_compression_compartment(agent, tport, tpn, -1);
3814
3815 if (cc != NULL((void*)0) && cc != NONE((void *)-1) &&
3816 tport_delivered_with_comp(tport, req_msg, NULL((void*)0)) != -1) {
3817 agent_accept_compressed(agent, req_msg, cc);
3818 }
3819 }
3820
3821 if (tport_tsend(tport, reply, tpn,
3822 IF_SIGCOMP_TPTAG_COMPARTMENT(cc)!(cc && cc != ((void *)-1)) ? tag_skip : tptag_compartment
, tag_ptr_v((cc)),
3823 TPTAG_MTU(INT_MAX)tptag_mtu, tag_usize_v((2147483647)),
3824 TPTAG_SDWN_AFTER(sdwn_after)tptag_sdwn_after, tag_bool_v((sdwn_after)),
3825 ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
)) {
3826 agent->sa_stats->as_sent_msg++;
3827 agent->sa_stats->as_sent_response++;
3828 retval = 0; /* Success! */
3829 }
3830 else {
3831 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__
, 3831, "%s: send fails\n", __func__)) : (void)0)
;
3832 }
3833 }
3834
3835 msg_destroy(reply);
3836 msg_destroy(req_msg);
3837
3838 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))
;
3839
3840 return retval;
3841}
3842
3843/** Add headers from the request to the response message. */
3844static
3845int complete_response(msg_t *response,
3846 int status, char const *phrase,
3847 msg_t *request)
3848{
3849 su_home_t *home = msg_home(response)((su_home_t*)(response));
3850 sip_t *response_sip = sip_object(response);
3851 sip_t const *request_sip = sip_object(request);
3852
3853 int incomplete = 0;
3854
3855 if (!response_sip || !request_sip || !request_sip->sip_request)
3856 return -1;
3857
3858 if (!response_sip->sip_status)
3859 response_sip->sip_status = sip_status_create(home, status, phrase, NULL((void*)0));
3860 if (!response_sip->sip_via)
3861 response_sip->sip_via = sip_via_dup(home, request_sip->sip_via);
3862 if (!response_sip->sip_from)
3863 response_sip->sip_from = sip_from_dup(home, request_sip->sip_from);
3864 if (!response_sip->sip_to)
3865 response_sip->sip_to = sip_to_dup(home, request_sip->sip_to);
3866 if (!response_sip->sip_call_id)
3867 response_sip->sip_call_id =
3868 sip_call_id_dup(home, request_sip->sip_call_id);
3869 if (!response_sip->sip_cseq)
3870 response_sip->sip_cseq = sip_cseq_dup(home, request_sip->sip_cseq);
3871
3872 if (!response_sip->sip_record_route && request_sip->sip_record_route)
3873 sip_add_dup(response, response_sip, (void*)request_sip->sip_record_route);
3874
3875 incomplete = sip_complete_message(response) < 0;
3876
3877 msg_serialize(response, (msg_pub_t *)response_sip);
3878
3879 if (incomplete ||
3880 !response_sip->sip_status ||
3881 !response_sip->sip_via ||
3882 !response_sip->sip_from ||
3883 !response_sip->sip_to ||
3884 !response_sip->sip_call_id ||
3885 !response_sip->sip_cseq ||
3886 !response_sip->sip_content_length ||
3887 !response_sip->sip_separator ||
3888 (request_sip->sip_record_route && !response_sip->sip_record_route))
3889 return -1;
3890
3891 return 0;
3892}
3893
3894/** ACK and BYE an unknown 200 OK response to INVITE.
3895 *
3896 * A UAS may still return a 2XX series response to client request after the
3897 * client transactions has been terminated. In that case, the UAC can not
3898 * really accept the call. This function was used to accept and immediately
3899 * terminate such a call.
3900 *
3901 * @deprecated This was a bad idea: see sf.net bug #1750691. It can be used
3902 * to amplify DoS attacks. Let UAS take care of retransmission timeout and
3903 * let it terminate the session. As of @VERSION_1_12_7, this function just
3904 * returns -1.
3905 */
3906int nta_msg_ackbye(nta_agent_t *agent, msg_t *msg)
3907{
3908 sip_t *sip = sip_object(msg);
3909 msg_t *amsg = nta_msg_create(agent, 0);
3910 sip_t *asip = sip_object(amsg);
3911 msg_t *bmsg = NULL((void*)0);
3912 sip_t *bsip;
3913 url_string_t const *ruri;
3914 nta_outgoing_t *ack = NULL((void*)0), *bye = NULL((void*)0);
3915 sip_cseq_t *cseq;
3916 sip_request_t *rq;
3917 sip_route_t *route = NULL((void*)0), *r, r0[1];
3918 su_home_t *home = msg_home(amsg)((su_home_t*)(amsg));
3919
3920 if (asip == NULL((void*)0))
3921 return -1;
3922
3923 sip_add_tl(amsg, asip,
3924 SIPTAG_TO(sip->sip_to)siptag_to, siptag_to_v(sip->sip_to),
3925 SIPTAG_FROM(sip->sip_from)siptag_from, siptag_from_v(sip->sip_from),
3926 SIPTAG_CALL_ID(sip->sip_call_id)siptag_call_id, siptag_call_id_v(sip->sip_call_id),
3927 TAG_END()(tag_type_t)0, (tag_value_t)0);
3928
3929 if (sip->sip_contact) {
3930 ruri = (url_string_t const *)sip->sip_contact->m_url;
3931 } else {
3932 ruri = (url_string_t const *)sip->sip_to->a_url;
3933 }
3934
3935 /* Reverse (and fix) record route */
3936 route = sip_route_reverse(home, sip->sip_record_route);
3937
3938 if (route && !url_has_param(route->r_url, "lr")) {
3939 for (r = route; r->r_next; r = r->r_next)
3940 ;
3941
3942 /* Append r-uri */
3943 *sip_route_init(r0)->r_url = *ruri->us_url;
3944 r->r_next = sip_route_dup(home, r0);
3945
3946 /* Use topmost route as request-uri */
3947 ruri = (url_string_t const *)route->r_url;
3948 route = route->r_next;
3949 }
3950
3951 msg_header_insert(amsg, (msg_pub_t *)asip, (msg_header_t *)route);
3952
3953 bmsg = msg_copy(amsg); bsip = sip_object(bmsg);
3954
3955 if (!(cseq = sip_cseq_create(home, sip->sip_cseq->cs_seq, SIP_METHOD_ACKsip_method_ack, "ACK")))
3956 goto err;
3957 else
3958 msg_header_insert(amsg, (msg_pub_t *)asip, (msg_header_t *)cseq);
3959
3960 if (!(rq = sip_request_create(home, SIP_METHOD_ACKsip_method_ack, "ACK", ruri, NULL((void*)0))))
3961 goto err;
3962 else
3963 msg_header_insert(amsg, (msg_pub_t *)asip, (msg_header_t *)rq);
3964
3965 if (!(ack = nta_outgoing_mcreate(agent, NULL((void*)0), NULL((void*)0), NULL((void*)0), amsg,
3966 NTATAG_ACK_BRANCH(sip->sip_via->v_branch)ntatag_ack_branch, tag_str_v((sip->sip_via->v_branch)),
3967 NTATAG_STATELESS(1)ntatag_stateless, tag_bool_v((1)),
3968 TAG_END()(tag_type_t)0, (tag_value_t)0)))
3969 goto err;
3970 else
3971 nta_outgoing_destroy(ack);
3972
3973 home = msg_home(bmsg)((su_home_t*)(bmsg));
3974
3975 if (!(cseq = sip_cseq_create(home, 0x7fffffff, SIP_METHOD_BYEsip_method_bye, "BYE")))
3976 goto err;
3977 else
3978 msg_header_insert(bmsg, (msg_pub_t *)bsip, (msg_header_t *)cseq);
3979
3980 if (!(rq = sip_request_create(home, SIP_METHOD_BYEsip_method_bye, "BYE", ruri, NULL((void*)0))))
3981 goto err;
3982 else
3983 msg_header_insert(bmsg, (msg_pub_t *)bsip, (msg_header_t *)rq);
3984
3985 if (!(bye = nta_outgoing_mcreate(agent, NULL((void*)0), NULL((void*)0), NULL((void*)0), bmsg,
3986 NTATAG_STATELESS(1)ntatag_stateless, tag_bool_v((1)),
3987 TAG_END()(tag_type_t)0, (tag_value_t)0)))
3988 goto err;
3989
3990 msg_destroy(msg);
3991 return 0;
3992
3993 err:
3994
3995 msg_destroy(bmsg);
3996 msg_destroy(amsg);
3997
3998 return -1;
3999}
4000
4001/**Complete a request with values from dialog.
4002 *
4003 * Complete a request message @a msg belonging to a dialog associated with
4004 * @a leg. It increments the local @CSeq value, adds @CallID, @To, @From and
4005 * @Route headers (if there is such headers present in @a leg), and creates
4006 * a new request line object from @a method, @a method_name and @a
4007 * request_uri.
4008 *
4009 * @param msg pointer to a request message object
4010 * @param leg pointer to a #nta_leg_t object
4011 * @param method request method number or #sip_method_unknown
4012 * @param method_name method name (if @a method == #sip_method_unknown)
4013 * @param request_uri request URI
4014 *
4015 * If @a request_uri contains query part, the query part is converted as SIP
4016 * headers and added to the request.
4017 *
4018 * @retval 0 when successful
4019 * @retval -1 upon an error
4020 *
4021 * @sa nta_outgoing_mcreate(), nta_outgoing_tcreate()
4022 */
4023int nta_msg_request_complete(msg_t *msg,
4024 nta_leg_t *leg,
4025 sip_method_t method,
4026 char const *method_name,
4027 url_string_t const *request_uri)
4028{
4029 su_home_t *home = msg_home(msg)((su_home_t*)(msg));
4030 sip_t *sip = sip_object(msg);
4031 sip_to_t const *to;
4032 uint32_t seq;
4033 url_t reg_url[1];
4034 url_string_t const *original = request_uri;
4035
4036 if (!leg || !msg || !sip)
4037 return -1;
4038
4039 if (!sip->sip_route && leg->leg_route) {
4040 if (leg->leg_loose_route) {
4041 if (leg->leg_target) {
4042 request_uri = (url_string_t *)leg->leg_target->m_url;
4043 }
4044 sip->sip_route = sip_route_dup(home, leg->leg_route);
4045 }
4046 else {
4047 sip_route_t **rr;
4048
4049 request_uri = (url_string_t *)leg->leg_route->r_url;
4050 sip->sip_route = sip_route_dup(home, leg->leg_route->r_next);
4051
4052 for (rr = &sip->sip_route; *rr; rr = &(*rr)->r_next)
4053 ;
4054
4055 if (leg->leg_target)
4056 *rr = sip_route_dup(home, (sip_route_t *)leg->leg_target);
4057 }
4058 }
4059 else if (leg->leg_target)
4060 request_uri = (url_string_t *)leg->leg_target->m_url;
4061
4062 if (!request_uri && sip->sip_request)
4063 request_uri = (url_string_t *)sip->sip_request->rq_url;
4064
4065 to = sip->sip_to ? sip->sip_to : leg->leg_remote;
4066
4067 if (!request_uri && to) {
4068 if (method != sip_method_register)
4069 request_uri = (url_string_t *)to->a_url;
4070 else {
4071 /* Remove user part from REGISTER requests */
4072 *reg_url = *to->a_url;
4073 reg_url->url_user = reg_url->url_password = NULL((void*)0);
4074 request_uri = (url_string_t *)reg_url;
4075 }
4076 }
4077
4078 if (!request_uri)
4079 return -1;
4080
4081 if (method || method_name) {
4082 sip_request_t *rq = sip->sip_request;
4083 int use_headers =
4084 request_uri == original || (url_t *)request_uri == rq->rq_url;
4085
4086 if (!rq
4087 || request_uri != (url_string_t *)rq->rq_url
4088 || method != rq->rq_method
4089 || !su_strmatch(method_name, rq->rq_method_name))
4090 rq = NULL((void*)0);
4091
4092 if (rq == NULL((void*)0)) {
4093 rq = sip_request_create(home, method, method_name, request_uri, NULL((void*)0));
4094 if (msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)rq) < 0)
4095 return -1;
4096 }
4097
4098 /* @RFC3261 table 1 (page 152):
4099 * Req-URI cannot contain method parameter or headers
4100 */
4101 if (rq->rq_url->url_params) {
4102 rq->rq_url->url_params =
4103 url_strip_param_string((char *)rq->rq_url->url_params, "method");
4104 sip_fragment_clear(rq->rq_common)((rq->rq_common)->h_data = ((void*)0), (rq->rq_common
)->h_len = 0)
;
4105 }
4106
4107 if (rq->rq_url->url_headers) {
4108 if (use_headers) {
4109 char *s = url_query_as_header_string(msg_home(msg)((su_home_t*)(msg)),
4110 rq->rq_url->url_headers);
4111 if (!s)
4112 return -1;
4113 msg_header_parse_str(msg, (msg_pub_t*)sip, s);
4114 }
4115 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)
;
4116 }
4117 }
4118
4119 if (!sip->sip_request)
4120 return -1;
4121
4122 if (!sip->sip_max_forwards)
4123 sip_add_dup(msg, sip, (sip_header_t *)leg->leg_agent->sa_max_forwards);
4124
4125 if (!sip->sip_from)
4126 sip->sip_from = sip_from_dup(home, leg->leg_local);
4127 else if (leg->leg_local && leg->leg_local->a_tag &&
4128 (!sip->sip_from->a_tag ||
4129 !su_casematch(sip->sip_from->a_tag, leg->leg_local->a_tag)))
4130 sip_from_tag(home, sip->sip_from, leg->leg_local->a_tag);
4131
4132 if (sip->sip_from && !sip->sip_from->a_tag) {
4133 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)
;
4134 sip_from_add_param(home, sip->sip_from,
4135 nta_agent_newtag(home, "tag=%s", leg->leg_agent));
4136 }
4137
4138 if (sip->sip_to) {
4139 if (leg->leg_remote && leg->leg_remote->a_tag)
4140 sip_to_tag(home, sip->sip_to, leg->leg_remote->a_tag);
4141 }
4142 else if (leg->leg_remote) {
4143 sip->sip_to = sip_to_dup(home, leg->leg_remote);
4144 }
4145 else {
4146 sip_to_t *to = sip_to_create(home, request_uri);
4147 if (to) sip_aor_strip(to->a_url);
4148 sip->sip_to = to;
4149 }
4150
4151 if (!sip->sip_from || !sip->sip_from || !sip->sip_to)
4152 return -1;
4153
4154 method = sip->sip_request->rq_method;
4155 method_name = sip->sip_request->rq_method_name;
4156
4157 if (!leg->leg_id && sip->sip_cseq)
4158 seq = sip->sip_cseq->cs_seq;
4159 else if (method == sip_method_ack || method == sip_method_cancel)
4160 /* Dangerous - we may do PRACK/UPDATE meanwhile */
4161 seq = sip->sip_cseq ? sip->sip_cseq->cs_seq : leg->leg_seq;
4162 else if (leg->leg_seq)
4163 seq = ++leg->leg_seq;
4164 else if (sip->sip_cseq) /* Obtain initial value from existing CSeq header */
4165 seq = leg->leg_seq = sip->sip_cseq->cs_seq;
4166 else
4167 seq = leg->leg_seq = (sip_now() >> 1) & 0x7ffffff;
4168
4169 if (!sip->sip_call_id) {
4170 if (leg->leg_id)
4171 sip->sip_call_id = sip_call_id_dup(home, leg->leg_id);
4172 else
4173 sip->sip_call_id = sip_call_id_create(home, NULL((void*)0));
4174 }
4175
4176 if (!sip->sip_cseq ||
4177 seq != sip->sip_cseq->cs_seq ||
4178 method != sip->sip_cseq->cs_method ||
4179 !su_strmatch(method_name, sip->sip_cseq->cs_method_name)) {
4180 sip_cseq_t *cseq = sip_cseq_create(home, seq, method, method_name);
4181 if (msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)cseq) < 0)
4182 return -1;
4183 }
4184
4185 return 0;
4186}
4187
4188/* ====================================================================== */
4189/* 6) Dialogs (legs) */
4190
4191static void leg_insert(nta_agent_t *agent, nta_leg_t *leg);
4192static int leg_route(nta_leg_t *leg,
4193 sip_record_route_t const *route,
4194 sip_record_route_t const *reverse,
4195 sip_contact_t const *contact,
4196 int reroute);
4197static int leg_callback_default(nta_leg_magic_t*, nta_leg_t*,
4198 nta_incoming_t*, sip_t const *);
4199#define HTABLE_HASH_LEG(leg)((leg)->leg_hash) ((leg)->leg_hash)
4200
4201#ifdef __clang__1
4202#pragma clang diagnostic push
4203#pragma clang diagnostic ignored "-Wunused-function"
4204#endif
4205
4206HTABLE_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", 4206, __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", 4206
, __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
;
4207
4208#ifdef __clang__1
4209#pragma clang diagnostic pop
4210#endif
4211
4212su_inlinestatic inline
4213hash_value_t hash_istring(char const *, char const *, hash_value_t);
4214
4215/**@typedef nta_request_f
4216 *
4217 * Callback for incoming requests
4218 *
4219 * This is a callback function invoked by NTA for each incoming SIP request.
4220 *
4221 * @param lmagic call leg context
4222 * @param leg call leg handle
4223 * @param ireq incoming request
4224 * @param sip incoming request contents
4225 *
4226 * @retval 100..699
4227 * NTA constructs a reply message with given error code and corresponding
4228 * standard phrase, then sends the reply.
4229 *
4230 * @retval 0
4231 * The application takes care of sending (or not sending) the reply.
4232 *
4233 * @retval other
4234 * All other return values will be interpreted as
4235 * @e 500 @e Internal @e server @e error.
4236 */
4237
4238
4239/**
4240 * Create a new leg object.
4241 *
4242 * Creates a leg object, which is used to represent dialogs, partial dialogs
4243 * (for example, in case of REGISTER), and destinations within a particular
4244 * NTA object.
4245 *
4246 * When a leg is created, a callback pointer and a application context is
4247 * provided. All other parameters are optional.
4248 *
4249 * @param agent agent object
4250 * @param callback function which is called for each
4251 * incoming request belonging to this leg
4252 * @param magic call leg context
4253 * @param tag,value,... optional extra headers in taglist
4254 *
4255 * When a leg representing dialog is created, the tags SIPTAG_CALL_ID(),
4256 * SIPTAG_FROM(), SIPTAG_TO(), and SIPTAG_CSEQ() (for local @CSeq number) are used
4257 * to establish dialog context. The SIPTAG_FROM() is used to pass local
4258 * address (@From header when making a call, @To header when answering
4259 * to a call) to the newly created leg. Respectively, the SIPTAG_TO() is
4260 * used to pass remote address (@To header when making a call, @From
4261 * header when answering to a call).
4262 *
4263 * If there is a (preloaded) route associated with the leg, SIPTAG_ROUTE()
4264 * and NTATAG_TARGET() can be used. A client or server can also set the
4265 * route using @RecordRoute and @Contact headers from a response or
4266 * request message with the functions nta_leg_client_route() and
4267 * nta_leg_server_route(), respectively.
4268 *
4269 * When a leg representing a local destination is created, the tags
4270 * NTATAG_NO_DIALOG(1), NTATAG_METHOD(), and URLTAG_URL() are used. When a
4271 * request with matching request-URI (URLTAG_URL()) and method
4272 * (NTATAG_METHOD()) is received, it is passed to the callback function
4273 * provided with the leg.
4274 *
4275 * @sa nta_leg_stateful(), nta_leg_bind(),
4276 * nta_leg_tag(), nta_leg_rtag(),
4277 * nta_leg_client_route(), nta_leg_server_route(),
4278 * nta_leg_destroy(), nta_outgoing_tcreate(), and nta_request_f().
4279 *
4280 * @TAGS
4281 * NTATAG_NO_DIALOG(), NTATAG_STATELESS(), NTATAG_METHOD(),
4282 * URLTAG_URL(), SIPTAG_CALL_ID(), SIPTAG_CALL_ID_STR(), SIPTAG_FROM(),
4283 * SIPTAG_FROM_STR(), SIPTAG_TO(), SIPTAG_TO_STR(), SIPTAG_ROUTE(),
4284 * NTATAG_TARGET() and SIPTAG_CSEQ().
4285 *
4286 */
4287nta_leg_t *nta_leg_tcreate(nta_agent_t *agent,
4288 nta_request_f *callback,
4289 nta_leg_magic_t *magic,
4290 tag_type_t tag, tag_value_t value, ...)
4291{
4292 sip_route_t const *route = NULL((void*)0);
4293 sip_contact_t const *contact = NULL((void*)0);
4294 sip_cseq_t const *cs = NULL((void*)0);
4295 sip_call_id_t const *i = NULL((void*)0);
4296 sip_from_t const *from = NULL((void*)0);
4297 sip_to_t const *to = NULL((void*)0);
4298 char const *method = NULL((void*)0);
4299 char const *i_str = NULL((void*)0), *to_str = NULL((void*)0), *from_str = NULL((void*)0), *cs_str = NULL((void*)0);
4300 url_string_t const *url_string = NULL((void*)0);
4301 int no_dialog = 0;
4302 unsigned rseq = 0;
4303 /* RFC 3261 section 12.2.1.1 */
4304 uint32_t seq = 0;
4305 ta_list ta;
4306 nta_leg_t *leg;
4307 su_home_t *home;
4308 url_t *url;
4309 char const *what = NULL((void*)0);
4310
4311 if (agent == NULL((void*)0))
4312 return su_seterrno(EINVAL22), NULL((void*)0);
4313
4314 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)
;
4315
4316 tl_gets(ta_args(ta)(ta).tl,
4317 NTATAG_NO_DIALOG_REF(no_dialog)ntatag_no_dialog_ref, tag_bool_vr(&(no_dialog)),
4318 NTATAG_METHOD_REF(method)ntatag_method_ref, tag_str_vr(&(method)),
4319 URLTAG_URL_REF(url_string)urltag_url_ref, urltag_url_vr(&(url_string)),
4320 SIPTAG_CALL_ID_REF(i)siptag_call_id_ref, siptag_call_id_vr(&(i)),
4321 SIPTAG_CALL_ID_STR_REF(i_str)siptag_call_id_str_ref, tag_str_vr(&(i_str)),
4322 SIPTAG_FROM_REF(from)siptag_from_ref, siptag_from_vr(&(from)),
4323 SIPTAG_FROM_STR_REF(from_str)siptag_from_str_ref, tag_str_vr(&(from_str)),
4324 SIPTAG_TO_REF(to)siptag_to_ref, siptag_to_vr(&(to)),
4325 SIPTAG_TO_STR_REF(to_str)siptag_to_str_ref, tag_str_vr(&(to_str)),
4326 SIPTAG_ROUTE_REF(route)siptag_route_ref, siptag_route_vr(&(route)),
4327 NTATAG_TARGET_REF(contact)ntatag_target_ref, siptag_contact_vr(&(contact)),
4328 NTATAG_REMOTE_CSEQ_REF(rseq)ntatag_remote_cseq_ref, tag_uint_vr(&(rseq)),
4329 SIPTAG_CSEQ_REF(cs)siptag_cseq_ref, siptag_cseq_vr(&(cs)),
4330 SIPTAG_CSEQ_STR_REF(cs_str)siptag_cseq_str_ref, tag_str_vr(&(cs_str)),
4331 TAG_END()(tag_type_t)0, (tag_value_t)0);
4332
4333 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))
;
4334
4335 if (cs)
4336 seq = cs->cs_seq;
4337 else if (cs_str)
4338 seq = strtoul(cs_str, (char **)&cs_str, 10);
4339
4340 if (i == NONE((void *)-1)) /* Magic value, used for compatibility */
4341 no_dialog = 1;
4342
4343 if (!(leg = su_home_clone(NULL((void*)0), sizeof(*leg))))
4344 return NULL((void*)0);
4345 home = leg->leg_home;
4346
4347 leg->leg_agent = agent;
4348 nta_leg_bind(leg, callback, magic);
4349
4350 if (from) {
4351 /* Now this is kludge */
4352 leg->leg_local_is_to = sip_is_to((sip_header_t*)from);
4353 leg->leg_local = sip_to_dup(home, from);
4354 }
4355 else if (from_str)
4356 leg->leg_local = sip_to_make(home, from_str);
4357
4358 if (to && no_dialog) {
4359 /* Remove tag, if any */
4360 sip_to_t to0[1]; *to0 = *to; to0->a_params = NULL((void*)0);
4361 leg->leg_remote = sip_from_dup(home, to0);
4362 }
4363 else if (to)
4364 leg->leg_remote = sip_from_dup(home, to);
4365 else if (to_str)
4366 leg->leg_remote = sip_from_make(home, to_str);
4367
4368 if (route && route != NONE((void *)-1))
4369 leg->leg_route = sip_route_dup(home, route), leg->leg_route_set = 1;
4370
4371 if (contact && contact != NONE((void *)-1)) {
4372 sip_contact_t m[1];
4373 sip_contact_init(m);
4374 *m->m_url = *contact->m_url;
4375 m->m_url->url_headers = NULL((void*)0);
4376 leg->leg_target = sip_contact_dup(home, m);
4377 }
4378
4379 url = url_hdup(home, url_string->us_url);
4380
4381 /* Match to local hosts */
4382 if (url && agent_aliases(agent, url, NULL((void*)0))) {
4383 url_t *changed = url_hdup(home, url);
4384 su_free(home, url);
4385 url = changed;
4386 }
4387
4388 leg->leg_rseq = rseq;
4389 leg->leg_seq = seq;
4390 leg->leg_url = url;
4391
4392 if (from && from != NONE((void *)-1) && leg->leg_local == NULL((void*)0)) {
4393 what = "cannot duplicate local address";
4394 goto err;
4395 }
4396 else if (to && to != NONE((void *)-1) && leg->leg_remote == NULL((void*)0)) {
4397 what = "cannot duplicate remote address";
4398 goto err;
4399 }
4400 else if (route && route != NONE((void *)-1) && leg->leg_route == NULL((void*)0)) {
4401 what = "cannot duplicate route";
4402 goto err;
4403 }
4404 else if (contact && contact != NONE((void *)-1) && leg->leg_target == NULL((void*)0)) {
4405 what = "cannot duplicate target";
4406 goto err;
4407 }
4408 else if (url_string && leg->leg_url == NULL((void*)0)) {
4409 what = "cannot duplicate local destination";
4410 goto err;
4411 }
4412
4413 if (!no_dialog) {
4414 if (!leg->leg_local || !leg->leg_remote) {
4415 /* To and/or From header missing */
4416 if (leg->leg_remote)
4417 what = "Missing local dialog address";
4418 else if (leg->leg_local)
4419 what = "Missing remote dialog address";
4420 else
4421 what = "Missing dialog addresses";
4422 goto err;
4423 }
4424
4425 leg->leg_dialog = 1;
4426
4427 if (i != NULL((void*)0))
4428 leg->leg_id = sip_call_id_dup(home, i);
4429 else if (i_str != NULL((void*)0))
4430 leg->leg_id = sip_call_id_make(home, i_str);
4431 else
4432 leg->leg_id = sip_call_id_create(home, NULL((void*)0));
4433
4434 if (!leg->leg_id) {
4435 what = "cannot create Call-ID";
4436 goto err;
4437 }
4438
4439 leg->leg_hash = leg->leg_id->i_hash;
4440 }
4441 else if (url) {
4442 /* This is "default leg" with a destination URL. */
4443 hash_value_t hash = 0;
4444
4445 if (method) {
4446 leg->leg_method = su_strdup(home, method);
4447 }
4448#if 0
4449 else if (url->url_params) {
4450 int len = url_param(url->url_params, "method", NULL((void*)0), 0);
4451 if (len) {
4452 char *tmp = su_alloc(home, len);
4453 leg->leg_method = tmp;
4454 url_param(url->url_params, "method", tmp, len);
4455 }
4456 }
4457#endif
4458
4459 if (url->url_user && strcmp(url->url_user, "") == 0)
4460 url->url_user = "%"; /* Match to any user */
4461
4462 hash = hash_istring(url->url_scheme, ":", 0);
4463 hash = hash_istring(url->url_host, "", hash);
4464 hash = hash_istring(url->url_user, "@", hash);
4465
4466 leg->leg_hash = hash;
4467 }
4468 else {
4469 /* This is "default leg" without a destination URL. */
4470 if (agent->sa_default_leg) {
4471 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__
, 4471, "%s(): %s\n", "nta_leg_tcreate", "tried to create second default leg"
)) : (void)0)
;
4472 su_seterrno(EEXIST17);
4473 goto err;
4474 }
4475 else {
4476 agent->sa_default_leg = leg;
4477 }
4478 return leg;
4479 }
4480
4481 if (url) {
4482 /* Parameters are ignored when comparing incoming URLs */
4483 url->url_params = NULL((void*)0);
4484 }
4485
4486 leg_insert(agent, leg);
4487
4488 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__
, 4488, "%s(%p)\n", "nta_leg_tcreate", (void *)leg)) : (void)
0)
;
4489
4490 return leg;
4491
4492 err:
4493 if (what)
4494 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__
, 4494, "%s(): %s\n", "nta_leg_tcreate", what)) : (void)0)
;
4495
4496 su_home_zap(leg->leg_home)su_home_unref((leg->leg_home));
4497
4498 return NULL((void*)0);
4499}
4500
4501/** Return the default leg, if any */
4502nta_leg_t *nta_default_leg(nta_agent_t const *agent)
4503{
4504 return agent ? agent->sa_default_leg : NULL((void*)0);
4505}
4506
4507
4508/**
4509 * Insert a call leg to agent.
4510 */
4511static
4512void leg_insert(nta_agent_t *sa, nta_leg_t *leg)
4513{
4514 leg_htable_t *leg_hash;
4515 assert(leg)((void) sizeof ((leg) ? 1 : 0), __extension__ ({ if (leg) ; else
__assert_fail ("leg", "nta.c", 4515, __extension__ __PRETTY_FUNCTION__
); }))
;
4516 assert(sa)((void) sizeof ((sa) ? 1 : 0), __extension__ ({ if (sa) ; else
__assert_fail ("sa", "nta.c", 4516, __extension__ __PRETTY_FUNCTION__
); }))
;
4517
4518 if (leg->leg_dialog)
4519 leg_hash = sa->sa_dialogs;
4520 else
4521 leg_hash = sa->sa_defaults;
4522
4523 if (leg_htable_is_full(leg_hash)) {
4524 leg_htable_resize(sa->sa_home, leg_hash, 0);
4525 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", 4525, __extension__ __PRETTY_FUNCTION__); }))
;
4526 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__
, 4527, "nta: resized%s leg hash to ""%zu""\n", leg->leg_dialog
? "" : " default", leg_hash->lht_size)) : (void)0)
4527 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__
, 4527, "nta: resized%s leg hash to ""%zu""\n", leg->leg_dialog
? "" : " default", leg_hash->lht_size)) : (void)0)
;
4528 }
4529
4530 /* Insert entry into hash table (before other legs with same hash) */
4531 leg_htable_insert(leg_hash, leg);
4532}
4533
4534/**
4535 * Destroy a leg.
4536 *
4537 * @param leg leg to be destroyed
4538 */
4539void nta_leg_destroy(nta_leg_t *leg)
4540{
4541 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__
, 4541, "nta_leg_destroy(%p)\n", (void *)leg)) : (void)0)
;
4542
4543 if (leg) {
4544 leg_htable_t *leg_hash;
4545 nta_agent_t *sa = leg->leg_agent;
4546
4547 assert(sa)((void) sizeof ((sa) ? 1 : 0), __extension__ ({ if (sa) ; else
__assert_fail ("sa", "nta.c", 4547, __extension__ __PRETTY_FUNCTION__
); }))
;
4548
4549 if (leg->leg_dialog) {
4550 assert(sa->sa_dialogs)((void) sizeof ((sa->sa_dialogs) ? 1 : 0), __extension__ (
{ if (sa->sa_dialogs) ; else __assert_fail ("sa->sa_dialogs"
, "nta.c", 4550, __extension__ __PRETTY_FUNCTION__); }))
;
4551 leg_hash = sa->sa_dialogs;
4552 }
4553 else if (leg != sa->sa_default_leg) {
4554 assert(sa->sa_defaults)((void) sizeof ((sa->sa_defaults) ? 1 : 0), __extension__ (
{ if (sa->sa_defaults) ; else __assert_fail ("sa->sa_defaults"
, "nta.c", 4554, __extension__ __PRETTY_FUNCTION__); }))
;
4555 leg_hash = sa->sa_defaults;
4556 }
4557 else {
4558 sa->sa_default_leg = NULL((void*)0);
4559 leg_hash = NULL((void*)0);
4560 }
4561
4562 if (leg_hash)
4563 leg_htable_remove(leg_hash, leg);
4564
4565 leg_free(sa, leg);
4566 }
4567}
4568
4569static
4570void leg_free(nta_agent_t *sa, nta_leg_t *leg)
4571{
4572 //su_free(sa->sa_home, leg);
4573 su_home_unref((su_home_t *)leg);
4574}
4575
4576/** Return application context for the leg */
4577nta_leg_magic_t *nta_leg_magic(nta_leg_t const *leg,
4578 nta_request_f *callback)
4579{
4580 if (leg)
4581 if (!callback || leg->leg_callback == callback)
4582 return leg->leg_magic;
4583
4584 return NULL((void*)0);
4585}
4586
4587/**Bind a callback function and context to a leg object.
4588 *
4589 * Change the callback function and context pointer attached to a leg
4590 * object.
4591 *
4592 * @param leg leg object to be bound
4593 * @param callback new callback function (or NULL if no callback is desired)
4594 * @param magic new context pointer
4595 */
4596void nta_leg_bind(nta_leg_t *leg,
4597 nta_request_f *callback,
4598 nta_leg_magic_t *magic)
4599{
4600 if (leg) {
4601 if (callback)
4602 leg->leg_callback = callback;
4603 else
4604 leg->leg_callback = leg_callback_default;
4605 leg->leg_magic = magic;
4606 }
4607}
4608
4609/** Add a local tag to the leg.
4610 *
4611 * @param leg leg to be tagged
4612 * @param tag tag to be added (if NULL, a tag generated by @b NTA is added)
4613 *
4614 * @return
4615 * Pointer to tag if successful, NULL otherwise.
4616 */
4617char const *nta_leg_tag(nta_leg_t *leg, char const *tag)
4618{
4619 if (!leg || !leg->leg_local)
4620 return su_seterrno(EINVAL22), NULL((void*)0);
4621
4622 if (tag && strchr(tag, '='))
4623 tag = strchr(tag, '=') + 1;
4624
4625 /* If there already is a tag,
4626 return NULL if it does not match with new one */
4627 if (leg->leg_local->a_tag) {
4628 if (tag == NULL((void*)0) || su_casematch(tag, leg->leg_local->a_tag))
4629 return leg->leg_local->a_tag;
4630 else
4631 return NULL((void*)0);
4632 }
4633
4634 if (tag) {
4635 if (sip_to_tag(leg->leg_home, leg->leg_local, tag) < 0)
4636 return NULL((void*)0);
4637 leg->leg_tagged = 1;
4638 return leg->leg_local->a_tag;
4639 }
4640
4641 tag = nta_agent_newtag(leg->leg_home, "tag=%s", leg->leg_agent);
4642
4643 if (!tag || sip_to_add_param(leg->leg_home, leg->leg_local, tag) < 0)
4644 return NULL((void*)0);
4645
4646 leg->leg_tagged = 1;
4647
4648 return leg->leg_local->a_tag;
4649}
4650
4651/** Get local tag. */
4652char const *nta_leg_get_tag(nta_leg_t const *leg)
4653{
4654 if (leg && leg->leg_local)
4655 return leg->leg_local->a_tag;
4656 else
4657 return NULL((void*)0);
4658}
4659
4660/** Add a remote tag to the leg.
4661 *
4662 * @note No remote tag is ever generated.
4663 *
4664 * @param leg leg to be tagged
4665 * @param tag tag to be added (@b must be non-NULL)
4666 *
4667 * @return
4668 * Pointer to tag if successful, NULL otherwise.
4669 */
4670char const *nta_leg_rtag(nta_leg_t *leg, char const *tag)
4671{
4672 /* Add a tag parameter, unless there already is a tag */
4673 if (leg && leg->leg_remote && tag) {
4674 if (sip_from_tag(leg->leg_home, leg->leg_remote, tag) < 0)
4675 return NULL((void*)0);
4676 }
4677
4678 if (leg && leg->leg_remote)
4679 return leg->leg_remote->a_tag;
4680 else
4681 return NULL((void*)0);
4682}
4683
4684/** Get remote tag. */
4685char const *nta_leg_get_rtag(nta_leg_t const *leg)
4686{
4687 if (leg && leg->leg_remote)
4688 return leg->leg_remote->a_tag;
4689 else
4690 return NULL((void*)0);
4691}
4692
4693/** Get local request sequence number. */
4694uint32_t nta_leg_get_seq(nta_leg_t const *leg)
4695{
4696 return leg ? leg->leg_seq : 0;
4697}
4698
4699/** Get remote request sequence number. */
4700uint32_t nta_leg_get_rseq(nta_leg_t const *leg)
4701{
4702 return leg ? leg->leg_rseq : 0;
4703}
4704
4705/** Save target and route set at UAC side.
4706 *
4707 * @sa nta_leg_client_reroute(), nta_leg_server_route(), @RFC3261 section 12.1.2
4708 *
4709 * @bug Allows modifying the route set after initial transaction, if initial
4710 * transaction had no @RecordRoute headers.
4711 *
4712 * @deprecated Use nta_leg_client_reroute() instead.
4713 */
4714int nta_leg_client_route(nta_leg_t *leg,
4715 sip_record_route_t const *route,
4716 sip_contact_t const *contact)
4717{
4718 return leg_route(leg, NULL((void*)0), route, contact, 0);
4719}
4720
4721/** Save target and route set at UAC side.
4722 *
4723 * If @a initial is true, the route set is modified even if it has been set
4724 * earlier.
4725 *
4726 * @param leg pointer to dialog leg
4727 * @param route @RecordRoute headers from response
4728 * @param contact @Contact header from response
4729 * @param initial true if response to initial transaction
4730 *
4731 * @sa nta_leg_client_route(), nta_leg_server_route(), @RFC3261 section 12.1.2
4732 *
4733 * @NEW_1_12_11
4734 */
4735int nta_leg_client_reroute(nta_leg_t *leg,
4736 sip_record_route_t const *route,
4737 sip_contact_t const *contact,
4738 int initial)
4739{
4740 return leg_route(leg, NULL((void*)0), route, contact, initial ? 2 : 1);
4741}
4742
4743/** Save target and route set at UAS side.
4744 *
4745 * @param leg pointer to dialog leg
4746 * @param route @RecordRoute headers from request
4747 * @param contact @Contact header from request
4748 *
4749 * @sa nta_leg_client_reroute(), @RFC3261 section 12.1.1
4750 */
4751int nta_leg_server_route(nta_leg_t *leg,
4752 sip_record_route_t const *route,
4753 sip_contact_t const *contact)
4754{
4755 return leg_route(leg, route, NULL((void*)0), contact, 1);
4756}
4757
4758/** Return route components. */
4759int nta_leg_get_route(nta_leg_t *leg,
4760 sip_route_t const **return_route,
4761 sip_contact_t const **return_target)
4762{
4763 if (!leg)
4764 return -1;
4765
4766 if (return_route)
4767 *return_route = leg->leg_route;
4768
4769 if (return_target)
4770 *return_target = leg->leg_target;
4771
4772 return 0;
4773}
4774
4775/** Generate @Replaces header.
4776 *
4777 * @since New in @VERSION_1_12_2.
4778 */
4779sip_replaces_t *
4780nta_leg_make_replaces(nta_leg_t *leg,
4781 su_home_t *home,
4782 int early_only)
4783{
4784 char const *from_tag, *to_tag;
4785
4786 if (!leg)
4787 return NULL((void*)0);
4788 if (!leg->leg_dialog || !leg->leg_local || !leg->leg_remote || !leg->leg_id)
4789 return NULL((void*)0);
4790
4791 from_tag = leg->leg_local->a_tag; if (!from_tag) from_tag = "0";
4792 to_tag = leg->leg_remote->a_tag; if (!to_tag) to_tag = "0";
4793
4794 return sip_replaces_format(home, "%s;from-tag=%s;to-tag=%s%s",
4795 leg->leg_id->i_id, from_tag, to_tag,
4796 early_only ? ";early-only" : "");
4797}
4798
4799/** Get dialog leg by @Replaces header.
4800 *
4801 * @since New in @VERSION_1_12_2.
4802 */
4803nta_leg_t *
4804nta_leg_by_replaces(nta_agent_t *sa, sip_replaces_t const *rp)
4805{
4806 nta_leg_t *leg = NULL((void*)0);
4807
4808 if (sa && rp && rp->rp_call_id && rp->rp_from_tag && rp->rp_to_tag) {
4809 char const *from_tag = rp->rp_from_tag, *to_tag = rp->rp_to_tag;
4810 sip_call_id_t id[1];
4811 sip_call_id_init(id);
4812
4813 id->i_hash = msg_hash_string(id->i_id = rp->rp_call_id);
4814
4815 leg = leg_find(sa, NULL((void*)0), NULL((void*)0), id, from_tag, to_tag);
4816
4817 if (leg == NULL((void*)0) && strcmp(from_tag, "0") == 0)
4818 leg = leg_find(sa, NULL((void*)0), NULL((void*)0), id, NULL((void*)0), to_tag);
4819 if (leg == NULL((void*)0) && strcmp(to_tag, "0") == 0)
4820 leg = leg_find(sa, NULL((void*)0), NULL((void*)0), id, from_tag, NULL((void*)0));
4821 }
4822
4823 return leg;
4824}
4825
4826/**@internal
4827 * Find a leg corresponding to the request message.
4828 *
4829 */
4830static nta_leg_t *
4831leg_find_call_id(nta_agent_t const *sa,
4832 sip_call_id_t const *i)
4833{
4834 hash_value_t hash = i->i_hash;
4835 leg_htable_t const *lht = sa->sa_dialogs;
4836 nta_leg_t **ll, *leg = NULL((void*)0);
4837
4838 for (ll = leg_htable_hash(lht, hash);
4839 (leg = *ll);
4840 ll = leg_htable_next(lht, ll)) {
4841 sip_call_id_t const *leg_i = leg->leg_id;
4842
4843 if (leg->leg_hash != hash)
4844 continue;
4845 if (strcmp(leg_i->i_id, i->i_id) != 0)
4846 continue;
4847
4848 return leg;
4849 }
4850
4851 return leg;
4852}
4853
4854/** Get dialog leg by @CallID.
4855 *
4856 * @note Usually there should be only single dialog per @CallID on
4857 * User-Agents. However, proxies may fork requests initiating the dialog and
4858 * result in multiple calls per @CallID.
4859 *
4860 * @since New in @VERSION_1_12_9.
4861 */
4862nta_leg_t *
4863nta_leg_by_call_id(nta_agent_t *sa, const char *call_id)
4864{
4865 nta_leg_t *leg = NULL((void*)0);
4866
4867 if (call_id) {
4868 sip_call_id_t id[1];
4869 sip_call_id_init(id);
4870
4871 id->i_hash = msg_hash_string(id->i_id = call_id);
4872
4873 leg = leg_find_call_id(sa, id);
4874 }
4875
4876 return leg;
4877}
4878
4879/** Calculate a simple case-insensitive hash over a string */
4880su_inlinestatic inline
4881hash_value_t hash_istring(char const *s, char const *term, hash_value_t hash)
4882{
4883 if (s) {
4884 for (; *s; s++) {
4885 unsigned char c = *s;
4886 if ('A' <= c && c <= 'Z')
4887 c += 'a' - 'A';
4888 hash = 38501U * (hash + c);
4889 }
4890 for (s = term; *s; s++) {
4891 unsigned char c = *s;
4892 hash = 38501U * (hash + c);
4893 }
4894 }
4895
4896 return hash;
4897}
4898
4899/** @internal Handle requests intended for this leg. */
4900static
4901void leg_recv(nta_leg_t *leg, msg_t *msg, sip_t *sip, tport_t *tport)
4902{
4903 nta_agent_t *agent = leg->leg_agent;
4904 nta_incoming_t *irq;
4905 sip_method_t method = sip->sip_request->rq_method;
4906 char const *method_name = sip->sip_request->rq_method_name;
4907 char const *tag = NULL((void*)0);
4908 int status;
4909
4910 if (leg->leg_local)
4911 tag = leg->leg_local->a_tag;
4912
4913 if (leg->leg_dialog)
4914 agent->sa_stats->as_dialog_tr++;
4915
4916 /* RFC-3262 section 3 (page 4) */
4917 if (agent->sa_is_a_uas && method == sip_method_prack) {
4918 mreply(agent, NULL((void*)0), 481, "No such response", msg,
4919 tport, 0, 0, NULL((void*)0),
4920 TAG_END()(tag_type_t)0, (tag_value_t)0);
4921 return;
4922 }
4923
4924 if (!(irq = incoming_create(agent, msg, sip, tport, tag))) {
4925 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__
, 4926, "nta: leg_recv(%p): cannot create transaction for %s\n"
, (void *)leg, method_name)) : (void)0)
4926 (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__
, 4926, "nta: leg_recv(%p): cannot create transaction for %s\n"
, (void *)leg, method_name)) : (void)0)
;
4927 mreply(agent, NULL((void*)0), SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error, msg,
4928 tport, 0, 0, NULL((void*)0),
4929 TAG_END()(tag_type_t)0, (tag_value_t)0);
4930 return;
4931 }
4932
4933 irq->irq_compressed = leg->leg_compressed;
4934 irq->irq_in_callback = 1;
4935 status = incoming_callback(leg, irq, sip);
4936 irq->irq_in_callback = 0;
4937
4938 if (irq->irq_destroyed) {
4939 if (irq->irq_terminated) {
4940 incoming_free(irq);
4941 return;
4942 }
4943 if (status < 200)
4944 status = 500;
4945 }
4946
4947 if (status == 0)
4948 return;
4949
4950 if (status < 100 || status > 699) {
4951 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__
, 4952, "nta_leg(%p): invalid status %03d from callback\n", (
void *)leg, status)) : (void)0)
4952 (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__
, 4952, "nta_leg(%p): invalid status %03d from callback\n", (
void *)leg, status)) : (void)0)
;
4953 status = 500;
4954 }
4955 else if (method == sip_method_invite && status >= 200 && status < 300) {
4956 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__
, 4957, "nta_leg(%p): invalid INVITE status %03d from callback\n"
, (void *)leg, status)) : (void)0)
4957 (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__
, 4957, "nta_leg(%p): invalid INVITE status %03d from callback\n"
, (void *)leg, status)) : (void)0)
;
4958 status = 500;
4959 }
4960
4961 if (status >= 100 && irq->irq_status < 200)
4962 nta_incoming_treply(irq, status, NULL((void*)0), TAG_END()(tag_type_t)0, (tag_value_t)0);
4963
4964 if (status >= 200)
4965 nta_incoming_destroy(irq);
4966}
4967
4968#if 0
4969/**Compare two SIP from/to fields.
4970 *
4971 * @retval nonzero if matching.
4972 * @retval zero if not matching.
4973 */
4974su_inlinestatic inline
4975int addr_cmp(url_t const *a, url_t const *b)
4976{
4977 if (b == NULL((void*)0))
4978 return 0;
4979 else
4980 return
4981 host_cmp(a->url_host, b->url_host) ||
4982 su_strcmp(a->url_port, b->url_port) ||
4983 su_strcmp(a->url_user, b->url_user);
4984}
4985#endif
4986
4987/** Get a leg by dialog.
4988 *
4989 * Search for a dialog leg from agent's hash table. The matching rules based
4990 * on parameters are as follows:
4991 *
4992 * @param agent pointer to agent object
4993 * @param request_uri if non-NULL, and there is destination URI
4994 * associated with the dialog, these URIs must match
4995 * @param call_id if non-NULL, must match with @CallID header contents
4996 * @param remote_tag if there is remote tag
4997 * associated with dialog, @a remote_tag must match
4998 * @param remote_uri ignored
4999 * @param local_tag if non-NULL and there is local tag associated with leg,
5000 * it must math
5001 * @param local_uri ignored
5002 *
5003 * @note
5004 * If @a remote_tag or @a local_tag is an empty string (""), the tag is
5005 * ignored when matching legs.
5006 */
5007nta_leg_t *nta_leg_by_dialog(nta_agent_t const *agent,
5008 url_t const *request_uri,
5009 sip_call_id_t const *call_id,
5010 char const *remote_tag,
5011 url_t const *remote_uri,
5012 char const *local_tag,
5013 url_t const *local_uri)
5014{
5015 void *to_be_freed = NULL((void*)0);
5016 url_t *url;
5017 url_t url0[1];
5018 nta_leg_t *leg;
5019
5020 if (!agent || !call_id)
5021 return su_seterrno(EINVAL22), NULL((void*)0);
5022
5023 if (request_uri == NULL((void*)0)) {
5024 url = NULL((void*)0);
5025 }
5026 else if (URL_IS_STRING(request_uri)((request_uri) && *((url_string_t*)(request_uri))->
us_str != 0)
) {
5027 /* accept a string as URL */
5028 to_be_freed = url = url_hdup(NULL((void*)0), request_uri);
5029 }
5030 else {
5031 *url0 = *request_uri, url = url0;
5032 }
5033
5034 if (url) {
5035 url->url_params = NULL((void*)0);
5036 agent_aliases(agent, url, NULL((void*)0)); /* canonize url */
5037 }
5038
5039 if (remote_tag && remote_tag[0] == '\0')
5040 remote_tag = NULL((void*)0);
5041 if (local_tag && local_tag[0] == '\0')
5042 local_tag = NULL((void*)0);
5043
5044 leg = leg_find(agent,
5045 NULL((void*)0), url,
5046 call_id,
5047 remote_tag,
5048 local_tag);
5049
5050 if (to_be_freed) su_free(NULL((void*)0), to_be_freed);
5051
5052 return leg;
5053}
5054
5055/**@internal
5056 * Find a leg corresponding to the request message.
5057 *
5058 * A leg matches to message if leg_match_request() returns true ("Call-ID",
5059 * "To"-tag, and "From"-tag match).
5060 */
5061static
5062nta_leg_t *leg_find(nta_agent_t const *sa,
5063 char const *method_name,
5064 url_t const *request_uri,
5065 sip_call_id_t const *i,
5066 char const *from_tag,
5067 char const *to_tag)
5068{
5069 hash_value_t hash = i->i_hash;
5070 leg_htable_t const *lht = sa->sa_dialogs;
5071 nta_leg_t **ll, *leg, *loose_match = NULL((void*)0);
5072
5073 for (ll = leg_htable_hash(lht, hash);
5074 (leg = *ll);
5075 ll = leg_htable_next(lht, ll)) {
5076 sip_call_id_t const *leg_i = leg->leg_id;
5077 char const *remote_tag = leg->leg_remote->a_tag;
5078 char const *local_tag = leg->leg_local->a_tag;
5079
5080 url_t const *leg_url = leg->leg_url;
5081 char const *leg_method = leg->leg_method;
5082
5083 if (leg->leg_hash != hash)
5084 continue;
5085 if (strcmp(leg_i->i_id, i->i_id) != 0)
5086 continue;
5087
5088 /* Do not match if the incoming To has tag, but the local does not */
5089 if (!local_tag && to_tag)
5090 continue;
5091
5092 /*
5093 * Do not match if incoming To has no tag and we have local tag
5094 * and the tag has been there from the beginning.
5095 */
5096 if (local_tag && !to_tag && !leg->leg_tagged)
5097 continue;
5098
5099 /* Do not match if incoming From has no tag but remote has a tag */
5100 if (remote_tag && !from_tag)
5101 continue;
5102
5103 /* Avoid matching with itself */
5104 if (!remote_tag != !from_tag && !local_tag != !to_tag)
5105 continue;
5106
5107 if (local_tag && to_tag && !su_casematch(local_tag, to_tag) && to_tag[0])
5108 continue;
5109 if (remote_tag && from_tag && !su_casematch(remote_tag, from_tag) && from_tag[0])
5110 continue;
5111
5112 if (leg_url && request_uri && url_cmp(leg_url, request_uri))
5113 continue;
5114 if (leg_method && method_name && !su_casematch(method_name, leg_method))
5115 continue;
5116
5117 /* Perfect match if both local and To have tag
5118 * or local does not have tag.
5119 */
5120 if ((!local_tag || to_tag))
5121 return leg;
5122
5123 if (loose_match == NULL((void*)0))
5124 loose_match = leg;
5125 }
5126
5127 return loose_match;
5128}
5129
5130/** Get leg by destination */
5131nta_leg_t *nta_leg_by_uri(nta_agent_t const *agent, url_string_t const *us)
5132{
5133 url_t *url;
5134 nta_leg_t *leg = NULL((void*)0);
5135
5136 if (!agent)
5137 return NULL((void*)0);
5138
5139 if (!us)
5140 return agent->sa_default_leg;
5141
5142 url = url_hdup(NULL((void*)0), us->us_url);
5143
5144 if (url) {
5145 agent_aliases(agent, url, NULL((void*)0));
5146 leg = dst_find(agent, url, NULL((void*)0));
5147 su_free(NULL((void*)0), url);
5148 }
5149
5150 return leg;
5151}
5152
5153/** Find a non-dialog leg corresponding to the request uri u0 */
5154static
5155nta_leg_t *dst_find(nta_agent_t const *sa,
5156 url_t const *u0,
5157 char const *method_name)
5158{
5159 hash_value_t hash, hash2;
5160 leg_htable_t const *lht = sa->sa_defaults;
5161 nta_leg_t **ll, *leg, *loose_match = NULL((void*)0);
5162 int again;
5163 url_t url[1];
5164
5165 *url = *u0;
5166 hash = hash_istring(url->url_scheme, ":", 0);
5167 hash = hash_istring(url->url_host, "", hash);
5168 hash2 = hash_istring("%", "@", hash);
5169 hash = hash_istring(url->url_user, "@", hash);
5170
5171 /* First round, search with user name */
5172 /* Second round, search without user name */
5173 do {
5174 for (ll = leg_htable_hash(lht, hash);
5175 (leg = *ll);
5176 ll = leg_htable_next(lht, ll)) {
5177 if (leg->leg_hash != hash)
5178 continue;
5179 if (url_cmp(url, leg->leg_url))
5180 continue;
5181 if (!method_name) {
5182 if (leg->leg_method)
5183 continue;
5184 return leg;
5185 }
5186 else if (leg->leg_method) {
5187 if (!su_casematch(method_name, leg->leg_method))
5188 continue;
5189 return leg;
5190 }
5191 loose_match = leg;
5192 }
5193 if (loose_match)
5194 return loose_match;
5195
5196 again = 0;
5197
5198 if (url->url_user && strcmp(url->url_user, "%")) {
5199 url->url_user = "%";
5200 hash = hash2;
5201 again = 1;
5202 }
5203 } while (again);
5204
5205 return NULL((void*)0);
5206}
5207
5208/** Set leg route and target URL.
5209 *
5210 * Sets the leg route and contact using the @RecordRoute and @Contact
5211 * headers.
5212 *
5213 * @param reroute - allow rerouting
5214 * - if 1, follow @RFC3261 semantics
5215 * - if 2, response to initial transaction)
5216 */
5217static
5218int leg_route(nta_leg_t *leg,
5219 sip_record_route_t const *route,
5220 sip_record_route_t const *reverse,
5221 sip_contact_t const *contact,
5222 int reroute)
5223{
5224 su_home_t *home = leg->leg_home;
5225 sip_route_t *r, r0[1], *old;
5226 int route_is_set;
5227
5228 if (!leg)
5229 return -1;
5230
5231 if (route == NULL((void*)0) && reverse == NULL((void*)0) && contact == NULL((void*)0))
5232 return 0;
5233
5234 sip_route_init(r0);
5235
5236 route_is_set = reroute ? leg->leg_route_set : leg->leg_route != NULL((void*)0);
5237
5238 if (route_is_set && reroute <= 1) {
5239 r = leg->leg_route;
5240 }
5241 else if (route) {
5242 r = sip_route_fixdup(home, route); if (!r) return -1;
5243 }
5244 else if (reverse) {
5245 r = sip_route_reverse(home, reverse); if (!r) return -1;
5246 }
5247 else
5248 r = NULL((void*)0);
5249
5250#ifdef NTA_STRICT_ROUTING
5251 /*
5252 * Handle Contact according to the RFC2543bis04 sections 16.1, 16.2 and 16.4.
5253 */
5254 if (contact) {
5255 *r0->r_url = *contact->m_url;
5256
5257 if (!(m_r = sip_route_dup(leg->leg_home, r0)))
5258 return -1;
5259
5260 /* Append, but replace last entry if it was generated from contact */
5261 for (rr = &r; *rr; rr = &(*rr)->r_next)
5262 if (leg->leg_contact_set && (*rr)->r_next == NULL((void*)0))
5263 break;
5264 }
5265 else
5266 rr = NULL((void*)0);
5267
5268 if (rr) {
5269 if (*rr)
5270 su_free(leg->leg_home, *rr);
5271 *rr = m_r;
5272 }
5273 if (m_r != NULL((void*)0))
5274 leg->leg_contact_set = 1;
5275
5276#else
5277 if (r && r->r_url->url_params)
5278 leg->leg_loose_route = url_has_param(r->r_url, "lr");
5279
5280 if (contact) {
5281 sip_contact_t *target, m[1], *m0;
5282
5283 sip_contact_init(m);
5284 *m->m_url = *contact->m_url;
5285 m->m_url->url_headers = NULL((void*)0);
5286 target = sip_contact_dup(leg->leg_home, m);
5287
5288 if (target && target->m_url->url_params) {
5289 /* Remove ttl, method. @RFC3261 table 1, page 152 */
5290 char *p = (char *)target->m_url->url_params;
5291 p = url_strip_param_string(p, "method");
5292 p = url_strip_param_string(p, "ttl");
5293 target->m_url->url_params = p;
5294 }
5295
5296 m0 = leg->leg_target, leg->leg_target = target;
5297
5298 if (m0)
5299 su_free(leg->leg_home, m0);
5300 }
5301#endif
5302
5303 old = leg->leg_route;
5304 leg->leg_route = r;
5305
5306 if (old && old != r)
5307 msg_header_free(leg->leg_home, (msg_header_t *)old);
5308
5309 leg->leg_route_set = 1;
5310
5311 return 0;
5312}
5313
5314/** @internal Default leg callback. */
5315static int
5316leg_callback_default(nta_leg_magic_t *magic,
5317 nta_leg_t *leg,
5318 nta_incoming_t *irq,
5319 sip_t const *sip)
5320{
5321 nta_incoming_treply(irq,
5322 SIP_501_NOT_IMPLEMENTED501, sip_501_Not_implemented,
5323 TAG_END()(tag_type_t)0, (tag_value_t)0);
5324 return 501;
5325}
5326
5327/* ====================================================================== */
5328/* 7) Server-side (incoming) transactions */
5329
5330#define HTABLE_HASH_IRQ(irq)((irq)->irq_hash) ((irq)->irq_hash)
5331HTABLE_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", 5332, __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", 5332
, __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
5332 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", 5332, __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", 5332
, __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
;
5333
5334static void incoming_insert(nta_agent_t *agent,
5335 incoming_queue_t *queue,
5336 nta_incoming_t *irq);
5337
5338su_inlinestatic inline int incoming_is_queued(nta_incoming_t const *irq);
5339su_inlinestatic inline void incoming_queue(incoming_queue_t *queue, nta_incoming_t *);
5340su_inlinestatic inline void incoming_remove(nta_incoming_t *irq);
5341su_inlinestatic inline void incoming_set_timer(nta_incoming_t *, uint32_t interval);
5342su_inlinestatic inline void incoming_reset_timer(nta_incoming_t *);
5343su_inlinestatic inline size_t incoming_mass_destroy(nta_agent_t *, incoming_queue_t *);
5344
5345static int incoming_set_params(nta_incoming_t *irq, tagi_t const *tags);
5346su_inlinestatic inline
5347int incoming_set_compartment(nta_incoming_t *irq, tport_t *tport, msg_t *msg,
5348 int create_if_needed);
5349
5350su_inlinestatic inline nta_incoming_t
5351 *incoming_call_callback(nta_incoming_t *, msg_t *, sip_t *);
5352su_inlinestatic inline int incoming_final_failed(nta_incoming_t *irq, msg_t *);
5353static void incoming_retransmit_reply(nta_incoming_t *irq, tport_t *tport);
5354
5355/** Create a default server transaction.
5356 *
5357 * The default server transaction is used by a proxy to forward responses
5358 * statelessly.
5359 *
5360 * @param agent pointer to agent object
5361 *
5362 * @retval pointer to default server transaction object
5363 * @retval NULL if failed
5364 */
5365nta_incoming_t *nta_incoming_default(nta_agent_t *agent)
5366{
5367 msg_t *msg;
5368 su_home_t *home;
5369 nta_incoming_t *irq;
5370
5371 if (agent == NULL((void*)0))
5372 return su_seterrno(EFAULT14), NULL((void*)0);
5373 if (agent->sa_default_incoming)
5374 return su_seterrno(EEXIST17), NULL((void*)0);
5375
5376 msg = nta_msg_create(agent, 0);
5377 if (!msg)
5378 return NULL((void*)0);
5379
5380 irq = su_zalloc(home = msg_home(msg)((su_home_t*)(msg)), sizeof(*irq));
5381 if (!irq)
5382 return (void)msg_destroy(msg), NULL((void*)0);
5383
5384 irq->irq_home = home;
5385 irq->irq_request = NULL((void*)0);
5386 irq->irq_agent = agent;
5387 irq->irq_received = agent_now(agent);
5388 irq->irq_method = sip_method_invalid;
5389
5390 irq->irq_default = 1;
5391 agent->sa_default_incoming = irq;
5392
5393 return irq;
5394}
5395
5396/** Create a server transaction.
5397 *
5398 * Create a server transaction for a request message. This function is used
5399 * when an element processing requests statelessly wants to process a
5400 * particular request statefully.
5401 *
5402 * @param agent pointer to agent object
5403 * @param leg pointer to leg object (either @a agent or @a leg may be NULL)
5404 * @param msg pointer to message object
5405 * @param sip pointer to SIP structure (may be NULL)
5406 * @param tag,value,... optional tagged parameters
5407 *
5408 * @note
5409 * The ownership of @a msg is taken over by the function even if the
5410 * function fails.
5411 *
5412 * @TAGS
5413 * @TAG NTATAG_TPORT() specifies the transport used to receive the request
5414 * and also default transport for sending the response.
5415 *
5416 * @retval nta_incoming_t pointer to the newly created server transaction
5417 * @retval NULL if failed
5418 */
5419nta_incoming_t *nta_incoming_create(nta_agent_t *agent,
5420 nta_leg_t *leg,
5421 msg_t *msg,
5422 sip_t *sip,
5423 tag_type_t tag, tag_value_t value, ...)
5424{
5425 char const *to_tag = NULL((void*)0);
5426 tport_t *tport = NULL((void*)0);
5427 ta_list ta;
5428 nta_incoming_t *irq;
5429
5430 if (msg == NULL((void*)0))
5431 return NULL((void*)0);
5432
5433 if (agent == NULL((void*)0) && leg != NULL((void*)0))
5434 agent = leg->leg_agent;
5435
5436 if (sip == NULL((void*)0))
5437 sip = sip_object(msg);
5438
5439 if (agent == NULL((void*)0) || sip == NULL((void*)0) || !sip->sip_request || !sip->sip_cseq)
5440 return msg_destroy(msg), NULL((void*)0);
5441
5442 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)
;
5443
5444 tl_gets(ta_args(ta)(ta).tl,
5445 NTATAG_TPORT_REF(tport)ntatag_tport_ref, tag_ptr_vr(&(tport), (tport)),
5446 TAG_END()(tag_type_t)0, (tag_value_t)0);
5447 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))
;
5448
5449 if (leg && leg->leg_local)
5450 to_tag = leg->leg_local->a_tag;
5451
5452 if (tport == NULL((void*)0))
5453 tport = tport_delivered_by(agent->sa_tports, msg);
5454
5455 irq = incoming_create(agent, msg, sip, tport, to_tag);
5456
5457 if (!irq)
5458 msg_destroy(msg);
5459
5460 return irq;
5461}
5462
5463/** @internal Create a new incoming transaction object. */
5464static
5465nta_incoming_t *incoming_create(nta_agent_t *agent,
5466 msg_t *msg,
5467 sip_t *sip,
5468 tport_t *tport,
5469 char const *tag)
5470{
5471 nta_incoming_t *irq = su_zalloc(msg_home(msg)((su_home_t*)(msg)), sizeof(*irq));
5472
5473 agent->sa_stats->as_server_tr++;
5474
5475 if (irq) {
5476 su_home_t *home;
5477 incoming_queue_t *queue;
5478 sip_method_t method = sip->sip_request->rq_method;
5479
5480 irq->irq_request = msg;
5481 irq->irq_home = home = msg_home(msg_ref_create(msg))((su_home_t*)(msg_ref_create(msg)));
5482 irq->irq_agent = agent;
5483
5484 irq->irq_received = agent_now(agent); /* Timestamp originally from tport */
5485
5486 irq->irq_method = method;
5487 irq->irq_rq = sip_request_copy(home, sip->sip_request);
5488 irq->irq_from = sip_from_copy(home, sip->sip_from);
5489 irq->irq_to = sip_to_copy(home, sip->sip_to);
5490 irq->irq_call_id = sip_call_id_copy(home, sip->sip_call_id);
5491 irq->irq_cseq = sip_cseq_copy(home, sip->sip_cseq);
5492 irq->irq_via = sip_via_copy(home, sip->sip_via);
5493 switch (method) {
5494 case sip_method_ack:
5495 case sip_method_cancel:
5496 case sip_method_bye:
5497 case sip_method_options:
5498 case sip_method_register: /* Handling Path is up to application */
5499 case sip_method_info:
5500 case sip_method_prack:
5501 case sip_method_publish:
5502 break;
5503 default:
5504 irq->irq_record_route =
5505 sip_record_route_copy(home, sip->sip_record_route);
5506 }
5507 irq->irq_branch = sip->sip_via->v_branch;
5508 irq->irq_reliable_tp = tport_is_reliable(tport);
5509 irq->irq_extra_100 = 0; /* Sending extra 100 trying false by default */
5510
5511 if (sip->sip_timestamp)
5512 irq->irq_timestamp = sip_timestamp_copy(home, sip->sip_timestamp);
5513
5514 /* Tag transaction */
5515 if (tag)
5516 sip_to_tag(home, irq->irq_to, tag);
5517 irq->irq_tag = irq->irq_to->a_tag;
5518
5519 if (method != sip_method_ack) {
5520 int *use_rport = NULL((void*)0);
5521 int retry_without_rport = 0;
5522
5523 if (agent->sa_server_rport)
5524 use_rport = &retry_without_rport, retry_without_rport = 1;
5525
5526 if (nta_tpn_by_via(irq->irq_tpn, irq->irq_via, use_rport) < 0)
5527 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__
, 5527, "%s: bad via\n", __func__)) : (void)0)
;
5528 }
5529
5530 incoming_set_compartment(irq, tport, msg, 0);
5531
5532 if (method == sip_method_invite) {
5533 irq->irq_must_100rel =
5534 sip->sip_require && sip_has_feature(sip->sip_require, "100rel");
5535
5536 if (irq->irq_must_100rel ||
5537 (sip->sip_supported &&
5538 sip_has_feature(sip->sip_supported, "100rel"))) {
5539 irq->irq_rseq = su_randint(1, 0x7fffffff); /* Initialize rseq */
5540 }
5541
5542 queue = agent->sa_in.proceeding;
5543
5544 if (irq->irq_reliable_tp)
5545 incoming_set_timer(irq, agent->sa_t2 / 2); /* N1 = T2 / 2 */
5546 else
5547 incoming_set_timer(irq, 200); /* N1 = 200 ms */
5548
5549 irq->irq_tport = tport_ref(tport);
5550 }
5551 else if (method == sip_method_ack) {
5552 irq->irq_status = 700; /* Never send reply to ACK */
5553 irq->irq_completed = 1;
5554 if (irq->irq_reliable_tp || !agent->sa_is_a_uas) {
5555 queue = agent->sa_in.terminated;
5556 irq->irq_terminated = 1;
5557 }
5558 else {
5559 queue = agent->sa_in.completed; /* Timer J */
5560 }
5561 }
5562 else {
5563 queue = agent->sa_in.proceeding;
5564 /* RFC 4320 (nit-actions-03):
5565
5566 Blacklisting on a late response occurs even over reliable transports.
5567 Thus, if an element processing a request received over a reliable
5568 transport is delaying its final response at all, sending a 100 Trying
5569 well in advance of the timeout will prevent blacklisting. Sending a
5570 100 Trying immediately will not harm the transaction as it would over
5571 UDP, but a policy of always sending such a message results in
5572 unneccessary traffic. A policy of sending a 100 Trying after the
5573 period of time in which Timer E reaches T2 had this been a UDP hop is
5574 one reasonable compromise.
5575
5576 */
5577 if (agent->sa_extra_100 && irq->irq_reliable_tp)
5578 incoming_set_timer(irq, agent->sa_t2 / 2); /* T2 / 2 */
5579
5580 irq->irq_tport = tport_ref(tport);
5581 }
5582
5583 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))
;
5584
5585 incoming_insert(agent, queue, irq);
5586 }
5587
5588 return irq;
5589}
5590
5591/** @internal
5592 * Insert incoming transaction to hash table.
5593 */
5594static void
5595incoming_insert(nta_agent_t *agent,
5596 incoming_queue_t *queue,
5597 nta_incoming_t *irq)
5598{
5599 incoming_queue(queue, irq);
5600
5601 if (incoming_htable_is_full(agent->sa_incoming))
5602 incoming_htable_resize(agent->sa_home, agent->sa_incoming, 0);
5603
5604 if (irq->irq_method != sip_method_ack)
5605 incoming_htable_insert(agent->sa_incoming, irq);
5606 else
5607 /* ACK is appended - final response with tags match with it,
5608 * not with the original INVITE transaction */
5609 /* XXX - what about rfc2543 servers, which do not add tag? */
5610 incoming_htable_append(agent->sa_incoming, irq);
5611}
5612
5613/** Call callback for incoming request */
5614static
5615int incoming_callback(nta_leg_t *leg, nta_incoming_t *irq, sip_t *sip)
5616{
5617 sip_method_t method = sip->sip_request->rq_method;
5618 char const *method_name = sip->sip_request->rq_method_name;
5619
5620 /* RFC-3261 section 12.2.2 (page 76) */
5621 if (leg->leg_dialog &&
5622 irq->irq_agent->sa_is_a_uas &&
5623 method != sip_method_ack) {
5624 uint32_t seq = sip->sip_cseq->cs_seq;
5625
5626 if (leg->leg_rseq > sip->sip_cseq->cs_seq) {
5627 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__
, 5628, "nta_leg(%p): out-of-order %s (%u < %u)\n", (void *
)leg, method_name, seq, leg->leg_rseq)) : (void)0)
5628 (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__
, 5628, "nta_leg(%p): out-of-order %s (%u < %u)\n", (void *
)leg, method_name, seq, leg->leg_rseq)) : (void)0)
;
5629 return 500;
5630 }
5631
5632 leg->leg_rseq = seq;
5633 }
5634
5635 return leg->leg_callback(leg->leg_magic, leg, irq, sip);
5636}
5637
5638/**
5639 * Destroy an incoming transaction.
5640 *
5641 * This function does not actually free transaction object, but marks it as
5642 * disposable. The object is freed after a timeout.
5643 *
5644 * @param irq incoming request object to be destroyed
5645 */
5646void nta_incoming_destroy(nta_incoming_t *irq)
5647{
5648 if (irq) {
5649 irq->irq_callback = NULL((void*)0);
5650 irq->irq_magic = NULL((void*)0);
5651 irq->irq_destroyed = 1;
5652 if (!irq->irq_in_callback) {
5653 if (irq->irq_terminated || irq->irq_default)
5654 incoming_free(irq);
5655 else if (irq->irq_status < 200)
5656 nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error, TAG_END()(tag_type_t)0, (tag_value_t)0);
5657 }
5658 }
5659}
5660
5661/** @internal
5662 * Initialize a queue for incoming transactions.
5663 */
5664static void
5665incoming_queue_init(incoming_queue_t *queue, unsigned timeout)
5666{
5667 memset(queue, 0, sizeof *queue);
5668 queue->q_tail = &queue->q_head;
5669 queue->q_timeout = timeout;
5670}
5671
5672/** Change the timeout value of a queue */
5673static void
5674incoming_queue_adjust(nta_agent_t *sa,
5675 incoming_queue_t *queue,
5676 uint32_t timeout)
5677{
5678 nta_incoming_t *irq;
5679 uint32_t latest;
5680
5681 if (timeout >= queue->q_timeout || !queue->q_head) {
5682 queue->q_timeout = timeout;
5683 return;
5684 }
5685
5686 latest = set_timeout(sa, queue->q_timeout = timeout);
5687
5688 for (irq = queue->q_head; irq; irq = irq->irq_next) {
5689 if ((int32_t)(irq->irq_timeout - latest) > 0)
5690 irq->irq_timeout = latest;
5691 }
5692}
5693
5694/** @internal
5695 * Test if an incoming transaction is in a queue.
5696 */
5697su_inlinestatic inline
5698int incoming_is_queued(nta_incoming_t const *irq)
5699{
5700 return irq && irq->irq_queue;
5701}
5702
5703/** @internal
5704 * Insert an incoming transaction into a queue.
5705 *
5706 * Insert a server transaction into a queue, and sets the corresponding
5707 * timeout at the same time.
5708 */
5709su_inlinestatic inline
5710void incoming_queue(incoming_queue_t *queue,
5711 nta_incoming_t *irq)
5712{
5713 if (irq->irq_queue == queue) {
15
Assuming 'queue' is not equal to field 'irq_queue'
16
Taking false branch
5714 assert(queue->q_timeout == 0)((void) sizeof ((queue->q_timeout == 0) ? 1 : 0), __extension__
({ if (queue->q_timeout == 0) ; else __assert_fail ("queue->q_timeout == 0"
, "nta.c", 5714, __extension__ __PRETTY_FUNCTION__); }))
;
5715 return;
5716 }
5717
5718 if (incoming_is_queued(irq))
17
Taking true branch
5719 incoming_remove(irq);
5720
5721 assert(*queue->q_tail == NULL)((void) sizeof ((*queue->q_tail == ((void*)0)) ? 1 : 0), __extension__
({ if (*queue->q_tail == ((void*)0)) ; else __assert_fail
("*queue->q_tail == NULL", "nta.c", 5721, __extension__ __PRETTY_FUNCTION__
); }))
;
18
Access to field 'q_tail' results in a dereference of a null pointer (loaded from variable 'queue')
5722
5723 irq->irq_timeout = set_timeout(irq->irq_agent, queue->q_timeout);
5724
5725 irq->irq_queue = queue;
5726 irq->irq_prev = queue->q_tail;
5727 *queue->q_tail = irq;
5728 queue->q_tail = &irq->irq_next;
5729 queue->q_length++;
5730}
5731
5732/** @internal
5733 * Remove an incoming transaction from a queue.
5734 */
5735su_inlinestatic inline
5736void incoming_remove(nta_incoming_t *irq)
5737{
5738 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", 5738, __extension__ __PRETTY_FUNCTION__); }))
;
5739 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", 5739, __extension__ __PRETTY_FUNCTION__); }))
;
5740
5741 if ((*irq->irq_prev = irq->irq_next))
5742 irq->irq_next->irq_prev = irq->irq_prev;
5743 else
5744 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", 5744, __extension__
__PRETTY_FUNCTION__); }))
;
5745
5746 irq->irq_queue->q_length--;
5747 irq->irq_next = NULL((void*)0);
5748 irq->irq_prev = NULL((void*)0);
5749 irq->irq_queue = NULL((void*)0);
5750 irq->irq_timeout = 0;
5751}
5752
5753su_inlinestatic inline
5754void incoming_set_timer(nta_incoming_t *irq, uint32_t interval)
5755{
5756 nta_incoming_t **rq;
5757
5758 assert(irq)((void) sizeof ((irq) ? 1 : 0), __extension__ ({ if (irq) ; else
__assert_fail ("irq", "nta.c", 5758, __extension__ __PRETTY_FUNCTION__
); }))
;
5759
5760 if (interval == 0) {
5761 incoming_reset_timer(irq);
5762 return;
5763 }
5764
5765 if (irq->irq_rprev) {
5766 if ((*irq->irq_rprev = irq->irq_rnext))
5767 irq->irq_rnext->irq_rprev = irq->irq_rprev;
5768 if (irq->irq_agent->sa_in.re_t1 == &irq->irq_rnext)
5769 irq->irq_agent->sa_in.re_t1 = irq->irq_rprev;
5770 } else {
5771 irq->irq_agent->sa_in.re_length++;
5772 }
5773
5774 irq->irq_retry = set_timeout(irq->irq_agent, irq->irq_interval = interval);
5775
5776 rq = irq->irq_agent->sa_in.re_t1;
5777
5778 if (!(*rq) || (int32_t)((*rq)->irq_retry - irq->irq_retry) > 0)
5779 rq = &irq->irq_agent->sa_in.re_list;
5780
5781 while (*rq && (int32_t)((*rq)->irq_retry - irq->irq_retry) <= 0)
5782 rq = &(*rq)->irq_rnext;
5783
5784 if ((irq->irq_rnext = *rq))
5785 irq->irq_rnext->irq_rprev = &irq->irq_rnext;
5786 *rq = irq;
5787 irq->irq_rprev = rq;
5788
5789 /* Optimization: keep special place for transactions with T1 interval */
5790 if (interval == irq->irq_agent->sa_t1)
5791 irq->irq_agent->sa_in.re_t1 = rq;
5792}
5793
5794su_inlinestatic inline
5795void incoming_reset_timer(nta_incoming_t *irq)
5796{
5797 if (irq->irq_rprev) {
5798 if ((*irq->irq_rprev = irq->irq_rnext))
5799 irq->irq_rnext->irq_rprev = irq->irq_rprev;
5800 if (irq->irq_agent->sa_in.re_t1 == &irq->irq_rnext)
5801 irq->irq_agent->sa_in.re_t1 = irq->irq_rprev;
5802 irq->irq_agent->sa_in.re_length--;
5803 }
5804
5805 irq->irq_interval = 0, irq->irq_retry = 0;
5806 irq->irq_rnext = NULL((void*)0), irq->irq_rprev = NULL((void*)0);
5807}
5808
5809/** @internal
5810 * Free an incoming transaction.
5811 */
5812static
5813void incoming_free(nta_incoming_t *irq)
5814{
5815 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__
, 5815, "nta: incoming_free(%p)\n", (void *)irq)) : (void)0)
;
5816
5817 incoming_cut_off(irq);
5818 incoming_reclaim(irq);
5819}
5820
5821/** Remove references to the irq */
5822su_inlinestatic inline
5823void incoming_cut_off(nta_incoming_t *irq)
5824{
5825 nta_agent_t *agent = irq->irq_agent;
5826
5827 assert(agent)((void) sizeof ((agent) ? 1 : 0), __extension__ ({ if (agent)
; else __assert_fail ("agent", "nta.c", 5827, __extension__ __PRETTY_FUNCTION__
); }))
;
5828
5829 if (irq->irq_default) {
5830 if (irq == agent->sa_default_incoming)
5831 agent->sa_default_incoming = NULL((void*)0);
5832 irq->irq_default = 0;
5833 return;
5834 }
5835
5836 if (incoming_is_queued(irq))
5837 incoming_remove(irq);
5838
5839 incoming_reset_timer(irq);
5840
5841 incoming_htable_remove(agent->sa_incoming, irq);
5842
5843 if (irq->irq_cc)
5844 nta_compartment_decref(&irq->irq_cc);
5845
5846 if (irq->irq_tport)
5847 tport_decref(&irq->irq_tport);
5848}
5849
5850/** Reclaim the memory used by irq */
5851su_inlinestatic inline
5852void incoming_reclaim(nta_incoming_t *irq)
5853{
5854 su_home_t *home = irq->irq_home;
5855 nta_reliable_t *rel, *rel_next;
5856
5857 if (irq->irq_request)
5858 msg_destroy(irq->irq_request), irq->irq_request = NULL((void*)0);
5859 if (irq->irq_request2)
5860 msg_destroy(irq->irq_request2), irq->irq_request2 = NULL((void*)0);
5861 if (irq->irq_response)
5862 msg_destroy(irq->irq_response), irq->irq_response = NULL((void*)0);
5863
5864 for (rel = irq->irq_reliable; rel; rel = rel_next) {
5865 rel_next = rel->rel_next;
5866 if (rel->rel_unsent)
5867 msg_destroy(rel->rel_unsent);
5868 su_free(irq->irq_agent->sa_home, rel);
5869 }
5870
5871 irq->irq_home = NULL((void*)0);
5872
5873 su_free(home, irq);
5874
5875 msg_destroy((msg_t *)home);
5876}
5877
5878/** Queue request to be freed */
5879su_inlinestatic inline
5880void incoming_free_queue(incoming_queue_t *q, nta_incoming_t *irq)
5881{
5882 incoming_cut_off(irq);
5883 incoming_queue(q, irq);
5884}
5885
5886/** Reclaim memory used by queue of requests */
5887static
5888void incoming_reclaim_queued(su_root_magic_t *rm,
5889 su_msg_r msg,
5890 union sm_arg_u *u)
5891{
5892 incoming_queue_t *q = u->a_incoming_queue;
5893 nta_incoming_t *irq, *irq_next;
5894
5895 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__
, 5896, "incoming_reclaim_all(%p, %p, %p)\n", (void *)rm, (void
*)msg, (void *)u)) : (void)0)
5896 (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__
, 5896, "incoming_reclaim_all(%p, %p, %p)\n", (void *)rm, (void
*)msg, (void *)u)) : (void)0)
;
5897
5898 for (irq = q->q_head; irq; irq = irq_next) {
5899 irq_next = irq->irq_next;
5900 incoming_reclaim(irq);
5901 }
5902}
5903
5904/**Bind a callback and context to an incoming transaction object
5905 *
5906 * Set the callback function and context pointer attached to an incoming
5907 * request object. The callback function will be invoked if the incoming
5908 * request is cancelled, or if the final response to an incoming @b INVITE
5909 * request has been acknowledged.
5910 *
5911 * If the callback is NULL, or no callback has been bound, NTA invokes the
5912 * request callback of the call leg.
5913 *
5914 * @param irq incoming transaction
5915 * @param callback callback function
5916 * @param magic application context
5917 */
5918void nta_incoming_bind(nta_incoming_t *irq,
5919 nta_ack_cancel_f *callback,
5920 nta_incoming_magic_t *magic)
5921{
5922 if (irq) {
5923 irq->irq_callback = callback;
5924 irq->irq_magic = magic;
5925 }
5926}
5927
5928/** Add a @To tag to incoming request if needed.
5929 *
5930 * If @a tag is NULL, a new tag is generated.
5931 */
5932char const *nta_incoming_tag(nta_incoming_t *irq, char const *tag)
5933{
5934 if (!irq)
5935 return su_seterrno(EFAULT14), NULL((void*)0);
5936
5937 if (irq->irq_default)
5938 return su_seterrno(EINVAL22), NULL((void*)0);
5939
5940 if (tag && strchr(tag, '='))
5941 tag = strchr(tag, '=') + 1;
5942
5943 if (tag && irq->irq_tag && !su_casematch(tag, irq->irq_tag))
5944 return NULL((void*)0);
5945
5946 if (!irq->irq_tag) {
5947 if (tag)
5948 tag = su_strdup(irq->irq_home, tag);
5949 else
5950 tag = nta_agent_newtag(irq->irq_home, NULL((void*)0), irq->irq_agent);
5951
5952 if (!tag)
5953 return tag;
5954
5955 irq->irq_tag = tag;
5956 irq->irq_tag_set = 1;
5957 }
5958
5959 return irq->irq_tag;
5960}
5961
5962
5963/**Get request message.
5964 *
5965 * Retrieve the incoming request message of the incoming transaction. Note
5966 * that the message is not copied, but a new reference to it is created.
5967 *
5968 * @param irq incoming transaction handle
5969 *
5970 * @retval
5971 * A pointer to request message is returned.
5972 */
5973msg_t *nta_incoming_getrequest(nta_incoming_t *irq)
5974{
5975 msg_t *msg = NULL((void*)0);
5976
5977 if (irq && !irq->irq_default)
5978 msg = msg_ref_create(irq->irq_request);
5979
5980 return msg;
5981}
5982
5983/**Get ACK or CANCEL message.
5984 *
5985 * Retrieve the incoming ACK or CANCEL request message of the incoming
5986 * transaction. Note that the ACK or CANCEL message is not copied, but a new
5987 * reference to it is created.
5988 *
5989 * @param irq incoming transaction handle
5990 *
5991 * @retval A pointer to request message is returned, or NULL if there is no
5992 * CANCEL or ACK received.
5993 */
5994msg_t *nta_incoming_getrequest_ackcancel(nta_incoming_t *irq)
5995{
5996 msg_t *msg = NULL((void*)0);
5997
5998 if (irq && irq->irq_request2)
5999 msg = msg_ref_create(irq->irq_request2);
6000
6001 return msg;
6002}
6003
6004/**Get response message.
6005 *
6006 * Retrieve the response message latest sent by the server transaction. Note
6007 * that the message is not copied, but a new reference to it is created. Use
6008 * msg_dup() or msg_copy() to make a copy of it.
6009 *
6010 * @param irq incoming transaction handle
6011 *
6012 * @retval
6013 * A pointer to a response message is returned.
6014 */
6015msg_t *nta_incoming_getresponse(nta_incoming_t *irq)
6016{
6017 msg_t *msg = NULL((void*)0);
6018
6019 if (irq && irq->irq_response)
6020 msg = msg_ref_create(irq->irq_response);
6021
6022 return msg;
6023}
6024
6025/** Get method of a server transaction. */
6026sip_method_t nta_incoming_method(nta_incoming_t const *irq)
6027{
6028 return irq ? irq->irq_method : sip_method_invalid;
6029}
6030
6031/** Get method name of a server transaction. */
6032char const *nta_incoming_method_name(nta_incoming_t const *irq)
6033{
6034 if (irq == NULL((void*)0))
6035 return NULL((void*)0);
6036 else if (irq->irq_rq)
6037 return irq->irq_rq->rq_method_name;
6038 else
6039 return "*";
6040}
6041
6042/** Get Request-URI of a server transaction */
6043url_t const *nta_incoming_url(nta_incoming_t const *irq)
6044{
6045 return irq && irq->irq_rq ? irq->irq_rq->rq_url : NULL((void*)0);
6046}
6047
6048/** Get sequence number of a server transaction.
6049 */
6050uint32_t nta_incoming_cseq(nta_incoming_t const *irq)
6051{
6052 return irq && irq->irq_cseq ? irq->irq_cseq->cs_seq : 0;
6053}
6054
6055/** Get local tag for incoming request */
6056char const *nta_incoming_gettag(nta_incoming_t const *irq)
6057{
6058 return irq ? irq->irq_tag : 0;
6059}
6060
6061/**
6062 * Get status code of a server transaction.
6063 */
6064int nta_incoming_status(nta_incoming_t const *irq)
6065{
6066 return irq ? irq->irq_status : 400;
6067}
6068
6069/** Get application context for a server transaction.
6070 *
6071 * @param irq server transaction
6072 * @param callback callback pointer
6073 *
6074 * Return the application context bound to the server transaction. If the @a
6075 * callback function pointer is given, return application context only if
6076 * the callback matches with the callback bound to the server transaction.
6077 *
6078 */
6079nta_incoming_magic_t *nta_incoming_magic(nta_incoming_t *irq,
6080 nta_ack_cancel_f *callback)
6081{
6082 return irq && (callback == NULL((void*)0) || irq->irq_callback == callback)
6083 ? irq->irq_magic : NULL((void*)0);
6084}
6085
6086/** When received.
6087 *
6088 * Return timestamp from the reception of the initial request.
6089 *
6090 * @NEW_1_12_7.
6091 */
6092sip_time_t nta_incoming_received(nta_incoming_t *irq,
6093 su_nanotime_t *return_nano)
6094{
6095 su_time_t tv = { 0, 0 };
6096
6097 if (irq)
6098 tv = irq->irq_received;
6099
6100 if (return_nano)
6101 *return_nano = (su_nanotime_t)tv.tv_sec * 1000000000 + tv.tv_usec * 1000;
6102
6103 return tv.tv_sec;
6104}
6105
6106/** Find incoming transaction. */
6107nta_incoming_t *nta_incoming_find(nta_agent_t const *agent,
6108 sip_t const *sip,
6109 sip_via_t const *v)
6110{
6111 if (agent && sip && v)
6112 return incoming_find(agent, sip, v, NULL((void*)0), NULL((void*)0), NULL((void*)0));
6113 else
6114 return NULL((void*)0);
6115}
6116
6117/** Find a matching server transaction object.
6118 *
6119 * Check also for requests to merge, to ACK, or to CANCEL.
6120 */
6121static nta_incoming_t *incoming_find(nta_agent_t const *agent,
6122 sip_t const *sip,
6123 sip_via_t const *v,
6124 nta_incoming_t **return_merge,
6125 nta_incoming_t **return_ack,
6126 nta_incoming_t **return_cancel)
6127{
6128 sip_cseq_t const *cseq = sip->sip_cseq;
6129 sip_call_id_t const *i = sip->sip_call_id;
6130 sip_to_t const *to = sip->sip_to;
6131 sip_from_t const *from = sip->sip_from;
6132 sip_request_t *rq = sip->sip_request;
6133 incoming_htable_t const *iht = agent->sa_incoming;
6134 hash_value_t hash = NTA_HASH(i, cseq->cs_seq)((i)->i_hash + 26839U * (uint32_t)(cseq->cs_seq));
6135 char const *magic_branch;
6136
6137 nta_incoming_t **ii, *irq;
6138
6139 int is_uas_ack = return_ack && agent->sa_is_a_uas;
6140
6141 if (v->v_branch && su_casenmatch(v->v_branch, "z9hG4bK", 7))
6142 magic_branch = v->v_branch + 7;
6143 else
6144 magic_branch = NULL((void*)0);
6145
6146 for (ii = incoming_htable_hash(iht, hash);
6147 (irq = *ii);
6148 ii = incoming_htable_next(iht, ii)) {
6149 if (hash != irq->irq_hash ||
6150 irq->irq_call_id->i_hash != i->i_hash ||
6151 strcmp(irq->irq_call_id->i_id, i->i_id))
6152 continue;
6153 if (irq->irq_cseq->cs_seq != cseq->cs_seq)
6154 continue;
6155 if (su_strcasecmp(irq->irq_from->a_tag, from->a_tag))
6156 continue;
6157
6158 if (is_uas_ack &&
6159 irq->irq_method == sip_method_invite &&
6160 200 <= irq->irq_status && irq->irq_status < 300 &&
6161 su_casematch(irq->irq_tag, to->a_tag)) {
6162 *return_ack = irq;
6163 return NULL((void*)0);
6164 }
6165
6166 if (magic_branch) {
6167 /* RFC3261 17.2.3:
6168 *
6169 * The request matches a transaction if branch and sent-by in topmost
6170 * the method of the request matches the one that created the
6171 * transaction, except for ACK, where the method of the request
6172 * that created the transaction is INVITE.
6173 */
6174 if (irq->irq_via->v_branch &&
6175 su_casematch(irq->irq_via->v_branch + 7, magic_branch) &&
6176 su_casematch(irq->irq_via->v_host, v->v_host) &&
6177 su_strmatch(irq->irq_via->v_port, v->v_port)) {
6178 if (irq->irq_method == cseq->cs_method &&
6179 strcmp(irq->irq_cseq->cs_method_name,
6180 cseq->cs_method_name) == 0)
6181 return irq;
6182 if (return_ack && irq->irq_method == sip_method_invite)
6183 return *return_ack = irq, NULL((void*)0);
6184 if (return_cancel && irq->irq_method != sip_method_ack)
6185 return *return_cancel = irq, NULL((void*)0);
6186 }
6187 }
6188 else {
6189 /* No magic branch */
6190
6191 /* INVITE request matches a transaction if
6192 the Request-URI, To tag, From tag, Call-ID, CSeq, and
6193 top Via header match */
6194
6195 /* From tag, Call-ID, and CSeq number has been matched above */
6196
6197 /* Match top Via header field */
6198 if (!su_casematch(irq->irq_via->v_branch, v->v_branch) ||
6199 !su_casematch(irq->irq_via->v_host, v->v_host) ||
6200 !su_strmatch(irq->irq_via->v_port, v->v_port))
6201 ;
6202 /* Match Request-URI */
6203 else if (url_cmp(irq->irq_rq->rq_url, rq->rq_url))
6204 ;
6205 else {
6206 /* Match CSeq */
6207 if (irq->irq_method == cseq->cs_method &&
6208 su_strmatch(irq->irq_cseq->cs_method_name, cseq->cs_method_name)) {
6209 /* Match To tag */
6210 if (!su_strcasecmp(irq->irq_to->a_tag, to->a_tag))
6211 return irq; /* found */
6212 }
6213 else if (
6214 /* Tag set by UAS */
6215 su_strcasecmp(irq->irq_tag, to->a_tag) &&
6216 /* Original tag */
6217 su_strcasecmp(irq->irq_to->a_tag, to->a_tag))
6218 ;
6219 else if (return_ack && irq->irq_method == sip_method_invite)
6220 return *return_ack = irq, NULL((void*)0);
6221 else if (return_cancel && irq->irq_method != sip_method_ack)
6222 return *return_cancel = irq, NULL((void*)0);
6223 }
6224 }
6225
6226 /* RFC3261 - section 8.2.2.2 Merged Requests */
6227 if (return_merge) {
6228 if (irq->irq_cseq->cs_method == cseq->cs_method &&
6229 strcmp(irq->irq_cseq->cs_method_name,
6230 cseq->cs_method_name) == 0)
6231 *return_merge = irq, return_merge = NULL((void*)0);
6232 }
6233 }
6234
6235 return NULL((void*)0);
6236}
6237
6238/** Process retransmitted requests. */
6239su_inlinestatic inline
6240int
6241incoming_recv(nta_incoming_t *irq, msg_t *msg, sip_t *sip, tport_t *tport)
6242{
6243 nta_agent_t *agent = irq->irq_agent;
6244
6245 agent->sa_stats->as_recv_retry++;
6246
6247 if (irq->irq_status >= 100) {
6248 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__
, 6249, "nta: re-received %s request, retransmitting %u reply\n"
, sip->sip_request->rq_method_name, irq->irq_status)
) : (void)0)
6249 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__
, 6249, "nta: re-received %s request, retransmitting %u reply\n"
, sip->sip_request->rq_method_name, irq->irq_status)
) : (void)0)
;
6250 incoming_retransmit_reply(irq, tport);
6251 }
6252 else if (irq->irq_agent->sa_extra_100 &&
6253 irq->irq_extra_100) {
6254 /* Agent and Irq configured to answer automatically with 100 Trying */
6255 if (irq->irq_method == sip_method_invite ||
6256 /*
6257 * Send 100 trying to non-invite if at least half of T2 has expired
6258 * since the transaction was created.
6259 */
6260 su_duration(agent_now(irq->irq_agent), irq->irq_received) * 2U >
6261 irq->irq_agent->sa_t2) {
6262 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__
, 6263, "nta: re-received %s request, sending 100 Trying\n", sip
->sip_request->rq_method_name)) : (void)0)
6263 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__
, 6263, "nta: re-received %s request, sending 100 Trying\n", sip
->sip_request->rq_method_name)) : (void)0)
;
6264 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);
6265 }
6266 }
6267
6268 msg_destroy(msg);
6269
6270 return 0;
6271}
6272
6273su_inlinestatic inline
6274int incoming_ack(nta_incoming_t *irq, msg_t *msg, sip_t *sip, tport_t *tport)
6275{
6276 nta_agent_t *agent = irq->irq_agent;
6277
6278 /* Process ACK separately? */
6279 if (irq->irq_status >= 200 && irq->irq_status < 300 && !agent->sa_is_a_uas)
6280 return -1;
6281
6282 if (irq->irq_queue == agent->sa_in.inv_completed) {
6283 if (!irq->irq_confirmed)
6284 agent->sa_stats->as_acked_tr++;
6285
6286 irq->irq_confirmed = 1;
6287 incoming_reset_timer(irq); /* Reset timer G */
6288
6289 if (!irq->irq_reliable_tp) {
6290 incoming_queue(agent->sa_in.inv_confirmed, irq); /* Timer I */
6291 }
6292 else {
6293 irq->irq_terminated = 1;
6294 incoming_queue(agent->sa_in.terminated, irq);
6295 }
6296
6297 if (!irq->irq_destroyed) {
6298 if (!irq->irq_callback) /* Process ACK normally */
6299 return -1;
6300
6301 incoming_call_callback(irq, msg, sip); /* ACK callback */
6302 }
6303 } else if (irq->irq_queue == agent->sa_in.proceeding ||
6304 irq->irq_queue == agent->sa_in.preliminary)
6305 return -1;
6306 else
6307 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", 6308, __extension__ __PRETTY_FUNCTION__); }))
6308 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", 6308, __extension__ __PRETTY_FUNCTION__); }))
;
6309
6310 msg_destroy(msg);
6311
6312 return 0;
6313}
6314
6315/** Respond to the CANCEL. */
6316su_inlinestatic inline
6317int incoming_cancel(nta_incoming_t *irq, msg_t *msg, sip_t *sip,
6318 tport_t *tport)
6319{
6320 nta_agent_t *agent = irq->irq_agent;
6321
6322 /* According to the RFC 3261, this INVITE has been destroyed */
6323 if (irq->irq_method == sip_method_invite &&
6324 200 <= irq->irq_status && irq->irq_status < 300) {
6325 mreply(agent, NULL((void*)0), SIP_481_NO_TRANSACTION481, sip_481_No_transaction, msg,
6326 tport, 0, 0, NULL((void*)0),
6327 TAG_END()(tag_type_t)0, (tag_value_t)0);
6328 return 0;
6329 }
6330
6331 /* UAS MUST use same tag in final response to CANCEL and INVITE */
6332 if (agent->sa_is_a_uas && irq->irq_tag == NULL((void*)0)) {
6333 nta_incoming_tag(irq, NULL((void*)0));
6334 }
6335
6336 mreply(agent, NULL((void*)0), SIP_200_OK200, sip_200_OK, msg_ref_create(msg),
6337 tport, 0, 0, irq->irq_tag,
6338 TAG_END()(tag_type_t)0, (tag_value_t)0);
6339
6340 /* We have already sent final response */
6341 if (irq->irq_completed || irq->irq_method != sip_method_invite) {
6342 msg_destroy(msg);
6343 return 0;
6344 }
6345
6346 if (!irq->irq_canceled) {
6347 irq->irq_canceled = 1;
6348 agent->sa_stats->as_canceled_tr++;
6349 irq = incoming_call_callback(irq, msg, sip);
6350 }
6351
6352 if (irq && !irq->irq_completed && agent->sa_cancel_487)
6353 /* Respond to the cancelled request */
6354 nta_incoming_treply(irq, SIP_487_REQUEST_CANCELLED487, sip_487_Request_terminated, TAG_END()(tag_type_t)0, (tag_value_t)0);
6355
6356 msg_destroy(msg);
6357
6358 return 0;
6359}
6360
6361/** Merge request */
6362static
6363void request_merge(nta_agent_t *agent,
6364 msg_t *msg, sip_t *sip, tport_t *tport,
6365 char const *to_tag)
6366{
6367 nta_incoming_t *irq;
6368
6369 agent->sa_stats->as_merged_request++;
6370
6371 irq = incoming_create(agent, msg, sip, tport, to_tag);
6372
6373 if (irq) {
6374 nta_incoming_treply(irq, 482, "Request merged", TAG_END()(tag_type_t)0, (tag_value_t)0);
6375 nta_incoming_destroy(irq);
6376 } else {
6377 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__
, 6378, "nta: request_merge(): cannot create transaction for %s\n"
, sip->sip_request->rq_method_name)) : (void)0)
6378 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__
, 6378, "nta: request_merge(): cannot create transaction for %s\n"
, sip->sip_request->rq_method_name)) : (void)0)
;
6379 mreply(agent, NULL((void*)0), 482, "Request merged", msg,
6380 tport, 0, 0, NULL((void*)0),
6381 TAG_END()(tag_type_t)0, (tag_value_t)0);
6382 }
6383}
6384
6385/**@typedef nta_ack_cancel_f
6386 *
6387 * Callback function prototype for CANCELed/ACKed requests
6388 *
6389 * This is a callback function is invoked by NTA when an incoming request
6390 * has been cancelled or an response to an incoming INVITE request has been
6391 * acknowledged.
6392 *
6393 * @param magic incoming request context
6394 * @param ireq incoming request
6395 * @param sip ACK/CANCEL message
6396 *
6397 * @retval 0
6398 * This callback function should return always 0.
6399 */
6400
6401/** Call callback of incoming transaction */
6402su_inlinestatic inline
6403nta_incoming_t *
6404incoming_call_callback(nta_incoming_t *irq, msg_t *msg, sip_t *sip)
6405{
6406 if (irq->irq_callback) {
6407 irq->irq_in_callback = 1;
6408 irq->irq_request2 = msg;
6409 irq->irq_callback(irq->irq_magic, irq, sip);
6410 irq->irq_request2 = NULL((void*)0);
6411 irq->irq_in_callback = 0;
6412
6413 if (irq->irq_terminated && irq->irq_destroyed)
6414 incoming_free(irq), irq = NULL((void*)0);
6415 }
6416 return irq;
6417}
6418
6419/**Set server transaction parameters.
6420 *
6421 * Sets the server transaction parameters. Among others, parameters determine the way
6422 * the SigComp compression is handled.
6423 *
6424 * @TAGS
6425 * NTATAG_COMP(), NTATAG_SIGCOMP_CLOSE() and NTATAG_EXTRA_100().
6426 *
6427 * @retval number of set parameters when succesful
6428 * @retval -1 upon an error
6429 */
6430int nta_incoming_set_params(nta_incoming_t *irq,
6431 tag_type_t tag, tag_value_t value, ...)
6432{
6433 int retval = -1;
6434
6435 if (irq) {
6436 ta_list ta;
6437 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)
;
6438 retval = incoming_set_params(irq, ta_args(ta)(ta).tl);
6439 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))
;
6440 }
6441 else {
6442 su_seterrno(EINVAL22);
6443 }
6444
6445 return retval;
6446}
6447
6448static
6449int incoming_set_params(nta_incoming_t *irq, tagi_t const *tags)
6450{
6451 int retval = 0;
6452
6453 tagi_t const *t;
6454 char const *comp = NONE((void *)-1);
6455 struct sigcomp_compartment *cc = NONE((void *)-1);
6456
6457 if (irq->irq_default)
6458 return retval;
6459
6460 for (t = tags; t; t = tl_next(t)) {
6461 tag_type_t tt = t->t_tag;
6462
6463 if (ntatag_comp == tt)
6464 comp = (char const *)t->t_value, retval++;
6465
6466 else if (ntatag_sigcomp_close == tt)
6467 irq->irq_sigcomp_zap = t->t_value != 0, retval++;
6468
6469 else if (tptag_compartment == tt)
6470 cc = (void *)t->t_value, retval++;
6471
6472 else if (ntatag_extra_100 == tt)
6473 irq->irq_extra_100 = t->t_value != 0, retval++;
6474 }
6475
6476 if (cc != NONE((void *)-1)) {
6477 if (cc)
6478 agent_accept_compressed(irq->irq_agent, irq->irq_request, cc);
6479 if (irq->irq_cc)
6480 nta_compartment_decref(&irq->irq_cc);
6481 irq->irq_cc = nta_compartment_ref(cc);
6482 }
6483 else if (comp != NULL((void*)0) && comp != NONE((void *)-1) && irq->irq_cc == NULL((void*)0)) {
6484 incoming_set_compartment(irq, irq->irq_tport, irq->irq_request, 1);
6485 }
6486
6487 else if (comp == NULL((void*)0)) {
6488 irq->irq_tpn->tpn_comp = NULL((void*)0);
6489 }
6490
6491 return retval;
6492}
6493
6494su_inlinestatic inline
6495int incoming_set_compartment(nta_incoming_t *irq, tport_t *tport, msg_t *msg,
6496 int create_if_needed)
6497{
6498 if (!nta_compressor_vtable)
6499 return 0;
6500
6501 if (irq->irq_cc == NULL((void*)0)
6502 || irq->irq_tpn->tpn_comp
6503 || tport_delivered_with_comp(tport, msg, NULL((void*)0)) != -1) {
6504 struct sigcomp_compartment *cc;
6505
6506 cc = agent_compression_compartment(irq->irq_agent, tport, irq->irq_tpn,
6507 create_if_needed);
6508
6509 if (cc)
6510 agent_accept_compressed(irq->irq_agent, msg, cc);
6511
6512 irq->irq_cc = cc;
6513 }
6514
6515 return 0;
6516}
6517
6518/** Add essential headers to the response message */
6519static int nta_incoming_response_headers(nta_incoming_t *irq,
6520 msg_t *msg,
6521 sip_t *sip)
6522{
6523 int clone = 0;
6524 su_home_t *home = msg_home(msg)((su_home_t*)(msg));
6525
6526 if (!sip->sip_from)
6527 clone = 1, sip->sip_from = sip_from_copy(home, irq->irq_from);
6528 if (!sip->sip_to)
6529 clone = 1, sip->sip_to = sip_to_copy(home, irq->irq_to);
6530 if (!sip->sip_call_id)
6531 clone = 1, sip->sip_call_id = sip_call_id_copy(home, irq->irq_call_id);
6532 if (!sip->sip_cseq)
6533 clone = 1, sip->sip_cseq = sip_cseq_copy(home, irq->irq_cseq);
6534 if (!sip->sip_via) {
6535 clone = 1;
6536 /* 100 responses are not forwarded by proxies, so only include the topmost Via header */
6537 if (sip->sip_status && sip->sip_status->st_status == 100)
6538 sip->sip_via = (sip_via_t *)msg_header_copy_one(home, (msg_header_t const *)irq->irq_via);
6539 else
6540 sip->sip_via = sip_via_copy(home, irq->irq_via);
6541 }
6542
6543 if (clone)
6544 msg_set_parent(msg, (msg_t *)irq->irq_home);
6545
6546 if (!sip->sip_from || !sip->sip_to || !sip->sip_call_id || !sip->sip_cseq || !sip->sip_via)
6547 return -1;
6548
6549 return 0;
6550}
6551
6552/** Complete a response message.
6553 *
6554 * @param irq server transaction object
6555 * @param msg response message to be completed
6556 * @param status status code (in range 100 - 699)
6557 * @param phrase status phrase (may be NULL)
6558 * @param tag,value,... taged argument list
6559 *
6560 * Generate status structure based on @a status and @a phrase.
6561 * Add essential headers to the response message:
6562 * @From, @To, @CallID, @CSeq, @Via, and optionally
6563 * @RecordRoute.
6564 */
6565int nta_incoming_complete_response(nta_incoming_t *irq,
6566 msg_t *msg,
6567 int status,
6568 char const *phrase,
6569 tag_type_t tag, tag_value_t value, ...)
6570{
6571 su_home_t *home = msg_home(msg)((su_home_t*)(msg));
6572 sip_t *sip = sip_object(msg);
6573 int retval;
6574 ta_list ta;
6575
6576 if (irq == NULL((void*)0) || sip == NULL((void*)0))
6577 return su_seterrno(EFAULT14), -1;
6578
6579 if (status != 0 && (status < 100 || status > 699))
6580 return su_seterrno(EINVAL22), -1;
6581
6582 if (status != 0 && !sip->sip_status)
6583 sip->sip_status = sip_status_create(home, status, phrase, NULL((void*)0));
6584
6585 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)
;
6586 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
);
6587 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))
;
6588
6589 if (retval < 0)
6590 return -1;
6591
6592 if (irq->irq_default)
6593 return sip_complete_message(msg);
6594
6595 if (status > 100 && !irq->irq_tag) {
6596 if (sip->sip_to)
6597 nta_incoming_tag(irq, sip->sip_to->a_tag);
6598 else
6599 nta_incoming_tag(irq, NULL((void*)0));
6600 }
6601
6602 if (nta_incoming_response_headers(irq, msg, sip) < 0)
6603 return -1;
6604
6605 if (sip->sip_status && sip->sip_status->st_status > 100 &&
6606 irq->irq_tag && sip->sip_to && !sip->sip_to->a_tag)
6607 if (sip_to_tag(home, sip->sip_to, irq->irq_tag) < 0)
6608 return -1;
6609
6610 if (status > 100 && status < 300 && !sip->sip_record_route && irq->irq_record_route)
6611 if (sip_add_dup(msg, sip, (sip_header_t *)irq->irq_record_route) < 0)
6612 return -1;
6613
6614 return sip_complete_message(msg);
6615}
6616
6617
6618/** Create a response message for request.
6619 *
6620 * @NEW_1_12_5.
6621 */
6622msg_t *nta_incoming_create_response(nta_incoming_t *irq,
6623 int status, char const *phrase)
6624{
6625 msg_t *msg = NULL((void*)0);
6626 sip_t *sip;
6627
6628 if (irq) {
6629 msg = nta_msg_create(irq->irq_agent, 0);
6630 sip = sip_object(msg);
6631
6632 if (sip) {
6633 if (status != 0)
6634 sip->sip_status = sip_status_create(msg_home(msg)((su_home_t*)(msg)), status, phrase, NULL((void*)0));
6635
6636 if (nta_incoming_response_headers(irq, msg, sip) < 0)
6637 msg_destroy(msg), msg = NULL((void*)0);
6638 }
6639 }
6640
6641 return msg;
6642}
6643
6644
6645/**Reply to an incoming transaction request.
6646 *
6647 * This function creates a response message to an incoming request and sends
6648 * it to the client.
6649 *
6650 * @note
6651 * It is possible to send several non-final (1xx) responses, but only one
6652 * final response.
6653 *
6654 * @param irq incoming request
6655 * @param status status code
6656 * @param phrase status phrase (may be NULL if status code is well-known)
6657 * @param tag,value,... optional additional headers terminated by TAG_END()
6658 *
6659 * @retval 0 when succesful
6660 * @retval -1 upon an error
6661 */
6662int nta_incoming_treply(nta_incoming_t *irq,
6663 int status,
6664 char const *phrase,
6665 tag_type_t tag, tag_value_t value, ...)
6666{
6667 int retval = -1;
6668
6669 if (irq &&
1
Assuming 'irq' is non-null
6670 (irq->irq_status < 200 || status < 200 ||
2
Assuming field 'irq_status' is < 200
6671 (irq->irq_method == sip_method_invite && status < 300))) {
6672 ta_list ta;
6673 msg_t *msg = nta_msg_create(irq->irq_agent, 0);
6674
6675 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)
;
3
Assuming 'ta_start__tag' is not equal to 'tag_next'
4
Assuming 'ta_start__tag' is equal to null
5
Loop condition is false. Exiting loop
6676
6677 if (!msg
5.1
'msg' is null
)
6
Taking true branch
6678 ;
6679 else if (nta_incoming_complete_response(irq, msg, status, phrase,
6680 ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
) < 0)
6681 msg_destroy(msg);
6682 else if (incoming_set_params(irq, ta_args(ta)(ta).tl) < 0)
6683 msg_destroy(msg);
6684 else
6685 retval = nta_incoming_mreply(irq, msg);
6686
6687 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))
;
7
'?' condition is false
6688
6689 if (retval
7.1
'retval' is < 0
< 0 && status >= 200)
8
Assuming 'status' is >= 200
9
Taking true branch
6690 incoming_final_failed(irq, NULL((void*)0));
10
Calling 'incoming_final_failed'
6691 }
6692
6693 return retval;
6694}
6695
6696/**
6697 * Return a response message to client.
6698 *
6699 * @note
6700 * The ownership of @a msg is taken over by the function even if the
6701 * function fails.
6702 *
6703 * @retval 0 when succesful
6704 * @retval -1 upon an error
6705 */
6706int nta_incoming_mreply(nta_incoming_t *irq, msg_t *msg)
6707{
6708 sip_t *sip = sip_object(msg);
6709
6710 int status;
6711
6712 if (irq == NULL((void*)0)) {
6713 msg_destroy(msg);
6714 return -1;
6715 }
6716
6717 if (msg == NULL((void*)0) || sip == NULL((void*)0))
6718 return -1;
6719
6720 if (msg == irq->irq_response)
6721 return 0;
6722
6723 if (!sip->sip_status || !sip->sip_via || !sip->sip_cseq)
6724 return incoming_final_failed(irq, msg);
6725
6726 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", 6726, __extension__ __PRETTY_FUNCTION__); }))
;
6727
6728 status = sip->sip_status->st_status;
6729
6730 if (!irq->irq_tag && status > 100 && !irq->irq_default)
6731 nta_incoming_tag(irq, NULL((void*)0));
6732
6733 if (/* (irq->irq_confirmed && status >= 200) || */
6734 (irq->irq_completed && status >= 300)) {
6735 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__
, 6736, "%s: already %s transaction\n", __func__, irq->irq_confirmed
? "confirmed" : "completed")) : (void)0)
6736 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__
, 6736, "%s: already %s transaction\n", __func__, irq->irq_confirmed
? "confirmed" : "completed")) : (void)0)
;
6737 msg_destroy(msg);
6738 return -1;
6739 }
6740
6741#ifdef HAVE_ZLIB_COMPRESS1
6742 if (irq->irq_compressed) {
6743 sip_content_encoding_Xflate(msg, sip, 0, 0);
6744 }
6745#endif
6746
6747 if (irq->irq_must_100rel && !sip->sip_rseq && status > 100 && status < 200) {
6748 /* This nta_reliable_t object will be destroyed by PRACK or timeout */
6749 if (nta_reliable_mreply(irq, NULL((void*)0), NULL((void*)0), msg))
6750 return 0;
6751
6752 return -1;
6753 }
6754
6755 if (status >= 200 && irq->irq_reliable && irq->irq_reliable->rel_unsent) {
6756 if (reliable_final(irq, msg, sip) == 0)
6757 return 0;
6758 }
6759
6760 return incoming_reply(irq, msg, sip);
6761}
6762
6763
6764
6765/** Send the response message.
6766 *
6767 * @note The ownership of msg is handled to incoming_reply().
6768 */
6769int incoming_reply(nta_incoming_t *irq, msg_t *msg, sip_t *sip)
6770{
6771 nta_agent_t *agent = irq->irq_agent;
6772 int status = sip->sip_status->st_status;
6773 int sending = 1;
6774 int *use_rport = NULL((void*)0);
6775 int retry_without_rport = 0;
6776 tp_name_t *tpn, default_tpn[1];
6777
6778 if (status == 408 &&
6779 irq->irq_method != sip_method_invite &&
6780 !agent->sa_pass_408 &&
6781 !irq->irq_default) {
6782 /* RFC 4320 nit-actions-03 Action 2:
6783
6784 A transaction-stateful SIP element MUST NOT send a response with
6785 Status-Code of 408 to a non-INVITE request. As a consequence, an
6786 element that can not respond before the transaction expires will not
6787 send a final response at all.
6788 */
6789 sending = 0;
6790 }
6791
6792 if (irq->irq_status == 0 && irq->irq_timestamp && !sip->sip_timestamp)
6793 incoming_timestamp(irq, msg, sip);
6794
6795 if (irq->irq_default) {
6796 if (agent->sa_server_rport)
6797 use_rport = &retry_without_rport, retry_without_rport = 1;
6798 tpn = default_tpn;
6799 if (nta_tpn_by_via(tpn, sip->sip_via, use_rport) < 0)
6800 tpn = NULL((void*)0);
6801 }
6802 else {
6803 tpn = irq->irq_tpn;
6804 }
6805
6806 if (sip_complete_message(msg) < 0)
6807 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__
, 6807, "%s: sip_complete_message() failed\n", __func__)) : (
void)0)
;
6808 else if (msg_serialize(msg, (msg_pub_t *)sip) < 0)
6809 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__
, 6809, "%s: sip_serialize() failed\n", __func__)) : (void)0)
;
6810 else if (!(irq->irq_tport) &&
6811 !(tport_decref(&irq->irq_tport),
6812 irq->irq_tport = tpn ? tport_by_name(agent->sa_tports, tpn) : 0))
6813 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__
, 6813, "%s: no tport\n", __func__)) : (void)0)
;
6814 else {
6815 int i, err = 0;
6816 tport_t *tp = NULL((void*)0);
6817 incoming_queue_t *queue;
6818
6819 char const *method_name;
6820 uint32_t cseq;
6821
6822 if (irq->irq_default) {
6823 assert(sip->sip_cseq)((void) sizeof ((sip->sip_cseq) ? 1 : 0), __extension__ ({
if (sip->sip_cseq) ; else __assert_fail ("sip->sip_cseq"
, "nta.c", 6823, __extension__ __PRETTY_FUNCTION__); }))
;
6824 method_name = sip->sip_cseq->cs_method_name, cseq = sip->sip_cseq->cs_seq;
6825 }
6826 else {
6827 method_name = irq->irq_rq->rq_method_name, cseq = irq->irq_cseq->cs_seq;
6828 }
6829
6830 if (sending) {
6831 for (i = 0; i < 3; i++) {
6832 tp = tport_tsend(irq->irq_tport, msg, tpn,
6833 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)),
6834 TPTAG_MTU(INT_MAX)tptag_mtu, tag_usize_v((2147483647)),
6835 TAG_END()(tag_type_t)0, (tag_value_t)0);
6836 if (tp)
6837 break;
6838
6839 err = msg_errno(msg);
6840 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__
, 6842, "%s: tport_tsend: %s%s\n", __func__, su_strerror(err)
, err == 32 ? "(retrying)" : "")) : (void)0)
6841 __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__
, 6842, "%s: tport_tsend: %s%s\n", __func__, su_strerror(err)
, err == 32 ? "(retrying)" : "")) : (void)0)
6842 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__
, 6842, "%s: tport_tsend: %s%s\n", __func__, su_strerror(err)
, err == 32 ? "(retrying)" : "")) : (void)0)
;
6843
6844 if (err != EPIPE32 && err != ECONNREFUSED111)
6845 break;
6846 tport_decref(&irq->irq_tport);
6847 irq->irq_tport = tport_ref(tport_by_name(agent->sa_tports, tpn));
6848 }
6849
6850 if (!tp) {
6851 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__
, 6854, "%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)
6852 "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__
, 6854, "%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)
6853 __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__
, 6854, "%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)
6854 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__
, 6854, "%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)
;
6855 if (status < 200)
6856 msg_destroy(msg);
6857 else
6858 incoming_final_failed(irq, msg);
6859 return 0;
6860 }
6861
6862 agent->sa_stats->as_sent_msg++;
6863 agent->sa_stats->as_sent_response++;
6864 }
6865
6866 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__
, 6868, "nta: %s %u %s for %s (%u)\n", sending ? "sent" : "not sending"
, status, sip->sip_status->st_phrase, method_name, cseq
)) : (void)0)
6867 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__
, 6868, "nta: %s %u %s for %s (%u)\n", sending ? "sent" : "not sending"
, status, sip->sip_status->st_phrase, method_name, cseq
)) : (void)0)
6868 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__
, 6868, "nta: %s %u %s for %s (%u)\n", sending ? "sent" : "not sending"
, status, sip->sip_status->st_phrase, method_name, cseq
)) : (void)0)
;
6869
6870 if (irq->irq_default) {
6871 msg_destroy(msg);
6872 return 0;
6873 }
6874
6875 incoming_reset_timer(irq);
6876
6877 if (status < 200) {
6878 queue = agent->sa_in.proceeding;
6879
6880 if (irq->irq_method == sip_method_invite && status > 100 &&
6881 agent->sa_progress != UINT_MAX(2147483647 *2U +1U) && agent->sa_is_a_uas) {
6882 /* Retransmit preliminary responses in regular intervals */
6883 incoming_set_timer(irq, agent->sa_progress); /* N2 */
6884 }
6885 }
6886 else {
6887 irq->irq_completed = 1;
6888
6889 /* XXX - we should do this only after message has actually been sent! */
6890 if (irq->irq_sigcomp_zap && irq->irq_cc)
6891 agent_close_compressor(irq->irq_agent, irq->irq_cc);
6892
6893 if (irq->irq_method != sip_method_invite) {
6894 irq->irq_confirmed = 1;
6895
6896 if (irq->irq_reliable_tp) {
6897 irq->irq_terminated = 1;
6898 queue = agent->sa_in.terminated ; /* J - set for 0 seconds */
6899 } else {
6900 queue = agent->sa_in.completed; /* J */
6901 }
6902
6903 tport_decref(&irq->irq_tport);
6904 }
6905 else if (status >= 300 || agent->sa_is_a_uas) {
6906 if (status < 300 || !irq->irq_reliable_tp)
6907 incoming_set_timer(irq, agent->sa_t1); /* G */
6908 queue = agent->sa_in.inv_completed; /* H */
6909 }
6910 else {
6911#if 1
6912 /* Avoid bug in @RFC3261:
6913 Keep INVITE transaction around in order to catch
6914 retransmitted INVITEs
6915 */
6916 irq->irq_confirmed = 1;
6917 queue = agent->sa_in.inv_confirmed; /* H */
6918#else
6919 irq->irq_terminated = 1;
6920 queue = agent->sa_in.terminated;
6921#endif
6922 }
6923 }
6924
6925 if (irq->irq_queue != queue)
6926 incoming_queue(queue, irq);
6927
6928 if (status >= 200 || irq->irq_status < 200) {
6929 if (irq->irq_response)
6930 msg_destroy(irq->irq_response);
6931 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"
, 6931, __extension__ __PRETTY_FUNCTION__); }))
;
6932 irq->irq_response = msg;
6933 }
6934 else {
6935 msg_destroy(msg);
6936 }
6937
6938 if (sip->sip_cseq->cs_method == irq->irq_method &&
6939 irq->irq_status < 200 && status > irq->irq_status)
6940 irq->irq_status = status;
6941
6942 return 0;
6943 }
6944
6945 /*
6946 * XXX - handling error is very problematic.
6947 * Nobody checks return code from nta_incoming_*reply()
6948 */
6949 if (status < 200) {
6950 msg_destroy(msg);
6951 return -1;
6952 }
6953
6954 /* We could not send final response. */
6955 return incoming_final_failed(irq, msg);
6956}
6957
6958
6959/** @internal Sending final response has failed.
6960 *
6961 * Put transaction into its own queue, try later to send the response.
6962 */
6963su_inlinestatic inline
6964int incoming_final_failed(nta_incoming_t *irq, msg_t *msg)
6965{
6966 msg_destroy(msg);
6967
6968 if (!irq->irq_default) {
11
Assuming field 'irq_default' is 0
12
Taking true branch
6969 irq->irq_final_failed = 1;
6970 incoming_queue(irq->irq_agent->sa_in.final_failed, irq);
13
Passing null pointer value via 1st parameter 'queue'
14
Calling 'incoming_queue'
6971 }
6972
6973 return -1;
6974}
6975
6976/** @internal Retransmit the reply */
6977static
6978void incoming_retransmit_reply(nta_incoming_t *irq, tport_t *tport)
6979{
6980 msg_t *msg = NULL((void*)0);
6981
6982 if (irq->irq_final_failed)
6983 return;
6984
6985 if (tport == NULL((void*)0))
6986 tport = irq->irq_tport;
6987
6988 /* Answer with existing reply */
6989 if (irq->irq_reliable && !irq->irq_reliable->rel_pracked)
6990 msg = reliable_response(irq);
6991 else
6992 msg = irq->irq_response;
6993
6994 if (msg && tport) {
6995 irq->irq_retries++;
6996
6997 if (irq->irq_retries == 2 && irq->irq_tpn->tpn_comp) {
6998 irq->irq_tpn->tpn_comp = NULL((void*)0);
6999
7000 if (irq->irq_cc) {
7001 agent_close_compressor(irq->irq_agent, irq->irq_cc);
7002 nta_compartment_decref(&irq->irq_cc);
7003 }
7004 }
7005
7006 tport_tsend(tport, msg, irq->irq_tpn,
7007 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)),
7008 TPTAG_MTU(INT_MAX)tptag_mtu, tag_usize_v((2147483647)), TAG_END()(tag_type_t)0, (tag_value_t)0);
7009 irq->irq_agent->sa_stats->as_sent_msg++;
7010 irq->irq_agent->sa_stats->as_sent_response++;
7011 }
7012}
7013
7014/** @internal Create timestamp header for response */
7015static
7016int incoming_timestamp(nta_incoming_t *irq, msg_t *msg, sip_t *sip)
7017{
7018 sip_timestamp_t ts[1];
7019 su_time_t now = su_now();
7020 char delay[32];
7021 double diff = su_time_diff(now, irq->irq_received);
7022
7023 snprintf(delay, sizeof delay, "%.06f", diff);
7024
7025 *ts = *irq->irq_timestamp;
7026 ts->ts_delay = delay;
7027
7028 return sip_add_dup(msg, sip, (sip_header_t *)ts);
7029}
7030
7031enum {
7032 timer_max_retransmit = 30,
7033 timer_max_terminate = 100000,
7034 timer_max_timeout = 100
7035};
7036
7037/** @internal Timer routine for the incoming request. */
7038static void
7039_nta_incoming_timer(nta_agent_t *sa)
7040{
7041 uint32_t now;
7042 nta_incoming_t *irq, *irq_next;
7043 size_t retransmitted = 0, timeout = 0, terminated = 0, destroyed = 0;
7044 size_t unconfirmed =
7045 sa->sa_in.inv_completed->q_length +
7046 sa->sa_in.preliminary->q_length;
7047 size_t unterminated =
7048 sa->sa_in.inv_confirmed->q_length +
7049 sa->sa_in.completed->q_length;
7050 size_t total = sa->sa_incoming->iht_used;
7051
7052 incoming_queue_t rq[1];
7053
7054 incoming_queue_init(rq, 0);
7055
7056 /* Handle retry queue */
7057 while ((irq = sa->sa_in.re_list)) {
7058
7059 now = su_time_ms(su_now());
7060
7061 if ((int32_t)(irq->irq_retry - now) > 0)
7062 break;
7063 if (retransmitted >= timer_max_retransmit)
7064 break;
7065
7066 if (irq->irq_method == sip_method_invite && irq->irq_status >= 200) {
7067 /* Timer G */
7068 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", 7068, __extension__ __PRETTY_FUNCTION__); }))
;
7069
7070 retransmitted++;
7071
7072 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__
, 7073, "nta: timer %s fired, retransmitting %u reply\n", "G"
, irq->irq_status)) : (void)0)
7073 "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__
, 7073, "nta: timer %s fired, retransmitting %u reply\n", "G"
, irq->irq_status)) : (void)0)
;
7074
7075 incoming_retransmit_reply(irq, irq->irq_tport);
7076
7077 if (2U * irq->irq_interval < sa->sa_t2)
7078 incoming_set_timer(irq, 2U * irq->irq_interval); /* G */
7079 else
7080 incoming_set_timer(irq, sa->sa_t2); /* G */
7081 }
7082 else if (irq->irq_method == sip_method_invite && irq->irq_status >= 100) {
7083 if (irq->irq_queue == sa->sa_in.preliminary) {
7084 /* Timer P1 - PRACK timer */
7085 retransmitted++;
7086 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__
, 7087, "nta: timer %s fired, retransmitting %u reply\n", "P1"
, irq->irq_status)) : (void)0)
7087 "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__
, 7087, "nta: timer %s fired, retransmitting %u reply\n", "P1"
, irq->irq_status)) : (void)0)
;
7088
7089 incoming_retransmit_reply(irq, irq->irq_tport);
7090
7091 incoming_set_timer(irq, 2 * irq->irq_interval); /* P1 */
7092 }
7093 else {
7094 /* Retransmitting provisional responses */
7095 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__
, 7096, "nta: timer %s fired, retransmitting %u reply\n", "N2"
, irq->irq_status)) : (void)0)
7096 "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__
, 7096, "nta: timer %s fired, retransmitting %u reply\n", "N2"
, irq->irq_status)) : (void)0)
;
7097 incoming_set_timer(irq, sa->sa_progress);
7098 retransmitted++;
7099 incoming_retransmit_reply(irq, irq->irq_tport);
7100 }
7101 }
7102 else {
7103 /* Timer N1 */
7104 incoming_reset_timer(irq);
7105
7106 if(irq->irq_extra_100) {
7107 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__
, 7107, "nta: timer N1 fired, sending %u %s\n", 100, sip_100_Trying
)) : (void)0)
;
7108 nta_incoming_treply(irq, SIP_100_TRYING100, sip_100_Trying, TAG_END()(tag_type_t)0, (tag_value_t)0);
7109 }
7110 else {
7111 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__
, 7112, "nta: timer N1 fired, but avoided sending %u %s\n", 100
, sip_100_Trying)) : (void)0)
7112 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__
, 7112, "nta: timer N1 fired, but avoided sending %u %s\n", 100
, sip_100_Trying)) : (void)0)
;
7113 }
7114 }
7115 }
7116
7117 while ((irq = sa->sa_in.final_failed->q_head)) {
7118
7119
7120 incoming_remove(irq);
7121 irq->irq_final_failed = 0;
7122
7123 /* Report error to application */
7124 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__
, 7125, "nta: sending final response failed, timeout %u response\n"
, irq->irq_status)) : (void)0)
7125 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__
, 7125, "nta: sending final response failed, timeout %u response\n"
, irq->irq_status)) : (void)0)
;
7126 reliable_timeout(irq, 0);
7127
7128 nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error, TAG_END()(tag_type_t)0, (tag_value_t)0);
7129
7130 if (!irq->irq_final_failed) /* We have taken care of the error... */
7131 continue;
7132
7133 if (irq->irq_destroyed) {
7134 incoming_free_queue(rq, irq);
7135 continue;
7136 }
7137
7138 incoming_reset_timer(irq);
7139 irq->irq_confirmed = 1;
7140 irq->irq_terminated = 1;
7141 incoming_queue(sa->sa_in.terminated, irq);
7142 }
7143
7144 /* Timeouts.
7145 * For each state the request is in, there is always a queue of its own
7146 */
7147 while ((irq = sa->sa_in.preliminary->q_head)) {
7148 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", 7148, __extension__ __PRETTY_FUNCTION__); }))
;
7149 assert(irq->irq_timeout)((void) sizeof ((irq->irq_timeout) ? 1 : 0), __extension__
({ if (irq->irq_timeout) ; else __assert_fail ("irq->irq_timeout"
, "nta.c", 7149, __extension__ __PRETTY_FUNCTION__); }))
;
7150
7151 now = su_time_ms(su_now());
7152
7153 if ((int32_t)(irq->irq_timeout - now) > 0)
7154 break;
7155 if (timeout >= timer_max_timeout)
7156 break;
7157
7158 timeout++;
7159
7160 /* Timer P2 - PRACK timer */
7161 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__
, 7162, "nta: timer %s fired, %s %u response\n", "P2", "timeout"
, irq->irq_status)) : (void)0)
7162 "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__
, 7162, "nta: timer %s fired, %s %u response\n", "P2", "timeout"
, irq->irq_status)) : (void)0)
;
7163 incoming_reset_timer(irq);
7164 irq->irq_timeout = 0;
7165 reliable_timeout(irq, 1);
7166 }
7167
7168 while ((irq = sa->sa_in.inv_completed->q_head)) {
7169 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", 7169, __extension__ __PRETTY_FUNCTION__); }))
;
7170 assert(irq->irq_timeout)((void) sizeof ((irq->irq_timeout) ? 1 : 0), __extension__
({ if (irq->irq_timeout) ; else __assert_fail ("irq->irq_timeout"
, "nta.c", 7170, __extension__ __PRETTY_FUNCTION__); }))
;
7171 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", 7171, __extension__ __PRETTY_FUNCTION__); }))
;
7172
7173 now = su_time_ms(su_now());
7174
7175 if ((int32_t)(irq->irq_timeout - now) > 0 ||
7176 timeout >= timer_max_timeout ||
7177 terminated >= timer_max_terminate)
7178 break;
7179
7180 /* Timer H */
7181 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__
, 7182, "nta: timer %s fired, %s %u response\n", "H", "timeout and terminate"
, irq->irq_status)) : (void)0)
7182 "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__
, 7182, "nta: timer %s fired, %s %u response\n", "H", "timeout and terminate"
, irq->irq_status)) : (void)0)
;
7183 irq->irq_confirmed = 1;
7184 irq->irq_terminated = 1;
7185 incoming_reset_timer(irq);
7186 if (!irq->irq_destroyed) {
7187 timeout++;
7188 incoming_queue(sa->sa_in.terminated, irq);
7189 /* report timeout error to user */
7190 incoming_call_callback(irq, NULL((void*)0), NULL((void*)0));
7191 } else {
7192 timeout++;
7193 terminated++;
7194 incoming_free_queue(rq, irq);
7195 }
7196 }
7197
7198 while ((irq = sa->sa_in.inv_confirmed->q_head)) {
7199 assert(irq->irq_timeout)((void) sizeof ((irq->irq_timeout) ? 1 : 0), __extension__
({ if (irq->irq_timeout) ; else __assert_fail ("irq->irq_timeout"
, "nta.c", 7199, __extension__ __PRETTY_FUNCTION__); }))
;
7200 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", 7200, __extension__ __PRETTY_FUNCTION__); }))
;
7201 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", 7201, __extension__ __PRETTY_FUNCTION__); }))
;
7202
7203 now = su_time_ms(su_now());
7204
7205 if ((int32_t)(irq->irq_timeout - now) > 0 ||
7206 terminated >= timer_max_terminate)
7207 break;
7208
7209 /* Timer I */
7210 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__
, 7211, "nta: timer %s fired, %s %u response\n", "I", "terminate"
, irq->irq_status)) : (void)0)
7211 "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__
, 7211, "nta: timer %s fired, %s %u response\n", "I", "terminate"
, irq->irq_status)) : (void)0)
;
7212
7213 terminated++;
7214 irq->irq_terminated = 1;
7215
7216 if (!irq->irq_destroyed)
7217 incoming_queue(sa->sa_in.terminated, irq);
7218 else
7219 incoming_free_queue(rq, irq);
7220 }
7221
7222 while ((irq = sa->sa_in.completed->q_head)) {
7223 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", 7223, __extension__ __PRETTY_FUNCTION__); }))
;
7224 assert(irq->irq_timeout)((void) sizeof ((irq->irq_timeout) ? 1 : 0), __extension__
({ if (irq->irq_timeout) ; else __assert_fail ("irq->irq_timeout"
, "nta.c", 7224, __extension__ __PRETTY_FUNCTION__); }))
;
7225 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", 7225, __extension__ __PRETTY_FUNCTION__); }))
;
7226
7227 now = su_time_ms(su_now());
7228
7229 if ((int32_t)(irq->irq_timeout - now) > 0 ||
7230 terminated >= timer_max_terminate)
7231 break;
7232
7233 /* Timer J */
7234
7235 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__
, 7236, "nta: timer %s fired, %s %u response\n", "J", "terminate"
, irq->irq_status)) : (void)0)
7236 "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__
, 7236, "nta: timer %s fired, %s %u response\n", "J", "terminate"
, irq->irq_status)) : (void)0)
;
7237
7238 terminated++;
7239 irq->irq_terminated = 1;
7240
7241 if (!irq->irq_destroyed)
7242 incoming_queue(sa->sa_in.terminated, irq);
7243 else
7244 incoming_free_queue(rq, irq);
7245 }
7246
7247 for (irq = sa->sa_in.terminated->q_head; irq; irq = irq_next) {
7248
7249 irq_next = irq->irq_next;
7250 if (irq->irq_destroyed)
7251 incoming_free_queue(rq, irq);
7252 }
7253
7254 destroyed = incoming_mass_destroy(sa, rq);
7255
7256 if (retransmitted || timeout || terminated || destroyed)
7257 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__
, 7265, "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)
7258 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__
, 7265, "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)
7259 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__
, 7265, "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)
7260 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__
, 7265, "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)
7261 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__
, 7265, "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)
7262 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__
, 7265, "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)
7263 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__
, 7265, "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)
7264 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__
, 7265, "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)
7265 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__
, 7265, "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)
;
7266}
7267
7268/** Mass destroy server transactions */
7269su_inlinestatic inline
7270size_t incoming_mass_destroy(nta_agent_t *sa, incoming_queue_t *q)
7271{
7272 size_t destroyed = q->q_length;
7273
7274 if (destroyed > 2 && *sa->sa_terminator) {
7275 su_msg_r m = SU_MSG_R_INIT{ ((void*)0) };
7276
7277 if (su_msg_create(m,
7278 su_clone_task(sa->sa_terminator),
7279 su_root_task(sa->sa_root),
7280 incoming_reclaim_queued,
7281 sizeof(incoming_queue_t)) == SU_SUCCESSsu_success) {
7282 incoming_queue_t *mq = su_msg_data(m)->a_incoming_queue;
7283
7284 *mq = *q;
7285
7286 if (su_msg_send(m) == SU_SUCCESSsu_success)
7287 q->q_length = 0;
7288 }
7289 }
7290
7291 if (q->q_length > 0)
7292 incoming_reclaim_queued(NULL((void*)0), NULL((void*)0), (void *)q);
7293
7294 return destroyed;
7295}
7296
7297/* ====================================================================== */
7298/* 8) Client-side (outgoing) transactions */
7299
7300#define HTABLE_HASH_ORQ(orq)((orq)->orq_hash) ((orq)->orq_hash)
7301
7302#ifdef __clang__1
7303#pragma clang diagnostic push
7304#pragma clang diagnostic ignored "-Wunused-function"
7305#endif
7306
7307HTABLE_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", 7308, __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", 7308
, __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
7308 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", 7308, __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", 7308
, __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
;
7309
7310#ifdef __clang__1
7311#pragma clang diagnostic pop
7312#endif
7313
7314static int outgoing_features(nta_agent_t *agent, nta_outgoing_t *orq,
7315 msg_t *msg, sip_t *sip,
7316 tagi_t *tags);
7317static void outgoing_prepare_send(nta_outgoing_t *orq);
7318static void outgoing_send_via(nta_outgoing_t *orq, tport_t *tp);
7319static void outgoing_send(nta_outgoing_t *orq, int retransmit);
7320static void outgoing_try_tcp_instead(nta_outgoing_t *orq);
7321static void outgoing_try_udp_instead(nta_outgoing_t *orq, int timeout);
7322static void outgoing_tport_error(nta_agent_t *agent, nta_outgoing_t *orq,
7323 tport_t *tp, msg_t *msg, int error);
7324static void outgoing_print_tport_error(nta_outgoing_t *orq,
7325 int level, char *todo,
7326 tp_name_t const *, msg_t *, int error);
7327static void outgoing_insert(nta_agent_t *sa, nta_outgoing_t *orq);
7328static void outgoing_destroy(nta_outgoing_t *orq);
7329su_inlinestatic inline int outgoing_is_queued(nta_outgoing_t const *orq);
7330su_inlinestatic inline void outgoing_queue(outgoing_queue_t *queue,
7331 nta_outgoing_t *orq);
7332su_inlinestatic inline void outgoing_remove(nta_outgoing_t *orq);
7333su_inlinestatic inline void outgoing_set_timer(nta_outgoing_t *orq, uint32_t interval);
7334static void outgoing_reset_timer(nta_outgoing_t *orq);
7335static size_t outgoing_timer_dk(outgoing_queue_t *q,
7336 char const *timer,
7337 uint32_t now);
7338static size_t outgoing_timer_bf(outgoing_queue_t *q,
7339 char const *timer,
7340 uint32_t now);
7341static size_t outgoing_timer_c(outgoing_queue_t *q,
7342 char const *timer,
7343 uint32_t now);
7344
7345static void outgoing_ack(nta_outgoing_t *orq, sip_t *sip);
7346static msg_t *outgoing_ackmsg(nta_outgoing_t *, sip_method_t, char const *,
7347 tag_type_t tag, tag_value_t value, ...);
7348static void outgoing_retransmit(nta_outgoing_t *orq);
7349static void outgoing_trying(nta_outgoing_t *orq);
7350static void outgoing_timeout(nta_outgoing_t *orq, uint32_t now);
7351static int outgoing_complete(nta_outgoing_t *orq);
7352static void outgoing_terminate_invite(nta_outgoing_t *);
7353static void outgoing_remove_fork(nta_outgoing_t *orq);
7354static int outgoing_terminate(nta_outgoing_t *orq);
7355static size_t outgoing_mass_destroy(nta_agent_t *sa, outgoing_queue_t *q);
7356static void outgoing_estimate_delay(nta_outgoing_t *orq, sip_t *sip);
7357static int outgoing_duplicate(nta_outgoing_t *orq,
7358 msg_t *msg,
7359 sip_t *sip);
7360static int outgoing_reply(nta_outgoing_t *orq,
7361 int status, char const *phrase,
7362 int delayed);
7363
7364static int outgoing_default_cb(nta_outgoing_magic_t *magic,
7365 nta_outgoing_t *request,
7366 sip_t const *sip);
7367
7368
7369/** Create a default outgoing transaction.
7370 *
7371 * The default outgoing transaction is used when agent receives responses
7372 * not belonging to any transaction.
7373 *
7374 * @sa nta_leg_default(), nta_incoming_default().
7375 */
7376nta_outgoing_t *nta_outgoing_default(nta_agent_t *agent,
7377 nta_response_f *callback,
7378 nta_outgoing_magic_t *magic)
7379{
7380 nta_outgoing_t *orq;
7381
7382 if (agent == NULL((void*)0))
7383 return NULL((void*)0);
7384
7385 if (agent->sa_default_outgoing)
7386 return NULL((void*)0);
7387
7388 orq = su_zalloc(agent->sa_home, sizeof *orq);
7389 if (!orq)
7390 return NULL((void*)0);
7391
7392 orq->orq_agent = agent;
7393 orq->orq_callback = callback;
7394 orq->orq_magic = magic;
7395 orq->orq_method = sip_method_invalid;
7396 orq->orq_method_name = "*";
7397 orq->orq_default = 1;
7398 orq->orq_stateless = 1;
7399 orq->orq_delay = UINT_MAX(2147483647 *2U +1U);
7400
7401 return agent->sa_default_outgoing = orq;
7402}
7403
7404/**Create an outgoing request and client transaction belonging to the leg.
7405 *
7406 * Create a request message and pass the request message to an outgoing
7407 * client transaction object. The request is sent to the @a route_url (if
7408 * non-NULL), default proxy (if defined by NTATAG_DEFAULT_PROXY()), or to
7409 * the address specified by @a request_uri. If no @a request_uri is
7410 * specified, it is taken from route-set target or from the @To header.
7411 *
7412 * When NTA receives response to the request, it invokes the @a callback
7413 * function.
7414 *
7415 * @param leg call leg object
7416 * @param callback callback function (may be @c NULL)
7417 * @param magic application context pointer
7418 * @param route_url optional URL used to route transaction requests
7419 * @param method method type
7420 * @param name method name
7421 * @param request_uri Request-URI
7422 * @param tag, value, ... list of tagged arguments
7423 *
7424 * @return
7425 * A pointer to a newly created outgoing transaction object if successful,
7426 * and NULL otherwise.
7427 *
7428 * @note If NTATAG_STATELESS(1) tag is given and the @a callback is NULL,
7429 * the transaction object is marked as destroyed from the beginning. In that
7430 * case, the function may return @code (nta_outgoing_t *)-1 @endcode if the
7431 * transaction is freed before returning from the function.
7432 *
7433 * @sa
7434 * nta_outgoing_mcreate(), nta_outgoing_tcancel(), nta_outgoing_destroy().
7435 *
7436 * @TAGS
7437 * NTATAG_STATELESS(), NTATAG_DELAY_SENDING(), NTATAG_BRANCH_KEY(),
7438 * NTATAG_ACK_BRANCH(), NTATAG_DEFAULT_PROXY(), NTATAG_PASS_100(),
7439 * NTATAG_USE_TIMESTAMP(), NTATAG_USER_VIA(), TPTAG_IDENT(), NTATAG_TPORT(). All
7440 * SIP tags from <sofia-sip/sip_tag.h> can be used to manipulate the request message.
7441 * SIP tags after SIPTAG_END() are ignored, however.
7442 */
7443nta_outgoing_t *nta_outgoing_tcreate(nta_leg_t *leg,
7444 nta_response_f *callback,
7445 nta_outgoing_magic_t *magic,
7446 url_string_t const *route_url,
7447 sip_method_t method,
7448 char const *name,
7449 url_string_t const *request_uri,
7450 tag_type_t tag, tag_value_t value, ...)
7451{
7452 nta_agent_t *agent;
7453 msg_t *msg;
7454 sip_t *sip;
7455 nta_outgoing_t *orq = NULL((void*)0);
7456 ta_list ta;
7457 tagi_t const *tagi;
7458
7459 if (leg == NULL((void*)0))
7460 return NULL((void*)0);
7461
7462 agent = leg->leg_agent;
7463 msg = nta_msg_create(agent, 0);
7464 sip = sip_object(msg);
7465
7466 if (route_url == NULL((void*)0))
7467 route_url = (url_string_t *)agent->sa_default_proxy;
7468
7469 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)
;
7470
7471 tagi = ta_args(ta)(ta).tl;
7472
7473 if (sip_add_tagis(msg, sip, &tagi) < 0) {
7474 if (tagi && tagi->t_tag) {
7475 tag_type_t t = tagi->t_tag;
7476 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__
, 7477, "%s(): bad tag %s::%s\n", __func__, t->tt_ns ? t->
tt_ns : "", t->tt_name ? t->tt_name : "")) : (void)0)
7477 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__
, 7477, "%s(): bad tag %s::%s\n", __func__, t->tt_ns ? t->
tt_ns : "", t->tt_name ? t->tt_name : "")) : (void)0)
;
7478 }
7479 }
7480 else if (route_url == NULL((void*)0) && leg->leg_route &&
7481 leg->leg_loose_route &&
7482 !(route_url = (url_string_t *)leg->leg_route->r_url))
7483 ;
7484 else if (nta_msg_request_complete(msg, leg, method, name, request_uri) < 0)
7485 ;
7486 else
7487 orq = outgoing_create(agent, callback, magic, route_url, NULL((void*)0), msg,
7488 ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
);
7489
7490 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))
;
7491
7492 if (!orq)
7493 msg_destroy(msg);
7494
7495 return orq;
7496}
7497
7498/**Create an outgoing client transaction.
7499 *
7500 * Create an outgoing transaction object. The request message is passed to
7501 * the transaction object, which sends the request to the network. The
7502 * request is sent to the @a route_url (if non-NULL), default proxy (if
7503 * defined by NTATAG_DEFAULT_PROXY()), or to the address specified by @a
7504 * request_uri. If no @a request_uri is specified, it is taken from
7505 * route-set target or from the @To header.
7506 *
7507 * When NTA receives response to the request, it invokes the @a callback
7508 * function.
7509 *
7510 * @param agent NTA agent object
7511 * @param callback callback function (may be @c NULL)
7512 * @param magic application context pointer
7513 * @param route_url optional URL used to route transaction requests
7514 * @param msg request message
7515 * @param tag, value, ... tagged parameter list
7516 *
7517 * @return
7518 * Returns a pointer to newly created outgoing transaction object if
7519 * successful, and NULL otherwise.
7520 *
7521 * @note The caller is responsible for destroying the request message @a msg
7522 * upon failure.
7523 *
7524 * @note If NTATAG_STATELESS(1) tag is given and the @a callback is NULL,
7525 * the transaction object is marked as destroyed from the beginning. In that
7526 * case, the function may return @code (nta_outgoing_t *)-1 @endcode if the
7527 * transaction is freed before returning from the function.
7528 *
7529 * @sa
7530 * nta_outgoing_tcreate(), nta_outgoing_tcancel(), nta_outgoing_destroy().
7531 *
7532 * @TAGS
7533 * NTATAG_STATELESS(), NTATAG_DELAY_SENDING(), NTATAG_BRANCH_KEY(),
7534 * NTATAG_ACK_BRANCH(), NTATAG_DEFAULT_PROXY(), NTATAG_PASS_100(),
7535 * NTATAG_USE_TIMESTAMP(), NTATAG_USER_VIA(), TPTAG_IDENT(), NTATAG_TPORT(). All
7536 * SIP tags from <sofia-sip/sip_tag.h> can be used to manipulate the request message.
7537 * SIP tags after SIPTAG_END() are ignored, however.
7538 */
7539nta_outgoing_t *nta_outgoing_mcreate(nta_agent_t *agent,
7540 nta_response_f *callback,
7541 nta_outgoing_magic_t *magic,
7542 url_string_t const *route_url,
7543 msg_t *msg,
7544 tag_type_t tag, tag_value_t value, ...)
7545{
7546 nta_outgoing_t *orq = NULL((void*)0);
7547 int cleanup = 0;
7548
7549 if (msg == NONE((void *)-1))
7550 msg = nta_msg_create(agent, 0), cleanup = 1;
7551
7552 if (msg && agent) {
7553 ta_list ta;
7554 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)
;
7555 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)
7556 orq = outgoing_create(agent, callback, magic, route_url, NULL((void*)0), msg,
7557 ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
);
7558 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))
;
7559 }
7560
7561 if (!orq && cleanup)
7562 msg_destroy(msg);
7563
7564 return orq;
7565}
7566
7567/** Cancel the request. */
7568int nta_outgoing_cancel(nta_outgoing_t *orq)
7569{
7570 nta_outgoing_t *cancel =
7571 nta_outgoing_tcancel(orq, NULL((void*)0), NULL((void*)0), TAG_NULL()(tag_type_t)0, (tag_value_t)0);
7572
7573 return (cancel != NULL((void*)0)) - 1;
7574}
7575
7576/** Cancel the request.
7577 *
7578 * Initiate a cancel transaction for client transaction @a orq.
7579 *
7580 * @param orq client transaction to cancel
7581 * @param callback callback function (may be @c NULL)
7582 * @param magic application context pointer
7583 * @param tag, value, ... list of extra arguments
7584 *
7585 * @note The function may return @code (nta_outgoing_t *)-1 @endcode (NONE)
7586 * if callback is NULL.
7587 *
7588 * @TAGS
7589 * NTATAG_CANCEL_2534(), NTATAG_CANCEL_408() and all the tags that are
7590 * accepted by nta_outgoing_tcreate().
7591 *
7592 * If NTATAG_CANCEL_408(1) or NTATAG_CANCEL_2543(1) is given, the stack
7593 * generates a 487 response to the request internally. If
7594 * NTATAG_CANCEL_408(1) is given, no CANCEL request is actually sent.
7595 *
7596 * @note
7597 * nta_outgoing_tcancel() refuses to send a CANCEL request for non-INVITE
7598 * requests.
7599 */
7600nta_outgoing_t *nta_outgoing_tcancel(nta_outgoing_t *orq,
7601 nta_response_f *callback,
7602 nta_outgoing_magic_t *magic,
7603 tag_type_t tag, tag_value_t value, ...)
7604{
7605 msg_t *msg;
7606 int cancel_2543, cancel_408;
7607 ta_list ta;
7608 int delay_sending;
7609
7610 if (orq == NULL((void*)0) || orq == NONE((void *)-1))
7611 return NULL((void*)0);
7612
7613 if (orq->orq_destroyed) {
7614 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__
, 7614, "%s: trying to cancel destroyed request\n", __func__)
) : (void)0)
;
7615 return NULL((void*)0);
7616 }
7617 if (orq->orq_method != sip_method_invite) {
7618 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__
, 7618, "%s: trying to cancel non-INVITE request\n", __func__
)) : (void)0)
;
7619 return NULL((void*)0);
7620 }
7621
7622 if (orq->orq_forking)
7623 orq = orq->orq_forking;
7624
7625 if (orq->orq_status >= 200
7626 /* && orq->orq_method != sip_method_invite ... !multicast */) {
7627 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__
, 7627, "%s: trying to cancel completed request\n", __func__)
) : (void)0)
;
7628 return NULL((void*)0);
7629 }
7630 if (orq->orq_canceled) {
7631 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__
, 7631, "%s: trying to cancel cancelled request\n", __func__)
) : (void)0)
;
7632 return NULL((void*)0);
7633 }
7634 orq->orq_canceled = 1;
7635
7636#if HAVE_SOFIA_SRESOLV1
7637 if (!orq->orq_resolved) {
7638 outgoing_destroy_resolver(orq);
7639 outgoing_reply(orq, SIP_487_REQUEST_CANCELLED487, sip_487_Request_terminated, 1);
7640 return NULL((void*)0); /* XXX - Does anyone care about reply? */
7641 }
7642#endif
7643
7644 cancel_408 = 0; /* Don't really CANCEL, this is timeout. */
7645 cancel_2543 = orq->orq_agent->sa_cancel_2543;
7646 /* CANCEL may be sent only after a provisional response has been received. */
7647 delay_sending = orq->orq_status < 100;
7648
7649 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)
;
7650
7651 tl_gets(ta_args(ta)(ta).tl,
7652 NTATAG_CANCEL_408_REF(cancel_408)ntatag_cancel_408_ref, tag_bool_vr(&(cancel_408)),
7653 NTATAG_CANCEL_2543_REF(cancel_2543)ntatag_cancel_2543_ref, tag_bool_vr(&(cancel_2543)),
7654 TAG_END()(tag_type_t)0, (tag_value_t)0);
7655
7656 if (!cancel_408)
7657 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
);
7658 else
7659 msg = NULL((void*)0);
7660
7661 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))
;
7662
7663 if ((cancel_2543 || cancel_408) && !orq->orq_stateless)
7664 outgoing_reply(orq, SIP_487_REQUEST_CANCELLED487, sip_487_Request_terminated, 1);
7665
7666 if (msg) {
7667 nta_outgoing_t *cancel;
7668 if (cancel_2543) /* Follow RFC 2543 semantics for CANCEL */
7669 delay_sending = 0;
7670
7671 cancel = outgoing_create(orq->orq_agent, callback, magic,
7672 NULL((void*)0), orq->orq_tpn, msg,
7673 NTATAG_BRANCH_KEY(orq->orq_branch)ntatag_branch_key, tag_str_v((orq->orq_branch)),
7674 NTATAG_DELAY_SENDING(delay_sending)ntatag_delay_sending, tag_bool_v((delay_sending)),
7675 NTATAG_USER_VIA(1)ntatag_user_via, tag_bool_v((1)),
7676 TAG_END()(tag_type_t)0, (tag_value_t)0);
7677
7678 if (delay_sending)
7679 orq->orq_cancel = cancel;
7680
7681 if (cancel) {
7682 if (!delay_sending)
7683 outgoing_complete(orq);
7684 return cancel;
7685 }
7686
7687 msg_destroy(msg);
7688 }
7689
7690 return NULL((void*)0);
7691}
7692
7693/**Bind callback and application context to a client transaction.
7694 *
7695 * @param orq outgoing client transaction
7696 * @param callback callback function (may be NULL)
7697 * @param magic application context pointer
7698 * (given as argument to @a callback)
7699 *
7700 * @NEW_1_12_9
7701 */
7702int
7703nta_outgoing_bind(nta_outgoing_t *orq,
7704 nta_response_f *callback,
7705 nta_outgoing_magic_t *magic)
7706{
7707 if (orq && !orq->orq_destroyed) {
7708 if (callback == NULL((void*)0))
7709 callback = outgoing_default_cb;
7710 orq->orq_callback = callback;
7711 orq->orq_magic = magic;
7712 return 0;
7713 }
7714 return -1;
7715}
7716
7717/**Get application context bound to a client transaction.
7718 *
7719 * @param orq outgoing client transaction
7720 * @param callback callback function (may be NULL)
7721 *
7722 * Return the application context bound to a client transaction. If the @a
7723 * callback function pointer is given, return application context only if
7724 * the callback matches with the callback bound to the client transaction.
7725 *
7726 * @NEW_1_12_11
7727 */
7728nta_outgoing_magic_t *
7729nta_outgoing_magic(nta_outgoing_t const *orq,
7730 nta_response_f *callback)
7731{
7732 if (orq && (callback == NULL((void*)0) || callback == orq->orq_callback))
7733 return orq->orq_magic;
7734 else
7735 return NULL((void*)0);
7736}
7737
7738
7739/**
7740 * Destroy a request object.
7741 *
7742 * @note
7743 * This function does not actually free the object, but marks it as
7744 * disposable. The object is freed after a timeout.
7745 */
7746void nta_outgoing_destroy(nta_outgoing_t *orq)
7747{
7748 if (orq == NULL((void*)0) || orq == NONE((void *)-1))
7749 return;
7750
7751 if (orq->orq_destroyed) {
7752 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__
, 7753, "%s(%p): %s\n", "nta_outgoing_destroy", (void *)orq, "already destroyed"
)) : (void)0)
7753 "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__
, 7753, "%s(%p): %s\n", "nta_outgoing_destroy", (void *)orq, "already destroyed"
)) : (void)0)
;
7754 return;
7755 }
7756
7757 outgoing_destroy(orq);
7758}
7759
7760/** Return the request URI */
7761url_t const *nta_outgoing_request_uri(nta_outgoing_t const *orq)
7762{
7763 return orq != NULL((void*)0) && orq != NONE((void *)-1) ? orq->orq_url : NULL((void*)0);
7764}
7765
7766/** Return the URI used to route the request */
7767url_t const *nta_outgoing_route_uri(nta_outgoing_t const *orq)
7768{
7769 return orq != NULL((void*)0) && orq != NONE((void *)-1) ? orq->orq_route : NULL((void*)0);
7770}
7771
7772/** Return method of the client transaction */
7773sip_method_t nta_outgoing_method(nta_outgoing_t const *orq)
7774{
7775 return orq != NULL((void*)0) && orq != NONE((void *)-1) ? orq->orq_method : sip_method_invalid;
7776}
7777
7778/** Return method name of the client transaction */
7779char const *nta_outgoing_method_name(nta_outgoing_t const *orq)
7780{
7781 return orq != NULL((void*)0) && orq != NONE((void *)-1) ? orq->orq_method_name : NULL((void*)0);
7782}
7783
7784/** Get sequence number of a client transaction.
7785 */
7786uint32_t nta_outgoing_cseq(nta_outgoing_t const *orq)
7787{
7788 return orq != NULL((void*)0) && orq != NONE((void *)-1) && orq->orq_cseq
7789 ? orq->orq_cseq->cs_seq : 0;
7790}
7791
7792/**
7793 * Get the status code of a client transaction.
7794 */
7795int nta_outgoing_status(nta_outgoing_t const *orq)
7796{
7797 /* Return 500 Internal server error for invalid handles. */
7798 return orq != NULL((void*)0) && orq != NONE((void *)-1) ? orq->orq_status : 500;
7799}
7800
7801/** Get the RTT delay measured using @Timestamp header. */
7802unsigned nta_outgoing_delay(nta_outgoing_t const *orq)
7803{
7804 return orq != NULL((void*)0) && orq != NONE((void *)-1) ? orq->orq_delay : UINT_MAX(2147483647 *2U +1U);
7805}
7806
7807/** Get the branch parameter. @NEW_1_12_7. */
7808char const *nta_outgoing_branch(nta_outgoing_t const *orq)
7809{
7810 return orq != NULL((void*)0) && orq != NONE((void *)-1) && orq->orq_branch
7811 ? orq->orq_branch + strlen("branch=")
7812 : NULL((void*)0);
7813}
7814
7815/**Get reference to response message.
7816 *
7817 * Retrieve the latest incoming response message to the outgoing
7818 * transaction. Note that the message is not copied, but a new reference to
7819 * it is created instead.
7820 *
7821 * @param orq outgoing transaction handle
7822 *
7823 * @retval
7824 * A pointer to response message is returned, or NULL if no response message
7825 * has been received.
7826 */
7827msg_t *nta_outgoing_getresponse(nta_outgoing_t *orq)
7828{
7829 if (orq != NULL((void*)0) && orq != NONE((void *)-1))
7830 return msg_ref_create(orq->orq_response);
7831 else
7832 return NULL((void*)0);
7833}
7834
7835/**Get request message.
7836 *
7837 * Retrieves the request message sent to the network. Note that the request
7838 * message is @b not copied, but a new reference to it is created.
7839 *
7840 * @retval
7841 * A pointer to the request message is returned, or NULL if an error
7842 * occurred.
7843 */
7844msg_t *nta_outgoing_getrequest(nta_outgoing_t *orq)
7845{
7846 if (orq != NULL((void*)0) && orq != NONE((void *)-1))
7847 return msg_ref_create(orq->orq_request);
7848 else
7849 return NULL((void*)0);
7850}
7851
7852/**Create an outgoing request.
7853 *
7854 * Create an outgoing transaction object and send the request to the
7855 * network. The request is sent to the @a route_url (if non-NULL), default
7856 * proxy (if defined by NTATAG_DEFAULT_PROXY()), or to the address specified
7857 * by @a sip->sip_request->rq_url.
7858 *
7859 * When NTA receives response to the request, it invokes the @a callback
7860 * function.
7861 *
7862 * @param agent nta agent object
7863 * @param callback callback function (may be @c NULL)
7864 * @param magic application context pointer
7865 * @param route_url optional URL used to route transaction requests
7866 * @param msg request message
7867 * @param tpn (optional) transport name
7868 * @param msg request message to
7869 * @param tag, value, ... tagged arguments
7870 *
7871 * @return
7872 * Returns a pointer to newly created outgoing transaction object if
7873 * successful, and NULL otherwise.
7874 *
7875 * @note If NTATAG_STATELESS(1) tag is given and the @a callback is NULL,
7876 * the transaction object is marked as destroyed from the beginning. In that
7877 * case, the function may return @code (nta_outgoing_t *)-1 @endcode if the
7878 * transaction is freed before returning from the function.
7879 *
7880 * @TAG NTATAG_TPORT must point to an existing transport object for
7881 * 'agent' (the passed tport is otherwise ignored).
7882 *
7883 * @sa
7884 * nta_outgoing_tcreate(), nta_outgoing_tcancel(), nta_outgoing_destroy().
7885 */
7886nta_outgoing_t *outgoing_create(nta_agent_t *agent,
7887 nta_response_f *callback,
7888 nta_outgoing_magic_t *magic,
7889 url_string_t const *route_url,
7890 tp_name_t const *tpn,
7891 msg_t *msg,
7892 tag_type_t tag, tag_value_t value, ...)
7893{
7894 nta_outgoing_t *orq;
7895 sip_t *sip;
7896 su_home_t *home;
7897 char const *comp = NONE((void *)-1);
7898 char const *branch = NONE((void *)-1);
7899 char const *ack_branch = NONE((void *)-1);
7900 char const *tp_ident;
7901 int delay_sending = 0, sigcomp_zap = 0;
7902 int pass_100 = agent->sa_pass_100, use_timestamp = agent->sa_timestamp;
7903 enum nta_res_order_e res_order = agent->sa_res_order;
7904 struct sigcomp_compartment *cc = NULL((void*)0);
7905 ta_list ta;
7906 char const *scheme = NULL((void*)0);
7907 char const *port = NULL((void*)0);
7908 int invalid, resolved = 0, stateless = 0, user_via = agent->sa_user_via;
7909 int invite_100rel = agent->sa_invite_100rel;
7910 int explicit_transport = 1;
7911 int call_tls_orq_connect_timeout_is_set = 0;
7912 int call_tls_orq_connect_timeout = 0;
7913
7914 tagi_t const *t;
7915 tport_t *override_tport = NULL((void*)0);
7916
7917 if (!agent->sa_tport_ip6)
7918 res_order = nta_res_ip4_only;
7919 else if (!agent->sa_tport_ip4)
7920 res_order = nta_res_ip6_only;
7921
7922 if (!callback)
7923 callback = outgoing_default_cb;
7924 if (!route_url)
7925 route_url = (url_string_t *)agent->sa_default_proxy;
7926
7927 sip = sip_object(msg);
7928 home = msg_home(msg)((su_home_t*)(msg));
7929
7930#ifdef HAVE_ZLIB_COMPRESS1
7931 sip_content_encoding_Xflate(msg, sip_object(msg), 0, 1);
7932#endif
7933
7934 if (!sip->sip_request || sip_complete_message(msg) < 0) {
7935 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__
, 7935, "nta: outgoing_create: incomplete request\n" "%s", ""
)) : (void)0)
;
7936 return NULL((void*)0);
7937 }
7938
7939 if (!route_url && !tpn && sip->sip_route &&
7940 sip->sip_route->r_url->url_params &&
7941 url_param(sip->sip_route->r_url->url_params, "lr", NULL((void*)0), 0))
7942 route_url = (url_string_t *)sip->sip_route->r_url;
7943
7944 if (!(orq = su_zalloc(agent->sa_home, sizeof(*orq))))
7945 return NULL((void*)0);
7946
7947 tp_ident = tpn ? tpn->tpn_ident : NULL((void*)0);
7948
7949 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)
;
7950
7951 /* tl_gets() is a bit too slow here... */
7952 for (t = ta_args(ta)(ta).tl; t; t = tl_next(t)) {
7953 tag_type_t tt = t->t_tag;
7954
7955 if (ntatag_stateless == tt)
7956 stateless = t->t_value != 0;
7957 else if (ntatag_delay_sending == tt)
7958 delay_sending = t->t_value != 0;
7959 else if (ntatag_branch_key == tt)
7960 branch = (void *)t->t_value;
7961 else if (ntatag_pass_100 == tt)
7962 pass_100 = t->t_value != 0;
7963 else if (ntatag_use_timestamp == tt)
7964 use_timestamp = t->t_value != 0;
7965 else if (ntatag_user_via == tt)
7966 user_via = t->t_value != 0;
7967 else if (ntatag_ack_branch == tt)
7968 ack_branch = (void *)t->t_value;
7969 else if (ntatag_default_proxy == tt)
7970 route_url = (void *)t->t_value;
7971 else if (tptag_ident == tt)
7972 tp_ident = (void *)t->t_value;
7973 else if (ntatag_comp == tt)
7974 comp = (char const *)t->t_value;
7975 else if (ntatag_sigcomp_close == tt)
7976 sigcomp_zap = t->t_value != 0;
7977 else if (tptag_compartment == tt)
7978 cc = (void *)t->t_value;
7979 else if (ntatag_tport == tt) {
7980 override_tport = (tport_t *)t->t_value;
7981 }
7982 else if (ntatag_rel100 == tt) {
7983 invite_100rel = t->t_value != 0;
7984 }
7985 else if (ntatag_tls_orq_connect_timeout == tt) {
7986 call_tls_orq_connect_timeout_is_set = 1;
7987 call_tls_orq_connect_timeout = t->t_value;
7988 if (call_tls_orq_connect_timeout > NTA_TIME_MAX) call_tls_orq_connect_timeout = NTA_TIME_MAX;
7989 }
7990 }
7991
7992 orq->orq_agent = agent;
7993 orq->orq_callback = callback;
7994 orq->orq_magic = magic;
7995 orq->orq_method = sip->sip_request->rq_method;
7996 orq->orq_method_name = sip->sip_request->rq_method_name;
7997 orq->orq_cseq = sip->sip_cseq;
7998 orq->orq_to = sip->sip_to;
7999 orq->orq_from = sip->sip_from;
8000 orq->orq_call_id = sip->sip_call_id;
8001 orq->orq_tags = tl_afilter(home, tport_tags, ta_args(ta)(ta).tl);
8002 orq->orq_delayed = delay_sending != 0;
8003 orq->orq_pass_100 = pass_100 != 0;
8004 orq->orq_sigcomp_zap = sigcomp_zap;
8005 orq->orq_sigcomp_new = comp != NONE((void *)-1) && comp != NULL((void*)0);
8006 orq->orq_timestamp = use_timestamp;
8007 orq->orq_delay = UINT_MAX(2147483647 *2U +1U);
8008 orq->orq_stateless = stateless != 0;
8009 orq->orq_user_via = user_via != 0 && sip->sip_via;
8010 orq->orq_100rel = invite_100rel;
8011 orq->orq_uas = !stateless && agent->sa_is_a_uas;
8012 orq->orq_call_tls_connect_timeout_is_set = call_tls_orq_connect_timeout_is_set;
8013 orq->orq_call_tls_connect_timeout = (call_tls_orq_connect_timeout > 0) ? call_tls_orq_connect_timeout : 0;
8014
8015 if (cc)
8016 orq->orq_cc = nta_compartment_ref(cc);
8017
8018 /* Add supported features */
8019 outgoing_features(agent, orq, msg, sip, ta_args(ta)(ta).tl);
8020
8021 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))
;
8022
8023 /* select the tport to use for the outgoing message */
8024 if (override_tport) {
8025 /* note: no ref taken to the tport as its only used once here */
8026 if (tport_is_secondary(override_tport)) {
8027 tpn = tport_name(override_tport);
8028 orq->orq_user_tport = 1;
8029 }
8030 }
8031
8032 if (tpn) {
8033 /* CANCEL or ACK to [3456]XX */
8034 invalid = tport_name_dup(home, orq->orq_tpn, tpn);
8035#if 0 //HAVE_SOFIA_SRESOLV
8036 /* We send ACK or CANCEL only if original request was really sent */
8037 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", 8037, __extension__ __PRETTY_FUNCTION__); }))
;
8038#endif
8039 resolved = tport_name_is_resolved(orq->orq_tpn);
8040 orq->orq_url = url_hdup(home, sip->sip_request->rq_url);
8041 }
8042 else if (route_url && !orq->orq_user_tport) {
8043 invalid = nta_tpn_by_url(home, orq->orq_tpn, &scheme, &port, route_url);
8044 if (invalid >= 0) {
8045 explicit_transport = invalid > 0;
8046 if (override_tport) { /* Use transport protocol name from transport */
8047 if (strcmp(orq->orq_tpn->tpn_proto, "*") == 0)
8048 orq->orq_tpn->tpn_proto = tport_name(override_tport)->tpn_proto;
8049 }
8050
8051 resolved = tport_name_is_resolved(orq->orq_tpn);
8052 orq->orq_url = url_hdup(home, sip->sip_request->rq_url);
8053 if (route_url != (url_string_t *)agent->sa_default_proxy)
8054 orq->orq_route = url_hdup(home, route_url->us_url);
8055 }
8056 }
8057 else {
8058 invalid = nta_tpn_by_url(home, orq->orq_tpn, &scheme, &port,
8059 (url_string_t *)sip->sip_request->rq_url);
8060 if (invalid >= 0) {
8061 explicit_transport = invalid > 0;
8062 resolved = tport_name_is_resolved(orq->orq_tpn);
8063 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)
;
8064 }
8065 orq->orq_url = url_hdup(home, sip->sip_request->rq_url);
8066 }
8067
8068 if (!override_tport)
8069 orq->orq_tpn->tpn_ident = tp_ident;
8070 else
8071 orq->orq_tpn->tpn_ident = tport_name(override_tport)->tpn_ident;
8072
8073 if (comp == NULL((void*)0))
8074 orq->orq_tpn->tpn_comp = comp;
8075
8076 if (orq->orq_user_via && su_strmatch(orq->orq_tpn->tpn_proto, "*")) {
8077 char const *proto = sip_via_transport(sip->sip_via);
8078 if (proto) orq->orq_tpn->tpn_proto = proto;
8079 }
8080
8081 if (branch && branch != NONE((void *)-1)) {
8082 if (su_casenmatch(branch, "branch=", 7))
8083 branch = su_strdup(home, branch);
8084 else
8085 branch = su_sprintf(home, "branch=%s", branch);
8086 }
8087 else if (orq->orq_user_via && sip->sip_via->v_branch && orq->orq_method != sip_method_invite )
8088 branch = su_sprintf(home, "branch=%s", sip->sip_via->v_branch);
8089 else if (stateless)
8090 branch = stateless_branch(agent, msg, sip, orq->orq_tpn);
8091 else
8092 branch = stateful_branch(home, agent);
8093
8094 orq->orq_branch = branch;
8095 orq->orq_via_branch = branch;
8096
8097 if (orq->orq_method == sip_method_ack) {
8098 /* Find the original INVITE which we are ACKing */
8099 if (ack_branch != NULL((void*)0) && ack_branch != NONE((void *)-1)) {
8100 if (su_casenmatch(ack_branch, "branch=", 7))
8101 orq->orq_branch = su_strdup(home, ack_branch);
8102 else
8103 orq->orq_branch = su_sprintf(home, "branch=%s", ack_branch);
8104 }
8105 else if (orq->orq_uas) {
8106 /*
8107 * ACK redirects further 2XX messages to it.
8108 *
8109 * Use orq_branch from INVITE, but put a different branch in topmost Via.
8110 */
8111 nta_outgoing_t *invite = outgoing_find(agent, msg, sip, NULL((void*)0));
8112
8113 if (invite) {
8114 sip_t const *inv = sip_object(invite->orq_request);
8115
8116 orq->orq_branch = su_strdup(home, invite->orq_branch);
8117
8118 /* @RFC3261 section 13.2.2.4 -
8119 * The ACK MUST contain the same credentials as the INVITE.
8120 */
8121 if (!sip->sip_proxy_authorization && !sip->sip_authorization) {
8122 if (inv->sip_proxy_authorization)
8123 sip_add_dup(msg, sip, (void *)inv->sip_proxy_authorization);
8124 if (inv->sip_authorization)
8125 sip_add_dup(msg, sip, (void *)inv->sip_authorization);
8126 }
8127 }
8128 else {
8129 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__
, 8129, "outgoing_create: ACK without INVITE\n" "%s", "")) : (
void)0)
;
8130 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", 8130, __extension__ __PRETTY_FUNCTION__); }))
;
8131 }
8132 }
8133 }
8134
8135#if HAVE_SOFIA_SRESOLV1
8136 if (!resolved)
8137 orq->orq_tpn->tpn_port = port;
8138 orq->orq_resolved = resolved;
8139#else
8140 orq->orq_resolved = resolved = 1;
8141#endif
8142 orq->orq_sips = su_casematch(scheme, "sips");
8143
8144 if (invalid < 0 || !orq->orq_branch || msg_serialize(msg, (void *)sip) < 0) {
8145 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__
, 8147, "nta outgoing create: %s\n", invalid < 0 ? "invalid URI"
: !orq->orq_branch ? "no branch" : "invalid message")) : (
void)0)
8146 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__
, 8147, "nta outgoing create: %s\n", invalid < 0 ? "invalid URI"
: !orq->orq_branch ? "no branch" : "invalid message")) : (
void)0)
8147 !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__
, 8147, "nta outgoing create: %s\n", invalid < 0 ? "invalid URI"
: !orq->orq_branch ? "no branch" : "invalid message")) : (
void)0)
;
8148 outgoing_free(orq);
8149 return NULL((void*)0);
8150 }
8151
8152 /* Now we are committed in sending the transaction */
8153 orq->orq_request = msg;
8154 agent->sa_stats->as_client_tr++;
8155 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))
;
8156
8157 if (orq->orq_user_tport)
8158 outgoing_send_via(orq, override_tport);
8159 else if (resolved)
8160 outgoing_prepare_send(orq);
8161#if HAVE_SOFIA_SRESOLV1
8162 else
8163 outgoing_resolve(orq, explicit_transport, res_order);
8164#endif
8165
8166 if (stateless &&
8167 orq->orq_status >= 200 &&
8168 callback == outgoing_default_cb) {
8169 void *retval;
8170
8171 if (orq->orq_status < 300)
8172 retval = (void *)-1; /* NONE */
8173 else
8174 retval = NULL((void*)0), orq->orq_request = NULL((void*)0);
8175
8176 outgoing_free(orq);
8177
8178 return retval;
8179 }
8180
8181 assert(orq->orq_queue)((void) sizeof ((orq->orq_queue) ? 1 : 0), __extension__ (
{ if (orq->orq_queue) ; else __assert_fail ("orq->orq_queue"
, "nta.c", 8181, __extension__ __PRETTY_FUNCTION__); }))
;
8182
8183 outgoing_insert(agent, orq);
8184
8185 return orq;
8186}
8187
8188/** Prepare sending a request */
8189static void
8190outgoing_prepare_send(nta_outgoing_t *orq)
8191{
8192 nta_agent_t *sa = orq->orq_agent;
8193 tport_t *tp;
8194 tp_name_t *tpn = orq->orq_tpn;
8195
8196 /* Select transport by scheme */
8197 if (orq->orq_sips && strcmp(tpn->tpn_proto, "*") == 0)
8198 tpn->tpn_proto = "tls";
8199
8200 if (!tpn->tpn_port)
8201 tpn->tpn_port = "";
8202
8203 tp = tport_by_name(sa->sa_tports, tpn);
8204
8205 if (tpn->tpn_port[0] == '\0') {
8206 if (orq->orq_sips || tport_has_tls(tp))
8207 tpn->tpn_port = "5061";
8208 else
8209 tpn->tpn_port = "5060";
8210 }
8211
8212 if (tp) {
8213 outgoing_send_via(orq, tp);
8214 }
8215 else if (orq->orq_sips) {
8216 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__
, 8216, "nta outgoing create: no secure transport\n" "%s", ""
)) : (void)0)
;
8217 outgoing_reply(orq, SIP_416_UNSUPPORTED_URI416, sip_416_Unsupported_uri, 1);
8218 }
8219 else {
8220 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__
, 8220, "nta outgoing create: no transport protocol\n" "%s", ""
)) : (void)0)
;
8221 outgoing_reply(orq, 503, "No transport", 1);
8222 }
8223}
8224
8225/** Send request using given transport */
8226static void
8227outgoing_send_via(nta_outgoing_t *orq, tport_t *tp)
8228{
8229 tport_t *old_tp = orq->orq_tport;
8230
8231 orq->orq_tport = tport_ref(tp);
8232
8233 if (orq->orq_pending && tp != old_tp) {
8234 tport_release(old_tp, orq->orq_pending,
8235 orq->orq_request, NULL((void*)0), orq, 0);
8236 orq->orq_pending = 0;
8237 }
8238
8239 if (old_tp) tport_unref(old_tp);
8240
8241 if (outgoing_insert_via(orq, agent_tport_via(tp)) < 0) {
8242 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__
, 8242, "nta outgoing create: cannot insert Via line\n" "%s",
"")) : (void)0)
;
8243 outgoing_reply(orq, 503, "Cannot insert Via", 1);
8244 return;
8245 }
8246
8247#if HAVE_SOFIA_SMIME0
8248 {
8249 sm_object_t *smime = sa->sa_smime;
8250 sip_t *sip = sip_object(orq->orq_request);
8251
8252 if (sa->sa_smime &&
8253 (sip->sip_request->rq_method == sip_method_invite ||
8254 sip->sip_request->rq_method == sip_method_message)) {
8255 msg_prepare(orq->orq_request);
8256 if (sm_encode_message(smime, msg, sip, SM_ID_NULL) < 0) {
8257 outgoing_tport_error(sa, orq, NULL((void*)0),
8258 orq->orq_request, su_errno());
8259 return;
8260 }
8261 }
8262 }
8263#endif
8264
8265 orq->orq_prepared = 1;
8266
8267 if (orq->orq_delayed) {
8268 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__
, 8269, "nta: delayed sending %s (%u)\n", orq->orq_method_name
, orq->orq_cseq->cs_seq)) : (void)0)
8269 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__
, 8269, "nta: delayed sending %s (%u)\n", orq->orq_method_name
, orq->orq_cseq->cs_seq)) : (void)0)
;
8270 outgoing_queue(orq->orq_agent->sa_out.delayed, orq);
8271 return;
8272 }
8273
8274 outgoing_send(orq, 0);
8275}
8276
8277
8278/** Send a request */
8279static void
8280outgoing_send(nta_outgoing_t *orq, int retransmit)
8281{
8282 int err;
8283 tp_name_t const *tpn = orq->orq_tpn;
8284 msg_t *msg = orq->orq_request;
8285 nta_agent_t *agent = orq->orq_agent;
8286 tport_t *tp;
8287 int once = 0;
8288 su_time_t now = su_now();
8289 tag_type_t tag = tag_skip;
8290 tag_value_t value = 0;
8291 struct sigcomp_compartment *cc; cc = NULL((void*)0);
8292
8293 /* tport can be NULL if we are just switching network */
8294 if (orq->orq_tport == NULL((void*)0)) {
8295 outgoing_tport_error(agent, orq, NULL((void*)0), orq->orq_request, ENETRESET102);
8296 return;
8297 }
8298
8299 if (orq->orq_user_tport && !tport_is_clear_to_send(orq->orq_tport)) {
8300 outgoing_tport_error(agent, orq, NULL((void*)0), orq->orq_request, EPIPE32);
8301 return;
8302 }
8303
8304 if (!retransmit)
8305 orq->orq_sent = now;
8306
8307 if (orq->orq_timestamp) {
8308 sip_t *sip = sip_object(msg);
8309 sip_timestamp_t *ts =
8310 sip_timestamp_format(msg_home(msg)((su_home_t*)(msg)), "%lu.%06lu",
8311 now.tv_sec, now.tv_usec);
8312
8313 if (ts) {
8314 if (sip->sip_timestamp)
8315 msg_header_remove(msg, (msg_pub_t *)sip, (msg_header_t *)sip->sip_timestamp);
8316 msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)ts);
8317 }
8318 }
8319
8320 for (;;) {
8321 if (tpn->tpn_comp == NULL((void*)0)) {
8322 /* xyzzy */
8323 }
8324 else if (orq->orq_cc) {
8325 cc = orq->orq_cc, orq->orq_cc = NULL((void*)0);
8326 }
8327 else {
8328 cc = agent_compression_compartment(agent, orq->orq_tport, tpn,
8329 orq->orq_sigcomp_new);
8330 }
8331
8332 if (orq->orq_try_udp_instead)
8333 tag = tptag_mtu, value = 65535;
8334
8335 if (orq->orq_pending) {
8336 tport_release(orq->orq_tport, orq->orq_pending,
8337 orq->orq_request, NULL((void*)0), orq, 0);
8338 orq->orq_pending = 0;
8339 }
8340
8341 tp = tport_tsend(orq->orq_tport, msg, tpn,
8342 tag, value,
8343 IF_SIGCOMP_TPTAG_COMPARTMENT(cc)!(cc && cc != ((void *)-1)) ? tag_skip : tptag_compartment
, tag_ptr_v((cc)),
8344 TAG_NEXT(orq->orq_tags)tag_next, (tag_value_t)(orq->orq_tags));
8345 if (tp)
8346 break;
8347
8348 err = msg_errno(orq->orq_request);
8349
8350 if (cc)
8351 nta_compartment_decref(&cc);
8352
8353 if (orq->orq_user_tport)
8354 /* No retries */;
8355 /* RFC3261, 18.1.1 */
8356 else if (err == EMSGSIZE90 && !orq->orq_try_tcp_instead) {
8357 if (su_casematch(tpn->tpn_proto, "udp") ||
8358 su_casematch(tpn->tpn_proto, "*")) {
8359 outgoing_try_tcp_instead(orq);
8360 continue;
8361 }
8362 }
8363 else if (err == ECONNREFUSED111 && orq->orq_try_tcp_instead) {
8364 if (su_casematch(tpn->tpn_proto, "tcp") && msg_size(msg) <= 65535) {
8365 outgoing_try_udp_instead(orq, 0);
8366 continue;
8367 }
8368 }
8369 else if (err == EPIPE32) {
8370 /* Connection was closed */
8371 if (!once++) {
8372 orq->orq_retries++;
8373 continue;
8374 }
8375 }
8376
8377 outgoing_tport_error(agent, orq, NULL((void*)0), orq->orq_request, err);
8378
8379 return;
8380 }
8381
8382 agent->sa_stats->as_sent_msg++;
8383 agent->sa_stats->as_sent_request++;
8384 if (retransmit)
8385 agent->sa_stats->as_retry_request++;
8386
8387 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__
, 8390, "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)
8388 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__
, 8390, "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)
8389 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__
, 8390, "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)
8390 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__
, 8390, "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)
;
8391
8392 if (cc) {
8393 if (orq->orq_cc)
8394 nta_compartment_decref(&orq->orq_cc);
8395 }
8396
8397 if (orq->orq_pending) {
8398 assert(orq->orq_tport)((void) sizeof ((orq->orq_tport) ? 1 : 0), __extension__ (
{ if (orq->orq_tport) ; else __assert_fail ("orq->orq_tport"
, "nta.c", 8398, __extension__ __PRETTY_FUNCTION__); }))
;
8399 tport_release(orq->orq_tport, orq->orq_pending,
8400 orq->orq_request, NULL((void*)0), orq, 0);
8401 orq->orq_pending = 0;
8402 }
8403
8404 if (orq->orq_stateless) {
8405 outgoing_reply(orq, 202, NULL((void*)0), 202);
8406 return;
8407 }
8408
8409 if (orq->orq_method != sip_method_ack) {
8410 orq->orq_pending = tport_pend(tp, orq->orq_request,
8411 outgoing_tport_error, orq);
8412 if (orq->orq_pending < 0)
8413 orq->orq_pending = 0;
8414 }
8415
8416 if (tp != orq->orq_tport) {
8417 tport_decref(&orq->orq_tport);
8418 orq->orq_tport = tport_ref(tp);
8419 }
8420
8421 orq->orq_reliable = tport_is_reliable(tp);
8422
8423 if (retransmit)
8424 return;
8425
8426 outgoing_trying(orq); /* Timer B / F */
8427
8428 if (orq->orq_method == sip_method_ack)
8429 ;
8430 else if (!orq->orq_reliable) {
8431 /* race condition on initial t1 timer timeout, set minimum initial timeout to 1000ms */
8432 unsigned t1_timer = agent->sa_t1;
8433 if (t1_timer < 1000) t1_timer = 1000;
8434 outgoing_set_timer(orq, t1_timer); /* Timer A/E */
8435 } else if (orq->orq_try_tcp_instead && !tport_is_connected(tp)) {
8436 outgoing_set_timer(orq, agent->sa_t4); /* Timer N3 */
8437 } else if (su_casenmatch(orq->orq_tpn->tpn_proto, "tls", 3) && !tport_is_connected(tp)) {
8438 unsigned tls_reconect_interval = (orq->orq_call_tls_connect_timeout_is_set) ?
8439 orq->orq_call_tls_connect_timeout : agent->sa_tls_orq_connect_timeout;
8440 if (tls_reconect_interval) {
8441 if (tls_reconect_interval < 1000) tls_reconect_interval = 1000;
8442 outgoing_set_timer(orq, tls_reconect_interval); /* Timer N3 set to (min 1000 ms if set) */
8443 }
8444 }
8445}
8446
8447static void
8448outgoing_try_tcp_instead(nta_outgoing_t *orq)
8449{
8450 tport_t *tp;
8451 tp_name_t tpn[1];
8452
8453 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", 8453, __extension__ __PRETTY_FUNCTION__); }))
;
8454
8455 *tpn = *orq->orq_tpn;
8456 tpn->tpn_proto = "tcp";
8457 orq->orq_try_tcp_instead = 1;
8458
8459 tp = tport_by_name(orq->orq_agent->sa_tports, tpn);
8460 if (tp && tp != orq->orq_tport) {
8461 sip_t *sip = sip_object(orq->orq_request);
8462 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)
;
8463 sip->sip_via->v_protocol = sip_transport_tcp;
8464
8465 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__
, 8466, "nta: %s (%u) too large for UDP, trying TCP\n", orq->
orq_method_name, orq->orq_cseq->cs_seq)) : (void)0)
8466 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__
, 8466, "nta: %s (%u) too large for UDP, trying TCP\n", orq->
orq_method_name, orq->orq_cseq->cs_seq)) : (void)0)
;
8467
8468 orq->orq_tpn->tpn_proto = "tcp";
8469 tport_decref(&orq->orq_tport);
8470 orq->orq_tport = tport_ref(tp);
8471
8472 return;
8473 }
8474
8475 /* No TCP - try again with UDP without SIP MTU limit */
8476 tpn->tpn_proto = "udp";
8477 orq->orq_try_udp_instead = 1;
8478
8479 tp = tport_by_name(orq->orq_agent->sa_tports, tpn);
8480 if (tp && tp != orq->orq_tport) {
8481 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__
, 8482, "nta: %s (%u) exceed normal UDP size limit\n", orq->
orq_method_name, orq->orq_cseq->cs_seq)) : (void)0)
8482 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__
, 8482, "nta: %s (%u) exceed normal UDP size limit\n", orq->
orq_method_name, orq->orq_cseq->cs_seq)) : (void)0)
;
8483
8484 tport_decref(&orq->orq_tport);
8485 orq->orq_tport = tport_ref(tp);
8486 }
8487}
8488
8489static void
8490outgoing_try_udp_instead(nta_outgoing_t *orq, int timeout)
8491{
8492 tport_t *tp;
8493 tp_name_t tpn[1];
8494
8495 if (orq->orq_pending) {
8496 tport_release(orq->orq_tport, orq->orq_pending,
8497 orq->orq_request, NULL((void*)0), orq, 0);
8498 orq->orq_pending = 0;
8499 }
8500
8501 *tpn = *orq->orq_tpn;
8502 tpn->tpn_proto = "udp";
8503 orq->orq_try_udp_instead = 1;
8504
8505 tp = tport_by_name(orq->orq_agent->sa_tports, tpn);
8506 if (tp && tp != orq->orq_tport) {
8507 sip_t *sip = sip_object(orq->orq_request);
8508
8509 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)
;
8510 sip->sip_via->v_protocol = sip_transport_udp;
8511
8512 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__
, 8514, "nta: %s (%u) TCP %s, trying UDP\n", orq->orq_method_name
, orq->orq_cseq->cs_seq, timeout ? "times out" : "refused"
)) : (void)0)
8513 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__
, 8514, "nta: %s (%u) TCP %s, trying UDP\n", orq->orq_method_name
, orq->orq_cseq->cs_seq, timeout ? "times out" : "refused"
)) : (void)0)
8514 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__
, 8514, "nta: %s (%u) TCP %s, trying UDP\n", orq->orq_method_name
, orq->orq_cseq->cs_seq, timeout ? "times out" : "refused"
)) : (void)0)
;
8515
8516 orq->orq_tpn->tpn_proto = "udp";
8517 tport_decref(&orq->orq_tport);
8518 orq->orq_tport = tport_ref(tp);
8519 }
8520}
8521
8522
8523/** @internal Report transport errors. */
8524void
8525outgoing_tport_error(nta_agent_t *agent, nta_outgoing_t *orq,
8526 tport_t *tp, msg_t *msg, int error)
8527{
8528 tp_name_t const *tpn = tp ? tport_name(tp) : orq->orq_tpn;
8529
8530 if (orq->orq_pending) {
8531 assert(orq->orq_tport)((void) sizeof ((orq->orq_tport) ? 1 : 0), __extension__ (
{ if (orq->orq_tport) ; else __assert_fail ("orq->orq_tport"
, "nta.c", 8531, __extension__ __PRETTY_FUNCTION__); }))
;
8532 tport_release(orq->orq_tport, orq->orq_pending, orq->orq_request,
8533 NULL((void*)0), orq, 0);
8534 orq->orq_pending = 0;
8535 }
8536
8537 if (error == EPIPE32 && orq->orq_retries++ == 0) {
8538 /* XXX - we should retry only if the transport is not newly created */
8539 outgoing_print_tport_error(orq, 5, "retrying once after ",
8540 tpn, msg, error);
8541 outgoing_send(orq, 1);
8542 return;
8543 }
8544 else if (error == ECONNREFUSED111 && orq->orq_try_tcp_instead) {
8545 /* RFC3261, 18.1.1 */
8546 if (su_casematch(tpn->tpn_proto, "tcp") && msg_size(msg) <= 65535) {
8547 outgoing_print_tport_error(orq, 5, "retrying with UDP after ",
8548 tpn, msg, error);
8549 outgoing_try_udp_instead(orq, 0);
8550 outgoing_remove(orq); /* Reset state - this is no resend! */
8551 outgoing_send(orq, 0); /* Send */
8552 return;
8553 }
8554 }
8555 else if (error == 0) {
8556 /*
8557 * Server closed connection. RFC3261:
8558 * "there is no coupling between TCP connection state and SIP
8559 * processing."
8560 */
8561 return;
8562 }
8563
8564 if (outgoing_other_destinations(orq)) {
8565 outgoing_print_tport_error(orq, 5, "trying alternative server after ",
8566 tpn, msg, error);
8567 outgoing_try_another(orq);
8568 return;
8569 }
8570
8571 outgoing_print_tport_error(orq, 3, "", tpn, msg, error);
8572
8573 outgoing_reply(orq, SIP_503_SERVICE_UNAVAILABLE503, sip_503_Service_unavailable, 0);
8574}
8575
8576static
8577void
8578outgoing_print_tport_error(nta_outgoing_t *orq, int level, char *todo,
8579 tp_name_t const *tpn, msg_t *msg, int error)
8580{
8581 su_sockaddr_t const *su = msg_addr(msg);
8582 char addr[SU_ADDRSIZE(48)];
8583
8584 su_llog(nta_log, level,_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8590
, "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))
8585 "nta: %s (%u): %s%s (%u) with %s/[%s]:%u\n",_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8590
, "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))
8586 orq->orq_method_name, orq->orq_cseq->cs_seq,_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8590
, "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))
8587 todo, su_strerror(error), error,_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8590
, "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))
8588 tpn->tpn_proto,_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8590
, "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))
8589 su_inet_ntop(su->su_family, SU_ADDR(su), addr, sizeof(addr)),_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8590
, "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))
8590 htons(su->su_port))_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8590
, "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))
;
8591}
8592
8593/**@internal
8594 * Add features supported.
8595 */
8596static
8597int outgoing_features(nta_agent_t *agent, nta_outgoing_t *orq,
8598 msg_t *msg, sip_t *sip,
8599 tagi_t *tags)
8600{
8601 char const *supported[8];
8602 int i;
8603
8604 if (orq->orq_method != sip_method_invite) /* fast path for now */
8605 return 0;
8606
8607 supported[i = 0] = NULL((void*)0);
8608
8609 if (orq->orq_method == sip_method_invite) {
8610 int require_100rel = sip_has_feature(sip->sip_require, "100rel");
8611
8612 if (require_100rel) {
8613 orq->orq_must_100rel = 1;
8614 orq->orq_100rel = 1;
8615 }
8616 else if (sip_has_feature(sip->sip_supported, "100rel")) {
8617 orq->orq_100rel = 1;
8618 }
8619 else if (orq->orq_100rel) {
8620 supported[i++] = "100rel";
8621 }
8622 }
8623
8624 if (i) {
8625 supported[i] = NULL((void*)0);
8626
8627 if (sip->sip_supported) {
8628 su_home_t *home = msg_home(msg)((su_home_t*)(msg));
8629 return msg_list_append_items(home, sip->sip_supported, supported);
8630 }
8631 else {
8632 sip_supported_t s[1];
8633 sip_supported_init(s);
8634 s->k_items = supported;
8635 return sip_add_dup(msg, sip, (sip_header_t *)s);
8636 }
8637 }
8638
8639 return 0;
8640}
8641
8642
8643/**@internal
8644 * Insert outgoing request to agent hash table
8645 */
8646static
8647void outgoing_insert(nta_agent_t *agent, nta_outgoing_t *orq)
8648{
8649 if (outgoing_htable_is_full(agent->sa_outgoing))
8650 outgoing_htable_resize(agent->sa_home, agent->sa_outgoing, 0);
8651 outgoing_htable_insert(agent->sa_outgoing, orq);
8652 orq->orq_inserted = 1;
8653}
8654
8655/** @internal
8656 * Initialize a queue for outgoing transactions.
8657 */
8658static void
8659outgoing_queue_init(outgoing_queue_t *queue, unsigned timeout)
8660{
8661 memset(queue, 0, sizeof *queue);
8662 queue->q_tail = &queue->q_head;
8663 queue->q_timeout = timeout;
8664}
8665
8666/** Change the timeout value of a queue */
8667static void
8668outgoing_queue_adjust(nta_agent_t *sa,
8669 outgoing_queue_t *queue,
8670 unsigned timeout)
8671{
8672 nta_outgoing_t *orq;
8673 uint32_t latest;
8674
8675 if (timeout >= queue->q_timeout || !queue->q_head) {
8676 queue->q_timeout = timeout;
8677 return;
8678 }
8679
8680 latest = set_timeout(sa, queue->q_timeout = timeout);
8681
8682 for (orq = queue->q_head; orq; orq = orq->orq_next) {
8683 if (orq->orq_timeout == 0 ||
8684 (int32_t)(orq->orq_timeout - latest) > 0)
8685 orq->orq_timeout = latest;
8686 }
8687}
8688
8689/** @internal
8690 * Test if an outgoing transaction is in a queue.
8691 */
8692su_inlinestatic inline int
8693outgoing_is_queued(nta_outgoing_t const *orq)
8694{
8695 return orq && orq->orq_queue;
8696}
8697
8698/** @internal
8699 * Insert an outgoing transaction into a queue.
8700 *
8701 * Insert a client transaction into a queue and set the corresponding
8702 * timeout at the same time.
8703 */
8704static void
8705outgoing_queue(outgoing_queue_t *queue,
8706 nta_outgoing_t *orq)
8707{
8708 if (orq->orq_queue == queue) {
8709 //assert(queue->q_timeout == 0);
8710 return;
8711 }
8712
8713 assert(!orq->orq_forked)((void) sizeof ((!orq->orq_forked) ? 1 : 0), __extension__
({ if (!orq->orq_forked) ; else __assert_fail ("!orq->orq_forked"
, "nta.c", 8713, __extension__ __PRETTY_FUNCTION__); }))
;
8714
8715 if (outgoing_is_queued(orq))
8716 outgoing_remove(orq);
8717
8718 orq->orq_timeout = set_timeout(orq->orq_agent, queue->q_timeout);
8719
8720 orq->orq_queue = queue;
8721 orq->orq_prev = queue->q_tail;
8722 *queue->q_tail = orq;
8723 queue->q_tail = &orq->orq_next;
8724 queue->q_length++;
8725}
8726
8727/** @internal
8728 * Remove an outgoing transaction from a queue.
8729 */
8730su_inlinestatic inline
8731void outgoing_remove(nta_outgoing_t *orq)
8732{
8733 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", 8733, __extension__ __PRETTY_FUNCTION__); }))
;
8734 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", 8734, __extension__ __PRETTY_FUNCTION__); }))
;
8735
8736 if ((*orq->orq_prev = orq->orq_next))
8737 orq->orq_next->orq_prev = orq->orq_prev;
8738 else
8739 orq->orq_queue->q_tail = orq->orq_prev;
8740
8741 orq->orq_queue->q_length--;
8742 orq->orq_next = NULL((void*)0);
8743 orq->orq_prev = NULL((void*)0);
8744 orq->orq_queue = NULL((void*)0);
8745 orq->orq_timeout = 0;
8746}
8747
8748/** Set retransmit timer (orq_retry).
8749 *
8750 * Set the retry timer (B/D) on the outgoing request (client transaction).
8751 */
8752su_inlinestatic inline
8753void outgoing_set_timer(nta_outgoing_t *orq, uint32_t interval)
8754{
8755 nta_outgoing_t **rq;
8756
8757 assert(orq)((void) sizeof ((orq) ? 1 : 0), __extension__ ({ if (orq) ; else
__assert_fail ("orq", "nta.c", 8757, __extension__ __PRETTY_FUNCTION__
); }))
;
8758
8759 if (interval == 0) {
8760 outgoing_reset_timer(orq);
8761 return;
8762 }
8763
8764 if (orq->orq_rprev) {
8765 /* Remove transaction from retry dequeue, re-insert it later. */
8766 if ((*orq->orq_rprev = orq->orq_rnext))
8767 orq->orq_rnext->orq_rprev = orq->orq_rprev;
8768 if (orq->orq_agent->sa_out.re_t1 == &orq->orq_rnext)
8769 orq->orq_agent->sa_out.re_t1 = orq->orq_rprev;
8770 }
8771 else {
8772 orq->orq_agent->sa_out.re_length++;
8773 }
8774
8775 orq->orq_retry = set_timeout(orq->orq_agent, orq->orq_interval = interval);
8776
8777 /* Shortcut into queue at SIP T1 */
8778 rq = orq->orq_agent->sa_out.re_t1;
8779
8780 if (!(*rq) || (int32_t)((*rq)->orq_retry - orq->orq_retry) > 0)
8781 rq = &orq->orq_agent->sa_out.re_list;
8782
8783 while (*rq && (int32_t)((*rq)->orq_retry - orq->orq_retry) <= 0)
8784 rq = &(*rq)->orq_rnext;
8785
8786 if ((orq->orq_rnext = *rq))
8787 orq->orq_rnext->orq_rprev = &orq->orq_rnext;
8788 *rq = orq;
8789 orq->orq_rprev = rq;
8790
8791 if (interval == orq->orq_agent->sa_t1)
8792 orq->orq_agent->sa_out.re_t1 = rq;
8793}
8794
8795static
8796void outgoing_reset_timer(nta_outgoing_t *orq)
8797{
8798 if (orq->orq_rprev) {
8799 if ((*orq->orq_rprev = orq->orq_rnext))
8800 orq->orq_rnext->orq_rprev = orq->orq_rprev;
8801 if (orq->orq_agent->sa_out.re_t1 == &orq->orq_rnext)
8802 orq->orq_agent->sa_out.re_t1 = orq->orq_rprev;
8803 orq->orq_agent->sa_out.re_length--;
8804 }
8805
8806 orq->orq_interval = 0, orq->orq_retry = 0;
8807 orq->orq_rnext = NULL((void*)0), orq->orq_rprev = NULL((void*)0);
8808}
8809
8810/** @internal
8811 * Free resources associated with the request.
8812 */
8813static
8814void outgoing_free(nta_outgoing_t *orq)
8815{
8816 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__
, 8816, "nta: outgoing_free(%p)\n", (void *)orq)) : (void)0)
;
8817 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", 8817, __extension__ __PRETTY_FUNCTION__); }))
;
8818 outgoing_cut_off(orq);
8819 outgoing_reclaim(orq);
8820}
8821
8822/** Remove outgoing request from hash tables */
8823su_inlinestatic inline void
8824outgoing_cut_off(nta_outgoing_t *orq)
8825{
8826 nta_agent_t *agent = orq->orq_agent;
8827
8828 if (orq->orq_default)
8829 agent->sa_default_outgoing = NULL((void*)0);
8830
8831 if (orq->orq_inserted)
8832 outgoing_htable_remove(agent->sa_outgoing, orq), orq->orq_inserted = 0;
8833
8834 if (outgoing_is_queued(orq))
8835 outgoing_remove(orq);
8836
8837#if 0
8838 if (orq->orq_forked)
8839 outgoing_remove_fork(orq);
8840#endif
8841
8842 outgoing_reset_timer(orq);
8843
8844 if (orq->orq_pending) {
8845 tport_release(orq->orq_tport, orq->orq_pending,
8846 orq->orq_request, NULL((void*)0), orq, 0);
8847 }
8848 orq->orq_pending = 0;
8849
8850 if (orq->orq_cc)
8851 nta_compartment_decref(&orq->orq_cc);
8852
8853 if (orq->orq_tport)
8854 tport_decref(&orq->orq_tport);
8855}
8856
8857/** Reclaim outgoing request */
8858su_inlinestatic inline
8859void outgoing_reclaim(nta_outgoing_t *orq)
8860{
8861 if (orq->orq_status2b)
8862 *orq->orq_status2b = -1;
8863
8864 if (orq->orq_request)
8865 msg_destroy(orq->orq_request), orq->orq_request = NULL((void*)0);
8866 if (orq->orq_response)
8867 msg_destroy(orq->orq_response), orq->orq_response = NULL((void*)0);
8868#if HAVE_SOFIA_SRESOLV1
8869 if (orq->orq_resolver)
8870 outgoing_destroy_resolver(orq);
8871#endif
8872 su_free(orq->orq_agent->sa_home, orq);
8873}
8874
8875/** Queue request to be freed */
8876su_inlinestatic inline
8877void outgoing_free_queue(outgoing_queue_t *q, nta_outgoing_t *orq)
8878{
8879 outgoing_cut_off(orq);
8880 outgoing_queue(q, orq);
8881}
8882
8883/** Reclaim memory used by queue of requests */
8884static
8885void outgoing_reclaim_queued(su_root_magic_t *rm,
8886 su_msg_r msg,
8887 union sm_arg_u *u)
8888{
8889 outgoing_queue_t *q = u->a_outgoing_queue;
8890 nta_outgoing_t *orq, *orq_next;
8891
8892 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__
, 8893, "outgoing_reclaim_all(%p, %p, %p)\n", (void *)rm, (void
*)msg, (void *)u)) : (void)0)
8893 (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__
, 8893, "outgoing_reclaim_all(%p, %p, %p)\n", (void *)rm, (void
*)msg, (void *)u)) : (void)0)
;
8894
8895 for (orq = q->q_head; orq; orq = orq_next) {
8896 orq_next = orq->orq_next;
8897 outgoing_reclaim(orq);
8898 }
8899}
8900
8901/** @internal Default callback for request */
8902int outgoing_default_cb(nta_outgoing_magic_t *magic,
8903 nta_outgoing_t *orq,
8904 sip_t const *sip)
8905{
8906 if (sip == NULL((void*)0) || sip->sip_status->st_status >= 200)
8907 outgoing_destroy(orq);
8908 return 0;
8909}
8910
8911/** @internal Destroy an outgoing transaction */
8912void outgoing_destroy(nta_outgoing_t *orq)
8913{
8914 if (orq->orq_terminated || orq->orq_default) {
8915 if (!orq->orq_forking && !orq->orq_forks) {
8916 outgoing_free(orq);
8917 return;
8918 }
8919 }
8920 /* Application is expected to handle 200 OK statelessly
8921 => kill transaction immediately */
8922 else if (orq->orq_method == sip_method_invite && !orq->orq_completed
8923 /* (unless transaction has been canceled) */
8924 && !orq->orq_canceled
8925 /* or it has been forked */
8926 && !orq->orq_forking && !orq->orq_forks) {
8927 orq->orq_destroyed = 1;
8928 outgoing_terminate(orq);
8929 return;
8930 }
8931
8932 orq->orq_destroyed = 1;
8933 orq->orq_callback = outgoing_default_cb;
8934 orq->orq_magic = NULL((void*)0);
8935}
8936
8937/** @internal Outgoing transaction timer routine.
8938 *
8939 */
8940static void
8941_nta_outgoing_timer(nta_agent_t *sa)
8942{
8943 uint32_t now = su_time_ms(su_now());
8944 nta_outgoing_t *orq;
8945 outgoing_queue_t rq[1];
8946 size_t retransmitted = 0, terminated = 0, timeout = 0, destroyed;
8947 size_t total = sa->sa_outgoing->oht_used;
8948 size_t trying = sa->sa_out.re_length;
8949 size_t pending = sa->sa_out.trying->q_length +
8950 sa->sa_out.inv_calling->q_length;
8951 size_t completed = sa->sa_out.completed->q_length +
8952 sa->sa_out.inv_completed->q_length;
8953
8954 outgoing_queue_init(sa->sa_out.free = rq, 0);
8955
8956 while ((orq = sa->sa_out.re_list)) {
8957
8958 now = su_time_ms(su_now());
8959
8960 if ((int32_t)(orq->orq_retry - now) > 0)
8961 break;
8962 if (retransmitted >= timer_max_retransmit)
8963 break;
8964
8965 if (orq->orq_reliable) {
8966 outgoing_reset_timer(orq);
8967
8968 if (!tport_is_connected(orq->orq_tport)) {
8969 uint32_t tls_connect_timeout = (orq->orq_call_tls_connect_timeout_is_set) ?
8970 orq->orq_call_tls_connect_timeout : sa->sa_tls_orq_connect_timeout;
8971 if (su_casenmatch(orq->orq_tpn->tpn_proto, "tls", 3) && tls_connect_timeout) {
8972 outgoing_remove(orq); /* Reset state - this is no resend! */
8973 if (outgoing_other_destinations(orq)) {
8974 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__
, 8976, "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)
8975 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__
, 8976, "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)
8976 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__
, 8976, "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)
;
8977 outgoing_try_another(orq);
8978 } else {
8979 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__
, 8981, "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)
8980 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__
, 8981, "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)
8981 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__
, 8981, "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)
;
8982 outgoing_send(orq, 0); /* Send */
8983 }
8984 } else {
8985 /*
8986 * Timer N3: try to use UDP if trying to send via TCP
8987 * but no connection is established within SIP T4
8988 */
8989 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__
, 8991, "nta: timer %s fired, %s %s (%u)\n", "N3", "try UDP instead for"
, orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void
)0)
8990 "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__
, 8991, "nta: timer %s fired, %s %s (%u)\n", "N3", "try UDP instead for"
, orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void
)0)
8991 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__
, 8991, "nta: timer %s fired, %s %s (%u)\n", "N3", "try UDP instead for"
, orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void
)0)
;
8992 outgoing_try_udp_instead(orq, 1);
8993 outgoing_remove(orq); /* Reset state - this is no resend! */
8994 outgoing_send(orq, 0); /* Send */
8995 }
8996 }
8997 continue;
8998 }
8999
9000 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", 9000, __extension__ __PRETTY_FUNCTION__); }))
;
9001
9002 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__
, 9004, "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)
9003 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__
, 9004, "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)
9004 "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__
, 9004, "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)
;
9005
9006 outgoing_retransmit(orq);
9007
9008 if (orq->orq_method == sip_method_invite ||
9009 2U * orq->orq_interval < sa->sa_t2)
9010 outgoing_set_timer(orq, 2U * orq->orq_interval);
9011 else
9012 outgoing_set_timer(orq, sa->sa_t2);
9013
9014 if (++retransmitted % 5 == 0)
9015 su_root_yield(sa->sa_root); /* Handle received packets */
9016 }
9017
9018 terminated
9019 = outgoing_timer_dk(sa->sa_out.inv_completed, "D", now)
9020 + outgoing_timer_dk(sa->sa_out.completed, "K", now);
9021
9022 timeout
9023 = outgoing_timer_bf(sa->sa_out.inv_calling, "B", now)
9024 + outgoing_timer_c(sa->sa_out.inv_proceeding, "C", now)
9025 + outgoing_timer_bf(sa->sa_out.trying, "F", now);
9026
9027 destroyed = outgoing_mass_destroy(sa, rq);
9028
9029 sa->sa_out.free = NULL((void*)0);
9030
9031 if (retransmitted || timeout || terminated || destroyed) {
9032 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__
, 9040, "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)
9033 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__
, 9040, "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)
9034 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__
, 9040, "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)
9035 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__
, 9040, "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)
9036 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__
, 9040, "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)
9037 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__
, 9040, "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)
9038 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__
, 9040, "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)
9039 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__
, 9040, "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)
9040 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__
, 9040, "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)
;
9041 }
9042}
9043
9044/** @internal Retransmit the outgoing request. */
9045void outgoing_retransmit(nta_outgoing_t *orq)
9046{
9047 if (orq->orq_prepared && !orq->orq_delayed) {
9048 orq->orq_retries++;
9049
9050 if (orq->orq_retries >= 4 && orq->orq_cc) {
9051 orq->orq_tpn->tpn_comp = NULL((void*)0);
9052 if (orq->orq_retries == 4) {
9053 agent_close_compressor(orq->orq_agent, orq->orq_cc);
9054 nta_compartment_decref(&orq->orq_cc);
9055 }
9056 }
9057
9058 outgoing_send(orq, 1);
9059 }
9060}
9061
9062/** Trying a client transaction. */
9063static
9064void outgoing_trying(nta_outgoing_t *orq)
9065{
9066 if (orq->orq_forked)
9067 ;
9068 else if (orq->orq_method == sip_method_invite) {
9069 if (!orq->orq_completed) {
9070 outgoing_queue(orq->orq_agent->sa_out.inv_calling, orq);
9071 } else {
9072 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__
, 9072, "nta(%p): completed request can not be put into inv_calling queue (%u)\n"
, (void *)orq, orq->orq_cseq->cs_seq)) : (void)0)
;
9073 if (orq->orq_queue != orq->orq_agent->sa_out.inv_completed) {
9074 /* Put back into inv_completed if it's not there by any reason */
9075 outgoing_queue(orq->orq_agent->sa_out.inv_completed, orq); /* Timer D */
9076 }
9077 }
9078 }
9079 else
9080 outgoing_queue(orq->orq_agent->sa_out.trying, orq);
9081}
9082
9083/** Handle timers B and F */
9084static
9085size_t outgoing_timer_bf(outgoing_queue_t *q,
9086 char const *timer,
9087 uint32_t now)
9088{
9089 nta_outgoing_t *orq;
9090 size_t timeout = 0;
9091
9092 while ((orq = q->q_head)) {
9093 if ((int32_t)(orq->orq_timeout - now) > 0 ||
9094 timeout >= timer_max_timeout)
9095 break;
9096
9097 timeout++;
9098
9099 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__
, 9102, "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)
9100 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__
, 9102, "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)
9101 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__
, 9102, "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)
9102 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__
, 9102, "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)
;
9103
9104 if (orq->orq_method != sip_method_ack)
9105 outgoing_timeout(orq, now);
9106 else
9107 outgoing_terminate(orq);
9108
9109 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", 9109, __extension__ __PRETTY_FUNCTION__); }))
;
9110 }
9111
9112 return timeout;
9113}
9114
9115/** Handle timer C */
9116static
9117size_t outgoing_timer_c(outgoing_queue_t *q,
9118 char const *timer,
9119 uint32_t now)
9120{
9121 nta_outgoing_t *orq;
9122 size_t timeout = 0;
9123
9124 if (q->q_timeout == 0)
9125 return 0;
9126
9127 while ((orq = q->q_head)) {
9128 if ((int32_t)(orq->orq_timeout - now) > 0 || timeout >= timer_max_timeout)
9129 break;
9130
9131 timeout++;
9132
9133 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__
, 9135, "nta: timer %s fired, %s %s (%u)\n", timer, "CANCEL and timeout"
, orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void
)0)
9134 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__
, 9135, "nta: timer %s fired, %s %s (%u)\n", timer, "CANCEL and timeout"
, orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void
)0)
9135 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__
, 9135, "nta: timer %s fired, %s %s (%u)\n", timer, "CANCEL and timeout"
, orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void
)0)
;
9136 /*
9137 * If the client transaction has received a provisional response, the
9138 * proxy MUST generate a CANCEL request matching that transaction.
9139 */
9140 nta_outgoing_tcancel(orq, NULL((void*)0), NULL((void*)0), TAG_NULL()(tag_type_t)0, (tag_value_t)0);
9141 }
9142
9143 return timeout;
9144}
9145
9146/** @internal Signal transaction timeout to the application. */
9147void outgoing_timeout(nta_outgoing_t *orq, uint32_t now)
9148{
9149 nta_outgoing_t *cancel = NULL((void*)0);
9150
9151 if (orq->orq_status || orq->orq_canceled)
9152 ;
9153 else if (outgoing_other_destinations(orq)) {
9154 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__
, 9155, "%s(%p): %s\n", "nta", (void *)orq, "try next after timeout"
)) : (void)0)
9155 "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__
, 9155, "%s(%p): %s\n", "nta", (void *)orq, "try next after timeout"
)) : (void)0)
;
9156 outgoing_try_another(orq);
9157 return;
9158 }
9159
9160 cancel = orq->orq_cancel, orq->orq_cancel = NULL((void*)0);
9161 orq->orq_agent->sa_stats->as_tout_request++;
9162
9163 outgoing_reply(orq, SIP_408_REQUEST_TIMEOUT408, sip_408_Request_timeout, 0);
9164
9165 if (cancel)
9166 outgoing_timeout(cancel, now);
9167}
9168
9169/** Complete a client transaction.
9170 *
9171 * @return True if transaction was free()d.
9172 */
9173static int
9174outgoing_complete(nta_outgoing_t *orq)
9175{
9176 orq->orq_completed = 1;
9177
9178 outgoing_reset_timer(orq); /* Timer A / Timer E */
9179
9180 if (orq->orq_stateless)
9181 return outgoing_terminate(orq);
9182
9183 if (orq->orq_forked) {
9184 outgoing_remove_fork(orq);
9185 return outgoing_terminate(orq);
9186 }
9187
9188 if (orq->orq_reliable) {
9189 if (orq->orq_method != sip_method_invite || !orq->orq_uas)
9190 return outgoing_terminate(orq);
9191 }
9192
9193 if (orq->orq_method == sip_method_invite) {
9194 if (orq->orq_queue != orq->orq_agent->sa_out.inv_completed)
9195 outgoing_queue(orq->orq_agent->sa_out.inv_completed, orq); /* Timer D */
9196 }
9197 else {
9198 outgoing_queue(orq->orq_agent->sa_out.completed, orq); /* Timer K */
9199 }
9200
9201 return 0;
9202}
9203
9204/** Handle timers D and K */
9205static
9206size_t outgoing_timer_dk(outgoing_queue_t *q,
9207 char const *timer,
9208 uint32_t now)
9209{
9210 nta_outgoing_t *orq;
9211 size_t terminated = 0;
9212
9213 while ((orq = q->q_head)) {
9214 if ((int32_t)(orq->orq_timeout - now) > 0 ||
9215 terminated >= timer_max_terminate)
9216 break;
9217
9218 terminated++;
9219
9220 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__
, 9221, "nta: timer %s fired, %s %s (%u)\n", timer, "terminate"
, orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void
)0)
9221 "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__
, 9221, "nta: timer %s fired, %s %s (%u)\n", timer, "terminate"
, orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void
)0)
;
9222
9223 if (orq->orq_method == sip_method_invite)
9224 outgoing_terminate_invite(orq);
9225 else
9226 outgoing_terminate(orq);
9227 }
9228
9229 return terminated;
9230}
9231
9232
9233/** Terminate an INVITE client transaction. */
9234static void
9235outgoing_terminate_invite(nta_outgoing_t *original)
9236{
9237 nta_outgoing_t *orq = original;
9238
9239 while (original->orq_forks) {
9240 orq = original->orq_forks;
9241 original->orq_forks = orq->orq_forks;
9242
9243 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", 9243, __extension__
__PRETTY_FUNCTION__); }))
;
9244
9245 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__
, 9247, "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)
9246 "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__
, 9247, "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)
9247 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__
, 9247, "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)
;
9248
9249 orq->orq_forking = NULL((void*)0), orq->orq_forks = NULL((void*)0), orq->orq_forked = 0;
9250
9251 if (outgoing_terminate(orq))
9252 continue;
9253
9254 if (orq->orq_status < 200) {
9255 /* Fork has timed out */
9256 orq->orq_agent->sa_stats->as_tout_request++;
9257 outgoing_reply(orq, SIP_408_REQUEST_TIMEOUT408, sip_408_Request_timeout, 0);
9258 }
9259 }
9260
9261 if (outgoing_terminate(orq = original))
9262 return;
9263
9264 if (orq->orq_status < 200) {
9265 /* Original INVITE has timed out */
9266 orq->orq_agent->sa_stats->as_tout_request++;
9267 outgoing_reply(orq, SIP_408_REQUEST_TIMEOUT408, sip_408_Request_timeout, 0);
9268 }
9269}
9270
9271static void
9272outgoing_remove_fork(nta_outgoing_t *orq)
9273{
9274 nta_outgoing_t **slot;
9275
9276 for (slot = &orq->orq_forking->orq_forks;
9277 slot && *slot;
9278 slot = &(*slot)->orq_forks) {
9279 if (orq == *slot) {
9280 *slot = orq->orq_forks;
9281 orq->orq_forks = NULL((void*)0);
9282 orq->orq_forking = NULL((void*)0);
9283 orq->orq_forked = 0;
9284 }
9285 }
9286
9287 assert(orq == NULL)((void) sizeof ((orq == ((void*)0)) ? 1 : 0), __extension__ (
{ if (orq == ((void*)0)) ; else __assert_fail ("orq == NULL",
"nta.c", 9287, __extension__ __PRETTY_FUNCTION__); }))
;
9288}
9289
9290/** Terminate a client transaction. */
9291static
9292int outgoing_terminate(nta_outgoing_t *orq)
9293{
9294 orq->orq_terminated = 1;
9295
9296 if (!orq->orq_destroyed) {
9297 outgoing_queue(orq->orq_agent->sa_out.terminated, orq);
9298 return 0;
9299 }
9300 else if (orq->orq_agent->sa_out.free) {
9301 outgoing_free_queue(orq->orq_agent->sa_out.free, orq);
9302 return 1;
9303 }
9304 else {
9305 outgoing_free(orq);
9306 return 1;
9307 }
9308}
9309
9310/** Mass destroy client transactions */
9311static
9312size_t outgoing_mass_destroy(nta_agent_t *sa, outgoing_queue_t *q)
9313{
9314 size_t destroyed = q->q_length;
9315
9316 if (destroyed > 2 && *sa->sa_terminator) {
9317 su_msg_r m = SU_MSG_R_INIT{ ((void*)0) };
9318
9319 if (su_msg_create(m,
9320 su_clone_task(sa->sa_terminator),
9321 su_root_task(sa->sa_root),
9322 outgoing_reclaim_queued,
9323 sizeof(outgoing_queue_t)) == SU_SUCCESSsu_success) {
9324 outgoing_queue_t *mq = su_msg_data(m)->a_outgoing_queue;
9325
9326 *mq = *q;
9327
9328 if (su_msg_send(m) == SU_SUCCESSsu_success)
9329 q->q_length = 0;
9330 }
9331 }
9332
9333 if (q->q_length)
9334 outgoing_reclaim_queued(NULL((void*)0), NULL((void*)0), (void*)q);
9335
9336 return destroyed;
9337}
9338
9339/** Find an outgoing request corresponging to a message and @Via line.
9340 *
9341 * Return an outgoing request object based on a message and the @Via line
9342 * given as argument. This function is used when doing loop checking: if we
9343 * have sent the request and it has been routed back to us.
9344 *
9345 * @param agent
9346 * @param msg
9347 * @param sip
9348 * @param v
9349 */
9350nta_outgoing_t *nta_outgoing_find(nta_agent_t const *agent,
9351 msg_t const *msg,
9352 sip_t const *sip,
9353 sip_via_t const *v)
9354{
9355 if (agent == NULL((void*)0) || msg == NULL((void*)0) || sip == NULL((void*)0) || v == NULL((void*)0)) {
9356 su_seterrno(EFAULT14);
9357 return NULL((void*)0);
9358 }
9359
9360 return outgoing_find(agent, msg, sip, v);
9361}
9362
9363/**@internal
9364 *
9365 * Find an outgoing request corresponging to a message and @Via line.
9366 *
9367 */
9368nta_outgoing_t *outgoing_find(nta_agent_t const *sa,
9369 msg_t const *msg,
9370 sip_t const *sip,
9371 sip_via_t const *v)
9372{
9373 nta_outgoing_t **oo, *orq;
9374 outgoing_htable_t const *oht = sa->sa_outgoing;
9375 sip_cseq_t const *cseq = sip->sip_cseq;
9376 sip_call_id_t const *i = sip->sip_call_id;
9377 hash_value_t hash;
9378 sip_method_t method, method2;
9379 unsigned short status = sip->sip_status ? sip->sip_status->st_status : 0;
9380
9381 if (cseq == NULL((void*)0))
9382 return NULL((void*)0);
9383
9384 hash = NTA_HASH(i, cseq->cs_seq)((i)->i_hash + 26839U * (uint32_t)(cseq->cs_seq));
9385
9386 method = cseq->cs_method;
9387
9388 /* Get original invite when ACKing */
9389 if (sip->sip_request && method == sip_method_ack && v == NULL((void*)0))
9390 method = sip_method_invite, method2 = sip_method_invalid;
9391 else if (sa->sa_is_a_uas && 200 <= status && status < 300 && method == sip_method_invite)
9392 method2 = sip_method_ack;
9393 else
9394 method2 = method;
9395
9396 for (oo = outgoing_htable_hash(oht, hash);
9397 (orq = *oo);
9398 oo = outgoing_htable_next(oht, oo)) {
9399 if (orq->orq_stateless)
9400 continue;
9401 /* Accept terminated transactions when looking for original INVITE */
9402 if (orq->orq_terminated && method2 != sip_method_invalid)
9403 continue;
9404 if (hash != orq->orq_hash)
9405 continue;
9406 if (orq->orq_call_id->i_hash != i->i_hash ||
9407 strcmp(orq->orq_call_id->i_id, i->i_id))
9408 continue;
9409 if (orq->orq_cseq->cs_seq != cseq->cs_seq)
9410 continue;
9411 if (method == sip_method_unknown &&
9412 strcmp(orq->orq_cseq->cs_method_name, cseq->cs_method_name))
9413 continue;
9414 if (orq->orq_method != method && orq->orq_method != method2)
9415 continue;
9416 if (su_strcasecmp(orq->orq_from->a_tag, sip->sip_from->a_tag))
9417 continue;
9418 if (orq->orq_to->a_tag &&
9419 su_strcasecmp(orq->orq_to->a_tag, sip->sip_to->a_tag))
9420 continue;
9421
9422 if (orq->orq_method == sip_method_ack && 300 <= status)
9423 continue;
9424
9425 if (v && !su_casematch(orq->orq_branch + strlen("branch="), v->v_branch))
9426 continue;
9427
9428 break; /* match */
9429 }
9430
9431 return orq;
9432}
9433
9434/** Process a response message. */
9435int outgoing_recv(nta_outgoing_t *_orq,
9436 int status,
9437 msg_t *msg,
9438 sip_t *sip)
9439{
9440 nta_outgoing_t *orq = _orq->orq_forking ? _orq->orq_forking : _orq;
9441 nta_agent_t *sa = orq->orq_agent;
9442 int internal = sip == NULL((void*)0) || (sip->sip_flags & NTA_INTERNAL_MSG(1<<15)) != 0;
9443
9444 assert(!internal || status >= 300)((void) sizeof ((!internal || status >= 300) ? 1 : 0), __extension__
({ if (!internal || status >= 300) ; else __assert_fail (
"!internal || status >= 300", "nta.c", 9444, __extension__
__PRETTY_FUNCTION__); }))
;
9445 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", 9445, __extension__ __PRETTY_FUNCTION__); }))
;
9446
9447 if (status < 100) status = 100;
9448
9449 if (!internal && orq->orq_delay == UINT_MAX(2147483647 *2U +1U))
9450 outgoing_estimate_delay(orq, sip);
9451
9452 if (orq->orq_cc)
9453 agent_accept_compressed(orq->orq_agent, msg, orq->orq_cc);
9454
9455 if (orq->orq_cancel) {
9456 nta_outgoing_t *cancel;
9457 cancel = orq->orq_cancel; orq->orq_cancel = NULL((void*)0);
9458 cancel->orq_delayed = 0;
9459
9460 if (status < 200) {
9461 outgoing_send(cancel, 0);
9462 outgoing_complete(orq);
9463 }
9464 else {
9465 outgoing_reply(cancel, SIP_481_NO_TRANSACTION481, sip_481_No_transaction, 0);
9466 }
9467 }
9468
9469 if (orq->orq_pending) {
9470 tport_release(orq->orq_tport, orq->orq_pending, orq->orq_request,
9471 msg, orq, status < 200);
9472 if (status >= 200)
9473 orq->orq_pending = 0;
9474 }
9475
9476 /* The state machines */
9477 if (orq->orq_method == sip_method_invite) {
9478 nta_outgoing_t *original = orq;
9479
9480 orq = _orq;
9481
9482 if (orq->orq_destroyed && 200 <= status && status < 300) {
9483 if (orq->orq_uas && su_strcasecmp(sip->sip_to->a_tag, orq->orq_tag) != 0) {
9484 /* Orphan 200 Ok to INVITE. ACK and BYE it */
9485 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__
, 9485, "nta: Orphan 200 Ok send ACK&BYE %p\n", (void *)orq
)) : (void)0)
;
9486 return nta_msg_ackbye(sa, msg);
9487 }
9488 return -1; /* Proxy statelessly (RFC3261 section 16.11) */
9489 }
9490
9491 outgoing_reset_timer(original); /* Retransmission */
9492
9493 if (status < 200) {
9494 if (original->orq_status < 200)
9495 original->orq_status = status;
9496 if (orq->orq_status < 200)
9497 orq->orq_status = status;
9498
9499 if (original->orq_queue == sa->sa_out.inv_calling) {
9500 outgoing_queue(sa->sa_out.inv_proceeding, original);
9501 }
9502 else if (original->orq_queue == sa->sa_out.inv_proceeding) {
9503 if (sa->sa_out.inv_proceeding->q_timeout) {
9504 outgoing_remove(original);
9505 outgoing_queue(sa->sa_out.inv_proceeding, original);
9506 }
9507 }
9508
9509 /* Handle 100rel */
9510 if (sip && sip->sip_rseq) {
9511 if (outgoing_recv_reliable(orq, msg, sip) < 0) {
9512 msg_destroy(msg);
9513 return 0;
9514 }
9515 }
9516 }
9517 else {
9518 /* Final response */
9519 if (status >= 300 && !internal)
9520 outgoing_ack(original, sip);
9521
9522 if (!original->orq_completed) {
9523 if (outgoing_complete(original))
9524 return 0;
9525
9526 if (orq->orq_uas && sip && orq == original) {
9527 /*
9528 * We silently discard duplicate final responses to INVITE below
9529 * with outgoing_duplicate()
9530 */
9531 su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request));
9532 orq->orq_tag = su_strdup(home, sip->sip_to->a_tag);
9533 }
9534 }
9535 /* Retransmission or response from another fork */
9536 else if (orq->orq_status >= 200) {
9537 /* Once 2xx has been received, non-2xx will not be forwarded */
9538 if (status >= 300)
9539 return outgoing_duplicate(orq, msg, sip);
9540
9541 if (orq->orq_uas) {
9542 if (su_strcasecmp(sip->sip_to->a_tag, orq->orq_tag) == 0)
9543 /* Catch retransmission */
9544 return outgoing_duplicate(orq, msg, sip);
9545
9546 /* Orphan 200 Ok to INVITE. ACK and BYE it */
9547 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__
, 9547, "nta: Orphan 200 Ok send ACK&BYE" "%s", "")) : (void
)0)
;
9548 return nta_msg_ackbye(sa, msg);
9549 }
9550 }
9551
9552 orq->orq_status = status;
9553 }
9554 }
9555 else if (orq->orq_method != sip_method_ack) {
9556 /* Non-INVITE */
9557 if (orq->orq_queue == sa->sa_out.trying ||
9558 orq->orq_queue == sa->sa_out.resolving) {
9559 /* hacked by freeswitch, this is being hit by options 404 status with 404 orq->orq_status and orq_destroyed = 1, orq_completed = 1 */
9560 /* assert(orq->orq_status < 200); */
9561 if (orq->orq_status >= 200) {msg_destroy(msg); return 0;}
9562
9563 if (status < 200) {
9564 /* @RFC3261 17.1.2.1:
9565 * retransmissions continue for unreliable transports,
9566 * but at an interval of T2.
9567 *
9568 * @RFC4321 1.2:
9569 * Note that Timer E is not altered during the transition
9570 * to Proceeding.
9571 */
9572 if (!orq->orq_reliable)
9573 orq->orq_interval = sa->sa_t2;
9574 }
9575 else if (!outgoing_complete(orq)) {
9576 if (orq->orq_sigcomp_zap && orq->orq_tport && orq->orq_cc)
9577 agent_zap_compressor(orq->orq_agent, orq->orq_cc);
9578 }
9579 else /* outgoing_complete */ {
9580 msg_destroy(msg);
9581 return 0;
9582 }
9583 }
9584 else {
9585 /* Already completed or terminated */
9586 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", 9587, __extension__ __PRETTY_FUNCTION__); }))
9587 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", 9587, __extension__ __PRETTY_FUNCTION__); }))
;
9588 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", 9588, __extension__ __PRETTY_FUNCTION__); }))
;
9589 return outgoing_duplicate(orq, msg, sip);
9590 }
9591
9592 orq->orq_status = status;
9593 }
9594 else {
9595 /* ACK */
9596 if (sip && (sip->sip_flags & NTA_INTERNAL_MSG(1<<15)) == 0)
9597 /* Received re-transmitted final reply to INVITE, retransmit ACK */
9598 outgoing_retransmit(orq);
9599 msg_destroy(msg);
9600 return 0;
9601 }
9602
9603 if (100 >= status + orq->orq_pass_100) {
9604 msg_destroy(msg);
9605 return 0;
9606 }
9607
9608 if (orq->orq_destroyed) {
9609 msg_destroy(msg);
9610 return 0;
9611 }
9612
9613 if (orq->orq_response)
9614 msg_destroy(orq->orq_response);
9615 orq->orq_response = msg;
9616 /* Call callback */
9617 orq->orq_callback(orq->orq_magic, orq, sip);
9618 return 0;
9619}
9620
9621static void outgoing_default_recv(nta_outgoing_t *orq,
9622 int status,
9623 msg_t *msg,
9624 sip_t *sip)
9625{
9626 assert(sip->sip_cseq)((void) sizeof ((sip->sip_cseq) ? 1 : 0), __extension__ ({
if (sip->sip_cseq) ; else __assert_fail ("sip->sip_cseq"
, "nta.c", 9626, __extension__ __PRETTY_FUNCTION__); }))
;
9627
9628 orq->orq_status = status;
9629 orq->orq_response = msg;
9630 orq->orq_callback(orq->orq_magic, orq, sip);
9631 orq->orq_response = NULL((void*)0);
9632 orq->orq_status = 0;
9633 msg_destroy(msg);
9634}
9635
9636static void outgoing_estimate_delay(nta_outgoing_t *orq, sip_t *sip)
9637{
9638 su_time_t now = su_now();
9639 double diff = 1000 * su_time_diff(now, orq->orq_sent);
9640
9641 if (orq->orq_timestamp && sip->sip_timestamp) {
9642 double diff2, delay = 0.0;
9643 su_time_t timestamp = { 0, 0 };
9644 char const *bad;
9645
9646 sscanf(sip->sip_timestamp->ts_stamp, "%lu.%lu",
9647 &timestamp.tv_sec, &timestamp.tv_usec);
9648
9649 diff2 = 1000 * su_time_diff(now, timestamp);
9650
9651 if (diff2 < 0)
9652 bad = "negative";
9653 else if (diff2 > diff + 1e-3)
9654 bad = "too large";
9655 else {
9656 if (sip->sip_timestamp->ts_delay)
9657 sscanf(sip->sip_timestamp->ts_delay, "%lg", &delay);
9658
9659 if (1000 * delay <= diff2) {
9660 diff = diff2 - 1000 * delay;
9661 orq->orq_delay = (unsigned)diff;
9662 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__
, 9667, "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)
9663 "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__
, 9667, "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)
9664 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__
, 9667, "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)
9665 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__
, 9667, "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)
9666 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__
, 9667, "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)
9667 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__
, 9667, "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)
;
9668 return;
9669 }
9670 bad = "delay";
9671 }
9672
9673 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__
, 9679, "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)
9674 "(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__
, 9679, "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)
9675 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__
, 9679, "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)
9676 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__
, 9679, "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)
9677 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__
, 9679, "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)
9678 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__
, 9679, "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)
9679 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__
, 9679, "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)
;
9680 }
9681
9682 if (diff >= 0 && diff < (double)UINT_MAX(2147483647 *2U +1U)) {
9683 orq->orq_delay = (unsigned)diff;
9684 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__
, 9684, "nta_outgoing: RTT is %g ms\n", diff)) : (void)0)
;
9685 }
9686}
9687
9688/**@typedef nta_response_f
9689 *
9690 * Callback for replies to outgoing requests.
9691 *
9692 * This is a callback function invoked by NTA when it has received a new
9693 * reply to an outgoing request.
9694 *
9695 * @param magic request context
9696 * @param request request handle
9697 * @param sip received status message
9698 *
9699 * @return
9700 * This callback function should return always 0.
9701 *
9702 */
9703
9704/** Process duplicate responses */
9705static int outgoing_duplicate(nta_outgoing_t *orq,
9706 msg_t *msg,
9707 sip_t *sip)
9708{
9709 sip_via_t *v;
9710
9711 if (sip && (sip->sip_flags & NTA_INTERNAL_MSG(1<<15)) == 0) {
9712 v = sip->sip_via;
9713
9714 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__
, 9716, "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)
9715 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__
, 9716, "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)
9716 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__
, 9716, "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)
;
9717 if (v)
9718 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__
, 9723, "\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)
9719 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__
, 9723, "\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)
9720 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__
, 9723, "\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)
9721 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__
, 9723, "\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)
9722 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__
, 9723, "\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)
9723 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__
, 9723, "\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)
;
9724 }
9725
9726 msg_destroy(msg);
9727 return 0;
9728}
9729
9730/** @internal ACK to a final response (300..699).
9731 * These messages are ACK'ed via the original URL (and tport)
9732 */
9733void outgoing_ack(nta_outgoing_t *orq, sip_t *sip)
9734{
9735 msg_t *ackmsg;
9736
9737 assert(orq)((void) sizeof ((orq) ? 1 : 0), __extension__ ({ if (orq) ; else
__assert_fail ("orq", "nta.c", 9737, __extension__ __PRETTY_FUNCTION__
); }))
;
9738
9739 /* Do not ack internally generated messages... */
9740 if (sip == NULL((void*)0) || sip->sip_flags & NTA_INTERNAL_MSG(1<<15))
9741 return;
9742
9743 assert(sip)((void) sizeof ((sip) ? 1 : 0), __extension__ ({ if (sip) ; else
__assert_fail ("sip", "nta.c", 9743, __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", 9743, __extension__ __PRETTY_FUNCTION__); }))
;
9744 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", 9744, __extension__ __PRETTY_FUNCTION__); }))
;
9745 assert(orq->orq_tport)((void) sizeof ((orq->orq_tport) ? 1 : 0), __extension__ (
{ if (orq->orq_tport) ; else __assert_fail ("orq->orq_tport"
, "nta.c", 9745, __extension__ __PRETTY_FUNCTION__); }))
;
9746
9747 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);
9748 if (!ackmsg)
9749 return;
9750
9751 if (!outgoing_create(orq->orq_agent, NULL((void*)0), NULL((void*)0),
9752 NULL((void*)0), orq->orq_tpn, ackmsg,
9753 NTATAG_BRANCH_KEY(sip->sip_via->v_branch)ntatag_branch_key, tag_str_v((sip->sip_via->v_branch)),
9754 NTATAG_USER_VIA(1)ntatag_user_via, tag_bool_v((1)),
9755 NTATAG_STATELESS(1)ntatag_stateless, tag_bool_v((1)),
9756 TAG_END()(tag_type_t)0, (tag_value_t)0))
9757 msg_destroy(ackmsg);
9758}
9759
9760/** Generate messages for hop-by-hop ACK or CANCEL.
9761 */
9762msg_t *outgoing_ackmsg(nta_outgoing_t *orq, sip_method_t m, char const *mname,
9763 tag_type_t tag, tag_value_t value, ...)
9764{
9765 msg_t *msg = nta_msg_create(orq->orq_agent, 0);
9766 su_home_t *home = msg_home(msg)((su_home_t*)(msg));
9767 sip_t *sip = sip_object(msg);
9768 sip_t *old = sip_object(orq->orq_request);
9769 sip_via_t via[1];
9770
9771 if (!sip)
9772 return NULL((void*)0);
9773
9774 if (tag) {
9775 ta_list ta;
9776
9777 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)
;
9778
9779 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
);
9780 /* Bug sf.net # 173323:
9781 * Ensure that request-URI, topmost Via, From, To, Call-ID, CSeq,
9782 * Max-Forward, Route, Accept-Contact, Reject-Contact and
9783 * Request-Disposition are copied from original request
9784 */
9785 if (sip->sip_from)
9786 sip_header_remove(msg, sip, (void *)sip->sip_from);
9787 if (sip->sip_to && m != sip_method_ack)
9788 sip_header_remove(msg, sip, (void *)sip->sip_to);
9789 if (sip->sip_call_id)
9790 sip_header_remove(msg, sip, (void *)sip->sip_call_id);
9791 while (sip->sip_route)
9792 sip_header_remove(msg, sip, (void *)sip->sip_route);
9793 while (sip->sip_accept_contact)
9794 sip_header_remove(msg, sip, (void *)sip->sip_accept_contact);
9795 while (sip->sip_reject_contact)
9796 sip_header_remove(msg, sip, (void *)sip->sip_reject_contact);
9797 if (sip->sip_request_disposition)
9798 sip_header_remove(msg, sip, (void *)sip->sip_request_disposition);
9799 while (sip->sip_via)
9800 sip_header_remove(msg, sip, (void *)sip->sip_via);
9801 if (sip->sip_max_forwards)
9802 sip_header_remove(msg, sip, (void *)sip->sip_max_forwards);
9803
9804 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))
;
9805 }
9806
9807 sip->sip_request =
9808 sip_request_create(home, m, mname, (url_string_t *)orq->orq_url, NULL((void*)0));
9809
9810 if (sip->sip_to == NULL((void*)0))
9811 sip_add_dup(msg, sip, (sip_header_t *)old->sip_to);
9812 sip_add_dup(msg, sip, (sip_header_t *)old->sip_from);
9813 sip_add_dup(msg, sip, (sip_header_t *)old->sip_call_id);
9814 sip_add_dup(msg, sip, (sip_header_t *)old->sip_route);
9815 /* @RFC3841. Bug #1326727. */
9816 sip_add_dup(msg, sip, (sip_header_t *)old->sip_accept_contact);
9817 sip_add_dup(msg, sip, (sip_header_t *)old->sip_reject_contact);
9818 sip_add_dup(msg, sip, (sip_header_t *)old->sip_request_disposition);
9819 sip_add_dup(msg, sip, (sip_header_t *)old->sip_max_forwards);
9820
9821 if (old->sip_via) {
9822 /* Add only the topmost Via header */
9823 *via = *old->sip_via; via->v_next = NULL((void*)0);
9824 sip_add_dup(msg, sip, (sip_header_t *)via);
9825 }
9826
9827 sip->sip_cseq = sip_cseq_create(home, old->sip_cseq->cs_seq, m, mname);
9828
9829 if (sip->sip_request &&
9830 sip->sip_to &&
9831 sip->sip_from &&
9832 sip->sip_call_id &&
9833 (!old->sip_route || sip->sip_route) &&
9834 sip->sip_cseq)
9835 return msg;
9836
9837 msg_destroy(msg);
9838
9839 return NULL((void*)0);
9840}
9841
9842static
9843void outgoing_delayed_recv(su_root_magic_t *rm,
9844 su_msg_r msg,
9845 union sm_arg_u *u);
9846
9847/** Respond internally to a transaction. */
9848int outgoing_reply(nta_outgoing_t *orq, int status, char const *phrase,
9849 int delayed)
9850{
9851 nta_agent_t *agent = orq->orq_agent;
9852 msg_t *msg = NULL((void*)0);
9853 sip_t *sip = NULL((void*)0);
9854
9855 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",
9855, __extension__ __PRETTY_FUNCTION__); }))
;
9856
9857 if (orq->orq_pending)
9858 tport_release(orq->orq_tport, orq->orq_pending,
9859 orq->orq_request, NULL((void*)0), orq, 0);
9860 orq->orq_pending = 0;
9861
9862 orq->orq_delayed = 0;
9863
9864 if (orq->orq_method == sip_method_ack) {
9865 if (status != delayed)
9866 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__
, 9867, "nta(%p): responding %u %s to ACK!\n", (void *)orq, status
, phrase)) : (void)0)
9867 (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__
, 9867, "nta(%p): responding %u %s to ACK!\n", (void *)orq, status
, phrase)) : (void)0)
;
9868 orq->orq_status = status;
9869 if (orq->orq_queue == NULL((void*)0))
9870 outgoing_trying(orq); /* Timer F */
9871 return 0;
9872 }
9873
9874 if (orq->orq_destroyed) {
9875 if (orq->orq_status < 200)
9876 orq->orq_status = status;
9877 outgoing_complete(orq); /* Timer D / Timer K */
9878 return 0;
9879 }
9880
9881 if (orq->orq_stateless)
9882 ;
9883 else if (orq->orq_queue == NULL((void*)0) ||
9884 orq->orq_queue == orq->orq_agent->sa_out.resolving ||
9885 orq->orq_queue == orq->orq_agent->sa_out.delayed)
9886 outgoing_trying(orq);
9887
9888 /** Insert a dummy Via header */
9889 if (!orq->orq_prepared) {
9890 tport_t *tp = tport_primaries(orq->orq_agent->sa_tports);
9891 outgoing_insert_via(orq, agent_tport_via(tp));
9892 }
9893
9894 /* Create response message, if needed */
9895 if (!orq->orq_stateless &&
9896 !(orq->orq_callback == outgoing_default_cb) &&
9897 !(status == 408 &&
9898 orq->orq_method != sip_method_invite &&
9899 !orq->orq_agent->sa_timeout_408)) {
9900 char const *to_tag;
9901
9902 msg = nta_msg_create(agent, NTA_INTERNAL_MSG(1<<15));
9903
9904 if (complete_response(msg, status, phrase, orq->orq_request) < 0) {
9905 assert(!"complete message")((void) sizeof ((!"complete message") ? 1 : 0), __extension__
({ if (!"complete message") ; else __assert_fail ("!\"complete message\""
, "nta.c", 9905, __extension__ __PRETTY_FUNCTION__); }))
;
9906 return -1;
9907 }
9908
9909 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", 9909, __extension__ __PRETTY_FUNCTION__); }))
;
9910 to_tag = nta_agent_newtag(msg_home(msg)((su_home_t*)(msg)), "tag=%s", agent);
9911
9912 if (status > 100 &&
9913 sip->sip_to && !sip->sip_to->a_tag &&
9914 sip->sip_cseq->cs_method != sip_method_cancel &&
9915 sip_to_tag(msg_home(msg)((su_home_t*)(msg)), sip->sip_to, to_tag) < 0) {
9916 assert(!"adding tag")((void) sizeof ((!"adding tag") ? 1 : 0), __extension__ ({ if
(!"adding tag") ; else __assert_fail ("!\"adding tag\"", "nta.c"
, 9916, __extension__ __PRETTY_FUNCTION__); }))
;
9917 return -1;
9918 }
9919
9920 if (status > 400 && agent->sa_blacklist) {
9921 sip_retry_after_t af[1];
9922 sip_retry_after_init(af)->af_delta = agent->sa_blacklist;
9923
9924 sip_add_dup(msg, sip, (sip_header_t *)af);
9925 }
9926 }
9927
9928 if (orq->orq_inserted && !delayed) {
9929 outgoing_recv(orq, status, msg, sip);
9930 return 0;
9931 }
9932 else if (orq->orq_stateless && orq->orq_callback == outgoing_default_cb) {
9933 /* Xyzzy */
9934 orq->orq_status = status;
9935 outgoing_complete(orq);
9936 }
9937 else {
9938 /*
9939 * The thread creating outgoing transaction must return to application
9940 * before transaction callback can be invoked. Therefore processing an
9941 * internally generated response message must be delayed until
9942 * transaction creation is completed.
9943 *
9944 * The internally generated message is transmitted using su_msg_send()
9945 * and it is delivered back to NTA when the application next time
9946 * executes the su_root_t event loop.
9947 */
9948 nta_agent_t *agent = orq->orq_agent;
9949 su_root_t *root = agent->sa_root;
9950 su_msg_r su_msg = SU_MSG_R_INIT{ ((void*)0) };
9951
9952 if (su_msg_create(su_msg,
9953 su_root_task(root),
9954 su_root_task(root),
9955 outgoing_delayed_recv,
9956 sizeof(struct outgoing_recv_s)) == SU_SUCCESSsu_success) {
9957 struct outgoing_recv_s *a = su_msg_data(su_msg)->a_outgoing_recv;
9958
9959 a->orq = orq;
9960 a->msg = msg;
9961 a->sip = sip;
9962 a->status = status;
9963
9964 orq->orq_status2b = &a->status;
9965
9966 if (su_msg_send(su_msg) == SU_SUCCESSsu_success) {
9967 return 0;
9968 }
9969 }
9970 }
9971
9972 if (msg)
9973 msg_destroy(msg);
9974
9975 return -1;
9976}
9977
9978static
9979void outgoing_delayed_recv(su_root_magic_t *rm,
9980 su_msg_r msg,
9981 union sm_arg_u *u)
9982{
9983 struct outgoing_recv_s *a = u->a_outgoing_recv;
9984
9985 if (a->status > 0) {
9986 a->orq->orq_status2b = 0;
9987 if (outgoing_recv(a->orq, a->status, a->msg, a->sip) >= 0)
9988 return;
9989 }
9990
9991 msg_destroy(a->msg);
9992}
9993
9994
9995/* ====================================================================== */
9996/* 9) Resolving (SIP) URL */
9997
9998#if HAVE_SOFIA_SRESOLV1
9999
10000struct sipdns_query;
10001
10002/** DNS resolving for (SIP) URLs */
10003struct sipdns_resolver
10004{
10005 tp_name_t sr_tpn[1]; /**< Copy of original transport name */
10006 sres_query_t *sr_query; /**< Current DNS Query */
10007 char const *sr_target; /**< Target for current query */
10008
10009 struct sipdns_query *sr_current; /**< Current query (with results) */
10010 char **sr_results; /**< A/AAAA results to be used */
10011
10012 struct sipdns_query *sr_head; /**< List of intermediate results */
10013 struct sipdns_query **sr_tail; /**< End of intermediate result list */
10014
10015 struct sipdns_query *sr_done; /**< Completed intermediate results */
10016
10017 struct sipdns_tport const *sr_tport; /**< Selected transport */
10018
10019 /** Transports to consider for this request */
10020 struct sipdns_tport const *sr_tports[SIPDNS_TRANSPORTS(6) + 1];
10021
10022 uint16_t sr_a_aaaa1, sr_a_aaaa2; /**< Order of A and/or AAAA queries. */
10023
10024 unsigned
10025 sr_use_naptr:1,
10026 sr_use_srv:1,
10027 sr_use_a_aaaa:1;
10028};
10029
10030/** Intermediate queries */
10031struct sipdns_query
10032{
10033 struct sipdns_query *sq_next;
10034
10035 char const *sq_proto;
10036 char const *sq_domain;
10037 char sq_port[6]; /* port number */
10038 uint16_t sq_otype; /* origin type of query data (0 means request) */
10039 uint16_t sq_type; /* query type */
10040 uint16_t sq_priority; /* priority or preference */
10041 uint16_t sq_weight; /* preference or weight */
10042 uint16_t sq_grayish; /* candidate for graylisting */
10043};
10044
10045static int outgoing_resolve_next(nta_outgoing_t *orq);
10046static int outgoing_resolving(nta_outgoing_t *orq);
10047static int outgoing_resolving_error(nta_outgoing_t *,
10048 int status, char const *phrase);
10049static void outgoing_graylist(nta_outgoing_t *orq, struct sipdns_query *sq);
10050static int outgoing_query_naptr(nta_outgoing_t *orq, char const *domain);
10051static void outgoing_answer_naptr(sres_context_t *orq, sres_query_t *q,
10052 sres_record_t *answers[]);
10053struct sipdns_tport const *outgoing_naptr_tport(nta_outgoing_t *orq,
10054 sres_record_t *answers[]);
10055
10056static int outgoing_make_srv_query(nta_outgoing_t *orq);
10057static int outgoing_make_a_aaaa_query(nta_outgoing_t *orq);
10058
10059static void outgoing_query_all(nta_outgoing_t *orq);
10060
10061static int outgoing_query_srv(nta_outgoing_t *orq, struct sipdns_query *);
10062static void outgoing_answer_srv(sres_context_t *orq, sres_query_t *q,
10063 sres_record_t *answers[]);
10064
10065#if SU_HAVE_IN61
10066static int outgoing_query_aaaa(nta_outgoing_t *orq, struct sipdns_query *);
10067static void outgoing_answer_aaaa(sres_context_t *orq, sres_query_t *q,
10068 sres_record_t *answers[]);
10069#endif
10070
10071static int outgoing_query_a(nta_outgoing_t *orq, struct sipdns_query *);
10072static void outgoing_answer_a(sres_context_t *orq, sres_query_t *q,
10073 sres_record_t *answers[]);
10074
10075#ifdef __clang_analyzer__1
10076#define FUNC_ATTR_NONNULL(...)__attribute__((nonnull(...))) __attribute__((nonnull(__VA_ARGS__)))
10077#else
10078#define FUNC_ATTR_NONNULL(...)__attribute__((nonnull(...)))
10079#endif
10080
10081static void outgoing_query_results(nta_outgoing_t *orq,
10082 struct sipdns_query *sq,
10083 char *results[],
10084 size_t rlen) FUNC_ATTR_NONNULL(3)__attribute__((nonnull(3)));
10085
10086
10087#define SIPDNS_503_ERROR503, "DNS Error" 503, "DNS Error"
10088
10089/** Resolve a request destination */
10090static void
10091outgoing_resolve(nta_outgoing_t *orq,
10092 int explicit_transport,
10093 enum nta_res_order_e res_order)
10094{
10095 struct sipdns_resolver *sr = NULL((void*)0);
10096 char const *tpname = orq->orq_tpn->tpn_proto;
10097 int tport_known = strcmp(tpname, "*") != 0;
10098
10099 if (orq->orq_agent->sa_resolver)
10100 orq->orq_resolver = sr = su_zalloc(orq->orq_agent->sa_home, (sizeof *sr));
10101
10102 if (!sr) {
10103 outgoing_resolving_error(orq, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error);
10104 return;
10105 }
10106
10107 *sr->sr_tpn = *orq->orq_tpn;
10108 sr->sr_use_srv = orq->orq_agent->sa_use_srv;
10109 sr->sr_use_naptr = orq->orq_agent->sa_use_naptr && sr->sr_use_srv;
10110 sr->sr_use_a_aaaa = 1;
10111 sr->sr_tail = &sr->sr_head;
10112
10113 /* RFC 3263:
10114 If the TARGET was not a numeric IP address, but a port is present in
10115 the URI, the client performs an A or AAAA record lookup of the domain
10116 name. The result will be a list of IP addresses, each of which can
10117 be contacted at the specific port from the URI and transport protocol
10118 determined previously. The client SHOULD try the first record. If
10119 an attempt should fail, based on the definition of failure in Section
10120 4.3, the next SHOULD be tried, and if that should fail, the next
10121 SHOULD be tried, and so on.
10122
10123 This is a change from RFC 2543. Previously, if the port was
10124 explicit, but with a value of 5060, SRV records were used. Now, A
10125 or AAAA records will be used.
10126 */
10127 if (sr->sr_tpn->tpn_port)
10128 sr->sr_use_naptr = 0, sr->sr_use_srv = 0;
10129
10130 /* RFC3263:
10131 If [...] a transport was specified explicitly, the client performs an
10132 SRV query for that specific transport,
10133 */
10134 if (explicit_transport)
10135 sr->sr_use_naptr = 0;
10136
10137 {
10138 /* Initialize sr_tports */
10139 tport_t *tport;
10140 char const *ident = sr->sr_tpn->tpn_ident;
10141 int i, j;
10142
10143 for (tport = tport_primary_by_name(orq->orq_agent->sa_tports, orq->orq_tpn);
10144 tport;
10145 tport = tport_next(tport)) {
10146 tp_name_t const *tpn = tport_name(tport);
10147 if (tport_known && !su_casematch(tpn->tpn_proto, tpname))
10148 continue;
10149 if (ident && (tpn->tpn_ident == NULL((void*)0) || strcmp(ident, tpn->tpn_ident)))
10150 continue;
10151
10152 for (j = 0; j < SIPDNS_TRANSPORTS(6); j++)
10153 if (su_casematch(tpn->tpn_proto, sipdns_tports[j].name))
10154 break;
10155
10156 assert(j < SIPDNS_TRANSPORTS)((void) sizeof ((j < (6)) ? 1 : 0), __extension__ ({ if (j
< (6)) ; else __assert_fail ("j < SIPDNS_TRANSPORTS", "nta.c"
, 10156, __extension__ __PRETTY_FUNCTION__); }))
;
10157 if (j == SIPDNS_TRANSPORTS(6))
10158 /* Someone added transport but did not update sipdns_tports */
10159 continue;
10160
10161 for (i = 0; i < SIPDNS_TRANSPORTS(6); i++) {
10162 if (sipdns_tports + j == sr->sr_tports[i] || sr->sr_tports[i] == NULL((void*)0))
10163 break;
10164 }
10165 sr->sr_tports[i] = sipdns_tports + j;
10166
10167 if (tport_known) /* Looking for only one transport */ {
10168 sr->sr_tport = sipdns_tports + j;
10169 break;
10170 }
10171 }
10172
10173 /* Nothing found */
10174 if (!sr->sr_tports[0]) {
10175 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__
, 10176, "nta(%p): transport %s is not supported%s%s\n", (void
*)orq, tpname, ident ? " by interface " : "", ident ? ident :
"")) : (void)0)
10176 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__
, 10176, "nta(%p): transport %s is not supported%s%s\n", (void
*)orq, tpname, ident ? " by interface " : "", ident ? ident :
"")) : (void)0)
;
10177 outgoing_resolving_error(orq, SIPDNS_503_ERROR503, "DNS Error");
10178 return;
10179 }
10180 }
10181
10182 switch (res_order) {
10183 default:
10184 case nta_res_ip6_ip4:
10185 sr->sr_a_aaaa1 = sres_type_aaaa, sr->sr_a_aaaa2 = sres_type_a;
10186 break;
10187 case nta_res_ip4_ip6:
10188 sr->sr_a_aaaa1 = sres_type_a, sr->sr_a_aaaa2 = sres_type_aaaa;
10189 break;
10190 case nta_res_ip6_only:
10191 sr->sr_a_aaaa1 = sres_type_aaaa, sr->sr_a_aaaa2 = sres_type_aaaa;
10192 break;
10193 case nta_res_ip4_only:
10194 sr->sr_a_aaaa1 = sres_type_a, sr->sr_a_aaaa2 = sres_type_a;
10195 break;
10196 }
10197
10198 outgoing_resolve_next(orq);
10199}
10200
10201/** Resolve next destination. */
10202static int
10203outgoing_resolve_next(nta_outgoing_t *orq)
10204{
10205 struct sipdns_resolver *sr = orq->orq_resolver;
10206
10207 if (sr == NULL((void*)0)) {
10208 outgoing_resolving_error(orq, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error);
10209 return 0;
10210 }
10211
10212 if (sr->sr_results) {
10213 /* Use existing A/AAAA results */
10214 su_free(msg_home(orq->orq_request)((su_home_t*)(orq->orq_request)), sr->sr_results[0]);
10215 sr->sr_results++;
10216 if (sr->sr_results[0]) {
10217 struct sipdns_query *sq = sr->sr_current; assert(sq)((void) sizeof ((sq) ? 1 : 0), __extension__ ({ if (sq) ; else
__assert_fail ("sq", "nta.c", 10217, __extension__ __PRETTY_FUNCTION__
); }))
;
10218
10219 if (sq->sq_proto)
10220 orq->orq_tpn->tpn_proto = sq->sq_proto;
10221 if (sq->sq_port[0])
10222 orq->orq_tpn->tpn_port = sq->sq_port;
10223
10224 orq->orq_tpn->tpn_host = sr->sr_results[0];
10225
10226 outgoing_reset_timer(orq);
10227 outgoing_queue(orq->orq_agent->sa_out.resolving, orq);
10228 outgoing_prepare_send(orq);
10229 return 1;
10230 }
10231 else {
10232 sr->sr_current = NULL((void*)0);
10233 sr->sr_results = NULL((void*)0);
10234 }
10235 }
10236
10237 if (sr->sr_head)
10238 outgoing_query_all(orq);
10239 else if (sr->sr_use_naptr)
10240 outgoing_query_naptr(orq, sr->sr_tpn->tpn_host); /* NAPTR */
10241 else if (sr->sr_use_srv)
10242 outgoing_make_srv_query(orq); /* SRV */
10243 else if (sr->sr_use_a_aaaa)
10244 outgoing_make_a_aaaa_query(orq); /* A/AAAA */
10245 else
10246 return outgoing_resolving_error(orq, SIPDNS_503_ERROR503, "DNS Error");
10247
10248 return 1;
10249}
10250
10251/** Check if can we retry other destinations? */
10252static int
10253outgoing_other_destinations(nta_outgoing_t const *orq)
10254{
10255 struct sipdns_resolver *sr = orq->orq_resolver;
10256
10257 if (!sr)
10258 return 0;
10259
10260 if (sr->sr_use_a_aaaa || sr->sr_use_srv || sr->sr_use_naptr)
10261 return 1;
10262
10263 if (sr->sr_results && sr->sr_results[1])
10264 return 1;
10265
10266 if (sr->sr_head)
10267 return 1;
10268
10269 return 0;
10270}
10271
10272/** Resolve a request destination */
10273static int
10274outgoing_try_another(nta_outgoing_t *orq)
10275{
10276 struct sipdns_resolver *sr = orq->orq_resolver;
10277
10278 if (sr == NULL((void*)0))
10279 return 0;
10280
10281 *orq->orq_tpn = *sr->sr_tpn;
10282 orq->orq_try_tcp_instead = 0, orq->orq_try_udp_instead = 0;
10283 outgoing_reset_timer(orq);
10284 outgoing_queue(orq->orq_agent->sa_out.resolving, orq);
10285
10286 if (orq->orq_status > 0)
10287 /* PP: don't hack priority if a preliminary response has been received */
10288 ;
10289 else if (orq->orq_agent->sa_graylist == 0)
10290 /* PP: priority hacking disabled */
10291 ;
10292 /* NetModule hack:
10293 * Move server that did not work to end of queue in sres cache
10294 *
10295 * the next request does not try to use the server that is currently down
10296 *
10297 * @TODO: fix cases with only A or AAAA answering, or all servers down.
10298 */
10299 else if (sr && sr->sr_target) {
10300 struct sipdns_query *sq;
10301
10302 /* find latest A/AAAA record */
10303 sq = sr->sr_head;
10304 if (sq && sq->sq_type == sr->sr_a_aaaa2 && sr->sr_a_aaaa1 != sr->sr_a_aaaa2) {
10305 sq->sq_grayish = 1;
10306 }
10307 else {
10308 outgoing_graylist(orq, sr->sr_done);
10309 }
10310 }
10311
10312 return outgoing_resolve_next(orq);
10313}
10314
10315/** Graylist SRV records */
10316static void outgoing_graylist(nta_outgoing_t *orq, struct sipdns_query *sq)
10317{
10318 struct sipdns_resolver *sr = orq->orq_resolver;
10319 char const *target = sq->sq_domain, *proto = sq->sq_proto;
10320 unsigned prio = sq->sq_priority, maxprio = prio;
10321
10322 /* Don't know how to graylist but SRV records */
10323 if (sq->sq_otype != sres_type_srv)
10324 return;
10325
10326 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__
, 10326, "nta: graylisting %s:%s;transport=%s\n", target, sq->
sq_port, proto)) : (void)0)
;
10327
10328 for (sq = sr->sr_head; sq; sq = sq->sq_next)
10329 if (sq->sq_otype == sres_type_srv && sq->sq_priority > maxprio)
10330 maxprio = sq->sq_priority;
10331
10332 for (sq = sr->sr_done; sq; sq = sq->sq_next)
10333 if (sq->sq_otype == sres_type_srv && sq->sq_priority > maxprio)
10334 maxprio = sq->sq_priority;
10335
10336 for (sq = sr->sr_done; sq; sq = sq->sq_next) {
10337 int modified;
10338
10339 if (sq->sq_type != sres_type_srv || strcmp(proto, sq->sq_proto))
10340 continue;
10341
10342 /* modify the SRV record(s) corresponding to the latest A/AAAA record */
10343 modified = sres_set_cached_srv_priority(
10344 orq->orq_agent->sa_resolver,
10345 sq->sq_domain,
10346 target,
10347 sq->sq_port[0] ? (uint16_t)strtoul(sq->sq_port, NULL((void*)0), 10) : 0,
10348 orq->orq_agent->sa_graylist,
10349 maxprio + 1);
10350
10351 if (modified >= 0)
10352 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__
, 10353, "nta: reduced priority of %d %s SRV records (increase value to %u)\n"
, modified, sq->sq_domain, maxprio + 1)) : (void)0)
10353 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__
, 10353, "nta: reduced priority of %d %s SRV records (increase value to %u)\n"
, modified, sq->sq_domain, maxprio + 1)) : (void)0)
;
10354 else
10355 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__
, 10355, "nta: failed to reduce %s SRV priority\n", sq->sq_domain
)) : (void)0)
;
10356 }
10357}
10358
10359/** Cancel resolver query */
10360su_inlinestatic inline void outgoing_cancel_resolver(nta_outgoing_t *orq)
10361{
10362 struct sipdns_resolver *sr = orq->orq_resolver;
10363
10364 assert(orq->orq_resolver)((void) sizeof ((orq->orq_resolver) ? 1 : 0), __extension__
({ if (orq->orq_resolver) ; else __assert_fail ("orq->orq_resolver"
, "nta.c", 10364, __extension__ __PRETTY_FUNCTION__); }))
;
10365
10366 if (sr->sr_query) /* Cancel resolver query */
10367 sres_query_bind(sr->sr_query, NULL((void*)0), NULL((void*)0)), sr->sr_query = NULL((void*)0);
10368}
10369
10370/** Destroy resolver */
10371su_inlinestatic inline void outgoing_destroy_resolver(nta_outgoing_t *orq)
10372{
10373 struct sipdns_resolver *sr = orq->orq_resolver;
10374
10375 assert(orq->orq_resolver)((void) sizeof ((orq->orq_resolver) ? 1 : 0), __extension__
({ if (orq->orq_resolver) ; else __assert_fail ("orq->orq_resolver"
, "nta.c", 10375, __extension__ __PRETTY_FUNCTION__); }))
;
10376
10377 outgoing_cancel_resolver(orq);
10378
10379 su_free(orq->orq_agent->sa_home, sr);
10380
10381 orq->orq_resolver = NULL((void*)0);
10382}
10383
10384/** Check if we are resolving. If not, return 503 response. */
10385static
10386int outgoing_resolving(nta_outgoing_t *orq)
10387{
10388 struct sipdns_resolver *sr = orq->orq_resolver;
10389
10390 assert(orq->orq_resolver)((void) sizeof ((orq->orq_resolver) ? 1 : 0), __extension__
({ if (orq->orq_resolver) ; else __assert_fail ("orq->orq_resolver"
, "nta.c", 10390, __extension__ __PRETTY_FUNCTION__); }))
;
10391
10392 if (!sr->sr_query) {
10393 return outgoing_resolving_error(orq, SIPDNS_503_ERROR503, "DNS Error");
10394 }
10395 else {
10396 outgoing_queue(orq->orq_agent->sa_out.resolving, orq);
10397 return 0;
10398 }
10399}
10400
10401/** Return 503 response */
10402static
10403int outgoing_resolving_error(nta_outgoing_t *orq, int status, char const *phrase)
10404{
10405 orq->orq_resolved = 1;
10406 outgoing_reply(orq, status, phrase, 0);
10407 return -1;
10408}
10409
10410/* Query SRV records (with the given tport). */
10411static
10412int outgoing_make_srv_query(nta_outgoing_t *orq)
10413{
10414 struct sipdns_resolver *sr = orq->orq_resolver;
10415 su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request));
10416 struct sipdns_query *sq;
10417 char const *host, *prefix;
10418 int i;
10419 size_t hlen, plen;
10420
10421 sr->sr_use_srv = 0;
10422
10423 host = sr->sr_tpn->tpn_host;
10424 hlen = strlen(host) + 1;
10425
10426 for (i = 0; sr->sr_tports[i]; i++) {
10427 if (sr->sr_tport && sr->sr_tports[i] != sr->sr_tport)
10428 continue;
10429
10430 prefix = sr->sr_tports[i]->prefix;
10431 plen = strlen(prefix);
10432
10433 sq = su_zalloc(home, (sizeof *sq) + plen + hlen);
10434 if (sq) {
10435 *sr->sr_tail = sq, sr->sr_tail = &sq->sq_next;
10436 sq->sq_domain = memcpy(sq + 1, prefix, plen);
10437 memcpy((char *)sq->sq_domain + plen, host, hlen);
10438 sq->sq_proto = sr->sr_tports[i]->name;
10439 sq->sq_type = sres_type_srv;
10440 sq->sq_priority = 1;
10441 sq->sq_weight = 1;
10442 }
10443 }
10444
10445 outgoing_query_all(orq);
10446
10447 return 0;
10448}
10449
10450/* Query A/AAAA records. */
10451static
10452int outgoing_make_a_aaaa_query(nta_outgoing_t *orq)
10453{
10454 struct sipdns_resolver *sr = orq->orq_resolver;
10455 su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request));
10456 tp_name_t *tpn = orq->orq_tpn;
10457 struct sipdns_query *sq;
10458
10459 assert(sr)((void) sizeof ((sr) ? 1 : 0), __extension__ ({ if (sr) ; else
__assert_fail ("sr", "nta.c", 10459, __extension__ __PRETTY_FUNCTION__
); }))
;
10460
10461 sr->sr_use_a_aaaa = 0;
10462
10463 sq = su_zalloc(home, 2 * (sizeof *sq));
10464 if (!sq)
10465 return outgoing_resolving(orq);
10466
10467 sq->sq_type = sr->sr_a_aaaa1;
10468 sq->sq_domain = tpn->tpn_host;
10469 sq->sq_priority = 1;
10470
10471 /* Append */
10472 *sr->sr_tail = sq, sr->sr_tail = &sq->sq_next;
10473
10474 outgoing_query_all(orq);
10475
10476 return 0;
10477}
10478
10479
10480/** Start SRV/A/AAAA queries */
10481static
10482void outgoing_query_all(nta_outgoing_t *orq)
10483{
10484 struct sipdns_resolver *sr = orq->orq_resolver;
10485 struct sipdns_query *sq = sr->sr_head;
10486
10487 if (sq == NULL((void*)0)) {
10488 outgoing_resolving_error(orq, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error);
10489 return;
10490 }
10491
10492 /* Remove from intermediate list */
10493 if (!(sr->sr_head = sq->sq_next))
10494 sr->sr_tail = &sr->sr_head;
10495
10496 if (sq->sq_type == sres_type_srv)
10497 outgoing_query_srv(orq, sq);
10498#if SU_HAVE_IN61
10499 else if (sq->sq_type == sres_type_aaaa)
10500 outgoing_query_aaaa(orq, sq);
10501#endif
10502 else if (sq->sq_type == sres_type_a)
10503 outgoing_query_a(orq, sq);
10504 else
10505 outgoing_resolving_error(orq, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error);
10506}
10507
10508/** Query NAPTR record. */
10509static
10510int outgoing_query_naptr(nta_outgoing_t *orq, char const *domain)
10511{
10512 struct sipdns_resolver *sr = orq->orq_resolver;
10513 sres_record_t **answers;
10514
10515 sr->sr_use_naptr = 0;
10516
10517 sr->sr_target = domain;
10518
10519 answers = sres_cached_answers(orq->orq_agent->sa_resolver,
10520 sres_type_naptr, domain);
10521
10522 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__
, 10524, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, domain, "NAPTR", answers ? " (cached)" : "")) :
(void)0)
10523 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__
, 10524, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, domain, "NAPTR", answers ? " (cached)" : "")) :
(void)0)
10524 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__
, 10524, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, domain, "NAPTR", answers ? " (cached)" : "")) :
(void)0)
;
10525
10526 if (answers) {
10527 outgoing_answer_naptr(orq, NULL((void*)0), answers);
10528 return 0;
10529 }
10530 else {
10531 sr->sr_query = sres_query(orq->orq_agent->sa_resolver,
10532 outgoing_answer_naptr, orq,
10533 sres_type_naptr, domain);
10534 return outgoing_resolving(orq);
10535 }
10536}
10537
10538/* Process NAPTR records */
10539static
10540void outgoing_answer_naptr(sres_context_t *orq,
10541 sres_query_t *q,
10542 sres_record_t *answers[])
10543{
10544 int i, order = -1;
10545 size_t rlen;
10546 su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request));
10547 struct sipdns_resolver *sr = orq->orq_resolver;
10548 tp_name_t tpn[1];
10549 struct sipdns_query *sq, *selected = NULL((void*)0), **tail = &selected, **at;
10550
10551 assert(sr)((void) sizeof ((sr) ? 1 : 0), __extension__ ({ if (sr) ; else
__assert_fail ("sr", "nta.c", 10551, __extension__ __PRETTY_FUNCTION__
); }))
;
10552
10553 sr->sr_query = NULL((void*)0);
10554
10555 *tpn = *sr->sr_tpn;
10556
10557 /* The NAPTR results are sorted first by Order then by Preference */
10558 sres_sort_answers(orq->orq_agent->sa_resolver, answers);
10559
10560 if (sr->sr_tport == NULL((void*)0))
10561 sr->sr_tport = outgoing_naptr_tport(orq, answers);
10562
10563 for (i = 0; answers && answers[i]; i++) {
10564 sres_naptr_record_t const *na = answers[i]->sr_naptr;
10565 uint16_t type;
10566 int valid_tport;
10567
10568 if (na->na_record->r_status)
10569 continue;
10570 if (na->na_record->r_type != sres_type_naptr)
10571 continue;
10572
10573 /* Check if NAPTR matches our target */
10574 if (!su_casenmatch(na->na_services, "SIP+", 4) &&
10575 !su_casenmatch(na->na_services, "SIPS+", 5))
10576 /* Not a SIP/SIPS service */
10577 continue;
10578
10579 /* Use NAPTR results, don't try extra SRV/A/AAAA records */
10580 sr->sr_use_srv = 0, sr->sr_use_a_aaaa = 0;
10581
10582 valid_tport = sr->sr_tport &&
10583 su_casematch(na->na_services, sr->sr_tport->service);
10584
10585 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__
, 10591, "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)
10586 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__
, 10591, "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)
10587 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__
, 10591, "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)
10588 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__
, 10591, "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)
10589 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__
, 10591, "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)
10590 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__
, 10591, "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)
10591 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__
, 10591, "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)
;
10592
10593 /* RFC 2915 p 4:
10594 * Order
10595 * A 16-bit unsigned integer specifying the order in which the
10596 * NAPTR records MUST be processed to ensure the correct ordering
10597 * of rules. Low numbers are processed before high numbers, and
10598 * once a NAPTR is found whose rule "matches" the target, the
10599 * client MUST NOT consider any NAPTRs with a higher value for
10600 * order (except as noted below for the Flags field).
10601 */
10602 if (order >= 0 && order != na->na_order)
10603 continue;
10604 if (!valid_tport)
10605 continue;
10606
10607 /* OK, we found matching NAPTR */
10608 order = na->na_order;
10609
10610 /*
10611 * The "S" flag means that the next lookup should be for SRV records
10612 * ... "A" means that the next lookup should be for either an A, AAAA,
10613 * or A6 record.
10614 */
10615 if (na->na_flags[0] == 's' || na->na_flags[0] == 'S')
10616 type = sres_type_srv; /* SRV */
10617 else if (na->na_flags[0] == 'a' || na->na_flags[0] == 'A')
10618 type = sr->sr_a_aaaa1; /* A / AAAA */
10619 else
10620 continue;
10621
10622 rlen = strlen(na->na_replace) + 1;
10623 sq = su_zalloc(home, (sizeof *sq) + rlen);
10624
10625 if (sq == NULL((void*)0))
10626 continue;
10627
10628 *tail = sq, tail = &sq->sq_next;
10629 sq->sq_otype = sres_type_naptr;
10630 sq->sq_priority = na->na_prefer;
10631 sq->sq_weight = 1;
10632 sq->sq_type = type;
10633 sq->sq_domain = memcpy(sq + 1, na->na_replace, rlen);
10634 sq->sq_proto = sr->sr_tport->name;
10635 }
10636
10637 sres_free_answers(orq->orq_agent->sa_resolver, answers);
10638
10639 /* RFC2915:
10640 Preference [...] specifies the order in which NAPTR
10641 records with equal "order" values SHOULD be processed, low
10642 numbers being processed before high numbers. */
10643 at = sr->sr_tail;
10644 while (selected) {
10645 sq = selected, selected = sq->sq_next;
10646
10647 for (tail = at; *tail; tail = &(*tail)->sq_next) {
10648 if (sq->sq_priority < (*tail)->sq_priority)
10649 break;
10650 if (sq->sq_priority == (*tail)->sq_priority &&
10651 sq->sq_weight < (*tail)->sq_weight)
10652 break;
10653 }
10654 /* Insert */
10655 sq->sq_next = *tail, *tail = sq;
10656
10657 if (!sq->sq_next) /* Last one */
10658 sr->sr_tail = &sq->sq_next;
10659 }
10660
10661 outgoing_resolve_next(orq);
10662}
10663
10664/* Find first supported protocol in order and preference */
10665struct sipdns_tport const *
10666outgoing_naptr_tport(nta_outgoing_t *orq, sres_record_t *answers[])
10667{
10668 int i, j, order, pref;
10669 int orders[SIPDNS_TRANSPORTS(6)] = {0}, prefs[SIPDNS_TRANSPORTS(6)] = {0};
10670 struct sipdns_tport const *tport;
10671
10672 struct sipdns_resolver *sr = orq->orq_resolver;
10673
10674 prefs[0] = 0;
10675 for (j = 0; sr->sr_tports[j]; j++) {
10676 tport = sr->sr_tports[j];
10677
10678 orders[j] = 65536, prefs[j] = 65536;
10679
10680 /* Find transport order */
10681 for (i = 0; answers && answers[i]; i++) {
10682 sres_naptr_record_t const *na = answers[i]->sr_naptr;
10683 if (na->na_record->r_status)
10684 continue;
10685 if (na->na_record->r_type != sres_type_naptr)
10686 continue;
10687 /* Check if NAPTR matches transport */
10688 if (!su_casematch(na->na_services, tport->service))
10689 continue;
10690 orders[j] = na->na_order;
10691 prefs[j] = na->na_prefer;
10692 break;
10693 }
10694 }
10695
10696 tport = sr->sr_tports[0], order = orders[0], pref = prefs[0];
10697
10698 for (j = 1; sr->sr_tports[j]; j++) {
10699 if (orders[j] <= order && prefs[j] < pref) {
10700 tport = sr->sr_tports[j], order = orders[j], pref = prefs[j];
10701 }
10702 }
10703
10704 return tport;
10705}
10706
10707
10708/* Query SRV records */
10709static
10710int outgoing_query_srv(nta_outgoing_t *orq,
10711 struct sipdns_query *sq)
10712{
10713 struct sipdns_resolver *sr = orq->orq_resolver;
10714
10715 sres_record_t **answers;
10716
10717 sr->sr_target = sq->sq_domain;
10718 sr->sr_current = sq;
10719
10720 answers = sres_cached_answers(orq->orq_agent->sa_resolver,
10721 sres_type_srv, sq->sq_domain);
10722
10723 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__
, 10725, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, sq->sq_domain, "SRV", answers ? " (cached)"
: "")) : (void)0)
10724 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__
, 10725, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, sq->sq_domain, "SRV", answers ? " (cached)"
: "")) : (void)0)
10725 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__
, 10725, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, sq->sq_domain, "SRV", answers ? " (cached)"
: "")) : (void)0)
;
10726
10727 if (answers) {
10728 outgoing_answer_srv(orq, NULL((void*)0), answers);
10729 return 0;
10730 }
10731 else {
10732 sr->sr_query = sres_query(orq->orq_agent->sa_resolver,
10733 outgoing_answer_srv, orq,
10734 sres_type_srv, sq->sq_domain);
10735 return outgoing_resolving(orq);
10736 }
10737}
10738
10739/* Process SRV records */
10740static
10741void
10742outgoing_answer_srv(sres_context_t *orq, sres_query_t *q,
10743 sres_record_t *answers[])
10744{
10745 struct sipdns_resolver *sr = orq->orq_resolver;
10746 su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request));
10747 struct sipdns_query *sq0, *sq, *selected = NULL((void*)0), **tail = &selected, **at;
10748 int i;
10749 size_t tlen;
10750
10751 sr->sr_query = NULL((void*)0);
10752
10753 sq0 = sr->sr_current;
10754 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", 10754, __extension__ __PRETTY_FUNCTION__); }))
;
10755 assert(sq0->sq_domain)((void) sizeof ((sq0->sq_domain) ? 1 : 0), __extension__ (
{ if (sq0->sq_domain) ; else __assert_fail ("sq0->sq_domain"
, "nta.c", 10755, __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", 10755, __extension__ __PRETTY_FUNCTION__); }))
;
10756
10757 /* Sort by priority, weight? */
10758 sres_sort_answers(orq->orq_agent->sa_resolver, answers);
10759
10760 for (i = 0; answers && answers[i]; i++) {
10761 sres_srv_record_t const *srv = answers[i]->sr_srv;
10762
10763 if (srv->srv_record->r_status /* There was an error */ ||
10764 srv->srv_record->r_type != sres_type_srv)
10765 continue;
10766
10767 tlen = strlen(srv->srv_target) + 1;
10768
10769 sq = su_zalloc(home, (sizeof *sq) + tlen);
10770
10771 if (sq) {
10772 *tail = sq, tail = &sq->sq_next;
10773
10774 sq->sq_otype = sres_type_srv;
10775 sq->sq_type = sr->sr_a_aaaa1;
10776 sq->sq_proto = sq0->sq_proto;
10777 sq->sq_domain = memcpy(sq + 1, srv->srv_target, tlen);
10778 snprintf(sq->sq_port, sizeof(sq->sq_port), "%u", srv->srv_port);
10779 sq->sq_priority = srv->srv_priority;
10780 sq->sq_weight = srv->srv_weight;
10781 }
10782 }
10783
10784 sres_free_answers(orq->orq_agent->sa_resolver, answers);
10785
10786 at = &sr->sr_head;
10787
10788 /* Insert sorted by priority, randomly select by weigth */
10789 while (selected) {
10790 unsigned long weight = 0;
10791 unsigned N = 0;
10792 uint16_t priority = selected->sq_priority;
10793
10794 /* Total weight of entries with same priority */
10795 for (sq = selected; sq && priority == sq->sq_priority; sq = sq->sq_next) {
10796 weight += sq->sq_weight;
10797 N ++;
10798 }
10799
10800 tail = &selected;
10801
10802 /* Select by weighted random. Entries with weight 0 are kept in order */
10803 if (N > 1 && weight > 0) {
10804 unsigned rand = su_randint(0, weight - 1);
10805
10806 while (*tail && rand >= (*tail)->sq_weight) {
10807 rand -= (*tail)->sq_weight;
10808 tail = &(*tail)->sq_next;
10809 }
10810 }
10811
10812 /* Remove selected */
10813 if (*tail) {
10814 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", 10814, __extension__
__PRETTY_FUNCTION__); }))
;
10815
10816 /* Append at *at */
10817 sq->sq_next = *at; *at = sq; at = &sq->sq_next; if (!*at) sr->sr_tail = at;
10818
10819 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__
, 10822, "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)
10820 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__
, 10822, "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)
10821 (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__
, 10822, "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)
10822 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__
, 10822, "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)
;
10823 }
10824 }
10825
10826 /* This is not needed anymore (?) */
10827 sr->sr_current = NULL((void*)0);
10828 sq0->sq_next = sr->sr_done; sr->sr_done = sq0;
10829
10830 outgoing_resolve_next(orq);
10831}
10832
10833#if SU_HAVE_IN61
10834/* Query AAAA records */
10835static
10836int outgoing_query_aaaa(nta_outgoing_t *orq, struct sipdns_query *sq)
10837{
10838 struct sipdns_resolver *sr = orq->orq_resolver;
10839 sres_record_t **answers;
10840
10841 sr->sr_target = sq->sq_domain;
10842 sr->sr_current = sq;
10843
10844 answers = sres_cached_answers(orq->orq_agent->sa_resolver,
10845 sres_type_aaaa, sq->sq_domain);
10846
10847 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__
, 10849, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, sq->sq_domain, "AAAA", answers ? " (cached)"
: "")) : (void)0)
10848 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__
, 10849, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, sq->sq_domain, "AAAA", answers ? " (cached)"
: "")) : (void)0)
10849 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__
, 10849, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, sq->sq_domain, "AAAA", answers ? " (cached)"
: "")) : (void)0)
;
10850
10851 if (answers) {
10852 outgoing_answer_aaaa(orq, NULL((void*)0), answers);
10853 return 0;
10854 }
10855
10856 sr->sr_query = sres_query(orq->orq_agent->sa_resolver,
10857 outgoing_answer_aaaa, orq,
10858 sres_type_aaaa, sq->sq_domain);
10859
10860 return outgoing_resolving(orq);
10861}
10862
10863/* Process AAAA records */
10864static
10865void outgoing_answer_aaaa(sres_context_t *orq, sres_query_t *q,
10866 sres_record_t *answers[])
10867{
10868 struct sipdns_resolver *sr = orq->orq_resolver;
10869 su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request));
10870 struct sipdns_query *sq = sr->sr_current;
10871
10872 size_t i, j, found;
10873 char *result, **results = NULL((void*)0);
10874
10875 assert(sq)((void) sizeof ((sq) ? 1 : 0), __extension__ ({ if (sq) ; else
__assert_fail ("sq", "nta.c", 10875, __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", 10875, __extension__
__PRETTY_FUNCTION__); }))
;
10876
10877 sr->sr_query = NULL((void*)0);
10878
10879 for (i = 0, found = 0; answers && answers[i]; i++) {
10880 sres_aaaa_record_t const *aaaa = answers[i]->sr_aaaa;
10881 if (aaaa->aaaa_record->r_status == 0 &&
10882 aaaa->aaaa_record->r_type == sres_type_aaaa)
10883 found++;
10884 }
10885
10886 if (found > 1)
10887 results = su_zalloc(home, (found + 1) * (sizeof *results));
10888 else if (found)
10889 results = &result;
10890
10891 for (i = j = 0; results && answers && answers[i]; i++) {
10892 char addr[SU_ADDRSIZE(48)];
10893 sres_aaaa_record_t const *aaaa = answers[i]->sr_aaaa;
10894
10895 if (aaaa->aaaa_record->r_status ||
10896 aaaa->aaaa_record->r_type != sres_type_aaaa)
10897 continue; /* There was an error */
10898
10899 su_inet_ntopinet_ntop(AF_INET610, &aaaa->aaaa_addr, addr, sizeof(addr));
10900
10901 if (j == 0)
10902 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__
, 10903, "nta(%p): %s IN AAAA %s\n", (void *)orq, aaaa->aaaa_record
->r_name, addr)) : (void)0)
10903 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__
, 10903, "nta(%p): %s IN AAAA %s\n", (void *)orq, aaaa->aaaa_record
->r_name, addr)) : (void)0)
;
10904 else
10905 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__
, 10905, "nta(%p): AAAA %s\n", (void *)orq, addr)) : (void)0
)
;
10906
10907 assert(j < found)((void) sizeof ((j < found) ? 1 : 0), __extension__ ({ if (
j < found) ; else __assert_fail ("j < found", "nta.c", 10907
, __extension__ __PRETTY_FUNCTION__); }))
;
10908 results[j++] = su_strdup(home, addr);
10909 }
10910
10911 sres_free_answers(orq->orq_agent->sa_resolver, answers);
10912
10913 if (results)
10914 outgoing_query_results(orq, sq, results, found);
10915 else if (!q)
10916 outgoing_resolving_error(orq, SIPDNS_503_ERROR503, "DNS Error");
10917}
10918#endif /* SU_HAVE_IN6 */
10919
10920/* Query A records */
10921static
10922int outgoing_query_a(nta_outgoing_t *orq, struct sipdns_query *sq)
10923{
10924 struct sipdns_resolver *sr = orq->orq_resolver;
10925 sres_record_t **answers;
10926
10927 sr->sr_target = sq->sq_domain;
10928 sr->sr_current = sq;
10929
10930 answers = sres_cached_answers(orq->orq_agent->sa_resolver,
10931 sres_type_a, sq->sq_domain);
10932
10933 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__
, 10935, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, sq->sq_domain, "A", answers ? " (cached)" :
"")) : (void)0)
10934 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__
, 10935, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, sq->sq_domain, "A", answers ? " (cached)" :
"")) : (void)0)
10935 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__
, 10935, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, sq->sq_domain, "A", answers ? " (cached)" :
"")) : (void)0)
;
10936
10937 if (answers) {
10938 outgoing_answer_a(orq, NULL((void*)0), answers);
10939 return 0;
10940 }
10941
10942 sr->sr_query = sres_query(orq->orq_agent->sa_resolver,
10943 outgoing_answer_a, orq,
10944 sres_type_a, sq->sq_domain);
10945
10946 return outgoing_resolving(orq);
10947}
10948
10949/* Process A records */
10950static
10951void outgoing_answer_a(sres_context_t *orq, sres_query_t *q,
10952 sres_record_t *answers[])
10953{
10954 struct sipdns_resolver *sr = orq->orq_resolver;
10955 su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request));
10956 struct sipdns_query *sq = sr->sr_current;
10957
10958 int i, j, found;
10959 char *result, **results = NULL((void*)0);
10960
10961 assert(sq)((void) sizeof ((sq) ? 1 : 0), __extension__ ({ if (sq) ; else
__assert_fail ("sq", "nta.c", 10961, __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", 10961, __extension__
__PRETTY_FUNCTION__); }))
;
10962
10963 sr->sr_query = NULL((void*)0);
10964
10965 for (i = 0, found = 0; answers && answers[i]; i++) {
10966 sres_a_record_t const *a = answers[i]->sr_a;
10967 if (a->a_record->r_status == 0 &&
10968 a->a_record->r_type == sres_type_a)
10969 found++;
10970 }
10971
10972 if (found > 1)
10973 results = su_zalloc(home, (found + 1) * (sizeof *results));
10974 else if (found)
10975 results = &result;
10976
10977 for (i = j = 0; answers && answers[i]; i++) {
10978 char addr[SU_ADDRSIZE(48)];
10979 sres_a_record_t const *a = answers[i]->sr_a;
10980
10981 if (a->a_record->r_status ||
10982 a->a_record->r_type != sres_type_a)
10983 continue; /* There was an error */
10984
10985 su_inet_ntopinet_ntop(AF_INET2, &a->a_addr, addr, sizeof(addr));
10986
10987 if (j == 0)
10988 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__
, 10988, "nta: %s IN A %s\n", a->a_record->r_name, addr
)) : (void)0)
;
10989 else
10990 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__
, 10990, "nta(%p): A %s\n", (void *)orq, addr)) : (void)0)
;
10991
10992 assert(j < found)((void) sizeof ((j < found) ? 1 : 0), __extension__ ({ if (
j < found) ; else __assert_fail ("j < found", "nta.c", 10992
, __extension__ __PRETTY_FUNCTION__); }))
;
10993 results[j++] = su_strdup(home, addr);
10994 }
10995
10996 sres_free_answers(orq->orq_agent->sa_resolver, answers);
10997
10998 if (results)
10999 outgoing_query_results(orq, sq, results, found);
11000 else if (!q)
11001 outgoing_resolving_error(orq, SIPDNS_503_ERROR503, "DNS Error");
11002}
11003
11004/** Store A/AAAA query results */
11005static void
11006outgoing_query_results(nta_outgoing_t *orq,
11007 struct sipdns_query *sq,
11008 char *results[],
11009 size_t rlen)
11010{
11011 struct sipdns_resolver *sr = orq->orq_resolver;
11012
11013 if (sq->sq_type == sr->sr_a_aaaa1 &&
11014 sq->sq_type != sr->sr_a_aaaa2) {
11015 sq->sq_type = sr->sr_a_aaaa2;
11016
11017 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__
, 11018, "nta(%p): %s %s record still unresolved\n", (void *)
orq, sq->sq_domain, sq->sq_type == sres_type_a ? "A" : "AAAA"
)) : (void)0)
11018 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__
, 11018, "nta(%p): %s %s record still unresolved\n", (void *)
orq, sq->sq_domain, sq->sq_type == sres_type_a ? "A" : "AAAA"
)) : (void)0)
;
11019
11020 /*
11021 * Three possible policies:
11022 * 1) try each host for AAAA/A, then A/AAAA
11023 * 2) try everything first for AAAA/A, then everything for A/AAAA
11024 * 3) try one SRV record results for AAAA/A, then for A/AAAA,
11025 * then next SRV record
11026 */
11027
11028 /* We use now policy #1 */
11029 if (!(sq->sq_next = sr->sr_head))
11030 sr->sr_tail = &sq->sq_next;
11031 sr->sr_head = sq;
11032 }
11033 else {
11034 sq->sq_next = sr->sr_done, sr->sr_done = sq;
11035
11036 if (rlen == 0 && sq->sq_grayish)
11037 outgoing_graylist(orq, sq);
11038 }
11039
11040 if (rlen > 1)
11041 sr->sr_results = results;
11042 else
11043 sr->sr_current = NULL((void*)0);
11044
11045 if (rlen > 0) {
11046 orq->orq_resolved = 1;
11047 orq->orq_tpn->tpn_host = results[0];
11048 if (sq->sq_proto) orq->orq_tpn->tpn_proto = sq->sq_proto;
11049 if (sq->sq_port[0]) orq->orq_tpn->tpn_port = sq->sq_port;
11050 outgoing_prepare_send(orq);
11051 } else {
11052 outgoing_resolve_next(orq);
11053 }
11054}
11055
11056
11057#endif
11058
11059/* ====================================================================== */
11060/* 10) Reliable responses */
11061
11062static nta_prack_f nta_reliable_destroyed;
11063
11064/**
11065 * Check that server transaction can be used to send reliable provisional
11066 * responses.
11067 */
11068su_inlinestatic inline
11069int reliable_check(nta_incoming_t *irq)
11070{
11071 if (irq == NULL((void*)0) || irq->irq_status >= 200 || !irq->irq_agent)
11072 return 0;
11073
11074 if (irq->irq_reliable && irq->irq_reliable->rel_status >= 200)
11075 return 0;
11076
11077 /* @RSeq is initialized to nonzero when request requires/supports 100rel */
11078 if (irq->irq_rseq == 0)
11079 return 0;
11080
11081 if (irq->irq_rseq == 0xffffffffU) /* already sent >> 2**31 responses */
11082 return 0;
11083
11084 return 1;
11085}
11086
11087/** Respond reliably.
11088 *
11089 * @param irq
11090 * @param callback
11091 * @param rmagic
11092 * @param status
11093 * @param phrase
11094 * @param tag, value, ..
11095 */
11096nta_reliable_t *nta_reliable_treply(nta_incoming_t *irq,
11097 nta_prack_f *callback,
11098 nta_reliable_magic_t *rmagic,
11099 int status, char const *phrase,
11100 tag_type_t tag,
11101 tag_value_t value, ...)
11102{
11103 ta_list ta;
11104 msg_t *msg;
11105 sip_t *sip;
11106 nta_reliable_t *retval = NULL((void*)0);
11107
11108 if (!reliable_check(irq) || (status <= 100 || status >= 200))
11109 return NULL((void*)0);
11110
11111 msg = nta_msg_create(irq->irq_agent, 0);
11112 sip = sip_object(msg);
11113
11114 if (!sip)
11115 return NULL((void*)0);
11116
11117 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)
;
11118
11119 if (0 > nta_incoming_complete_response(irq, msg, status, phrase,
11120 ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
))
11121 msg_destroy(msg);
11122 else if (!(retval = reliable_mreply(irq, callback, rmagic, msg, sip)))
11123 msg_destroy(msg);
11124
11125 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))
;
11126
11127 return retval;
11128}
11129
11130/** Respond reliably with @a msg.
11131 *
11132 * @note
11133 * The stack takes over the ownership of @a msg. (It is destroyed even if
11134 * sending the response fails.)
11135 *
11136 * @param irq
11137 * @param callback
11138 * @param rmagic
11139 * @param msg
11140 */
11141nta_reliable_t *nta_reliable_mreply(nta_incoming_t *irq,
11142 nta_prack_f *callback,
11143 nta_reliable_magic_t *rmagic,
11144 msg_t *msg)
11145{
11146 sip_t *sip = sip_object(msg);
11147
11148 if (!reliable_check(irq)) {
11149 msg_destroy(msg);
11150 return NULL((void*)0);
11151 }
11152
11153 if (sip == NULL((void*)0) || !sip->sip_status || sip->sip_status->st_status <= 100) {
11154 msg_destroy(msg);
11155 return NULL((void*)0);
11156 }
11157
11158 if (sip->sip_status->st_status >= 200) {
11159 incoming_final_failed(irq, msg);
11160 return NULL((void*)0);
11161 }
11162
11163 return reliable_mreply(irq, callback, rmagic, msg, sip);
11164}
11165
11166static
11167nta_reliable_t *reliable_mreply(nta_incoming_t *irq,
11168 nta_prack_f *callback,
11169 nta_reliable_magic_t *rmagic,
11170 msg_t *msg,
11171 sip_t *sip)
11172{
11173 nta_reliable_t *rel;
11174 nta_agent_t *agent;
11175
11176 agent = irq->irq_agent;
11177
11178 if (callback == NULL((void*)0))
11179 callback = nta_reliable_destroyed;
11180
11181 rel = su_zalloc(agent->sa_home, sizeof(*rel));
11182 if (rel) {
11183 rel->rel_irq = irq;
11184 rel->rel_callback = callback;
11185 rel->rel_magic = rmagic;
11186 rel->rel_unsent = msg;
11187 rel->rel_status = sip->sip_status->st_status;
11188 rel->rel_precious = sip->sip_payload != NULL((void*)0);
11189 rel->rel_next = irq->irq_reliable;
11190
11191 /*
11192 * If there already is a un-pr-acknowledged response, queue this one
11193 * until at least one response is pr-acknowledged.
11194 */
11195 if (irq->irq_reliable &&
11196 (irq->irq_reliable->rel_next == NULL((void*)0) ||
11197 irq->irq_reliable->rel_rseq == 0)) {
11198 return irq->irq_reliable = rel;
11199 }
11200
11201 if (reliable_send(irq, rel, msg_ref_create(msg), sip) < 0) {
11202 msg_destroy(msg);
11203 su_free(agent->sa_home, rel);
11204 return NULL((void*)0);
11205 }
11206
11207 irq->irq_reliable = rel;
11208
11209 return callback ? rel : (nta_reliable_t *)-1;
11210 }
11211
11212 msg_destroy(msg);
11213 return NULL((void*)0);
11214}
11215
11216static
11217int reliable_send(nta_incoming_t *irq,
11218 nta_reliable_t *rel,
11219 msg_t *msg,
11220 sip_t *sip)
11221{
11222 nta_agent_t *sa = irq->irq_agent;
11223 su_home_t *home = msg_home(msg)((su_home_t*)(msg));
11224 sip_rseq_t rseq[1];
11225 sip_rseq_init(rseq);
11226
11227 if (sip->sip_require)
11228 msg_header_replace_param(home, sip->sip_require->k_common, "100rel");
11229 else
11230 sip_add_make(msg, sip, sip_require_class, "100rel");
11231
11232 rel->rel_rseq = rseq->rs_response = irq->irq_rseq;
11233 sip_add_dup(msg, sip, (sip_header_t *)rseq);
11234
11235 if (!sip->sip_rseq || incoming_reply(irq, msg, sip) < 0) {
11236 msg_destroy(msg);
11237 return -1;
11238 }
11239
11240 irq->irq_rseq++;
11241
11242 if (irq->irq_queue == sa->sa_in.preliminary)
11243 /* Make sure we are moved to the tail */
11244 incoming_remove(irq);
11245
11246 incoming_queue(sa->sa_in.preliminary, irq); /* P1 */
11247 incoming_set_timer(irq, sa->sa_t1); /* P2 */
11248
11249 return 0;
11250}
11251
11252/** Queue final response when there are unsent precious preliminary responses */
11253static
11254int reliable_final(nta_incoming_t *irq, msg_t *msg, sip_t *sip)
11255{
11256 nta_reliable_t *r;
11257 unsigned already_in_callback;
11258 /*
11259 * We delay sending final response if it's 2XX and
11260 * an unpracked reliable response contains session description
11261 */
11262 /* Get last unpracked response from queue */
11263 if (sip->sip_status->st_status < 300)
11264 for (r = irq->irq_reliable; r; r = r->rel_next)
11265 if (r->rel_unsent && r->rel_precious) {
11266 /* Delay sending 2XX */
11267 reliable_mreply(irq, NULL((void*)0), NULL((void*)0), msg, sip);
11268 return 0;
11269 }
11270
11271 /* Flush unsent responses. */
11272 already_in_callback = irq->irq_in_callback;
11273 irq->irq_in_callback = 1;
11274 reliable_flush(irq);
11275 irq->irq_in_callback = already_in_callback;
11276
11277 if (!already_in_callback && irq->irq_terminated && irq->irq_destroyed) {
11278 incoming_free(irq);
11279 msg_destroy(msg);
11280 return 0;
11281 }
11282
11283 return 1;
11284}
11285
11286/** Get latest reliably sent response */
11287static
11288msg_t *reliable_response(nta_incoming_t *irq)
11289{
11290 nta_reliable_t *r, *rel;
11291
11292 /* Get last unpracked response from queue */
11293 for (rel = NULL((void*)0), r = irq->irq_reliable; r; r = r->rel_next)
11294 if (!r->rel_pracked)
11295 rel = r;
11296
11297 assert(rel)((void) sizeof ((rel) ? 1 : 0), __extension__ ({ if (rel) ; else
__assert_fail ("rel", "nta.c", 11297, __extension__ __PRETTY_FUNCTION__
); }))
;
11298
11299 return rel->rel_unsent;
11300}
11301
11302/* Find un-PRACKed responses */
11303static
11304nta_reliable_t *reliable_find(nta_agent_t const *agent,
11305 sip_t const *sip)
11306{
11307 incoming_htable_t const *iht = agent->sa_incoming;
11308 nta_incoming_t *irq, **ii;
11309 sip_call_id_t const *i = sip->sip_call_id;
11310 sip_rack_t const *rack = sip->sip_rack;
11311 hash_value_t hash = NTA_HASH(i, rack->ra_cseq)((i)->i_hash + 26839U * (uint32_t)(rack->ra_cseq));
11312
11313 /* XXX - add own hash table for 100rel */
11314
11315 for (ii = incoming_htable_hash(iht, hash);
11316 (irq = *ii);
11317 ii = incoming_htable_next(iht, ii)) {
11318
11319 if (hash == irq->irq_hash &&
11320 irq->irq_call_id->i_hash == i->i_hash &&
11321 irq->irq_cseq->cs_seq == rack->ra_cseq &&
11322 irq->irq_method == sip_method_invite &&
11323 strcmp(irq->irq_call_id->i_id, i->i_id) == 0 &&
11324 (irq->irq_to->a_tag == NULL((void*)0) ||
11325 su_casematch(irq->irq_to->a_tag, sip->sip_to->a_tag)) &&
11326 su_casematch(irq->irq_from->a_tag, sip->sip_from->a_tag)) {
11327
11328 nta_reliable_t const *rel;
11329
11330 /* Found matching INVITE */
11331 for (rel = irq->irq_reliable; rel; rel = rel->rel_next)
11332 if (rel->rel_rseq == rack->ra_response)
11333 return (nta_reliable_t *)rel;
11334
11335 }
11336 }
11337
11338 return NULL((void*)0);
11339}
11340
11341/** Process incoming PRACK with matching @RAck field */
11342static
11343int reliable_recv(nta_reliable_t *rel, msg_t *msg, sip_t *sip, tport_t *tp)
11344{
11345 nta_incoming_t *irq = rel->rel_irq;
11346 nta_incoming_t *pr_irq;
11347 int status;
11348
11349 rel->rel_pracked = 1;
11350 msg_ref_destroy(rel->rel_unsent), rel->rel_unsent = NULL((void*)0);
11351
11352 pr_irq = incoming_create(irq->irq_agent, msg, sip, tp, irq->irq_tag);
11353 if (!pr_irq) {
11354 mreply(irq->irq_agent, NULL((void*)0),
11355 SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error, msg,
11356 tp, 0, 0, NULL((void*)0),
11357 TAG_END()(tag_type_t)0, (tag_value_t)0);
11358 return 0;
11359 }
11360
11361 if (irq->irq_status < 200) {
11362 incoming_queue(irq->irq_agent->sa_in.proceeding, irq); /* Reset P1 */
11363 incoming_reset_timer(irq); /* Reset P2 */
11364 }
11365
11366 irq->irq_in_callback = pr_irq->irq_in_callback = 1;
11367 status = rel->rel_callback(rel->rel_magic, rel, pr_irq, sip); rel = NULL((void*)0);
11368 irq->irq_in_callback = pr_irq->irq_in_callback = 0;
11369
11370 if (pr_irq->irq_completed) { /* Already sent final response */
11371 if (pr_irq->irq_terminated && pr_irq->irq_destroyed)
11372 incoming_free(pr_irq);
11373 }
11374 else if (status != 0) {
11375 if (status < 200 || status > 299) {
11376 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__
, 11377, "nta_reliable(): invalid status %03d from callback\n"
, status)) : (void)0)
11377 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__
, 11377, "nta_reliable(): invalid status %03d from callback\n"
, status)) : (void)0)
;
11378 status = 200;
11379 }
11380 nta_incoming_treply(pr_irq, status, "OK", TAG_END()(tag_type_t)0, (tag_value_t)0);
11381 nta_incoming_destroy(pr_irq);
11382 }
11383
11384 /* If there are queued unsent reliable responses, send them all. */
11385 while (irq->irq_reliable && irq->irq_reliable->rel_rseq == 0) {
11386 nta_reliable_t *r;
11387
11388 for (r = irq->irq_reliable; r; r = r->rel_next)
11389 if (r->rel_rseq == 0)
11390 rel = r;
11391
11392 msg = rel->rel_unsent, sip = sip_object(msg);
11393
11394 if (sip->sip_status->st_status < 200) {
11395 if (reliable_send(irq, rel, msg_ref_create(msg), sip) < 0) {
11396 assert(!"send reliable response")((void) sizeof ((!"send reliable response") ? 1 : 0), __extension__
({ if (!"send reliable response") ; else __assert_fail ("!\"send reliable response\""
, "nta.c", 11396, __extension__ __PRETTY_FUNCTION__); }))
;
11397 }
11398 }
11399 else {
11400 /*
11401 * XXX
11402 * Final response should be delayed until a reliable provisional
11403 * response has been pracked
11404 */
11405 rel->rel_unsent = NULL((void*)0), rel->rel_rseq = (uint32_t)-1;
11406 if (incoming_reply(irq, msg, sip) < 0) {
11407 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", 11407, __extension__
__PRETTY_FUNCTION__); }))
;
11408 }
11409 }
11410 }
11411
11412 return 0;
11413}
11414
11415/** Flush unacknowledged and unsent reliable responses */
11416void reliable_flush(nta_incoming_t *irq)
11417{
11418 nta_reliable_t *r, *rel;
11419
11420 do {
11421 for (r = irq->irq_reliable, rel = NULL((void*)0); r; r = r->rel_next)
11422 if (r->rel_unsent)
11423 rel = r;
11424
11425 if (rel) {
11426 rel->rel_pracked = 1;
11427 msg_ref_destroy(rel->rel_unsent), rel->rel_unsent = NULL((void*)0);
11428 rel->rel_callback(rel->rel_magic, rel, NULL((void*)0), NULL((void*)0));
11429 }
11430 } while (rel);
11431}
11432
11433void reliable_timeout(nta_incoming_t *irq, int timeout)
11434{
11435 if (timeout)
11436 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__
, 11436, "nta: response timeout with %u\n", irq->irq_status
)) : (void)0)
;
11437
11438 irq->irq_in_callback = 1;
11439
11440 reliable_flush(irq);
11441
11442 if (irq->irq_callback)
11443 irq->irq_callback(irq->irq_magic, irq, NULL((void*)0));
11444
11445 irq->irq_in_callback = 0;
11446
11447 if (!timeout)
11448 return;
11449
11450 if (irq->irq_completed && irq->irq_destroyed)
11451 incoming_free(irq), irq = NULL((void*)0);
11452 else if (irq->irq_status < 200)
11453 nta_incoming_treply(irq, 503, "Reliable Response Time-Out", TAG_END()(tag_type_t)0, (tag_value_t)0);
11454}
11455
11456#if 0 /* Not needed, yet. */
11457/** Use this callback when normal leg callback is supposed to
11458 * process incoming PRACK requests
11459 */
11460int nta_reliable_leg_prack(nta_reliable_magic_t *magic,
11461 nta_reliable_t *rel,
11462 nta_incoming_t *irq,
11463 sip_t const *sip)
11464{
11465 nta_agent_t *agent;
11466 nta_leg_t *leg;
11467 char const *method_name;
11468 url_t url[1];
11469 int retval;
11470
11471 if (irq == NULL((void*)0) || sip == NULL((void*)0) || rel == NULL((void*)0) ||
11472 sip_object(irq->irq_request) != sip)
11473 return 500;
11474
11475 agent = irq->irq_agent;
11476 method_name = sip->sip_request->rq_method_name;
11477 *url = *sip->sip_request->rq_url; url->url_params = NULL((void*)0);
11478 agent_aliases(agent, url, irq->irq_tport); /* canonize urls */
11479
11480 if ((leg = leg_find(irq->irq_agent,
11481 method_name, url,
11482 sip->sip_call_id,
11483 sip->sip_from->a_tag,
11484 sip->sip_to->a_tag))) {
11485 /* Use existing dialog */
11486 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__
, 11488, "nta: %s (%u) %s\n", method_name, sip->sip_cseq->
cs_seq, "PRACK processed by default callback, too")) : (void)
0)
11487 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__
, 11488, "nta: %s (%u) %s\n", method_name, sip->sip_cseq->
cs_seq, "PRACK processed by default callback, too")) : (void)
0)
11488 "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__
, 11488, "nta: %s (%u) %s\n", method_name, sip->sip_cseq->
cs_seq, "PRACK processed by default callback, too")) : (void)
0)
;
11489 retval = leg->leg_callback(leg->leg_magic, leg, irq, sip);
11490 }
11491 else {
11492 retval = 500;
11493 }
11494
11495 nta_reliable_destroy(rel);
11496
11497 return retval;
11498}
11499#endif
11500
11501/** Destroy a reliable response.
11502 *
11503 * Mark a reliable response object for destroyal and free it if possible.
11504 */
11505void nta_reliable_destroy(nta_reliable_t *rel)
11506{
11507 if (rel == NULL((void*)0) || rel == NONE((void *)-1))
11508 return;
11509
11510 if (rel->rel_callback == nta_reliable_destroyed)
11511 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__
, 11511, "%s(%p): %s\n", __func__, (void *)rel, "already destroyed"
)) : (void)0)
;
11512
11513 rel->rel_callback = nta_reliable_destroyed;
11514
11515 if (rel->rel_response)
11516 return;
11517
11518 nta_reliable_destroyed(NULL((void*)0), rel, NULL((void*)0), NULL((void*)0));
11519}
11520
11521/** Free and unallocate the nta_reliable_t structure. */
11522static
11523int nta_reliable_destroyed(nta_reliable_magic_t *rmagic,
11524 nta_reliable_t *rel,
11525 nta_incoming_t *prack,
11526 sip_t const *sip)
11527{
11528 nta_reliable_t **prev;
11529
11530 assert(rel)((void) sizeof ((rel) ? 1 : 0), __extension__ ({ if (rel) ; else
__assert_fail ("rel", "nta.c", 11530, __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"
, 11530, __extension__ __PRETTY_FUNCTION__); }))
;
11531
11532 for (prev = &rel->rel_irq->irq_reliable; *prev; prev = &(*prev)->rel_next)
11533 if (*prev == rel)
11534 break;
11535
11536 if (!*prev) {
11537 assert(*prev)((void) sizeof ((*prev) ? 1 : 0), __extension__ ({ if (*prev)
; else __assert_fail ("*prev", "nta.c", 11537, __extension__
__PRETTY_FUNCTION__); }))
;
11538 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__
, 11538, "%s(%p): %s\n", __func__, (void *)rel, "not linked")
) : (void)0)
;
11539 return 200;
11540 }
11541
11542 *prev = rel->rel_next;
11543
11544 if (rel->rel_unsent)
11545 msg_destroy(rel->rel_unsent), rel->rel_unsent = NULL((void*)0);
11546
11547 su_free(rel->rel_irq->irq_agent->sa_home, rel);
11548
11549 return 200;
11550}
11551
11552/** Validate a reliable response. */
11553int outgoing_recv_reliable(nta_outgoing_t *orq,
11554 msg_t *msg,
11555 sip_t *sip)
11556{
11557 short status = sip->sip_status->st_status;
11558 char const *phrase = sip->sip_status->st_phrase;
11559 uint32_t rseq = sip->sip_rseq->rs_response;
11560
11561 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__
, 11562, "nta: %03u %s is reliably received with RSeq: %u\n",
status, phrase, rseq)) : (void)0)
11562 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__
, 11562, "nta: %03u %s is reliably received with RSeq: %u\n",
status, phrase, rseq)) : (void)0)
;
11563
11564 /* Cannot handle reliable responses unless we have a full dialog */
11565 if (orq->orq_rseq == 0 && !orq->orq_to->a_tag) {
11566 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__
, 11567, "nta: %03u %s with initial RSeq: %u outside dialog\n"
, status, phrase, rseq)) : (void)0)
11567 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__
, 11567, "nta: %03u %s with initial RSeq: %u outside dialog\n"
, status, phrase, rseq)) : (void)0)
;
11568 return 0;
11569 }
11570
11571 if (rseq <= orq->orq_rseq) {
11572 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__
, 11573, "nta: %03u %s already received (RSeq: %u, expecting %u)\n"
, status, phrase, rseq, orq->orq_rseq + 1)) : (void)0)
11573 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__
, 11573, "nta: %03u %s already received (RSeq: %u, expecting %u)\n"
, status, phrase, rseq, orq->orq_rseq + 1)) : (void)0)
;
11574 return -1;
11575 }
11576
11577 if (orq->orq_rseq && orq->orq_rseq + 1 != rseq) {
11578 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__
, 11580, "nta: %03d %s is not expected (RSeq: %u, expecting %u)\n"
, status, sip->sip_status->st_phrase, rseq, orq->orq_rseq
+ 1)) : (void)0)
11579 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__
, 11580, "nta: %03d %s is not expected (RSeq: %u, expecting %u)\n"
, status, sip->sip_status->st_phrase, rseq, orq->orq_rseq
+ 1)) : (void)0)
11580 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__
, 11580, "nta: %03d %s is not expected (RSeq: %u, expecting %u)\n"
, status, sip->sip_status->st_phrase, rseq, orq->orq_rseq
+ 1)) : (void)0)
;
11581 return -1;
11582 }
11583
11584 return 0;
11585}
11586
11587/** Create a tagged fork of outgoing request.
11588 *
11589 * When a dialog-creating INVITE request is forked, each response from
11590 * diffent fork will create an early dialog with a distinct tag in @To
11591 * header. When each fork should be handled separately, a tagged INVITE
11592 * request can be used. It will only receive responses from the specified
11593 * fork. Please note that the tagged transaction should be terminated with
11594 * the final response from another fork, too.
11595 *
11596 * @param orq
11597 * @param callback
11598 * @param magic
11599 * @param to_tag
11600 * @param rseq
11601 *
11602 * @bug Fix the memory leak - either one of the requests is left unreleased
11603 * for ever.
11604 */
11605nta_outgoing_t *nta_outgoing_tagged(nta_outgoing_t *orq,
11606 nta_response_f *callback,
11607 nta_outgoing_magic_t *magic,
11608 char const *to_tag,
11609 sip_rseq_t const *rseq)
11610{
11611 nta_agent_t *agent;
11612 su_home_t *home;
11613 nta_outgoing_t *tagged;
11614 sip_to_t *to;
11615
11616 if (orq == NULL((void*)0) || to_tag == NULL((void*)0))
11617 return NULL((void*)0);
11618
11619 if (orq->orq_to->a_tag) {
11620 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__
, 11621, "%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)
11621 (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__
, 11621, "%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)
;
11622 return NULL((void*)0);
11623 }
11624 if (orq->orq_method != sip_method_invite) {
11625 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__
, 11626, "%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)
11626 (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__
, 11626, "%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)
;
11627 return NULL((void*)0);
11628 }
11629 if (orq->orq_status < 100) {
11630 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__
, 11631, "%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)
11631 (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__
, 11631, "%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)
;
11632 return NULL((void*)0);
11633 }
11634
11635 assert(orq->orq_agent)((void) sizeof ((orq->orq_agent) ? 1 : 0), __extension__ (
{ if (orq->orq_agent) ; else __assert_fail ("orq->orq_agent"
, "nta.c", 11635, __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", 11635, __extension__ __PRETTY_FUNCTION__); }))
;
11636
11637 agent = orq->orq_agent;
11638 tagged = su_zalloc(agent->sa_home, sizeof(*tagged));
11639
11640 home = msg_home((msg_t *)orq->orq_request)((su_home_t*)((msg_t *)orq->orq_request));
11641
11642 tagged->orq_hash = orq->orq_hash;
11643 tagged->orq_agent = orq->orq_agent;
11644 tagged->orq_callback = callback;
11645 tagged->orq_magic = magic;
11646
11647 tagged->orq_method = orq->orq_method;
11648 tagged->orq_method_name = orq->orq_method_name;
11649 tagged->orq_url = orq->orq_url;
11650 tagged->orq_from = orq->orq_from;
11651
11652 sip_to_tag(home, to = sip_to_copy(home, orq->orq_to), to_tag);
11653
11654 tagged->orq_to = to;
11655 tagged->orq_tag = to->a_tag;
11656 tagged->orq_cseq = orq->orq_cseq;
11657 tagged->orq_call_id = orq->orq_call_id;
11658
11659 tagged->orq_request = msg_ref_create(orq->orq_request);
11660 tagged->orq_response = msg_ref_create(orq->orq_response);
11661
11662 tagged->orq_status = orq->orq_status;
11663 tagged->orq_via_added = orq->orq_via_added;
11664 tagged->orq_prepared = orq->orq_prepared;
11665 tagged->orq_reliable = orq->orq_reliable;
11666 tagged->orq_sips = orq->orq_sips;
11667 tagged->orq_uas = orq->orq_uas;
11668 tagged->orq_pass_100 = orq->orq_pass_100;
11669 tagged->orq_must_100rel = orq->orq_must_100rel;
11670 tagged->orq_100rel = orq->orq_100rel;
11671 tagged->orq_route = orq->orq_route;
11672 *tagged->orq_tpn = *orq->orq_tpn;
11673 tagged->orq_tport = tport_ref(orq->orq_tport);
11674 if (orq->orq_cc)
11675 tagged->orq_cc = nta_compartment_ref(orq->orq_cc);
11676 tagged->orq_branch = orq->orq_branch;
11677 tagged->orq_via_branch = orq->orq_via_branch;
11678
11679 if (tagged->orq_uas) {
11680 tagged->orq_forking = orq;
11681 tagged->orq_forks = orq->orq_forks;
11682 tagged->orq_forked = 1;
11683 orq->orq_forks = tagged;
11684 }
11685
11686 outgoing_insert(agent, tagged);
11687
11688 return tagged;
11689}
11690
11691/**PRACK a provisional response.
11692 *
11693 * Create and send a PRACK request used to acknowledge a provisional
11694 * response.
11695 *
11696 * The request is sent using the route of the original request @a oorq.
11697 *
11698 * When NTA receives response to the prack request, it invokes the @a
11699 * callback function.
11700 *
11701 * @param leg dialog object
11702 * @param oorq original transaction request
11703 * @param callback callback function (may be @c NULL)
11704 * @param magic application context pointer
11705 * @param route_url optional URL used to route transaction requests
11706 * @param resp (optional) response message to be acknowledged
11707 * @param tag,value,... optional
11708 *
11709 * @return
11710 * If successful, return a pointer to newly created client transaction
11711 * object for PRACK request, NULL otherwise.
11712 *
11713 * @sa
11714 * nta_outgoing_tcreate(), nta_outgoing_tcancel(), nta_outgoing_destroy().
11715 */
11716nta_outgoing_t *nta_outgoing_prack(nta_leg_t *leg,
11717 nta_outgoing_t *oorq,
11718 nta_response_f *callback,
11719 nta_outgoing_magic_t *magic,
11720 url_string_t const *route_url,
11721 sip_t const *resp,
11722 tag_type_t tag, tag_value_t value, ...)
11723{
11724 ta_list ta;
11725 msg_t *msg;
11726 su_home_t *home;
11727 sip_t *sip;
11728 sip_to_t const *to = NULL((void*)0);
11729 sip_route_t *route = NULL((void*)0), r0[1];
11730 nta_outgoing_t *orq = NULL((void*)0);
11731 sip_rack_t *rack = NULL((void*)0), rack0[1];
11732
11733 if (!leg || !oorq) {
11734 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__
, 11734, "%s: invalid arguments\n", __func__)) : (void)0)
;
11735 return NULL((void*)0);
11736 }
11737
11738 sip_rack_init(rack0);
11739
11740 if (resp) {
11741 if (!resp->sip_status) {
11742 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__
, 11742, "%s: invalid arguments\n", __func__)) : (void)0)
;
11743 return NULL((void*)0);
11744 }
11745
11746 if (resp->sip_status->st_status <= 100 ||
11747 resp->sip_status->st_status >= 200) {
11748 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__
, 11749, "%s: %u response cannot be PRACKed\n", __func__, resp
->sip_status->st_status)) : (void)0)
11749 __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__
, 11749, "%s: %u response cannot be PRACKed\n", __func__, resp
->sip_status->st_status)) : (void)0)
;
11750 return NULL((void*)0);
11751 }
11752
11753 if (!resp->sip_rseq) {
11754 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__
, 11755, "%s: %u response missing RSeq\n", __func__, resp->
sip_status->st_status)) : (void)0)
11755 __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__
, 11755, "%s: %u response missing RSeq\n", __func__, resp->
sip_status->st_status)) : (void)0)
;
11756 return NULL((void*)0);
11757 }
11758
11759 if (resp->sip_rseq->rs_response <= oorq->orq_rseq) {
11760 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__
, 11761, "%s: %u response RSeq does not match received RSeq\n"
, __func__, resp->sip_status->st_status)) : (void)0)
11761 __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__
, 11761, "%s: %u response RSeq does not match received RSeq\n"
, __func__, resp->sip_status->st_status)) : (void)0)
;
11762 return NULL((void*)0);
11763 }
11764 if (!oorq->orq_must_100rel &&
11765 !sip_has_feature(resp->sip_require, "100rel")) {
11766 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__
, 11767, "%s: %u response does not require 100rel\n", __func__
, resp->sip_status->st_status)) : (void)0)
11767 __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__
, 11767, "%s: %u response does not require 100rel\n", __func__
, resp->sip_status->st_status)) : (void)0)
;
11768 return NULL((void*)0);
11769 }
11770
11771 if (!resp->sip_to->a_tag) {
11772 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__
, 11773, "%s: %u response has no To tag\n", __func__, resp->
sip_status->st_status)) : (void)0)
11773 __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__
, 11773, "%s: %u response has no To tag\n", __func__, resp->
sip_status->st_status)) : (void)0)
;
11774 return NULL((void*)0);
11775 }
11776 if (su_strcasecmp(resp->sip_to->a_tag, leg->leg_remote->a_tag) ||
11777 su_strcasecmp(resp->sip_to->a_tag, oorq->orq_to->a_tag)) {
11778 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__
, 11779, "%s: %u response To tag does not agree with dialog tag\n"
, __func__, resp->sip_status->st_status)) : (void)0)
11779 __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__
, 11779, "%s: %u response To tag does not agree with dialog tag\n"
, __func__, resp->sip_status->st_status)) : (void)0)
;
11780 return NULL((void*)0);
11781 }
11782
11783 to = resp->sip_to;
11784 rack = rack0;
11785
11786 rack->ra_response = resp->sip_rseq->rs_response;
11787 rack->ra_cseq = resp->sip_cseq->cs_seq;
11788 rack->ra_method = resp->sip_cseq->cs_method;
11789 rack->ra_method_name = resp->sip_cseq->cs_method_name;
11790 }
11791
11792 msg = nta_msg_create(leg->leg_agent, 0);
11793 sip = sip_object(msg); home = msg_home(msg)((su_home_t*)(msg));
11794
11795 if (!sip)
11796 return NULL((void*)0);
11797
11798 if (!leg->leg_route && resp) {
11799 /* Insert contact into route */
11800 if (resp->sip_contact) {
11801 sip_route_init(r0)->r_url[0] = resp->sip_contact->m_url[0];
11802 route = sip_route_dup(home, r0);
11803 }
11804
11805 /* Reverse record route */
11806 if (resp->sip_record_route) {
11807 sip_route_t *r, *r_next;
11808 for (r = sip_route_dup(home, resp->sip_record_route); r; r = r_next) {
11809 r_next = r->r_next, r->r_next = route, route = r;
11810 }
11811 }
11812 }
11813
11814 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)
;
11815
11816 if (!resp) {
11817 tagi_t const *t;
11818
11819 if ((t = tl_find(ta_args(ta)(ta).tl, ntatag_rseq)) && t->t_value) {
11820 rack = rack0;
11821 rack->ra_response = (uint32_t)t->t_value;
11822 }
11823
11824 if (rack) {
11825 rack->ra_cseq = oorq->orq_cseq->cs_seq;
11826 rack->ra_method = oorq->orq_cseq->cs_method;
11827 rack->ra_method_name = oorq->orq_cseq->cs_method_name;
11828 }
11829 }
11830
11831 if (sip_add_tl(msg, sip,
11832 TAG_IF(rack, SIPTAG_RACK(rack))!(rack) ? tag_skip : siptag_rack, siptag_rack_v(rack),
11833 TAG_IF(to, SIPTAG_TO(to))!(to) ? tag_skip : siptag_to, siptag_to_v(to),
11834 ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
) < 0)
11835 ;
11836 else if (route && sip_add_dup(msg, sip, (sip_header_t *)route) < 0)
11837 ;
11838 else if (!sip->sip_rack)
11839 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__
, 11839, "%s: RAck header missing\n", __func__)) : (void)0)
;
11840 else if (nta_msg_request_complete(msg, leg,
11841 SIP_METHOD_PRACKsip_method_prack, "PRACK",
11842 (url_string_t *)oorq->orq_url) < 0)
11843 ;
11844 else
11845 orq = outgoing_create(leg->leg_agent, callback, magic,
11846 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
);
11847
11848 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))
;
11849
11850 if (!orq)
11851 msg_destroy(msg);
11852 else if (rack)
11853 oorq->orq_rseq = rack->ra_response;
11854 else if (sip->sip_rack)
11855 oorq->orq_rseq = sip->sip_rack->ra_response;
11856
11857 return orq;
11858}
11859
11860/** Get @RSeq value stored with client transaction. */
11861uint32_t nta_outgoing_rseq(nta_outgoing_t const *orq)
11862{
11863 return orq ? orq->orq_rseq : 0;
11864}
11865
11866/** Set @RSeq value stored with client transaction.
11867 *
11868 * @return 0 if rseq was set successfully
11869 * @return -1 if rseq is invalid or orq is NULL.
11870 */
11871int nta_outgoing_setrseq(nta_outgoing_t *orq, uint32_t rseq)
11872{
11873 if (orq && orq->orq_rseq <= rseq) {
11874 orq->orq_rseq = rseq;
11875 return 0;
11876 }
11877
11878 return -1;
11879}
11880
11881/* ------------------------------------------------------------------------ */
11882/* 11) SigComp handling and public transport interface */
11883
11884#include <sofia-sip/nta_tport.h>
11885
11886/** Return the master transport for the agent.
11887 *
11888 * @NEW_1_12_11
11889 */
11890tport_t *
11891nta_agent_tports(nta_agent_t *agent)
11892{
11893 return agent ? agent->sa_tports : NULL((void*)0);
11894}
11895
11896su_inlinestatic inline tport_t *
11897nta_transport_(nta_agent_t *agent,
11898 nta_incoming_t *irq,
11899 msg_t *msg)
11900{
11901 if (irq)
11902 return irq->irq_tport;
11903 else if (agent && msg)
11904 return tport_delivered_by(agent->sa_tports, msg);
11905
11906 errno(*__errno_location ()) = EINVAL22;
11907 return NULL((void*)0);
11908}
11909
11910
11911/** Return a new reference to the transaction transport.
11912 *
11913 * @note The referenced transport must be unreferenced with tport_unref()
11914 */
11915tport_t *
11916nta_incoming_transport(nta_agent_t *agent,
11917 nta_incoming_t *irq,
11918 msg_t *msg)
11919{
11920 return tport_ref(nta_transport_(agent, irq, msg));
11921}
11922
11923nta_compressor_t *nta_agent_init_sigcomp(nta_agent_t *sa)
11924{
11925 if (!nta_compressor_vtable || !sa)
11926 return NULL((void*)0);
11927
11928 if (sa->sa_compressor == NULL((void*)0)) {
11929 char const * const *l = sa->sa_sigcomp_option_list;
11930 nta_compressor_t *comp;
11931 comp = nta_compressor_vtable->ncv_init_agent(sa, l);
11932 sa->sa_compressor = comp;
11933 }
11934
11935 return sa->sa_compressor;
11936}
11937
11938void nta_agent_deinit_sigcomp(nta_agent_t *sa)
11939{
11940 if (nta_compressor_vtable && sa && sa->sa_compressor) {
11941 nta_compressor_vtable->ncv_deinit_agent(sa, sa->sa_compressor);
11942 sa->sa_compressor = NULL((void*)0);
11943 }
11944}
11945
11946struct sigcomp_compartment *
11947nta_incoming_compartment(nta_incoming_t *irq)
11948{
11949 if (nta_compressor_vtable && irq && irq->irq_cc)
11950 return nta_compressor_vtable->ncv_compartment_ref(irq->irq_cc);
11951 else
11952 return NULL((void*)0);
11953}
11954
11955tport_t *
11956nta_outgoing_transport(nta_outgoing_t *orq)
11957{
11958 if (orq)
11959 return tport_ref(orq->orq_tport);
11960 else
11961 return NULL((void*)0);
11962}
11963
11964
11965struct sigcomp_compartment *
11966nta_outgoing_compartment(nta_outgoing_t *orq)
11967{
11968 if (nta_compressor_vtable && orq && orq->orq_cc)
11969 return nta_compressor_vtable->ncv_compartment_ref(orq->orq_cc);
11970 else
11971 return NULL((void*)0);
11972}
11973
11974
11975struct sigcomp_compartment *
11976nta_compartment_ref(struct sigcomp_compartment *cc)
11977{
11978 if (nta_compressor_vtable)
11979 return nta_compressor_vtable->ncv_compartment_ref(cc);
11980 else
11981 return NULL((void*)0);
11982}
11983
11984void
11985nta_compartment_decref(struct sigcomp_compartment **pcc)
11986{
11987 if (nta_compressor_vtable && pcc && *pcc)
11988 nta_compressor_vtable->ncv_compartment_unref(*pcc), *pcc = NULL((void*)0);
11989}
11990
11991
11992/** Get compartment for connection, create it when needed. */
11993static
11994struct sigcomp_compartment *
11995agent_compression_compartment(nta_agent_t *sa,
11996 tport_t *tp,
11997 tp_name_t const *tpn,
11998 int new_if_needed)
11999{
12000 if (nta_compressor_vtable) {
12001 char const * const *l = sa->sa_sigcomp_option_list;
12002 return nta_compressor_vtable->
12003 ncv_compartment(sa, tp, sa->sa_compressor, tpn, l, new_if_needed);
12004 }
12005 else
12006 return NULL((void*)0);
12007}
12008
12009static
12010int agent_accept_compressed(nta_agent_t *sa, msg_t *msg,
12011 struct sigcomp_compartment *cc)
12012{
12013 if (nta_compressor_vtable) {
12014 nta_compressor_t *msc = sa->sa_compressor;
12015 tport_compressor_t *sc = NULL((void*)0);
12016 if (tport_delivered_with_comp(sa->sa_tports, msg, &sc) < 0)
12017 return 0;
12018 return nta_compressor_vtable->ncv_accept_compressed(sa, msc, sc, msg, cc);
12019 }
12020 else
12021 return 0;
12022}
12023
12024/** Close compressor (lose its state). */
12025static
12026int agent_close_compressor(nta_agent_t *sa,
12027 struct sigcomp_compartment *cc)
12028{
12029 if (nta_compressor_vtable)
12030 return nta_compressor_vtable->ncv_close_compressor(sa, cc);
12031 return 0;
12032}
12033
12034/** Close both compressor and decompressor */
12035static
12036int agent_zap_compressor(nta_agent_t *sa,
12037 struct sigcomp_compartment *cc)
12038{
12039 if (nta_compressor_vtable)
12040 return nta_compressor_vtable->ncv_zap_compressor(sa, cc);
12041 return 0;
12042}
12043
12044/** Bind transport update callback */
12045int nta_agent_bind_tport_update(nta_agent_t *agent,
12046 nta_update_magic_t *magic,
12047 nta_update_tport_f *callback)
12048{
12049 if (!agent)
12050 return su_seterrno(EFAULT14), -1;
12051 agent->sa_update_magic = magic;
12052 agent->sa_update_tport = callback;
12053 return 0;
12054}
12055
12056/** Bind transport error callback */
12057int nta_agent_bind_tport_error(nta_agent_t *agent,
12058 nta_error_magic_t *magic,
12059 nta_error_tport_f *callback)
12060{
12061 if (!agent)
12062 return su_seterrno(EFAULT14), -1;
12063 agent->sa_error_magic = magic;
12064 agent->sa_error_tport = callback;
12065 return 0;
12066}
12067
12068/** Check if public transport binding is in progress */
12069int nta_agent_tport_is_updating(nta_agent_t *agent)
12070{
12071 return agent && tport_is_updating(agent->sa_tports);
12072}
12073
12074/** Initiate STUN keepalive controller to TPORT */
12075int nta_tport_keepalive(nta_outgoing_t *orq)
12076{
12077 assert(orq)((void) sizeof ((orq) ? 1 : 0), __extension__ ({ if (orq) ; else
__assert_fail ("orq", "nta.c", 12077, __extension__ __PRETTY_FUNCTION__
); }))
;
12078
12079#if HAVE_SOFIA_STUN
12080 return tport_keepalive(orq->orq_tport, msg_addrinfo(orq->orq_request),
12081 TAG_END()(tag_type_t)0, (tag_value_t)0);
12082#else
12083 return -1;
12084#endif
12085}
12086
12087/** Close all transports. @since Experimental in @VERSION_1_12_2. */
12088int nta_agent_close_tports(nta_agent_t *agent)
12089{
12090 size_t i;
12091 outgoing_htable_t *oht = agent->sa_outgoing;
12092 incoming_htable_t *iht = agent->sa_incoming;
12093
12094 for (i = oht->oht_size; i-- > 0;)
12095 /* while */ if (oht->oht_table[i]) {
12096 nta_outgoing_t *orq = oht->oht_table[i];
12097
12098 if (orq->orq_pending && orq->orq_tport)
12099 tport_release(orq->orq_tport, orq->orq_pending, orq->orq_request,
12100 NULL((void*)0), orq, 0);
12101
12102 orq->orq_pending = 0;
12103 tport_unref(orq->orq_tport), orq->orq_tport = NULL((void*)0);
12104 }
12105
12106
12107 for (i = iht->iht_size; i-- > 0;)
12108 /* while */ if (iht->iht_table[i]) {
12109 nta_incoming_t *irq = iht->iht_table[i];
12110 tport_unref(irq->irq_tport), irq->irq_tport = NULL((void*)0);
12111 }
12112
12113 tport_destroy(agent->sa_tports), agent->sa_tports = NULL((void*)0);
12114
12115 msg_header_free(agent->sa_home, (void *)agent->sa_vias);
12116 agent->sa_vias = NULL((void*)0);
12117 msg_header_free(agent->sa_home, (void *)agent->sa_public_vias);
12118 agent->sa_public_vias = NULL((void*)0);
12119
12120 return 0;
12121}