Bug Summary

File:libs/sofia-sip/libsofia-sip-ua/nta/nta.c
Location:line 2435, column 12
Description:Access to field 'v_next' results in a dereference of a null pointer (loaded from variable 'via')

Annotated Source Code

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.12.10devel";
101
102#if HAVE_FUNC1
103#elif HAVE_FUNCTION1
104#define __func__ __FUNCTION__
105#else
106static char const __func__[] = "nta";
107#endif
108
109#ifndef _MSC_VER
110#define NONE((void *)-1) ((void *)-1)
111#else
112#define NONE((void *)-1) ((void *)(INT_PTR)-1)
113#endif
114/* ------------------------------------------------------------------------- */
115
116/** Resolving order */
117enum nta_res_order_e
118{
119 nta_res_ip6_ip4,
120 nta_res_ip4_ip6,
121 nta_res_ip6_only,
122 nta_res_ip4_only
123};
124
125HTABLE_DECLARE_WITH(leg_htable, lht, nta_leg_t, size_t, hash_value_t)typedef struct leg_htable_s { size_t lht_size; size_t lht_used
; nta_leg_t** lht_table; } leg_htable_t
;
126HTABLE_DECLARE_WITH(outgoing_htable, oht, nta_outgoing_t, size_t, hash_value_t)typedef struct outgoing_htable_s { size_t oht_size; size_t oht_used
; nta_outgoing_t** oht_table; } outgoing_htable_t
;
127HTABLE_DECLARE_WITH(incoming_htable, iht, nta_incoming_t, size_t, hash_value_t)typedef struct incoming_htable_s { size_t iht_size; size_t iht_used
; nta_incoming_t** iht_table; } incoming_htable_t
;
128
129typedef struct outgoing_queue_t {
130 nta_outgoing_t **q_tail;
131 nta_outgoing_t *q_head;
132 size_t q_length;
133 unsigned q_timeout;
134} outgoing_queue_t;
135
136typedef struct incoming_queue_t {
137 nta_incoming_t **q_tail;
138 nta_incoming_t *q_head;
139 size_t q_length;
140 unsigned q_timeout;
141} incoming_queue_t;
142
143struct nta_agent_s
144{
145 su_home_t sa_home[1];
146 su_root_t *sa_root;
147 su_timer_t *sa_timer;
148 nta_agent_magic_t *sa_magic;
149 nta_message_f *sa_callback;
150
151 nta_update_magic_t *sa_update_magic;
152 nta_update_tport_f *sa_update_tport;
153
154 nta_error_magic_t *sa_error_magic;
155 nta_error_tport_f *sa_error_tport;
156
157 uint32_t sa_next; /**< Timestamp for next agent_timer. */
158
159 msg_mclass_t const *sa_mclass;
160 uint32_t sa_flags; /**< SIP message flags */
161 unsigned sa_preload; /**< Memory preload for SIP messages. */
162
163 tport_t *sa_tports;
164 sip_contact_t *sa_contact;
165 sip_via_t *sa_vias; /**< @Via headers for all transports */
166 sip_via_t *sa_public_vias; /**< @Vias for public transports */
167 sip_contact_t *sa_aliases;/**< List of aliases for agent */
168
169 uint64_t sa_branch; /**< Generator for branch parameters */
170 uint64_t sa_tags; /**< Generator for tag parameters */
171
172#if HAVE_SOFIA_SRESOLV1
173 sres_resolver_t *sa_resolver; /**< DNS resolver */
174 enum nta_res_order_e sa_res_order; /** Resolving order (AAAA/A) */
175#endif
176
177 url_t *sa_default_proxy; /**< Default outbound proxy */
178 unsigned sa_bad_req_mask; /**< Request error mask */
179 unsigned sa_bad_resp_mask; /**< Response error mask */
180 usize_t sa_maxsize; /**< Maximum size of incoming messages */
181 usize_t sa_max_proceeding; /**< Maximum size of proceeding queue */
182
183 unsigned sa_udp_mtu; /**< Maximum size of outgoing UDP requests */
184
185 unsigned sa_t1; /**< SIP T1 - initial retransmit interval (500 ms) */
186 unsigned sa_t2; /**< SIP T2 - maximum retransmit interval (4000 ms) */
187 unsigned sa_t4; /**< SIP T4 - clear message time (5000 ms) */
188
189
190 unsigned sa_t1x64; /**< SIP T1X64 - transaction lifetime (32 s) */
191
192 unsigned sa_progress; /**< Progress timer.
193 Interval between retransmitting
194 provisional responses. */
195
196 unsigned sa_timer_c; /**< SIP timer C.
197 Maximum interval between receiving
198 provisional responses. */
199
200 unsigned sa_graylist; /**< Graylisting period */
201 unsigned sa_blacklist; /**< Blacklisting period */
202
203 unsigned sa_drop_prob : 10; /**< NTA is used to test packet drop */
204 unsigned sa_is_a_uas : 1; /**< NTA is acting as an User Agent server */
205 unsigned sa_is_stateless : 1; /**< Process requests statelessly
206 * unless they match existing dialog.
207 */
208 unsigned sa_user_via:1; /**< Let application provide @Via headers */
209 unsigned sa_extra_100:1; /**< Allow NTA to return "100 Trying" response
210 * even if application has not responded.
211 */
212 unsigned sa_pass_100:1; /**< Pass the "100 Trying"
213 * provisional responses to the application
214 */
215 unsigned sa_timeout_408:1; /**< A "408 Request Timeout" message
216 * is generated when outgoing request expires.
217 */
218 unsigned sa_pass_408:1; /**< A "408 Request Timeout" responses
219 * are passed to client.
220 */
221 unsigned sa_merge_482 : 1; /**< A "482 Request Merged" response is returned
222 * to merged requests.
223 */
224 unsigned sa_cancel_2543 : 1; /**< Send a CANCEL to an INVITE without
225 * waiting for an provisional response.
226 */
227 unsigned sa_cancel_487 : 1; /**< Return 487 response automatically when
228 * a CANCEL is received.
229 */
230
231 unsigned sa_invite_100rel:1; /**< Include 100rel in INVITE requests. */
232 unsigned sa_timestamp : 1; /**< Insert @Timestamp in requests. */
233
234 unsigned sa_tport_ip4 : 1; /**< Transports support IPv4. */
235 unsigned sa_tport_ip6 : 1; /**< Transports support IPv6. */
236 unsigned sa_tport_udp : 1; /**< Transports support UDP. */
237 unsigned sa_tport_tcp : 1; /**< Transports support TCP. */
238 unsigned sa_tport_sctp : 1; /**< Transports support SCTP. */
239 unsigned sa_tport_tls : 1; /**< Transports support TLS. */
240 unsigned sa_tport_ws : 1; /**< Transports support WS. */
241 unsigned sa_tport_wss : 1; /**< Transports support WSS. */
242
243 unsigned sa_use_naptr : 1; /**< Use NAPTR lookup */
244 unsigned sa_use_srv : 1; /**< Use SRV lookup */
245
246 unsigned sa_srv_503 : 1; /**< SRV: choice another destination on 503 RFC 3263 */
247
248 unsigned sa_tport_threadpool:1; /**< Transports use threadpool */
249
250 unsigned sa_rport:1; /**< Use rport at client */
251 unsigned sa_server_rport:2; /**< Use rport at server */
252 unsigned sa_tcp_rport:1; /**< Use rport with tcp, too */
253 unsigned sa_tls_rport:1; /**< Use rport with tls, too */
254
255 unsigned sa_auto_comp:1; /**< Automatically create compartments */
256 unsigned sa_in_timer:1; /**< Set when executing timers */
257 unsigned sa_use_timer_c:1; /**< Application has set value for timer C */
258
259 unsigned :0;
260
261#if HAVE_SMIME
262 sm_object_t *sa_smime;
263#else
264 void *sa_smime;
265#endif
266
267 /** @MaxForwards */
268 sip_max_forwards_t sa_max_forwards[1];
269
270 /** Name of SigComp algorithm */
271 char const *sa_algorithm;
272 /** Options for SigComp. */
273 char const *sa_sigcomp_options;
274 char const* const *sa_sigcomp_option_list;
275 char const *sa_sigcomp_option_free;
276
277 nta_compressor_t *sa_compressor;
278
279 /* Statistics */
280 struct {
281 usize_t as_recv_msg;
282 usize_t as_recv_request;
283 usize_t as_recv_response;
284 usize_t as_bad_message;
285 usize_t as_bad_request;
286 usize_t as_bad_response;
287 usize_t as_drop_request;
288 usize_t as_drop_response;
289 usize_t as_client_tr;
290 usize_t as_server_tr;
291 usize_t as_dialog_tr;
292 usize_t as_acked_tr;
293 usize_t as_canceled_tr;
294 usize_t as_trless_request;
295 usize_t as_trless_to_tr;
296 usize_t as_trless_response;
297 usize_t as_trless_200;
298 usize_t as_merged_request;
299 usize_t as_sent_msg;
300 usize_t as_sent_request;
301 usize_t as_sent_response;
302 usize_t as_retry_request;
303 usize_t as_retry_response;
304 usize_t as_recv_retry;
305 usize_t as_tout_request;
306 usize_t as_tout_response;
307 } sa_stats[1];
308
309 /** Hash of dialogs. */
310 leg_htable_t sa_dialogs[1];
311 /** Default leg */
312 nta_leg_t *sa_default_leg;
313 /** Hash of legs without dialogs. */
314 leg_htable_t sa_defaults[1];
315 /** Hash table for outgoing transactions */
316 outgoing_htable_t sa_outgoing[1];
317 nta_outgoing_t *sa_default_outgoing;
318 /** Hash table for incoming transactions */
319 incoming_htable_t sa_incoming[1];
320 nta_incoming_t *sa_default_incoming;
321
322 /* Queues (states) for outgoing client transactions */
323 struct {
324 /** Queue for retrying client transactions */
325 nta_outgoing_t *re_list;
326 nta_outgoing_t **re_t1; /**< Special place for T1 timer */
327 size_t re_length; /**< Length of sa_out.re_list */
328
329 outgoing_queue_t delayed[1];
330 outgoing_queue_t resolving[1];
331
332 outgoing_queue_t trying[1]; /* Timer F / Timer E */
333 outgoing_queue_t completed[1]; /* Timer K */
334 outgoing_queue_t terminated[1];
335
336 /* Special queues (states) for outgoing INVITE transactions */
337 outgoing_queue_t inv_calling[1]; /* Timer B/A */
338 outgoing_queue_t inv_proceeding[1]; /* Timer C */
339 outgoing_queue_t inv_completed[1]; /* Timer D */
340
341 /* Temporary queue for transactions waiting to be freed */
342 outgoing_queue_t *free;
343 } sa_out;
344
345 /* Queues (states) for incoming server transactions */
346 struct {
347 /** Queue for retransmitting response of server transactions */
348 nta_incoming_t *re_list;
349 nta_incoming_t **re_t1; /**< Special place for T1 timer */
350 size_t re_length; /**< Length of sa_in.re_list */
351
352 incoming_queue_t proceeding[1]; /**< Request received */
353 incoming_queue_t preliminary[1]; /**< 100rel sent */
354 incoming_queue_t completed[1]; /**< Final answer sent (non-invite). */
355 incoming_queue_t inv_completed[1]; /**< Final answer sent (INVITE). */
356 incoming_queue_t inv_confirmed[1]; /**< Final answer sent, ACK recvd. */
357 incoming_queue_t terminated[1]; /**< Terminated, ready to free. */
358 incoming_queue_t final_failed[1];
359 } sa_in;
360
361 /* Special task for freeing memory */
362 su_clone_r sa_terminator;
363};
364
365struct nta_leg_s
366{
367 su_home_t leg_home[1];
368 hash_value_t leg_hash;
369
370 unsigned leg_dialog : 1;
371 unsigned leg_stateless : 1; /**< Process requests statelessly */
372#ifdef NTA_STRICT_ROUTING
373 unsigned leg_contact_set : 1;
374#else
375 unsigned leg_loose_route : 1; /**< Topmost route in set is LR */
376#endif
377 unsigned leg_route_set : 1; /**< Route set has been saved */
378 unsigned leg_local_is_to : 1; /**< Backwards-compatibility. */
379 unsigned leg_tagged : 1; /**< Tagged after creation.
380 *
381 * Request missing @To tag matches
382 * a tagged leg even after tagging.
383 */
384 unsigned leg_compressed:1;
385 unsigned:0;
386 nta_request_f *leg_callback;
387 nta_leg_magic_t *leg_magic;
388 nta_agent_t *leg_agent;
389
390 url_t const *leg_url; /**< Match incoming requests. */
391 char const *leg_method; /**< Match incoming requests. */
392
393 uint32_t leg_seq; /**< Sequence number for next transaction */
394 uint32_t leg_rseq; /**< Remote sequence number */
395 sip_call_id_t *leg_id; /**< Call ID */
396 sip_from_t *leg_remote; /**< Remote address (@To/@From) */
397 sip_to_t *leg_local; /**< Local address (@From/@To) */
398
399 sip_route_t *leg_route; /**< @Route for outgoing requests. */
400 sip_contact_t *leg_target; /**< Remote destination (from @Contact). */
401};
402
403struct nta_incoming_s
404{
405 su_home_t *irq_home;
406 hash_value_t irq_hash;
407 nta_agent_t *irq_agent;
408 nta_ack_cancel_f *irq_callback;
409 nta_incoming_magic_t *irq_magic;
410
411 /* Timeout/state queue */
412 nta_incoming_t **irq_prev;
413 nta_incoming_t *irq_next;
414 incoming_queue_t *irq_queue;
415
416 /* Retry queue */
417 nta_incoming_t **irq_rprev;
418 nta_incoming_t *irq_rnext;
419
420 sip_method_t irq_method;
421 sip_request_t *irq_rq;
422 sip_from_t *irq_from;
423 sip_to_t *irq_to;
424 char const *irq_tag;
425 sip_cseq_t *irq_cseq;
426 sip_call_id_t *irq_call_id;
427 sip_via_t *irq_via;
428 sip_record_route_t *irq_record_route;
429 char const *irq_branch;
430
431 uint32_t irq_rseq;
432
433 sip_timestamp_t *irq_timestamp;
434 su_time_t irq_received;
435
436 uint32_t irq_timeout; /**< Timer H, I, J */
437 uint32_t irq_retry; /**< Timer G */
438 unsigned short irq_interval; /**< Next timer */
439
440 short irq_status;
441
442 unsigned irq_retries:8;
443 unsigned irq_default:1; /**< Default transaction */
444 unsigned irq_canceled:1; /**< Transaction is canceled */
445 unsigned irq_completed:1; /**< Transaction is completed */
446 unsigned irq_confirmed:1; /**< Response has been acked */
447 unsigned irq_terminated:1; /**< Transaction is terminated */
448 unsigned irq_final_failed:1; /**< Sending final response failed */
449 unsigned irq_destroyed :1; /**< Transaction is destroyed */
450 unsigned irq_in_callback:1; /**< Callback is being invoked */
451 unsigned irq_reliable_tp:1; /**< Transport is reliable */
452 unsigned irq_sigcomp_zap:1; /**< Reset SigComp */
453 unsigned irq_must_100rel:1; /**< 100rel is required */
454 unsigned irq_extra_100:1; /**< 100 Trying should be sent */
455 unsigned irq_tag_set:1; /**< Tag is not from request */
456 unsigned irq_compressed:1;
457 unsigned :0;
458
459 tp_name_t irq_tpn[1];
460 tport_t *irq_tport;
461 struct sigcomp_compartment *irq_cc;
462 msg_t *irq_request;
463 msg_t *irq_request2; /**< ACK/CANCEL */
464 msg_t *irq_response;
465
466 nta_reliable_t *irq_reliable; /**< List of reliable responses */
467};
468
469struct nta_reliable_s
470{
471 nta_reliable_t *rel_next;
472 nta_incoming_t *rel_irq;
473 nta_prack_f *rel_callback;
474 nta_reliable_magic_t *rel_magic;
475 uint32_t rel_rseq;
476 unsigned short rel_status;
477 unsigned rel_pracked:1;
478 unsigned rel_precious:1;
479 msg_t *rel_response;
480 msg_t *rel_unsent;
481};
482
483typedef struct sipdns_resolver sipdns_resolver_t;
484
485struct nta_outgoing_s
486{
487 hash_value_t orq_hash; /**< Hash value */
488 nta_agent_t *orq_agent;
489 nta_response_f *orq_callback;
490 nta_outgoing_magic_t *orq_magic;
491
492 /* Timeout/state queue */
493 nta_outgoing_t **orq_prev;
494 nta_outgoing_t *orq_next;
495 outgoing_queue_t *orq_queue;
496
497 /* Retry queue */
498 nta_outgoing_t **orq_rprev;
499 nta_outgoing_t *orq_rnext;
500
501 sip_method_t orq_method;
502 char const *orq_method_name;
503 url_t const *orq_url; /**< Original RequestURI */
504
505 sip_from_t const *orq_from;
506 sip_to_t const *orq_to;
507 char const *orq_tag; /**< Tag from final response. */
508
509 sip_cseq_t const *orq_cseq;
510 sip_call_id_t const *orq_call_id;
511
512 msg_t *orq_request;
513 msg_t *orq_response;
514
515 su_time_t orq_sent; /**< When request was sent? */
516 unsigned orq_delay; /**< RTT estimate */
517
518 uint32_t orq_retry; /**< Timer A, E */
519 uint32_t orq_timeout; /**< Timer B, D, F, K */
520
521 unsigned short orq_interval; /**< Next timer A/E */
522
523 unsigned short orq_status;
524 unsigned char orq_retries; /**< Number of tries this far */
525
526 unsigned orq_default:1; /**< This is default transaction */
527 unsigned orq_inserted:1;
528 unsigned orq_resolved:1;
529 unsigned orq_via_added:1;
530 unsigned orq_prepared:1;
531 unsigned orq_canceled:1;
532 unsigned orq_terminated:1;
533 unsigned orq_destroyed:1;
534 unsigned orq_completed:1;
535 unsigned orq_delayed:1;
536 unsigned orq_user_tport:1; /**< Application provided tport - don't retry */
537 unsigned orq_try_tcp_instead:1;
538 unsigned orq_try_udp_instead:1;
539 unsigned orq_reliable:1; /**< Transport is reliable */
540
541 unsigned orq_forked:1; /**< Tagged fork */
542
543 /* Attributes */
544 unsigned orq_sips:1;
545 unsigned orq_uas:1; /**< Running this transaction as UAS */
546 unsigned orq_user_via:1;
547 unsigned orq_stateless:1;
548 unsigned orq_pass_100:1;
549 unsigned orq_sigcomp_new:1; /**< Create compartment if needed */
550 unsigned orq_sigcomp_zap:1; /**< Reset SigComp after completing */
551 unsigned orq_must_100rel:1;
552 unsigned orq_timestamp:1; /**< Insert @Timestamp header. */
553 unsigned orq_100rel:1; /**< Support 100rel */
554 unsigned:0; /* pad */
555
556#if HAVE_SOFIA_SRESOLV1
557 sipdns_resolver_t *orq_resolver;
558#endif
559 url_t *orq_route; /**< Route URL */
560 tp_name_t orq_tpn[1]; /**< Where to send request */
561
562 tport_t *orq_tport;
563 struct sigcomp_compartment *orq_cc;
564 tagi_t *orq_tags; /**< Tport tag items */
565
566 char const *orq_branch; /**< Transaction branch */
567 char const *orq_via_branch; /**< @Via branch */
568
569 int *orq_status2b; /**< Delayed response */
570
571 nta_outgoing_t *orq_cancel; /**< Delayed CANCEL transaction */
572
573 nta_outgoing_t *orq_forking; /**< Untagged transaction */
574 nta_outgoing_t *orq_forks; /**< Tagged transactions */
575 uint32_t orq_rseq; /**< Latest incoming rseq */
576 int orq_pending; /**< Request is pending in tport */
577};
578
579/* ------------------------------------------------------------------------- */
580
581/* Internal tags */
582
583/* Delay sending of request */
584#define NTATAG_DELAY_SENDING(x)ntatag_delay_sending, tag_bool_v((x)) ntatag_delay_sending, tag_bool_v((x))
585#define NTATAG_DELAY_SENDING_REF(x)ntatag_delay_sending_ref, tag_bool_vr(&(x)) \
586ntatag_delay_sending_ref, tag_bool_vr(&(x))
587
588extern tag_typedef_t ntatag_delay_sending;
589extern tag_typedef_t ntatag_delay_sending_ref;
590
591/* Allow sending incomplete responses */
592#define NTATAG_INCOMPLETE(x)ntatag_incomplete, tag_bool_v((x)) ntatag_incomplete, tag_bool_v((x))
593#define NTATAG_INCOMPLETE_REF(x)ntatag_incomplete_ref, tag_bool_vr(&(x)) \
594ntatag_incomplete_ref, tag_bool_vr(&(x))
595
596extern tag_typedef_t ntatag_incomplete;
597extern tag_typedef_t ntatag_incomplete_ref;
598
599nta_compressor_vtable_t *nta_compressor_vtable = NULL((void*)0);
600
601/* Agent */
602static int agent_tag_init(nta_agent_t *self);
603static int agent_timer_init(nta_agent_t *agent);
604static void agent_timer(su_root_magic_t *rm, su_timer_t *, nta_agent_t *);
605static int agent_launch_terminator(nta_agent_t *agent);
606static void agent_kill_terminator(nta_agent_t *agent);
607static int agent_set_params(nta_agent_t *agent, tagi_t *tags);
608static void agent_set_udp_params(nta_agent_t *self, usize_t udp_mtu);
609static int agent_get_params(nta_agent_t *agent, tagi_t *tags);
610
611/* Transport interface */
612static sip_via_t const *agent_tport_via(tport_t *tport);
613static int outgoing_insert_via(nta_outgoing_t *orq, sip_via_t const *);
614static int nta_tpn_by_via(tp_name_t *tpn, sip_via_t const *v, int *using_rport);
615
616static msg_t *nta_msg_create_for_transport(nta_agent_t *agent, int flags,
617 char const data[], usize_t dlen,
618 tport_t const *tport,
619 tp_client_t *via);
620
621static int complete_response(msg_t *response,
622 int status, char const *phrase,
623 msg_t *request);
624
625static int mreply(nta_agent_t *agent,
626 msg_t *reply,
627 int status, char const *phrase,
628 msg_t *req_msg,
629 tport_t *tport,
630 int incomplete,
631 int sdwn_after,
632 char const *to_tag,
633 tag_type_t tag, tag_value_t value, ...);
634
635#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))
,
636#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),
637
638struct sigcomp_compartment;
639
640struct sigcomp_compartment *
641nta_compartment_ref(struct sigcomp_compartment *cc);
642
643static
644struct sigcomp_compartment *
645agent_compression_compartment(nta_agent_t *sa, tport_t *tp, tp_name_t const *tpn,
646 int new_if_needed);
647
648static
649int agent_accept_compressed(nta_agent_t *sa, msg_t *msg,
650 struct sigcomp_compartment *cc);
651
652static int agent_close_compressor(nta_agent_t *sa,
653 struct sigcomp_compartment *cc);
654
655static int agent_zap_compressor(nta_agent_t *sa,
656 struct sigcomp_compartment *cc);
657
658
659static char const * stateful_branch(su_home_t *home, nta_agent_t *);
660static char const * stateless_branch(nta_agent_t *, msg_t *, sip_t const *,
661 tp_name_t const *tp);
662
663#define NTA_BRANCH_PRIME(uint64_t)(0xB9591D1C361C6521ULL) SU_U64_C(0xB9591D1C361C6521)(uint64_t)(0xB9591D1C361C6521ULL)
664#define NTA_TAG_PRIME(uint64_t)(0xB9591D1C361C6521ULL) SU_U64_C(0xB9591D1C361C6521)(uint64_t)(0xB9591D1C361C6521ULL)
665
666#ifndef UINT32_MAX(4294967295U)
667#define UINT32_MAX(4294967295U) (0xffffffffU)
668#endif
669
670HTABLE_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)
;
671static nta_leg_t *leg_find(nta_agent_t const *sa,
672 char const *method_name,
673 url_t const *request_uri,
674 sip_call_id_t const *i,
675 char const *from_tag,
676 char const *to_tag);
677static nta_leg_t *dst_find(nta_agent_t const *sa, url_t const *u0,
678 char const *method);
679static void leg_recv(nta_leg_t *, msg_t *, sip_t *, tport_t *);
680static void leg_free(nta_agent_t *sa, nta_leg_t *leg);
681
682#define NTA_HASH(i, cs)((i)->i_hash + 26839U * (uint32_t)(cs)) ((i)->i_hash + 26839U * (uint32_t)(cs))
683
684HTABLE_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)
;
685static nta_incoming_t *incoming_create(nta_agent_t *agent,
686 msg_t *request,
687 sip_t *sip,
688 tport_t *tport,
689 char const *tag);
690static int incoming_callback(nta_leg_t *leg, nta_incoming_t *irq, sip_t *sip);
691static void incoming_free(nta_incoming_t *irq);
692su_inlinestatic inline void incoming_cut_off(nta_incoming_t *irq);
693su_inlinestatic inline void incoming_reclaim(nta_incoming_t *irq);
694static void incoming_queue_init(incoming_queue_t *,
695 unsigned timeout);
696static void incoming_queue_adjust(nta_agent_t *sa,
697 incoming_queue_t *queue,
698 unsigned timeout);
699
700static nta_incoming_t *incoming_find(nta_agent_t const *agent,
701 sip_t const *sip,
702 sip_via_t const *v,
703 nta_incoming_t **merge,
704 nta_incoming_t **ack,
705 nta_incoming_t **cancel);
706static int incoming_reply(nta_incoming_t *irq, msg_t *msg, sip_t *sip);
707su_inlinestatic inline int incoming_recv(nta_incoming_t *irq, msg_t *msg, sip_t *sip,
708 tport_t *tport);
709su_inlinestatic inline int incoming_ack(nta_incoming_t *irq, msg_t *msg, sip_t *sip,
710 tport_t *tport);
711su_inlinestatic inline int incoming_cancel(nta_incoming_t *irq, msg_t *msg, sip_t *sip,
712 tport_t *tport);
713static void request_merge(nta_agent_t *,
714 msg_t *msg, sip_t *sip, tport_t *tport,
715 char const *to_tag);
716su_inlinestatic inline int incoming_timestamp(nta_incoming_t *, msg_t *, sip_t *);
717static void _nta_incoming_timer(nta_agent_t *);
718
719static nta_reliable_t *reliable_mreply(nta_incoming_t *,
720 nta_prack_f *, nta_reliable_magic_t *,
721 msg_t *, sip_t *);
722static int reliable_send(nta_incoming_t *, nta_reliable_t *, msg_t *, sip_t *);
723static int reliable_final(nta_incoming_t *irq, msg_t *msg, sip_t *sip);
724static msg_t *reliable_response(nta_incoming_t *irq);
725static nta_reliable_t *reliable_find(nta_agent_t const *, sip_t const *);
726static int reliable_recv(nta_reliable_t *rel, msg_t *, sip_t *, tport_t *);
727static void reliable_flush(nta_incoming_t *irq);
728static void reliable_timeout(nta_incoming_t *irq, int timeout);
729
730HTABLE_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)
;
731static nta_outgoing_t *outgoing_create(nta_agent_t *agent,
732 nta_response_f *callback,
733 nta_outgoing_magic_t *magic,
734 url_string_t const *route_url,
735 tp_name_t const *tpn,
736 msg_t *msg,
737 tag_type_t tag, tag_value_t value, ...);
738static void outgoing_queue_init(outgoing_queue_t *,
739 unsigned timeout);
740static void outgoing_queue_adjust(nta_agent_t *sa,
741 outgoing_queue_t *queue,
742 unsigned timeout);
743static void outgoing_free(nta_outgoing_t *orq);
744su_inlinestatic inline void outgoing_cut_off(nta_outgoing_t *orq);
745su_inlinestatic inline void outgoing_reclaim(nta_outgoing_t *orq);
746static nta_outgoing_t *outgoing_find(nta_agent_t const *sa,
747 msg_t const *msg,
748 sip_t const *sip,
749 sip_via_t const *v);
750static int outgoing_recv(nta_outgoing_t *orq, int status, msg_t *, sip_t *);
751static void outgoing_default_recv(nta_outgoing_t *, int, msg_t *, sip_t *);
752static void _nta_outgoing_timer(nta_agent_t *);
753static int outgoing_recv_reliable(nta_outgoing_t *orq, msg_t *msg, sip_t *sip);
754
755/* Internal message passing */
756union sm_arg_u {
757 struct outgoing_recv_s {
758 nta_outgoing_t *orq;
759 msg_t *msg;
760 sip_t *sip;
761 int status;
762 } a_outgoing_recv[1];
763
764 incoming_queue_t a_incoming_queue[1];
765 outgoing_queue_t a_outgoing_queue[1];
766};
767
768/* Global module data */
769
770/**@var char const NTA_DEBUG[];
771 *
772 * Environment variable determining the default debug log level.
773 *
774 * The NTA_DEBUG environment variable is used to determine the default
775 * debug logging level. The normal level is 3.
776 *
777 * @sa <sofia-sip/su_debug.h>, #su_log_global, #SOFIA_DEBUG
778 */
779#ifdef DOXYGEN
780extern char const NTA_DEBUG[]; /* dummy declaration for Doxygen */
781#endif
782
783#ifndef SU_DEBUG0
784#define SU_DEBUG0 3
785#endif
786
787/**Debug log for @b nta module.
788 *
789 * The nta_log is the log object used by @b nta module. The level of
790 * nta_log is set using #NTA_DEBUG environment variable.
791 */
792su_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), }
};
793
794/* ====================================================================== */
795/* 1) Agent */
796
797/**
798 * Create an NTA agent object.
799 *
800 * Create an NTA agent object. The agent
801 * object creates and binds a server socket with address specified in @e url.
802 * If the @e host portion of the @e url is @c "*", the agent listens to all
803 * addresses available on the host.
804 *
805 * When a message is received, the agent object parses it. If the result is
806 * a valid SIP message, the agent object passes the message to the
807 * application by invoking the nta_message_f @e callback function.
808 *
809 * @note
810 * The @e url can be either parsed url (of type url_t ()), or a valid
811 * SIP URL as a string.
812 *
813 * @note
814 * If @e url is @c NULL, the default @e url @c "sip:*" is used.
815 * @par
816 * If @e url is @c NONE (iow, (void*)-1), no server sockets are bound.
817 * @par
818 * If @p transport parameters are specified in @a url, agent uses only
819 * specified transport type.
820 *
821 * @par
822 * If an @p maddr parameter is specified in @e url, agent binds to the
823 * specified address, but uses @e host part of @e url when it generates
824 * @Contact and @Via headers. The @p maddr parameter is also included,
825 * unless it equals to @c INADDR_ANY (@p 0.0.0.0 or @p [::]).
826 *
827 * @param root pointer to a su_root_t used for synchronization
828 * @param contact_url URL that agent uses to bind the server sockets
829 * @param callback pointer to callback function
830 * @param magic pointer to user data
831 * @param tag,value,... tagged arguments
832 *
833 * @TAGS
834 * NTATAG_ALIASES(),
835 * NTATAG_BAD_REQ_MASK(), NTATAG_BAD_RESP_MASK(), NTATAG_BLACKLIST(),
836 * NTATAG_CANCEL_2543(), NTATAG_CANCEL_487(), NTATAG_CLIENT_RPORT(),
837 * NTATAG_DEBUG_DROP_PROB(), NTATAG_DEFAULT_PROXY(),
838 * NTATAG_EXTRA_100(), NTATAG_GRAYLIST(),
839 * NTATAG_MAXSIZE(), NTATAG_MAX_FORWARDS(), NTATAG_MERGE_482(), NTATAG_MCLASS()
840 * NTATAG_PASS_100(), NTATAG_PASS_408(), NTATAG_PRELOAD(), NTATAG_PROGRESS(),
841 * NTATAG_REL100(),
842 * NTATAG_SERVER_RPORT(),
843 * NTATAG_SIPFLAGS(),
844 * NTATAG_SIP_T1X64(), NTATAG_SIP_T1(), NTATAG_SIP_T2(), NTATAG_SIP_T4(),
845 * NTATAG_STATELESS(),
846 * NTATAG_TAG_3261(), NTATAG_TCP_RPORT(), NTATAG_TIMEOUT_408(),
847 * NTATAG_TLS_RPORT(),
848 * NTATAG_TIMER_C(), NTATAG_MAX_PROCEEDING(),
849 * NTATAG_UA(), NTATAG_UDP_MTU(), NTATAG_USER_VIA(),
850 * NTATAG_USE_NAPTR(), NTATAG_USE_SRV() and NTATAG_USE_TIMESTAMP().
851 *
852 * @note The value from following tags are stored, but they currently do nothing:
853 * NTATAG_SIGCOMP_ALGORITHM(), NTATAG_SIGCOMP_OPTIONS(), NTATAG_SMIME()
854 *
855 * @note It is possible to provide @c (url_string_t*)-1 as @a contact_url.
856 * In that case, no server sockets are bound.
857 *
858 * @retval handle to the agent when successful,
859 * @retval NULL upon an error.
860 *
861 * @sa NUTAG_
862 */
863nta_agent_t *nta_agent_create(su_root_t *root,
864 url_string_t const *contact_url,
865 nta_message_f *callback,
866 nta_agent_magic_t *magic,
867 tag_type_t tag, tag_value_t value, ...)
868{
869 nta_agent_t *agent;
870 ta_list ta;
871
872 if (root == NULL((void*)0))
873 return su_seterrno(EINVAL22), NULL((void*)0);
874
875 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)
;
876
877 if ((agent = su_home_new(sizeof(*agent)))) {
878 unsigned timer_c = 0, timer_d = 32000;
879
880 agent->sa_root = root;
881 agent->sa_callback = callback;
882 agent->sa_magic = magic;
883 agent->sa_flags = MSG_DO_CANONICMSG_FLG_CANONIC;
884
885 agent->sa_maxsize = 2 * 1024 * 1024; /* 2 MB */
886 agent->sa_bad_req_mask =
887 /*
888 * Bit-wise not of these - what is left is suitable for UAs with
889 * 100rel, timer, events, publish
890 */
891 (unsigned) ~(sip_mask_response | sip_mask_proxy | sip_mask_registrar |
892 sip_mask_pref | sip_mask_privacy);
893 agent->sa_bad_resp_mask =
894 (unsigned) ~(sip_mask_request | sip_mask_proxy | sip_mask_registrar |
895 sip_mask_pref | sip_mask_privacy);
896 agent->sa_t1 = NTA_SIP_T1;
897 agent->sa_t2 = NTA_SIP_T2;
898 agent->sa_t4 = NTA_SIP_T4;
899 agent->sa_t1x64 = 64 * NTA_SIP_T1;
900 agent->sa_timer_c = 185 * 1000;
901 agent->sa_graylist = 600;
902 agent->sa_drop_prob = 0;
903 agent->sa_is_a_uas = 0;
904 agent->sa_progress = 60 * 1000;
905 agent->sa_user_via = 0;
906 agent->sa_extra_100 = 0;
907 agent->sa_pass_100 = 0;
908 agent->sa_timeout_408 = 1;
909 agent->sa_pass_408 = 0;
910 agent->sa_merge_482 = 0;
911 agent->sa_cancel_2543 = 0;
912 agent->sa_cancel_487 = 1;
913 agent->sa_invite_100rel = 0;
914 agent->sa_timestamp = 0;
915 agent->sa_use_naptr = 1;
916 agent->sa_use_srv = 1;
917 agent->sa_srv_503 = 1;
918 agent->sa_auto_comp = 0;
919 agent->sa_server_rport = 1;
920
921 /* RFC 3261 section 8.1.1.6 */
922 sip_max_forwards_init(agent->sa_max_forwards);
923
924 if (getenv("SIPCOMPACT"))
925 agent->sa_flags |= MSG_DO_COMPACTMSG_FLG_COMPACT;
926
927 agent_set_params(agent, ta_args(ta)(ta).tl);
928
929 if (agent->sa_mclass == NULL((void*)0))
930 agent->sa_mclass = sip_default_mclass();
931
932 agent->sa_in.re_t1 = &agent->sa_in.re_list;
933
934 incoming_queue_init(agent->sa_in.proceeding, 0);
935 incoming_queue_init(agent->sa_in.preliminary, agent->sa_t1x64); /* P1 */
936 incoming_queue_init(agent->sa_in.inv_completed, agent->sa_t1x64); /* H */
937 incoming_queue_init(agent->sa_in.inv_confirmed, agent->sa_t4); /* I */
938 incoming_queue_init(agent->sa_in.completed, agent->sa_t1x64); /* J */
939 incoming_queue_init(agent->sa_in.terminated, 0);
940 incoming_queue_init(agent->sa_in.final_failed, 0);
941
942 agent->sa_out.re_t1 = &agent->sa_out.re_list;
943
944 if (agent->sa_use_timer_c || !agent->sa_is_a_uas)
945 timer_c = agent->sa_timer_c;
946 if (timer_d < agent->sa_t1x64)
947 timer_d = agent->sa_t1x64;
948
949 outgoing_queue_init(agent->sa_out.delayed, 0);
950 outgoing_queue_init(agent->sa_out.resolving, 0);
951 outgoing_queue_init(agent->sa_out.trying, agent->sa_t1x64); /* F */
952 outgoing_queue_init(agent->sa_out.completed, agent->sa_t4); /* K */
953 outgoing_queue_init(agent->sa_out.terminated, 0);
954 /* Special queues (states) for outgoing INVITE transactions */
955 outgoing_queue_init(agent->sa_out.inv_calling, agent->sa_t1x64); /* B */
956 outgoing_queue_init(agent->sa_out.inv_proceeding, timer_c); /* C */
957 outgoing_queue_init(agent->sa_out.inv_completed, timer_d); /* D */
958
959 if (leg_htable_resize(agent->sa_home, agent->sa_dialogs, 0) < 0 ||
960 leg_htable_resize(agent->sa_home, agent->sa_defaults, 0) < 0 ||
961 outgoing_htable_resize(agent->sa_home, agent->sa_outgoing, 0) < 0 ||
962 incoming_htable_resize(agent->sa_home, agent->sa_incoming, 0) < 0) {
963 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__
, 963, "nta_agent_create: failure with %s\n", "hash tables"))
: (void)0)
;
964 goto deinit;
965 }
966 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__
, 966, "nta_agent_create: initialized %s\n", "hash tables")) :
(void)0)
;
967
968 if (contact_url != (url_string_t *)-1 &&
969 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) {
970 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__
, 970, "nta_agent_create: failure with %s\n", "transport")) :
(void)0)
;
971 goto deinit;
972 }
973 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__
, 973, "nta_agent_create: initialized %s\n", "transports")) :
(void)0)
;
974
975 if (agent_tag_init(agent) < 0) {
976 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__
, 976, "nta_agent_create: failure with %s\n", "random identifiers"
)) : (void)0)
;
977 goto deinit;
978 }
979 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__
, 979, "nta_agent_create: initialized %s\n", "random identifiers"
)) : (void)0)
;
980
981 if (agent_timer_init(agent) < 0) {
982 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__
, 982, "nta_agent_create: failure with %s\n", "timer")) : (void
)0)
;
983 goto deinit;
984 }
985 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__
, 985, "nta_agent_create: initialized %s\n", "timer")) : (void
)0)
;
986
987 if (agent_launch_terminator(agent) == 0)
988 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__
, 988, "nta_agent_create: initialized %s\n", "threads")) : (void
)0)
;
989
990#if HAVE_SOFIA_SRESOLV1
991 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
);
992 if (!agent->sa_resolver) {
993 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__
, 993, "nta_agent_create: failure with %s\n", "resolver")) : (
void)0)
;
994 }
995 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__
, 995, "nta_agent_create: initialized %s\n", "resolver")) : (
void)0)
;
996#endif
997
998 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))
;
999
1000 return agent;
1001
1002 deinit:
1003 nta_agent_destroy(agent);
1004 }
1005
1006 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))
;
1007
1008 return NULL((void*)0);
1009}
1010
1011/**
1012 * Destroy an NTA agent object.
1013 *
1014 * @param agent the NTA agent object to be destroyed.
1015 *
1016 */
1017void nta_agent_destroy(nta_agent_t *agent)
1018{
1019 if (agent) {
1020 size_t i;
1021 outgoing_htable_t *oht = agent->sa_outgoing;
1022 incoming_htable_t *iht = agent->sa_incoming;
1023 /* Currently, this is pretty pointless, as legs don't keep any resources */
1024 leg_htable_t *lht;
1025 nta_leg_t *leg;
1026
1027 for (i = 0, lht = agent->sa_dialogs; i < lht->lht_size; i++) {
1028 if ((leg = lht->lht_table[i])) {
1029 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__
, 1031, "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)
1030 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__
, 1031, "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)
1031 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__
, 1031, "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)
;
1032 leg_free(agent, leg);
1033 }
1034 }
1035
1036 for (i = 0, lht = agent->sa_defaults; i < lht->lht_size; i++) {
1037 if ((leg = lht->lht_table[i])) {
1038 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__
, 1040, "%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)
1039 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__
, 1040, "%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)
1040 __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__
, 1040, "%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)
;
1041 leg_free(agent, leg);
1042 }
1043 }
1044
1045 if (agent->sa_default_leg)
1046 leg_free(agent, agent->sa_default_leg);
1047
1048 for (i = iht->iht_size; i-- > 0; )
1049 while (iht->iht_table[i]) {
1050 nta_incoming_t *irq = iht->iht_table[i];
1051
1052 if (!irq->irq_destroyed)
1053 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__
, 1056, "%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
)
1054 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__
, 1056, "%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
)
1055 __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__
, 1056, "%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
)
1056 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__
, 1056, "%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
)
;
1057
1058 incoming_free(irq);
1059 }
1060
1061 for (i = oht->oht_size; i-- > 0;)
1062 while (oht->oht_table[i]) {
1063 nta_outgoing_t *orq = oht->oht_table[i];
1064
1065 if (!orq->orq_destroyed)
1066 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__
, 1071, "%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)
1067 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__
, 1071, "%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)
1068 __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__
, 1071, "%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)
1069 (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__
, 1071, "%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)
1070 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__
, 1071, "%s: destroying %s%s client transaction to <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
">\n", __func__, (orq->orq_forking || orq->orq_forks
) ? "forked " : "forking", orq->orq_method_name, (orq->
orq_to->a_url)->url_scheme ? (orq->orq_to->a_url)
->url_scheme : "", (orq->orq_to->a_url)->url_type
!= url_any && (orq->orq_to->a_url)->url_scheme
&& (orq->orq_to->a_url)->url_scheme[0] ? ":"
: "", (orq->orq_to->a_url)->url_root && ((orq
->orq_to->a_url)->url_host || (orq->orq_to->a_url
)->url_user) ? "//" : "", (orq->orq_to->a_url)->url_user
? (orq->orq_to->a_url)->url_user : "", (orq->orq_to
->a_url)->url_user && (orq->orq_to->a_url
)->url_password ? ":" : "", (orq->orq_to->a_url)->
url_user && (orq->orq_to->a_url)->url_password
? (orq->orq_to->a_url)->url_password : "", (orq->
orq_to->a_url)->url_user && (orq->orq_to->
a_url)->url_host ? "@" : "", (orq->orq_to->a_url)->
url_host ? (orq->orq_to->a_url)->url_host : "", (orq
->orq_to->a_url)->url_host && (orq->orq_to
->a_url)->url_port ? ":" : "", (orq->orq_to->a_url
)->url_host && (orq->orq_to->a_url)->url_port
? (orq->orq_to->a_url)->url_port : "", (orq->orq_to
->a_url)->url_root && (orq->orq_to->a_url
)->url_path ? "/" : "", (orq->orq_to->a_url)->url_path
? (orq->orq_to->a_url)->url_path : "", (orq->orq_to
->a_url)->url_params ? ";" : "", (orq->orq_to->a_url
)->url_params ? (orq->orq_to->a_url)->url_params :
"", (orq->orq_to->a_url)->url_headers ? "?" : "", (
orq->orq_to->a_url)->url_headers ? (orq->orq_to->
a_url)->url_headers : "", (orq->orq_to->a_url)->url_fragment
? "#" : "", (orq->orq_to->a_url)->url_fragment ? (orq
->orq_to->a_url)->url_fragment : "")) : (void)0)
1071 URL_PRINT_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__
, 1071, "%s: destroying %s%s client transaction to <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
">\n", __func__, (orq->orq_forking || orq->orq_forks
) ? "forked " : "forking", orq->orq_method_name, (orq->
orq_to->a_url)->url_scheme ? (orq->orq_to->a_url)
->url_scheme : "", (orq->orq_to->a_url)->url_type
!= url_any && (orq->orq_to->a_url)->url_scheme
&& (orq->orq_to->a_url)->url_scheme[0] ? ":"
: "", (orq->orq_to->a_url)->url_root && ((orq
->orq_to->a_url)->url_host || (orq->orq_to->a_url
)->url_user) ? "//" : "", (orq->orq_to->a_url)->url_user
? (orq->orq_to->a_url)->url_user : "", (orq->orq_to
->a_url)->url_user && (orq->orq_to->a_url
)->url_password ? ":" : "", (orq->orq_to->a_url)->
url_user && (orq->orq_to->a_url)->url_password
? (orq->orq_to->a_url)->url_password : "", (orq->
orq_to->a_url)->url_user && (orq->orq_to->
a_url)->url_host ? "@" : "", (orq->orq_to->a_url)->
url_host ? (orq->orq_to->a_url)->url_host : "", (orq
->orq_to->a_url)->url_host && (orq->orq_to
->a_url)->url_port ? ":" : "", (orq->orq_to->a_url
)->url_host && (orq->orq_to->a_url)->url_port
? (orq->orq_to->a_url)->url_port : "", (orq->orq_to
->a_url)->url_root && (orq->orq_to->a_url
)->url_path ? "/" : "", (orq->orq_to->a_url)->url_path
? (orq->orq_to->a_url)->url_path : "", (orq->orq_to
->a_url)->url_params ? ";" : "", (orq->orq_to->a_url
)->url_params ? (orq->orq_to->a_url)->url_params :
"", (orq->orq_to->a_url)->url_headers ? "?" : "", (
orq->orq_to->a_url)->url_headers ? (orq->orq_to->
a_url)->url_headers : "", (orq->orq_to->a_url)->url_fragment
? "#" : "", (orq->orq_to->a_url)->url_fragment ? (orq
->orq_to->a_url)->url_fragment : "")) : (void)0)
;
1072
1073 orq->orq_forks = NULL((void*)0), orq->orq_forking = NULL((void*)0);
1074 outgoing_free(orq);
1075 }
1076
1077 su_timer_destroy(agent->sa_timer), agent->sa_timer = NULL((void*)0);
1078
1079# if HAVE_SOFIA_SRESOLV1
1080 sres_resolver_destroy(agent->sa_resolver), agent->sa_resolver = NULL((void*)0);
1081# endif
1082
1083 tport_destroy(agent->sa_tports), agent->sa_tports = NULL((void*)0);
1084
1085 agent_kill_terminator(agent);
1086
1087 su_home_unref(agent->sa_home);
1088 }
1089}
1090
1091/** Return agent context. */
1092nta_agent_magic_t *nta_agent_magic(nta_agent_t const *agent)
1093{
1094 return agent ? agent->sa_magic : NULL((void*)0);
1095}
1096
1097/** Return @Contact header.
1098 *
1099 * Get a @Contact header, which can be used to reach @a agent.
1100 *
1101 * @param agent NTA agent object
1102 *
1103 * User agents can insert the @Contact header in the outgoing REGISTER,
1104 * INVITE, and ACK requests and replies to incoming INVITE and OPTIONS
1105 * transactions.
1106 *
1107 * Proxies can use the @Contact header to create appropriate @RecordRoute
1108 * headers:
1109 * @code
1110 * r_r = sip_record_route_create(msg_home(msg),
1111 * sip->sip_request->rq_url,
1112 * contact->m_url);
1113 * @endcode
1114 *
1115 * @return A sip_contact_t object corresponding to the @a agent.
1116 */
1117sip_contact_t *nta_agent_contact(nta_agent_t const *agent)
1118{
1119 return agent ? agent->sa_contact : NULL((void*)0);
1120}
1121
1122/** Return a list of @Via headers.
1123 *
1124 * Get @Via headers for all activated transport.
1125 *
1126 * @param agent NTA agent object
1127 *
1128 * @return A list of #sip_via_t objects used by the @a agent.
1129 */
1130sip_via_t *nta_agent_via(nta_agent_t const *agent)
1131{
1132 return agent ? agent->sa_vias : NULL((void*)0);
1133}
1134
1135/** Return a list of public (UPnP, STUN) @Via headers.
1136 *
1137 * Get public @Via headers for all activated transports.
1138 *
1139 * @param agent NTA agent object
1140 *
1141 * @return A list of #sip_via_t objects used by the @a agent.
1142 */
1143sip_via_t *nta_agent_public_via(nta_agent_t const *agent)
1144{
1145 return agent ? agent->sa_public_vias : NULL((void*)0);
1146}
1147
1148/** Match a @Via header @a v with @Via headers in @a agent.
1149 *
1150 */
1151static
1152sip_via_t *agent_has_via(nta_agent_t const *agent, sip_via_t const *via)
1153{
1154 sip_via_t const *v;
1155
1156 for (v = agent->sa_public_vias; v; v = v->v_next) {
1157 if (!su_casematch(via->v_host, v->v_host))
1158 continue;
1159 if (!su_strmatch(via->v_port, v->v_port))
1160 continue;
1161 if (!su_casematch(via->v_protocol, v->v_protocol))
1162 continue;
1163 return (sip_via_t *)v;
1164 }
1165
1166 for (v = agent->sa_vias; v; v = v->v_next) {
1167 if (!su_casematch(via->v_host, v->v_host))
1168 continue;
1169 if (!su_strmatch(via->v_port, v->v_port))
1170 continue;
1171 if (!su_casematch(via->v_protocol, v->v_protocol))
1172 continue;
1173 return (sip_via_t *)v;
1174 }
1175
1176 return NULL((void*)0);
1177}
1178
1179/** Return @UserAgent header.
1180 *
1181 * Get @UserAgent information with NTA version.
1182 *
1183 * @param agent NTA agent object (may be NULL)
1184 *
1185 * @return A string containing the @a agent version.
1186 */
1187char const *nta_agent_version(nta_agent_t const *agent)
1188{
1189 return "nta" "/" VERSION"1.12.10devel";
1190}
1191
1192/** Initialize default tag */
1193static int agent_tag_init(nta_agent_t *self)
1194{
1195 sip_contact_t *m = self->sa_contact;
1196 uint32_t hash = su_random();
1197
1198 if (m) {
1199 if (m->m_url->url_user)
1200 hash = 914715421U * hash + msg_hash_string(m->m_url->url_user);
1201 if (m->m_url->url_host)
1202 hash = 914715421U * hash + msg_hash_string(m->m_url->url_host);
1203 if (m->m_url->url_port)
1204 hash = 914715421U * hash + msg_hash_string(m->m_url->url_port);
1205 if (m->m_url->url_params)
1206 hash = 914715421U * hash + msg_hash_string(m->m_url->url_params);
1207 }
1208
1209 if (hash == 0)
1210 hash = 914715421U;
1211
1212 self->sa_branch = NTA_BRANCH_PRIME(uint64_t)(0xB9591D1C361C6521ULL) * (uint64_t)su_nanotime(NULL((void*)0));
1213 self->sa_branch *= hash;
1214
1215 self->sa_tags = NTA_TAG_PRIME(uint64_t)(0xB9591D1C361C6521ULL) * self->sa_branch;
1216
1217 return 0;
1218}
1219
1220/** Initialize agent timer. */
1221static
1222int agent_timer_init(nta_agent_t *agent)
1223{
1224 agent->sa_timer = su_timer_create(su_root_task(agent->sa_root),
1225 NTA_SIP_T1 / 8);
1226#if 0
1227 return su_timer_set(agent->sa_timer,
1228 agent_timer,
1229 agent);
1230#endif
1231 return -(agent->sa_timer == NULL((void*)0));
1232}
1233
1234/**
1235 * Agent timer routine.
1236 */
1237static
1238void agent_timer(su_root_magic_t *rm, su_timer_t *timer, nta_agent_t *agent)
1239{
1240 su_time_t stamp = su_now();
1241 uint32_t now = su_time_ms(stamp), next, latest;
1242
1243 now += now == 0;
1244
1245 agent->sa_next = 0;
1246
1247 agent->sa_in_timer = 1;
1248
1249
1250 _nta_outgoing_timer(agent);
1251 _nta_incoming_timer(agent);
1252
1253 agent->sa_in_timer = 0;
1254
1255 /* Calculate next timeout */
1256 next = latest = now + NTA_TIME_MAX + 1;
1257
1258#define NEXT_TIMEOUT(next, p, f, now) \
1259 (void)(p && (int32_t)(p->f - (next)) < 0 && \
1260 ((next) = ((int32_t)(p->f - (now)) > 0 ? p->f : (now))))
1261
1262 NEXT_TIMEOUT(next, agent->sa_out.re_list, orq_retry, now);
1263 NEXT_TIMEOUT(next, agent->sa_out.inv_completed->q_head, orq_timeout, now);
1264 NEXT_TIMEOUT(next, agent->sa_out.completed->q_head, orq_timeout, now);
1265 NEXT_TIMEOUT(next, agent->sa_out.inv_calling->q_head, orq_timeout, now);
1266 if (agent->sa_out.inv_proceeding->q_timeout)
1267 NEXT_TIMEOUT(next, agent->sa_out.inv_proceeding->q_head, orq_timeout, now);
1268 NEXT_TIMEOUT(next, agent->sa_out.trying->q_head, orq_timeout, now);
1269
1270 NEXT_TIMEOUT(next, agent->sa_in.preliminary->q_head, irq_timeout, now);
1271 NEXT_TIMEOUT(next, agent->sa_in.inv_completed->q_head, irq_timeout, now);
1272 NEXT_TIMEOUT(next, agent->sa_in.inv_confirmed->q_head, irq_timeout, now);
1273 NEXT_TIMEOUT(next, agent->sa_in.completed->q_head, irq_timeout, now);
1274 NEXT_TIMEOUT(next, agent->sa_in.re_list, irq_retry, now);
1275
1276 if (agent->sa_next)
1277 NEXT_TIMEOUT(next, agent, sa_next, now);
1278
1279#undef NEXT_TIMEOUT
1280
1281 if (next == latest) {
1282 /* Do not set timer? */
1283 /* check it there are still things queued, if there are, that means everything scheduled is > 15 days in the future */
1284 /* in this case, we had a large time shift, we should schedule for 15 days in the future (which is probably still before now) */
1285 /* and this should sort itself out on the next run through */
1286 if ( !agent->sa_out.completed->q_head && !agent->sa_out.trying->q_head && !agent->sa_out.inv_calling->q_head &&
1287 !agent->sa_out.re_list && !agent->sa_in.inv_confirmed->q_head && !agent->sa_in.preliminary->q_head &&
1288 !agent->sa_in.completed->q_head && !agent->sa_in.inv_completed->q_head && !agent->sa_in.re_list ) {
1289 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__
, 1289, "nta: timer not set\n" "%s", "")) : (void)0)
;
1290 return;
1291 }
1292 }
1293
1294 if (next == now) if (++next == 0) ++next;
1295
1296 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__
, 1296, "nta: timer %s to %ld ms\n", "set next", (long)(next -
now))) : (void)0)
;
1297
1298 agent->sa_next = next;
1299
1300 su_timer_set_at(timer, agent_timer, agent, su_time_add(stamp, next - now));
1301}
1302
1303/** Add uin32_t milliseconds to the time. */
1304static su_time_t add_milliseconds(su_time_t t0, uint32_t ms)
1305{
1306 unsigned long sec = ms / 1000, usec = (ms % 1000) * 1000;
1307
1308 t0.tv_usec += usec;
1309 t0.tv_sec += sec;
1310
1311 if (t0.tv_usec >= 1000000) {
1312 t0.tv_sec += 1;
1313 t0.tv_usec -= 1000000;
1314 }
1315
1316 return t0;
1317}
1318
1319/** Calculate nonzero value for timeout.
1320 *
1321 * Sets or adjusts agent timer when needed.
1322 *
1323 * @retval 0 if offset is 0
1324 * @retval timeout (millisecond counter) otherwise
1325 */
1326static
1327uint32_t set_timeout(nta_agent_t *agent, uint32_t offset)
1328{
1329 su_time_t now;
1330 uint32_t next, ms;
1331
1332 if (offset == 0)
1333 return 0;
1334
1335 now = su_now();
1336 ms = su_time_ms(now);
1337
1338 next = ms + offset;
1339
1340 if (next == 0) next = 1;
1341
1342 if (agent->sa_in_timer) /* Currently executing timer */
1343 return next;
1344
1345 if (agent->sa_next == 0 || (int32_t)(agent->sa_next - next - 5L) > 0) {
1346 /* Set timer */
1347 if (agent->sa_next)
1348 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__
, 1348, "nta: timer %s to %ld ms\n", "shortened", (long)offset
)) : (void)0)
;
1349 else
1350 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__
, 1350, "nta: timer %s to %ld ms\n", "set", (long)offset)) : (
void)0)
;
1351
1352 su_timer_set_at(agent->sa_timer, agent_timer, agent,
1353 add_milliseconds(now, offset));
1354 agent->sa_next = next;
1355 }
1356
1357 return next;
1358}
1359
1360
1361/** Return current timeval. */
1362static
1363su_time_t agent_now(nta_agent_t const *agent)
1364{
1365 return su_now();
1366}
1367
1368
1369/** Launch transaction terminator task */
1370static
1371int agent_launch_terminator(nta_agent_t *agent)
1372{
1373#ifdef TPTAG_THRPSIZE
1374 if (agent->sa_tport_threadpool) {
1375 su_home_threadsafe(agent->sa_home);
1376 return su_clone_start(agent->sa_root,
1377 agent->sa_terminator,
1378 NULL((void*)0),
1379 NULL((void*)0),
1380 NULL((void*)0));
1381 }
1382#endif
1383 return -1;
1384}
1385
1386/** Kill transaction terminator task */
1387static
1388void agent_kill_terminator(nta_agent_t *agent)
1389{
1390 su_clone_wait(agent->sa_root, agent->sa_terminator);
1391}
1392
1393
1394/**Set NTA Parameters.
1395 *
1396 * The nta_agent_set_params() function sets the stack parameters. The
1397 * parameters determine the way NTA handles the retransmissions, how long
1398 * NTA keeps transactions alive, does NTA apply proxy or user-agent logic to
1399 * INVITE transactions, or how the @Via headers are generated.
1400 *
1401 * @note
1402 * Setting the parameters NTATAG_MAXSIZE(), NTATAG_UDP_MTU(), NTATAG_MAX_PROCEEDING(),
1403 * NTATAG_SIP_T1X64(), NTATAG_SIP_T1(), NTATAG_SIP_T2(), NTATAG_SIP_T4() to
1404 * 0 selects the default value.
1405 *
1406 * @TAGS
1407 * NTATAG_ALIASES(),
1408 * NTATAG_BAD_REQ_MASK(), NTATAG_BAD_RESP_MASK(), NTATAG_BLACKLIST(),
1409 * NTATAG_CANCEL_2543(), NTATAG_CANCEL_487(), NTATAG_CLIENT_RPORT(),
1410 * NTATAG_DEBUG_DROP_PROB(), NTATAG_DEFAULT_PROXY(),
1411 * NTATAG_EXTRA_100(), NTATAG_GRAYLIST(),
1412 * NTATAG_MAXSIZE(), NTATAG_MAX_FORWARDS(), NTATAG_MERGE_482(), NTATAG_MCLASS()
1413 * NTATAG_PASS_100(), NTATAG_PASS_408(), NTATAG_PRELOAD(), NTATAG_PROGRESS(),
1414 * NTATAG_REL100(),
1415 * NTATAG_SERVER_RPORT(),
1416 * NTATAG_SIPFLAGS(),
1417 * NTATAG_SIP_T1X64(), NTATAG_SIP_T1(), NTATAG_SIP_T2(), NTATAG_SIP_T4(),
1418 * NTATAG_STATELESS(),
1419 * NTATAG_TAG_3261(), NTATAG_TCP_RPORT(), NTATAG_TIMEOUT_408(),
1420 * NTATAG_TLS_RPORT(),
1421 * NTATAG_TIMER_C(), NTATAG_MAX_PROCEEDING(),
1422 * NTATAG_UA(), NTATAG_UDP_MTU(), NTATAG_USER_VIA(),
1423 * NTATAG_USE_NAPTR(), NTATAG_USE_SRV() and NTATAG_USE_TIMESTAMP().
1424 *
1425 * @note The value from following tags are stored, but they currently do nothing:
1426 * NTATAG_SIGCOMP_ALGORITHM(), NTATAG_SIGCOMP_OPTIONS(), NTATAG_SMIME()
1427 */
1428int nta_agent_set_params(nta_agent_t *agent,
1429 tag_type_t tag, tag_value_t value, ...)
1430{
1431 int retval;
1432
1433 if (agent) {
1434 ta_list ta;
1435 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)
;
1436 retval = agent_set_params(agent, ta_args(ta)(ta).tl);
1437 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))
;
1438 } else {
1439 su_seterrno(EINVAL22);
1440 retval = -1;
1441 }
1442
1443 return retval;
1444}
1445
1446/** Internal function for setting tags */
1447static
1448int agent_set_params(nta_agent_t *agent, tagi_t *tags)
1449{
1450 int n, nC, m;
1451 unsigned bad_req_mask = agent->sa_bad_req_mask;
1452 unsigned bad_resp_mask = agent->sa_bad_resp_mask;
1453 usize_t maxsize = agent->sa_maxsize;
1454 usize_t max_proceeding = agent->sa_max_proceeding;
1455 unsigned max_forwards = agent->sa_max_forwards->mf_count;
1456 unsigned udp_mtu = agent->sa_udp_mtu;
1457 unsigned sip_t1 = agent->sa_t1;
1458 unsigned sip_t2 = agent->sa_t2;
1459 unsigned sip_t4 = agent->sa_t4;
1460 unsigned sip_t1x64 = agent->sa_t1x64;
1461 unsigned timer_c = agent->sa_timer_c;
1462 unsigned timer_d = 32000;
1463 unsigned graylist = agent->sa_graylist;
1464 unsigned blacklist = agent->sa_blacklist;
1465 int ua = agent->sa_is_a_uas;
1466 unsigned progress = agent->sa_progress;
1467 int stateless = agent->sa_is_stateless;
1468 unsigned drop_prob = agent->sa_drop_prob;
1469 int user_via = agent->sa_user_via;
1470 int extra_100 = agent->sa_extra_100;
1471 int pass_100 = agent->sa_pass_100;
1472 int timeout_408 = agent->sa_timeout_408;
1473 int pass_408 = agent->sa_pass_408;
1474 int merge_482 = agent->sa_merge_482;
1475 int cancel_2543 = agent->sa_cancel_2543;
1476 int cancel_487 = agent->sa_cancel_487;
1477 int invite_100rel = agent->sa_invite_100rel;
1478 int use_timestamp = agent->sa_timestamp;
1479 int use_naptr = agent->sa_use_naptr;
1480 int use_srv = agent->sa_use_srv;
1481 int srv_503 = agent->sa_srv_503;
1482 void *smime = agent->sa_smime;
1483 uint32_t flags = agent->sa_flags;
1484 int rport = agent->sa_rport;
1485 int server_rport = agent->sa_server_rport;
1486 int tcp_rport = agent->sa_tcp_rport;
1487 int tls_rport = agent->sa_tls_rport;
1488 unsigned preload = agent->sa_preload;
1489 unsigned threadpool = agent->sa_tport_threadpool;
1490 char const *sigcomp = agent->sa_sigcomp_options;
1491 char const *algorithm = NONE((void *)-1);
1492 msg_mclass_t const *mclass = NONE((void *)-1);
1493 sip_contact_t const *aliases = NONE((void *)-1);
1494 url_string_t const *proxy = NONE((void *)-1);
1495 tport_t *tport;
1496
1497 su_home_t *home = agent->sa_home;
1498
1499 n = tl_gets(tags,
1500 NTATAG_ALIASES_REF(aliases)ntatag_aliases_ref, siptag_contact_vr(&(aliases)),
1501 NTATAG_BAD_REQ_MASK_REF(bad_req_mask)ntatag_bad_req_mask_ref, tag_uint_vr(&(bad_req_mask)),
1502 NTATAG_BAD_RESP_MASK_REF(bad_resp_mask)ntatag_bad_resp_mask_ref, tag_uint_vr(&(bad_resp_mask)),
1503 NTATAG_BLACKLIST_REF(blacklist)ntatag_blacklist_ref, tag_uint_vr(&(blacklist)),
1504 NTATAG_CANCEL_2543_REF(cancel_2543)ntatag_cancel_2543_ref, tag_bool_vr(&(cancel_2543)),
1505 NTATAG_CANCEL_487_REF(cancel_487)ntatag_cancel_487_ref, tag_bool_vr(&(cancel_487)),
1506 NTATAG_DEBUG_DROP_PROB_REF(drop_prob)ntatag_debug_drop_prob_ref, tag_uint_vr(&(drop_prob)),
1507 NTATAG_DEFAULT_PROXY_REF(proxy)ntatag_default_proxy_ref, urltag_url_vr(&(proxy)),
1508 NTATAG_EXTRA_100_REF(extra_100)ntatag_extra_100_ref, tag_bool_vr(&(extra_100)),
1509 NTATAG_GRAYLIST_REF(graylist)ntatag_graylist_ref, tag_uint_vr(&(graylist)),
1510 NTATAG_MAXSIZE_REF(maxsize)ntatag_maxsize_ref, tag_usize_vr(&(maxsize)),
1511 NTATAG_MAX_PROCEEDING_REF(max_proceeding)ntatag_max_proceeding_ref, tag_usize_vr(&(max_proceeding)
)
,
1512 NTATAG_MAX_FORWARDS_REF(max_forwards)ntatag_max_forwards_ref, tag_uint_vr(&(max_forwards)),
1513 NTATAG_MCLASS_REF(mclass)ntatag_mclass_ref, tag_cptr_vr(&(mclass), (mclass)),
1514 NTATAG_MERGE_482_REF(merge_482)ntatag_merge_482_ref, tag_bool_vr(&(merge_482)),
1515 NTATAG_PASS_100_REF(pass_100)ntatag_pass_100_ref, tag_bool_vr(&(pass_100)),
1516 NTATAG_PASS_408_REF(pass_408)ntatag_pass_408_ref, tag_bool_vr(&(pass_408)),
1517 NTATAG_PRELOAD_REF(preload)ntatag_preload_ref, tag_uint_vr(&(preload)),
1518 NTATAG_PROGRESS_REF(progress)ntatag_progress_ref, tag_uint_vr(&(progress)),
1519 NTATAG_REL100_REF(invite_100rel)ntatag_rel100_ref, tag_bool_vr(&(invite_100rel)),
1520 NTATAG_RPORT_REF(rport)ntatag_client_rport_ref, tag_bool_vr(&(rport)),
1521 NTATAG_SERVER_RPORT_REF(server_rport)ntatag_server_rport_ref, tag_int_vr(&(server_rport)),
1522 NTATAG_SIGCOMP_ALGORITHM_REF(algorithm)ntatag_sigcomp_algorithm_ref, tag_str_vr(&(algorithm)),
1523 NTATAG_SIGCOMP_OPTIONS_REF(sigcomp)ntatag_sigcomp_options_ref, tag_str_vr(&(sigcomp)),
1524 NTATAG_SIPFLAGS_REF(flags)ntatag_sipflags_ref, tag_uint_vr(&(flags)),
1525 NTATAG_SIP_T1X64_REF(sip_t1x64)ntatag_sip_t1x64_ref, tag_uint_vr(&(sip_t1x64)),
1526 NTATAG_SIP_T1_REF(sip_t1)ntatag_sip_t1_ref, tag_uint_vr(&(sip_t1)),
1527 NTATAG_SIP_T2_REF(sip_t2)ntatag_sip_t2_ref, tag_uint_vr(&(sip_t2)),
1528 NTATAG_SIP_T4_REF(sip_t4)ntatag_sip_t4_ref, tag_uint_vr(&(sip_t4)),
1529#if HAVE_SOFIA_SMIME0
1530 NTATAG_SMIME_REF(smime)ntatag_smime_ref, tag_ptr_vr(&(smime), (smime)),
1531#endif
1532 NTATAG_STATELESS_REF(stateless)ntatag_stateless_ref, tag_bool_vr(&(stateless)),
1533 NTATAG_TCP_RPORT_REF(tcp_rport)ntatag_tcp_rport_ref, tag_bool_vr(&(tcp_rport)),
1534 NTATAG_TLS_RPORT_REF(tls_rport)ntatag_tls_rport_ref, tag_bool_vr(&(tls_rport)),
1535 NTATAG_TIMEOUT_408_REF(timeout_408)ntatag_timeout_408_ref, tag_bool_vr(&(timeout_408)),
1536 NTATAG_UA_REF(ua)ntatag_ua_ref, tag_bool_vr(&(ua)),
1537 NTATAG_UDP_MTU_REF(udp_mtu)ntatag_udp_mtu_ref, tag_uint_vr(&(udp_mtu)),
1538 NTATAG_USER_VIA_REF(user_via)ntatag_user_via_ref, tag_bool_vr(&(user_via)),
1539 NTATAG_USE_NAPTR_REF(use_naptr)ntatag_use_naptr_ref, tag_bool_vr(&(use_naptr)),
1540 NTATAG_USE_SRV_REF(use_srv)ntatag_use_srv_ref, tag_bool_vr(&(use_srv)),
1541 NTATAG_USE_TIMESTAMP_REF(use_timestamp)ntatag_use_timestamp_ref, tag_bool_vr(&(use_timestamp)),
1542#ifdef TPTAG_THRPSIZE
1543 /* If threadpool is enabled, start a separate "reaper thread" */
1544 TPTAG_THRPSIZE_REF(threadpool)tptag_thrpsize_ref, tag_uint_vr(&(threadpool)),
1545#endif
1546 NTATAG_SRV_503_REF(srv_503)ntatag_srv_503_ref, tag_bool_vr(&(srv_503)),
1547 TAG_END()(tag_type_t)0, (tag_value_t)0);
1548 nC = tl_gets(tags,
1549 NTATAG_TIMER_C_REF(timer_c)ntatag_timer_c_ref, tag_uint_vr(&(timer_c)),
1550 TAG_END()(tag_type_t)0, (tag_value_t)0);
1551 n += nC;
1552
1553 if (mclass != NONE((void *)-1))
1554 agent->sa_mclass = mclass ? mclass : sip_default_mclass();
1555
1556 m = 0;
1557 for (tport = agent->sa_tports; tport; tport = tport_next(tport)) {
1558 int m0 = tport_set_params(tport, TAG_NEXT(tags)tag_next, (tag_value_t)(tags));
1559 if (m0 < 0)
1560 return m0;
1561 if (m0 > m)
1562 m = m0;
1563 }
1564
1565 n += m;
1566
1567 if (aliases != NONE((void *)-1)) {
1568 sip_contact_t const *m, *m_next;
1569
1570 m = agent->sa_aliases;
1571 agent->sa_aliases = sip_contact_dup(home, aliases);
1572
1573 for (; m; m = m_next) { /* Free old aliases */
1574 m_next = m->m_next;
1575 su_free(home, (void *)m);
1576 }
1577 }
1578
1579 if (proxy != NONE((void *)-1)) {
1580 url_t *dp = url_hdup(home, proxy->us_url);
1581
1582 url_sanitize(dp);
1583
1584 if (dp == NULL((void*)0) || dp->url_type == url_sip || dp->url_type == url_sips) {
1585 if (agent->sa_default_proxy)
1586 su_free(home, agent->sa_default_proxy);
1587 agent->sa_default_proxy = dp;
1588 }
1589 else
1590 n = -1;
1591 }
1592
1593 if (algorithm != NONE((void *)-1))
1594 agent->sa_algorithm = su_strdup(home, algorithm);
1595
1596 if (!su_strmatch(sigcomp, agent->sa_sigcomp_options)) {
1597 msg_param_t const *l = NULL((void*)0);
1598 char *s = su_strdup(home, sigcomp);
1599 char *s1 = su_strdup(home, s), *s2 = s1;
1600
1601 if (s && s2 && msg_avlist_d(home, &s2, &l) == 0 && *s2 == '\0') {
1602 su_free(home, (void *)agent->sa_sigcomp_options);
1603 su_free(home, (void *)agent->sa_sigcomp_option_list);
1604 agent->sa_sigcomp_options = s;
1605 agent->sa_sigcomp_option_free = s1;
1606 agent->sa_sigcomp_option_list = l;
1607 } else {
1608 su_free(home, s);
1609 su_free(home, s1);
1610 su_free(home, (void *)l);
1611 n = -1;
1612 }
1613 }
1614
1615 if (maxsize == 0) maxsize = 2 * 1024 * 1024;
1616 if (maxsize > UINT32_MAX(4294967295U)) maxsize = UINT32_MAX(4294967295U);
1617 agent->sa_maxsize = maxsize;
1618
1619 if (max_proceeding == 0) max_proceeding = USIZE_MAX(2147483647 *2U +1U);
1620 agent->sa_max_proceeding = max_proceeding;
1621
1622 if (max_forwards == 0) max_forwards = 70; /* Default value */
1623 agent->sa_max_forwards->mf_count = max_forwards;
1624
1625 if (udp_mtu == 0) udp_mtu = 1300;
1626 if (udp_mtu > 65535) udp_mtu = 65535;
1627 if (agent->sa_udp_mtu != udp_mtu) {
1628 agent->sa_udp_mtu = udp_mtu;
1629 agent_set_udp_params(agent, udp_mtu);
1630 }
1631
1632 if (sip_t1 == 0) sip_t1 = NTA_SIP_T1;
1633 if (sip_t1 > NTA_TIME_MAX) sip_t1 = NTA_TIME_MAX;
1634 agent->sa_t1 = sip_t1;
1635
1636 if (sip_t2 == 0) sip_t2 = NTA_SIP_T2;
1637 if (sip_t2 > NTA_TIME_MAX) sip_t2 = NTA_TIME_MAX;
1638 agent->sa_t2 = sip_t2;
1639
1640 if (sip_t4 == 0) sip_t4 = NTA_SIP_T4;
1641 if (sip_t4 > NTA_TIME_MAX) sip_t4 = NTA_TIME_MAX;
1642 if (agent->sa_t4 != sip_t4) {
1643 incoming_queue_adjust(agent, agent->sa_in.inv_confirmed, sip_t4);
1644 outgoing_queue_adjust(agent, agent->sa_out.completed, sip_t4);
1645 }
1646 agent->sa_t4 = sip_t4;
1647
1648 if (sip_t1x64 == 0) sip_t1x64 = NTA_SIP_T1 * 64;
1649 if (sip_t1x64 > NTA_TIME_MAX) sip_t1x64 = NTA_TIME_MAX;
1650 if (agent->sa_t1x64 != sip_t1x64) {
1651 incoming_queue_adjust(agent, agent->sa_in.preliminary, sip_t1x64);
1652 incoming_queue_adjust(agent, agent->sa_in.completed, sip_t1x64);
1653 incoming_queue_adjust(agent, agent->sa_in.inv_completed, sip_t1x64);
1654 outgoing_queue_adjust(agent, agent->sa_out.trying, sip_t1x64);
1655 outgoing_queue_adjust(agent, agent->sa_out.inv_calling, sip_t1x64);
1656 }
1657 agent->sa_t1x64 = sip_t1x64;
1658 if (nC == 1) {
1659 agent->sa_use_timer_c = 1;
1660 if (timer_c == 0)
1661 timer_c = 185 * 1000;
1662 agent->sa_timer_c = timer_c;
1663 outgoing_queue_adjust(agent, agent->sa_out.inv_proceeding, timer_c);
1664 }
1665 if (timer_d < sip_t1x64)
1666 timer_d = sip_t1x64;
1667 outgoing_queue_adjust(agent, agent->sa_out.inv_completed, timer_d);
1668
1669 if (graylist > 24 * 60 * 60)
1670 graylist = 24 * 60 * 60;
1671 agent->sa_graylist = graylist;
1672
1673 if (blacklist > 24 * 60 * 60)
1674 blacklist = 24 * 60 * 60;
1675 agent->sa_blacklist = blacklist;
1676
1677 if (progress == 0)
1678 progress = 60 * 1000;
1679 agent->sa_progress = progress;
1680
1681 if (server_rport > 3)
1682 server_rport = 1;
1683 else if (server_rport < 0)
1684 server_rport = 1;
1685 agent->sa_server_rport = server_rport;
1686
1687 agent->sa_bad_req_mask = bad_req_mask;
1688 agent->sa_bad_resp_mask = bad_resp_mask;
1689
1690 agent->sa_is_a_uas = ua != 0;
1691 agent->sa_is_stateless = stateless != 0;
1692 agent->sa_drop_prob = drop_prob < 1000 ? drop_prob : 1000;
1693 agent->sa_user_via = user_via != 0;
1694 agent->sa_extra_100 = extra_100 != 0;
1695 agent->sa_pass_100 = pass_100 != 0;
1696 agent->sa_timeout_408 = timeout_408 != 0;
1697 agent->sa_pass_408 = pass_408 != 0;
1698 agent->sa_merge_482 = merge_482 != 0;
1699 agent->sa_cancel_2543 = cancel_2543 != 0;
1700 agent->sa_cancel_487 = cancel_487 != 0;
1701 agent->sa_invite_100rel = invite_100rel != 0;
1702 agent->sa_timestamp = use_timestamp != 0;
1703 agent->sa_use_naptr = use_naptr != 0;
1704 agent->sa_use_srv = use_srv != 0;
1705 agent->sa_srv_503 = srv_503 != 0;
1706 agent->sa_smime = smime;
1707 agent->sa_flags = flags & MSG_FLG_USERMASK;
1708 agent->sa_rport = rport != 0;
1709 agent->sa_tcp_rport = tcp_rport != 0;
1710 agent->sa_tls_rport = tls_rport != 0;
1711 agent->sa_preload = preload;
1712 agent->sa_tport_threadpool = threadpool;
1713
1714 return n;
1715}
1716
1717static
1718void agent_set_udp_params(nta_agent_t *self, usize_t udp_mtu)
1719{
1720 tport_t *tp;
1721
1722 /* Set via fields for the tports */
1723 for (tp = tport_primaries(self->sa_tports); tp; tp = tport_next(tp)) {
1724 if (tport_is_udp(tp))
1725 tport_set_params(tp,
1726 TPTAG_TIMEOUT(2 * self->sa_t1x64)tptag_timeout, tag_uint_v((2 * self->sa_t1x64)),
1727 TPTAG_MTU(udp_mtu)tptag_mtu, tag_usize_v((udp_mtu)),
1728 TAG_END()(tag_type_t)0, (tag_value_t)0);
1729 }
1730}
1731
1732/**Get NTA Parameters.
1733 *
1734 * The nta_agent_get_params() function retrieves the stack parameters. The
1735 * parameters determine the way NTA handles the retransmissions, how long
1736 * NTA keeps transactions alive, does NTA apply proxy or user-agent logic to
1737 * INVITE transactions, or how the @Via headers are generated.
1738 *
1739 * @TAGS
1740 * NTATAG_ALIASES_REF(), NTATAG_BLACKLIST_REF(),
1741 * NTATAG_CANCEL_2543_REF(), NTATAG_CANCEL_487_REF(),
1742 * NTATAG_CLIENT_RPORT_REF(), NTATAG_CONTACT_REF(),
1743 * NTATAG_DEBUG_DROP_PROB_REF(), NTATAG_DEFAULT_PROXY_REF(),
1744 * NTATAG_EXTRA_100_REF(), NTATAG_GRAYLIST_REF(),
1745 * NTATAG_MAXSIZE_REF(), NTATAG_MAX_FORWARDS_REF(), NTATAG_MCLASS_REF(),
1746 * NTATAG_MERGE_482_REF(), NTATAG_MAX_PROCEEDING_REF(),
1747 * NTATAG_PASS_100_REF(), NTATAG_PASS_408_REF(), NTATAG_PRELOAD_REF(),
1748 * NTATAG_PROGRESS_REF(),
1749 * NTATAG_REL100_REF(),
1750 * NTATAG_SERVER_RPORT_REF(),
1751 * NTATAG_SIGCOMP_ALGORITHM_REF(), NTATAG_SIGCOMP_OPTIONS_REF(),
1752 * NTATAG_SIPFLAGS_REF(),
1753 * NTATAG_SIP_T1_REF(), NTATAG_SIP_T1X64_REF(), NTATAG_SIP_T2_REF(),
1754 * NTATAG_SIP_T4_REF(), NTATAG_SMIME_REF(), NTATAG_STATELESS_REF(),
1755 * NTATAG_TAG_3261_REF(), NTATAG_TIMEOUT_408_REF(), NTATAG_TIMER_C_REF(),
1756 * NTATAG_UA_REF(), NTATAG_UDP_MTU_REF(), NTATAG_USER_VIA_REF(),
1757 * NTATAG_USE_NAPTR_REF(), NTATAG_USE_SRV_REF(),
1758 * and NTATAG_USE_TIMESTAMP_REF().
1759 *
1760 */
1761int nta_agent_get_params(nta_agent_t *agent,
1762 tag_type_t tag, tag_value_t value, ...)
1763{
1764 int n;
1765 ta_list ta;
1766
1767 if (agent) {
1768 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)
;
1769 n = agent_get_params(agent, ta_args(ta)(ta).tl);
1770 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))
;
1771 return n;
1772 }
1773
1774 su_seterrno(EINVAL22);
1775 return -1;
1776}
1777
1778/** Get NTA parameters */
1779static
1780int agent_get_params(nta_agent_t *agent, tagi_t *tags)
1781{
1782 return
1783 tl_tgets(tags,
1784 NTATAG_ALIASES(agent->sa_aliases)ntatag_aliases, siptag_contact_v((agent->sa_aliases)),
1785 NTATAG_BLACKLIST(agent->sa_blacklist)ntatag_blacklist, tag_uint_v((agent->sa_blacklist)),
1786 NTATAG_CANCEL_2543(agent->sa_cancel_2543)ntatag_cancel_2543, tag_bool_v((agent->sa_cancel_2543)),
1787 NTATAG_CANCEL_487(agent->sa_cancel_487)ntatag_cancel_487, tag_bool_v((agent->sa_cancel_487)),
1788 NTATAG_CLIENT_RPORT(agent->sa_rport)ntatag_client_rport, tag_bool_v((agent->sa_rport)),
1789 NTATAG_CONTACT(agent->sa_contact)ntatag_contact, siptag_contact_v((agent->sa_contact)),
1790 NTATAG_DEBUG_DROP_PROB(agent->sa_drop_prob)ntatag_debug_drop_prob, tag_uint_v((agent->sa_drop_prob)),
1791 NTATAG_DEFAULT_PROXY(agent->sa_default_proxy)ntatag_default_proxy, urltag_url_v((agent->sa_default_proxy
))
,
1792 NTATAG_EXTRA_100(agent->sa_extra_100)ntatag_extra_100, tag_bool_v((agent->sa_extra_100)),
1793 NTATAG_GRAYLIST(agent->sa_graylist)ntatag_graylist, tag_uint_v((agent->sa_graylist)),
1794 NTATAG_MAXSIZE(agent->sa_maxsize)ntatag_maxsize, tag_usize_v((agent->sa_maxsize)),
1795 NTATAG_MAX_PROCEEDING(agent->sa_max_proceeding)ntatag_max_proceeding, tag_usize_v((agent->sa_max_proceeding
))
,
1796 NTATAG_MAX_FORWARDS(agent->sa_max_forwards->mf_count)ntatag_max_forwards, tag_uint_v((agent->sa_max_forwards->
mf_count))
,
1797 NTATAG_MCLASS(agent->sa_mclass)ntatag_mclass, tag_cptr_v((agent->sa_mclass)),
1798 NTATAG_MERGE_482(agent->sa_merge_482)ntatag_merge_482, tag_bool_v((agent->sa_merge_482)),
1799 NTATAG_PASS_100(agent->sa_pass_100)ntatag_pass_100, tag_bool_v((agent->sa_pass_100)),
1800 NTATAG_PASS_408(agent->sa_pass_408)ntatag_pass_408, tag_bool_v((agent->sa_pass_408)),
1801 NTATAG_PRELOAD(agent->sa_preload)ntatag_preload, tag_uint_v((agent->sa_preload)),
1802 NTATAG_PROGRESS(agent->sa_progress)ntatag_progress, tag_uint_v((agent->sa_progress)),
1803 NTATAG_REL100(agent->sa_invite_100rel)ntatag_rel100, tag_bool_v((agent->sa_invite_100rel)),
1804 NTATAG_SERVER_RPORT((int)(agent->sa_server_rport))ntatag_server_rport, tag_int_v(((int)(agent->sa_server_rport
)))
,
1805 NTATAG_SIGCOMP_ALGORITHM(agent->sa_algorithm)ntatag_sigcomp_algorithm, tag_str_v((agent->sa_algorithm)),
1806 NTATAG_SIGCOMP_OPTIONS(agent->sa_sigcomp_options ?ntatag_sigcomp_options, tag_str_v((agent->sa_sigcomp_options
? agent->sa_sigcomp_options : "sip"))
1807 agent->sa_sigcomp_options :ntatag_sigcomp_options, tag_str_v((agent->sa_sigcomp_options
? agent->sa_sigcomp_options : "sip"))
1808 "sip")ntatag_sigcomp_options, tag_str_v((agent->sa_sigcomp_options
? agent->sa_sigcomp_options : "sip"))
,
1809 NTATAG_SIPFLAGS(agent->sa_flags)ntatag_sipflags, tag_uint_v((agent->sa_flags)),
1810 NTATAG_SIP_T1(agent->sa_t1)ntatag_sip_t1, tag_uint_v((agent->sa_t1)),
1811 NTATAG_SIP_T1X64(agent->sa_t1x64)ntatag_sip_t1x64, tag_uint_v((agent->sa_t1x64)),
1812 NTATAG_SIP_T2(agent->sa_t2)ntatag_sip_t2, tag_uint_v((agent->sa_t2)),
1813 NTATAG_SIP_T4(agent->sa_t4)ntatag_sip_t4, tag_uint_v((agent->sa_t4)),
1814#if HAVE_SOFIA_SMIME0
1815 NTATAG_SMIME(agent->sa_smime)ntatag_smime, tag_ptr_v((agent->sa_smime)),
1816#else
1817 NTATAG_SMIME(NULL)ntatag_smime, tag_ptr_v((((void*)0))),
1818#endif
1819 NTATAG_STATELESS(agent->sa_is_stateless)ntatag_stateless, tag_bool_v((agent->sa_is_stateless)),
1820 NTATAG_TAG_3261(1)ntatag_tag_3261, tag_bool_v((1)),
1821 NTATAG_TIMEOUT_408(agent->sa_timeout_408)ntatag_timeout_408, tag_bool_v((agent->sa_timeout_408)),
1822 NTATAG_TIMER_C(agent->sa_timer_c)ntatag_timer_c, tag_uint_v((agent->sa_timer_c)),
1823 NTATAG_UA(agent->sa_is_a_uas)ntatag_ua, tag_bool_v((agent->sa_is_a_uas)),
1824 NTATAG_UDP_MTU(agent->sa_udp_mtu)ntatag_udp_mtu, tag_uint_v((agent->sa_udp_mtu)),
1825 NTATAG_USER_VIA(agent->sa_user_via)ntatag_user_via, tag_bool_v((agent->sa_user_via)),
1826 NTATAG_USE_NAPTR(agent->sa_use_naptr)ntatag_use_naptr, tag_bool_v((agent->sa_use_naptr)),
1827 NTATAG_USE_SRV(agent->sa_use_srv)ntatag_use_srv, tag_bool_v((agent->sa_use_srv)),
1828 NTATAG_USE_TIMESTAMP(agent->sa_timestamp)ntatag_use_timestamp, tag_bool_v((agent->sa_timestamp)),
1829 NTATAG_SRV_503(agent->sa_srv_503)ntatag_srv_503, tag_bool_v((agent->sa_srv_503)),
1830 TAG_END()(tag_type_t)0, (tag_value_t)0);
1831}
1832
1833/**Get NTA statistics.
1834 *
1835 * The nta_agent_get_stats() function retrieves the stack statistics.
1836 *
1837 * @TAGS
1838 * NTATAG_S_ACKED_TR_REF(),
1839 * NTATAG_S_BAD_MESSAGE_REF(),
1840 * NTATAG_S_BAD_REQUEST_REF(),
1841 * NTATAG_S_BAD_RESPONSE_REF(),
1842 * NTATAG_S_CANCELED_TR_REF(),
1843 * NTATAG_S_CLIENT_TR_REF(),
1844 * NTATAG_S_DIALOG_TR_REF(),
1845 * NTATAG_S_DROP_REQUEST_REF(),
1846 * NTATAG_S_DROP_RESPONSE_REF(),
1847 * NTATAG_S_IRQ_HASH_REF(),
1848 * NTATAG_S_IRQ_HASH_USED_REF(),
1849 * NTATAG_S_LEG_HASH_REF(),
1850 * NTATAG_S_LEG_HASH_USED_REF(),
1851 * NTATAG_S_MERGED_REQUEST_REF(),
1852 * NTATAG_S_ORQ_HASH_REF(),
1853 * NTATAG_S_ORQ_HASH_USED_REF(),
1854 * NTATAG_S_RECV_MSG_REF(),
1855 * NTATAG_S_RECV_REQUEST_REF(),
1856 * NTATAG_S_RECV_RESPONSE_REF(),
1857 * NTATAG_S_RECV_RETRY_REF(),
1858 * NTATAG_S_RETRY_REQUEST_REF(),
1859 * NTATAG_S_RETRY_RESPONSE_REF(),
1860 * NTATAG_S_SENT_MSG_REF(),
1861 * NTATAG_S_SENT_REQUEST_REF(),
1862 * NTATAG_S_SENT_RESPONSE_REF(),
1863 * NTATAG_S_SERVER_TR_REF(),
1864 * NTATAG_S_TOUT_REQUEST_REF(),
1865 * NTATAG_S_TOUT_RESPONSE_REF(),
1866 * NTATAG_S_TRLESS_200_REF(),
1867 * NTATAG_S_TRLESS_REQUEST_REF(),
1868 * NTATAG_S_TRLESS_RESPONSE_REF(), and
1869 * NTATAG_S_TRLESS_TO_TR_REF(),
1870 */
1871int nta_agent_get_stats(nta_agent_t *agent,
1872 tag_type_t tag, tag_value_t value, ...)
1873{
1874 int n;
1875 ta_list ta;
1876
1877 if (!agent)
1878 return su_seterrno(EINVAL22), -1;
1879
1880 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)
;
1881
1882 n = tl_tgets(ta_args(ta)(ta).tl,
1883 NTATAG_S_IRQ_HASH(agent->sa_incoming->iht_size)ntatag_s_irq_hash, tag_usize_v(agent->sa_incoming->iht_size
)
,
1884 NTATAG_S_ORQ_HASH(agent->sa_outgoing->oht_size)ntatag_s_orq_hash, tag_usize_v(agent->sa_outgoing->oht_size
)
,
1885 NTATAG_S_LEG_HASH(agent->sa_dialogs->lht_size)ntatag_s_leg_hash, tag_usize_v(agent->sa_dialogs->lht_size
)
,
1886 NTATAG_S_IRQ_HASH_USED(agent->sa_incoming->iht_used)ntatag_s_irq_hash_used, tag_usize_v(agent->sa_incoming->
iht_used)
,
1887 NTATAG_S_ORQ_HASH_USED(agent->sa_outgoing->oht_used)ntatag_s_orq_hash_used, tag_usize_v(agent->sa_outgoing->
oht_used)
,
1888 NTATAG_S_LEG_HASH_USED(agent->sa_dialogs->lht_used)ntatag_s_leg_hash_used, tag_usize_v(agent->sa_dialogs->
lht_used)
,
1889 NTATAG_S_RECV_MSG(agent->sa_stats->as_recv_msg)ntatag_s_recv_msg, tag_usize_v(agent->sa_stats->as_recv_msg
)
,
1890 NTATAG_S_RECV_REQUEST(agent->sa_stats->as_recv_request)ntatag_s_recv_request, tag_usize_v(agent->sa_stats->as_recv_request
)
,
1891 NTATAG_S_RECV_RESPONSE(agent->sa_stats->as_recv_response)ntatag_s_recv_response, tag_usize_v(agent->sa_stats->as_recv_response
)
,
1892 NTATAG_S_BAD_MESSAGE(agent->sa_stats->as_bad_message)ntatag_s_bad_message, tag_usize_v(agent->sa_stats->as_bad_message
)
,
1893 NTATAG_S_BAD_REQUEST(agent->sa_stats->as_bad_request)ntatag_s_bad_request, tag_usize_v(agent->sa_stats->as_bad_request
)
,
1894 NTATAG_S_BAD_RESPONSE(agent->sa_stats->as_bad_response)ntatag_s_bad_response, tag_usize_v(agent->sa_stats->as_bad_response
)
,
1895 NTATAG_S_DROP_REQUEST(agent->sa_stats->as_drop_request)ntatag_s_drop_request, tag_usize_v(agent->sa_stats->as_drop_request
)
,
1896 NTATAG_S_DROP_RESPONSE(agent->sa_stats->as_drop_response)ntatag_s_drop_response, tag_usize_v(agent->sa_stats->as_drop_response
)
,
1897 NTATAG_S_CLIENT_TR(agent->sa_stats->as_client_tr)ntatag_s_client_tr, tag_usize_v(agent->sa_stats->as_client_tr
)
,
1898 NTATAG_S_SERVER_TR(agent->sa_stats->as_server_tr)ntatag_s_server_tr, tag_usize_v(agent->sa_stats->as_server_tr
)
,
1899 NTATAG_S_DIALOG_TR(agent->sa_stats->as_dialog_tr)ntatag_s_dialog_tr, tag_usize_v(agent->sa_stats->as_dialog_tr
)
,
1900 NTATAG_S_ACKED_TR(agent->sa_stats->as_acked_tr)ntatag_s_acked_tr, tag_usize_v(agent->sa_stats->as_acked_tr
)
,
1901 NTATAG_S_CANCELED_TR(agent->sa_stats->as_canceled_tr)ntatag_s_canceled_tr, tag_usize_v(agent->sa_stats->as_canceled_tr
)
,
1902 NTATAG_S_TRLESS_REQUEST(agent->sa_stats->as_trless_request)ntatag_s_trless_request, tag_usize_v(agent->sa_stats->as_trless_request
)
,
1903 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
)
,
1904 NTATAG_S_TRLESS_RESPONSE(agent->sa_stats->as_trless_response)ntatag_s_trless_response, tag_usize_v(agent->sa_stats->
as_trless_response)
,
1905 NTATAG_S_TRLESS_200(agent->sa_stats->as_trless_200)ntatag_s_trless_200, tag_usize_v(agent->sa_stats->as_trless_200
)
,
1906 NTATAG_S_MERGED_REQUEST(agent->sa_stats->as_merged_request)ntatag_s_merged_request, tag_usize_v(agent->sa_stats->as_merged_request
)
,
1907 NTATAG_S_SENT_MSG(agent->sa_stats->as_sent_msg)ntatag_s_sent_msg, tag_usize_v(agent->sa_stats->as_sent_msg
)
,
1908 NTATAG_S_SENT_REQUEST(agent->sa_stats->as_sent_request)ntatag_s_sent_request, tag_usize_v(agent->sa_stats->as_sent_request
)
,
1909 NTATAG_S_SENT_RESPONSE(agent->sa_stats->as_sent_response)ntatag_s_sent_response, tag_usize_v(agent->sa_stats->as_sent_response
)
,
1910 NTATAG_S_RETRY_REQUEST(agent->sa_stats->as_retry_request)ntatag_s_retry_request, tag_usize_v(agent->sa_stats->as_retry_request
)
,
1911 NTATAG_S_RETRY_RESPONSE(agent->sa_stats->as_retry_response)ntatag_s_retry_response, tag_usize_v(agent->sa_stats->as_retry_response
)
,
1912 NTATAG_S_RECV_RETRY(agent->sa_stats->as_recv_retry)ntatag_s_recv_retry, tag_usize_v(agent->sa_stats->as_recv_retry
)
,
1913 NTATAG_S_TOUT_REQUEST(agent->sa_stats->as_tout_request)ntatag_s_tout_request, tag_usize_v(agent->sa_stats->as_tout_request
)
,
1914 NTATAG_S_TOUT_RESPONSE(agent->sa_stats->as_tout_response)ntatag_s_tout_response, tag_usize_v(agent->sa_stats->as_tout_response
)
,
1915 TAG_END()(tag_type_t)0, (tag_value_t)0);
1916
1917 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))
;
1918
1919 return n;
1920}
1921
1922/**Calculate a new unique tag.
1923 *
1924 * This function generates a series of 2**64 unique tags for @From or @To
1925 * headers. The start of the tag series is derived from the NTP time the NTA
1926 * agent was initialized.
1927 *
1928 */
1929char const *nta_agent_newtag(su_home_t *home, char const *fmt, nta_agent_t *sa)
1930{
1931 char tag[(8 * 8 + 4)/ 5 + 1];
1932
1933 if (sa == NULL((void*)0))
1934 return su_seterrno(EINVAL22), NULL((void*)0);
1935
1936 /* XXX - use a cryptographically safe func here? */
1937 sa->sa_tags += NTA_TAG_PRIME(uint64_t)(0xB9591D1C361C6521ULL);
1938
1939 msg_random_token(tag, sizeof(tag) - 1, &sa->sa_tags, sizeof(sa->sa_tags));
1940
1941 if (fmt && fmt[0])
1942 return su_sprintf(home, fmt, tag);
1943 else
1944 return su_strdup(home, tag);
1945}
1946
1947/**
1948 * Calculate branch value.
1949 */
1950static char const *stateful_branch(su_home_t *home, nta_agent_t *sa)
1951{
1952 char branch[(8 * 8 + 4)/ 5 + 1];
1953
1954 /* XXX - use a cryptographically safe func here? */
1955 sa->sa_branch += NTA_BRANCH_PRIME(uint64_t)(0xB9591D1C361C6521ULL);
1956
1957 msg_random_token(branch, sizeof(branch) - 1,
1958 &sa->sa_branch, sizeof(sa->sa_branch));
1959
1960 return su_sprintf(home, "branch=z9hG4bK%s", branch);
1961}
1962
1963#include <sofia-sip/su_md5.h>
1964
1965/**
1966 * Calculate branch value for stateless operation.
1967 *
1968 * XXX - should include HMAC of previous @Via line.
1969 */
1970static
1971char const *stateless_branch(nta_agent_t *sa,
1972 msg_t *msg,
1973 sip_t const *sip,
1974 tp_name_t const *tpn)
1975{
1976 su_md5_t md5[1];
1977 uint8_t digest[SU_MD5_DIGEST_SIZE16];
1978 char branch[(SU_MD5_DIGEST_SIZE16 * 8 + 4)/ 5 + 1];
1979 sip_route_t const *r;
1980
1981 assert(sip->sip_request)((sip->sip_request) ? (void) (0) : __assert_fail ("sip->sip_request"
, "nta.c", 1981, __PRETTY_FUNCTION__))
;
1982
1983 if (!sip->sip_via)
1984 return stateful_branch(msg_home(msg)((su_home_t*)(msg)), sa);
1985
1986 su_md5_init(md5);
1987
1988 su_md5_str0update(md5, tpn->tpn_host);
1989 su_md5_str0update(md5, tpn->tpn_port);
1990
1991 url_update(md5, sip->sip_request->rq_url);
1992 if (sip->sip_call_id) {
1993 su_md5_str0update(md5, sip->sip_call_id->i_id);
1994 }
1995 if (sip->sip_from) {
1996 url_update(md5, sip->sip_from->a_url);
1997 su_md5_stri0update(md5, sip->sip_from->a_tag);
1998 }
1999 if (sip->sip_to) {
2000 url_update(md5, sip->sip_to->a_url);
2001 /* XXX - some broken implementations include To tag in CANCEL */
2002 /* su_md5_str0update(md5, sip->sip_to->a_tag); */
2003 }
2004 if (sip->sip_cseq) {
2005 uint32_t cseq = htonl(sip->sip_cseq->cs_seq)(__extension__ ({ unsigned int __v, __x = (sip->sip_cseq->
cs_seq); if (__builtin_constant_p (__x)) __v = ((((__x) &
0xff000000) >> 24) | (((__x) & 0x00ff0000) >>
8) | (((__x) & 0x0000ff00) << 8) | (((__x) & 0x000000ff
) << 24)); else __asm__ ("bswap %0" : "=r" (__v) : "0" (
__x)); __v; }))
;
2006 su_md5_update(md5, &cseq, sizeof(cseq));
2007 }
2008
2009 for (r = sip->sip_route; r; r = r->r_next)
2010 url_update(md5, r->r_url);
2011
2012 su_md5_digest(md5, digest);
2013
2014 msg_random_token(branch, sizeof(branch) - 1, digest, sizeof(digest));
2015
2016 return su_sprintf(msg_home(msg)((su_home_t*)(msg)), "branch=z9hG4bK.%s", branch);
2017}
2018
2019/* ====================================================================== */
2020/* 2) Transport interface */
2021
2022/* Local prototypes */
2023static int agent_create_master_transport(nta_agent_t *self, tagi_t *tags);
2024static int agent_init_via(nta_agent_t *self, tport_t *primaries, int use_maddr);
2025static int agent_init_contact(nta_agent_t *self);
2026static void agent_recv_message(nta_agent_t *agent,
2027 tport_t *tport,
2028 msg_t *msg,
2029 sip_via_t *tport_via,
2030 su_time_t now);
2031static void agent_tp_error(nta_agent_t *agent,
2032 tport_t *tport,
2033 int errcode,
2034 char const *remote);
2035static void agent_update_tport(nta_agent_t *agent, tport_t *);
2036
2037/**For each transport, we have name used by tport module, SRV prefixes used
2038 * for resolving, and NAPTR service/conversion.
2039 */
2040static
2041struct sipdns_tport {
2042 char name[6]; /**< Named used by tport module */
2043 char port[6]; /**< Default port number */
2044 char prefix[14]; /**< Prefix for SRV domains */
2045 char service[10]; /**< NAPTR service */
2046}
2047#define SIPDNS_TRANSPORTS(6) (6)
2048const sipdns_tports[SIPDNS_TRANSPORTS(6)] = {
2049 { "udp", "5060", "_sip._udp.", "SIP+D2U" },
2050 { "tcp", "5060", "_sip._tcp.", "SIP+D2T" },
2051 { "sctp", "5060", "_sip._sctp.", "SIP+D2S" },
2052 { "tls", "5061", "_sips._tcp.", "SIPS+D2T" },
2053 { "ws", "5080", "_sips._ws.", "SIP+D2W" },
2054 { "wss", "5081", "_sips._wss.", "SIPS+D2W" },
2055};
2056
2057static char const * const tports_sip[] =
2058 {
2059 "udp", "tcp", "sctp", "ws", NULL((void*)0)
2060 };
2061
2062static char const * const tports_sips[] =
2063 {
2064 "tls", "wss", "ws", NULL((void*)0)
2065 };
2066
2067static tport_stack_class_t nta_agent_class[1] =
2068 {{
2069 sizeof(nta_agent_class),
2070 agent_recv_message,
2071 agent_tp_error,
2072 nta_msg_create_for_transport,
2073 agent_update_tport,
2074 }};
2075
2076
2077/** Add a transport to the agent.
2078 *
2079 * Creates a new transport and binds it
2080 * to the port specified by the @a uri. The @a uri must have sip: or sips:
2081 * scheme or be a wildcard uri ("*"). The @a uri syntax allowed is as
2082 * follows:
2083 *
2084 * @code url <scheme>:<host>[:<port>]<url-params> @endcode
2085 * where <url-params> may be
2086 * @code
2087 * ;transport=<xxx>
2088 * ;maddr=<actual addr>
2089 * ;comp=sigcomp
2090 * @endcode
2091 *
2092 * The scheme part determines which transports are used. "sip" implies UDP
2093 * and TCP, "sips" TLS over TCP. In the future, more transports can be
2094 * supported, for instance, "sip" can use SCTP or DCCP, "sips" DTLS or TLS
2095 * over SCTP.
2096 *
2097 * The "host" part determines what address/domain name is used in @Contact.
2098 * An "*" in "host" part is shorthand for any local IP address. 0.0.0.0
2099 * means that the only the IPv4 addresses are used. [::] means that only
2100 * the IPv6 addresses are used. If a domain name or a specific IP address
2101 * is given as "host" part, an additional "maddr" parameter can be used to
2102 * control which addresses are used by the stack when binding listen
2103 * sockets for incoming requests.
2104 *
2105 * The "port" determines what port is used in contact, and to which port the
2106 * stack binds in order to listen for incoming requests. Empty or missing
2107 * port means that default port should be used (5060 for sip, 5061 for
2108 * sips). An "*" in "port" part means any port, i.e., the stack binds to an
2109 * ephemeral port.
2110 *
2111 * The "transport" parameter determines the transport protocol that is used
2112 * and how they are preferred. If no protocol is specified, both UDP and TCP
2113 * are used for SIP URL and TLS for SIPS URL. The preference can be
2114 * indicated with a comma-separated list of transports, for instance,
2115 * parameter @code transport=tcp,udp @endcode indicates that TCP is
2116 * preferred to UDP.
2117 *
2118 * The "maddr" parameter determines to which address the stack binds in
2119 * order to listen for incoming requests. An "*" in "maddr" parameter is
2120 * shorthand for any local IP address. 0.0.0.0 means that only IPv4 sockets
2121 * are created. [::] means that only IPv6 sockets are created.
2122 *
2123 * The "comp" parameter determines the supported compression protocol.
2124 * Currently only sigcomp is supported (with suitable library).
2125 *
2126 * @par Examples:
2127 * @code sip:172.21.40.24;maddr=* @endcode \n
2128 * @code sip:172.21.40.24:50600;transport=TCP,UDP;comp=sigcomp @endcode \n
2129 * @code sips:* @endcode
2130 *
2131 * @return
2132 * On success, zero is returned. On error, -1 is returned, and @a errno is
2133 * set appropriately.
2134 */
2135int nta_agent_add_tport(nta_agent_t *self,
2136 url_string_t const *uri,
2137 tag_type_t tag, tag_value_t value, ...)
2138{
2139 url_t *url;
2140 char tp[32];
2141 char maddr[256];
2142 char comp[32];
2143 tp_name_t tpn[1] = {{ NULL((void*)0) }};
2144 char const * const * tports = tports_sip;
2145 int error;
2146 ta_list ta;
2147 char *tps[9] = {0};
2148
2149 if (self == NULL((void*)0)) {
2150 su_seterrno(EINVAL22);
2151 return -1;
2152 }
2153
2154 if (uri == NULL((void*)0))
2155 uri = (url_string_t *)"sip:*";
2156 else if (url_string_p(uri) ?
2157 strcmp(uri->us_str, "*")__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(uri->us_str) && __builtin_constant_p ("*") &&
(__s1_len = __builtin_strlen (uri->us_str), __s2_len = __builtin_strlen
("*"), (!((size_t)(const void *)((uri->us_str) + 1) - (size_t
)(const void *)(uri->us_str) == 1) || __s1_len >= 4) &&
(!((size_t)(const void *)(("*") + 1) - (size_t)(const void *
)("*") == 1) || __s2_len >= 4)) ? __builtin_strcmp (uri->
us_str, "*") : (__builtin_constant_p (uri->us_str) &&
((size_t)(const void *)((uri->us_str) + 1) - (size_t)(const
void *)(uri->us_str) == 1) && (__s1_len = __builtin_strlen
(uri->us_str), __s1_len < 4) ? (__builtin_constant_p (
"*") && ((size_t)(const void *)(("*") + 1) - (size_t)
(const void *)("*") == 1) ? __builtin_strcmp (uri->us_str,
"*") : (__extension__ ({ const unsigned char *__s2 = (const unsigned
char *) (const char *) ("*"); int __result = (((const unsigned
char *) (const char *) (uri->us_str))[0] - __s2[0]); if (
__s1_len > 0 && __result == 0) { __result = (((const
unsigned char *) (const char *) (uri->us_str))[1] - __s2[
1]); if (__s1_len > 1 && __result == 0) { __result
= (((const unsigned char *) (const char *) (uri->us_str))
[2] - __s2[2]); if (__s1_len > 2 && __result == 0)
__result = (((const unsigned char *) (const char *) (uri->
us_str))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p
("*") && ((size_t)(const void *)(("*") + 1) - (size_t
)(const void *)("*") == 1) && (__s2_len = __builtin_strlen
("*"), __s2_len < 4) ? (__builtin_constant_p (uri->us_str
) && ((size_t)(const void *)((uri->us_str) + 1) - (
size_t)(const void *)(uri->us_str) == 1) ? __builtin_strcmp
(uri->us_str, "*") : (- (__extension__ ({ const unsigned char
*__s2 = (const unsigned char *) (const char *) (uri->us_str
); int __result = (((const unsigned char *) (const char *) ("*"
))[0] - __s2[0]); if (__s2_len > 0 && __result == 0
) { __result = (((const unsigned char *) (const char *) ("*")
)[1] - __s2[1]); if (__s2_len > 1 && __result == 0
) { __result = (((const unsigned char *) (const char *) ("*")
)[2] - __s2[2]); if (__s2_len > 2 && __result == 0
) __result = (((const unsigned char *) (const char *) ("*"))[
3] - __s2[3]); } } __result; })))) : __builtin_strcmp (uri->
us_str, "*")))); })
== 0 :
2158 uri->us_url->url_type == url_any) {
2159 uri = (url_string_t *)"sip:*:*";
2160 }
2161
2162 if (!(url = url_hdup(self->sa_home, uri->us_url)) ||
2163 (url->url_type != url_sip && url->url_type != url_sips)) {
2164 if (url_string_p(uri))
2165 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__
, 2165, "nta: %s: invalid bind URL\n", uri->us_str)) : (void
)0)
;
2166 else
2167 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__
, 2167, "nta: invalid bind URL\n" "%s", "")) : (void)0)
;
2168 su_seterrno(EINVAL22);
2169 return -1;
2170 }
2171
2172 tpn->tpn_canon = url->url_host;
2173 tpn->tpn_host = url->url_host;
2174 tpn->tpn_port = url_port(url);
2175
2176 if (url->url_type == url_sip) {
2177 tpn->tpn_proto = "*";
2178 tports = tports_sip;
2179 if (!tpn->tpn_port || !tpn->tpn_port[0])
2180 tpn->tpn_port = SIP_DEFAULT_SERV"5060";
2181 }
2182 else {
2183 assert(url->url_type == url_sips)((url->url_type == url_sips) ? (void) (0) : __assert_fail (
"url->url_type == url_sips", "nta.c", 2183, __PRETTY_FUNCTION__
))
;
2184 tpn->tpn_proto = "*";
2185 tports = tports_sips;
2186 if (!tpn->tpn_port || !tpn->tpn_port[0])
2187 tpn->tpn_port = SIPS_DEFAULT_SERV"5061";
2188 }
2189
2190 if (url->url_params) {
2191 if (url_param(url->url_params, "transport", tp, sizeof(tp)) > 0) {
2192 if (strchr(tp, ',')(__extension__ (__builtin_constant_p (',') && !__builtin_constant_p
(tp) && (',') == '\0' ? (char *) __rawmemchr (tp, ','
) : __builtin_strchr (tp, ',')))
) {
2193 int i; char *t;
2194
2195 /* Split tp into transports */
2196 for (i = 0, t = tp; t && i < 8; i++) {
2197 tps[i] = t;
2198 if ((t = strchr(t, ',')(__extension__ (__builtin_constant_p (',') && !__builtin_constant_p
(t) && (',') == '\0' ? (char *) __rawmemchr (t, ',')
: __builtin_strchr (t, ',')))
))
2199 *t++ = '\0';
2200 }
2201
2202 tps[i] = NULL((void*)0);
2203 tports = (char const * const *)tps;
2204 } else {
2205 tpn->tpn_proto = tp;
2206 }
2207 }
2208 if (url_param(url->url_params, "maddr", maddr, sizeof(maddr)) > 0)
2209 tpn->tpn_host = maddr;
2210 if (url_param(url->url_params, "comp", comp, sizeof(comp)) > 0)
2211 tpn->tpn_comp = comp;
2212
2213 if (tpn->tpn_comp &&
2214 (nta_compressor_vtable == NULL((void*)0) ||
2215 !su_casematch(tpn->tpn_comp, nta_compressor_vtable->ncv_name))) {
2216 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__
, 2217, "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)
2217 (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__
, 2217, "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)
;
2218 }
2219 }
2220
2221 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)
;
2222
2223 if (self->sa_tports == NULL((void*)0)) {
2224 if (agent_create_master_transport(self, ta_args(ta)(ta).tl) < 0) {
2225 error = su_errno();
2226 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__
, 2227, "nta: cannot create master transport: %s\n", su_strerror
(error))) : (void)0)
2227 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__
, 2227, "nta: cannot create master transport: %s\n", su_strerror
(error))) : (void)0)
;
2228 goto error;
2229 }
2230 }
2231
2232 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) {
2233 error = su_errno();
2234 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__
, 2240, "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)
2235 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__
, 2240, "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)
2236 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__
, 2240, "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)
2237 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__
, 2240, "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)
2238 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__
, 2240, "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)
2239 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__
, 2240, "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)
2240 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__
, 2240, "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)
;
2241 goto error;
2242 }
2243 else
2244 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__
, 2249, "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)
2245 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__
, 2249, "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)
2246 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__
, 2249, "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)
2247 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__
, 2249, "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)
2248 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__
, 2249, "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)
2249 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__
, 2249, "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)
;
2250
2251 /* XXX - when to use maddr? */
2252 if ((agent_init_via(self, tport_primaries(self->sa_tports), 0)) < 0) {
2253 error = su_errno();
2254 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__
, 2254, "nta: cannot create Via headers\n" "%s", "")) : (void
)0)
;
2255 goto error;
2256 }
2257 else
2258 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__
, 2258, "nta: Via fields initialized\n" "%s", "")) : (void)0)
;
2259
2260 if ((agent_init_contact(self)) < 0) {
2261 error = su_errno();
2262 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__
, 2262, "nta: cannot create Contact header\n" "%s", "")) : (void
)0)
;
2263 goto error;
2264 }
2265 else
2266 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__
, 2266, "nta: Contact header created\n" "%s", "")) : (void)0)
;
2267
2268 su_free(self->sa_home, url);
2269 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))
;
2270
2271 return 0;
2272
2273 error:
2274 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))
;
2275 su_seterrno(error);
2276 return -1;
2277}
2278
2279static
2280int agent_create_master_transport(nta_agent_t *self, tagi_t *tags)
2281{
2282 self->sa_tports =
2283 tport_tcreate(self, nta_agent_class, self->sa_root,
2284 TPTAG_IDLE(1800000)tptag_idle, tag_uint_v((1800000)),
2285 TAG_NEXT(tags)tag_next, (tag_value_t)(tags));
2286
2287 if (!self->sa_tports)
2288 return -1;
2289
2290 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__
, 2290, "nta: master transport created\n" "%s", "")) : (void)
0)
;
2291
2292 return 0;
2293}
2294
2295
2296/** Initialize @Via headers. */
2297static
2298int agent_init_via(nta_agent_t *self, tport_t *primaries, int use_maddr)
2299{
2300 sip_via_t *via = NULL((void*)0), *new_via, *dup_via, *v, **vv = &via;
1
'via' initialized to a null pointer value
2301 sip_via_t *new_vias, **next_new_via, *new_publics, **next_new_public;
2302 tport_t *tp;
2303 su_addrinfo_t const *ai;
2304
2305 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))
];
2306
2307 su_home_auto(autohome, sizeof autohome);
2308
2309 self->sa_tport_ip4 = 0;
2310 self->sa_tport_ip6 = 0;
2311 self->sa_tport_udp = 0;
2312 self->sa_tport_tcp = 0;
2313 self->sa_tport_sctp = 0;
2314 self->sa_tport_tls = 0;
2315 self->sa_tport_ws = 0;
2316 self->sa_tport_wss = 0;
2317
2318 /* Set via fields for the tports */
2319 for (tp = primaries; tp; tp = tport_next(tp)) {
2
Loop condition is true. Entering loop body
12
Loop condition is false. Execution continues on line 2410
2320 int maddr;
2321 tp_name_t tpn[1];
2322 char const *comp = NULL((void*)0);
2323
2324 *tpn = *tport_name(tp);
2325
2326 assert(tpn->tpn_proto)((tpn->tpn_proto) ? (void) (0) : __assert_fail ("tpn->tpn_proto"
, "nta.c", 2326, __PRETTY_FUNCTION__))
;
2327 assert(tpn->tpn_canon)((tpn->tpn_canon) ? (void) (0) : __assert_fail ("tpn->tpn_canon"
, "nta.c", 2327, __PRETTY_FUNCTION__))
;
2328 assert(tpn->tpn_host)((tpn->tpn_host) ? (void) (0) : __assert_fail ("tpn->tpn_host"
, "nta.c", 2328, __PRETTY_FUNCTION__))
;
2329 assert(tpn->tpn_port)((tpn->tpn_port) ? (void) (0) : __assert_fail ("tpn->tpn_port"
, "nta.c", 2329, __PRETTY_FUNCTION__))
;
2330
2331#if 0
2332 if (getenv("SIP_UDP_CONNECT")
2333 && strcmp(tpn->tpn_proto, "udp")__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(tpn->tpn_proto) && __builtin_constant_p ("udp") &&
(__s1_len = __builtin_strlen (tpn->tpn_proto), __s2_len =
__builtin_strlen ("udp"), (!((size_t)(const void *)((tpn->
tpn_proto) + 1) - (size_t)(const void *)(tpn->tpn_proto) ==
1) || __s1_len >= 4) && (!((size_t)(const void *)
(("udp") + 1) - (size_t)(const void *)("udp") == 1) || __s2_len
>= 4)) ? __builtin_strcmp (tpn->tpn_proto, "udp") : (__builtin_constant_p
(tpn->tpn_proto) && ((size_t)(const void *)((tpn->
tpn_proto) + 1) - (size_t)(const void *)(tpn->tpn_proto) ==
1) && (__s1_len = __builtin_strlen (tpn->tpn_proto
), __s1_len < 4) ? (__builtin_constant_p ("udp") &&
((size_t)(const void *)(("udp") + 1) - (size_t)(const void *
)("udp") == 1) ? __builtin_strcmp (tpn->tpn_proto, "udp") :
(__extension__ ({ const unsigned char *__s2 = (const unsigned
char *) (const char *) ("udp"); int __result = (((const unsigned
char *) (const char *) (tpn->tpn_proto))[0] - __s2[0]); if
(__s1_len > 0 && __result == 0) { __result = (((const
unsigned char *) (const char *) (tpn->tpn_proto))[1] - __s2
[1]); if (__s1_len > 1 && __result == 0) { __result
= (((const unsigned char *) (const char *) (tpn->tpn_proto
))[2] - __s2[2]); if (__s1_len > 2 && __result == 0
) __result = (((const unsigned char *) (const char *) (tpn->
tpn_proto))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p
("udp") && ((size_t)(const void *)(("udp") + 1) - (size_t
)(const void *)("udp") == 1) && (__s2_len = __builtin_strlen
("udp"), __s2_len < 4) ? (__builtin_constant_p (tpn->tpn_proto
) && ((size_t)(const void *)((tpn->tpn_proto) + 1)
- (size_t)(const void *)(tpn->tpn_proto) == 1) ? __builtin_strcmp
(tpn->tpn_proto, "udp") : (- (__extension__ ({ const unsigned
char *__s2 = (const unsigned char *) (const char *) (tpn->
tpn_proto); int __result = (((const unsigned char *) (const char
*) ("udp"))[0] - __s2[0]); if (__s2_len > 0 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
"udp"))[1] - __s2[1]); if (__s2_len > 1 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
"udp"))[2] - __s2[2]); if (__s2_len > 2 && __result
== 0) __result = (((const unsigned char *) (const char *) ("udp"
))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (tpn
->tpn_proto, "udp")))); })
== 0)
2334 tport_set_params(tp, TPTAG_CONNECT(1)tptag_connect, tag_bool_v((1)), TAG_END()(tag_type_t)0, (tag_value_t)0);
2335#endif
2336
2337 if (tport_has_ip4(tp)) self->sa_tport_ip4 = 1;
3
Taking false branch
2338
2339#if SU_HAVE_IN61
2340 if (tport_has_ip6(tp)) self->sa_tport_ip6 = 1;
4
Taking false branch
2341#endif
2342
2343 if (su_casematch(tpn->tpn_proto, "udp"))
5
Taking false branch
2344 self->sa_tport_udp = 1;
2345 else if (su_casematch(tpn->tpn_proto, "tcp"))
6
Taking false branch
2346 self->sa_tport_tcp = 1;
2347 else if (su_casematch(tpn->tpn_proto, "sctp"))
7
Taking false branch
2348 self->sa_tport_sctp = 1;
2349 else if (su_casematch(tpn->tpn_proto, "ws"))
8
Taking false branch
2350 self->sa_tport_ws = 1;
2351 else if (su_casematch(tpn->tpn_proto, "wss"))
9
Taking false branch
2352 self->sa_tport_wss = 1;
2353
2354 if (tport_has_tls(tp)) self->sa_tport_tls = 1;
10
Taking false branch
2355
2356 ai = tport_get_address(tp);
2357
2358 for (; ai; ai = ai->ai_next) {
11
Loop condition is false. Execution continues on line 2319
2359 char host[TPORT_HOSTPORTSIZE(55)] = "";
2360 char sport[8];
2361 char const *canon = ai->ai_canonname;
2362 su_sockaddr_t *su = (void *)ai->ai_addr;
2363 int port;
2364
2365 if (su) {
2366 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);
2367 maddr = use_maddr && !su_casematch(canon, host);
2368 port = ntohs(su->su_port)(__extension__ ({ unsigned short int __v, __x = (unsigned short
int) (su->su_sin.sin_port); if (__builtin_constant_p (__x
)) __v = ((unsigned short int) ((((__x) >> 8) & 0xff
) | (((__x) & 0xff) << 8))); else __asm__ ("rorw $8, %w0"
: "=r" (__v) : "0" (__x) : "cc"); __v; }))
;
2369 }
2370 else {
2371 msg_random_token(host, 16, NULL((void*)0), 0);
2372 canon = strcat(host, ".is.invalid");
2373 maddr = 0;
2374 port = 0;
2375 }
2376
2377 if (su_casenmatch(tpn->tpn_proto, "tls", 3)
2378 ? port == SIPS_DEFAULT_PORTSIPS_DEFAULT_PORT
2379 : port == SIP_DEFAULT_PORTSIP_DEFAULT_PORT)
2380 port = 0;
2381
2382 snprintf(sport, sizeof sport, ":%u", port);
2383
2384 comp = tpn->tpn_comp;
2385
2386 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__
, 2392, "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)
2387 "%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__
, 2392, "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)
2388 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__
, 2392, "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)
2389 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__
, 2392, "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)
2390 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__
, 2392, "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)
2391 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__
, 2392, "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)
2392 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__
, 2392, "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)
;
2393
2394 v = sip_via_format(autohome,
2395 "%s/%s %s%s%s%s%s%s",
2396 SIP_VERSION_CURRENTsip_version_2_0, tpn->tpn_proto,
2397 canon, port ? sport : "",
2398 maddr ? ";maddr=" : "", maddr ? host : "",
2399 comp ? ";comp=" : "", comp ? comp : "");
2400 if (v == NULL((void*)0))
2401 goto error;
2402
2403 v->v_comment = tpn->tpn_ident;
2404 v->v_common->h_data = tp; /* Nasty trick */
2405 *vv = v; vv = &(*vv)->v_next;
2406 }
2407 }
2408
2409 /* Duplicate the list bind to the transports */
2410 new_via = sip_via_dup(self->sa_home, via);
2411 /* Duplicate the complete list shown to the application */
2412 dup_via = sip_via_dup(self->sa_home, via);
2413
2414 if (via && (!new_via || !dup_via)) {
2415 msg_header_free(self->sa_home, (void *)new_via);
2416 msg_header_free(self->sa_home, (void *)dup_via);
2417 goto error;
2418 }
2419
2420 new_vias = NULL((void*)0), next_new_via = &new_vias;
2421 new_publics = NULL((void*)0), next_new_public = &new_publics;
2422
2423 /* Set via field magic for the tports */
2424 for (tp = primaries; tp; tp = tport_next(tp)) {
13
Loop condition is true. Entering loop body
2425 assert(via->v_common->h_data == tp)((via->v_common->h_data == tp) ? (void) (0) : __assert_fail
("via->v_common->h_data == tp", "nta.c", 2425, __PRETTY_FUNCTION__
))
;
2426 v = tport_magic(tp);
2427 tport_set_magic(tp, new_via);
2428 msg_header_free(self->sa_home, (void *)v);
2429
2430 if (tport_is_public(tp))
14
Taking false branch
2431 *next_new_public = dup_via;
2432 else
2433 *next_new_via = dup_via;
2434
2435 while (via->v_next && via->v_next->v_common->h_data == tp)
15
Access to field 'v_next' results in a dereference of a null pointer (loaded from variable 'via')
2436 via = via->v_next, new_via = new_via->v_next, dup_via = dup_via->v_next;
2437
2438 via = via->v_next;
2439 /* Break the link in via list between transports */
2440 vv = &new_via->v_next, new_via = *vv, *vv = NULL((void*)0);
2441 vv = &dup_via->v_next, dup_via = *vv, *vv = NULL((void*)0);
2442
2443 if (tport_is_public(tp))
2444 while (*next_new_public) next_new_public = &(*next_new_public)->v_next;
2445 else
2446 while (*next_new_via) next_new_via = &(*next_new_via)->v_next;
2447 }
2448
2449 assert(dup_via == NULL)((dup_via == ((void*)0)) ? (void) (0) : __assert_fail ("dup_via == ((void*)0)"
, "nta.c", 2449, __PRETTY_FUNCTION__))
;
2450 assert(new_via == NULL)((new_via == ((void*)0)) ? (void) (0) : __assert_fail ("new_via == ((void*)0)"
, "nta.c", 2450, __PRETTY_FUNCTION__))
;
2451
2452 if (self->sa_tport_udp)
2453 agent_set_udp_params(self, self->sa_udp_mtu);
2454
2455 v = self->sa_vias;
2456 self->sa_vias = new_vias;
2457 msg_header_free(self->sa_home, (void *)v);
2458
2459 v = self->sa_public_vias;
2460 self->sa_public_vias = new_publics;
2461 msg_header_free(self->sa_home, (void *)v);
2462
2463 su_home_deinit(autohome);
2464
2465 return 0;
2466
2467 error:
2468 su_home_deinit(autohome);
2469 return -1;
2470}
2471
2472
2473/** Initialize main contact header. */
2474static
2475int agent_init_contact(nta_agent_t *self)
2476{
2477 sip_via_t const *v1, *v2;
2478 char const *tp;
2479
2480 if (self->sa_contact)
2481 return 0;
2482
2483 for (v1 = self->sa_vias ? self->sa_vias : self->sa_public_vias;
2484 v1;
2485 v1 = v1->v_next) {
2486 if (host_is_ip_address(v1->v_host)) {
2487 if (!host_is_local(v1->v_host))
2488 break;
2489 }
2490 else if (!host_has_domain_invalid(v1->v_host)) {
2491 break;
2492 }
2493 }
2494
2495 if (v1 == NULL((void*)0))
2496 v1 = self->sa_vias ? self->sa_vias : self->sa_public_vias;
2497
2498 if (!v1)
2499 return -1;
2500
2501 tp = strrchr(v1->v_protocol, '/');
2502 if (!tp++)
2503 return -1;
2504
2505 v2 = v1->v_next;
2506
2507 if (v2 &&
2508 su_casematch(v1->v_host, v2->v_host) &&
2509 su_casematch(v1->v_port, v2->v_port)) {
2510 char const *p1 = v1->v_protocol, *p2 = v2->v_protocol;
2511
2512 if (!su_casematch(p1, sip_transport_udp))
2513 p1 = v2->v_protocol, p2 = v1->v_protocol;
2514
2515 if (su_casematch(p1, sip_transport_udp) &&
2516 su_casematch(p2, sip_transport_tcp))
2517 /* Do not include transport if we have both UDP and TCP */
2518 tp = NULL((void*)0);
2519 }
2520
2521 self->sa_contact =
2522 sip_contact_create_from_via_with_transport(self->sa_home, v1, NULL((void*)0), tp);
2523
2524 if (!self->sa_contact)
2525 return -1;
2526
2527 agent_tag_init(self);
2528
2529 return 0;
2530}
2531
2532/** Return @Via line corresponging to tport. */
2533static
2534sip_via_t const *agent_tport_via(tport_t *tport)
2535{
2536 sip_via_t *v = tport_magic(tport);
2537 while (v && v->v_next)
2538 v = v->v_next;
2539 return v;
2540}
2541
2542/** Insert @Via to a request message */
2543static
2544int outgoing_insert_via(nta_outgoing_t *orq,
2545 sip_via_t const *via)
2546{
2547 nta_agent_t *self = orq->orq_agent;
2548 msg_t *msg = orq->orq_request;
2549 sip_t *sip = sip_object(msg);
2550 char const *branch = orq->orq_via_branch;
2551 int already = orq->orq_user_via || orq->orq_via_added;
2552 int user_via = orq->orq_user_via;
2553 sip_via_t *v;
2554 int clear = 0;
2555
2556 assert(sip)((sip) ? (void) (0) : __assert_fail ("sip", "nta.c", 2556, __PRETTY_FUNCTION__
))
; assert(via)((via) ? (void) (0) : __assert_fail ("via", "nta.c", 2556, __PRETTY_FUNCTION__
))
;
2557
2558 if (already && sip->sip_via) {
2559 /* Use existing @Via */
2560 v = sip->sip_via;
2561 }
2562 else if (msg && via && sip->sip_request &&
2563 (v = sip_via_copy(msg_home(msg)((su_home_t*)(msg)), via))) {
2564 if (msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)v) < 0)
2565 return -1;
2566 orq->orq_via_added = 1;
2567 }
2568 else
2569 return -1;
2570
2571 if (!v->v_rport &&
2572 ((self->sa_rport && v->v_protocol == sip_transport_udp) ||
2573 (self->sa_tcp_rport && v->v_protocol == sip_transport_tcp) ||
2574 (self->sa_tls_rport && v->v_protocol == sip_transport_tls)))
2575 msg_header_add_param(msg_home(msg)((su_home_t*)(msg)), v->v_common, "rport");
2576
2577 if (!orq->orq_tpn->tpn_comp)
2578 msg_header_remove_param(v->v_common, "comp");
2579
2580 if (branch && branch != v->v_branch) {
2581 char const *bvalue = branch + strcspn(branch, "=")__extension__ ({ char __r0, __r1, __r2; (__builtin_constant_p
("=") && ((size_t)(const void *)(("=") + 1) - (size_t
)(const void *)("=") == 1) ? ((__builtin_constant_p (branch) &&
((size_t)(const void *)((branch) + 1) - (size_t)(const void *
)(branch) == 1)) ? __builtin_strcspn (branch, "=") : ((__r0 =
((const char *) ("="))[0], __r0 == '\0') ? strlen (branch) :
((__r1 = ((const char *) ("="))[1], __r1 == '\0') ? __strcspn_c1
(branch, __r0) : ((__r2 = ((const char *) ("="))[2], __r2 ==
'\0') ? __strcspn_c2 (branch, __r0, __r1) : (((const char *)
("="))[3] == '\0' ? __strcspn_c3 (branch, __r0, __r1, __r2) :
__builtin_strcspn (branch, "=")))))) : __builtin_strcspn (branch
, "=")); })
;
2582 if (*bvalue) bvalue++;
2583 if (!v->v_branch || !su_casematch(bvalue, v->v_branch))
2584 msg_header_replace_param(msg_home(msg)((su_home_t*)(msg)), v->v_common, branch);
2585 }
2586
2587 if (!su_casematch(via->v_protocol, v->v_protocol))
2588 clear = 1, v->v_protocol = via->v_protocol;
2589
2590 /* XXX - should we do this? */
2591 if ((!user_via || !v->v_host) &&
2592 !su_strmatch(via->v_host, v->v_host))
2593 clear = 1, v->v_host = via->v_host;
2594
2595 if ((!user_via || !v->v_port ||
2596 /* Replace port in user Via only if we use udp and no rport */
2597 (v->v_protocol == sip_transport_udp && !v->v_rport &&
2598 !orq->orq_stateless)) &&
2599 !su_strmatch(via->v_port, v->v_port))
2600 clear = 1, v->v_port = via->v_port;
2601
2602 if (clear)
2603 msg_fragment_clear(v->v_common);
2604
2605 return 0;
2606}
2607
2608/** Get destination name from @Via.
2609 *
2610 * If @a using_rport is non-null, try rport.
2611 * If *using_rport is non-zero, try rport even if <protocol> is not UDP.
2612 * If <protocol> is UDP, set *using_rport to zero.
2613 */
2614static
2615int nta_tpn_by_via(tp_name_t *tpn, sip_via_t const *v, int *using_rport)
2616{
2617 if (!v)
2618 return -1;
2619
2620 tpn->tpn_proto = sip_via_transport(v);
2621 tpn->tpn_canon = v->v_host;
2622
2623 if (v->v_maddr)
2624 tpn->tpn_host = v->v_maddr;
2625 else if (v->v_received)
2626 tpn->tpn_host = v->v_received;
2627 else
2628 tpn->tpn_host = v->v_host;
2629
2630 tpn->tpn_port = sip_via_port(v, using_rport);
2631 tpn->tpn_comp = v->v_comp;
2632 tpn->tpn_ident = NULL((void*)0);
2633
2634 return 0;
2635}
2636
2637/** Get transport name from URL. */
2638static int
2639nta_tpn_by_url(su_home_t *home,
2640 tp_name_t *tpn,
2641 char const **scheme,
2642 char const **port,
2643 url_string_t const *us)
2644{
2645 url_t url[1];
2646 isize_t n;
2647 char *b;
2648
2649 n = url_xtra(us->us_url);
2650 b = su_alloc(home, n);
2651
2652 if (b == NULL((void*)0) || url_dup(b, n, url, us->us_url) < 0) {
2653 su_free(home, b);
2654 return -1;
2655 }
2656
2657 if (url->url_type != url_sip &&
2658 url->url_type != url_sips &&
2659 url->url_type != url_im &&
2660 url->url_type != url_pres) {
2661 su_free(home, b);
2662 return -1;
2663 }
2664
2665 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__
, 2665, "nta: selecting scheme %s\n", url->url_scheme)) : (
void)0)
;
2666
2667 *scheme = url->url_scheme;
2668
2669 tpn->tpn_proto = NULL((void*)0);
2670 tpn->tpn_canon = url->url_host;
2671 tpn->tpn_host = url->url_host;
2672
2673 if (url->url_params) {
2674 for (b = (char *)url->url_params; b[0]; b += n) {
2675 n = strcspn(b, ";")__extension__ ({ char __r0, __r1, __r2; (__builtin_constant_p
(";") && ((size_t)(const void *)((";") + 1) - (size_t
)(const void *)(";") == 1) ? ((__builtin_constant_p (b) &&
((size_t)(const void *)((b) + 1) - (size_t)(const void *)(b)
== 1)) ? __builtin_strcspn (b, ";") : ((__r0 = ((const char *
) (";"))[0], __r0 == '\0') ? strlen (b) : ((__r1 = ((const char
*) (";"))[1], __r1 == '\0') ? __strcspn_c1 (b, __r0) : ((__r2
= ((const char *) (";"))[2], __r2 == '\0') ? __strcspn_c2 (b
, __r0, __r1) : (((const char *) (";"))[3] == '\0' ? __strcspn_c3
(b, __r0, __r1, __r2) : __builtin_strcspn (b, ";")))))) : __builtin_strcspn
(b, ";")); })
;
2676
2677 if (n > 10 && su_casenmatch(b, "transport=", 10))
2678 tpn->tpn_proto = b + 10;
2679 else if (n > 5 && su_casenmatch(b, "comp=", 5))
2680 tpn->tpn_comp = b + 5;
2681 else if (n > 6 && su_casenmatch(b, "maddr=", 6))
2682 tpn->tpn_host = b + 6;
2683
2684 if (b[n])
2685 b[n++] = '\0';
2686 }
2687 }
2688
2689 if ((*port = url->url_port))
2690 tpn->tpn_port = url->url_port;
2691
2692 tpn->tpn_ident = NULL((void*)0);
2693
2694 if (tpn->tpn_proto) {
2695 if (su_casematch(url->url_scheme, "sips") && su_casematch(tpn->tpn_proto, "ws")) {
2696 tpn->tpn_proto = "wss";
2697 }
2698 return 1;
2699 }
2700
2701 if (su_casematch(url->url_scheme, "sips"))
2702 tpn->tpn_proto = "tls";
2703 else
2704 tpn->tpn_proto = "*";
2705
2706 return 0;
2707}
2708
2709/** Handle transport errors. */
2710static
2711void agent_tp_error(nta_agent_t *agent,
2712 tport_t *tport,
2713 int errcode,
2714 char const *remote)
2715{
2716 su_llog(nta_log, 1,_su_llog(nta_log, 1, "nta.c", (const char *)__func__, 2719, "nta_agent: tport: %s%s%s\n"
, remote ? remote : "", remote ? ": " : "", su_strerror(errcode
))
2717 "nta_agent: tport: %s%s%s\n",_su_llog(nta_log, 1, "nta.c", (const char *)__func__, 2719, "nta_agent: tport: %s%s%s\n"
, remote ? remote : "", remote ? ": " : "", su_strerror(errcode
))
2718 remote ? remote : "", remote ? ": " : "",_su_llog(nta_log, 1, "nta.c", (const char *)__func__, 2719, "nta_agent: tport: %s%s%s\n"
, remote ? remote : "", remote ? ": " : "", su_strerror(errcode
))
2719 su_strerror(errcode))_su_llog(nta_log, 1, "nta.c", (const char *)__func__, 2719, "nta_agent: tport: %s%s%s\n"
, remote ? remote : "", remote ? ": " : "", su_strerror(errcode
))
;
2720
2721 if (agent->sa_error_tport) {
2722 agent->sa_error_tport(agent->sa_error_magic, agent, tport);
2723 }
2724}
2725
2726/** Handle updated transport addresses */
2727static void agent_update_tport(nta_agent_t *self, tport_t *tport)
2728{
2729 /* Initialize local Vias first */
2730 agent_init_via(self, tport_primaries(self->sa_tports), 0);
2731
2732 if (self->sa_update_tport) {
2733 self->sa_update_tport(self->sa_update_magic, self);
2734 }
2735 else {
2736 /* XXX - we should do something else? */
2737 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__
, 2738, "%s(%p): %s\n", "nta", (void *)self, "transport address updated"
)) : (void)0)
2738 "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__
, 2738, "%s(%p): %s\n", "nta", (void *)self, "transport address updated"
)) : (void)0)
;
2739 }
2740}
2741
2742/* ====================================================================== */
2743/* 3) Message dispatch */
2744
2745static void agent_recv_request(nta_agent_t *agent,
2746 msg_t *msg,
2747 sip_t *sip,
2748 tport_t *tport);
2749static int agent_check_request_via(nta_agent_t *agent,
2750 msg_t *msg,
2751 sip_t *sip,
2752 sip_via_t *v,
2753 tport_t *tport);
2754static int agent_aliases(nta_agent_t const *, url_t [], tport_t *);
2755static void agent_recv_response(nta_agent_t*, msg_t *, sip_t *,
2756 sip_via_t *, tport_t*);
2757static void agent_recv_garbage(nta_agent_t*, msg_t*, tport_t*);
2758
2759#if HAVE_SOFIA_SRESOLV1
2760static void outgoing_resolve(nta_outgoing_t *orq,
2761 int explicit_transport,
2762 enum nta_res_order_e order);
2763su_inlinestatic inline void outgoing_cancel_resolver(nta_outgoing_t *orq);
2764su_inlinestatic inline void outgoing_destroy_resolver(nta_outgoing_t *orq);
2765static int outgoing_other_destinations(nta_outgoing_t const *orq);
2766static int outgoing_try_another(nta_outgoing_t *orq);
2767#else
2768#define outgoing_other_destinations(orq) (0)
2769#define outgoing_try_another(orq) (0)
2770#endif
2771
2772/** Handle incoming message. */
2773static
2774void agent_recv_message(nta_agent_t *agent,
2775 tport_t *tport,
2776 msg_t *msg,
2777 sip_via_t *tport_via,
2778 su_time_t now)
2779{
2780 sip_t *sip = sip_object(msg);
2781
2782 if (sip && sip->sip_request) {
2783 agent_recv_request(agent, msg, sip, tport);
2784 }
2785 else if (sip && sip->sip_status) {
2786 agent_recv_response(agent, msg, sip, tport_via, tport);
2787 }
2788 else {
2789 agent_recv_garbage(agent, msg, tport);
2790 }
2791}
2792
2793#ifdef HAVE_ZLIB_COMPRESS1
2794int sip_content_encoding_Xflate(msg_t *msg, sip_t *sip, int inflate, int check)
2795{
2796 char const *method_name;
2797 unsigned cseq = sip->sip_cseq ? sip->sip_cseq->cs_seq : 0;
2798 int ok = !check;
2799
2800 if (!sip->sip_payload) {
2801 return 0;
2802 }
2803
2804 if (sip->sip_request) {
2805 method_name = sip->sip_request->rq_method_name;
2806 } else if (sip->sip_cseq) {
2807 method_name = sip->sip_cseq->cs_method_name;
2808 } else {
2809 method_name = "Unknown";
2810 }
2811
2812 if (!ok) {
2813 if (sip->sip_content_encoding && sip->sip_content_encoding->k_items) {
2814 const char *val = sip->sip_content_encoding->k_items[0];
2815 if (val && (!strcasecmp(val, "gzip") || !strcasecmp(val, "deflate"))) {
2816 ok = 1;
2817 }
2818 }
2819 }
2820
2821 if (ok) {
2822 unsigned long n = 0;
2823 void *decoded = NULL((void*)0);
2824 const char *id = "N/A";
2825 const char *orig_payload = sip->sip_payload->pl_data;
2826
2827 n = sip->sip_payload->pl_len * 10;
2828
2829 decoded = su_alloc(msg_home(msg)((su_home_t*)(msg)), n);
2830 assert(decoded)((decoded) ? (void) (0) : __assert_fail ("decoded", "nta.c", 2830
, __PRETTY_FUNCTION__))
;
2831
2832 if (inflate) {
2833 uncompress(decoded, &n, (void *)sip->sip_payload->pl_data, (unsigned long)sip->sip_payload->pl_len);
2834 } else {
2835 compress(decoded, &n, (void *)sip->sip_payload->pl_data, (unsigned long)sip->sip_payload->pl_len);
2836 }
2837
2838 sip->sip_payload = sip_payload_create(msg_home(msg)((su_home_t*)(msg)), decoded, n);
2839 sip->sip_content_encoding = sip_content_encoding_make(msg_home(msg)((su_home_t*)(msg)), "deflate");
2840
2841 if (sip->sip_call_id) {
2842 id = sip->sip_call_id->i_id;
2843 }
2844
2845 if (inflate) {
2846 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__
, 2846, "nta: %s (%u) (%s) Inflating compressed body:\n%s\n",
method_name, cseq, id, (char *)decoded)) : (void)0)
;
2847 } else {
2848 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__
, 2848, "nta: %s (%u) (%s) Deflating compressed body:\n%s\n",
method_name, cseq, id, orig_payload)) : (void)0)
;
2849 }
2850
2851 return 1;
2852 }
2853
2854 return 0;
2855}
2856#endif
2857
2858/** @internal Handle incoming requests. */
2859static
2860void agent_recv_request(nta_agent_t *agent,
2861 msg_t *msg,
2862 sip_t *sip,
2863 tport_t *tport)
2864{
2865 nta_leg_t *leg;
2866 nta_incoming_t *irq, *merge = NULL((void*)0), *ack = NULL((void*)0), *cancel = NULL((void*)0);
2867 sip_method_t method = sip->sip_request->rq_method;
2868 char const *method_name = sip->sip_request->rq_method_name;
2869 url_t url[1];
2870 unsigned cseq = sip->sip_cseq ? sip->sip_cseq->cs_seq : 0;
2871 int insane, errors, stream;
2872 unsigned compressed = 0;
2873
2874 agent->sa_stats->as_recv_msg++;
2875 agent->sa_stats->as_recv_request++;
2876
2877 SU_DEBUG_5(("nta: received %s " URL_PRINT_FORMAT " %s (CSeq %u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 2880, "nta: received %s " "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
" %s (CSeq %u)\n", method_name, (sip->sip_request->rq_url
)->url_scheme ? (sip->sip_request->rq_url)->url_scheme
: "", (sip->sip_request->rq_url)->url_type != url_any
&& (sip->sip_request->rq_url)->url_scheme &&
(sip->sip_request->rq_url)->url_scheme[0] ? ":" : ""
, (sip->sip_request->rq_url)->url_root && ((
sip->sip_request->rq_url)->url_host || (sip->sip_request
->rq_url)->url_user) ? "//" : "", (sip->sip_request->
rq_url)->url_user ? (sip->sip_request->rq_url)->url_user
: "", (sip->sip_request->rq_url)->url_user &&
(sip->sip_request->rq_url)->url_password ? ":" : ""
, (sip->sip_request->rq_url)->url_user && (sip
->sip_request->rq_url)->url_password ? (sip->sip_request
->rq_url)->url_password : "", (sip->sip_request->
rq_url)->url_user && (sip->sip_request->rq_url
)->url_host ? "@" : "", (sip->sip_request->rq_url)->
url_host ? (sip->sip_request->rq_url)->url_host : ""
, (sip->sip_request->rq_url)->url_host && (sip
->sip_request->rq_url)->url_port ? ":" : "", (sip->
sip_request->rq_url)->url_host && (sip->sip_request
->rq_url)->url_port ? (sip->sip_request->rq_url)->
url_port : "", (sip->sip_request->rq_url)->url_root &&
(sip->sip_request->rq_url)->url_path ? "/" : "", (sip
->sip_request->rq_url)->url_path ? (sip->sip_request
->rq_url)->url_path : "", (sip->sip_request->rq_url
)->url_params ? ";" : "", (sip->sip_request->rq_url)
->url_params ? (sip->sip_request->rq_url)->url_params
: "", (sip->sip_request->rq_url)->url_headers ? "?"
: "", (sip->sip_request->rq_url)->url_headers ? (sip
->sip_request->rq_url)->url_headers : "", (sip->sip_request
->rq_url)->url_fragment ? "#" : "", (sip->sip_request
->rq_url)->url_fragment ? (sip->sip_request->rq_url
)->url_fragment : "", sip->sip_request->rq_version, cseq
)) : (void)0)
2878 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__
, 2880, "nta: received %s " "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
" %s (CSeq %u)\n", method_name, (sip->sip_request->rq_url
)->url_scheme ? (sip->sip_request->rq_url)->url_scheme
: "", (sip->sip_request->rq_url)->url_type != url_any
&& (sip->sip_request->rq_url)->url_scheme &&
(sip->sip_request->rq_url)->url_scheme[0] ? ":" : ""
, (sip->sip_request->rq_url)->url_root && ((
sip->sip_request->rq_url)->url_host || (sip->sip_request
->rq_url)->url_user) ? "//" : "", (sip->sip_request->
rq_url)->url_user ? (sip->sip_request->rq_url)->url_user
: "", (sip->sip_request->rq_url)->url_user &&
(sip->sip_request->rq_url)->url_password ? ":" : ""
, (sip->sip_request->rq_url)->url_user && (sip
->sip_request->rq_url)->url_password ? (sip->sip_request
->rq_url)->url_password : "", (sip->sip_request->
rq_url)->url_user && (sip->sip_request->rq_url
)->url_host ? "@" : "", (sip->sip_request->rq_url)->
url_host ? (sip->sip_request->rq_url)->url_host : ""
, (sip->sip_request->rq_url)->url_host && (sip
->sip_request->rq_url)->url_port ? ":" : "", (sip->
sip_request->rq_url)->url_host && (sip->sip_request
->rq_url)->url_port ? (sip->sip_request->rq_url)->
url_port : "", (sip->sip_request->rq_url)->url_root &&
(sip->sip_request->rq_url)->url_path ? "/" : "", (sip
->sip_request->rq_url)->url_path ? (sip->sip_request
->rq_url)->url_path : "", (sip->sip_request->rq_url
)->url_params ? ";" : "", (sip->sip_request->rq_url)
->url_params ? (sip->sip_request->rq_url)->url_params
: "", (sip->sip_request->rq_url)->url_headers ? "?"
: "", (sip->sip_request->rq_url)->url_headers ? (sip
->sip_request->rq_url)->url_headers : "", (sip->sip_request
->rq_url)->url_fragment ? "#" : "", (sip->sip_request
->rq_url)->url_fragment ? (sip->sip_request->rq_url
)->url_fragment : "", sip->sip_request->rq_version, cseq
)) : (void)0)
2879 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__
, 2880, "nta: received %s " "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
" %s (CSeq %u)\n", method_name, (sip->sip_request->rq_url
)->url_scheme ? (sip->sip_request->rq_url)->url_scheme
: "", (sip->sip_request->rq_url)->url_type != url_any
&& (sip->sip_request->rq_url)->url_scheme &&
(sip->sip_request->rq_url)->url_scheme[0] ? ":" : ""
, (sip->sip_request->rq_url)->url_root && ((
sip->sip_request->rq_url)->url_host || (sip->sip_request
->rq_url)->url_user) ? "//" : "", (sip->sip_request->
rq_url)->url_user ? (sip->sip_request->rq_url)->url_user
: "", (sip->sip_request->rq_url)->url_user &&
(sip->sip_request->rq_url)->url_password ? ":" : ""
, (sip->sip_request->rq_url)->url_user && (sip
->sip_request->rq_url)->url_password ? (sip->sip_request
->rq_url)->url_password : "", (sip->sip_request->
rq_url)->url_user && (sip->sip_request->rq_url
)->url_host ? "@" : "", (sip->sip_request->rq_url)->
url_host ? (sip->sip_request->rq_url)->url_host : ""
, (sip->sip_request->rq_url)->url_host && (sip
->sip_request->rq_url)->url_port ? ":" : "", (sip->
sip_request->rq_url)->url_host && (sip->sip_request
->rq_url)->url_port ? (sip->sip_request->rq_url)->
url_port : "", (sip->sip_request->rq_url)->url_root &&
(sip->sip_request->rq_url)->url_path ? "/" : "", (sip
->sip_request->rq_url)->url_path ? (sip->sip_request
->rq_url)->url_path : "", (sip->sip_request->rq_url
)->url_params ? ";" : "", (sip->sip_request->rq_url)
->url_params ? (sip->sip_request->rq_url)->url_params
: "", (sip->sip_request->rq_url)->url_headers ? "?"
: "", (sip->sip_request->rq_url)->url_headers ? (sip
->sip_request->rq_url)->url_headers : "", (sip->sip_request
->rq_url)->url_fragment ? "#" : "", (sip->sip_request
->rq_url)->url_fragment ? (sip->sip_request->rq_url
)->url_fragment : "", sip->sip_request->rq_version, cseq
)) : (void)0)
2880 sip->sip_request->rq_version, cseq))(((nta_log != ((void*)0) && nta_log->log_init) == 0
? 9 : ((nta_log != ((void*)0) && nta_log->log_init
> 1) ? nta_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__
, 2880, "nta: received %s " "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
" %s (CSeq %u)\n", method_name, (sip->sip_request->rq_url
)->url_scheme ? (sip->sip_request->rq_url)->url_scheme
: "", (sip->sip_request->rq_url)->url_type != url_any
&& (sip->sip_request->rq_url)->url_scheme &&
(sip->sip_request->rq_url)->url_scheme[0] ? ":" : ""
, (sip->sip_request->rq_url)->url_root && ((
sip->sip_request->rq_url)->url_host || (sip->sip_request
->rq_url)->url_user) ? "//" : "", (sip->sip_request->
rq_url)->url_user ? (sip->sip_request->rq_url)->url_user
: "", (sip->sip_request->rq_url)->url_user &&
(sip->sip_request->rq_url)->url_password ? ":" : ""
, (sip->sip_request->rq_url)->url_user && (sip
->sip_request->rq_url)->url_password ? (sip->sip_request
->rq_url)->url_password : "", (sip->sip_request->
rq_url)->url_user && (sip->sip_request->rq_url
)->url_host ? "@" : "", (sip->sip_request->rq_url)->
url_host ? (sip->sip_request->rq_url)->url_host : ""
, (sip->sip_request->rq_url)->url_host && (sip
->sip_request->rq_url)->url_port ? ":" : "", (sip->
sip_request->rq_url)->url_host && (sip->sip_request
->rq_url)->url_port ? (sip->sip_request->rq_url)->
url_port : "", (sip->sip_request->rq_url)->url_root &&
(sip->sip_request->rq_url)->url_path ? "/" : "", (sip
->sip_request->rq_url)->url_path ? (sip->sip_request
->rq_url)->url_path : "", (sip->sip_request->rq_url
)->url_params ? ";" : "", (sip->sip_request->rq_url)
->url_params ? (sip->sip_request->rq_url)->url_params
: "", (sip->sip_request->rq_url)->url_headers ? "?"
: "", (sip->sip_request->rq_url)->url_headers ? (sip
->sip_request->rq_url)->url_headers : "", (sip->sip_request
->rq_url)->url_fragment ? "#" : "", (sip->sip_request
->rq_url)->url_fragment ? (sip->sip_request->rq_url
)->url_fragment : "", sip->sip_request->rq_version, cseq
)) : (void)0)
;
2881
2882 if (agent->sa_drop_prob && !tport_is_reliable(tport)) {
2883 if ((unsigned)su_randint(0, 1000) < agent->sa_drop_prob) {
2884 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__
, 2885, "nta: %s (%u) is %s\n", method_name, cseq, "dropped simulating packet loss"
)) : (void)0)
2885 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__
, 2885, "nta: %s (%u) is %s\n", method_name, cseq, "dropped simulating packet loss"
)) : (void)0)
;
2886 agent->sa_stats->as_drop_request++;
2887 msg_destroy(msg);
2888 return;
2889 }
2890 }
2891
2892 stream = tport_is_stream(tport);
2893
2894 /* Try to use compression on reverse direction if @Via has comp=sigcomp */
2895 if (stream &&
2896 sip->sip_via && sip->sip_via->v_comp &&
2897 tport_can_send_sigcomp(tport) &&
2898 tport_name(tport)->tpn_comp == NULL((void*)0) &&
2899 tport_has_compression(tport_parent(tport), sip->sip_via->v_comp)) {
2900 tport_set_compression(tport, sip->sip_via->v_comp);
2901 }
2902
2903 if (sip->sip_flags & MSG_FLG_TOOLARGE) {
2904 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__
, 2905, "nta: %s (%u) is %s\n", method_name, cseq, sip_413_Request_too_large
)) : (void)0)
2905 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__
, 2905, "nta: %s (%u) is %s\n", method_name, cseq, sip_413_Request_too_large
)) : (void)0)
;
2906 agent->sa_stats->as_bad_request++;
2907 mreply(agent, NULL((void*)0), SIP_413_REQUEST_TOO_LARGE413, sip_413_Request_too_large, msg,
2908 tport, 1, stream, NULL((void*)0),
2909 TAG_END()(tag_type_t)0, (tag_value_t)0);
2910 return;
2911 }
2912
2913 insane = 0;
2914
2915 if (agent->sa_bad_req_mask != ~0U)
2916 errors = msg_extract_errors(msg) & agent->sa_bad_req_mask;
2917 else
2918 errors = sip->sip_error != NULL((void*)0);
2919
2920 if (errors ||
2921 (sip->sip_flags & MSG_FLG_ERROR) /* Fatal error */ ||
2922 (insane = (sip_sanity_check(sip) < 0))) {
2923 sip_header_t const *h;
2924 char const *badname = NULL((void*)0), *phrase;
2925
2926 agent->sa_stats->as_bad_message++;
2927 agent->sa_stats->as_bad_request++;
2928
2929 if (insane)
2930 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__
, 2931, "nta: %s (%u) %s\n", method_name, cseq, "failed sanity check"
)) : (void)0)
2931 "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__
, 2931, "nta: %s (%u) %s\n", method_name, cseq, "failed sanity check"
)) : (void)0)
;
2932
2933 for (h = (sip_header_t const *)sip->sip_error; h; h = h->sh_nextsh_header_next->shn_next) {
2934 char const *bad;
2935
2936 if (h->sh_classsh_common->h_class == sip_error_class)
2937 bad = h->sh_error->er_name;
2938 else
2939 bad = h->sh_classsh_common->h_class->hc_name;
2940
2941 if (bad)
2942 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__
, 2942, "nta: %s has bad %s header\n", method_name, bad)) : (
void)0)
;
2943
2944 if (!badname)
2945 badname = bad;
2946 }
2947
2948 if (sip->sip_via && method != sip_method_ack) {
2949 msg_t *reply = nta_msg_create(agent, 0);
2950
2951 agent_check_request_via(agent, msg, sip, sip->sip_via, tport);
2952
2953 if (badname && reply)
2954 phrase = su_sprintf(msg_home(reply)((su_home_t*)(reply)), "Bad %s Header", badname);
2955 else
2956 phrase = sip_400_Bad_request;
2957
2958 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__
, 2958, "nta: %s (%u) is %s\n", method_name, cseq, phrase)) :
(void)0)
;
2959
2960 mreply(agent, reply, 400, phrase, msg,
2961 tport, 1, stream, NULL((void*)0),
2962 TAG_END()(tag_type_t)0, (tag_value_t)0);
2963 }
2964 else {
2965 msg_destroy(msg);
2966 if (stream) /* Send FIN */
2967 tport_shutdown(tport, 1);
2968 }
2969
2970 return;
2971 }
2972
2973 if (!su_casematch(sip->sip_request->rq_version, sip_version_2_0)) {
2974 agent->sa_stats->as_bad_request++;
2975 agent->sa_stats->as_bad_message++;
2976
2977 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__
, 2978, "nta: bad version %s for %s (%u)\n", sip->sip_request
->rq_version, method_name, cseq)) : (void)0)
2978 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__
, 2978, "nta: bad version %s for %s (%u)\n", sip->sip_request
->rq_version, method_name, cseq)) : (void)0)
;
2979
2980 mreply(agent, NULL((void*)0), SIP_505_VERSION_NOT_SUPPORTED505, sip_505_Version_not_supported, msg,
2981 tport, 0, stream, NULL((void*)0),
2982 TAG_END()(tag_type_t)0, (tag_value_t)0);
2983
2984 return;
2985 }
2986
2987 if (agent_check_request_via(agent, msg, sip, sip->sip_via, tport) < 0) {
2988 agent->sa_stats->as_bad_message++;
2989 agent->sa_stats->as_bad_request++;
2990 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__
, 2990, "nta: %s (%u) %s\n", method_name, cseq, "has invalid Via"
)) : (void)0)
;
2991 msg_destroy(msg);
2992 return;
2993 }
2994
2995#ifdef HAVE_ZLIB_COMPRESS1
2996 compressed = sip_content_encoding_Xflate(msg, sip, 1, 1);
2997#endif
2998
2999 /* First, try existing incoming requests */
3000 irq = incoming_find(agent, sip, sip->sip_via,
3001 agent->sa_merge_482 &&
3002 !sip->sip_to->a_tag &&
3003 method != sip_method_ack
3004 ? &merge
3005 : NULL((void*)0),
3006 method == sip_method_ack ? &ack : NULL((void*)0),
3007 method == sip_method_cancel ? &cancel : NULL((void*)0));
3008
3009 if (irq) {
3010 /* Match - this is a retransmission */
3011 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__
, 3012, "nta: %s (%u) going to existing %s transaction\n", method_name
, cseq, irq->irq_rq->rq_method_name)) : (void)0)
3012 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__
, 3012, "nta: %s (%u) going to existing %s transaction\n", method_name
, cseq, irq->irq_rq->rq_method_name)) : (void)0)
;
3013 if (incoming_recv(irq, msg, sip, tport) >= 0)
3014 return;
3015 }
3016 else if (ack) {
3017 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__
, 3019, "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)
3018 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__
, 3019, "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)
3019 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__
, 3019, "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)
;
3020 if (incoming_ack(ack, msg, sip, tport) >= 0)
3021 return;
3022 }
3023 else if (cancel) {
3024 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__
, 3026, "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)
3025 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__
, 3026, "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)
3026 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__
, 3026, "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)
;
3027 if (incoming_cancel(cancel, msg, sip, tport) >= 0)
3028 return;
3029 }
3030 else if (merge) {
3031 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__
, 3032, "nta: %s (%u) %s\n", method_name, cseq, "is a merged request"
)) : (void)0)
3032 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__
, 3032, "nta: %s (%u) %s\n", method_name, cseq, "is a merged request"
)) : (void)0)
;
3033 request_merge(agent, msg, sip, tport, merge->irq_tag);
3034 return;
3035 }
3036
3037 if (method == sip_method_prack && sip->sip_rack) {
3038 nta_reliable_t *rel = reliable_find(agent, sip);
3039 if (rel) {
3040 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__
, 3043, "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)
3041 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__
, 3043, "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)
3042 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__
, 3043, "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)
3043 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__
, 3043, "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)
;
3044 reliable_recv(rel, msg, sip, tport);
3045 return;
3046 }
3047 }
3048
3049 *url = *sip->sip_request->rq_url;
3050 url->url_params = NULL((void*)0);
3051 agent_aliases(agent, url, tport); /* canonize urls */
3052
3053 if (method != sip_method_subscribe && (leg = leg_find(agent,
3054 method_name, url,
3055 sip->sip_call_id,
3056 sip->sip_from->a_tag,
3057 sip->sip_to->a_tag))) {
3058 /* Try existing dialog */
3059 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__
, 3060, "nta: %s (%u) %s\n", method_name, cseq, "going to existing leg"
)) : (void)0)
3060 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__
, 3060, "nta: %s (%u) %s\n", method_name, cseq, "going to existing leg"
)) : (void)0)
;
3061 leg->leg_compressed = compressed;
3062 leg_recv(leg, msg, sip, tport);
3063 return;
3064 }
3065 else if (!agent->sa_is_stateless &&
3066 (leg = dst_find(agent, url, method_name))) {
3067 /* Dialogless legs - let application process transactions statefully */
3068 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__
, 3069, "nta: %s (%u) %s\n", method_name, cseq, "going to a dialogless leg"
)) : (void)0)
3069 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__
, 3069, "nta: %s (%u) %s\n", method_name, cseq, "going to a dialogless leg"
)) : (void)0)
;
3070 leg->leg_compressed = compressed;
3071 leg_recv(leg, msg, sip, tport);
3072 }
3073 else if (!agent->sa_is_stateless && (leg = agent->sa_default_leg)) {
3074 if (method == sip_method_invite &&
3075 agent->sa_in.proceeding->q_length >= agent->sa_max_proceeding) {
3076 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__
, 3077, "nta: proceeding queue full for %s (%u)\n", method_name
, cseq)) : (void)0)
3077 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__
, 3077, "nta: proceeding queue full for %s (%u)\n", method_name
, cseq)) : (void)0)
;
3078 mreply(agent, NULL((void*)0), SIP_503_SERVICE_UNAVAILABLE503, sip_503_Service_unavailable, msg,
3079 tport, 0, 0, NULL((void*)0),
3080 TAG_END()(tag_type_t)0, (tag_value_t)0);
3081 return;
3082 }
3083 else {
3084 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__
, 3085, "nta: %s (%u) %s\n", method_name, cseq, "going to a default leg"
)) : (void)0)
3085 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__
, 3085, "nta: %s (%u) %s\n", method_name, cseq, "going to a default leg"
)) : (void)0)
;
3086 leg->leg_compressed = compressed;
3087 leg_recv(leg, msg, sip, tport);
3088 }
3089 }
3090 else if (agent->sa_callback) {
3091 /* Stateless processing for request */
3092 agent->sa_stats->as_trless_request++;
3093 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__
, 3094, "nta: %s (%u) %s\n", method_name, cseq, "to message callback"
)) : (void)0)
3094 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__
, 3094, "nta: %s (%u) %s\n", method_name, cseq, "to message callback"
)) : (void)0)
;
3095 (void)agent->sa_callback(agent->sa_magic, agent, msg, sip);
3096 }
3097 else {
3098 agent->sa_stats->as_trless_request++;
3099 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__
, 3101, "nta: %s (%u) %s\n", method_name, cseq, "not processed by application: returning 501"
)) : (void)0)
3100 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__
, 3101, "nta: %s (%u) %s\n", method_name, cseq, "not processed by application: returning 501"
)) : (void)0)
3101 "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__
, 3101, "nta: %s (%u) %s\n", method_name, cseq, "not processed by application: returning 501"
)) : (void)0)
;
3102 if (method != sip_method_ack)
3103 mreply(agent, NULL((void*)0), SIP_501_NOT_IMPLEMENTED501, sip_501_Not_implemented, msg,
3104 tport, 0, 0, NULL((void*)0),
3105 TAG_END()(tag_type_t)0, (tag_value_t)0);
3106 else
3107 msg_destroy(msg);
3108 }
3109}
3110
3111/** Check @Via header.
3112 *
3113 */
3114static
3115int agent_check_request_via(nta_agent_t *agent,
3116 msg_t *msg,
3117 sip_t *sip,
3118 sip_via_t *v,
3119 tport_t *tport)
3120{
3121 enum { receivedlen = sizeof("received=") - 1 };
3122 char received[receivedlen + TPORT_HOSTPORTSIZE(55)];
3123 char *hostport = received + receivedlen;
3124 char const *rport;
3125 su_sockaddr_t const *from;
3126 sip_via_t const *tpv = agent_tport_via(tport);
3127
3128 assert(tport)((tport) ? (void) (0) : __assert_fail ("tport", "nta.c", 3128
, __PRETTY_FUNCTION__))
; assert(msg)((msg) ? (void) (0) : __assert_fail ("msg", "nta.c", 3128, __PRETTY_FUNCTION__
))
; assert(sip)((sip) ? (void) (0) : __assert_fail ("sip", "nta.c", 3128, __PRETTY_FUNCTION__
))
;
3129 assert(sip->sip_request)((sip->sip_request) ? (void) (0) : __assert_fail ("sip->sip_request"
, "nta.c", 3129, __PRETTY_FUNCTION__))
; assert(tpv)((tpv) ? (void) (0) : __assert_fail ("tpv", "nta.c", 3129, __PRETTY_FUNCTION__
))
;
3130
3131 from = msg_addr(msg);
3132
3133 if (v == NULL((void*)0)) {
3134 /* Make up a via line */
3135 v = sip_via_format(msg_home(msg)((su_home_t*)(msg)), "SIP/2.0/%s %s",
3136 tport_name(tport)->tpn_proto,
3137 tport_hostport(hostport, TPORT_HOSTPORTSIZE(55), from, 1));
3138 msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)v);
3139
3140 return v ? 0 : -1;
3141 }
3142
3143 if (!su_strmatch(v->v_protocol, tpv->v_protocol)) {
3144 tport_hostport(hostport, TPORT_HOSTPORTSIZE(55), from, 1);
3145 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__
, 3146, "nta: Via check: invalid transport \"%s\" from %s\n",
v->v_protocol, hostport)) : (void)0)
3146 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__
, 3146, "nta: Via check: invalid transport \"%s\" from %s\n",
v->v_protocol, hostport)) : (void)0)
;
3147 return -1;
3148 }
3149
3150 if (v->v_received) {
3151 /* Nasty, nasty */
3152 tport_hostport(hostport, TPORT_HOSTPORTSIZE(55), from, 1);
3153 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__
, 3154, "nta: Via check: extra received=%s from %s\n", v->
v_received, hostport)) : (void)0)
3154 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__
, 3154, "nta: Via check: extra received=%s from %s\n", v->
v_received, hostport)) : (void)0)
;
3155 msg_header_remove_param(v->v_common, "received");
3156 }
3157
3158 if (!tport_hostport(hostport, TPORT_HOSTPORTSIZE(55), from, 0))
3159 return -1;
3160
3161 if (!su_casematch(hostport, v->v_host)) {
3162 size_t rlen;
3163 /* Add the "received" field */
3164 memcpy(received, "received=", receivedlen);
3165
3166 if (hostport[0] == '[') {
3167 rlen = strlen(hostport + 1) - 1;
3168 memmove(hostport, hostport + 1, rlen);
3169 hostport[rlen] = '\0';
3170 }
3171
3172 msg_header_replace_param(msg_home(msg)((su_home_t*)(msg)), v->v_common,
3173 su_strdup(msg_home(msg)((su_home_t*)(msg)), received));
3174 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__
, 3174, "nta: Via check: %s\n", received)) : (void)0)
;
3175 }
3176
3177 if (!agent->sa_server_rport) {
3178 /*Xyzzy*/;
3179 }
3180 else if (v->v_rport) {
3181 rport = su_sprintf(msg_home(msg)((su_home_t*)(msg)), "rport=%u", ntohs(from->su_port)(__extension__ ({ unsigned short int __v, __x = (unsigned short
int) (from->su_sin.sin_port); if (__builtin_constant_p (__x
)) __v = ((unsigned short int) ((((__x) >> 8) & 0xff
) | (((__x) & 0xff) << 8))); else __asm__ ("rorw $8, %w0"
: "=r" (__v) : "0" (__x) : "cc"); __v; }))
);
3182 msg_header_replace_param(msg_home(msg)((su_home_t*)(msg)), v->v_common, rport);
3183 }
3184 else if (tport_is_tcp(tport)) {
3185 rport = su_sprintf(msg_home(msg)((su_home_t*)(msg)), "rport=%u", ntohs(from->su_port)(__extension__ ({ unsigned short int __v, __x = (unsigned short
int) (from->su_sin.sin_port); if (__builtin_constant_p (__x
)) __v = ((unsigned short int) ((((__x) >> 8) & 0xff
) | (((__x) & 0xff) << 8))); else __asm__ ("rorw $8, %w0"
: "=r" (__v) : "0" (__x) : "cc"); __v; }))
);
3186 msg_header_replace_param(msg_home(msg)((su_home_t*)(msg)), v->v_common, rport);
3187 }
3188 else if (agent->sa_server_rport == 2 ||
3189 (agent->sa_server_rport == 3 && sip && sip->sip_user_agent &&
3190 sip->sip_user_agent->g_string &&
3191 (!strncasecmp(sip->sip_user_agent->g_string, "Polycom", 7) ||
3192 !strncasecmp(sip->sip_user_agent->g_string, "KIRK Wireless Server", 20) ||
3193 !strncasecmp(sip->sip_user_agent->g_string, "ADTRAN_Total_Access", 19)))) {
3194 rport = su_sprintf(msg_home(msg)((su_home_t*)(msg)), "rport=%u", ntohs(from->su_port)(__extension__ ({ unsigned short int __v, __x = (unsigned short
int) (from->su_sin.sin_port); if (__builtin_constant_p (__x
)) __v = ((unsigned short int) ((((__x) >> 8) & 0xff
) | (((__x) & 0xff) << 8))); else __asm__ ("rorw $8, %w0"
: "=r" (__v) : "0" (__x) : "cc"); __v; }))
);
3195 msg_header_replace_param(msg_home(msg)((su_home_t*)(msg)), v->v_common, rport);
3196 }
3197
3198 return 0;
3199}
3200
3201/** @internal Handle aliases of local node.
3202 *
3203 * Return true if @a url is modified.
3204 */
3205static
3206int agent_aliases(nta_agent_t const *agent, url_t url[], tport_t *tport)
3207{
3208 sip_contact_t *m;
3209 sip_via_t const *lv;
3210 char const *tport_port = "";
3211
3212 if (!url->url_host)
3213 return 0;
3214
3215 if (tport)
3216 tport_port = tport_name(tport)->tpn_port;
3217
3218 assert(tport_port)((tport_port) ? (void) (0) : __assert_fail ("tport_port", "nta.c"
, 3218, __PRETTY_FUNCTION__))
;
3219
3220 for (m = agent->sa_aliases ? agent->sa_aliases : agent->sa_contact;
3221 m;
3222 m = m->m_next) {
3223 if (url->url_type != m->m_url->url_type)
3224 continue;
3225
3226 if (host_cmp(url->url_host, m->m_url->url_host))
3227 continue;
3228
3229 if (url->url_port == NULL((void*)0))
3230 break;
3231
3232 if (m->m_url->url_port) {
3233 if (strcmp(url->url_port, m->m_url->url_port)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(url->url_port) && __builtin_constant_p (m->m_url
->url_port) && (__s1_len = __builtin_strlen (url->
url_port), __s2_len = __builtin_strlen (m->m_url->url_port
), (!((size_t)(const void *)((url->url_port) + 1) - (size_t
)(const void *)(url->url_port) == 1) || __s1_len >= 4) &&
(!((size_t)(const void *)((m->m_url->url_port) + 1) - (
size_t)(const void *)(m->m_url->url_port) == 1) || __s2_len
>= 4)) ? __builtin_strcmp (url->url_port, m->m_url->
url_port) : (__builtin_constant_p (url->url_port) &&
((size_t)(const void *)((url->url_port) + 1) - (size_t)(const
void *)(url->url_port) == 1) && (__s1_len = __builtin_strlen
(url->url_port), __s1_len < 4) ? (__builtin_constant_p
(m->m_url->url_port) && ((size_t)(const void *
)((m->m_url->url_port) + 1) - (size_t)(const void *)(m->
m_url->url_port) == 1) ? __builtin_strcmp (url->url_port
, m->m_url->url_port) : (__extension__ ({ const unsigned
char *__s2 = (const unsigned char *) (const char *) (m->m_url
->url_port); int __result = (((const unsigned char *) (const
char *) (url->url_port))[0] - __s2[0]); if (__s1_len >
0 && __result == 0) { __result = (((const unsigned char
*) (const char *) (url->url_port))[1] - __s2[1]); if (__s1_len
> 1 && __result == 0) { __result = (((const unsigned
char *) (const char *) (url->url_port))[2] - __s2[2]); if
(__s1_len > 2 && __result == 0) __result = (((const
unsigned char *) (const char *) (url->url_port))[3] - __s2
[3]); } } __result; }))) : (__builtin_constant_p (m->m_url
->url_port) && ((size_t)(const void *)((m->m_url
->url_port) + 1) - (size_t)(const void *)(m->m_url->
url_port) == 1) && (__s2_len = __builtin_strlen (m->
m_url->url_port), __s2_len < 4) ? (__builtin_constant_p
(url->url_port) && ((size_t)(const void *)((url->
url_port) + 1) - (size_t)(const void *)(url->url_port) == 1
) ? __builtin_strcmp (url->url_port, m->m_url->url_port
) : (- (__extension__ ({ const unsigned char *__s2 = (const unsigned
char *) (const char *) (url->url_port); int __result = ((
(const unsigned char *) (const char *) (m->m_url->url_port
))[0] - __s2[0]); if (__s2_len > 0 && __result == 0
) { __result = (((const unsigned char *) (const char *) (m->
m_url->url_port))[1] - __s2[1]); if (__s2_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (m->m_url->url_port))[2] - __s2[2]); if (__s2_len
> 2 && __result == 0) __result = (((const unsigned
char *) (const char *) (m->m_url->url_port))[3] - __s2
[3]); } } __result; })))) : __builtin_strcmp (url->url_port
, m->m_url->url_port)))); })
)
3234 continue;
3235 } else {
3236 if (strcmp(url->url_port, tport_port)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(url->url_port) && __builtin_constant_p (tport_port
) && (__s1_len = __builtin_strlen (url->url_port),
__s2_len = __builtin_strlen (tport_port), (!((size_t)(const void
*)((url->url_port) + 1) - (size_t)(const void *)(url->
url_port) == 1) || __s1_len >= 4) && (!((size_t)(const
void *)((tport_port) + 1) - (size_t)(const void *)(tport_port
) == 1) || __s2_len >= 4)) ? __builtin_strcmp (url->url_port
, tport_port) : (__builtin_constant_p (url->url_port) &&
((size_t)(const void *)((url->url_port) + 1) - (size_t)(const
void *)(url->url_port) == 1) && (__s1_len = __builtin_strlen
(url->url_port), __s1_len < 4) ? (__builtin_constant_p
(tport_port) && ((size_t)(const void *)((tport_port)
+ 1) - (size_t)(const void *)(tport_port) == 1) ? __builtin_strcmp
(url->url_port, tport_port) : (__extension__ ({ const unsigned
char *__s2 = (const unsigned char *) (const char *) (tport_port
); int __result = (((const unsigned char *) (const char *) (url
->url_port))[0] - __s2[0]); if (__s1_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (url->url_port))[1] - __s2[1]); if (__s1_len >
1 && __result == 0) { __result = (((const unsigned char
*) (const char *) (url->url_port))[2] - __s2[2]); if (__s1_len
> 2 && __result == 0) __result = (((const unsigned
char *) (const char *) (url->url_port))[3] - __s2[3]); } }
__result; }))) : (__builtin_constant_p (tport_port) &&
((size_t)(const void *)((tport_port) + 1) - (size_t)(const void
*)(tport_port) == 1) && (__s2_len = __builtin_strlen
(tport_port), __s2_len < 4) ? (__builtin_constant_p (url->
url_port) && ((size_t)(const void *)((url->url_port
) + 1) - (size_t)(const void *)(url->url_port) == 1) ? __builtin_strcmp
(url->url_port, tport_port) : (- (__extension__ ({ const unsigned
char *__s2 = (const unsigned char *) (const char *) (url->
url_port); int __result = (((const unsigned char *) (const char
*) (tport_port))[0] - __s2[0]); if (__s2_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (tport_port))[1] - __s2[1]); if (__s2_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (tport_port))[2] - __s2[2]); if (__s2_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) (tport_port))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp
(url->url_port, tport_port)))); })
)
3237 continue;
3238 }
3239
3240 break;
3241 }
3242
3243 if (!m)
3244 return 0;
3245
3246 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__
, 3248, "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)
3247 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__
, 3248, "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)
3248 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__
, 3248, "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)
;
3249
3250 url->url_host = "%";
3251
3252 if (agent->sa_aliases) {
3253 url->url_type = agent->sa_aliases->m_url->url_type;
3254 url->url_scheme = agent->sa_aliases->m_url->url_scheme;
3255 url->url_port = agent->sa_aliases->m_url->url_port;
3256 return 1;
3257 }
3258 else {
3259 /* Canonize the request URL port */
3260 if (tport) {
3261 lv = agent_tport_via(tport_parent(tport)); assert(lv)((lv) ? (void) (0) : __assert_fail ("lv", "nta.c", 3261, __PRETTY_FUNCTION__
))
;
3262 if (lv->v_port)
3263 /* Add non-default port */
3264 url->url_port = lv->v_port;
3265 return 1;
3266 }
3267 if (su_strmatch(url->url_port, url_port_default((enum url_type_e)url->url_type)) ||
3268 su_strmatch(url->url_port, ""))
3269 /* Remove default or empty port */
3270 url->url_port = NULL((void*)0);
3271
3272 return 0;
3273 }
3274}
3275
3276/** @internal Handle incoming responses. */
3277static
3278void agent_recv_response(nta_agent_t *agent,
3279 msg_t *msg,
3280 sip_t *sip,
3281 sip_via_t *tport_via,
3282 tport_t *tport)
3283{
3284 int status = sip->sip_status->st_status;
3285 int errors;
3286 char const *phrase = sip->sip_status->st_phrase;
3287 char const *method =
3288 sip->sip_cseq ? sip->sip_cseq->cs_method_name : "<UNKNOWN>";
3289 uint32_t cseq = sip->sip_cseq ? sip->sip_cseq->cs_seq : 0;
3290 nta_outgoing_t *orq;
3291 su_home_t *home;
3292 char const *branch = NONE((void *)-1);
3293
3294
3295 agent->sa_stats->as_recv_msg++;
3296 agent->sa_stats->as_recv_response++;
3297
3298 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__
, 3299, "nta: received %03d %s for %s (%u)\n", status, phrase
, method, cseq)) : (void)0)
3299 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__
, 3299, "nta: received %03d %s for %s (%u)\n", status, phrase
, method, cseq)) : (void)0)
;
3300
3301 if (agent->sa_drop_prob && !tport_is_reliable(tport)) {
3302 if ((unsigned)su_randint(0, 1000) < agent->sa_drop_prob) {
3303 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__
, 3304, "nta: %03d %s %s\n", status, phrase, "dropped simulating packet loss"
)) : (void)0)
3304 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__
, 3304, "nta: %03d %s %s\n", status, phrase, "dropped simulating packet loss"
)) : (void)0)
;
3305 agent->sa_stats->as_drop_response++;
3306 msg_destroy(msg);
3307 return;
3308 }
3309 }
3310
3311 if (agent->sa_bad_resp_mask)
3312 errors = msg_extract_errors(msg) & agent->sa_bad_resp_mask;
3313 else
3314 errors = sip->sip_error != NULL((void*)0);
3315
3316 if (errors ||
3317 sip_sanity_check(sip) < 0) {
3318 sip_header_t const *h;
3319
3320 agent->sa_stats->as_bad_response++;
3321 agent->sa_stats->as_bad_message++;
3322
3323 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__
, 3326, "nta: %03d %s %s\n", status, phrase, errors ? "has fatal syntax errors"
: "failed sanity check")) : (void)0)
3324 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__
, 3326, "nta: %03d %s %s\n", status, phrase, errors ? "has fatal syntax errors"
: "failed sanity check")) : (void)0)
3325 ? "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__
, 3326, "nta: %03d %s %s\n", status, phrase, errors ? "has fatal syntax errors"
: "failed sanity check")) : (void)0)
3326 : "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__
, 3326, "nta: %03d %s %s\n", status, phrase, errors ? "has fatal syntax errors"
: "failed sanity check")) : (void)0)
;
3327
3328 for (h = (sip_header_t const *)sip->sip_error; h; h = h->sh_nextsh_header_next->shn_next) {
3329 if (h->sh_classsh_common->h_class->hc_name) {
3330 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__
, 3331, "nta: %03d has bad %s header\n", status, h->sh_common
->h_class->hc_name)) : (void)0)
3331 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__
, 3331, "nta: %03d has bad %s header\n", status, h->sh_common
->h_class->hc_name)) : (void)0)
;
3332 }
3333 }
3334
3335 msg_destroy(msg);
3336 return;
3337 }
3338
3339 if (!su_casematch(sip->sip_status->st_version, sip_version_2_0)) {
3340 agent->sa_stats->as_bad_response++;
3341 agent->sa_stats->as_bad_message++;
3342
3343 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__
, 3344, "nta: bad version %s %03d %s\n", sip->sip_status->
st_version, status, phrase)) : (void)0)
3344 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__
, 3344, "nta: bad version %s %03d %s\n", sip->sip_status->
st_version, status, phrase)) : (void)0)
;
3345 msg_destroy(msg);
3346 return;
3347 }
3348
3349 if (sip->sip_cseq->cs_method == sip_method_ack) {
3350 /* Drop response messages to ACK */
3351 agent->sa_stats->as_bad_response++;
3352 agent->sa_stats->as_bad_message++;
3353 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__
, 3353, "nta: %03d %s %s\n", status, phrase, "is response to ACK"
)) : (void)0)
;
3354 msg_destroy(msg);
3355 return;
3356 }
3357
3358 /* XXX - should check if msg should be discarded based on via? */
3359
3360#ifdef HAVE_ZLIB_COMPRESS1
3361 sip_content_encoding_Xflate(msg, sip, 1, 1);
3362#endif
3363
3364 if ((orq = outgoing_find(agent, msg, sip, sip->sip_via))) {
3365 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__
, 3366, "nta: %03d %s %s\n", status, phrase, "is going to a transaction"
)) : (void)0)
3366 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__
, 3366, "nta: %03d %s %s\n", status, phrase, "is going to a transaction"
)) : (void)0)
;
3367 /* RFC3263 4.3 "503 error response" */
3368 if(agent->sa_srv_503 && status == 503 && outgoing_other_destinations(orq)) {
3369 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__
, 3369, "%s(%p): <%03d> for <%s>, %s\n", "nta", (
void *)orq, status, method, "try next after timeout")) : (void
)0)
;
3370 home = msg_home(msg)((su_home_t*)(msg));
3371 if (agent->sa_is_stateless)
3372 branch = stateless_branch(agent, msg, sip, orq->orq_tpn);
3373 else
3374 branch = stateful_branch(home, agent);
3375
3376 orq->orq_branch = branch;
3377 orq->orq_via_branch = branch;
3378 outgoing_try_another(orq);
3379 return;
3380 }
3381
3382 if (outgoing_recv(orq, status, msg, sip) == 0)
3383 return;
3384 }
3385
3386
3387 agent->sa_stats->as_trless_response++;
3388
3389 if ((orq = agent->sa_default_outgoing)) {
3390 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__
, 3391, "nta: %03d %s %s\n", status, phrase, "to the default transaction"
)) : (void)0)
3391 "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__
, 3391, "nta: %03d %s %s\n", status, phrase, "to the default transaction"
)) : (void)0)
;
3392 outgoing_default_recv(orq, status, msg, sip);
3393 return;
3394 }
3395 else if (agent->sa_callback) {
3396 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__
, 3396, "nta: %03d %s %s\n", status, phrase, "to message callback"
)) : (void)0)
;
3397 /*
3398 * Store message and transport to hook for the duration of the callback
3399 * so that the transport can be obtained by nta_transport().
3400 */
3401 (void)agent->sa_callback(agent->sa_magic, agent, msg, sip);
3402 return;
3403 }
3404
3405 if (sip->sip_cseq->cs_method == sip_method_invite
3406 && 200 <= sip->sip_status->st_status
3407 && sip->sip_status->st_status < 300
3408 /* Exactly one Via header, belonging to us */
3409 && sip->sip_via && !sip->sip_via->v_next
3410 && agent_has_via(agent, sip->sip_via)) {
3411 agent->sa_stats->as_trless_200++;
3412 }
3413
3414 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__
, 3414, "nta: %03d %s %s\n", status, phrase, "was discarded")
) : (void)0)
;
3415 msg_destroy(msg);
3416}
3417
3418/** @internal Agent receives garbage */
3419static
3420void agent_recv_garbage(nta_agent_t *agent,
3421 msg_t *msg,
3422 tport_t *tport)
3423{
3424 agent->sa_stats->as_recv_msg++;
3425 agent->sa_stats->as_bad_message++;
3426
3427#if SU_DEBUG0 >= 3
3428 if (nta_log->log_level >= 3) {
3429 tp_name_t tpn[1];
3430
3431 tport_delivered_from(tport, msg, tpn);
3432
3433 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__
, 3434, "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)
3434 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__
, 3434, "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)
;
3435 }
3436#endif
3437
3438 msg_destroy(msg);
3439}
3440
3441/* ====================================================================== */
3442/* 4) Message handling - create, complete, destroy */
3443
3444/** Create a new message belonging to the agent */
3445msg_t *nta_msg_create(nta_agent_t *agent, int flags)
3446{
3447 msg_t *msg;
3448
3449 if (agent == NULL((void*)0))
3450 return su_seterrno(EINVAL22), NULL((void*)0);
3451
3452 msg = msg_create(agent->sa_mclass, agent->sa_flags | flags);
3453
3454 if (agent->sa_preload)
3455 su_home_preload(msg_home(msg)((su_home_t*)(msg)), 1, agent->sa_preload);
3456
3457 return msg;
3458}
3459
3460/** Create a new message for transport */
3461msg_t *nta_msg_create_for_transport(nta_agent_t *agent, int flags,
3462 char const data[], usize_t dlen,
3463 tport_t const *tport, tp_client_t *via)
3464{
3465 msg_t *msg = msg_create(agent->sa_mclass, agent->sa_flags | flags);
3466
3467 msg_maxsize(msg, agent->sa_maxsize);
3468
3469 if (agent->sa_preload)
3470 su_home_preload(msg_home(msg)((su_home_t*)(msg)), 1, dlen + agent->sa_preload);
3471
3472 return msg;
3473}
3474
3475/** Complete a message. */
3476int nta_msg_complete(msg_t *msg)
3477{
3478 return sip_complete_message(msg);
3479}
3480
3481/** Discard a message */
3482void nta_msg_discard(nta_agent_t *agent, msg_t *msg)
3483{
3484 msg_destroy(msg);
3485}
3486
3487/** Check if the headers are from response generated locally by NTA. */
3488int nta_sip_is_internal(sip_t const *sip)
3489{
3490 return
3491 sip == NULL((void*)0) /* No message generated */
3492 || (sip->sip_flags & NTA_INTERNAL_MSG(1<<15)) == NTA_INTERNAL_MSG(1<<15);
3493}
3494
3495/** Check if the message is internally generated by NTA. */
3496int nta_msg_is_internal(msg_t const *msg)
3497{
3498 return msg_get_flags(msg, NTA_INTERNAL_MSG(1<<15)) == NTA_INTERNAL_MSG(1<<15);
3499}
3500
3501/** Check if the message is internally generated by NTA.
3502 *
3503 * @deprecated Use nta_msg_is_internal() instead
3504 */
3505int nta_is_internal_msg(msg_t const *msg) { return nta_msg_is_internal(msg); }
3506
3507/* ====================================================================== */
3508/* 5) Stateless operation */
3509
3510/**Forward a request or response message.
3511 *
3512 * @note
3513 * The ownership of @a msg is taken over by the function even if the
3514 * function fails.
3515 */
3516int nta_msg_tsend(nta_agent_t *agent, msg_t *msg, url_string_t const *u,
3517 tag_type_t tag, tag_value_t value, ...)
3518{
3519 int retval = -1;
3520 ta_list ta;
3521 sip_t *sip = sip_object(msg);
3522 tp_name_t tpn[1] = {{ NULL((void*)0) }};
3523 char const *what;
3524
3525 if (!sip) {
3526 msg_destroy(msg);
3527 return -1;
3528 }
3529
3530 what =
3531 sip->sip_status ? "nta_msg_tsend(response)" :
3532 sip->sip_request ? "nta_msg_tsend(request)" :
3533 "nta_msg_tsend()";
3534
3535 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)
;
3536
3537 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)
3538 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__
, 3538, "%s: cannot add headers\n", what)) : (void)0)
;
3539 else if (sip->sip_status) {
3540 tport_t *tport = NULL((void*)0);
3541 int *use_rport = NULL((void*)0);
3542 int retry_without_rport = 0;
3543
3544 struct sigcomp_compartment *cc; cc = NONE((void *)-1);
3545
3546 if (agent->sa_server_rport)
3547 use_rport = &retry_without_rport, retry_without_rport = 1;
3548
3549 tl_gets(ta_args(ta)(ta).tl,
3550 NTATAG_TPORT_REF(tport)ntatag_tport_ref, tag_ptr_vr(&(tport), (tport)),
3551 IF_SIGCOMP_TPTAG_COMPARTMENT_REF(cc)tptag_compartment_ref, tag_ptr_vr(&(cc), cc),
3552 /* NTATAG_INCOMPLETE_REF(incomplete), */
3553 TAG_END()(tag_type_t)0, (tag_value_t)0);
3554
3555 if (!sip->sip_separator &&
3556 !(sip->sip_separator = sip_separator_create(msg_home(msg)((su_home_t*)(msg)))))
3557 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__
, 3557, "%s: cannot create sip_separator\n", what)) : (void)0
)
;
3558 else if (msg_serialize(msg, (msg_pub_t *)sip) != 0)
3559 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__
, 3559, "%s: sip_serialize() failed\n", what)) : (void)0)
;
3560 else if (!sip_via_remove(msg, sip))
3561 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__
, 3561, "%s: cannot remove Via\n", what)) : (void)0)
;
3562 else if (nta_tpn_by_via(tpn, sip->sip_via, use_rport) < 0)
3563 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__
, 3563, "%s: bad via\n", what)) : (void)0)
;
3564 else {
3565 if (!tport)
3566 tport = tport_by_name(agent->sa_tports, tpn);
3567 if (!tport)
3568 tport = tport_by_protocol(agent->sa_tports, tpn->tpn_proto);
3569
3570 if (retry_without_rport)
3571 tpn->tpn_port = sip_via_port(sip->sip_via, NULL((void*)0));
3572
3573 if (tport && tpn->tpn_comp && cc == NONE((void *)-1))
3574 cc = agent_compression_compartment(agent, tport, tpn, -1);
3575
3576 if (tport_tsend(tport, msg, tpn,
3577 IF_SIGCOMP_TPTAG_COMPARTMENT(cc)!(cc && cc != ((void *)-1)) ? tag_skip : tptag_compartment
, tag_ptr_v((cc)),
3578 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)) {
3579 agent->sa_stats->as_sent_msg++;
3580 agent->sa_stats->as_sent_response++;
3581 retval = 0;
3582 }
3583 else {
3584 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__
, 3584, "%s: send fails\n", what)) : (void)0)
;
3585 }
3586 }
3587 }
3588 else {
3589 /* Send request */
3590 if (outgoing_create(agent, NULL((void*)0), NULL((void*)0), u, NULL((void*)0), msg_ref_create(msg),
3591 NTATAG_STATELESS(1)ntatag_stateless, tag_bool_v((1)),
3592 ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
))
3593 retval = 0;
3594 }
3595
3596 if (retval == 0)
3597 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__
, 3597, "%s\n", what)) : (void)0)
;
3598
3599 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))
;
3600
3601 msg_destroy(msg);
3602
3603 return retval;
3604}
3605
3606/** Reply to a request message.
3607 *
3608 * @param agent nta agent object
3609 * @param req_msg request message
3610 * @param status status code
3611 * @param phrase status phrase (may be NULL if status code is well-known)
3612 * @param tag, value, ... optional additional headers terminated by TAG_END()
3613 *
3614 * @retval 0 when succesful
3615 * @retval -1 upon an error
3616 *
3617 * @note
3618 * The ownership of @a msg is taken over by the function even if the
3619 * function fails.
3620 */
3621int nta_msg_treply(nta_agent_t *agent,
3622 msg_t *req_msg,
3623 int status, char const *phrase,
3624 tag_type_t tag, tag_value_t value, ...)
3625{
3626 int retval;
3627 ta_list ta;
3628
3629 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)
;
3630
3631 retval = mreply(agent, NULL((void*)0), status, phrase, req_msg,
3632 NULL((void*)0), 0, 0, NULL((void*)0),
3633 ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
);
3634 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))
;
3635
3636 return retval;
3637}
3638
3639/**Reply to the request message.
3640 *
3641 * @note
3642 * The ownership of @a msg is taken over by the function even if the
3643 * function fails.
3644 */
3645int nta_msg_mreply(nta_agent_t *agent,
3646 msg_t *reply, sip_t *sip,
3647 int status, char const *phrase,
3648 msg_t *req_msg,
3649 tag_type_t tag, tag_value_t value, ...)
3650{
3651 int retval = -1;
3652 ta_list ta;
3653
3654 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)
;
3655
3656 retval = mreply(agent, reply, status, phrase, req_msg,
3657 NULL((void*)0), 0, 0, NULL((void*)0),
3658 ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
);
3659 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))
;
3660
3661 return retval;
3662}
3663
3664static
3665int mreply(nta_agent_t *agent,
3666 msg_t *reply,
3667 int status, char const *phrase,
3668 msg_t *req_msg,
3669 tport_t *tport,
3670 int incomplete,
3671 int sdwn_after,
3672 char const *to_tag,
3673 tag_type_t tag, tag_value_t value, ...)
3674{
3675 ta_list ta;
3676 sip_t *sip;
3677 int *use_rport = NULL((void*)0);
3678 int retry_without_rport = 0;
3679 tp_name_t tpn[1];
3680 int retval = -1;
3681
3682 if (!agent)
3683 return -1;
3684
3685 if (agent->sa_server_rport)
3686 use_rport = &retry_without_rport, retry_without_rport = 1;
3687
3688 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)
;
3689
3690 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);
3691
3692 if (reply == NULL((void*)0)) {
3693 reply = nta_msg_create(agent, 0);
3694 }
3695 sip = sip_object(reply);
3696
3697 if (!sip) {
3698 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__
, 3698, "%s: cannot create response msg\n", __func__)) : (void
)0)
;
3699 }
3700 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) {
3701 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__
, 3701, "%s: cannot add user headers\n", __func__)) : (void)0
)
;
3702 }
3703 else if (complete_response(reply, status, phrase, req_msg) < 0 &&
3704 !incomplete) {
3705 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__
, 3705, "%s: cannot complete message\n", __func__)) : (void)0
)
;
3706 }
3707 else if (sip->sip_status && sip->sip_status->st_status > 100 &&
3708 sip->sip_to && !sip->sip_to->a_tag &&
3709 (to_tag == NONE((void *)-1) ? 0 :
3710 to_tag != NULL((void*)0)
3711 ? sip_to_tag(msg_home(reply)((su_home_t*)(reply)), sip->sip_to, to_tag) < 0
3712 : sip_to_tag(msg_home(reply)((su_home_t*)(reply)), sip->sip_to,
3713 nta_agent_newtag(msg_home(reply)((su_home_t*)(reply)), "tag=%s", agent)) < 0)) {
3714 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__
, 3714, "%s: cannot add To tag\n", __func__)) : (void)0)
;
3715 }
3716 else if (nta_tpn_by_via(tpn, sip->sip_via, use_rport) < 0) {
3717 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__
, 3717, "%s: no Via\n", __func__)) : (void)0)
;
3718 }
3719 else {
3720 struct sigcomp_compartment *cc = NONE((void *)-1);
3721
3722 if (tport == NULL((void*)0))
3723 tport = tport_delivered_by(agent->sa_tports, req_msg);
3724
3725 if (!tport) {
3726 tport_t *primary = tport_by_protocol(agent->sa_tports, tpn->tpn_proto);
3727
3728 tport = tport_by_name(primary, tpn);
3729
3730 if (!tport)
3731 tport = primary;
3732 }
3733
3734 if (retry_without_rport)
3735 tpn->tpn_port = sip_via_port(sip->sip_via, NULL((void*)0));
3736
3737 if (tport && tpn->tpn_comp) {
3738 tl_gets(ta_args(ta)(ta).tl, TPTAG_COMPARTMENT_REF(cc)tptag_compartment_ref, tag_ptr_vr(&(cc), cc),
3739 /* XXX - should also check ntatag_sigcomp_close() */
3740 TAG_END()(tag_type_t)0, (tag_value_t)0);
3741 if (cc == NONE((void *)-1))
3742 cc = agent_compression_compartment(agent, tport, tpn, -1);
3743
3744 if (cc != NULL((void*)0) && cc != NONE((void *)-1) &&
3745 tport_delivered_with_comp(tport, req_msg, NULL((void*)0)) != -1) {
3746 agent_accept_compressed(agent, req_msg, cc);
3747 }
3748 }
3749
3750 if (tport_tsend(tport, reply, tpn,
3751 IF_SIGCOMP_TPTAG_COMPARTMENT(cc)!(cc && cc != ((void *)-1)) ? tag_skip : tptag_compartment
, tag_ptr_v((cc)),
3752 TPTAG_MTU(INT_MAX)tptag_mtu, tag_usize_v((2147483647)),
3753 TPTAG_SDWN_AFTER(sdwn_after)tptag_sdwn_after, tag_bool_v((sdwn_after)),
3754 ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
)) {
3755 agent->sa_stats->as_sent_msg++;
3756 agent->sa_stats->as_sent_response++;
3757 retval = 0; /* Success! */
3758 }
3759 else {
3760 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__
, 3760, "%s: send fails\n", __func__)) : (void)0)
;
3761 }
3762 }
3763
3764 msg_destroy(reply);
3765 msg_destroy(req_msg);
3766
3767 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))
;
3768
3769 return retval;
3770}
3771
3772/** Add headers from the request to the response message. */
3773static
3774int complete_response(msg_t *response,
3775 int status, char const *phrase,
3776 msg_t *request)
3777{
3778 su_home_t *home = msg_home(response)((su_home_t*)(response));
3779 sip_t *response_sip = sip_object(response);
3780 sip_t const *request_sip = sip_object(request);
3781
3782 int incomplete = 0;
3783
3784 if (!response_sip || !request_sip || !request_sip->sip_request)
3785 return -1;
3786
3787 if (!response_sip->sip_status)
3788 response_sip->sip_status = sip_status_create(home, status, phrase, NULL((void*)0));
3789 if (!response_sip->sip_via)
3790 response_sip->sip_via = sip_via_dup(home, request_sip->sip_via);
3791 if (!response_sip->sip_from)
3792 response_sip->sip_from = sip_from_dup(home, request_sip->sip_from);
3793 if (!response_sip->sip_to)
3794 response_sip->sip_to = sip_to_dup(home, request_sip->sip_to);
3795 if (!response_sip->sip_call_id)
3796 response_sip->sip_call_id =
3797 sip_call_id_dup(home, request_sip->sip_call_id);
3798 if (!response_sip->sip_cseq)
3799 response_sip->sip_cseq = sip_cseq_dup(home, request_sip->sip_cseq);
3800
3801 if (!response_sip->sip_record_route && request_sip->sip_record_route)
3802 sip_add_dup(response, response_sip, (void*)request_sip->sip_record_route);
3803
3804 incomplete = sip_complete_message(response) < 0;
3805
3806 msg_serialize(response, (msg_pub_t *)response_sip);
3807
3808 if (incomplete ||
3809 !response_sip->sip_status ||
3810 !response_sip->sip_via ||
3811 !response_sip->sip_from ||
3812 !response_sip->sip_to ||
3813 !response_sip->sip_call_id ||
3814 !response_sip->sip_cseq ||
3815 !response_sip->sip_content_length ||
3816 !response_sip->sip_separator ||
3817 (request_sip->sip_record_route && !response_sip->sip_record_route))
3818 return -1;
3819
3820 return 0;
3821}
3822
3823/** ACK and BYE an unknown 200 OK response to INVITE.
3824 *
3825 * A UAS may still return a 2XX series response to client request after the
3826 * client transactions has been terminated. In that case, the UAC can not
3827 * really accept the call. This function was used to accept and immediately
3828 * terminate such a call.
3829 *
3830 * @deprecated This was a bad idea: see sf.net bug #1750691. It can be used
3831 * to amplify DoS attacks. Let UAS take care of retransmission timeout and
3832 * let it terminate the session. As of @VERSION_1_12_7, this function just
3833 * returns -1.
3834 */
3835int nta_msg_ackbye(nta_agent_t *agent, msg_t *msg)
3836{
3837 sip_t *sip = sip_object(msg);
3838 msg_t *amsg = nta_msg_create(agent, 0);
3839 sip_t *asip = sip_object(amsg);
3840 msg_t *bmsg = NULL((void*)0);
3841 sip_t *bsip;
3842 url_string_t const *ruri;
3843 nta_outgoing_t *ack = NULL((void*)0), *bye = NULL((void*)0);
3844 sip_cseq_t *cseq;
3845 sip_request_t *rq;
3846 sip_route_t *route = NULL((void*)0), *r, r0[1];
3847 su_home_t *home = msg_home(amsg)((su_home_t*)(amsg));
3848
3849 if (asip == NULL((void*)0))
3850 return -1;
3851
3852 sip_add_tl(amsg, asip,
3853 SIPTAG_TO(sip->sip_to)siptag_to, siptag_to_v(sip->sip_to),
3854 SIPTAG_FROM(sip->sip_from)siptag_from, siptag_from_v(sip->sip_from),
3855 SIPTAG_CALL_ID(sip->sip_call_id)siptag_call_id, siptag_call_id_v(sip->sip_call_id),
3856 TAG_END()(tag_type_t)0, (tag_value_t)0);
3857
3858 if (sip->sip_contact) {
3859 ruri = (url_string_t const *)sip->sip_contact->m_url;
3860 } else {
3861 ruri = (url_string_t const *)sip->sip_to->a_url;
3862 }
3863
3864 /* Reverse (and fix) record route */
3865 route = sip_route_reverse(home, sip->sip_record_route);
3866
3867 if (route && !url_has_param(route->r_url, "lr")) {
3868 for (r = route; r->r_next; r = r->r_next)
3869 ;
3870
3871 /* Append r-uri */
3872 *sip_route_init(r0)->r_url = *ruri->us_url;
3873 r->r_next = sip_route_dup(home, r0);
3874
3875 /* Use topmost route as request-uri */
3876 ruri = (url_string_t const *)route->r_url;
3877 route = route->r_next;
3878 }
3879
3880 msg_header_insert(amsg, (msg_pub_t *)asip, (msg_header_t *)route);
3881
3882 bmsg = msg_copy(amsg); bsip = sip_object(bmsg);
3883
3884 if (!(cseq = sip_cseq_create(home, sip->sip_cseq->cs_seq, SIP_METHOD_ACKsip_method_ack, "ACK")))
3885 goto err;
3886 else
3887 msg_header_insert(amsg, (msg_pub_t *)asip, (msg_header_t *)cseq);
3888
3889 if (!(rq = sip_request_create(home, SIP_METHOD_ACKsip_method_ack, "ACK", ruri, NULL((void*)0))))
3890 goto err;
3891 else
3892 msg_header_insert(amsg, (msg_pub_t *)asip, (msg_header_t *)rq);
3893
3894 if (!(ack = nta_outgoing_mcreate(agent, NULL((void*)0), NULL((void*)0), NULL((void*)0), amsg,
3895 NTATAG_ACK_BRANCH(sip->sip_via->v_branch)ntatag_ack_branch, tag_str_v((sip->sip_via->v_branch)),
3896 NTATAG_STATELESS(1)ntatag_stateless, tag_bool_v((1)),
3897 TAG_END()(tag_type_t)0, (tag_value_t)0)))
3898 goto err;
3899 else
3900 nta_outgoing_destroy(ack);
3901
3902 home = msg_home(bmsg)((su_home_t*)(bmsg));
3903
3904 if (!(cseq = sip_cseq_create(home, 0x7fffffff, SIP_METHOD_BYEsip_method_bye, "BYE")))
3905 goto err;
3906 else
3907 msg_header_insert(bmsg, (msg_pub_t *)bsip, (msg_header_t *)cseq);
3908
3909 if (!(rq = sip_request_create(home, SIP_METHOD_BYEsip_method_bye, "BYE", ruri, NULL((void*)0))))
3910 goto err;
3911 else
3912 msg_header_insert(bmsg, (msg_pub_t *)bsip, (msg_header_t *)rq);
3913
3914 if (!(bye = nta_outgoing_mcreate(agent, NULL((void*)0), NULL((void*)0), NULL((void*)0), bmsg,
3915 NTATAG_STATELESS(1)ntatag_stateless, tag_bool_v((1)),
3916 TAG_END()(tag_type_t)0, (tag_value_t)0)))
3917 goto err;
3918
3919 msg_destroy(msg);
3920 return 0;
3921
3922 err:
3923
3924 msg_destroy(bmsg);
3925 msg_destroy(amsg);
3926
3927 return -1;
3928}
3929
3930/**Complete a request with values from dialog.
3931 *
3932 * Complete a request message @a msg belonging to a dialog associated with
3933 * @a leg. It increments the local @CSeq value, adds @CallID, @To, @From and
3934 * @Route headers (if there is such headers present in @a leg), and creates
3935 * a new request line object from @a method, @a method_name and @a
3936 * request_uri.
3937 *
3938 * @param msg pointer to a request message object
3939 * @param leg pointer to a #nta_leg_t object
3940 * @param method request method number or #sip_method_unknown
3941 * @param method_name method name (if @a method == #sip_method_unknown)
3942 * @param request_uri request URI
3943 *
3944 * If @a request_uri contains query part, the query part is converted as SIP
3945 * headers and added to the request.
3946 *
3947 * @retval 0 when successful
3948 * @retval -1 upon an error
3949 *
3950 * @sa nta_outgoing_mcreate(), nta_outgoing_tcreate()
3951 */
3952int nta_msg_request_complete(msg_t *msg,
3953 nta_leg_t *leg,
3954 sip_method_t method,
3955 char const *method_name,
3956 url_string_t const *request_uri)
3957{
3958 su_home_t *home = msg_home(msg)((su_home_t*)(msg));
3959 sip_t *sip = sip_object(msg);
3960 sip_to_t const *to;
3961 uint32_t seq;
3962 url_t reg_url[1];
3963 url_string_t const *original = request_uri;
3964
3965 if (!leg || !msg || !sip)
3966 return -1;
3967
3968 if (!sip->sip_route && leg->leg_route) {
3969 if (leg->leg_loose_route) {
3970 if (leg->leg_target) {
3971 request_uri = (url_string_t *)leg->leg_target->m_url;
3972 }
3973 sip->sip_route = sip_route_dup(home, leg->leg_route);
3974 }
3975 else {
3976 sip_route_t **rr;
3977
3978 request_uri = (url_string_t *)leg->leg_route->r_url;
3979 sip->sip_route = sip_route_dup(home, leg->leg_route->r_next);
3980
3981 for (rr = &sip->sip_route; *rr; rr = &(*rr)->r_next)
3982 ;
3983
3984 if (leg->leg_target)
3985 *rr = sip_route_dup(home, (sip_route_t *)leg->leg_target);
3986 }
3987 }
3988 else if (leg->leg_target)
3989 request_uri = (url_string_t *)leg->leg_target->m_url;
3990
3991 if (!request_uri && sip->sip_request)
3992 request_uri = (url_string_t *)sip->sip_request->rq_url;
3993
3994 to = sip->sip_to ? sip->sip_to : leg->leg_remote;
3995
3996 if (!request_uri && to) {
3997 if (method != sip_method_register)
3998 request_uri = (url_string_t *)to->a_url;
3999 else {
4000 /* Remove user part from REGISTER requests */
4001 *reg_url = *to->a_url;
4002 reg_url->url_user = reg_url->url_password = NULL((void*)0);
4003 request_uri = (url_string_t *)reg_url;
4004 }
4005 }
4006
4007 if (!request_uri)
4008 return -1;
4009
4010 if (method || method_name) {
4011 sip_request_t *rq = sip->sip_request;
4012 int use_headers =
4013 request_uri == original || (url_t *)request_uri == rq->rq_url;
4014
4015 if (!rq
4016 || request_uri != (url_string_t *)rq->rq_url
4017 || method != rq->rq_method
4018 || !su_strmatch(method_name, rq->rq_method_name))
4019 rq = NULL((void*)0);
4020
4021 if (rq == NULL((void*)0)) {
4022 rq = sip_request_create(home, method, method_name, request_uri, NULL((void*)0));
4023 if (msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)rq) < 0)
4024 return -1;
4025 }
4026
4027 /* @RFC3261 table 1 (page 152):
4028 * Req-URI cannot contain method parameter or headers
4029 */
4030 if (rq->rq_url->url_params) {
4031 rq->rq_url->url_params =
4032 url_strip_param_string((char *)rq->rq_url->url_params, "method");
4033 sip_fragment_clear(rq->rq_common)((rq->rq_common)->h_data = ((void*)0), (rq->rq_common
)->h_len = 0)
;
4034 }
4035
4036 if (rq->rq_url->url_headers) {
4037 if (use_headers) {
4038 char *s = url_query_as_header_string(msg_home(msg)((su_home_t*)(msg)),
4039 rq->rq_url->url_headers);
4040 if (!s)
4041 return -1;
4042 msg_header_parse_str(msg, (msg_pub_t*)sip, s);
4043 }
4044 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)
;
4045 }
4046 }
4047
4048 if (!sip->sip_request)
4049 return -1;
4050
4051 if (!sip->sip_max_forwards)
4052 sip_add_dup(msg, sip, (sip_header_t *)leg->leg_agent->sa_max_forwards);
4053
4054 if (!sip->sip_from)
4055 sip->sip_from = sip_from_dup(home, leg->leg_local);
4056 else if (leg->leg_local && leg->leg_local->a_tag &&
4057 (!sip->sip_from->a_tag ||
4058 !su_casematch(sip->sip_from->a_tag, leg->leg_local->a_tag)))
4059 sip_from_tag(home, sip->sip_from, leg->leg_local->a_tag);
4060
4061 if (sip->sip_from && !sip->sip_from->a_tag) {
4062 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)
;
4063 sip_from_add_param(home, sip->sip_from,
4064 nta_agent_newtag(home, "tag=%s", leg->leg_agent));
4065 }
4066
4067 if (sip->sip_to) {
4068 if (leg->leg_remote && leg->leg_remote->a_tag)
4069 sip_to_tag(home, sip->sip_to, leg->leg_remote->a_tag);
4070 }
4071 else if (leg->leg_remote) {
4072 sip->sip_to = sip_to_dup(home, leg->leg_remote);
4073 }
4074 else {
4075 sip_to_t *to = sip_to_create(home, request_uri);
4076 if (to) sip_aor_strip(to->a_url);
4077 sip->sip_to = to;
4078 }
4079
4080 if (!sip->sip_from || !sip->sip_from || !sip->sip_to)
4081 return -1;
4082
4083 method = sip->sip_request->rq_method;
4084 method_name = sip->sip_request->rq_method_name;
4085
4086 if (!leg->leg_id && sip->sip_cseq)
4087 seq = sip->sip_cseq->cs_seq;
4088 else if (method == sip_method_ack || method == sip_method_cancel)
4089 /* Dangerous - we may do PRACK/UPDATE meanwhile */
4090 seq = sip->sip_cseq ? sip->sip_cseq->cs_seq : leg->leg_seq;
4091 else if (leg->leg_seq)
4092 seq = ++leg->leg_seq;
4093 else if (sip->sip_cseq) /* Obtain initial value from existing CSeq header */
4094 seq = leg->leg_seq = sip->sip_cseq->cs_seq;
4095 else
4096 seq = leg->leg_seq = (sip_now() >> 1) & 0x7ffffff;
4097
4098 if (!sip->sip_call_id) {
4099 if (leg->leg_id)
4100 sip->sip_call_id = sip_call_id_dup(home, leg->leg_id);
4101 else
4102 sip->sip_call_id = sip_call_id_create(home, NULL((void*)0));
4103 }
4104
4105 if (!sip->sip_cseq ||
4106 seq != sip->sip_cseq->cs_seq ||
4107 method != sip->sip_cseq->cs_method ||
4108 !su_strmatch(method_name, sip->sip_cseq->cs_method_name)) {
4109 sip_cseq_t *cseq = sip_cseq_create(home, seq, method, method_name);
4110 if (msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)cseq) < 0)
4111 return -1;
4112 }
4113
4114 return 0;
4115}
4116
4117/* ====================================================================== */
4118/* 6) Dialogs (legs) */
4119
4120static void leg_insert(nta_agent_t *agent, nta_leg_t *leg);
4121static int leg_route(nta_leg_t *leg,
4122 sip_record_route_t const *route,
4123 sip_record_route_t const *reverse,
4124 sip_contact_t const *contact,
4125 int reroute);
4126static int leg_callback_default(nta_leg_magic_t*, nta_leg_t*,
4127 nta_incoming_t*, sip_t const *);
4128#define HTABLE_HASH_LEG(leg)((leg)->leg_hash) ((leg)->leg_hash)
4129
4130#ifdef __clang__1
4131#pragma clang diagnostic push
4132#pragma clang diagnostic ignored "-Wunused-function"
4133#endif
4134
4135HTABLE_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, ((i != i0) ? (void) (0) : __assert_fail
("i != i0", "nta.c", 4135, __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; ((lht-> lht_used == used) ? (void
) (0) : __assert_fail ("lht-> lht_used == used", "nta.c", 4135
, __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
;
4136
4137#ifdef __clang__1
4138#pragma clang diagnostic pop
4139#endif
4140
4141su_inlinestatic inline
4142hash_value_t hash_istring(char const *, char const *, hash_value_t);
4143
4144/**@typedef nta_request_f
4145 *
4146 * Callback for incoming requests
4147 *
4148 * This is a callback function invoked by NTA for each incoming SIP request.
4149 *
4150 * @param lmagic call leg context
4151 * @param leg call leg handle
4152 * @param ireq incoming request
4153 * @param sip incoming request contents
4154 *
4155 * @retval 100..699
4156 * NTA constructs a reply message with given error code and corresponding
4157 * standard phrase, then sends the reply.
4158 *
4159 * @retval 0
4160 * The application takes care of sending (or not sending) the reply.
4161 *
4162 * @retval other
4163 * All other return values will be interpreted as
4164 * @e 500 @e Internal @e server @e error.
4165 */
4166
4167
4168/**
4169 * Create a new leg object.
4170 *
4171 * Creates a leg object, which is used to represent dialogs, partial dialogs
4172 * (for example, in case of REGISTER), and destinations within a particular
4173 * NTA object.
4174 *
4175 * When a leg is created, a callback pointer and a application context is
4176 * provided. All other parameters are optional.
4177 *
4178 * @param agent agent object
4179 * @param callback function which is called for each
4180 * incoming request belonging to this leg
4181 * @param magic call leg context
4182 * @param tag,value,... optional extra headers in taglist
4183 *
4184 * When a leg representing dialog is created, the tags SIPTAG_CALL_ID(),
4185 * SIPTAG_FROM(), SIPTAG_TO(), and SIPTAG_CSEQ() (for local @CSeq number) are used
4186 * to establish dialog context. The SIPTAG_FROM() is used to pass local
4187 * address (@From header when making a call, @To header when answering
4188 * to a call) to the newly created leg. Respectively, the SIPTAG_TO() is
4189 * used to pass remote address (@To header when making a call, @From
4190 * header when answering to a call).
4191 *
4192 * If there is a (preloaded) route associated with the leg, SIPTAG_ROUTE()
4193 * and NTATAG_TARGET() can be used. A client or server can also set the
4194 * route using @RecordRoute and @Contact headers from a response or
4195 * request message with the functions nta_leg_client_route() and
4196 * nta_leg_server_route(), respectively.
4197 *
4198 * When a leg representing a local destination is created, the tags
4199 * NTATAG_NO_DIALOG(1), NTATAG_METHOD(), and URLTAG_URL() are used. When a
4200 * request with matching request-URI (URLTAG_URL()) and method
4201 * (NTATAG_METHOD()) is received, it is passed to the callback function
4202 * provided with the leg.
4203 *
4204 * @sa nta_leg_stateful(), nta_leg_bind(),
4205 * nta_leg_tag(), nta_leg_rtag(),
4206 * nta_leg_client_route(), nta_leg_server_route(),
4207 * nta_leg_destroy(), nta_outgoing_tcreate(), and nta_request_f().
4208 *
4209 * @TAGS
4210 * NTATAG_NO_DIALOG(), NTATAG_STATELESS(), NTATAG_METHOD(),
4211 * URLTAG_URL(), SIPTAG_CALL_ID(), SIPTAG_CALL_ID_STR(), SIPTAG_FROM(),
4212 * SIPTAG_FROM_STR(), SIPTAG_TO(), SIPTAG_TO_STR(), SIPTAG_ROUTE(),
4213 * NTATAG_TARGET() and SIPTAG_CSEQ().
4214 *
4215 */
4216nta_leg_t *nta_leg_tcreate(nta_agent_t *agent,
4217 nta_request_f *callback,
4218 nta_leg_magic_t *magic,
4219 tag_type_t tag, tag_value_t value, ...)
4220{
4221 sip_route_t const *route = NULL((void*)0);
4222 sip_contact_t const *contact = NULL((void*)0);
4223 sip_cseq_t const *cs = NULL((void*)0);
4224 sip_call_id_t const *i = NULL((void*)0);
4225 sip_from_t const *from = NULL((void*)0);
4226 sip_to_t const *to = NULL((void*)0);
4227 char const *method = NULL((void*)0);
4228 char const *i_str = NULL((void*)0), *to_str = NULL((void*)0), *from_str = NULL((void*)0), *cs_str = NULL((void*)0);
4229 url_string_t const *url_string = NULL((void*)0);
4230 int no_dialog = 0;
4231 unsigned rseq = 0;
4232 /* RFC 3261 section 12.2.1.1 */
4233 uint32_t seq = 0;
4234 ta_list ta;
4235 nta_leg_t *leg;
4236 su_home_t *home;
4237 url_t *url;
4238 char const *what = NULL((void*)0);
4239
4240 if (agent == NULL((void*)0))
4241 return su_seterrno(EINVAL22), NULL((void*)0);
4242
4243 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)
;
4244
4245 tl_gets(ta_args(ta)(ta).tl,
4246 NTATAG_NO_DIALOG_REF(no_dialog)ntatag_no_dialog_ref, tag_bool_vr(&(no_dialog)),
4247 NTATAG_METHOD_REF(method)ntatag_method_ref, tag_str_vr(&(method)),
4248 URLTAG_URL_REF(url_string)urltag_url_ref, urltag_url_vr(&(url_string)),
4249 SIPTAG_CALL_ID_REF(i)siptag_call_id_ref, siptag_call_id_vr(&(i)),
4250 SIPTAG_CALL_ID_STR_REF(i_str)siptag_call_id_str_ref, tag_str_vr(&(i_str)),
4251 SIPTAG_FROM_REF(from)siptag_from_ref, siptag_from_vr(&(from)),
4252 SIPTAG_FROM_STR_REF(from_str)siptag_from_str_ref, tag_str_vr(&(from_str)),
4253 SIPTAG_TO_REF(to)siptag_to_ref, siptag_to_vr(&(to)),
4254 SIPTAG_TO_STR_REF(to_str)siptag_to_str_ref, tag_str_vr(&(to_str)),
4255 SIPTAG_ROUTE_REF(route)siptag_route_ref, siptag_route_vr(&(route)),
4256 NTATAG_TARGET_REF(contact)ntatag_target_ref, siptag_contact_vr(&(contact)),
4257 NTATAG_REMOTE_CSEQ_REF(rseq)ntatag_remote_cseq_ref, tag_uint_vr(&(rseq)),
4258 SIPTAG_CSEQ_REF(cs)siptag_cseq_ref, siptag_cseq_vr(&(cs)),
4259 SIPTAG_CSEQ_STR_REF(cs_str)siptag_cseq_str_ref, tag_str_vr(&(cs_str)),
4260 TAG_END()(tag_type_t)0, (tag_value_t)0);
4261
4262 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))
;
4263
4264 if (cs)
4265 seq = cs->cs_seq;
4266 else if (cs_str)
4267 seq = strtoul(cs_str, (char **)&cs_str, 10);
4268
4269 if (i == NONE((void *)-1)) /* Magic value, used for compatibility */
4270 no_dialog = 1;
4271
4272 if (!(leg = su_home_clone(NULL((void*)0), sizeof(*leg))))
4273 return NULL((void*)0);
4274 home = leg->leg_home;
4275
4276 leg->leg_agent = agent;
4277 nta_leg_bind(leg, callback, magic);
4278
4279 if (from) {
4280 /* Now this is kludge */
4281 leg->leg_local_is_to = sip_is_to((sip_header_t*)from);
4282 leg->leg_local = sip_to_dup(home, from);
4283 }
4284 else if (from_str)
4285 leg->leg_local = sip_to_make(home, from_str);
4286
4287 if (to && no_dialog) {
4288 /* Remove tag, if any */
4289 sip_to_t to0[1]; *to0 = *to; to0->a_params = NULL((void*)0);
4290 leg->leg_remote = sip_from_dup(home, to0);
4291 }
4292 else if (to)
4293 leg->leg_remote = sip_from_dup(home, to);
4294 else if (to_str)
4295 leg->leg_remote = sip_from_make(home, to_str);
4296
4297 if (route && route != NONE((void *)-1))
4298 leg->leg_route = sip_route_dup(home, route), leg->leg_route_set = 1;
4299
4300 if (contact && contact != NONE((void *)-1)) {
4301 sip_contact_t m[1];
4302 sip_contact_init(m);
4303 *m->m_url = *contact->m_url;
4304 m->m_url->url_headers = NULL((void*)0);
4305 leg->leg_target = sip_contact_dup(home, m);
4306 }
4307
4308 url = url_hdup(home, url_string->us_url);
4309
4310 /* Match to local hosts */
4311 if (url && agent_aliases(agent, url, NULL((void*)0))) {
4312 url_t *changed = url_hdup(home, url);
4313 su_free(home, url);
4314 url = changed;
4315 }
4316
4317 leg->leg_rseq = rseq;
4318 leg->leg_seq = seq;
4319 leg->leg_url = url;
4320
4321 if (from && from != NONE((void *)-1) && leg->leg_local == NULL((void*)0)) {
4322 what = "cannot duplicate local address";
4323 goto err;
4324 }
4325 else if (to && to != NONE((void *)-1) && leg->leg_remote == NULL((void*)0)) {
4326 what = "cannot duplicate remote address";
4327 goto err;
4328 }
4329 else if (route && route != NONE((void *)-1) && leg->leg_route == NULL((void*)0)) {
4330 what = "cannot duplicate route";
4331 goto err;
4332 }
4333 else if (contact && contact != NONE((void *)-1) && leg->leg_target == NULL((void*)0)) {
4334 what = "cannot duplicate target";
4335 goto err;
4336 }
4337 else if (url_string && leg->leg_url == NULL((void*)0)) {
4338 what = "cannot duplicate local destination";
4339 goto err;
4340 }
4341
4342 if (!no_dialog) {
4343 if (!leg->leg_local || !leg->leg_remote) {
4344 /* To and/or From header missing */
4345 if (leg->leg_remote)
4346 what = "Missing local dialog address";
4347 else if (leg->leg_local)
4348 what = "Missing remote dialog address";
4349 else
4350 what = "Missing dialog addresses";
4351 goto err;
4352 }
4353
4354 leg->leg_dialog = 1;
4355
4356 if (i != NULL((void*)0))
4357 leg->leg_id = sip_call_id_dup(home, i);
4358 else if (i_str != NULL((void*)0))
4359 leg->leg_id = sip_call_id_make(home, i_str);
4360 else
4361 leg->leg_id = sip_call_id_create(home, NULL((void*)0));
4362
4363 if (!leg->leg_id) {
4364 what = "cannot create Call-ID";
4365 goto err;
4366 }
4367
4368 leg->leg_hash = leg->leg_id->i_hash;
4369 }
4370 else if (url) {
4371 /* This is "default leg" with a destination URL. */
4372 hash_value_t hash = 0;
4373
4374 if (method) {
4375 leg->leg_method = su_strdup(home, method);
4376 }
4377#if 0
4378 else if (url->url_params) {
4379 int len = url_param(url->url_params, "method", NULL((void*)0), 0);
4380 if (len) {
4381 char *tmp = su_alloc(home, len);
4382 leg->leg_method = tmp;
4383 url_param(url->url_params, "method", tmp, len);
4384 }
4385 }
4386#endif
4387
4388 if (url->url_user && strcmp(url->url_user, "")__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(url->url_user) && __builtin_constant_p ("") &&
(__s1_len = __builtin_strlen (url->url_user), __s2_len = __builtin_strlen
(""), (!((size_t)(const void *)((url->url_user) + 1) - (size_t
)(const void *)(url->url_user) == 1) || __s1_len >= 4) &&
(!((size_t)(const void *)(("") + 1) - (size_t)(const void *)
("") == 1) || __s2_len >= 4)) ? __builtin_strcmp (url->
url_user, "") : (__builtin_constant_p (url->url_user) &&
((size_t)(const void *)((url->url_user) + 1) - (size_t)(const
void *)(url->url_user) == 1) && (__s1_len = __builtin_strlen
(url->url_user), __s1_len < 4) ? (__builtin_constant_p
("") && ((size_t)(const void *)(("") + 1) - (size_t)
(const void *)("") == 1) ? __builtin_strcmp (url->url_user
, "") : (__extension__ ({ const unsigned char *__s2 = (const unsigned
char *) (const char *) (""); int __result = (((const unsigned
char *) (const char *) (url->url_user))[0] - __s2[0]); if
(__s1_len > 0 && __result == 0) { __result = (((const
unsigned char *) (const char *) (url->url_user))[1] - __s2
[1]); if (__s1_len > 1 && __result == 0) { __result
= (((const unsigned char *) (const char *) (url->url_user
))[2] - __s2[2]); if (__s1_len > 2 && __result == 0
) __result = (((const unsigned char *) (const char *) (url->
url_user))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p
("") && ((size_t)(const void *)(("") + 1) - (size_t)
(const void *)("") == 1) && (__s2_len = __builtin_strlen
(""), __s2_len < 4) ? (__builtin_constant_p (url->url_user
) && ((size_t)(const void *)((url->url_user) + 1) -
(size_t)(const void *)(url->url_user) == 1) ? __builtin_strcmp
(url->url_user, "") : (- (__extension__ ({ const unsigned
char *__s2 = (const unsigned char *) (const char *) (url->
url_user); int __result = (((const unsigned char *) (const char
*) (""))[0] - __s2[0]); if (__s2_len > 0 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
""))[1] - __s2[1]); if (__s2_len > 1 && __result ==
0) { __result = (((const unsigned char *) (const char *) (""
))[2] - __s2[2]); if (__s2_len > 2 && __result == 0
) __result = (((const unsigned char *) (const char *) (""))[3
] - __s2[3]); } } __result; })))) : __builtin_strcmp (url->
url_user, "")))); })
== 0)
4389 url->url_user = "%"; /* Match to any user */
4390
4391 hash = hash_istring(url->url_scheme, ":", 0);
4392 hash = hash_istring(url->url_host, "", hash);
4393 hash = hash_istring(url->url_user, "@", hash);
4394
4395 leg->leg_hash = hash;
4396 }
4397 else {
4398 /* This is "default leg" without a destination URL. */
4399 if (agent->sa_default_leg) {
4400 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__
, 4400, "%s(): %s\n", "nta_leg_tcreate", "tried to create second default leg"
)) : (void)0)
;
4401 su_seterrno(EEXIST17);
4402 goto err;
4403 }
4404 else {
4405 agent->sa_default_leg = leg;
4406 }
4407 return leg;
4408 }
4409
4410 if (url) {
4411 /* Parameters are ignored when comparing incoming URLs */
4412 url->url_params = NULL((void*)0);
4413 }
4414
4415 leg_insert(agent, leg);
4416
4417 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__
, 4417, "%s(%p)\n", "nta_leg_tcreate", (void *)leg)) : (void)
0)
;
4418
4419 return leg;
4420
4421 err:
4422 if (what)
4423 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__
, 4423, "%s(): %s\n", "nta_leg_tcreate", what)) : (void)0)
;
4424
4425 su_home_zap(leg->leg_home)su_home_unref((leg->leg_home));
4426
4427 return NULL((void*)0);
4428}
4429
4430/** Return the default leg, if any */
4431nta_leg_t *nta_default_leg(nta_agent_t const *agent)
4432{
4433 return agent ? agent->sa_default_leg : NULL((void*)0);
4434}
4435
4436
4437/**
4438 * Insert a call leg to agent.
4439 */
4440static
4441void leg_insert(nta_agent_t *sa, nta_leg_t *leg)
4442{
4443 leg_htable_t *leg_hash;
4444 assert(leg)((leg) ? (void) (0) : __assert_fail ("leg", "nta.c", 4444, __PRETTY_FUNCTION__
))
;
4445 assert(sa)((sa) ? (void) (0) : __assert_fail ("sa", "nta.c", 4445, __PRETTY_FUNCTION__
))
;
4446
4447 if (leg->leg_dialog)
4448 leg_hash = sa->sa_dialogs;
4449 else
4450 leg_hash = sa->sa_defaults;
4451
4452 if (leg_htable_is_full(leg_hash)) {
4453 leg_htable_resize(sa->sa_home, leg_hash, 0);
4454 assert(leg_hash->lht_table)((leg_hash->lht_table) ? (void) (0) : __assert_fail ("leg_hash->lht_table"
, "nta.c", 4454, __PRETTY_FUNCTION__))
;
4455 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__
, 4456, "nta: resized%s leg hash to ""%zu""\n", leg->leg_dialog
? "" : " default", leg_hash->lht_size)) : (void)0)
4456 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__
, 4456, "nta: resized%s leg hash to ""%zu""\n", leg->leg_dialog
? "" : " default", leg_hash->lht_size)) : (void)0)
;
4457 }
4458
4459 /* Insert entry into hash table (before other legs with same hash) */
4460 leg_htable_insert(leg_hash, leg);
4461}
4462
4463/**
4464 * Destroy a leg.
4465 *
4466 * @param leg leg to be destroyed
4467 */
4468void nta_leg_destroy(nta_leg_t *leg)
4469{
4470 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__
, 4470, "nta_leg_destroy(%p)\n", (void *)leg)) : (void)0)
;
4471
4472 if (leg) {
4473 leg_htable_t *leg_hash;
4474 nta_agent_t *sa = leg->leg_agent;
4475
4476 assert(sa)((sa) ? (void) (0) : __assert_fail ("sa", "nta.c", 4476, __PRETTY_FUNCTION__
))
;
4477
4478 if (leg->leg_dialog) {
4479 assert(sa->sa_dialogs)((sa->sa_dialogs) ? (void) (0) : __assert_fail ("sa->sa_dialogs"
, "nta.c", 4479, __PRETTY_FUNCTION__))
;
4480 leg_hash = sa->sa_dialogs;
4481 }
4482 else if (leg != sa->sa_default_leg) {
4483 assert(sa->sa_defaults)((sa->sa_defaults) ? (void) (0) : __assert_fail ("sa->sa_defaults"
, "nta.c", 4483, __PRETTY_FUNCTION__))
;
4484 leg_hash = sa->sa_defaults;
4485 }
4486 else {
4487 sa->sa_default_leg = NULL((void*)0);
4488 leg_hash = NULL((void*)0);
4489 }
4490
4491 if (leg_hash)
4492 leg_htable_remove(leg_hash, leg);
4493
4494 leg_free(sa, leg);
4495 }
4496}
4497
4498static
4499void leg_free(nta_agent_t *sa, nta_leg_t *leg)
4500{
4501 //su_free(sa->sa_home, leg);
4502 su_home_unref((su_home_t *)leg);
4503}
4504
4505/** Return application context for the leg */
4506nta_leg_magic_t *nta_leg_magic(nta_leg_t const *leg,
4507 nta_request_f *callback)
4508{
4509 if (leg)
4510 if (!callback || leg->leg_callback == callback)
4511 return leg->leg_magic;
4512
4513 return NULL((void*)0);
4514}
4515
4516/**Bind a callback function and context to a leg object.
4517 *
4518 * Change the callback function and context pointer attached to a leg
4519 * object.
4520 *
4521 * @param leg leg object to be bound
4522 * @param callback new callback function (or NULL if no callback is desired)
4523 * @param magic new context pointer
4524 */
4525void nta_leg_bind(nta_leg_t *leg,
4526 nta_request_f *callback,
4527 nta_leg_magic_t *magic)
4528{
4529 if (leg) {
4530 if (callback)
4531 leg->leg_callback = callback;
4532 else
4533 leg->leg_callback = leg_callback_default;
4534 leg->leg_magic = magic;
4535 }
4536}
4537
4538/** Add a local tag to the leg.
4539 *
4540 * @param leg leg to be tagged
4541 * @param tag tag to be added (if NULL, a tag generated by @b NTA is added)
4542 *
4543 * @return
4544 * Pointer to tag if successful, NULL otherwise.
4545 */
4546char const *nta_leg_tag(nta_leg_t *leg, char const *tag)
4547{
4548 if (!leg || !leg->leg_local)
4549 return su_seterrno(EINVAL22), NULL((void*)0);
4550
4551 if (tag && strchr(tag, '=')(__extension__ (__builtin_constant_p ('=') && !__builtin_constant_p
(tag) && ('=') == '\0' ? (char *) __rawmemchr (tag, '='
) : __builtin_strchr (tag, '=')))
)
4552 tag = strchr(tag, '=')(__extension__ (__builtin_constant_p ('=') && !__builtin_constant_p
(tag) && ('=') == '\0' ? (char *) __rawmemchr (tag, '='
) : __builtin_strchr (tag, '=')))
+ 1;
4553
4554 /* If there already is a tag,
4555 return NULL if it does not match with new one */
4556 if (leg->leg_local->a_tag) {
4557 if (tag == NULL((void*)0) || su_casematch(tag, leg->leg_local->a_tag))
4558 return leg->leg_local->a_tag;
4559 else
4560 return NULL((void*)0);
4561 }
4562
4563 if (tag) {
4564 if (sip_to_tag(leg->leg_home, leg->leg_local, tag) < 0)
4565 return NULL((void*)0);
4566 leg->leg_tagged = 1;
4567 return leg->leg_local->a_tag;
4568 }
4569
4570 tag = nta_agent_newtag(leg->leg_home, "tag=%s", leg->leg_agent);
4571
4572 if (!tag || sip_to_add_param(leg->leg_home, leg->leg_local, tag) < 0)
4573 return NULL((void*)0);
4574
4575 leg->leg_tagged = 1;
4576
4577 return leg->leg_local->a_tag;
4578}
4579
4580/** Get local tag. */
4581char const *nta_leg_get_tag(nta_leg_t const *leg)
4582{
4583 if (leg && leg->leg_local)
4584 return leg->leg_local->a_tag;
4585 else
4586 return NULL((void*)0);
4587}
4588
4589/** Add a remote tag to the leg.
4590 *
4591 * @note No remote tag is ever generated.
4592 *
4593 * @param leg leg to be tagged
4594 * @param tag tag to be added (@b must be non-NULL)
4595 *
4596 * @return
4597 * Pointer to tag if successful, NULL otherwise.
4598 */
4599char const *nta_leg_rtag(nta_leg_t *leg, char const *tag)
4600{
4601 /* Add a tag parameter, unless there already is a tag */
4602 if (leg && leg->leg_remote && tag) {
4603 if (sip_from_tag(leg->leg_home, leg->leg_remote, tag) < 0)
4604 return NULL((void*)0);
4605 }
4606
4607 if (leg && leg->leg_remote)
4608 return leg->leg_remote->a_tag;
4609 else
4610 return NULL((void*)0);
4611}
4612
4613/** Get remote tag. */
4614char const *nta_leg_get_rtag(nta_leg_t const *leg)
4615{
4616 if (leg && leg->leg_remote)
4617 return leg->leg_remote->a_tag;
4618 else
4619 return NULL((void*)0);
4620}
4621
4622/** Get local request sequence number. */
4623uint32_t nta_leg_get_seq(nta_leg_t const *leg)
4624{
4625 return leg ? leg->leg_seq : 0;
4626}
4627
4628/** Get remote request sequence number. */
4629uint32_t nta_leg_get_rseq(nta_leg_t const *leg)
4630{
4631 return leg ? leg->leg_rseq : 0;
4632}
4633
4634/** Save target and route set at UAC side.
4635 *
4636 * @sa nta_leg_client_reroute(), nta_leg_server_route(), @RFC3261 section 12.1.2
4637 *
4638 * @bug Allows modifying the route set after initial transaction, if initial
4639 * transaction had no @RecordRoute headers.
4640 *
4641 * @deprecated Use nta_leg_client_reroute() instead.
4642 */
4643int nta_leg_client_route(nta_leg_t *leg,
4644 sip_record_route_t const *route,
4645 sip_contact_t const *contact)
4646{
4647 return leg_route(leg, NULL((void*)0), route, contact, 0);
4648}
4649
4650/** Save target and route set at UAC side.
4651 *
4652 * If @a initial is true, the route set is modified even if it has been set
4653 * earlier.
4654 *
4655 * @param leg pointer to dialog leg
4656 * @param route @RecordRoute headers from response
4657 * @param contact @Contact header from response
4658 * @param initial true if response to initial transaction
4659 *
4660 * @sa nta_leg_client_route(), nta_leg_server_route(), @RFC3261 section 12.1.2
4661 *
4662 * @NEW_1_12_11
4663 */
4664int nta_leg_client_reroute(nta_leg_t *leg,
4665 sip_record_route_t const *route,
4666 sip_contact_t const *contact,
4667 int initial)
4668{
4669 return leg_route(leg, NULL((void*)0), route, contact, initial ? 2 : 1);
4670}
4671
4672/** Save target and route set at UAS side.
4673 *
4674 * @param leg pointer to dialog leg
4675 * @param route @RecordRoute headers from request
4676 * @param contact @Contact header from request
4677 *
4678 * @sa nta_leg_client_reroute(), @RFC3261 section 12.1.1
4679 */
4680int nta_leg_server_route(nta_leg_t *leg,
4681 sip_record_route_t const *route,
4682 sip_contact_t const *contact)
4683{
4684 return leg_route(leg, route, NULL((void*)0), contact, 1);
4685}
4686
4687/** Return route components. */
4688int nta_leg_get_route(nta_leg_t *leg,
4689 sip_route_t const **return_route,
4690 sip_contact_t const **return_target)
4691{
4692 if (!leg)
4693 return -1;
4694
4695 if (return_route)
4696 *return_route = leg->leg_route;
4697
4698 if (return_target)
4699 *return_target = leg->leg_target;
4700
4701 return 0;
4702}
4703
4704/** Generate @Replaces header.
4705 *
4706 * @since New in @VERSION_1_12_2.
4707 */
4708sip_replaces_t *
4709nta_leg_make_replaces(nta_leg_t *leg,
4710 su_home_t *home,
4711 int early_only)
4712{
4713 char const *from_tag, *to_tag;
4714
4715 if (!leg)
4716 return NULL((void*)0);
4717 if (!leg->leg_dialog || !leg->leg_local || !leg->leg_remote || !leg->leg_id)
4718 return NULL((void*)0);
4719
4720 from_tag = leg->leg_local->a_tag; if (!from_tag) from_tag = "0";
4721 to_tag = leg->leg_remote->a_tag; if (!to_tag) to_tag = "0";
4722
4723 return sip_replaces_format(home, "%s;from-tag=%s;to-tag=%s%s",
4724 leg->leg_id->i_id, from_tag, to_tag,
4725 early_only ? ";early-only" : "");
4726}
4727
4728/** Get dialog leg by @Replaces header.
4729 *
4730 * @since New in @VERSION_1_12_2.
4731 */
4732nta_leg_t *
4733nta_leg_by_replaces(nta_agent_t *sa, sip_replaces_t const *rp)
4734{
4735 nta_leg_t *leg = NULL((void*)0);
4736
4737 if (sa && rp && rp->rp_call_id && rp->rp_from_tag && rp->rp_to_tag) {
4738 char const *from_tag = rp->rp_from_tag, *to_tag = rp->rp_to_tag;
4739 sip_call_id_t id[1];
4740 sip_call_id_init(id);
4741
4742 id->i_hash = msg_hash_string(id->i_id = rp->rp_call_id);
4743
4744 leg = leg_find(sa, NULL((void*)0), NULL((void*)0), id, from_tag, to_tag);
4745
4746 if (leg == NULL((void*)0) && strcmp(from_tag, "0")__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(from_tag) && __builtin_constant_p ("0") && (
__s1_len = __builtin_strlen (from_tag), __s2_len = __builtin_strlen
("0"), (!((size_t)(const void *)((from_tag) + 1) - (size_t)(
const void *)(from_tag) == 1) || __s1_len >= 4) &&
(!((size_t)(const void *)(("0") + 1) - (size_t)(const void *
)("0") == 1) || __s2_len >= 4)) ? __builtin_strcmp (from_tag
, "0") : (__builtin_constant_p (from_tag) && ((size_t
)(const void *)((from_tag) + 1) - (size_t)(const void *)(from_tag
) == 1) && (__s1_len = __builtin_strlen (from_tag), __s1_len
< 4) ? (__builtin_constant_p ("0") && ((size_t)(const
void *)(("0") + 1) - (size_t)(const void *)("0") == 1) ? __builtin_strcmp
(from_tag, "0") : (__extension__ ({ const unsigned char *__s2
= (const unsigned char *) (const char *) ("0"); int __result
= (((const unsigned char *) (const char *) (from_tag))[0] - __s2
[0]); if (__s1_len > 0 && __result == 0) { __result
= (((const unsigned char *) (const char *) (from_tag))[1] - __s2
[1]); if (__s1_len > 1 && __result == 0) { __result
= (((const unsigned char *) (const char *) (from_tag))[2] - __s2
[2]); if (__s1_len > 2 && __result == 0) __result =
(((const unsigned char *) (const char *) (from_tag))[3] - __s2
[3]); } } __result; }))) : (__builtin_constant_p ("0") &&
((size_t)(const void *)(("0") + 1) - (size_t)(const void *)(
"0") == 1) && (__s2_len = __builtin_strlen ("0"), __s2_len
< 4) ? (__builtin_constant_p (from_tag) && ((size_t
)(const void *)((from_tag) + 1) - (size_t)(const void *)(from_tag
) == 1) ? __builtin_strcmp (from_tag, "0") : (- (__extension__
({ const unsigned char *__s2 = (const unsigned char *) (const
char *) (from_tag); int __result = (((const unsigned char *)
(const char *) ("0"))[0] - __s2[0]); if (__s2_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) ("0"))[1] - __s2[1]); if (__s2_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) ("0"))[2] - __s2[2]); if (__s2_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) ("0"))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp
(from_tag, "0")))); })
== 0)
4747 leg = leg_find(sa, NULL((void*)0), NULL((void*)0), id, NULL((void*)0), to_tag);
4748 if (leg == NULL((void*)0) && strcmp(to_tag, "0")__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(to_tag) && __builtin_constant_p ("0") && (__s1_len
= __builtin_strlen (to_tag), __s2_len = __builtin_strlen ("0"
), (!((size_t)(const void *)((to_tag) + 1) - (size_t)(const void
*)(to_tag) == 1) || __s1_len >= 4) && (!((size_t)
(const void *)(("0") + 1) - (size_t)(const void *)("0") == 1)
|| __s2_len >= 4)) ? __builtin_strcmp (to_tag, "0") : (__builtin_constant_p
(to_tag) && ((size_t)(const void *)((to_tag) + 1) - (
size_t)(const void *)(to_tag) == 1) && (__s1_len = __builtin_strlen
(to_tag), __s1_len < 4) ? (__builtin_constant_p ("0") &&
((size_t)(const void *)(("0") + 1) - (size_t)(const void *)(
"0") == 1) ? __builtin_strcmp (to_tag, "0") : (__extension__ (
{ const unsigned char *__s2 = (const unsigned char *) (const char
*) ("0"); int __result = (((const unsigned char *) (const char
*) (to_tag))[0] - __s2[0]); if (__s1_len > 0 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
to_tag))[1] - __s2[1]); if (__s1_len > 1 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
to_tag))[2] - __s2[2]); if (__s1_len > 2 && __result
== 0) __result = (((const unsigned char *) (const char *) (to_tag
))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p (
"0") && ((size_t)(const void *)(("0") + 1) - (size_t)
(const void *)("0") == 1) && (__s2_len = __builtin_strlen
("0"), __s2_len < 4) ? (__builtin_constant_p (to_tag) &&
((size_t)(const void *)((to_tag) + 1) - (size_t)(const void *
)(to_tag) == 1) ? __builtin_strcmp (to_tag, "0") : (- (__extension__
({ const unsigned char *__s2 = (const unsigned char *) (const
char *) (to_tag); int __result = (((const unsigned char *) (
const char *) ("0"))[0] - __s2[0]); if (__s2_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) ("0"))[1] - __s2[1]); if (__s2_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) ("0"))[2] - __s2[2]); if (__s2_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) ("0"))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp
(to_tag, "0")))); })
== 0)
4749 leg = leg_find(sa, NULL((void*)0), NULL((void*)0), id, from_tag, NULL((void*)0));
4750 }
4751
4752 return leg;
4753}
4754
4755/**@internal
4756 * Find a leg corresponding to the request message.
4757 *
4758 */
4759static nta_leg_t *
4760leg_find_call_id(nta_agent_t const *sa,
4761 sip_call_id_t const *i)
4762{
4763 hash_value_t hash = i->i_hash;
4764 leg_htable_t const *lht = sa->sa_dialogs;
4765 nta_leg_t **ll, *leg = NULL((void*)0);
4766
4767 for (ll = leg_htable_hash(lht, hash);
4768 (leg = *ll);
4769 ll = leg_htable_next(lht, ll)) {
4770 sip_call_id_t const *leg_i = leg->leg_id;
4771
4772 if (leg->leg_hash != hash)
4773 continue;
4774 if (strcmp(leg_i->i_id, i->i_id)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(leg_i->i_id) && __builtin_constant_p (i->i_id
) && (__s1_len = __builtin_strlen (leg_i->i_id), __s2_len
= __builtin_strlen (i->i_id), (!((size_t)(const void *)((
leg_i->i_id) + 1) - (size_t)(const void *)(leg_i->i_id)
== 1) || __s1_len >= 4) && (!((size_t)(const void
*)((i->i_id) + 1) - (size_t)(const void *)(i->i_id) ==
1) || __s2_len >= 4)) ? __builtin_strcmp (leg_i->i_id,
i->i_id) : (__builtin_constant_p (leg_i->i_id) &&
((size_t)(const void *)((leg_i->i_id) + 1) - (size_t)(const
void *)(leg_i->i_id) == 1) && (__s1_len = __builtin_strlen
(leg_i->i_id), __s1_len < 4) ? (__builtin_constant_p (
i->i_id) && ((size_t)(const void *)((i->i_id) +
1) - (size_t)(const void *)(i->i_id) == 1) ? __builtin_strcmp
(leg_i->i_id, i->i_id) : (__extension__ ({ const unsigned
char *__s2 = (const unsigned char *) (const char *) (i->i_id
); int __result = (((const unsigned char *) (const char *) (leg_i
->i_id))[0] - __s2[0]); if (__s1_len > 0 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
leg_i->i_id))[1] - __s2[1]); if (__s1_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (leg_i->i_id))[2] - __s2[2]); if (__s1_len > 2
&& __result == 0) __result = (((const unsigned char *
) (const char *) (leg_i->i_id))[3] - __s2[3]); } } __result
; }))) : (__builtin_constant_p (i->i_id) && ((size_t
)(const void *)((i->i_id) + 1) - (size_t)(const void *)(i->
i_id) == 1) && (__s2_len = __builtin_strlen (i->i_id
), __s2_len < 4) ? (__builtin_constant_p (leg_i->i_id) &&
((size_t)(const void *)((leg_i->i_id) + 1) - (size_t)(const
void *)(leg_i->i_id) == 1) ? __builtin_strcmp (leg_i->
i_id, i->i_id) : (- (__extension__ ({ const unsigned char *
__s2 = (const unsigned char *) (const char *) (leg_i->i_id
); int __result = (((const unsigned char *) (const char *) (i
->i_id))[0] - __s2[0]); if (__s2_len > 0 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
i->i_id))[1] - __s2[1]); if (__s2_len > 1 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
i->i_id))[2] - __s2[2]); if (__s2_len > 2 && __result
== 0) __result = (((const unsigned char *) (const char *) (i
->i_id))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp
(leg_i->i_id, i->i_id)))); })
!= 0)
4775 continue;
4776
4777 return leg;
4778 }
4779
4780 return leg;
4781}
4782
4783/** Get dialog leg by @CallID.
4784 *
4785 * @note Usually there should be only single dialog per @CallID on
4786 * User-Agents. However, proxies may fork requests initiating the dialog and
4787 * result in multiple calls per @CallID.
4788 *
4789 * @since New in @VERSION_1_12_9.
4790 */
4791nta_leg_t *
4792nta_leg_by_call_id(nta_agent_t *sa, const char *call_id)
4793{
4794 nta_leg_t *leg = NULL((void*)0);
4795
4796 if (call_id) {
4797 sip_call_id_t id[1];
4798 sip_call_id_init(id);
4799
4800 id->i_hash = msg_hash_string(id->i_id = call_id);
4801
4802 leg = leg_find_call_id(sa, id);
4803 }
4804
4805 return leg;
4806}
4807
4808/** Calculate a simple case-insensitive hash over a string */
4809su_inlinestatic inline
4810hash_value_t hash_istring(char const *s, char const *term, hash_value_t hash)
4811{
4812 if (s) {
4813 for (; *s; s++) {
4814 unsigned char c = *s;
4815 if ('A' <= c && c <= 'Z')
4816 c += 'a' - 'A';
4817 hash = 38501U * (hash + c);
4818 }
4819 for (s = term; *s; s++) {
4820 unsigned char c = *s;
4821 hash = 38501U * (hash + c);
4822 }
4823 }
4824
4825 return hash;
4826}
4827
4828/** @internal Handle requests intended for this leg. */
4829static
4830void leg_recv(nta_leg_t *leg, msg_t *msg, sip_t *sip, tport_t *tport)
4831{
4832 nta_agent_t *agent = leg->leg_agent;
4833 nta_incoming_t *irq;
4834 sip_method_t method = sip->sip_request->rq_method;
4835 char const *method_name = sip->sip_request->rq_method_name;
4836 char const *tag = NULL((void*)0);
4837 int status;
4838
4839 if (leg->leg_local)
4840 tag = leg->leg_local->a_tag;
4841
4842 if (leg->leg_dialog)
4843 agent->sa_stats->as_dialog_tr++;
4844
4845 /* RFC-3262 section 3 (page 4) */
4846 if (agent->sa_is_a_uas && method == sip_method_prack) {
4847 mreply(agent, NULL((void*)0), 481, "No such response", msg,
4848 tport, 0, 0, NULL((void*)0),
4849 TAG_END()(tag_type_t)0, (tag_value_t)0);
4850 return;
4851 }
4852
4853 if (!(irq = incoming_create(agent, msg, sip, tport, tag))) {
4854 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__
, 4855, "nta: leg_recv(%p): cannot create transaction for %s\n"
, (void *)leg, method_name)) : (void)0)
4855 (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__
, 4855, "nta: leg_recv(%p): cannot create transaction for %s\n"
, (void *)leg, method_name)) : (void)0)
;
4856 mreply(agent, NULL((void*)0), SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error, msg,
4857 tport, 0, 0, NULL((void*)0),
4858 TAG_END()(tag_type_t)0, (tag_value_t)0);
4859 return;
4860 }
4861
4862 irq->irq_compressed = leg->leg_compressed;
4863 irq->irq_in_callback = 1;
4864 status = incoming_callback(leg, irq, sip);
4865 irq->irq_in_callback = 0;
4866
4867 if (irq->irq_destroyed) {
4868 if (irq->irq_terminated) {
4869 incoming_free(irq);
4870 return;
4871 }
4872 if (status < 200)
4873 status = 500;
4874 }
4875
4876 if (status == 0)
4877 return;
4878
4879 if (status < 100 || status > 699) {
4880 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__
, 4881, "nta_leg(%p): invalid status %03d from callback\n", (
void *)leg, status)) : (void)0)
4881 (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__
, 4881, "nta_leg(%p): invalid status %03d from callback\n", (
void *)leg, status)) : (void)0)
;
4882 status = 500;
4883 }
4884 else if (method == sip_method_invite && status >= 200 && status < 300) {
4885 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__
, 4886, "nta_leg(%p): invalid INVITE status %03d from callback\n"
, (void *)leg, status)) : (void)0)
4886 (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__
, 4886, "nta_leg(%p): invalid INVITE status %03d from callback\n"
, (void *)leg, status)) : (void)0)
;
4887 status = 500;
4888 }
4889
4890 if (status >= 100 && irq->irq_status < 200)
4891 nta_incoming_treply(irq, status, NULL((void*)0), TAG_END()(tag_type_t)0, (tag_value_t)0);
4892
4893 if (status >= 200)
4894 nta_incoming_destroy(irq);
4895}
4896
4897#if 0
4898/**Compare two SIP from/to fields.
4899 *
4900 * @retval nonzero if matching.
4901 * @retval zero if not matching.
4902 */
4903su_inlinestatic inline
4904int addr_cmp(url_t const *a, url_t const *b)
4905{
4906 if (b == NULL((void*)0))
4907 return 0;
4908 else
4909 return
4910 host_cmp(a->url_host, b->url_host) ||
4911 su_strcmp(a->url_port, b->url_port) ||
4912 su_strcmp(a->url_user, b->url_user);
4913}
4914#endif
4915
4916/** Get a leg by dialog.
4917 *
4918 * Search for a dialog leg from agent's hash table. The matching rules based
4919 * on parameters are as follows:
4920 *
4921 * @param agent pointer to agent object
4922 * @param request_uri if non-NULL, and there is destination URI
4923 * associated with the dialog, these URIs must match
4924 * @param call_id if non-NULL, must match with @CallID header contents
4925 * @param remote_tag if there is remote tag
4926 * associated with dialog, @a remote_tag must match
4927 * @param remote_uri ignored
4928 * @param local_tag if non-NULL and there is local tag associated with leg,
4929 * it must math
4930 * @param local_uri ignored
4931 *
4932 * @note
4933 * If @a remote_tag or @a local_tag is an empty string (""), the tag is
4934 * ignored when matching legs.
4935 */
4936nta_leg_t *nta_leg_by_dialog(nta_agent_t const *agent,
4937 url_t const *request_uri,
4938 sip_call_id_t const *call_id,
4939 char const *remote_tag,
4940 url_t const *remote_uri,
4941 char const *local_tag,
4942 url_t const *local_uri)
4943{
4944 void *to_be_freed = NULL((void*)0);
4945 url_t *url;
4946 url_t url0[1];
4947 nta_leg_t *leg;
4948
4949 if (!agent || !call_id)
4950 return su_seterrno(EINVAL22), NULL((void*)0);
4951
4952 if (request_uri == NULL((void*)0)) {
4953 url = NULL((void*)0);
4954 }
4955 else if (URL_IS_STRING(request_uri)((request_uri) && *((url_string_t*)(request_uri))->
us_str != 0)
) {
4956 /* accept a string as URL */
4957 to_be_freed = url = url_hdup(NULL((void*)0), request_uri);
4958 }
4959 else {
4960 *url0 = *request_uri, url = url0;
4961 }
4962
4963 if (url) {
4964 url->url_params = NULL((void*)0);
4965 agent_aliases(agent, url, NULL((void*)0)); /* canonize url */
4966 }
4967
4968 if (remote_tag && remote_tag[0] == '\0')
4969 remote_tag = NULL((void*)0);
4970 if (local_tag && local_tag[0] == '\0')
4971 local_tag = NULL((void*)0);
4972
4973 leg = leg_find(agent,
4974 NULL((void*)0), url,
4975 call_id,
4976 remote_tag,
4977 local_tag);
4978
4979 if (to_be_freed) su_free(NULL((void*)0), to_be_freed);
4980
4981 return leg;
4982}
4983
4984/**@internal
4985 * Find a leg corresponding to the request message.
4986 *
4987 * A leg matches to message if leg_match_request() returns true ("Call-ID",
4988 * "To"-tag, and "From"-tag match).
4989 */
4990static
4991nta_leg_t *leg_find(nta_agent_t const *sa,
4992 char const *method_name,
4993 url_t const *request_uri,
4994 sip_call_id_t const *i,
4995 char const *from_tag,
4996 char const *to_tag)
4997{
4998 hash_value_t hash = i->i_hash;
4999 leg_htable_t const *lht = sa->sa_dialogs;
5000 nta_leg_t **ll, *leg, *loose_match = NULL((void*)0);
5001
5002 for (ll = leg_htable_hash(lht, hash);
5003 (leg = *ll);
5004 ll = leg_htable_next(lht, ll)) {
5005 sip_call_id_t const *leg_i = leg->leg_id;
5006 char const *remote_tag = leg->leg_remote->a_tag;
5007 char const *local_tag = leg->leg_local->a_tag;
5008
5009 url_t const *leg_url = leg->leg_url;
5010 char const *leg_method = leg->leg_method;
5011
5012 if (leg->leg_hash != hash)
5013 continue;
5014 if (strcmp(leg_i->i_id, i->i_id)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(leg_i->i_id) && __builtin_constant_p (i->i_id
) && (__s1_len = __builtin_strlen (leg_i->i_id), __s2_len
= __builtin_strlen (i->i_id), (!((size_t)(const void *)((
leg_i->i_id) + 1) - (size_t)(const void *)(leg_i->i_id)
== 1) || __s1_len >= 4) && (!((size_t)(const void
*)((i->i_id) + 1) - (size_t)(const void *)(i->i_id) ==
1) || __s2_len >= 4)) ? __builtin_strcmp (leg_i->i_id,
i->i_id) : (__builtin_constant_p (leg_i->i_id) &&
((size_t)(const void *)((leg_i->i_id) + 1) - (size_t)(const
void *)(leg_i->i_id) == 1) && (__s1_len = __builtin_strlen
(leg_i->i_id), __s1_len < 4) ? (__builtin_constant_p (
i->i_id) && ((size_t)(const void *)((i->i_id) +
1) - (size_t)(const void *)(i->i_id) == 1) ? __builtin_strcmp
(leg_i->i_id, i->i_id) : (__extension__ ({ const unsigned
char *__s2 = (const unsigned char *) (const char *) (i->i_id
); int __result = (((const unsigned char *) (const char *) (leg_i
->i_id))[0] - __s2[0]); if (__s1_len > 0 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
leg_i->i_id))[1] - __s2[1]); if (__s1_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (leg_i->i_id))[2] - __s2[2]); if (__s1_len > 2
&& __result == 0) __result = (((const unsigned char *
) (const char *) (leg_i->i_id))[3] - __s2[3]); } } __result
; }))) : (__builtin_constant_p (i->i_id) && ((size_t
)(const void *)((i->i_id) + 1) - (size_t)(const void *)(i->
i_id) == 1) && (__s2_len = __builtin_strlen (i->i_id
), __s2_len < 4) ? (__builtin_constant_p (leg_i->i_id) &&
((size_t)(const void *)((leg_i->i_id) + 1) - (size_t)(const
void *)(leg_i->i_id) == 1) ? __builtin_strcmp (leg_i->
i_id, i->i_id) : (- (__extension__ ({ const unsigned char *
__s2 = (const unsigned char *) (const char *) (leg_i->i_id
); int __result = (((const unsigned char *) (const char *) (i
->i_id))[0] - __s2[0]); if (__s2_len > 0 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
i->i_id))[1] - __s2[1]); if (__s2_len > 1 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
i->i_id))[2] - __s2[2]); if (__s2_len > 2 && __result
== 0) __result = (((const unsigned char *) (const char *) (i
->i_id))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp
(leg_i->i_id, i->i_id)))); })
!= 0)
5015 continue;
5016
5017 /* Do not match if the incoming To has tag, but the local does not */
5018 if (!local_tag && to_tag)
5019 continue;
5020
5021 /*
5022 * Do not match if incoming To has no tag and we have local tag
5023 * and the tag has been there from the beginning.
5024 */
5025 if (local_tag && !to_tag && !leg->leg_tagged)
5026 continue;
5027
5028 /* Do not match if incoming From has no tag but remote has a tag */
5029 if (remote_tag && !from_tag)
5030 continue;
5031
5032 /* Avoid matching with itself */
5033 if (!remote_tag != !from_tag && !local_tag != !to_tag)
5034 continue;
5035
5036 if (local_tag && to_tag && !su_casematch(local_tag, to_tag) && to_tag[0])
5037 continue;
5038 if (remote_tag && from_tag && !su_casematch(remote_tag, from_tag) && from_tag[0])
5039 continue;
5040
5041 if (leg_url && request_uri && url_cmp(leg_url, request_uri))
5042 continue;
5043 if (leg_method && method_name && !su_casematch(method_name, leg_method))
5044 continue;
5045
5046 /* Perfect match if both local and To have tag
5047 * or local does not have tag.
5048 */
5049 if ((!local_tag || to_tag))
5050 return leg;
5051
5052 if (loose_match == NULL((void*)0))
5053 loose_match = leg;
5054 }
5055
5056 return loose_match;
5057}
5058
5059/** Get leg by destination */
5060nta_leg_t *nta_leg_by_uri(nta_agent_t const *agent, url_string_t const *us)
5061{
5062 url_t *url;
5063 nta_leg_t *leg = NULL((void*)0);
5064
5065 if (!agent)
5066 return NULL((void*)0);
5067
5068 if (!us)
5069 return agent->sa_default_leg;
5070
5071 url = url_hdup(NULL((void*)0), us->us_url);
5072
5073 if (url) {
5074 agent_aliases(agent, url, NULL((void*)0));
5075 leg = dst_find(agent, url, NULL((void*)0));
5076 su_free(NULL((void*)0), url);
5077 }
5078
5079 return leg;
5080}
5081
5082/** Find a non-dialog leg corresponding to the request uri u0 */
5083static
5084nta_leg_t *dst_find(nta_agent_t const *sa,
5085 url_t const *u0,
5086 char const *method_name)
5087{
5088 hash_value_t hash, hash2;
5089 leg_htable_t const *lht = sa->sa_defaults;
5090 nta_leg_t **ll, *leg, *loose_match = NULL((void*)0);
5091 int again;
5092 url_t url[1];
5093
5094 *url = *u0;
5095 hash = hash_istring(url->url_scheme, ":", 0);
5096 hash = hash_istring(url->url_host, "", hash);
5097 hash2 = hash_istring("%", "@", hash);
5098 hash = hash_istring(url->url_user, "@", hash);
5099
5100 /* First round, search with user name */
5101 /* Second round, search without user name */
5102 do {
5103 for (ll = leg_htable_hash(lht, hash);
5104 (leg = *ll);
5105 ll = leg_htable_next(lht, ll)) {
5106 if (leg->leg_hash != hash)
5107 continue;
5108 if (url_cmp(url, leg->leg_url))
5109 continue;
5110 if (!method_name) {
5111 if (leg->leg_method)
5112 continue;
5113 return leg;
5114 }
5115 else if (leg->leg_method) {
5116 if (!su_casematch(method_name, leg->leg_method))
5117 continue;
5118 return leg;
5119 }
5120 loose_match = leg;
5121 }
5122 if (loose_match)
5123 return loose_match;
5124
5125 again = 0;
5126
5127 if (url->url_user && strcmp(url->url_user, "%")__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(url->url_user) && __builtin_constant_p ("%") &&
(__s1_len = __builtin_strlen (url->url_user), __s2_len = __builtin_strlen
("%"), (!((size_t)(const void *)((url->url_user) + 1) - (
size_t)(const void *)(url->url_user) == 1) || __s1_len >=
4) && (!((size_t)(const void *)(("%") + 1) - (size_t
)(const void *)("%") == 1) || __s2_len >= 4)) ? __builtin_strcmp
(url->url_user, "%") : (__builtin_constant_p (url->url_user
) && ((size_t)(const void *)((url->url_user) + 1) -
(size_t)(const void *)(url->url_user) == 1) && (__s1_len
= __builtin_strlen (url->url_user), __s1_len < 4) ? (__builtin_constant_p
("%") && ((size_t)(const void *)(("%") + 1) - (size_t
)(const void *)("%") == 1) ? __builtin_strcmp (url->url_user
, "%") : (__extension__ ({ const unsigned char *__s2 = (const
unsigned char *) (const char *) ("%"); int __result = (((const
unsigned char *) (const char *) (url->url_user))[0] - __s2
[0]); if (__s1_len > 0 && __result == 0) { __result
= (((const unsigned char *) (const char *) (url->url_user
))[1] - __s2[1]); if (__s1_len > 1 && __result == 0
) { __result = (((const unsigned char *) (const char *) (url->
url_user))[2] - __s2[2]); if (__s1_len > 2 && __result
== 0) __result = (((const unsigned char *) (const char *) (url
->url_user))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p
("%") && ((size_t)(const void *)(("%") + 1) - (size_t
)(const void *)("%") == 1) && (__s2_len = __builtin_strlen
("%"), __s2_len < 4) ? (__builtin_constant_p (url->url_user
) && ((size_t)(const void *)((url->url_user) + 1) -
(size_t)(const void *)(url->url_user) == 1) ? __builtin_strcmp
(url->url_user, "%") : (- (__extension__ ({ const unsigned
char *__s2 = (const unsigned char *) (const char *) (url->
url_user); int __result = (((const unsigned char *) (const char
*) ("%"))[0] - __s2[0]); if (__s2_len > 0 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
"%"))[1] - __s2[1]); if (__s2_len > 1 && __result ==
0) { __result = (((const unsigned char *) (const char *) ("%"
))[2] - __s2[2]); if (__s2_len > 2 && __result == 0
) __result = (((const unsigned char *) (const char *) ("%"))[
3] - __s2[3]); } } __result; })))) : __builtin_strcmp (url->
url_user, "%")))); })
) {
5128 url->url_user = "%";
5129 hash = hash2;
5130 again = 1;
5131 }
5132 } while (again);
5133
5134 return NULL((void*)0);
5135}
5136
5137/** Set leg route and target URL.
5138 *
5139 * Sets the leg route and contact using the @RecordRoute and @Contact
5140 * headers.
5141 *
5142 * @param reroute - allow rerouting
5143 * - if 1, follow @RFC3261 semantics
5144 * - if 2, response to initial transaction)
5145 */
5146static
5147int leg_route(nta_leg_t *leg,
5148 sip_record_route_t const *route,
5149 sip_record_route_t const *reverse,
5150 sip_contact_t const *contact,
5151 int reroute)
5152{
5153 su_home_t *home = leg->leg_home;
5154 sip_route_t *r, r0[1], *old;
5155 int route_is_set;
5156
5157 if (!leg)
5158 return -1;
5159
5160 if (route == NULL((void*)0) && reverse == NULL((void*)0) && contact == NULL((void*)0))
5161 return 0;
5162
5163 sip_route_init(r0);
5164
5165 route_is_set = reroute ? leg->leg_route_set : leg->leg_route != NULL((void*)0);
5166
5167 if (route_is_set && reroute <= 1) {
5168 r = leg->leg_route;
5169 }
5170 else if (route) {
5171 r = sip_route_fixdup(home, route); if (!r) return -1;
5172 }
5173 else if (reverse) {
5174 r = sip_route_reverse(home, reverse); if (!r) return -1;
5175 }
5176 else
5177 r = NULL((void*)0);
5178
5179#ifdef NTA_STRICT_ROUTING
5180 /*
5181 * Handle Contact according to the RFC2543bis04 sections 16.1, 16.2 and 16.4.
5182 */
5183 if (contact) {
5184 *r0->r_url = *contact->m_url;
5185
5186 if (!(m_r = sip_route_dup(leg->leg_home, r0)))
5187 return -1;
5188
5189 /* Append, but replace last entry if it was generated from contact */
5190 for (rr = &r; *rr; rr = &(*rr)->r_next)
5191 if (leg->leg_contact_set && (*rr)->r_next == NULL((void*)0))
5192 break;
5193 }
5194 else
5195 rr = NULL((void*)0);
5196
5197 if (rr) {
5198 if (*rr)
5199 su_free(leg->leg_home, *rr);
5200 *rr = m_r;
5201 }
5202 if (m_r != NULL((void*)0))
5203 leg->leg_contact_set = 1;
5204
5205#else
5206 if (r && r->r_url->url_params)
5207 leg->leg_loose_route = url_has_param(r->r_url, "lr");
5208
5209 if (contact) {
5210 sip_contact_t *target, m[1], *m0;
5211
5212 sip_contact_init(m);
5213 *m->m_url = *contact->m_url;
5214 m->m_url->url_headers = NULL((void*)0);
5215 target = sip_contact_dup(leg->leg_home, m);
5216
5217 if (target && target->m_url->url_params) {
5218 /* Remove ttl, method. @RFC3261 table 1, page 152 */
5219 char *p = (char *)target->m_url->url_params;
5220 p = url_strip_param_string(p, "method");
5221 p = url_strip_param_string(p, "ttl");
5222 target->m_url->url_params = p;
5223 }
5224
5225 m0 = leg->leg_target, leg->leg_target = target;
5226
5227 if (m0)
5228 su_free(leg->leg_home, m0);
5229 }
5230#endif
5231
5232 old = leg->leg_route;
5233 leg->leg_route = r;
5234
5235 if (old && old != r)
5236 msg_header_free(leg->leg_home, (msg_header_t *)old);
5237
5238 leg->leg_route_set = 1;
5239
5240 return 0;
5241}
5242
5243/** @internal Default leg callback. */
5244static int
5245leg_callback_default(nta_leg_magic_t *magic,
5246 nta_leg_t *leg,
5247 nta_incoming_t *irq,
5248 sip_t const *sip)
5249{
5250 nta_incoming_treply(irq,
5251 SIP_501_NOT_IMPLEMENTED501, sip_501_Not_implemented,
5252 TAG_END()(tag_type_t)0, (tag_value_t)0);
5253 return 501;
5254}
5255
5256/* ====================================================================== */
5257/* 7) Server-side (incoming) transactions */
5258
5259#define HTABLE_HASH_IRQ(irq)((irq)->irq_hash) ((irq)->irq_hash)
5260HTABLE_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, ((i != i0) ? (void) (0) : __assert_fail
("i != i0", "nta.c", 5261, __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; ((iht-> iht_used == used) ? (void
) (0) : __assert_fail ("iht-> iht_used == used", "nta.c", 5261
, __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
5261 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, ((i != i0) ? (void) (0) : __assert_fail
("i != i0", "nta.c", 5261, __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; ((iht-> iht_used == used) ? (void
) (0) : __assert_fail ("iht-> iht_used == used", "nta.c", 5261
, __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
;
5262
5263static void incoming_insert(nta_agent_t *agent,
5264 incoming_queue_t *queue,
5265 nta_incoming_t *irq);
5266
5267su_inlinestatic inline int incoming_is_queued(nta_incoming_t const *irq);
5268su_inlinestatic inline void incoming_queue(incoming_queue_t *queue, nta_incoming_t *);
5269su_inlinestatic inline void incoming_remove(nta_incoming_t *irq);
5270su_inlinestatic inline void incoming_set_timer(nta_incoming_t *, uint32_t interval);
5271su_inlinestatic inline void incoming_reset_timer(nta_incoming_t *);
5272su_inlinestatic inline size_t incoming_mass_destroy(nta_agent_t *, incoming_queue_t *);
5273
5274static int incoming_set_params(nta_incoming_t *irq, tagi_t const *tags);
5275su_inlinestatic inline
5276int incoming_set_compartment(nta_incoming_t *irq, tport_t *tport, msg_t *msg,
5277 int create_if_needed);
5278
5279su_inlinestatic inline nta_incoming_t
5280 *incoming_call_callback(nta_incoming_t *, msg_t *, sip_t *);
5281su_inlinestatic inline int incoming_final_failed(nta_incoming_t *irq, msg_t *);
5282static void incoming_retransmit_reply(nta_incoming_t *irq, tport_t *tport);
5283
5284/** Create a default server transaction.
5285 *
5286 * The default server transaction is used by a proxy to forward responses
5287 * statelessly.
5288 *
5289 * @param agent pointer to agent object
5290 *
5291 * @retval pointer to default server transaction object
5292 * @retval NULL if failed
5293 */
5294nta_incoming_t *nta_incoming_default(nta_agent_t *agent)
5295{
5296 msg_t *msg;
5297 su_home_t *home;
5298 nta_incoming_t *irq;
5299
5300 if (agent == NULL((void*)0))
5301 return su_seterrno(EFAULT14), NULL((void*)0);
5302 if (agent->sa_default_incoming)
5303 return su_seterrno(EEXIST17), NULL((void*)0);
5304
5305 msg = nta_msg_create(agent, 0);
5306 if (!msg)
5307 return NULL((void*)0);
5308
5309 irq = su_zalloc(home = msg_home(msg)((su_home_t*)(msg)), sizeof(*irq));
5310 if (!irq)
5311 return (void)msg_destroy(msg), NULL((void*)0);
5312
5313 irq->irq_home = home;
5314 irq->irq_request = NULL((void*)0);
5315 irq->irq_agent = agent;
5316 irq->irq_received = agent_now(agent);
5317 irq->irq_method = sip_method_invalid;
5318
5319 irq->irq_default = 1;
5320 agent->sa_default_incoming = irq;
5321
5322 return irq;
5323}
5324
5325/** Create a server transaction.
5326 *
5327 * Create a server transaction for a request message. This function is used
5328 * when an element processing requests statelessly wants to process a
5329 * particular request statefully.
5330 *
5331 * @param agent pointer to agent object
5332 * @param leg pointer to leg object (either @a agent or @a leg may be NULL)
5333 * @param msg pointer to message object
5334 * @param sip pointer to SIP structure (may be NULL)
5335 * @param tag,value,... optional tagged parameters
5336 *
5337 * @note
5338 * The ownership of @a msg is taken over by the function even if the
5339 * function fails.
5340 *
5341 * @TAGS
5342 * @TAG NTATAG_TPORT() specifies the transport used to receive the request
5343 * and also default transport for sending the response.
5344 *
5345 * @retval nta_incoming_t pointer to the newly created server transaction
5346 * @retval NULL if failed
5347 */
5348nta_incoming_t *nta_incoming_create(nta_agent_t *agent,
5349 nta_leg_t *leg,
5350 msg_t *msg,
5351 sip_t *sip,
5352 tag_type_t tag, tag_value_t value, ...)
5353{
5354 char const *to_tag = NULL((void*)0);
5355 tport_t *tport = NULL((void*)0);
5356 ta_list ta;
5357 nta_incoming_t *irq;
5358
5359 if (msg == NULL((void*)0))
5360 return NULL((void*)0);
5361
5362 if (agent == NULL((void*)0) && leg != NULL((void*)0))
5363 agent = leg->leg_agent;
5364
5365 if (sip == NULL((void*)0))
5366 sip = sip_object(msg);
5367
5368 if (agent == NULL((void*)0) || sip == NULL((void*)0) || !sip->sip_request || !sip->sip_cseq)
5369 return msg_destroy(msg), NULL((void*)0);
5370
5371 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)
;
5372
5373 tl_gets(ta_args(ta)(ta).tl,
5374 NTATAG_TPORT_REF(tport)ntatag_tport_ref, tag_ptr_vr(&(tport), (tport)),
5375 TAG_END()(tag_type_t)0, (tag_value_t)0);
5376 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))
;
5377
5378 if (leg && leg->leg_local)
5379 to_tag = leg->leg_local->a_tag;
5380
5381 if (tport == NULL((void*)0))
5382 tport = tport_delivered_by(agent->sa_tports, msg);
5383
5384 irq = incoming_create(agent, msg, sip, tport, to_tag);
5385
5386 if (!irq)
5387 msg_destroy(msg);
5388
5389 return irq;
5390}
5391
5392/** @internal Create a new incoming transaction object. */
5393static
5394nta_incoming_t *incoming_create(nta_agent_t *agent,
5395 msg_t *msg,
5396 sip_t *sip,
5397 tport_t *tport,
5398 char const *tag)
5399{
5400 nta_incoming_t *irq = su_zalloc(msg_home(msg)((su_home_t*)(msg)), sizeof(*irq));
5401
5402 agent->sa_stats->as_server_tr++;
5403
5404 if (irq) {
5405 su_home_t *home;
5406 incoming_queue_t *queue;
5407 sip_method_t method = sip->sip_request->rq_method;
5408
5409 irq->irq_request = msg;
5410 irq->irq_home = home = msg_home(msg_ref_create(msg))((su_home_t*)(msg_ref_create(msg)));
5411 irq->irq_agent = agent;
5412
5413 irq->irq_received = agent_now(agent); /* Timestamp originally from tport */
5414
5415 irq->irq_method = method;
5416 irq->irq_rq = sip_request_copy(home, sip->sip_request);
5417 irq->irq_from = sip_from_copy(home, sip->sip_from);
5418 irq->irq_to = sip_to_copy(home, sip->sip_to);
5419 irq->irq_call_id = sip_call_id_copy(home, sip->sip_call_id);
5420 irq->irq_cseq = sip_cseq_copy(home, sip->sip_cseq);
5421 irq->irq_via = sip_via_copy(home, sip->sip_via);
5422 switch (method) {
5423 case sip_method_ack:
5424 case sip_method_cancel:
5425 case sip_method_bye:
5426 case sip_method_options:
5427 case sip_method_register: /* Handling Path is up to application */
5428 case sip_method_info:
5429 case sip_method_prack:
5430 case sip_method_publish:
5431 break;
5432 default:
5433 irq->irq_record_route =
5434 sip_record_route_copy(home, sip->sip_record_route);
5435 }
5436 irq->irq_branch = sip->sip_via->v_branch;
5437 irq->irq_reliable_tp = tport_is_reliable(tport);
5438 irq->irq_extra_100 = 0; /* Sending extra 100 trying false by default */
5439
5440 if (sip->sip_timestamp)
5441 irq->irq_timestamp = sip_timestamp_copy(home, sip->sip_timestamp);
5442
5443 /* Tag transaction */
5444 if (tag)
5445 sip_to_tag(home, irq->irq_to, tag);
5446 irq->irq_tag = irq->irq_to->a_tag;
5447
5448 if (method != sip_method_ack) {
5449 int *use_rport = NULL((void*)0);
5450 int retry_without_rport = 0;
5451
5452 if (agent->sa_server_rport)
5453 use_rport = &retry_without_rport, retry_without_rport = 1;
5454
5455 if (nta_tpn_by_via(irq->irq_tpn, irq->irq_via, use_rport) < 0)
5456 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__
, 5456, "%s: bad via\n", __func__)) : (void)0)
;
5457 }
5458
5459 incoming_set_compartment(irq, tport, msg, 0);
5460
5461 if (method == sip_method_invite) {
5462 irq->irq_must_100rel =
5463 sip->sip_require && sip_has_feature(sip->sip_require, "100rel");
5464
5465 if (irq->irq_must_100rel ||
5466 (sip->sip_supported &&
5467 sip_has_feature(sip->sip_supported, "100rel"))) {
5468 irq->irq_rseq = su_randint(1, 0x7fffffff); /* Initialize rseq */
5469 }
5470
5471 queue = agent->sa_in.proceeding;
5472
5473 if (irq->irq_reliable_tp)
5474 incoming_set_timer(irq, agent->sa_t2 / 2); /* N1 = T2 / 2 */
5475 else
5476 incoming_set_timer(irq, 200); /* N1 = 200 ms */
5477
5478 irq->irq_tport = tport_ref(tport);
5479 }
5480 else if (method == sip_method_ack) {
5481 irq->irq_status = 700; /* Never send reply to ACK */
5482 irq->irq_completed = 1;
5483 if (irq->irq_reliable_tp || !agent->sa_is_a_uas) {
5484 queue = agent->sa_in.terminated;
5485 irq->irq_terminated = 1;
5486 }
5487 else {
5488 queue = agent->sa_in.completed; /* Timer J */
5489 }
5490 }
5491 else {
5492 queue = agent->sa_in.proceeding;
5493 /* RFC 4320 (nit-actions-03):
5494
5495 Blacklisting on a late response occurs even over reliable transports.
5496 Thus, if an element processing a request received over a reliable
5497 transport is delaying its final response at all, sending a 100 Trying
5498 well in advance of the timeout will prevent blacklisting. Sending a
5499 100 Trying immediately will not harm the transaction as it would over
5500 UDP, but a policy of always sending such a message results in
5501 unneccessary traffic. A policy of sending a 100 Trying after the
5502 period of time in which Timer E reaches T2 had this been a UDP hop is
5503 one reasonable compromise.
5504
5505 */
5506 if (agent->sa_extra_100 && irq->irq_reliable_tp)
5507 incoming_set_timer(irq, agent->sa_t2 / 2); /* T2 / 2 */
5508
5509 irq->irq_tport = tport_ref(tport);
5510 }
5511
5512 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))
;
5513
5514 incoming_insert(agent, queue, irq);
5515 }
5516
5517 return irq;
5518}
5519
5520/** @internal
5521 * Insert incoming transaction to hash table.
5522 */
5523static void
5524incoming_insert(nta_agent_t *agent,
5525 incoming_queue_t *queue,
5526 nta_incoming_t *irq)
5527{
5528 incoming_queue(queue, irq);
5529
5530 if (incoming_htable_is_full(agent->sa_incoming))
5531 incoming_htable_resize(agent->sa_home, agent->sa_incoming, 0);
5532
5533 if (irq->irq_method != sip_method_ack)
5534 incoming_htable_insert(agent->sa_incoming, irq);
5535 else
5536 /* ACK is appended - final response with tags match with it,
5537 * not with the original INVITE transaction */
5538 /* XXX - what about rfc2543 servers, which do not add tag? */
5539 incoming_htable_append(agent->sa_incoming, irq);
5540}
5541
5542/** Call callback for incoming request */
5543static
5544int incoming_callback(nta_leg_t *leg, nta_incoming_t *irq, sip_t *sip)
5545{
5546 sip_method_t method = sip->sip_request->rq_method;
5547 char const *method_name = sip->sip_request->rq_method_name;
5548
5549 /* RFC-3261 section 12.2.2 (page 76) */
5550 if (leg->leg_dialog &&
5551 irq->irq_agent->sa_is_a_uas &&
5552 method != sip_method_ack) {
5553 uint32_t seq = sip->sip_cseq->cs_seq;
5554
5555 if (leg->leg_rseq > sip->sip_cseq->cs_seq) {
5556 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__
, 5557, "nta_leg(%p): out-of-order %s (%u < %u)\n", (void *
)leg, method_name, seq, leg->leg_rseq)) : (void)0)
5557 (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__
, 5557, "nta_leg(%p): out-of-order %s (%u < %u)\n", (void *
)leg, method_name, seq, leg->leg_rseq)) : (void)0)
;
5558 return 500;
5559 }
5560
5561 leg->leg_rseq = seq;
5562 }
5563
5564 return leg->leg_callback(leg->leg_magic, leg, irq, sip);
5565}
5566
5567/**
5568 * Destroy an incoming transaction.
5569 *
5570 * This function does not actually free transaction object, but marks it as
5571 * disposable. The object is freed after a timeout.
5572 *
5573 * @param irq incoming request object to be destroyed
5574 */
5575void nta_incoming_destroy(nta_incoming_t *irq)
5576{
5577 if (irq) {
5578 irq->irq_callback = NULL((void*)0);
5579 irq->irq_magic = NULL((void*)0);
5580 irq->irq_destroyed = 1;
5581 if (!irq->irq_in_callback) {
5582 if (irq->irq_terminated || irq->irq_default)
5583 incoming_free(irq);
5584 else if (irq->irq_status < 200)
5585 nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error, TAG_END()(tag_type_t)0, (tag_value_t)0);
5586 }
5587 }
5588}
5589
5590/** @internal
5591 * Initialize a queue for incoming transactions.
5592 */
5593static void
5594incoming_queue_init(incoming_queue_t *queue, unsigned timeout)
5595{
5596 memset(queue, 0, sizeof *queue);
5597 queue->q_tail = &queue->q_head;
5598 queue->q_timeout = timeout;
5599}
5600
5601/** Change the timeout value of a queue */
5602static void
5603incoming_queue_adjust(nta_agent_t *sa,
5604 incoming_queue_t *queue,
5605 uint32_t timeout)
5606{
5607 nta_incoming_t *irq;
5608 uint32_t latest;
5609
5610 if (timeout >= queue->q_timeout || !queue->q_head) {
5611 queue->q_timeout = timeout;
5612 return;
5613 }
5614
5615 latest = set_timeout(sa, queue->q_timeout = timeout);
5616
5617 for (irq = queue->q_head; irq; irq = irq->irq_next) {
5618 if ((int32_t)(irq->irq_timeout - latest) > 0)
5619 irq->irq_timeout = latest;
5620 }
5621}
5622
5623/** @internal
5624 * Test if an incoming transaction is in a queue.
5625 */
5626su_inlinestatic inline
5627int incoming_is_queued(nta_incoming_t const *irq)
5628{
5629 return irq && irq->irq_queue;
5630}
5631
5632/** @internal
5633 * Insert an incoming transaction into a queue.
5634 *
5635 * Insert a server transaction into a queue, and sets the corresponding
5636 * timeout at the same time.
5637 */
5638su_inlinestatic inline
5639void incoming_queue(incoming_queue_t *queue,
5640 nta_incoming_t *irq)
5641{
5642 if (irq->irq_queue == queue) {
5643 assert(queue->q_timeout == 0)((queue->q_timeout == 0) ? (void) (0) : __assert_fail ("queue->q_timeout == 0"
, "nta.c", 5643, __PRETTY_FUNCTION__))
;
5644 return;
5645 }
5646
5647 if (incoming_is_queued(irq))
5648 incoming_remove(irq);
5649
5650 assert(*queue->q_tail == NULL)((*queue->q_tail == ((void*)0)) ? (void) (0) : __assert_fail
("*queue->q_tail == ((void*)0)", "nta.c", 5650, __PRETTY_FUNCTION__
))
;
5651
5652 irq->irq_timeout = set_timeout(irq->irq_agent, queue->q_timeout);
5653
5654 irq->irq_queue = queue;
5655 irq->irq_prev = queue->q_tail;
5656 *queue->q_tail = irq;
5657 queue->q_tail = &irq->irq_next;
5658 queue->q_length++;
5659}
5660
5661/** @internal
5662 * Remove an incoming transaction from a queue.
5663 */
5664su_inlinestatic inline
5665void incoming_remove(nta_incoming_t *irq)
5666{
5667 assert(incoming_is_queued(irq))((incoming_is_queued(irq)) ? (void) (0) : __assert_fail ("incoming_is_queued(irq)"
, "nta.c", 5667, __PRETTY_FUNCTION__))
;
5668 assert(irq->irq_queue->q_length > 0)((irq->irq_queue->q_length > 0) ? (void) (0) : __assert_fail
("irq->irq_queue->q_length > 0", "nta.c", 5668, __PRETTY_FUNCTION__
))
;
5669
5670 if ((*irq->irq_prev = irq->irq_next))
5671 irq->irq_next->irq_prev = irq->irq_prev;
5672 else
5673 irq->irq_queue->q_tail = irq->irq_prev, assert(!*irq->irq_queue->q_tail)((!*irq->irq_queue->q_tail) ? (void) (0) : __assert_fail
("!*irq->irq_queue->q_tail", "nta.c", 5673, __PRETTY_FUNCTION__
))
;
5674
5675 irq->irq_queue->q_length--;
5676 irq->irq_next = NULL((void*)0);
5677 irq->irq_prev = NULL((void*)0);
5678 irq->irq_queue = NULL((void*)0);
5679 irq->irq_timeout = 0;
5680}
5681
5682su_inlinestatic inline
5683void incoming_set_timer(nta_incoming_t *irq, uint32_t interval)
5684{
5685 nta_incoming_t **rq;
5686
5687 assert(irq)((irq) ? (void) (0) : __assert_fail ("irq", "nta.c", 5687, __PRETTY_FUNCTION__
))
;
5688
5689 if (interval == 0) {
5690 incoming_reset_timer(irq);
5691 return;
5692 }
5693
5694 if (irq->irq_rprev) {
5695 if ((*irq->irq_rprev = irq->irq_rnext))
5696 irq->irq_rnext->irq_rprev = irq->irq_rprev;
5697 if (irq->irq_agent->sa_in.re_t1 == &irq->irq_rnext)
5698 irq->irq_agent->sa_in.re_t1 = irq->irq_rprev;
5699 } else {
5700 irq->irq_agent->sa_in.re_length++;
5701 }
5702
5703 irq->irq_retry = set_timeout(irq->irq_agent, irq->irq_interval = interval);
5704
5705 rq = irq->irq_agent->sa_in.re_t1;
5706
5707 if (!(*rq) || (int32_t)((*rq)->irq_retry - irq->irq_retry) > 0)
5708 rq = &irq->irq_agent->sa_in.re_list;
5709
5710 while (*rq && (int32_t)((*rq)->irq_retry - irq->irq_retry) <= 0)
5711 rq = &(*rq)->irq_rnext;
5712
5713 if ((irq->irq_rnext = *rq))
5714 irq->irq_rnext->irq_rprev = &irq->irq_rnext;
5715 *rq = irq;
5716 irq->irq_rprev = rq;
5717
5718 /* Optimization: keep special place for transactions with T1 interval */
5719 if (interval == irq->irq_agent->sa_t1)
5720 irq->irq_agent->sa_in.re_t1 = rq;
5721}
5722
5723su_inlinestatic inline
5724void incoming_reset_timer(nta_incoming_t *irq)
5725{
5726 if (irq->irq_rprev) {
5727 if ((*irq->irq_rprev = irq->irq_rnext))
5728 irq->irq_rnext->irq_rprev = irq->irq_rprev;
5729 if (irq->irq_agent->sa_in.re_t1 == &irq->irq_rnext)
5730 irq->irq_agent->sa_in.re_t1 = irq->irq_rprev;
5731 irq->irq_agent->sa_in.re_length--;
5732 }
5733
5734 irq->irq_interval = 0, irq->irq_retry = 0;
5735 irq->irq_rnext = NULL((void*)0), irq->irq_rprev = NULL((void*)0);
5736}
5737
5738/** @internal
5739 * Free an incoming transaction.
5740 */
5741static
5742void incoming_free(nta_incoming_t *irq)
5743{
5744 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__
, 5744, "nta: incoming_free(%p)\n", (void *)irq)) : (void)0)
;
5745
5746 incoming_cut_off(irq);
5747 incoming_reclaim(irq);
5748}
5749
5750/** Remove references to the irq */
5751su_inlinestatic inline
5752void incoming_cut_off(nta_incoming_t *irq)
5753{
5754 nta_agent_t *agent = irq->irq_agent;
5755
5756 assert(agent)((agent) ? (void) (0) : __assert_fail ("agent", "nta.c", 5756
, __PRETTY_FUNCTION__))
;
5757
5758 if (irq->irq_default) {
5759 if (irq == agent->sa_default_incoming)
5760 agent->sa_default_incoming = NULL((void*)0);
5761 irq->irq_default = 0;
5762 return;
5763 }
5764
5765 if (incoming_is_queued(irq))
5766 incoming_remove(irq);
5767
5768 incoming_reset_timer(irq);
5769
5770 incoming_htable_remove(agent->sa_incoming, irq);
5771
5772 if (irq->irq_cc)
5773 nta_compartment_decref(&irq->irq_cc);
5774
5775 if (irq->irq_tport)
5776 tport_decref(&irq->irq_tport);
5777}
5778
5779/** Reclaim the memory used by irq */
5780su_inlinestatic inline
5781void incoming_reclaim(nta_incoming_t *irq)
5782{
5783 su_home_t *home = irq->irq_home;
5784 nta_reliable_t *rel, *rel_next;
5785
5786 if (irq->irq_request)
5787 msg_destroy(irq->irq_request), irq->irq_request = NULL((void*)0);
5788 if (irq->irq_request2)
5789 msg_destroy(irq->irq_request2), irq->irq_request2 = NULL((void*)0);
5790 if (irq->irq_response)
5791 msg_destroy(irq->irq_response), irq->irq_response = NULL((void*)0);
5792
5793 for (rel = irq->irq_reliable; rel; rel = rel_next) {
5794 rel_next = rel->rel_next;
5795 if (rel->rel_unsent)
5796 msg_destroy(rel->rel_unsent);
5797 su_free(irq->irq_agent->sa_home, rel);
5798 }
5799
5800 irq->irq_home = NULL((void*)0);
5801
5802 su_free(home, irq);
5803
5804 msg_destroy((msg_t *)home);
5805}
5806
5807/** Queue request to be freed */
5808su_inlinestatic inline
5809void incoming_free_queue(incoming_queue_t *q, nta_incoming_t *irq)
5810{
5811 incoming_cut_off(irq);
5812 incoming_queue(q, irq);
5813}
5814
5815/** Reclaim memory used by queue of requests */
5816static
5817void incoming_reclaim_queued(su_root_magic_t *rm,
5818 su_msg_r msg,
5819 union sm_arg_u *u)
5820{
5821 incoming_queue_t *q = u->a_incoming_queue;
5822 nta_incoming_t *irq, *irq_next;
5823
5824 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__
, 5825, "incoming_reclaim_all(%p, %p, %p)\n", (void *)rm, (void
*)msg, (void *)u)) : (void)0)
5825 (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__
, 5825, "incoming_reclaim_all(%p, %p, %p)\n", (void *)rm, (void
*)msg, (void *)u)) : (void)0)
;
5826
5827 for (irq = q->q_head; irq; irq = irq_next) {
5828 irq_next = irq->irq_next;
5829 incoming_reclaim(irq);
5830 }
5831}
5832
5833/**Bind a callback and context to an incoming transaction object
5834 *
5835 * Set the callback function and context pointer attached to an incoming
5836 * request object. The callback function will be invoked if the incoming
5837 * request is cancelled, or if the final response to an incoming @b INVITE
5838 * request has been acknowledged.
5839 *
5840 * If the callback is NULL, or no callback has been bound, NTA invokes the
5841 * request callback of the call leg.
5842 *
5843 * @param irq incoming transaction
5844 * @param callback callback function
5845 * @param magic application context
5846 */
5847void nta_incoming_bind(nta_incoming_t *irq,
5848 nta_ack_cancel_f *callback,
5849 nta_incoming_magic_t *magic)
5850{
5851 if (irq) {
5852 irq->irq_callback = callback;
5853 irq->irq_magic = magic;
5854 }
5855}
5856
5857/** Add a @To tag to incoming request if needed.
5858 *
5859 * If @a tag is NULL, a new tag is generated.
5860 */
5861char const *nta_incoming_tag(nta_incoming_t *irq, char const *tag)
5862{
5863 if (!irq)
5864 return su_seterrno(EFAULT14), NULL((void*)0);
5865
5866 if (irq->irq_default)
5867 return su_seterrno(EINVAL22), NULL((void*)0);
5868
5869 if (tag && strchr(tag, '=')(__extension__ (__builtin_constant_p ('=') && !__builtin_constant_p
(tag) && ('=') == '\0' ? (char *) __rawmemchr (tag, '='
) : __builtin_strchr (tag, '=')))
)
5870 tag = strchr(tag, '=')(__extension__ (__builtin_constant_p ('=') && !__builtin_constant_p
(tag) && ('=') == '\0' ? (char *) __rawmemchr (tag, '='
) : __builtin_strchr (tag, '=')))
+ 1;
5871
5872 if (tag && irq->irq_tag && !su_casematch(tag, irq->irq_tag))
5873 return NULL((void*)0);
5874
5875 if (!irq->irq_tag) {
5876 if (tag)
5877 tag = su_strdup(irq->irq_home, tag);
5878 else
5879 tag = nta_agent_newtag(irq->irq_home, NULL((void*)0), irq->irq_agent);
5880
5881 if (!tag)
5882 return tag;
5883
5884 irq->irq_tag = tag;
5885 irq->irq_tag_set = 1;
5886 }
5887
5888 return irq->irq_tag;
5889}
5890
5891
5892/**Get request message.
5893 *
5894 * Retrieve the incoming request message of the incoming transaction. Note
5895 * that the message is not copied, but a new reference to it is created.
5896 *
5897 * @param irq incoming transaction handle
5898 *
5899 * @retval
5900 * A pointer to request message is returned.
5901 */
5902msg_t *nta_incoming_getrequest(nta_incoming_t *irq)
5903{
5904 msg_t *msg = NULL((void*)0);
5905
5906 if (irq && !irq->irq_default)
5907 msg = msg_ref_create(irq->irq_request);
5908
5909 return msg;
5910}
5911
5912/**Get ACK or CANCEL message.
5913 *
5914 * Retrieve the incoming ACK or CANCEL request message of the incoming
5915 * transaction. Note that the ACK or CANCEL message is not copied, but a new
5916 * reference to it is created.
5917 *
5918 * @param irq incoming transaction handle
5919 *
5920 * @retval A pointer to request message is returned, or NULL if there is no
5921 * CANCEL or ACK received.
5922 */
5923msg_t *nta_incoming_getrequest_ackcancel(nta_incoming_t *irq)
5924{
5925 msg_t *msg = NULL((void*)0);
5926
5927 if (irq && irq->irq_request2)
5928 msg = msg_ref_create(irq->irq_request2);
5929
5930 return msg;
5931}
5932
5933/**Get response message.
5934 *
5935 * Retrieve the response message latest sent by the server transaction. Note
5936 * that the message is not copied, but a new reference to it is created. Use
5937 * msg_dup() or msg_copy() to make a copy of it.
5938 *
5939 * @param irq incoming transaction handle
5940 *
5941 * @retval
5942 * A pointer to a response message is returned.
5943 */
5944msg_t *nta_incoming_getresponse(nta_incoming_t *irq)
5945{
5946 msg_t *msg = NULL((void*)0);
5947
5948 if (irq && irq->irq_response)
5949 msg = msg_ref_create(irq->irq_response);
5950
5951 return msg;
5952}
5953
5954/** Get method of a server transaction. */
5955sip_method_t nta_incoming_method(nta_incoming_t const *irq)
5956{
5957 return irq ? irq->irq_method : sip_method_invalid;
5958}
5959
5960/** Get method name of a server transaction. */
5961char const *nta_incoming_method_name(nta_incoming_t const *irq)
5962{
5963 if (irq == NULL((void*)0))
5964 return NULL((void*)0);
5965 else if (irq->irq_rq)
5966 return irq->irq_rq->rq_method_name;
5967 else
5968 return "*";
5969}
5970
5971/** Get Request-URI of a server transaction */
5972url_t const *nta_incoming_url(nta_incoming_t const *irq)
5973{
5974 return irq && irq->irq_rq ? irq->irq_rq->rq_url : NULL((void*)0);
5975}
5976
5977/** Get sequence number of a server transaction.
5978 */
5979uint32_t nta_incoming_cseq(nta_incoming_t const *irq)
5980{
5981 return irq && irq->irq_cseq ? irq->irq_cseq->cs_seq : 0;
5982}
5983
5984/** Get local tag for incoming request */
5985char const *nta_incoming_gettag(nta_incoming_t const *irq)
5986{
5987 return irq ? irq->irq_tag : 0;
5988}
5989
5990/**
5991 * Get status code of a server transaction.
5992 */
5993int nta_incoming_status(nta_incoming_t const *irq)
5994{
5995 return irq ? irq->irq_status : 400;
5996}
5997
5998/** Get application context for a server transaction.
5999 *
6000 * @param irq server transaction
6001 * @param callback callback pointer
6002 *
6003 * Return the application context bound to the server transaction. If the @a
6004 * callback function pointer is given, return application context only if
6005 * the callback matches with the callback bound to the server transaction.
6006 *
6007 */
6008nta_incoming_magic_t *nta_incoming_magic(nta_incoming_t *irq,
6009 nta_ack_cancel_f *callback)
6010{
6011 return irq && (callback == NULL((void*)0) || irq->irq_callback == callback)
6012 ? irq->irq_magic : NULL((void*)0);
6013}
6014
6015/** When received.
6016 *
6017 * Return timestamp from the reception of the initial request.
6018 *
6019 * @NEW_1_12_7.
6020 */
6021sip_time_t nta_incoming_received(nta_incoming_t *irq,
6022 su_nanotime_t *return_nano)
6023{
6024 su_time_t tv = { 0, 0 };
6025
6026 if (irq)
6027 tv = irq->irq_received;
6028
6029 if (return_nano)
6030 *return_nano = (su_nanotime_t)tv.tv_sec * 1000000000 + tv.tv_usec * 1000;
6031
6032 return tv.tv_sec;
6033}
6034
6035/** Find incoming transaction. */
6036nta_incoming_t *nta_incoming_find(nta_agent_t const *agent,
6037 sip_t const *sip,
6038 sip_via_t const *v)
6039{
6040 if (agent && sip && v)
6041 return incoming_find(agent, sip, v, NULL((void*)0), NULL((void*)0), NULL((void*)0));
6042 else
6043 return NULL((void*)0);
6044}
6045
6046/** Find a matching server transaction object.
6047 *
6048 * Check also for requests to merge, to ACK, or to CANCEL.
6049 */
6050static nta_incoming_t *incoming_find(nta_agent_t const *agent,
6051 sip_t const *sip,
6052 sip_via_t const *v,
6053 nta_incoming_t **return_merge,
6054 nta_incoming_t **return_ack,
6055 nta_incoming_t **return_cancel)
6056{
6057 sip_cseq_t const *cseq = sip->sip_cseq;
6058 sip_call_id_t const *i = sip->sip_call_id;
6059 sip_to_t const *to = sip->sip_to;
6060 sip_from_t const *from = sip->sip_from;
6061 sip_request_t *rq = sip->sip_request;
6062 incoming_htable_t const *iht = agent->sa_incoming;
6063 hash_value_t hash = NTA_HASH(i, cseq->cs_seq)((i)->i_hash + 26839U * (uint32_t)(cseq->cs_seq));
6064 char const *magic_branch;
6065
6066 nta_incoming_t **ii, *irq;
6067
6068 int is_uas_ack = return_ack && agent->sa_is_a_uas;
6069
6070 if (v->v_branch && su_casenmatch(v->v_branch, "z9hG4bK", 7))
6071 magic_branch = v->v_branch + 7;
6072 else
6073 magic_branch = NULL((void*)0);
6074
6075 for (ii = incoming_htable_hash(iht, hash);
6076 (irq = *ii);
6077 ii = incoming_htable_next(iht, ii)) {
6078 if (hash != irq->irq_hash ||
6079 irq->irq_call_id->i_hash != i->i_hash ||
6080 strcmp(irq->irq_call_id->i_id, i->i_id)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(irq->irq_call_id->i_id) && __builtin_constant_p
(i->i_id) && (__s1_len = __builtin_strlen (irq->
irq_call_id->i_id), __s2_len = __builtin_strlen (i->i_id
), (!((size_t)(const void *)((irq->irq_call_id->i_id) +
1) - (size_t)(const void *)(irq->irq_call_id->i_id) ==
1) || __s1_len >= 4) && (!((size_t)(const void *)
((i->i_id) + 1) - (size_t)(const void *)(i->i_id) == 1)
|| __s2_len >= 4)) ? __builtin_strcmp (irq->irq_call_id
->i_id, i->i_id) : (__builtin_constant_p (irq->irq_call_id
->i_id) && ((size_t)(const void *)((irq->irq_call_id
->i_id) + 1) - (size_t)(const void *)(irq->irq_call_id->
i_id) == 1) && (__s1_len = __builtin_strlen (irq->
irq_call_id->i_id), __s1_len < 4) ? (__builtin_constant_p
(i->i_id) && ((size_t)(const void *)((i->i_id)
+ 1) - (size_t)(const void *)(i->i_id) == 1) ? __builtin_strcmp
(irq->irq_call_id->i_id, i->i_id) : (__extension__ (
{ const unsigned char *__s2 = (const unsigned char *) (const char
*) (i->i_id); int __result = (((const unsigned char *) (const
char *) (irq->irq_call_id->i_id))[0] - __s2[0]); if (__s1_len
> 0 && __result == 0) { __result = (((const unsigned
char *) (const char *) (irq->irq_call_id->i_id))[1] - __s2
[1]); if (__s1_len > 1 && __result == 0) { __result
= (((const unsigned char *) (const char *) (irq->irq_call_id
->i_id))[2] - __s2[2]); if (__s1_len > 2 && __result
== 0) __result = (((const unsigned char *) (const char *) (irq
->irq_call_id->i_id))[3] - __s2[3]); } } __result; })))
: (__builtin_constant_p (i->i_id) && ((size_t)(const
void *)((i->i_id) + 1) - (size_t)(const void *)(i->i_id
) == 1) && (__s2_len = __builtin_strlen (i->i_id),
__s2_len < 4) ? (__builtin_constant_p (irq->irq_call_id
->i_id) && ((size_t)(const void *)((irq->irq_call_id
->i_id) + 1) - (size_t)(const void *)(irq->irq_call_id->
i_id) == 1) ? __builtin_strcmp (irq->irq_call_id->i_id,
i->i_id) : (- (__extension__ ({ const unsigned char *__s2
= (const unsigned char *) (const char *) (irq->irq_call_id
->i_id); int __result = (((const unsigned char *) (const char
*) (i->i_id))[0] - __s2[0]); if (__s2_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (i->i_id))[1] - __s2[1]); if (__s2_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (i->i_id))[2] - __s2[2]); if (__s2_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) (i->i_id))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp
(irq->irq_call_id->i_id, i->i_id)))); })
)
6081 continue;
6082 if (irq->irq_cseq->cs_seq != cseq->cs_seq)
6083 continue;
6084 if (su_strcasecmp(irq->irq_from->a_tag, from->a_tag))
6085 continue;
6086
6087 if (is_uas_ack &&
6088 irq->irq_method == sip_method_invite &&
6089 200 <= irq->irq_status && irq->irq_status < 300 &&
6090 su_casematch(irq->irq_tag, to->a_tag)) {
6091 *return_ack = irq;
6092 return NULL((void*)0);
6093 }
6094
6095 if (magic_branch) {
6096 /* RFC3261 17.2.3:
6097 *
6098 * The request matches a transaction if branch and sent-by in topmost
6099 * the method of the request matches the one that created the
6100 * transaction, except for ACK, where the method of the request
6101 * that created the transaction is INVITE.
6102 */
6103 if (irq->irq_via->v_branch &&
6104 su_casematch(irq->irq_via->v_branch + 7, magic_branch) &&
6105 su_casematch(irq->irq_via->v_host, v->v_host) &&
6106 su_strmatch(irq->irq_via->v_port, v->v_port)) {
6107 if (irq->irq_method == cseq->cs_method &&
6108 strcmp(irq->irq_cseq->cs_method_name,__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(irq->irq_cseq->cs_method_name) && __builtin_constant_p
(cseq->cs_method_name) && (__s1_len = __builtin_strlen
(irq->irq_cseq->cs_method_name), __s2_len = __builtin_strlen
(cseq->cs_method_name), (!((size_t)(const void *)((irq->
irq_cseq->cs_method_name) + 1) - (size_t)(const void *)(irq
->irq_cseq->cs_method_name) == 1) || __s1_len >= 4) &&
(!((size_t)(const void *)((cseq->cs_method_name) + 1) - (
size_t)(const void *)(cseq->cs_method_name) == 1) || __s2_len
>= 4)) ? __builtin_strcmp (irq->irq_cseq->cs_method_name
, cseq->cs_method_name) : (__builtin_constant_p (irq->irq_cseq
->cs_method_name) && ((size_t)(const void *)((irq->
irq_cseq->cs_method_name) + 1) - (size_t)(const void *)(irq
->irq_cseq->cs_method_name) == 1) && (__s1_len =
__builtin_strlen (irq->irq_cseq->cs_method_name), __s1_len
< 4) ? (__builtin_constant_p (cseq->cs_method_name) &&
((size_t)(const void *)((cseq->cs_method_name) + 1) - (size_t
)(const void *)(cseq->cs_method_name) == 1) ? __builtin_strcmp
(irq->irq_cseq->cs_method_name, cseq->cs_method_name
) : (__extension__ ({ const unsigned char *__s2 = (const unsigned
char *) (const char *) (cseq->cs_method_name); int __result
= (((const unsigned char *) (const char *) (irq->irq_cseq
->cs_method_name))[0] - __s2[0]); if (__s1_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (irq->irq_cseq->cs_method_name))[1] - __s2[1])
; if (__s1_len > 1 && __result == 0) { __result = (
((const unsigned char *) (const char *) (irq->irq_cseq->
cs_method_name))[2] - __s2[2]); if (__s1_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) (irq->irq_cseq->cs_method_name))[3] - __s2[3]); } }
__result; }))) : (__builtin_constant_p (cseq->cs_method_name
) && ((size_t)(const void *)((cseq->cs_method_name
) + 1) - (size_t)(const void *)(cseq->cs_method_name) == 1
) && (__s2_len = __builtin_strlen (cseq->cs_method_name
), __s2_len < 4) ? (__builtin_constant_p (irq->irq_cseq
->cs_method_name) && ((size_t)(const void *)((irq->
irq_cseq->cs_method_name) + 1) - (size_t)(const void *)(irq
->irq_cseq->cs_method_name) == 1) ? __builtin_strcmp (irq
->irq_cseq->cs_method_name, cseq->cs_method_name) : (
- (__extension__ ({ const unsigned char *__s2 = (const unsigned
char *) (const char *) (irq->irq_cseq->cs_method_name)
; int __result = (((const unsigned char *) (const char *) (cseq
->cs_method_name))[0] - __s2[0]); if (__s2_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (cseq->cs_method_name))[1] - __s2[1]); if (__s2_len
> 1 && __result == 0) { __result = (((const unsigned
char *) (const char *) (cseq->cs_method_name))[2] - __s2[
2]); if (__s2_len > 2 && __result == 0) __result =
(((const unsigned char *) (const char *) (cseq->cs_method_name
))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (irq
->irq_cseq->cs_method_name, cseq->cs_method_name))))
; })
6109 cseq->cs_method_name)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(irq->irq_cseq->cs_method_name) && __builtin_constant_p
(cseq->cs_method_name) && (__s1_len = __builtin_strlen
(irq->irq_cseq->cs_method_name), __s2_len = __builtin_strlen
(cseq->cs_method_name), (!((size_t)(const void *)((irq->
irq_cseq->cs_method_name) + 1) - (size_t)(const void *)(irq
->irq_cseq->cs_method_name) == 1) || __s1_len >= 4) &&
(!((size_t)(const void *)((cseq->cs_method_name) + 1) - (
size_t)(const void *)(cseq->cs_method_name) == 1) || __s2_len
>= 4)) ? __builtin_strcmp (irq->irq_cseq->cs_method_name
, cseq->cs_method_name) : (__builtin_constant_p (irq->irq_cseq
->cs_method_name) && ((size_t)(const void *)((irq->
irq_cseq->cs_method_name) + 1) - (size_t)(const void *)(irq
->irq_cseq->cs_method_name) == 1) && (__s1_len =
__builtin_strlen (irq->irq_cseq->cs_method_name), __s1_len
< 4) ? (__builtin_constant_p (cseq->cs_method_name) &&
((size_t)(const void *)((cseq->cs_method_name) + 1) - (size_t
)(const void *)(cseq->cs_method_name) == 1) ? __builtin_strcmp
(irq->irq_cseq->cs_method_name, cseq->cs_method_name
) : (__extension__ ({ const unsigned char *__s2 = (const unsigned
char *) (const char *) (cseq->cs_method_name); int __result
= (((const unsigned char *) (const char *) (irq->irq_cseq
->cs_method_name))[0] - __s2[0]); if (__s1_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (irq->irq_cseq->cs_method_name))[1] - __s2[1])
; if (__s1_len > 1 && __result == 0) { __result = (
((const unsigned char *) (const char *) (irq->irq_cseq->
cs_method_name))[2] - __s2[2]); if (__s1_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) (irq->irq_cseq->cs_method_name))[3] - __s2[3]); } }
__result; }))) : (__builtin_constant_p (cseq->cs_method_name
) && ((size_t)(const void *)((cseq->cs_method_name
) + 1) - (size_t)(const void *)(cseq->cs_method_name) == 1
) && (__s2_len = __builtin_strlen (cseq->cs_method_name
), __s2_len < 4) ? (__builtin_constant_p (irq->irq_cseq
->cs_method_name) && ((size_t)(const void *)((irq->
irq_cseq->cs_method_name) + 1) - (size_t)(const void *)(irq
->irq_cseq->cs_method_name) == 1) ? __builtin_strcmp (irq
->irq_cseq->cs_method_name, cseq->cs_method_name) : (
- (__extension__ ({ const unsigned char *__s2 = (const unsigned
char *) (const char *) (irq->irq_cseq->cs_method_name)
; int __result = (((const unsigned char *) (const char *) (cseq
->cs_method_name))[0] - __s2[0]); if (__s2_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (cseq->cs_method_name))[1] - __s2[1]); if (__s2_len
> 1 && __result == 0) { __result = (((const unsigned
char *) (const char *) (cseq->cs_method_name))[2] - __s2[
2]); if (__s2_len > 2 && __result == 0) __result =
(((const unsigned char *) (const char *) (cseq->cs_method_name
))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (irq
->irq_cseq->cs_method_name, cseq->cs_method_name))))
; })
== 0)
6110 return irq;
6111 if (return_ack && irq->irq_method == sip_method_invite)
6112 return *return_ack = irq, NULL((void*)0);
6113 if (return_cancel && irq->irq_method != sip_method_ack)
6114 return *return_cancel = irq, NULL((void*)0);
6115 }
6116 }
6117 else {
6118 /* No magic branch */
6119
6120 /* INVITE request matches a transaction if
6121 the Request-URI, To tag, From tag, Call-ID, CSeq, and
6122 top Via header match */
6123
6124 /* From tag, Call-ID, and CSeq number has been matched above */
6125
6126 /* Match top Via header field */
6127 if (!su_casematch(irq->irq_via->v_branch, v->v_branch) ||
6128 !su_casematch(irq->irq_via->v_host, v->v_host) ||
6129 !su_strmatch(irq->irq_via->v_port, v->v_port))
6130 ;
6131 /* Match Request-URI */
6132 else if (url_cmp(irq->irq_rq->rq_url, rq->rq_url))
6133 ;
6134 else {
6135 /* Match CSeq */
6136 if (irq->irq_method == cseq->cs_method &&
6137 su_strmatch(irq->irq_cseq->cs_method_name, cseq->cs_method_name)) {
6138 /* Match To tag */
6139 if (!su_strcasecmp(irq->irq_to->a_tag, to->a_tag))
6140 return irq; /* found */
6141 }
6142 else if (
6143 /* Tag set by UAS */
6144 su_strcasecmp(irq->irq_tag, to->a_tag) &&
6145 /* Original tag */
6146 su_strcasecmp(irq->irq_to->a_tag, to->a_tag))
6147 ;
6148 else if (return_ack && irq->irq_method == sip_method_invite)
6149 return *return_ack = irq, NULL((void*)0);
6150 else if (return_cancel && irq->irq_method != sip_method_ack)
6151 return *return_cancel = irq, NULL((void*)0);
6152 }
6153 }
6154
6155 /* RFC3261 - section 8.2.2.2 Merged Requests */
6156 if (return_merge) {
6157 if (irq->irq_cseq->cs_method == cseq->cs_method &&
6158 strcmp(irq->irq_cseq->cs_method_name,__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(irq->irq_cseq->cs_method_name) && __builtin_constant_p
(cseq->cs_method_name) && (__s1_len = __builtin_strlen
(irq->irq_cseq->cs_method_name), __s2_len = __builtin_strlen
(cseq->cs_method_name), (!((size_t)(const void *)((irq->
irq_cseq->cs_method_name) + 1) - (size_t)(const void *)(irq
->irq_cseq->cs_method_name) == 1) || __s1_len >= 4) &&
(!((size_t)(const void *)((cseq->cs_method_name) + 1) - (
size_t)(const void *)(cseq->cs_method_name) == 1) || __s2_len
>= 4)) ? __builtin_strcmp (irq->irq_cseq->cs_method_name
, cseq->cs_method_name) : (__builtin_constant_p (irq->irq_cseq
->cs_method_name) && ((size_t)(const void *)((irq->
irq_cseq->cs_method_name) + 1) - (size_t)(const void *)(irq
->irq_cseq->cs_method_name) == 1) && (__s1_len =
__builtin_strlen (irq->irq_cseq->cs_method_name), __s1_len
< 4) ? (__builtin_constant_p (cseq->cs_method_name) &&
((size_t)(const void *)((cseq->cs_method_name) + 1) - (size_t
)(const void *)(cseq->cs_method_name) == 1) ? __builtin_strcmp
(irq->irq_cseq->cs_method_name, cseq->cs_method_name
) : (__extension__ ({ const unsigned char *__s2 = (const unsigned
char *) (const char *) (cseq->cs_method_name); int __result
= (((const unsigned char *) (const char *) (irq->irq_cseq
->cs_method_name))[0] - __s2[0]); if (__s1_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (irq->irq_cseq->cs_method_name))[1] - __s2[1])
; if (__s1_len > 1 && __result == 0) { __result = (
((const unsigned char *) (const char *) (irq->irq_cseq->
cs_method_name))[2] - __s2[2]); if (__s1_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) (irq->irq_cseq->cs_method_name))[3] - __s2[3]); } }
__result; }))) : (__builtin_constant_p (cseq->cs_method_name
) && ((size_t)(const void *)((cseq->cs_method_name
) + 1) - (size_t)(const void *)(cseq->cs_method_name) == 1
) && (__s2_len = __builtin_strlen (cseq->cs_method_name
), __s2_len < 4) ? (__builtin_constant_p (irq->irq_cseq
->cs_method_name) && ((size_t)(const void *)((irq->
irq_cseq->cs_method_name) + 1) - (size_t)(const void *)(irq
->irq_cseq->cs_method_name) == 1) ? __builtin_strcmp (irq
->irq_cseq->cs_method_name, cseq->cs_method_name) : (
- (__extension__ ({ const unsigned char *__s2 = (const unsigned
char *) (const char *) (irq->irq_cseq->cs_method_name)
; int __result = (((const unsigned char *) (const char *) (cseq
->cs_method_name))[0] - __s2[0]); if (__s2_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (cseq->cs_method_name))[1] - __s2[1]); if (__s2_len
> 1 && __result == 0) { __result = (((const unsigned
char *) (const char *) (cseq->cs_method_name))[2] - __s2[
2]); if (__s2_len > 2 && __result == 0) __result =
(((const unsigned char *) (const char *) (cseq->cs_method_name
))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (irq
->irq_cseq->cs_method_name, cseq->cs_method_name))))
; })
6159 cseq->cs_method_name)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(irq->irq_cseq->cs_method_name) && __builtin_constant_p
(cseq->cs_method_name) && (__s1_len = __builtin_strlen
(irq->irq_cseq->cs_method_name), __s2_len = __builtin_strlen
(cseq->cs_method_name), (!((size_t)(const void *)((irq->
irq_cseq->cs_method_name) + 1) - (size_t)(const void *)(irq
->irq_cseq->cs_method_name) == 1) || __s1_len >= 4) &&
(!((size_t)(const void *)((cseq->cs_method_name) + 1) - (
size_t)(const void *)(cseq->cs_method_name) == 1) || __s2_len
>= 4)) ? __builtin_strcmp (irq->irq_cseq->cs_method_name
, cseq->cs_method_name) : (__builtin_constant_p (irq->irq_cseq
->cs_method_name) && ((size_t)(const void *)((irq->
irq_cseq->cs_method_name) + 1) - (size_t)(const void *)(irq
->irq_cseq->cs_method_name) == 1) && (__s1_len =
__builtin_strlen (irq->irq_cseq->cs_method_name), __s1_len
< 4) ? (__builtin_constant_p (cseq->cs_method_name) &&
((size_t)(const void *)((cseq->cs_method_name) + 1) - (size_t
)(const void *)(cseq->cs_method_name) == 1) ? __builtin_strcmp
(irq->irq_cseq->cs_method_name, cseq->cs_method_name
) : (__extension__ ({ const unsigned char *__s2 = (const unsigned
char *) (const char *) (cseq->cs_method_name); int __result
= (((const unsigned char *) (const char *) (irq->irq_cseq
->cs_method_name))[0] - __s2[0]); if (__s1_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (irq->irq_cseq->cs_method_name))[1] - __s2[1])
; if (__s1_len > 1 && __result == 0) { __result = (
((const unsigned char *) (const char *) (irq->irq_cseq->
cs_method_name))[2] - __s2[2]); if (__s1_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) (irq->irq_cseq->cs_method_name))[3] - __s2[3]); } }
__result; }))) : (__builtin_constant_p (cseq->cs_method_name
) && ((size_t)(const void *)((cseq->cs_method_name
) + 1) - (size_t)(const void *)(cseq->cs_method_name) == 1
) && (__s2_len = __builtin_strlen (cseq->cs_method_name
), __s2_len < 4) ? (__builtin_constant_p (irq->irq_cseq
->cs_method_name) && ((size_t)(const void *)((irq->
irq_cseq->cs_method_name) + 1) - (size_t)(const void *)(irq
->irq_cseq->cs_method_name) == 1) ? __builtin_strcmp (irq
->irq_cseq->cs_method_name, cseq->cs_method_name) : (
- (__extension__ ({ const unsigned char *__s2 = (const unsigned
char *) (const char *) (irq->irq_cseq->cs_method_name)
; int __result = (((const unsigned char *) (const char *) (cseq
->cs_method_name))[0] - __s2[0]); if (__s2_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (cseq->cs_method_name))[1] - __s2[1]); if (__s2_len
> 1 && __result == 0) { __result = (((const unsigned
char *) (const char *) (cseq->cs_method_name))[2] - __s2[
2]); if (__s2_len > 2 && __result == 0) __result =
(((const unsigned char *) (const char *) (cseq->cs_method_name
))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (irq
->irq_cseq->cs_method_name, cseq->cs_method_name))))
; })
== 0)
6160 *return_merge = irq, return_merge = NULL((void*)0);
6161 }
6162 }
6163
6164 return NULL((void*)0);
6165}
6166
6167/** Process retransmitted requests. */
6168su_inlinestatic inline
6169int
6170incoming_recv(nta_incoming_t *irq, msg_t *msg, sip_t *sip, tport_t *tport)
6171{
6172 nta_agent_t *agent = irq->irq_agent;
6173
6174 agent->sa_stats->as_recv_retry++;
6175
6176 if (irq->irq_status >= 100) {
6177 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__
, 6178, "nta: re-received %s request, retransmitting %u reply\n"
, sip->sip_request->rq_method_name, irq->irq_status)
) : (void)0)
6178 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__
, 6178, "nta: re-received %s request, retransmitting %u reply\n"
, sip->sip_request->rq_method_name, irq->irq_status)
) : (void)0)
;
6179 incoming_retransmit_reply(irq, tport);
6180 }
6181 else if (irq->irq_agent->sa_extra_100 &&
6182 irq->irq_extra_100) {
6183 /* Agent and Irq configured to answer automatically with 100 Trying */
6184 if (irq->irq_method == sip_method_invite ||
6185 /*
6186 * Send 100 trying to non-invite if at least half of T2 has expired
6187 * since the transaction was created.
6188 */
6189 su_duration(agent_now(irq->irq_agent), irq->irq_received) * 2U >
6190 irq->irq_agent->sa_t2) {
6191 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__
, 6192, "nta: re-received %s request, sending 100 Trying\n", sip
->sip_request->rq_method_name)) : (void)0)
6192 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__
, 6192, "nta: re-received %s request, sending 100 Trying\n", sip
->sip_request->rq_method_name)) : (void)0)
;
6193 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);
6194 }
6195 }
6196
6197 msg_destroy(msg);
6198
6199 return 0;
6200}
6201
6202su_inlinestatic inline
6203int incoming_ack(nta_incoming_t *irq, msg_t *msg, sip_t *sip, tport_t *tport)
6204{
6205 nta_agent_t *agent = irq->irq_agent;
6206
6207 /* Process ACK separately? */
6208 if (irq->irq_status >= 200 && irq->irq_status < 300 && !agent->sa_is_a_uas)
6209 return -1;
6210
6211 if (irq->irq_queue == agent->sa_in.inv_completed) {
6212 if (!irq->irq_confirmed)
6213 agent->sa_stats->as_acked_tr++;
6214
6215 irq->irq_confirmed = 1;
6216 incoming_reset_timer(irq); /* Reset timer G */
6217
6218 if (!irq->irq_reliable_tp) {
6219 incoming_queue(agent->sa_in.inv_confirmed, irq); /* Timer I */
6220 }
6221 else {
6222 irq->irq_terminated = 1;
6223 incoming_queue(agent->sa_in.terminated, irq);
6224 }
6225
6226 if (!irq->irq_destroyed) {
6227 if (!irq->irq_callback) /* Process ACK normally */
6228 return -1;
6229
6230 incoming_call_callback(irq, msg, sip); /* ACK callback */
6231 }
6232 } else if (irq->irq_queue == agent->sa_in.proceeding ||
6233 irq->irq_queue == agent->sa_in.preliminary)
6234 return -1;
6235 else
6236 assert(irq->irq_queue == agent->sa_in.inv_confirmed ||((irq->irq_queue == agent->sa_in.inv_confirmed || irq->
irq_queue == agent->sa_in.terminated) ? (void) (0) : __assert_fail
("irq->irq_queue == agent->sa_in.inv_confirmed || irq->irq_queue == agent->sa_in.terminated"
, "nta.c", 6237, __PRETTY_FUNCTION__))
6237 irq->irq_queue == agent->sa_in.terminated)((irq->irq_queue == agent->sa_in.inv_confirmed || irq->
irq_queue == agent->sa_in.terminated) ? (void) (0) : __assert_fail
("irq->irq_queue == agent->sa_in.inv_confirmed || irq->irq_queue == agent->sa_in.terminated"
, "nta.c", 6237, __PRETTY_FUNCTION__))
;
6238
6239 msg_destroy(msg);
6240
6241 return 0;
6242}
6243
6244/** Respond to the CANCEL. */
6245su_inlinestatic inline
6246int incoming_cancel(nta_incoming_t *irq, msg_t *msg, sip_t *sip,
6247 tport_t *tport)
6248{
6249 nta_agent_t *agent = irq->irq_agent;
6250
6251 /* According to the RFC 3261, this INVITE has been destroyed */
6252 if (irq->irq_method == sip_method_invite &&
6253 200 <= irq->irq_status && irq->irq_status < 300) {
6254 mreply(agent, NULL((void*)0), SIP_481_NO_TRANSACTION481, sip_481_No_transaction, msg,
6255 tport, 0, 0, NULL((void*)0),
6256 TAG_END()(tag_type_t)0, (tag_value_t)0);
6257 return 0;
6258 }
6259
6260 /* UAS MUST use same tag in final response to CANCEL and INVITE */
6261 if (agent->sa_is_a_uas && irq->irq_tag == NULL((void*)0)) {
6262 nta_incoming_tag(irq, NULL((void*)0));
6263 }
6264
6265 mreply(agent, NULL((void*)0), SIP_200_OK200, sip_200_OK, msg_ref_create(msg),
6266 tport, 0, 0, irq->irq_tag,
6267 TAG_END()(tag_type_t)0, (tag_value_t)0);
6268
6269 /* We have already sent final response */
6270 if (irq->irq_completed || irq->irq_method != sip_method_invite) {
6271 msg_destroy(msg);
6272 return 0;
6273 }
6274
6275 if (!irq->irq_canceled) {
6276 irq->irq_canceled = 1;
6277 agent->sa_stats->as_canceled_tr++;
6278 irq = incoming_call_callback(irq, msg, sip);
6279 }
6280
6281 if (irq && !irq->irq_completed && agent->sa_cancel_487)
6282 /* Respond to the cancelled request */
6283 nta_incoming_treply(irq, SIP_487_REQUEST_CANCELLED487, sip_487_Request_terminated, TAG_END()(tag_type_t)0, (tag_value_t)0);
6284
6285 msg_destroy(msg);
6286
6287 return 0;
6288}
6289
6290/** Merge request */
6291static
6292void request_merge(nta_agent_t *agent,
6293 msg_t *msg, sip_t *sip, tport_t *tport,
6294 char const *to_tag)
6295{
6296 nta_incoming_t *irq;
6297
6298 agent->sa_stats->as_merged_request++;
6299
6300 irq = incoming_create(agent, msg, sip, tport, to_tag);
6301
6302 if (irq) {
6303 nta_incoming_treply(irq, 482, "Request merged", TAG_END()(tag_type_t)0, (tag_value_t)0);
6304 nta_incoming_destroy(irq);
6305 } else {
6306 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__
, 6307, "nta: request_merge(): cannot create transaction for %s\n"
, sip->sip_request->rq_method_name)) : (void)0)
6307 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__
, 6307, "nta: request_merge(): cannot create transaction for %s\n"
, sip->sip_request->rq_method_name)) : (void)0)
;
6308 mreply(agent, NULL((void*)0), 482, "Request merged", msg,
6309 tport, 0, 0, NULL((void*)0),
6310 TAG_END()(tag_type_t)0, (tag_value_t)0);
6311 }
6312}
6313
6314/**@typedef nta_ack_cancel_f
6315 *
6316 * Callback function prototype for CANCELed/ACKed requests
6317 *
6318 * This is a callback function is invoked by NTA when an incoming request
6319 * has been cancelled or an response to an incoming INVITE request has been
6320 * acknowledged.
6321 *
6322 * @param magic incoming request context
6323 * @param ireq incoming request
6324 * @param sip ACK/CANCEL message
6325 *
6326 * @retval 0
6327 * This callback function should return always 0.
6328 */
6329
6330/** Call callback of incoming transaction */
6331su_inlinestatic inline
6332nta_incoming_t *
6333incoming_call_callback(nta_incoming_t *irq, msg_t *msg, sip_t *sip)
6334{
6335 if (irq->irq_callback) {
6336 irq->irq_in_callback = 1;
6337 irq->irq_request2 = msg;
6338 irq->irq_callback(irq->irq_magic, irq, sip);
6339 irq->irq_request2 = NULL((void*)0);
6340 irq->irq_in_callback = 0;
6341
6342 if (irq->irq_terminated && irq->irq_destroyed)
6343 incoming_free(irq), irq = NULL((void*)0);
6344 }
6345 return irq;
6346}
6347
6348/**Set server transaction parameters.
6349 *
6350 * Sets the server transaction parameters. Among others, parameters determine the way
6351 * the SigComp compression is handled.
6352 *
6353 * @TAGS
6354 * NTATAG_COMP(), NTATAG_SIGCOMP_CLOSE() and NTATAG_EXTRA_100().
6355 *
6356 * @retval number of set parameters when succesful
6357 * @retval -1 upon an error
6358 */
6359int nta_incoming_set_params(nta_incoming_t *irq,
6360 tag_type_t tag, tag_value_t value, ...)
6361{
6362 int retval = -1;
6363
6364 if (irq) {
6365 ta_list ta;
6366 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)
;
6367 retval = incoming_set_params(irq, ta_args(ta)(ta).tl);
6368 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))
;
6369 }
6370 else {
6371 su_seterrno(EINVAL22);
6372 }
6373
6374 return retval;
6375}
6376
6377static
6378int incoming_set_params(nta_incoming_t *irq, tagi_t const *tags)
6379{
6380 int retval = 0;
6381
6382 tagi_t const *t;
6383 char const *comp = NONE((void *)-1);
6384 struct sigcomp_compartment *cc = NONE((void *)-1);
6385
6386 if (irq->irq_default)
6387 return retval;
6388
6389 for (t = tags; t; t = tl_next(t)) {
6390 tag_type_t tt = t->t_tag;
6391
6392 if (ntatag_comp == tt)
6393 comp = (char const *)t->t_value, retval++;
6394
6395 else if (ntatag_sigcomp_close == tt)
6396 irq->irq_sigcomp_zap = t->t_value != 0, retval++;
6397
6398 else if (tptag_compartment == tt)
6399 cc = (void *)t->t_value, retval++;
6400
6401 else if (ntatag_extra_100 == tt)
6402 irq->irq_extra_100 = t->t_value != 0, retval++;
6403 }
6404
6405 if (cc != NONE((void *)-1)) {
6406 if (cc)
6407 agent_accept_compressed(irq->irq_agent, irq->irq_request, cc);
6408 if (irq->irq_cc)
6409 nta_compartment_decref(&irq->irq_cc);
6410 irq->irq_cc = nta_compartment_ref(cc);
6411 }
6412 else if (comp != NULL((void*)0) && comp != NONE((void *)-1) && irq->irq_cc == NULL((void*)0)) {
6413 incoming_set_compartment(irq, irq->irq_tport, irq->irq_request, 1);
6414 }
6415
6416 else if (comp == NULL((void*)0)) {
6417 irq->irq_tpn->tpn_comp = NULL((void*)0);
6418 }
6419
6420 return retval;
6421}
6422
6423su_inlinestatic inline
6424int incoming_set_compartment(nta_incoming_t *irq, tport_t *tport, msg_t *msg,
6425 int create_if_needed)
6426{
6427 if (!nta_compressor_vtable)
6428 return 0;
6429
6430 if (irq->irq_cc == NULL((void*)0)
6431 || irq->irq_tpn->tpn_comp
6432 || tport_delivered_with_comp(tport, msg, NULL((void*)0)) != -1) {
6433 struct sigcomp_compartment *cc;
6434
6435 cc = agent_compression_compartment(irq->irq_agent, tport, irq->irq_tpn,
6436 create_if_needed);
6437
6438 if (cc)
6439 agent_accept_compressed(irq->irq_agent, msg, cc);
6440
6441 irq->irq_cc = cc;
6442 }
6443
6444 return 0;
6445}
6446
6447/** Add essential headers to the response message */
6448static int nta_incoming_response_headers(nta_incoming_t *irq,
6449 msg_t *msg,
6450 sip_t *sip)
6451{
6452 int clone = 0;
6453 su_home_t *home = msg_home(msg)((su_home_t*)(msg));
6454
6455 if (!sip->sip_from)
6456 clone = 1, sip->sip_from = sip_from_copy(home, irq->irq_from);
6457 if (!sip->sip_to)
6458 clone = 1, sip->sip_to = sip_to_copy(home, irq->irq_to);
6459 if (!sip->sip_call_id)
6460 clone = 1, sip->sip_call_id = sip_call_id_copy(home, irq->irq_call_id);
6461 if (!sip->sip_cseq)
6462 clone = 1, sip->sip_cseq = sip_cseq_copy(home, irq->irq_cseq);
6463 if (!sip->sip_via)
6464 clone = 1, sip->sip_via = sip_via_copy(home, irq->irq_via);
6465
6466 if (clone)
6467 msg_set_parent(msg, (msg_t *)irq->irq_home);
6468
6469 if (!sip->sip_from || !sip->sip_to || !sip->sip_call_id || !sip->sip_cseq || !sip->sip_via)
6470 return -1;
6471
6472 return 0;
6473}
6474
6475/** Complete a response message.
6476 *
6477 * @param irq server transaction object
6478 * @param msg response message to be completed
6479 * @param status status code (in range 100 - 699)
6480 * @param phrase status phrase (may be NULL)
6481 * @param tag,value,... taged argument list
6482 *
6483 * Generate status structure based on @a status and @a phrase.
6484 * Add essential headers to the response message:
6485 * @From, @To, @CallID, @CSeq, @Via, and optionally
6486 * @RecordRoute.
6487 */
6488int nta_incoming_complete_response(nta_incoming_t *irq,
6489 msg_t *msg,
6490 int status,
6491 char const *phrase,
6492 tag_type_t tag, tag_value_t value, ...)
6493{
6494 su_home_t *home = msg_home(msg)((su_home_t*)(msg));
6495 sip_t *sip = sip_object(msg);
6496 int retval;
6497 ta_list ta;
6498
6499 if (irq == NULL((void*)0) || sip == NULL((void*)0))
6500 return su_seterrno(EFAULT14), -1;
6501
6502 if (status != 0 && (status < 100 || status > 699))
6503 return su_seterrno(EINVAL22), -1;
6504
6505 if (status != 0 && !sip->sip_status)
6506 sip->sip_status = sip_status_create(home, status, phrase, NULL((void*)0));
6507
6508 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)
;
6509 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
);
6510 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))
;
6511
6512 if (retval < 0)
6513 return -1;
6514
6515 if (irq->irq_default)
6516 return sip_complete_message(msg);
6517
6518 if (status > 100 && !irq->irq_tag) {
6519 if (sip->sip_to)
6520 nta_incoming_tag(irq, sip->sip_to->a_tag);
6521 else
6522 nta_incoming_tag(irq, NULL((void*)0));
6523 }
6524
6525 if (nta_incoming_response_headers(irq, msg, sip) < 0)
6526 return -1;
6527
6528 if (sip->sip_status && sip->sip_status->st_status > 100 &&
6529 irq->irq_tag && sip->sip_to && !sip->sip_to->a_tag)
6530 if (sip_to_tag(home, sip->sip_to, irq->irq_tag) < 0)
6531 return -1;
6532
6533 if (status < 300 && !sip->sip_record_route && irq->irq_record_route)
6534 if (sip_add_dup(msg, sip, (sip_header_t *)irq->irq_record_route) < 0)
6535 return -1;
6536
6537 return sip_complete_message(msg);
6538}
6539
6540
6541/** Create a response message for request.
6542 *
6543 * @NEW_1_12_5.
6544 */
6545msg_t *nta_incoming_create_response(nta_incoming_t *irq,
6546 int status, char const *phrase)
6547{
6548 msg_t *msg = NULL((void*)0);
6549 sip_t *sip;
6550
6551 if (irq) {
6552 msg = nta_msg_create(irq->irq_agent, 0);
6553 sip = sip_object(msg);
6554
6555 if (sip) {
6556 if (status != 0)
6557 sip->sip_status = sip_status_create(msg_home(msg)((su_home_t*)(msg)), status, phrase, NULL((void*)0));
6558
6559 if (nta_incoming_response_headers(irq, msg, sip) < 0)
6560 msg_destroy(msg), msg = NULL((void*)0);
6561 }
6562 }
6563
6564 return msg;
6565}
6566
6567
6568/**Reply to an incoming transaction request.
6569 *
6570 * This function creates a response message to an incoming request and sends
6571 * it to the client.
6572 *
6573 * @note
6574 * It is possible to send several non-final (1xx) responses, but only one
6575 * final response.
6576 *
6577 * @param irq incoming request
6578 * @param status status code
6579 * @param phrase status phrase (may be NULL if status code is well-known)
6580 * @param tag,value,... optional additional headers terminated by TAG_END()
6581 *
6582 * @retval 0 when succesful
6583 * @retval -1 upon an error
6584 */
6585int nta_incoming_treply(nta_incoming_t *irq,
6586 int status,
6587 char const *phrase,
6588 tag_type_t tag, tag_value_t value, ...)
6589{
6590 int retval = -1;
6591
6592 if (irq &&
6593 (irq->irq_status < 200 || status < 200 ||
6594 (irq->irq_method == sip_method_invite && status < 300))) {
6595 ta_list ta;
6596 msg_t *msg = nta_msg_create(irq->irq_agent, 0);
6597
6598 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)
;
6599
6600 if (!msg)
6601 ;
6602 else if (nta_incoming_complete_response(irq, msg, status, phrase,
6603 ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
) < 0)
6604 msg_destroy(msg);
6605 else if (incoming_set_params(irq, ta_args(ta)(ta).tl) < 0)
6606 msg_destroy(msg);
6607 else
6608 retval = nta_incoming_mreply(irq, msg);
6609
6610 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))
;
6611
6612 if (retval < 0 && status >= 200)
6613 incoming_final_failed(irq, NULL((void*)0));
6614 }
6615
6616 return retval;
6617}
6618
6619/**
6620 * Return a response message to client.
6621 *
6622 * @note
6623 * The ownership of @a msg is taken over by the function even if the
6624 * function fails.
6625 *
6626 * @retval 0 when succesful
6627 * @retval -1 upon an error
6628 */
6629int nta_incoming_mreply(nta_incoming_t *irq, msg_t *msg)
6630{
6631 sip_t *sip = sip_object(msg);
6632
6633 int status;
6634
6635 if (irq == NULL((void*)0)) {
6636 msg_destroy(msg);
6637 return -1;
6638 }
6639
6640 if (msg == NULL((void*)0) || sip == NULL((void*)0))
6641 return -1;
6642
6643 if (msg == irq->irq_response)
6644 return 0;
6645
6646 if (!sip->sip_status || !sip->sip_via || !sip->sip_cseq)
6647 return incoming_final_failed(irq, msg);
6648
6649 assert (sip->sip_cseq->cs_method == irq->irq_method || irq->irq_default)((sip->sip_cseq->cs_method == irq->irq_method || irq
->irq_default) ? (void) (0) : __assert_fail ("sip->sip_cseq->cs_method == irq->irq_method || irq->irq_default"
, "nta.c", 6649, __PRETTY_FUNCTION__))
;
6650
6651 status = sip->sip_status->st_status;
6652
6653 if (!irq->irq_tag && status > 100 && !irq->irq_default)
6654 nta_incoming_tag(irq, NULL((void*)0));
6655
6656 if (/* (irq->irq_confirmed && status >= 200) || */
6657 (irq->irq_completed && status >= 300)) {
6658 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__
, 6659, "%s: already %s transaction\n", __func__, irq->irq_confirmed
? "confirmed" : "completed")) : (void)0)
6659 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__
, 6659, "%s: already %s transaction\n", __func__, irq->irq_confirmed
? "confirmed" : "completed")) : (void)0)
;
6660 msg_destroy(msg);
6661 return -1;
6662 }
6663
6664#ifdef HAVE_ZLIB_COMPRESS1
6665 if (irq->irq_compressed) {
6666 sip_content_encoding_Xflate(msg, sip, 0, 0);
6667 }
6668#endif
6669
6670 if (irq->irq_must_100rel && !sip->sip_rseq && status > 100 && status < 200) {
6671 /* This nta_reliable_t object will be destroyed by PRACK or timeout */
6672 if (nta_reliable_mreply(irq, NULL((void*)0), NULL((void*)0), msg))
6673 return 0;
6674
6675 return -1;
6676 }
6677
6678 if (status >= 200 && irq->irq_reliable && irq->irq_reliable->rel_unsent) {
6679 if (reliable_final(irq, msg, sip) == 0)
6680 return 0;
6681 }
6682
6683 return incoming_reply(irq, msg, sip);
6684}
6685
6686
6687
6688/** Send the response message.
6689 *
6690 * @note The ownership of msg is handled to incoming_reply().
6691 */
6692int incoming_reply(nta_incoming_t *irq, msg_t *msg, sip_t *sip)
6693{
6694 nta_agent_t *agent = irq->irq_agent;
6695 int status = sip->sip_status->st_status;
6696 int sending = 1;
6697 int *use_rport = NULL((void*)0);
6698 int retry_without_rport = 0;
6699 tp_name_t *tpn, default_tpn[1];
6700
6701 if (status == 408 &&
6702 irq->irq_method != sip_method_invite &&
6703 !agent->sa_pass_408 &&
6704 !irq->irq_default) {
6705 /* RFC 4320 nit-actions-03 Action 2:
6706
6707 A transaction-stateful SIP element MUST NOT send a response with
6708 Status-Code of 408 to a non-INVITE request. As a consequence, an
6709 element that can not respond before the transaction expires will not
6710 send a final response at all.
6711 */
6712 sending = 0;
6713 }
6714
6715 if (irq->irq_status == 0 && irq->irq_timestamp && !sip->sip_timestamp)
6716 incoming_timestamp(irq, msg, sip);
6717
6718 if (irq->irq_default) {
6719 if (agent->sa_server_rport)
6720 use_rport = &retry_without_rport, retry_without_rport = 1;
6721 tpn = default_tpn;
6722 if (nta_tpn_by_via(tpn, sip->sip_via, use_rport) < 0)
6723 tpn = NULL((void*)0);
6724 }
6725 else {
6726 tpn = irq->irq_tpn;
6727 }
6728
6729 if (sip_complete_message(msg) < 0)
6730 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__
, 6730, "%s: sip_complete_message() failed\n", __func__)) : (
void)0)
;
6731 else if (msg_serialize(msg, (msg_pub_t *)sip) < 0)
6732 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__
, 6732, "%s: sip_serialize() failed\n", __func__)) : (void)0)
;
6733 else if (!(irq->irq_tport) &&
6734 !(tport_decref(&irq->irq_tport),
6735 irq->irq_tport = tpn ? tport_by_name(agent->sa_tports, tpn) : 0))
6736 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__
, 6736, "%s: no tport\n", __func__)) : (void)0)
;
6737 else {
6738 int i, err = 0;
6739 tport_t *tp = NULL((void*)0);
6740 incoming_queue_t *queue;
6741
6742 char const *method_name;
6743 uint32_t cseq;
6744
6745 if (irq->irq_default) {
6746 assert(sip->sip_cseq)((sip->sip_cseq) ? (void) (0) : __assert_fail ("sip->sip_cseq"
, "nta.c", 6746, __PRETTY_FUNCTION__))
;
6747 method_name = sip->sip_cseq->cs_method_name, cseq = sip->sip_cseq->cs_seq;
6748 }
6749 else {
6750 method_name = irq->irq_rq->rq_method_name, cseq = irq->irq_cseq->cs_seq;
6751 }
6752
6753 if (sending) {
6754 for (i = 0; i < 3; i++) {
6755 tp = tport_tsend(irq->irq_tport, msg, tpn,
6756 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)),
6757 TPTAG_MTU(INT_MAX)tptag_mtu, tag_usize_v((2147483647)),
6758 TAG_END()(tag_type_t)0, (tag_value_t)0);
6759 if (tp)
6760 break;
6761
6762 err = msg_errno(msg);
6763 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__
, 6765, "%s: tport_tsend: %s%s\n", __func__, su_strerror(err)
, err == 32 ? "(retrying)" : "")) : (void)0)
6764 __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__
, 6765, "%s: tport_tsend: %s%s\n", __func__, su_strerror(err)
, err == 32 ? "(retrying)" : "")) : (void)0)
6765 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__
, 6765, "%s: tport_tsend: %s%s\n", __func__, su_strerror(err)
, err == 32 ? "(retrying)" : "")) : (void)0)
;
6766
6767 if (err != EPIPE32 && err != ECONNREFUSED111)
6768 break;
6769 tport_decref(&irq->irq_tport);
6770 irq->irq_tport = tport_ref(tport_by_name(agent->sa_tports, tpn));
6771 }
6772
6773 if (!tp) {
6774 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__
, 6777, "%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)
6775 "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__
, 6777, "%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)
6776 __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__
, 6777, "%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)
6777 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__
, 6777, "%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)
;
6778 if (status < 200)
6779 msg_destroy(msg);
6780 else
6781 incoming_final_failed(irq, msg);
6782 return 0;
6783 }
6784
6785 agent->sa_stats->as_sent_msg++;
6786 agent->sa_stats->as_sent_response++;
6787 }
6788
6789 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__
, 6791, "nta: %s %u %s for %s (%u)\n", sending ? "sent" : "not sending"
, status, sip->sip_status->st_phrase, method_name, cseq
)) : (void)0)
6790 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__
, 6791, "nta: %s %u %s for %s (%u)\n", sending ? "sent" : "not sending"
, status, sip->sip_status->st_phrase, method_name, cseq
)) : (void)0)
6791 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__
, 6791, "nta: %s %u %s for %s (%u)\n", sending ? "sent" : "not sending"
, status, sip->sip_status->st_phrase, method_name, cseq
)) : (void)0)
;
6792
6793 if (irq->irq_default) {
6794 msg_destroy(msg);
6795 return 0;
6796 }
6797
6798 incoming_reset_timer(irq);
6799
6800 if (status < 200) {
6801 queue = agent->sa_in.proceeding;
6802
6803 if (irq->irq_method == sip_method_invite && status > 100 &&
6804 agent->sa_progress != UINT_MAX(2147483647 *2U +1U) && agent->sa_is_a_uas) {
6805 /* Retransmit preliminary responses in regular intervals */
6806 incoming_set_timer(irq, agent->sa_progress); /* N2 */
6807 }
6808 }
6809 else {
6810 irq->irq_completed = 1;
6811
6812 /* XXX - we should do this only after message has actually been sent! */
6813 if (irq->irq_sigcomp_zap && irq->irq_cc)
6814 agent_close_compressor(irq->irq_agent, irq->irq_cc);
6815
6816 if (irq->irq_method != sip_method_invite) {
6817 irq->irq_confirmed = 1;
6818
6819 if (irq->irq_reliable_tp) {
6820 irq->irq_terminated = 1;
6821 queue = agent->sa_in.terminated ; /* J - set for 0 seconds */
6822 } else {
6823 queue = agent->sa_in.completed; /* J */
6824 }
6825
6826 tport_decref(&irq->irq_tport);
6827 }
6828 else if (status >= 300 || agent->sa_is_a_uas) {
6829 if (status < 300 || !irq->irq_reliable_tp)
6830 incoming_set_timer(irq, agent->sa_t1); /* G */
6831 queue = agent->sa_in.inv_completed; /* H */
6832 }
6833 else {
6834#if 1
6835 /* Avoid bug in @RFC3261:
6836 Keep INVITE transaction around in order to catch
6837 retransmitted INVITEs
6838 */
6839 irq->irq_confirmed = 1;
6840 queue = agent->sa_in.inv_confirmed; /* H */
6841#else
6842 irq->irq_terminated = 1;
6843 queue = agent->sa_in.terminated;
6844#endif
6845 }
6846 }
6847
6848 if (irq->irq_queue != queue)
6849 incoming_queue(queue, irq);
6850
6851 if (status >= 200 || irq->irq_status < 200) {
6852 if (irq->irq_response)
6853 msg_destroy(irq->irq_response);
6854 assert(msg_home(msg) != irq->irq_home)((((su_home_t*)(msg)) != irq->irq_home) ? (void) (0) : __assert_fail
("((su_home_t*)(msg)) != irq->irq_home", "nta.c", 6854, __PRETTY_FUNCTION__
))
;
6855 irq->irq_response = msg;
6856 }
6857 else {
6858 msg_destroy(msg);
6859 }
6860
6861 if (sip->sip_cseq->cs_method == irq->irq_method &&
6862 irq->irq_status < 200 && status > irq->irq_status)
6863 irq->irq_status = status;
6864
6865 return 0;
6866 }
6867
6868 /*
6869 * XXX - handling error is very problematic.
6870 * Nobody checks return code from nta_incoming_*reply()
6871 */
6872 if (status < 200) {
6873 msg_destroy(msg);
6874 return -1;
6875 }
6876
6877 /* We could not send final response. */
6878 return incoming_final_failed(irq, msg);
6879}
6880
6881
6882/** @internal Sending final response has failed.
6883 *
6884 * Put transaction into its own queue, try later to send the response.
6885 */
6886su_inlinestatic inline
6887int incoming_final_failed(nta_incoming_t *irq, msg_t *msg)
6888{
6889 msg_destroy(msg);
6890
6891 if (!irq->irq_default) {
6892 irq->irq_final_failed = 1;
6893 incoming_queue(irq->irq_agent->sa_in.final_failed, irq);
6894 }
6895
6896 return -1;
6897}
6898
6899/** @internal Retransmit the reply */
6900static
6901void incoming_retransmit_reply(nta_incoming_t *irq, tport_t *tport)
6902{
6903 msg_t *msg = NULL((void*)0);
6904
6905 if (irq->irq_final_failed)
6906 return;
6907
6908 if (tport == NULL((void*)0))
6909 tport = irq->irq_tport;
6910
6911 /* Answer with existing reply */
6912 if (irq->irq_reliable && !irq->irq_reliable->rel_pracked)
6913 msg = reliable_response(irq);
6914 else
6915 msg = irq->irq_response;
6916
6917 if (msg && tport) {
6918 irq->irq_retries++;
6919
6920 if (irq->irq_retries == 2 && irq->irq_tpn->tpn_comp) {
6921 irq->irq_tpn->tpn_comp = NULL((void*)0);
6922
6923 if (irq->irq_cc) {
6924 agent_close_compressor(irq->irq_agent, irq->irq_cc);
6925 nta_compartment_decref(&irq->irq_cc);
6926 }
6927 }
6928
6929 tport = tport_tsend(tport, msg, irq->irq_tpn,
6930 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)),
6931 TPTAG_MTU(INT_MAX)tptag_mtu, tag_usize_v((2147483647)), TAG_END()(tag_type_t)0, (tag_value_t)0);
6932 irq->irq_agent->sa_stats->as_sent_msg++;
6933 irq->irq_agent->sa_stats->as_sent_response++;
6934 }
6935}
6936
6937/** @internal Create timestamp header for response */
6938static
6939int incoming_timestamp(nta_incoming_t *irq, msg_t *msg, sip_t *sip)
6940{
6941 sip_timestamp_t ts[1];
6942 su_time_t now = su_now();
6943 char delay[32];
6944 double diff = su_time_diff(now, irq->irq_received);
6945
6946 snprintf(delay, sizeof delay, "%.06f", diff);
6947
6948 *ts = *irq->irq_timestamp;
6949 ts->ts_delay = delay;
6950
6951 return sip_add_dup(msg, sip, (sip_header_t *)ts);
6952}
6953
6954enum {
6955 timer_max_retransmit = 30,
6956 timer_max_terminate = 100000,
6957 timer_max_timeout = 100
6958};
6959
6960/** @internal Timer routine for the incoming request. */
6961static void
6962_nta_incoming_timer(nta_agent_t *sa)
6963{
6964 uint32_t now = su_time_ms(su_now());
6965 nta_incoming_t *irq, *irq_next;
6966 size_t retransmitted = 0, timeout = 0, terminated = 0, destroyed = 0;
6967 size_t unconfirmed =
6968 sa->sa_in.inv_completed->q_length +
6969 sa->sa_in.preliminary->q_length;
6970 size_t unterminated =
6971 sa->sa_in.inv_confirmed->q_length +
6972 sa->sa_in.completed->q_length;
6973 size_t total = sa->sa_incoming->iht_used;
6974
6975 incoming_queue_t rq[1];
6976
6977 incoming_queue_init(rq, 0);
6978
6979 /* Handle retry queue */
6980 while ((irq = sa->sa_in.re_list)) {
6981
6982 now = su_time_ms(su_now());
6983
6984 if ((int32_t)(irq->irq_retry - now) > 0)
6985 break;
6986 if (retransmitted >= timer_max_retransmit)
6987 break;
6988
6989 if (irq->irq_method == sip_method_invite && irq->irq_status >= 200) {
6990 /* Timer G */
6991 assert(irq->irq_queue == sa->sa_in.inv_completed)((irq->irq_queue == sa->sa_in.inv_completed) ? (void) (
0) : __assert_fail ("irq->irq_queue == sa->sa_in.inv_completed"
, "nta.c", 6991, __PRETTY_FUNCTION__))
;
6992
6993 retransmitted++;
6994
6995 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__
, 6996, "nta: timer %s fired, retransmitting %u reply\n", "G"
, irq->irq_status)) : (void)0)
6996 "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__
, 6996, "nta: timer %s fired, retransmitting %u reply\n", "G"
, irq->irq_status)) : (void)0)
;
6997
6998 incoming_retransmit_reply(irq, irq->irq_tport);
6999
7000 if (2U * irq->irq_interval < sa->sa_t2)
7001 incoming_set_timer(irq, 2U * irq->irq_interval); /* G */
7002 else
7003 incoming_set_timer(irq, sa->sa_t2); /* G */
7004 }
7005 else if (irq->irq_method == sip_method_invite && irq->irq_status >= 100) {
7006 if (irq->irq_queue == sa->sa_in.preliminary) {
7007 /* Timer P1 - PRACK timer */
7008 retransmitted++;
7009 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__
, 7010, "nta: timer %s fired, retransmitting %u reply\n", "P1"
, irq->irq_status)) : (void)0)
7010 "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__
, 7010, "nta: timer %s fired, retransmitting %u reply\n", "P1"
, irq->irq_status)) : (void)0)
;
7011
7012 incoming_retransmit_reply(irq, irq->irq_tport);
7013
7014 incoming_set_timer(irq, 2 * irq->irq_interval); /* P1 */
7015 }
7016 else {
7017 /* Retransmitting provisional responses */
7018 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__
, 7019, "nta: timer %s fired, retransmitting %u reply\n", "N2"
, irq->irq_status)) : (void)0)
7019 "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__
, 7019, "nta: timer %s fired, retransmitting %u reply\n", "N2"
, irq->irq_status)) : (void)0)
;
7020 incoming_set_timer(irq, sa->sa_progress);
7021 retransmitted++;
7022 incoming_retransmit_reply(irq, irq->irq_tport);
7023 }
7024 }
7025 else {
7026 /* Timer N1 */
7027 incoming_reset_timer(irq);
7028
7029 if(irq->irq_extra_100) {
7030 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__
, 7030, "nta: timer N1 fired, sending %u %s\n", 100, sip_100_Trying
)) : (void)0)
;
7031 nta_incoming_treply(irq, SIP_100_TRYING100, sip_100_Trying, TAG_END()(tag_type_t)0, (tag_value_t)0);
7032 }
7033 else {
7034 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__
, 7035, "nta: timer N1 fired, but avoided sending %u %s\n", 100
, sip_100_Trying)) : (void)0)
7035 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__
, 7035, "nta: timer N1 fired, but avoided sending %u %s\n", 100
, sip_100_Trying)) : (void)0)
;
7036 }
7037 }
7038 }
7039
7040 while ((irq = sa->sa_in.final_failed->q_head)) {
7041
7042
7043 incoming_remove(irq);
7044 irq->irq_final_failed = 0;
7045
7046 /* Report error to application */
7047 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__
, 7048, "nta: sending final response failed, timeout %u response\n"
, irq->irq_status)) : (void)0)
7048 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__
, 7048, "nta: sending final response failed, timeout %u response\n"
, irq->irq_status)) : (void)0)
;
7049 reliable_timeout(irq, 0);
7050
7051 nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error, TAG_END()(tag_type_t)0, (tag_value_t)0);
7052
7053 if (!irq->irq_final_failed) /* We have taken care of the error... */
7054 continue;
7055
7056 if (irq->irq_destroyed) {
7057 incoming_free_queue(rq, irq);
7058 continue;
7059 }
7060
7061 incoming_reset_timer(irq);
7062 irq->irq_confirmed = 1;
7063 irq->irq_terminated = 1;
7064 incoming_queue(sa->sa_in.terminated, irq);
7065 }
7066
7067 /* Timeouts.
7068 * For each state the request is in, there is always a queue of its own
7069 */
7070 while ((irq = sa->sa_in.preliminary->q_head)) {
7071 assert(irq->irq_status < 200)((irq->irq_status < 200) ? (void) (0) : __assert_fail (
"irq->irq_status < 200", "nta.c", 7071, __PRETTY_FUNCTION__
))
;
7072 assert(irq->irq_timeout)((irq->irq_timeout) ? (void) (0) : __assert_fail ("irq->irq_timeout"
, "nta.c", 7072, __PRETTY_FUNCTION__))
;
7073
7074 now = su_time_ms(su_now());
7075
7076 if ((int32_t)(irq->irq_timeout - now) > 0)
7077 break;
7078 if (timeout >= timer_max_timeout)
7079 break;
7080
7081 timeout++;
7082
7083 /* Timer P2 - PRACK timer */
7084 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__
, 7085, "nta: timer %s fired, %s %u response\n", "P2", "timeout"
, irq->irq_status)) : (void)0)
7085 "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__
, 7085, "nta: timer %s fired, %s %u response\n", "P2", "timeout"
, irq->irq_status)) : (void)0)
;
7086 incoming_reset_timer(irq);
7087 irq->irq_timeout = 0;
7088 reliable_timeout(irq, 1);
7089 }
7090
7091 while ((irq = sa->sa_in.inv_completed->q_head)) {
7092 assert(irq->irq_status >= 200)((irq->irq_status >= 200) ? (void) (0) : __assert_fail (
"irq->irq_status >= 200", "nta.c", 7092, __PRETTY_FUNCTION__
))
;
7093 assert(irq->irq_timeout)((irq->irq_timeout) ? (void) (0) : __assert_fail ("irq->irq_timeout"
, "nta.c", 7093, __PRETTY_FUNCTION__))
;
7094 assert(irq->irq_method == sip_method_invite)((irq->irq_method == sip_method_invite) ? (void) (0) : __assert_fail
("irq->irq_method == sip_method_invite", "nta.c", 7094, __PRETTY_FUNCTION__
))
;
7095
7096 now = su_time_ms(su_now());
7097
7098 if ((int32_t)(irq->irq_timeout - now) > 0 ||
7099 timeout >= timer_max_timeout ||
7100 terminated >= timer_max_terminate)
7101 break;
7102
7103 /* Timer H */
7104 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__
, 7105, "nta: timer %s fired, %s %u response\n", "H", "timeout and terminate"
, irq->irq_status)) : (void)0)
7105 "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__
, 7105, "nta: timer %s fired, %s %u response\n", "H", "timeout and terminate"
, irq->irq_status)) : (void)0)
;
7106 irq->irq_confirmed = 1;
7107 irq->irq_terminated = 1;
7108 incoming_reset_timer(irq);
7109 if (!irq->irq_destroyed) {
7110 timeout++;
7111 incoming_queue(sa->sa_in.terminated, irq);
7112 /* report timeout error to user */
7113 incoming_call_callback(irq, NULL((void*)0), NULL((void*)0));
7114 } else {
7115 timeout++;
7116 terminated++;
7117 incoming_free_queue(rq, irq);
7118 }
7119 }
7120
7121 while ((irq = sa->sa_in.inv_confirmed->q_head)) {
7122 assert(irq->irq_timeout)((irq->irq_timeout) ? (void) (0) : __assert_fail ("irq->irq_timeout"
, "nta.c", 7122, __PRETTY_FUNCTION__))
;
7123 assert(irq->irq_status >= 200)((irq->irq_status >= 200) ? (void) (0) : __assert_fail (
"irq->irq_status >= 200", "nta.c", 7123, __PRETTY_FUNCTION__
))
;
7124 assert(irq->irq_method == sip_method_invite)((irq->irq_method == sip_method_invite) ? (void) (0) : __assert_fail
("irq->irq_method == sip_method_invite", "nta.c", 7124, __PRETTY_FUNCTION__
))
;
7125
7126 now = su_time_ms(su_now());
7127
7128 if ((int32_t)(irq->irq_timeout - now) > 0 ||
7129 terminated >= timer_max_terminate)
7130 break;
7131
7132 /* Timer I */
7133 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__
, 7134, "nta: timer %s fired, %s %u response\n", "I", "terminate"
, irq->irq_status)) : (void)0)
7134 "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__
, 7134, "nta: timer %s fired, %s %u response\n", "I", "terminate"
, irq->irq_status)) : (void)0)
;
7135
7136 terminated++;
7137 irq->irq_terminated = 1;
7138
7139 if (!irq->irq_destroyed)
7140 incoming_queue(sa->sa_in.terminated, irq);
7141 else
7142 incoming_free_queue(rq, irq);
7143 }
7144
7145 while ((irq = sa->sa_in.completed->q_head)) {
7146 assert(irq->irq_status >= 200)((irq->irq_status >= 200) ? (void) (0) : __assert_fail (
"irq->irq_status >= 200", "nta.c", 7146, __PRETTY_FUNCTION__
))
;
7147 assert(irq->irq_timeout)((irq->irq_timeout) ? (void) (0) : __assert_fail ("irq->irq_timeout"
, "nta.c", 7147, __PRETTY_FUNCTION__))
;
7148 assert(irq->irq_method != sip_method_invite)((irq->irq_method != sip_method_invite) ? (void) (0) : __assert_fail
("irq->irq_method != sip_method_invite", "nta.c", 7148, __PRETTY_FUNCTION__
))
;
7149
7150 now = su_time_ms(su_now());
7151
7152 if ((int32_t)(irq->irq_timeout - now) > 0 ||
7153 terminated >= timer_max_terminate)
7154 break;
7155
7156 /* Timer J */
7157
7158 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__
, 7159, "nta: timer %s fired, %s %u response\n", "J", "terminate"
, irq->irq_status)) : (void)0)
7159 "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__
, 7159, "nta: timer %s fired, %s %u response\n", "J", "terminate"
, irq->irq_status)) : (void)0)
;
7160
7161 terminated++;
7162 irq->irq_terminated = 1;
7163
7164 if (!irq->irq_destroyed)
7165 incoming_queue(sa->sa_in.terminated, irq);
7166 else
7167 incoming_free_queue(rq, irq);
7168 }
7169
7170 for (irq = sa->sa_in.terminated->q_head; irq; irq = irq_next) {
7171
7172 irq_next = irq->irq_next;
7173 if (irq->irq_destroyed)
7174 incoming_free_queue(rq, irq);
7175 }
7176
7177 destroyed = incoming_mass_destroy(sa, rq);
7178
7179 if (retransmitted || timeout || terminated || destroyed)
7180 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__
, 7188, "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)
7181 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__
, 7188, "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)
7182 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__
, 7188, "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)
7183 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__
, 7188, "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)
7184 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__
, 7188, "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)
7185 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__
, 7188, "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)
7186 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__
, 7188, "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)
7187 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__
, 7188, "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)
7188 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__
, 7188, "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)
;
7189}
7190
7191/** Mass destroy server transactions */
7192su_inlinestatic inline
7193size_t incoming_mass_destroy(nta_agent_t *sa, incoming_queue_t *q)
7194{
7195 size_t destroyed = q->q_length;
7196
7197 if (destroyed > 2 && *sa->sa_terminator) {
7198 su_msg_r m = SU_MSG_R_INIT{ ((void*)0) };
7199
7200 if (su_msg_create(m,
7201 su_clone_task(sa->sa_terminator),
7202 su_root_task(sa->sa_root),
7203 incoming_reclaim_queued,
7204 sizeof(incoming_queue_t)) == SU_SUCCESSsu_success) {
7205 incoming_queue_t *mq = su_msg_data(m)->a_incoming_queue;
7206
7207 *mq = *q;
7208
7209 if (su_msg_send(m) == SU_SUCCESSsu_success)
7210 q->q_length = 0;
7211 }
7212 }
7213
7214 if (q->q_length > 0)
7215 incoming_reclaim_queued(NULL((void*)0), NULL((void*)0), (void *)q);
7216
7217 return destroyed;
7218}
7219
7220/* ====================================================================== */
7221/* 8) Client-side (outgoing) transactions */
7222
7223#define HTABLE_HASH_ORQ(orq)((orq)->orq_hash) ((orq)->orq_hash)
7224
7225#ifdef __clang__1
7226#pragma clang diagnostic push
7227#pragma clang diagnostic ignored "-Wunused-function"
7228#endif
7229
7230HTABLE_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, ((i != i0) ? (void) (0) : __assert_fail
("i != i0", "nta.c", 7231, __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; ((oht-> oht_used == used) ? (void
) (0) : __assert_fail ("oht-> oht_used == used", "nta.c", 7231
, __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
7231 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, ((i != i0) ? (void) (0) : __assert_fail
("i != i0", "nta.c", 7231, __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; ((oht-> oht_used == used) ? (void
) (0) : __assert_fail ("oht-> oht_used == used", "nta.c", 7231
, __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
;
7232
7233#ifdef __clang__1
7234#pragma clang diagnostic pop
7235#endif
7236
7237static int outgoing_features(nta_agent_t *agent, nta_outgoing_t *orq,
7238 msg_t *msg, sip_t *sip,
7239 tagi_t *tags);
7240static void outgoing_prepare_send(nta_outgoing_t *orq);
7241static void outgoing_send_via(nta_outgoing_t *orq, tport_t *tp);
7242static void outgoing_send(nta_outgoing_t *orq, int retransmit);
7243static void outgoing_try_tcp_instead(nta_outgoing_t *orq);
7244static void outgoing_try_udp_instead(nta_outgoing_t *orq, int timeout);
7245static void outgoing_tport_error(nta_agent_t *agent, nta_outgoing_t *orq,
7246 tport_t *tp, msg_t *msg, int error);
7247static void outgoing_print_tport_error(nta_outgoing_t *orq,
7248 int level, char *todo,
7249 tp_name_t const *, msg_t *, int error);
7250static void outgoing_insert(nta_agent_t *sa, nta_outgoing_t *orq);
7251static void outgoing_destroy(nta_outgoing_t *orq);
7252su_inlinestatic inline int outgoing_is_queued(nta_outgoing_t const *orq);
7253su_inlinestatic inline void outgoing_queue(outgoing_queue_t *queue,
7254 nta_outgoing_t *orq);
7255su_inlinestatic inline void outgoing_remove(nta_outgoing_t *orq);
7256su_inlinestatic inline void outgoing_set_timer(nta_outgoing_t *orq, uint32_t interval);
7257static void outgoing_reset_timer(nta_outgoing_t *orq);
7258static size_t outgoing_timer_dk(outgoing_queue_t *q,
7259 char const *timer,
7260 uint32_t now);
7261static size_t outgoing_timer_bf(outgoing_queue_t *q,
7262 char const *timer,
7263 uint32_t now);
7264static size_t outgoing_timer_c(outgoing_queue_t *q,
7265 char const *timer,
7266 uint32_t now);
7267
7268static void outgoing_ack(nta_outgoing_t *orq, sip_t *sip);
7269static msg_t *outgoing_ackmsg(nta_outgoing_t *, sip_method_t, char const *,
7270 tag_type_t tag, tag_value_t value, ...);
7271static void outgoing_retransmit(nta_outgoing_t *orq);
7272static void outgoing_trying(nta_outgoing_t *orq);
7273static void outgoing_timeout(nta_outgoing_t *orq, uint32_t now);
7274static int outgoing_complete(nta_outgoing_t *orq);
7275static void outgoing_terminate_invite(nta_outgoing_t *);
7276static void outgoing_remove_fork(nta_outgoing_t *orq);
7277static int outgoing_terminate(nta_outgoing_t *orq);
7278static size_t outgoing_mass_destroy(nta_agent_t *sa, outgoing_queue_t *q);
7279static void outgoing_estimate_delay(nta_outgoing_t *orq, sip_t *sip);
7280static int outgoing_duplicate(nta_outgoing_t *orq,
7281 msg_t *msg,
7282 sip_t *sip);
7283static int outgoing_reply(nta_outgoing_t *orq,
7284 int status, char const *phrase,
7285 int delayed);
7286
7287static int outgoing_default_cb(nta_outgoing_magic_t *magic,
7288 nta_outgoing_t *request,
7289 sip_t const *sip);
7290
7291
7292/** Create a default outgoing transaction.
7293 *
7294 * The default outgoing transaction is used when agent receives responses
7295 * not belonging to any transaction.
7296 *
7297 * @sa nta_leg_default(), nta_incoming_default().
7298 */
7299nta_outgoing_t *nta_outgoing_default(nta_agent_t *agent,
7300 nta_response_f *callback,
7301 nta_outgoing_magic_t *magic)
7302{
7303 nta_outgoing_t *orq;
7304
7305 if (agent == NULL((void*)0))
7306 return NULL((void*)0);
7307
7308 if (agent->sa_default_outgoing)
7309 return NULL((void*)0);
7310
7311 orq = su_zalloc(agent->sa_home, sizeof *orq);
7312 if (!orq)
7313 return NULL((void*)0);
7314
7315 orq->orq_agent = agent;
7316 orq->orq_callback = callback;
7317 orq->orq_magic = magic;
7318 orq->orq_method = sip_method_invalid;
7319 orq->orq_method_name = "*";
7320 orq->orq_default = 1;
7321 orq->orq_stateless = 1;
7322 orq->orq_delay = UINT_MAX(2147483647 *2U +1U);
7323
7324 return agent->sa_default_outgoing = orq;
7325}
7326
7327/**Create an outgoing request and client transaction belonging to the leg.
7328 *
7329 * Create a request message and pass the request message to an outgoing
7330 * client transaction object. The request is sent to the @a route_url (if
7331 * non-NULL), default proxy (if defined by NTATAG_DEFAULT_PROXY()), or to
7332 * the address specified by @a request_uri. If no @a request_uri is
7333 * specified, it is taken from route-set target or from the @To header.
7334 *
7335 * When NTA receives response to the request, it invokes the @a callback
7336 * function.
7337 *
7338 * @param leg call leg object
7339 * @param callback callback function (may be @c NULL)
7340 * @param magic application context pointer
7341 * @param route_url optional URL used to route transaction requests
7342 * @param method method type
7343 * @param name method name
7344 * @param request_uri Request-URI
7345 * @param tag, value, ... list of tagged arguments
7346 *
7347 * @return
7348 * A pointer to a newly created outgoing transaction object if successful,
7349 * and NULL otherwise.
7350 *
7351 * @note If NTATAG_STATELESS(1) tag is given and the @a callback is NULL,
7352 * the transaction object is marked as destroyed from the beginning. In that
7353 * case, the function may return @code (nta_outgoing_t *)-1 @endcode if the
7354 * transaction is freed before returning from the function.
7355 *
7356 * @sa
7357 * nta_outgoing_mcreate(), nta_outgoing_tcancel(), nta_outgoing_destroy().
7358 *
7359 * @TAGS
7360 * NTATAG_STATELESS(), NTATAG_DELAY_SENDING(), NTATAG_BRANCH_KEY(),
7361 * NTATAG_ACK_BRANCH(), NTATAG_DEFAULT_PROXY(), NTATAG_PASS_100(),
7362 * NTATAG_USE_TIMESTAMP(), NTATAG_USER_VIA(), TPTAG_IDENT(), NTATAG_TPORT(). All
7363 * SIP tags from <sofia-sip/sip_tag.h> can be used to manipulate the request message.
7364 * SIP tags after SIPTAG_END() are ignored, however.
7365 */
7366nta_outgoing_t *nta_outgoing_tcreate(nta_leg_t *leg,
7367 nta_response_f *callback,
7368 nta_outgoing_magic_t *magic,
7369 url_string_t const *route_url,
7370 sip_method_t method,
7371 char const *name,
7372 url_string_t const *request_uri,
7373 tag_type_t tag, tag_value_t value, ...)
7374{
7375 nta_agent_t *agent;
7376 msg_t *msg;
7377 sip_t *sip;
7378 nta_outgoing_t *orq = NULL((void*)0);
7379 ta_list ta;
7380 tagi_t const *tagi;
7381
7382 if (leg == NULL((void*)0))
7383 return NULL((void*)0);
7384
7385 agent = leg->leg_agent;
7386 msg = nta_msg_create(agent, 0);
7387 sip = sip_object(msg);
7388
7389 if (route_url == NULL((void*)0))
7390 route_url = (url_string_t *)agent->sa_default_proxy;
7391
7392 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)
;
7393
7394 tagi = ta_args(ta)(ta).tl;
7395
7396 if (sip_add_tagis(msg, sip, &tagi) < 0) {
7397 if (tagi && tagi->t_tag) {
7398 tag_type_t t = tagi->t_tag;
7399 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__
, 7400, "%s(): bad tag %s::%s\n", __func__, t->tt_ns ? t->
tt_ns : "", t->tt_name ? t->tt_name : "")) : (void)0)
7400 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__
, 7400, "%s(): bad tag %s::%s\n", __func__, t->tt_ns ? t->
tt_ns : "", t->tt_name ? t->tt_name : "")) : (void)0)
;
7401 }
7402 }
7403 else if (route_url == NULL((void*)0) && leg->leg_route &&
7404 leg->leg_loose_route &&
7405 !(route_url = (url_string_t *)leg->leg_route->r_url))
7406 ;
7407 else if (nta_msg_request_complete(msg, leg, method, name, request_uri) < 0)
7408 ;
7409 else
7410 orq = outgoing_create(agent, callback, magic, route_url, NULL((void*)0), msg,
7411 ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
);
7412
7413 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))
;
7414
7415 if (!orq)
7416 msg_destroy(msg);
7417
7418 return orq;
7419}
7420
7421/**Create an outgoing client transaction.
7422 *
7423 * Create an outgoing transaction object. The request message is passed to
7424 * the transaction object, which sends the request to the network. The
7425 * request is sent to the @a route_url (if non-NULL), default proxy (if
7426 * defined by NTATAG_DEFAULT_PROXY()), or to the address specified by @a
7427 * request_uri. If no @a request_uri is specified, it is taken from
7428 * route-set target or from the @To header.
7429 *
7430 * When NTA receives response to the request, it invokes the @a callback
7431 * function.
7432 *
7433 * @param agent NTA agent object
7434 * @param callback callback function (may be @c NULL)
7435 * @param magic application context pointer
7436 * @param route_url optional URL used to route transaction requests
7437 * @param msg request message
7438 * @param tag, value, ... tagged parameter list
7439 *
7440 * @return
7441 * Returns a pointer to newly created outgoing transaction object if
7442 * successful, and NULL otherwise.
7443 *
7444 * @note The caller is responsible for destroying the request message @a msg
7445 * upon failure.
7446 *
7447 * @note If NTATAG_STATELESS(1) tag is given and the @a callback is NULL,
7448 * the transaction object is marked as destroyed from the beginning. In that
7449 * case, the function may return @code (nta_outgoing_t *)-1 @endcode if the
7450 * transaction is freed before returning from the function.
7451 *
7452 * @sa
7453 * nta_outgoing_tcreate(), nta_outgoing_tcancel(), nta_outgoing_destroy().
7454 *
7455 * @TAGS
7456 * NTATAG_STATELESS(), NTATAG_DELAY_SENDING(), NTATAG_BRANCH_KEY(),
7457 * NTATAG_ACK_BRANCH(), NTATAG_DEFAULT_PROXY(), NTATAG_PASS_100(),
7458 * NTATAG_USE_TIMESTAMP(), NTATAG_USER_VIA(), TPTAG_IDENT(), NTATAG_TPORT(). All
7459 * SIP tags from <sofia-sip/sip_tag.h> can be used to manipulate the request message.
7460 * SIP tags after SIPTAG_END() are ignored, however.
7461 */
7462nta_outgoing_t *nta_outgoing_mcreate(nta_agent_t *agent,
7463 nta_response_f *callback,
7464 nta_outgoing_magic_t *magic,
7465 url_string_t const *route_url,
7466 msg_t *msg,
7467 tag_type_t tag, tag_value_t value, ...)
7468{
7469 nta_outgoing_t *orq = NULL((void*)0);
7470 int cleanup = 0;
7471
7472 if (msg == NONE((void *)-1))
7473 msg = nta_msg_create(agent, 0), cleanup = 1;
7474
7475 if (msg && agent) {
7476 ta_list ta;
7477 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)
;
7478 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)
7479 orq = outgoing_create(agent, callback, magic, route_url, NULL((void*)0), msg,
7480 ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
);
7481 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))
;
7482 }
7483
7484 if (!orq && cleanup)
7485 msg_destroy(msg);
7486
7487 return orq;
7488}
7489
7490/** Cancel the request. */
7491int nta_outgoing_cancel(nta_outgoing_t *orq)
7492{
7493 nta_outgoing_t *cancel =
7494 nta_outgoing_tcancel(orq, NULL((void*)0), NULL((void*)0), TAG_NULL()(tag_type_t)0, (tag_value_t)0);
7495
7496 return (cancel != NULL((void*)0)) - 1;
7497}
7498
7499/** Cancel the request.
7500 *
7501 * Initiate a cancel transaction for client transaction @a orq.
7502 *
7503 * @param orq client transaction to cancel
7504 * @param callback callback function (may be @c NULL)
7505 * @param magic application context pointer
7506 * @param tag, value, ... list of extra arguments
7507 *
7508 * @note The function may return @code (nta_outgoing_t *)-1 @endcode (NONE)
7509 * if callback is NULL.
7510 *
7511 * @TAGS
7512 * NTATAG_CANCEL_2534(), NTATAG_CANCEL_408() and all the tags that are
7513 * accepted by nta_outgoing_tcreate().
7514 *
7515 * If NTATAG_CANCEL_408(1) or NTATAG_CANCEL_2543(1) is given, the stack
7516 * generates a 487 response to the request internally. If
7517 * NTATAG_CANCEL_408(1) is given, no CANCEL request is actually sent.
7518 *
7519 * @note
7520 * nta_outgoing_tcancel() refuses to send a CANCEL request for non-INVITE
7521 * requests.
7522 */
7523nta_outgoing_t *nta_outgoing_tcancel(nta_outgoing_t *orq,
7524 nta_response_f *callback,
7525 nta_outgoing_magic_t *magic,
7526 tag_type_t tag, tag_value_t value, ...)
7527{
7528 msg_t *msg;
7529 int cancel_2543, cancel_408;
7530 ta_list ta;
7531 int delay_sending;
7532
7533 if (orq == NULL((void*)0) || orq == NONE((void *)-1))
7534 return NULL((void*)0);
7535
7536 if (orq->orq_destroyed) {
7537 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__
, 7537, "%s: trying to cancel destroyed request\n", __func__)
) : (void)0)
;
7538 return NULL((void*)0);
7539 }
7540 if (orq->orq_method != sip_method_invite) {
7541 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__
, 7541, "%s: trying to cancel non-INVITE request\n", __func__
)) : (void)0)
;
7542 return NULL((void*)0);
7543 }
7544
7545 if (orq->orq_forking)
7546 orq = orq->orq_forking;
7547
7548 if (orq->orq_status >= 200
7549 /* && orq->orq_method != sip_method_invite ... !multicast */) {
7550 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__
, 7550, "%s: trying to cancel completed request\n", __func__)
) : (void)0)
;
7551 return NULL((void*)0);
7552 }
7553 if (orq->orq_canceled) {
7554 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__
, 7554, "%s: trying to cancel cancelled request\n", __func__)
) : (void)0)
;
7555 return NULL((void*)0);
7556 }
7557 orq->orq_canceled = 1;
7558
7559#if HAVE_SOFIA_SRESOLV1
7560 if (!orq->orq_resolved) {
7561 outgoing_destroy_resolver(orq);
7562 outgoing_reply(orq, SIP_487_REQUEST_CANCELLED487, sip_487_Request_terminated, 1);
7563 return NULL((void*)0); /* XXX - Does anyone care about reply? */
7564 }
7565#endif
7566
7567 cancel_408 = 0; /* Don't really CANCEL, this is timeout. */
7568 cancel_2543 = orq->orq_agent->sa_cancel_2543;
7569 /* CANCEL may be sent only after a provisional response has been received. */
7570 delay_sending = orq->orq_status < 100;
7571
7572 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)
;
7573
7574 tl_gets(ta_args(ta)(ta).tl,
7575 NTATAG_CANCEL_408_REF(cancel_408)ntatag_cancel_408_ref, tag_bool_vr(&(cancel_408)),
7576 NTATAG_CANCEL_2543_REF(cancel_2543)ntatag_cancel_2543_ref, tag_bool_vr(&(cancel_2543)),
7577 TAG_END()(tag_type_t)0, (tag_value_t)0);
7578
7579 if (!cancel_408)
7580 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
);
7581 else
7582 msg = NULL((void*)0);
7583
7584 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))
;
7585
7586 if ((cancel_2543 || cancel_408) && !orq->orq_stateless)
7587 outgoing_reply(orq, SIP_487_REQUEST_CANCELLED487, sip_487_Request_terminated, 1);
7588
7589 if (msg) {
7590 nta_outgoing_t *cancel;
7591 if (cancel_2543) /* Follow RFC 2543 semantics for CANCEL */
7592 delay_sending = 0;
7593
7594 cancel = outgoing_create(orq->orq_agent, callback, magic,
7595 NULL((void*)0), orq->orq_tpn, msg,
7596 NTATAG_BRANCH_KEY(orq->orq_branch)ntatag_branch_key, tag_str_v((orq->orq_branch)),
7597 NTATAG_DELAY_SENDING(delay_sending)ntatag_delay_sending, tag_bool_v((delay_sending)),
7598 NTATAG_USER_VIA(1)ntatag_user_via, tag_bool_v((1)),
7599 TAG_END()(tag_type_t)0, (tag_value_t)0);
7600
7601 if (delay_sending)
7602 orq->orq_cancel = cancel;
7603
7604 if (cancel) {
7605 if (!delay_sending)
7606 outgoing_complete(orq);
7607 return cancel;
7608 }
7609
7610 msg_destroy(msg);
7611 }
7612
7613 return NULL((void*)0);
7614}
7615
7616/**Bind callback and application context to a client transaction.
7617 *
7618 * @param orq outgoing client transaction
7619 * @param callback callback function (may be NULL)
7620 * @param magic application context pointer
7621 * (given as argument to @a callback)
7622 *
7623 * @NEW_1_12_9
7624 */
7625int
7626nta_outgoing_bind(nta_outgoing_t *orq,
7627 nta_response_f *callback,
7628 nta_outgoing_magic_t *magic)
7629{
7630 if (orq && !orq->orq_destroyed) {
7631 if (callback == NULL((void*)0))
7632 callback = outgoing_default_cb;
7633 orq->orq_callback = callback;
7634 orq->orq_magic = magic;
7635 return 0;
7636 }
7637 return -1;
7638}
7639
7640/**Get application context bound to a client transaction.
7641 *
7642 * @param orq outgoing client transaction
7643 * @param callback callback function (may be NULL)
7644 *
7645 * Return the application context bound to a client transaction. If the @a
7646 * callback function pointer is given, return application context only if
7647 * the callback matches with the callback bound to the client transaction.
7648 *
7649 * @NEW_1_12_11
7650 */
7651nta_outgoing_magic_t *
7652nta_outgoing_magic(nta_outgoing_t const *orq,
7653 nta_response_f *callback)
7654{
7655 if (orq && (callback == NULL((void*)0) || callback == orq->orq_callback))
7656 return orq->orq_magic;
7657 else
7658 return NULL((void*)0);
7659}
7660
7661
7662/**
7663 * Destroy a request object.
7664 *
7665 * @note
7666 * This function does not actually free the object, but marks it as
7667 * disposable. The object is freed after a timeout.
7668 */
7669void nta_outgoing_destroy(nta_outgoing_t *orq)
7670{
7671 if (orq == NULL((void*)0) || orq == NONE((void *)-1))
7672 return;
7673
7674 if (orq->orq_destroyed) {
7675 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__
, 7676, "%s(%p): %s\n", "nta_outgoing_destroy", (void *)orq, "already destroyed"
)) : (void)0)
7676 "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__
, 7676, "%s(%p): %s\n", "nta_outgoing_destroy", (void *)orq, "already destroyed"
)) : (void)0)
;
7677 return;
7678 }
7679
7680 outgoing_destroy(orq);
7681}
7682
7683/** Return the request URI */
7684url_t const *nta_outgoing_request_uri(nta_outgoing_t const *orq)
7685{
7686 return orq != NULL((void*)0) && orq != NONE((void *)-1) ? orq->orq_url : NULL((void*)0);
7687}
7688
7689/** Return the URI used to route the request */
7690url_t const *nta_outgoing_route_uri(nta_outgoing_t const *orq)
7691{
7692 return orq != NULL((void*)0) && orq != NONE((void *)-1) ? orq->orq_route : NULL((void*)0);
7693}
7694
7695/** Return method of the client transaction */
7696sip_method_t nta_outgoing_method(nta_outgoing_t const *orq)
7697{
7698 return orq != NULL((void*)0) && orq != NONE((void *)-1) ? orq->orq_method : sip_method_invalid;
7699}
7700
7701/** Return method name of the client transaction */
7702char const *nta_outgoing_method_name(nta_outgoing_t const *orq)
7703{
7704 return orq != NULL((void*)0) && orq != NONE((void *)-1) ? orq->orq_method_name : NULL((void*)0);
7705}
7706
7707/** Get sequence number of a client transaction.
7708 */
7709uint32_t nta_outgoing_cseq(nta_outgoing_t const *orq)
7710{
7711 return orq != NULL((void*)0) && orq != NONE((void *)-1) && orq->orq_cseq
7712 ? orq->orq_cseq->cs_seq : 0;
7713}
7714
7715/**
7716 * Get the status code of a client transaction.
7717 */
7718int nta_outgoing_status(nta_outgoing_t const *orq)
7719{
7720 /* Return 500 Internal server error for invalid handles. */
7721 return orq != NULL((void*)0) && orq != NONE((void *)-1) ? orq->orq_status : 500;
7722}
7723
7724/** Get the RTT delay measured using @Timestamp header. */
7725unsigned nta_outgoing_delay(nta_outgoing_t const *orq)
7726{
7727 return orq != NULL((void*)0) && orq != NONE((void *)-1) ? orq->orq_delay : UINT_MAX(2147483647 *2U +1U);
7728}
7729
7730/** Get the branch parameter. @NEW_1_12_7. */
7731char const *nta_outgoing_branch(nta_outgoing_t const *orq)
7732{
7733 return orq != NULL((void*)0) && orq != NONE((void *)-1) && orq->orq_branch
7734 ? orq->orq_branch + strlen("branch=")
7735 : NULL((void*)0);
7736}
7737
7738/**Get reference to response message.
7739 *
7740 * Retrieve the latest incoming response message to the outgoing
7741 * transaction. Note that the message is not copied, but a new reference to
7742 * it is created instead.
7743 *
7744 * @param orq outgoing transaction handle
7745 *
7746 * @retval
7747 * A pointer to response message is returned, or NULL if no response message
7748 * has been received.
7749 */
7750msg_t *nta_outgoing_getresponse(nta_outgoing_t *orq)
7751{
7752 if (orq != NULL((void*)0) && orq != NONE((void *)-1))
7753 return msg_ref_create(orq->orq_response);
7754 else
7755 return NULL((void*)0);
7756}
7757
7758/**Get request message.
7759 *
7760 * Retrieves the request message sent to the network. Note that the request
7761 * message is @b not copied, but a new reference to it is created.
7762 *
7763 * @retval
7764 * A pointer to the request message is returned, or NULL if an error
7765 * occurred.
7766 */
7767msg_t *nta_outgoing_getrequest(nta_outgoing_t *orq)
7768{
7769 if (orq != NULL((void*)0) && orq != NONE((void *)-1))
7770 return msg_ref_create(orq->orq_request);
7771 else
7772 return NULL((void*)0);
7773}
7774
7775/**Create an outgoing request.
7776 *
7777 * Create an outgoing transaction object and send the request to the
7778 * network. The request is sent to the @a route_url (if non-NULL), default
7779 * proxy (if defined by NTATAG_DEFAULT_PROXY()), or to the address specified
7780 * by @a sip->sip_request->rq_url.
7781 *
7782 * When NTA receives response to the request, it invokes the @a callback
7783 * function.
7784 *
7785 * @param agent nta agent object
7786 * @param callback callback function (may be @c NULL)
7787 * @param magic application context pointer
7788 * @param route_url optional URL used to route transaction requests
7789 * @param msg request message
7790 * @param tpn (optional) transport name
7791 * @param msg request message to
7792 * @param tag, value, ... tagged arguments
7793 *
7794 * @return
7795 * Returns a pointer to newly created outgoing transaction object if
7796 * successful, and NULL otherwise.
7797 *
7798 * @note If NTATAG_STATELESS(1) tag is given and the @a callback is NULL,
7799 * the transaction object is marked as destroyed from the beginning. In that
7800 * case, the function may return @code (nta_outgoing_t *)-1 @endcode if the
7801 * transaction is freed before returning from the function.
7802 *
7803 * @TAG NTATAG_TPORT must point to an existing transport object for
7804 * 'agent' (the passed tport is otherwise ignored).
7805 *
7806 * @sa
7807 * nta_outgoing_tcreate(), nta_outgoing_tcancel(), nta_outgoing_destroy().
7808 */
7809nta_outgoing_t *outgoing_create(nta_agent_t *agent,
7810 nta_response_f *callback,
7811 nta_outgoing_magic_t *magic,
7812 url_string_t const *route_url,
7813 tp_name_t const *tpn,
7814 msg_t *msg,
7815 tag_type_t tag, tag_value_t value, ...)
7816{
7817 nta_outgoing_t *orq;
7818 sip_t *sip;
7819 su_home_t *home;
7820 char const *comp = NONE((void *)-1);
7821 char const *branch = NONE((void *)-1);
7822 char const *ack_branch = NONE((void *)-1);
7823 char const *tp_ident;
7824 int delay_sending = 0, sigcomp_zap = 0;
7825 int pass_100 = agent->sa_pass_100, use_timestamp = agent->sa_timestamp;
7826 enum nta_res_order_e res_order = agent->sa_res_order;
7827 struct sigcomp_compartment *cc = NULL((void*)0);
7828 ta_list ta;
7829 char const *scheme = NULL((void*)0);
7830 char const *port = NULL((void*)0);
7831 int invalid, resolved = 0, stateless = 0, user_via = agent->sa_user_via;
7832 int invite_100rel = agent->sa_invite_100rel;
7833 int explicit_transport = 1;
7834
7835 tagi_t const *t;
7836 tport_t *override_tport = NULL((void*)0);
7837
7838 if (!agent->sa_tport_ip6)
7839 res_order = nta_res_ip4_only;
7840 else if (!agent->sa_tport_ip4)
7841 res_order = nta_res_ip6_only;
7842
7843 if (!callback)
7844 callback = outgoing_default_cb;
7845 if (!route_url)
7846 route_url = (url_string_t *)agent->sa_default_proxy;
7847
7848 sip = sip_object(msg);
7849 home = msg_home(msg)((su_home_t*)(msg));
7850
7851#ifdef HAVE_ZLIB_COMPRESS1
7852 sip_content_encoding_Xflate(msg, sip_object(msg), 0, 1);
7853#endif
7854
7855 if (!sip->sip_request || sip_complete_message(msg) < 0) {
7856 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__
, 7856, "nta: outgoing_create: incomplete request\n" "%s", ""
)) : (void)0)
;
7857 return NULL((void*)0);
7858 }
7859
7860 if (!route_url && !tpn && sip->sip_route &&
7861 sip->sip_route->r_url->url_params &&
7862 url_param(sip->sip_route->r_url->url_params, "lr", NULL((void*)0), 0))
7863 route_url = (url_string_t *)sip->sip_route->r_url;
7864
7865 if (!(orq = su_zalloc(agent->sa_home, sizeof(*orq))))
7866 return NULL((void*)0);
7867
7868 tp_ident = tpn ? tpn->tpn_ident : NULL((void*)0);
7869
7870 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)
;
7871
7872 /* tl_gets() is a bit too slow here... */
7873 for (t = ta_args(ta)(ta).tl; t; t = tl_next(t)) {
7874 tag_type_t tt = t->t_tag;
7875
7876 if (ntatag_stateless == tt)
7877 stateless = t->t_value != 0;
7878 else if (ntatag_delay_sending == tt)
7879 delay_sending = t->t_value != 0;
7880 else if (ntatag_branch_key == tt)
7881 branch = (void *)t->t_value;
7882 else if (ntatag_pass_100 == tt)
7883 pass_100 = t->t_value != 0;
7884 else if (ntatag_use_timestamp == tt)
7885 use_timestamp = t->t_value != 0;
7886 else if (ntatag_user_via == tt)
7887 user_via = t->t_value != 0;
7888 else if (ntatag_ack_branch == tt)
7889 ack_branch = (void *)t->t_value;
7890 else if (ntatag_default_proxy == tt)
7891 route_url = (void *)t->t_value;
7892 else if (tptag_ident == tt)
7893 tp_ident = (void *)t->t_value;
7894 else if (ntatag_comp == tt)
7895 comp = (char const *)t->t_value;
7896 else if (ntatag_sigcomp_close == tt)
7897 sigcomp_zap = t->t_value != 0;
7898 else if (tptag_compartment == tt)
7899 cc = (void *)t->t_value;
7900 else if (ntatag_tport == tt) {
7901 override_tport = (tport_t *)t->t_value;
7902 }
7903 else if (ntatag_rel100 == tt) {
7904 invite_100rel = t->t_value != 0;
7905 }
7906 }
7907
7908 orq->orq_agent = agent;
7909 orq->orq_callback = callback;
7910 orq->orq_magic = magic;
7911 orq->orq_method = sip->sip_request->rq_method;
7912 orq->orq_method_name = sip->sip_request->rq_method_name;
7913 orq->orq_cseq = sip->sip_cseq;
7914 orq->orq_to = sip->sip_to;
7915 orq->orq_from = sip->sip_from;
7916 orq->orq_call_id = sip->sip_call_id;
7917 orq->orq_tags = tl_afilter(home, tport_tags, ta_args(ta)(ta).tl);
7918 orq->orq_delayed = delay_sending != 0;
7919 orq->orq_pass_100 = pass_100 != 0;
7920 orq->orq_sigcomp_zap = sigcomp_zap;
7921 orq->orq_sigcomp_new = comp != NONE((void *)-1) && comp != NULL((void*)0);
7922 orq->orq_timestamp = use_timestamp;
7923 orq->orq_delay = UINT_MAX(2147483647 *2U +1U);
7924 orq->orq_stateless = stateless != 0;
7925 orq->orq_user_via = user_via != 0 && sip->sip_via;
7926 orq->orq_100rel = invite_100rel;
7927 orq->orq_uas = !stateless && agent->sa_is_a_uas;
7928
7929 if (cc)
7930 orq->orq_cc = nta_compartment_ref(cc);
7931
7932 /* Add supported features */
7933 outgoing_features(agent, orq, msg, sip, ta_args(ta)(ta).tl);
7934
7935 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))
;
7936
7937 /* select the tport to use for the outgoing message */
7938 if (override_tport) {
7939 /* note: no ref taken to the tport as its only used once here */
7940 if (tport_is_secondary(override_tport)) {
7941 tpn = tport_name(override_tport);
7942 orq->orq_user_tport = 1;
7943 }
7944 }
7945
7946 if (tpn) {
7947 /* CANCEL or ACK to [3456]XX */
7948 invalid = tport_name_dup(home, orq->orq_tpn, tpn);
7949#if 0 //HAVE_SOFIA_SRESOLV
7950 /* We send ACK or CANCEL only if original request was really sent */
7951 assert(tport_name_is_resolved(orq->orq_tpn))((tport_name_is_resolved(orq->orq_tpn)) ? (void) (0) : __assert_fail
("tport_name_is_resolved(orq->orq_tpn)", "nta.c", 7951, __PRETTY_FUNCTION__
))
;
7952#endif
7953 resolved = tport_name_is_resolved(orq->orq_tpn);
7954 orq->orq_url = url_hdup(home, sip->sip_request->rq_url);
7955 }
7956 else if (route_url && !orq->orq_user_tport) {
7957 invalid = nta_tpn_by_url(home, orq->orq_tpn, &scheme, &port, route_url);
7958 if (invalid >= 0) {
7959 explicit_transport = invalid > 0;
7960 if (override_tport) { /* Use transport protocol name from transport */
7961 if (strcmp(orq->orq_tpn->tpn_proto, "*")__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(orq->orq_tpn->tpn_proto) && __builtin_constant_p
("*") && (__s1_len = __builtin_strlen (orq->orq_tpn
->tpn_proto), __s2_len = __builtin_strlen ("*"), (!((size_t
)(const void *)((orq->orq_tpn->tpn_proto) + 1) - (size_t
)(const void *)(orq->orq_tpn->tpn_proto) == 1) || __s1_len
>= 4) && (!((size_t)(const void *)(("*") + 1) - (
size_t)(const void *)("*") == 1) || __s2_len >= 4)) ? __builtin_strcmp
(orq->orq_tpn->tpn_proto, "*") : (__builtin_constant_p
(orq->orq_tpn->tpn_proto) && ((size_t)(const void
*)((orq->orq_tpn->tpn_proto) + 1) - (size_t)(const void
*)(orq->orq_tpn->tpn_proto) == 1) && (__s1_len
= __builtin_strlen (orq->orq_tpn->tpn_proto), __s1_len
< 4) ? (__builtin_constant_p ("*") && ((size_t)(const
void *)(("*") + 1) - (size_t)(const void *)("*") == 1) ? __builtin_strcmp
(orq->orq_tpn->tpn_proto, "*") : (__extension__ ({ const
unsigned char *__s2 = (const unsigned char *) (const char *)
("*"); int __result = (((const unsigned char *) (const char *
) (orq->orq_tpn->tpn_proto))[0] - __s2[0]); if (__s1_len
> 0 && __result == 0) { __result = (((const unsigned
char *) (const char *) (orq->orq_tpn->tpn_proto))[1] -
__s2[1]); if (__s1_len > 1 && __result == 0) { __result
= (((const unsigned char *) (const char *) (orq->orq_tpn->
tpn_proto))[2] - __s2[2]); if (__s1_len > 2 && __result
== 0) __result = (((const unsigned char *) (const char *) (orq
->orq_tpn->tpn_proto))[3] - __s2[3]); } } __result; }))
) : (__builtin_constant_p ("*") && ((size_t)(const void
*)(("*") + 1) - (size_t)(const void *)("*") == 1) &&
(__s2_len = __builtin_strlen ("*"), __s2_len < 4) ? (__builtin_constant_p
(orq->orq_tpn->tpn_proto) && ((size_t)(const void
*)((orq->orq_tpn->tpn_proto) + 1) - (size_t)(const void
*)(orq->orq_tpn->tpn_proto) == 1) ? __builtin_strcmp (
orq->orq_tpn->tpn_proto, "*") : (- (__extension__ ({ const
unsigned char *__s2 = (const unsigned char *) (const char *)
(orq->orq_tpn->tpn_proto); int __result = (((const unsigned
char *) (const char *) ("*"))[0] - __s2[0]); if (__s2_len >
0 && __result == 0) { __result = (((const unsigned char
*) (const char *) ("*"))[1] - __s2[1]); if (__s2_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) ("*"))[2] - __s2[2]); if (__s2_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) ("*"))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp
(orq->orq_tpn->tpn_proto, "*")))); })
== 0)
7962 orq->orq_tpn->tpn_proto = tport_name(override_tport)->tpn_proto;
7963 }
7964
7965 resolved = tport_name_is_resolved(orq->orq_tpn);
7966 orq->orq_url = url_hdup(home, sip->sip_request->rq_url);
7967 if (route_url != (url_string_t *)agent->sa_default_proxy)
7968 orq->orq_route = url_hdup(home, route_url->us_url);
7969 }
7970 }
7971 else {
7972 invalid = nta_tpn_by_url(home, orq->orq_tpn, &scheme, &port,
7973 (url_string_t *)sip->sip_request->rq_url);
7974 if (invalid >= 0) {
7975 explicit_transport = invalid > 0;
7976 resolved = tport_name_is_resolved(orq->orq_tpn);
7977 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)
;
7978 }
7979 orq->orq_url = url_hdup(home, sip->sip_request->rq_url);
7980 }
7981
7982 if (!override_tport)
7983 orq->orq_tpn->tpn_ident = tp_ident;
7984 else
7985 orq->orq_tpn->tpn_ident = tport_name(override_tport)->tpn_ident;
7986
7987 if (comp == NULL((void*)0))
7988 orq->orq_tpn->tpn_comp = comp;
7989
7990 if (orq->orq_user_via && su_strmatch(orq->orq_tpn->tpn_proto, "*")) {
7991 char const *proto = sip_via_transport(sip->sip_via);
7992 if (proto) orq->orq_tpn->tpn_proto = proto;
7993 }
7994
7995 if (branch && branch != NONE((void *)-1)) {
7996 if (su_casenmatch(branch, "branch=", 7))
7997 branch = su_strdup(home, branch);
7998 else
7999 branch = su_sprintf(home, "branch=%s", branch);
8000 }
8001 else if (orq->orq_user_via && sip->sip_via->v_branch && orq->orq_method != sip_method_invite )
8002 branch = su_sprintf(home, "branch=%s", sip->sip_via->v_branch);
8003 else if (stateless)
8004 branch = stateless_branch(agent, msg, sip, orq->orq_tpn);
8005 else
8006 branch = stateful_branch(home, agent);
8007
8008 orq->orq_branch = branch;
8009 orq->orq_via_branch = branch;
8010
8011 if (orq->orq_method == sip_method_ack) {
8012 /* Find the original INVITE which we are ACKing */
8013 if (ack_branch != NULL((void*)0) && ack_branch != NONE((void *)-1)) {
8014 if (su_casenmatch(ack_branch, "branch=", 7))
8015 orq->orq_branch = su_strdup(home, ack_branch);
8016 else
8017 orq->orq_branch = su_sprintf(home, "branch=%s", ack_branch);
8018 }
8019 else if (orq->orq_uas) {
8020 /*
8021 * ACK redirects further 2XX messages to it.
8022 *
8023 * Use orq_branch from INVITE, but put a different branch in topmost Via.
8024 */
8025 nta_outgoing_t *invite = outgoing_find(agent, msg, sip, NULL((void*)0));
8026
8027 if (invite) {
8028 sip_t const *inv = sip_object(invite->orq_request);
8029
8030 orq->orq_branch = su_strdup(home, invite->orq_branch);
8031
8032 /* @RFC3261 section 13.2.2.4 -
8033 * The ACK MUST contain the same credentials as the INVITE.
8034 */
8035 if (!sip->sip_proxy_authorization && !sip->sip_authorization) {
8036 if (inv->sip_proxy_authorization)
8037 sip_add_dup(msg, sip, (void *)inv->sip_proxy_authorization);
8038 if (inv->sip_authorization)
8039 sip_add_dup(msg, sip, (void *)inv->sip_authorization);
8040 }
8041 }
8042 else {
8043 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__
, 8043, "outgoing_create: ACK without INVITE\n" "%s", "")) : (
void)0)
;
8044 assert(!"INVITE found for ACK")((!"INVITE found for ACK") ? (void) (0) : __assert_fail ("!\"INVITE found for ACK\""
, "nta.c", 8044, __PRETTY_FUNCTION__))
;
8045 }
8046 }
8047 }
8048
8049#if HAVE_SOFIA_SRESOLV1
8050 if (!resolved)
8051 orq->orq_tpn->tpn_port = port;
8052 orq->orq_resolved = resolved;
8053#else
8054 orq->orq_resolved = resolved = 1;
8055#endif
8056 orq->orq_sips = su_casematch(scheme, "sips");
8057
8058 if (invalid < 0 || !orq->orq_branch || msg_serialize(msg, (void *)sip) < 0) {
8059 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__
, 8061, "nta outgoing create: %s\n", invalid < 0 ? "invalid URI"
: !orq->orq_branch ? "no branch" : "invalid message")) : (
void)0)
8060 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__
, 8061, "nta outgoing create: %s\n", invalid < 0 ? "invalid URI"
: !orq->orq_branch ? "no branch" : "invalid message")) : (
void)0)
8061 !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__
, 8061, "nta outgoing create: %s\n", invalid < 0 ? "invalid URI"
: !orq->orq_branch ? "no branch" : "invalid message")) : (
void)0)
;
8062 outgoing_free(orq);
8063 return NULL((void*)0);
8064 }
8065
8066 /* Now we are committed in sending the transaction */
8067 orq->orq_request = msg;
8068 agent->sa_stats->as_client_tr++;
8069 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))
;
8070
8071 if (orq->orq_user_tport)
8072 outgoing_send_via(orq, override_tport);
8073 else if (resolved)
8074 outgoing_prepare_send(orq);
8075#if HAVE_SOFIA_SRESOLV1
8076 else
8077 outgoing_resolve(orq, explicit_transport, res_order);
8078#endif
8079
8080 if (stateless &&
8081 orq->orq_status >= 200 &&
8082 callback == outgoing_default_cb) {
8083 void *retval;
8084
8085 if (orq->orq_status < 300)
8086 retval = (void *)-1; /* NONE */
8087 else
8088 retval = NULL((void*)0), orq->orq_request = NULL((void*)0);
8089
8090 outgoing_free(orq);
8091
8092 return retval;
8093 }
8094
8095 assert(orq->orq_queue)((orq->orq_queue) ? (void) (0) : __assert_fail ("orq->orq_queue"
, "nta.c", 8095, __PRETTY_FUNCTION__))
;
8096
8097 outgoing_insert(agent, orq);
8098
8099 return orq;
8100}
8101
8102/** Prepare sending a request */
8103static void
8104outgoing_prepare_send(nta_outgoing_t *orq)
8105{
8106 nta_agent_t *sa = orq->orq_agent;
8107 tport_t *tp;
8108 tp_name_t *tpn = orq->orq_tpn;
8109
8110 /* Select transport by scheme */
8111 if (orq->orq_sips && strcmp(tpn->tpn_proto, "*")__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(tpn->tpn_proto) && __builtin_constant_p ("*") &&
(__s1_len = __builtin_strlen (tpn->tpn_proto), __s2_len =
__builtin_strlen ("*"), (!((size_t)(const void *)((tpn->tpn_proto
) + 1) - (size_t)(const void *)(tpn->tpn_proto) == 1) || __s1_len
>= 4) && (!((size_t)(const void *)(("*") + 1) - (
size_t)(const void *)("*") == 1) || __s2_len >= 4)) ? __builtin_strcmp
(tpn->tpn_proto, "*") : (__builtin_constant_p (tpn->tpn_proto
) && ((size_t)(const void *)((tpn->tpn_proto) + 1)
- (size_t)(const void *)(tpn->tpn_proto) == 1) &&
(__s1_len = __builtin_strlen (tpn->tpn_proto), __s1_len <
4) ? (__builtin_constant_p ("*") && ((size_t)(const void
*)(("*") + 1) - (size_t)(const void *)("*") == 1) ? __builtin_strcmp
(tpn->tpn_proto, "*") : (__extension__ ({ const unsigned char
*__s2 = (const unsigned char *) (const char *) ("*"); int __result
= (((const unsigned char *) (const char *) (tpn->tpn_proto
))[0] - __s2[0]); if (__s1_len > 0 && __result == 0
) { __result = (((const unsigned char *) (const char *) (tpn->
tpn_proto))[1] - __s2[1]); if (__s1_len > 1 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
tpn->tpn_proto))[2] - __s2[2]); if (__s1_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) (tpn->tpn_proto))[3] - __s2[3]); } } __result; }))) : (
__builtin_constant_p ("*") && ((size_t)(const void *)
(("*") + 1) - (size_t)(const void *)("*") == 1) && (__s2_len
= __builtin_strlen ("*"), __s2_len < 4) ? (__builtin_constant_p
(tpn->tpn_proto) && ((size_t)(const void *)((tpn->
tpn_proto) + 1) - (size_t)(const void *)(tpn->tpn_proto) ==
1) ? __builtin_strcmp (tpn->tpn_proto, "*") : (- (__extension__
({ const unsigned char *__s2 = (const unsigned char *) (const
char *) (tpn->tpn_proto); int __result = (((const unsigned
char *) (const char *) ("*"))[0] - __s2[0]); if (__s2_len >
0 && __result == 0) { __result = (((const unsigned char
*) (const char *) ("*"))[1] - __s2[1]); if (__s2_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) ("*"))[2] - __s2[2]); if (__s2_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) ("*"))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp
(tpn->tpn_proto, "*")))); })
== 0)
8112 tpn->tpn_proto = "tls";
8113
8114 if (!tpn->tpn_port)
8115 tpn->tpn_port = "";
8116
8117 tp = tport_by_name(sa->sa_tports, tpn);
8118
8119 if (tpn->tpn_port[0] == '\0') {
8120 if (orq->orq_sips || tport_has_tls(tp))
8121 tpn->tpn_port = "5061";
8122 else
8123 tpn->tpn_port = "5060";
8124 }
8125
8126 if (tp) {
8127 outgoing_send_via(orq, tp);
8128 }
8129 else if (orq->orq_sips) {
8130 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__
, 8130, "nta outgoing create: no secure transport\n" "%s", ""
)) : (void)0)
;
8131 outgoing_reply(orq, SIP_416_UNSUPPORTED_URI416, sip_416_Unsupported_uri, 1);
8132 }
8133 else {
8134 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__
, 8134, "nta outgoing create: no transport protocol\n" "%s", ""
)) : (void)0)
;
8135 outgoing_reply(orq, 503, "No transport", 1);
8136 }
8137}
8138
8139/** Send request using given transport */
8140static void
8141outgoing_send_via(nta_outgoing_t *orq, tport_t *tp)
8142{
8143 tport_t *old_tp = orq->orq_tport;
8144
8145 orq->orq_tport = tport_ref(tp);
8146
8147 if (orq->orq_pending && tp != old_tp) {
8148 tport_release(old_tp, orq->orq_pending,
8149 orq->orq_request, NULL((void*)0), orq, 0);
8150 orq->orq_pending = 0;
8151 }
8152
8153 if (old_tp) tport_unref(old_tp);
8154
8155 if (outgoing_insert_via(orq, agent_tport_via(tp)) < 0) {
8156 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__
, 8156, "nta outgoing create: cannot insert Via line\n" "%s",
"")) : (void)0)
;
8157 outgoing_reply(orq, 503, "Cannot insert Via", 1);
8158 return;
8159 }
8160
8161#if HAVE_SOFIA_SMIME0
8162 {
8163 sm_object_t *smime = sa->sa_smime;
8164 sip_t *sip = sip_object(orq->orq_request);
8165
8166 if (sa->sa_smime &&
8167 (sip->sip_request->rq_method == sip_method_invite ||
8168 sip->sip_request->rq_method == sip_method_message)) {
8169 msg_prepare(orq->orq_request);
8170 if (sm_encode_message(smime, msg, sip, SM_ID_NULL) < 0) {
8171 outgoing_tport_error(sa, orq, NULL((void*)0),
8172 orq->orq_request, su_errno());
8173 return;
8174 }
8175 }
8176 }
8177#endif
8178
8179 orq->orq_prepared = 1;
8180
8181 if (orq->orq_delayed) {
8182 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__
, 8183, "nta: delayed sending %s (%u)\n", orq->orq_method_name
, orq->orq_cseq->cs_seq)) : (void)0)
8183 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__
, 8183, "nta: delayed sending %s (%u)\n", orq->orq_method_name
, orq->orq_cseq->cs_seq)) : (void)0)
;
8184 outgoing_queue(orq->orq_agent->sa_out.delayed, orq);
8185 return;
8186 }
8187
8188 outgoing_send(orq, 0);
8189}
8190
8191
8192/** Send a request */
8193static void
8194outgoing_send(nta_outgoing_t *orq, int retransmit)
8195{
8196 int err;
8197 tp_name_t const *tpn = orq->orq_tpn;
8198 msg_t *msg = orq->orq_request;
8199 nta_agent_t *agent = orq->orq_agent;
8200 tport_t *tp;
8201 int once = 0;
8202 su_time_t now = su_now();
8203 tag_type_t tag = tag_skip;
8204 tag_value_t value = 0;
8205 struct sigcomp_compartment *cc; cc = NULL((void*)0);
8206
8207 /* tport can be NULL if we are just switching network */
8208 if (orq->orq_tport == NULL((void*)0)) {
8209 outgoing_tport_error(agent, orq, NULL((void*)0), orq->orq_request, ENETRESET102);
8210 return;
8211 }
8212
8213 if (orq->orq_user_tport && !tport_is_clear_to_send(orq->orq_tport)) {
8214 outgoing_tport_error(agent, orq, NULL((void*)0), orq->orq_request, EPIPE32);
8215 return;
8216 }
8217
8218 if (!retransmit)
8219 orq->orq_sent = now;
8220
8221 if (orq->orq_timestamp) {
8222 sip_t *sip = sip_object(msg);
8223 sip_timestamp_t *ts =
8224 sip_timestamp_format(msg_home(msg)((su_home_t*)(msg)), "%lu.%06lu",
8225 now.tv_sec, now.tv_usec);
8226
8227 if (ts) {
8228 if (sip->sip_timestamp)
8229 msg_header_remove(msg, (msg_pub_t *)sip, (msg_header_t *)sip->sip_timestamp);
8230 msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)ts);
8231 }
8232 }
8233
8234 for (;;) {
8235 if (tpn->tpn_comp == NULL((void*)0)) {
8236 /* xyzzy */
8237 }
8238 else if (orq->orq_cc) {
8239 cc = orq->orq_cc, orq->orq_cc = NULL((void*)0);
8240 }
8241 else {
8242 cc = agent_compression_compartment(agent, orq->orq_tport, tpn,
8243 orq->orq_sigcomp_new);
8244 }
8245
8246 if (orq->orq_try_udp_instead)
8247 tag = tptag_mtu, value = 65535;
8248
8249 if (orq->orq_pending) {
8250 tport_release(orq->orq_tport, orq->orq_pending,
8251 orq->orq_request, NULL((void*)0), orq, 0);
8252 orq->orq_pending = 0;
8253 }
8254
8255 tp = tport_tsend(orq->orq_tport, msg, tpn,
8256 tag, value,
8257 IF_SIGCOMP_TPTAG_COMPARTMENT(cc)!(cc && cc != ((void *)-1)) ? tag_skip : tptag_compartment
, tag_ptr_v((cc)),
8258 TAG_NEXT(orq->orq_tags)tag_next, (tag_value_t)(orq->orq_tags));
8259 if (tp)
8260 break;
8261
8262 err = msg_errno(orq->orq_request);
8263
8264 if (cc)
8265 nta_compartment_decref(&cc);
8266
8267 if (orq->orq_user_tport)
8268 /* No retries */;
8269 /* RFC3261, 18.1.1 */
8270 else if (err == EMSGSIZE90 && !orq->orq_try_tcp_instead) {
8271 if (su_casematch(tpn->tpn_proto, "udp") ||
8272 su_casematch(tpn->tpn_proto, "*")) {
8273 outgoing_try_tcp_instead(orq);
8274 continue;
8275 }
8276 }
8277 else if (err == ECONNREFUSED111 && orq->orq_try_tcp_instead) {
8278 if (su_casematch(tpn->tpn_proto, "tcp") && msg_size(msg) <= 65535) {
8279 outgoing_try_udp_instead(orq, 0);
8280 continue;
8281 }
8282 }
8283 else if (err == EPIPE32) {
8284 /* Connection was closed */
8285 if (!once++) {
8286 orq->orq_retries++;
8287 continue;
8288 }
8289 }
8290
8291 outgoing_tport_error(agent, orq, NULL((void*)0), orq->orq_request, err);
8292
8293 return;
8294 }
8295
8296 agent->sa_stats->as_sent_msg++;
8297 agent->sa_stats->as_sent_request++;
8298 if (retransmit)
8299 agent->sa_stats->as_retry_request++;
8300
8301 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__
, 8304, "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)
8302 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__
, 8304, "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)
8303 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__
, 8304, "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)
8304 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__
, 8304, "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)
;
8305
8306 if (cc) {
8307 if (orq->orq_cc)
8308 nta_compartment_decref(&orq->orq_cc);
8309 }
8310
8311 if (orq->orq_pending) {
8312 assert(orq->orq_tport)((orq->orq_tport) ? (void) (0) : __assert_fail ("orq->orq_tport"
, "nta.c", 8312, __PRETTY_FUNCTION__))
;
8313 tport_release(orq->orq_tport, orq->orq_pending,
8314 orq->orq_request, NULL((void*)0), orq, 0);
8315 orq->orq_pending = 0;
8316 }
8317
8318 if (orq->orq_stateless) {
8319 outgoing_reply(orq, 202, NULL((void*)0), 202);
8320 return;
8321 }
8322
8323 if (orq->orq_method != sip_method_ack) {
8324 orq->orq_pending = tport_pend(tp, orq->orq_request,
8325 outgoing_tport_error, orq);
8326 if (orq->orq_pending < 0)
8327 orq->orq_pending = 0;
8328 }
8329
8330 if (tp != orq->orq_tport) {
8331 tport_decref(&orq->orq_tport);
8332 orq->orq_tport = tport_ref(tp);
8333 }
8334
8335 orq->orq_reliable = tport_is_reliable(tp);
8336
8337 if (retransmit)
8338 return;
8339
8340 outgoing_trying(orq); /* Timer B / F */
8341
8342 if (orq->orq_method == sip_method_ack)
8343 ;
8344 else if (!orq->orq_reliable) {
8345 /* race condition on initial t1 timer timeout, set minimum initial timeout to 1000ms */
8346 unsigned t1_timer = agent->sa_t1;
8347 if (t1_timer < 1000) t1_timer = 1000;
8348 outgoing_set_timer(orq, t1_timer); /* Timer A/E */
8349 } else if (orq->orq_try_tcp_instead && !tport_is_connected(tp))
8350 outgoing_set_timer(orq, agent->sa_t4); /* Timer N3 */
8351}
8352
8353static void
8354outgoing_try_tcp_instead(nta_outgoing_t *orq)
8355{
8356 tport_t *tp;
8357 tp_name_t tpn[1];
8358
8359 assert(orq->orq_pending == 0)((orq->orq_pending == 0) ? (void) (0) : __assert_fail ("orq->orq_pending == 0"
, "nta.c", 8359, __PRETTY_FUNCTION__))
;
8360
8361 *tpn = *orq->orq_tpn;
8362 tpn->tpn_proto = "tcp";
8363 orq->orq_try_tcp_instead = 1;
8364
8365 tp = tport_by_name(orq->orq_agent->sa_tports, tpn);
8366 if (tp && tp != orq->orq_tport) {
8367 sip_t *sip = sip_object(orq->orq_request);
8368 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)
;
8369 sip->sip_via->v_protocol = sip_transport_tcp;
8370
8371 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__
, 8372, "nta: %s (%u) too large for UDP, trying TCP\n", orq->
orq_method_name, orq->orq_cseq->cs_seq)) : (void)0)
8372 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__
, 8372, "nta: %s (%u) too large for UDP, trying TCP\n", orq->
orq_method_name, orq->orq_cseq->cs_seq)) : (void)0)
;
8373
8374 orq->orq_tpn->tpn_proto = "tcp";
8375 tport_decref(&orq->orq_tport);
8376 orq->orq_tport = tport_ref(tp);
8377
8378 return;
8379 }
8380
8381 /* No TCP - try again with UDP without SIP MTU limit */
8382 tpn->tpn_proto = "udp";
8383 orq->orq_try_udp_instead = 1;
8384
8385 tp = tport_by_name(orq->orq_agent->sa_tports, tpn);
8386 if (tp && tp != orq->orq_tport) {
8387 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__
, 8388, "nta: %s (%u) exceed normal UDP size limit\n", orq->
orq_method_name, orq->orq_cseq->cs_seq)) : (void)0)
8388 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__
, 8388, "nta: %s (%u) exceed normal UDP size limit\n", orq->
orq_method_name, orq->orq_cseq->cs_seq)) : (void)0)
;
8389
8390 tport_decref(&orq->orq_tport);
8391 orq->orq_tport = tport_ref(tp);
8392 }
8393}
8394
8395static void
8396outgoing_try_udp_instead(nta_outgoing_t *orq, int timeout)
8397{
8398 tport_t *tp;
8399 tp_name_t tpn[1];
8400
8401 if (orq->orq_pending) {
8402 tport_release(orq->orq_tport, orq->orq_pending,
8403 orq->orq_request, NULL((void*)0), orq, 0);
8404 orq->orq_pending = 0;
8405 }
8406
8407 *tpn = *orq->orq_tpn;
8408 tpn->tpn_proto = "udp";
8409 orq->orq_try_udp_instead = 1;
8410
8411 tp = tport_by_name(orq->orq_agent->sa_tports, tpn);
8412 if (tp && tp != orq->orq_tport) {
8413 sip_t *sip = sip_object(orq->orq_request);
8414
8415 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)
;
8416 sip->sip_via->v_protocol = sip_transport_udp;
8417
8418 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__
, 8420, "nta: %s (%u) TCP %s, trying UDP\n", orq->orq_method_name
, orq->orq_cseq->cs_seq, timeout ? "times out" : "refused"
)) : (void)0)
8419 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__
, 8420, "nta: %s (%u) TCP %s, trying UDP\n", orq->orq_method_name
, orq->orq_cseq->cs_seq, timeout ? "times out" : "refused"
)) : (void)0)
8420 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__
, 8420, "nta: %s (%u) TCP %s, trying UDP\n", orq->orq_method_name
, orq->orq_cseq->cs_seq, timeout ? "times out" : "refused"
)) : (void)0)
;
8421
8422 orq->orq_tpn->tpn_proto = "udp";
8423 tport_decref(&orq->orq_tport);
8424 orq->orq_tport = tport_ref(tp);
8425 }
8426}
8427
8428
8429/** @internal Report transport errors. */
8430void
8431outgoing_tport_error(nta_agent_t *agent, nta_outgoing_t *orq,
8432 tport_t *tp, msg_t *msg, int error)
8433{
8434 tp_name_t const *tpn = tp ? tport_name(tp) : orq->orq_tpn;
8435
8436 if (orq->orq_pending) {
8437 assert(orq->orq_tport)((orq->orq_tport) ? (void) (0) : __assert_fail ("orq->orq_tport"
, "nta.c", 8437, __PRETTY_FUNCTION__))
;
8438 tport_release(orq->orq_tport, orq->orq_pending, orq->orq_request,
8439 NULL((void*)0), orq, 0);
8440 orq->orq_pending = 0;
8441 }
8442
8443 if (error == EPIPE32 && orq->orq_retries++ == 0) {
8444 /* XXX - we should retry only if the transport is not newly created */
8445 outgoing_print_tport_error(orq, 5, "retrying once after ",
8446 tpn, msg, error);
8447 outgoing_send(orq, 1);
8448 return;
8449 }
8450 else if (error == ECONNREFUSED111 && orq->orq_try_tcp_instead) {
8451 /* RFC3261, 18.1.1 */
8452 if (su_casematch(tpn->tpn_proto, "tcp") && msg_size(msg) <= 65535) {
8453 outgoing_print_tport_error(orq, 5, "retrying with UDP after ",
8454 tpn, msg, error);
8455 outgoing_try_udp_instead(orq, 0);
8456 outgoing_remove(orq); /* Reset state - this is no resend! */
8457 outgoing_send(orq, 0); /* Send */
8458 return;
8459 }
8460 }
8461 else if (error == 0) {
8462 /*
8463 * Server closed connection. RFC3261:
8464 * "there is no coupling between TCP connection state and SIP
8465 * processing."
8466 */
8467 return;
8468 }
8469
8470 if (outgoing_other_destinations(orq)) {
8471 outgoing_print_tport_error(orq, 5, "trying alternative server after ",
8472 tpn, msg, error);
8473 outgoing_try_another(orq);
8474 return;
8475 }
8476
8477 outgoing_print_tport_error(orq, 3, "", tpn, msg, error);
8478
8479 outgoing_reply(orq, SIP_503_SERVICE_UNAVAILABLE503, sip_503_Service_unavailable, 0);
8480}
8481
8482static
8483void
8484outgoing_print_tport_error(nta_outgoing_t *orq, int level, char *todo,
8485 tp_name_t const *tpn, msg_t *msg, int error)
8486{
8487 su_sockaddr_t const *su = msg_addr(msg);
8488 char addr[SU_ADDRSIZE(48)];
8489
8490 su_llog(nta_log, level,_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8496
, "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)), (__extension__ ({ unsigned short int __v, __x = (unsigned
short int) (su->su_sin.sin_port); if (__builtin_constant_p
(__x)) __v = ((unsigned short int) ((((__x) >> 8) &
0xff) | (((__x) & 0xff) << 8))); else __asm__ ("rorw $8, %w0"
: "=r" (__v) : "0" (__x) : "cc"); __v; })))
8491 "nta: %s (%u): %s%s (%u) with %s/[%s]:%u\n",_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8496
, "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)), (__extension__ ({ unsigned short int __v, __x = (unsigned
short int) (su->su_sin.sin_port); if (__builtin_constant_p
(__x)) __v = ((unsigned short int) ((((__x) >> 8) &
0xff) | (((__x) & 0xff) << 8))); else __asm__ ("rorw $8, %w0"
: "=r" (__v) : "0" (__x) : "cc"); __v; })))
8492 orq->orq_method_name, orq->orq_cseq->cs_seq,_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8496
, "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)), (__extension__ ({ unsigned short int __v, __x = (unsigned
short int) (su->su_sin.sin_port); if (__builtin_constant_p
(__x)) __v = ((unsigned short int) ((((__x) >> 8) &
0xff) | (((__x) & 0xff) << 8))); else __asm__ ("rorw $8, %w0"
: "=r" (__v) : "0" (__x) : "cc"); __v; })))
8493 todo, su_strerror(error), error,_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8496
, "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)), (__extension__ ({ unsigned short int __v, __x = (unsigned
short int) (su->su_sin.sin_port); if (__builtin_constant_p
(__x)) __v = ((unsigned short int) ((((__x) >> 8) &
0xff) | (((__x) & 0xff) << 8))); else __asm__ ("rorw $8, %w0"
: "=r" (__v) : "0" (__x) : "cc"); __v; })))
8494 tpn->tpn_proto,_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8496
, "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)), (__extension__ ({ unsigned short int __v, __x = (unsigned
short int) (su->su_sin.sin_port); if (__builtin_constant_p
(__x)) __v = ((unsigned short int) ((((__x) >> 8) &
0xff) | (((__x) & 0xff) << 8))); else __asm__ ("rorw $8, %w0"
: "=r" (__v) : "0" (__x) : "cc"); __v; })))
8495 su_inet_ntop(su->su_family, SU_ADDR(su), addr, sizeof(addr)),_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8496
, "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)), (__extension__ ({ unsigned short int __v, __x = (unsigned
short int) (su->su_sin.sin_port); if (__builtin_constant_p
(__x)) __v = ((unsigned short int) ((((__x) >> 8) &
0xff) | (((__x) & 0xff) << 8))); else __asm__ ("rorw $8, %w0"
: "=r" (__v) : "0" (__x) : "cc"); __v; })))
8496 htons(su->su_port))_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8496
, "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)), (__extension__ ({ unsigned short int __v, __x = (unsigned
short int) (su->su_sin.sin_port); if (__builtin_constant_p
(__x)) __v = ((unsigned short int) ((((__x) >> 8) &
0xff) | (((__x) & 0xff) << 8))); else __asm__ ("rorw $8, %w0"
: "=r" (__v) : "0" (__x) : "cc"); __v; })))
;
8497}
8498
8499/**@internal
8500 * Add features supported.
8501 */
8502static
8503int outgoing_features(nta_agent_t *agent, nta_outgoing_t *orq,
8504 msg_t *msg, sip_t *sip,
8505 tagi_t *tags)
8506{
8507 char const *supported[8];
8508 int i;
8509
8510 if (orq->orq_method != sip_method_invite) /* fast path for now */
8511 return 0;
8512
8513 supported[i = 0] = NULL((void*)0);
8514
8515 if (orq->orq_method == sip_method_invite) {
8516 int require_100rel = sip_has_feature(sip->sip_require, "100rel");
8517
8518 if (require_100rel) {
8519 orq->orq_must_100rel = 1;
8520 orq->orq_100rel = 1;
8521 }
8522 else if (sip_has_feature(sip->sip_supported, "100rel")) {
8523 orq->orq_100rel = 1;
8524 }
8525 else if (orq->orq_100rel) {
8526 supported[i++] = "100rel";
8527 }
8528 }
8529
8530 if (i) {
8531 supported[i] = NULL((void*)0);
8532
8533 if (sip->sip_supported) {
8534 su_home_t *home = msg_home(msg)((su_home_t*)(msg));
8535 return msg_list_append_items(home, sip->sip_supported, supported);
8536 }
8537 else {
8538 sip_supported_t s[1];
8539 sip_supported_init(s);
8540 s->k_items = supported;
8541 return sip_add_dup(msg, sip, (sip_header_t *)s);
8542 }
8543 }
8544
8545 return 0;
8546}
8547
8548
8549/**@internal
8550 * Insert outgoing request to agent hash table
8551 */
8552static
8553void outgoing_insert(nta_agent_t *agent, nta_outgoing_t *orq)
8554{
8555 if (outgoing_htable_is_full(agent->sa_outgoing))
8556 outgoing_htable_resize(agent->sa_home, agent->sa_outgoing, 0);
8557 outgoing_htable_insert(agent->sa_outgoing, orq);
8558 orq->orq_inserted = 1;
8559}
8560
8561/** @internal
8562 * Initialize a queue for outgoing transactions.
8563 */
8564static void
8565outgoing_queue_init(outgoing_queue_t *queue, unsigned timeout)
8566{
8567 memset(queue, 0, sizeof *queue);
8568 queue->q_tail = &queue->q_head;
8569 queue->q_timeout = timeout;
8570}
8571
8572/** Change the timeout value of a queue */
8573static void
8574outgoing_queue_adjust(nta_agent_t *sa,
8575 outgoing_queue_t *queue,
8576 unsigned timeout)
8577{
8578 nta_outgoing_t *orq;
8579 uint32_t latest;
8580
8581 if (timeout >= queue->q_timeout || !queue->q_head) {
8582 queue->q_timeout = timeout;
8583 return;
8584 }
8585
8586 latest = set_timeout(sa, queue->q_timeout = timeout);
8587
8588 for (orq = queue->q_head; orq; orq = orq->orq_next) {
8589 if (orq->orq_timeout == 0 ||
8590 (int32_t)(orq->orq_timeout - latest) > 0)
8591 orq->orq_timeout = latest;
8592 }
8593}
8594
8595/** @internal
8596 * Test if an outgoing transaction is in a queue.
8597 */
8598su_inlinestatic inline int
8599outgoing_is_queued(nta_outgoing_t const *orq)
8600{
8601 return orq && orq->orq_queue;
8602}
8603
8604/** @internal
8605 * Insert an outgoing transaction into a queue.
8606 *
8607 * Insert a client transaction into a queue and set the corresponding
8608 * timeout at the same time.
8609 */
8610static void
8611outgoing_queue(outgoing_queue_t *queue,
8612 nta_outgoing_t *orq)
8613{
8614 if (orq->orq_queue == queue) {
8615 //assert(queue->q_timeout == 0);
8616 return;
8617 }
8618
8619 assert(!orq->orq_forked)((!orq->orq_forked) ? (void) (0) : __assert_fail ("!orq->orq_forked"
, "nta.c", 8619, __PRETTY_FUNCTION__))
;
8620
8621 if (outgoing_is_queued(orq))
8622 outgoing_remove(orq);
8623
8624 orq->orq_timeout = set_timeout(orq->orq_agent, queue->q_timeout);
8625
8626 orq->orq_queue = queue;
8627 orq->orq_prev = queue->q_tail;
8628 *queue->q_tail = orq;
8629 queue->q_tail = &orq->orq_next;
8630 queue->q_length++;
8631}
8632
8633/** @internal
8634 * Remove an outgoing transaction from a queue.
8635 */
8636su_inlinestatic inline
8637void outgoing_remove(nta_outgoing_t *orq)
8638{
8639 assert(outgoing_is_queued(orq))((outgoing_is_queued(orq)) ? (void) (0) : __assert_fail ("outgoing_is_queued(orq)"
, "nta.c", 8639, __PRETTY_FUNCTION__))
;
8640 assert(orq->orq_queue->q_length > 0)((orq->orq_queue->q_length > 0) ? (void) (0) : __assert_fail
("orq->orq_queue->q_length > 0", "nta.c", 8640, __PRETTY_FUNCTION__
))
;
8641
8642 if ((*orq->orq_prev = orq->orq_next))
8643 orq->orq_next->orq_prev = orq->orq_prev;
8644 else
8645 orq->orq_queue->q_tail = orq->orq_prev;
8646
8647 orq->orq_queue->q_length--;
8648 orq->orq_next = NULL((void*)0);
8649 orq->orq_prev = NULL((void*)0);
8650 orq->orq_queue = NULL((void*)0);
8651 orq->orq_timeout = 0;
8652}
8653
8654/** Set retransmit timer (orq_retry).
8655 *
8656 * Set the retry timer (B/D) on the outgoing request (client transaction).
8657 */
8658su_inlinestatic inline
8659void outgoing_set_timer(nta_outgoing_t *orq, uint32_t interval)
8660{
8661 nta_outgoing_t **rq;
8662
8663 assert(orq)((orq) ? (void) (0) : __assert_fail ("orq", "nta.c", 8663, __PRETTY_FUNCTION__
))
;
8664
8665 if (interval == 0) {
8666 outgoing_reset_timer(orq);
8667 return;
8668 }
8669
8670 if (orq->orq_rprev) {
8671 /* Remove transaction from retry dequeue, re-insert it later. */
8672 if ((*orq->orq_rprev = orq->orq_rnext))
8673 orq->orq_rnext->orq_rprev = orq->orq_rprev;
8674 if (orq->orq_agent->sa_out.re_t1 == &orq->orq_rnext)
8675 orq->orq_agent->sa_out.re_t1 = orq->orq_rprev;
8676 }
8677 else {
8678 orq->orq_agent->sa_out.re_length++;
8679 }
8680
8681 orq->orq_retry = set_timeout(orq->orq_agent, orq->orq_interval = interval);
8682
8683 /* Shortcut into queue at SIP T1 */
8684 rq = orq->orq_agent->sa_out.re_t1;
8685
8686 if (!(*rq) || (int32_t)((*rq)->orq_retry - orq->orq_retry) > 0)
8687 rq = &orq->orq_agent->sa_out.re_list;
8688
8689 while (*rq && (int32_t)((*rq)->orq_retry - orq->orq_retry) <= 0)
8690 rq = &(*rq)->orq_rnext;
8691
8692 if ((orq->orq_rnext = *rq))
8693 orq->orq_rnext->orq_rprev = &orq->orq_rnext;
8694 *rq = orq;
8695 orq->orq_rprev = rq;
8696
8697 if (interval == orq->orq_agent->sa_t1)
8698 orq->orq_agent->sa_out.re_t1 = rq;
8699}
8700
8701static
8702void outgoing_reset_timer(nta_outgoing_t *orq)
8703{
8704 if (orq->orq_rprev) {
8705 if ((*orq->orq_rprev = orq->orq_rnext))
8706 orq->orq_rnext->orq_rprev = orq->orq_rprev;
8707 if (orq->orq_agent->sa_out.re_t1 == &orq->orq_rnext)
8708 orq->orq_agent->sa_out.re_t1 = orq->orq_rprev;
8709 orq->orq_agent->sa_out.re_length--;
8710 }
8711
8712 orq->orq_interval = 0, orq->orq_retry = 0;
8713 orq->orq_rnext = NULL((void*)0), orq->orq_rprev = NULL((void*)0);
8714}
8715
8716/** @internal
8717 * Free resources associated with the request.
8718 */
8719static
8720void outgoing_free(nta_outgoing_t *orq)
8721{
8722 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__
, 8722, "nta: outgoing_free(%p)\n", (void *)orq)) : (void)0)
;
8723 assert(orq->orq_forks == NULL && orq->orq_forking == NULL)((orq->orq_forks == ((void*)0) && orq->orq_forking
== ((void*)0)) ? (void) (0) : __assert_fail ("orq->orq_forks == ((void*)0) && orq->orq_forking == ((void*)0)"
, "nta.c", 8723, __PRETTY_FUNCTION__))
;
8724 outgoing_cut_off(orq);
8725 outgoing_reclaim(orq);
8726}
8727
8728/** Remove outgoing request from hash tables */
8729su_inlinestatic inline void
8730outgoing_cut_off(nta_outgoing_t *orq)
8731{
8732 nta_agent_t *agent = orq->orq_agent;
8733
8734 if (orq->orq_default)
8735 agent->sa_default_outgoing = NULL((void*)0);
8736
8737 if (orq->orq_inserted)
8738 outgoing_htable_remove(agent->sa_outgoing, orq), orq->orq_inserted = 0;
8739
8740 if (outgoing_is_queued(orq))
8741 outgoing_remove(orq);
8742
8743#if 0
8744 if (orq->orq_forked)
8745 outgoing_remove_fork(orq);
8746#endif
8747
8748 outgoing_reset_timer(orq);
8749
8750 if (orq->orq_pending) {
8751 tport_release(orq->orq_tport, orq->orq_pending,
8752 orq->orq_request, NULL((void*)0), orq, 0);
8753 }
8754 orq->orq_pending = 0;
8755
8756 if (orq->orq_cc)
8757 nta_compartment_decref(&orq->orq_cc);
8758
8759 if (orq->orq_tport)
8760 tport_decref(&orq->orq_tport);
8761}
8762
8763/** Reclaim outgoing request */
8764su_inlinestatic inline
8765void outgoing_reclaim(nta_outgoing_t *orq)
8766{
8767 if (orq->orq_status2b)
8768 *orq->orq_status2b = -1;
8769
8770 if (orq->orq_request)
8771 msg_destroy(orq->orq_request), orq->orq_request = NULL((void*)0);
8772 if (orq->orq_response)
8773 msg_destroy(orq->orq_response), orq->orq_response = NULL((void*)0);
8774#if HAVE_SOFIA_SRESOLV1
8775 if (orq->orq_resolver)
8776 outgoing_destroy_resolver(orq);
8777#endif
8778 su_free(orq->orq_agent->sa_home, orq);
8779}
8780
8781/** Queue request to be freed */
8782su_inlinestatic inline
8783void outgoing_free_queue(outgoing_queue_t *q, nta_outgoing_t *orq)
8784{
8785 outgoing_cut_off(orq);
8786 outgoing_queue(q, orq);
8787}
8788
8789/** Reclaim memory used by queue of requests */
8790static
8791void outgoing_reclaim_queued(su_root_magic_t *rm,
8792 su_msg_r msg,
8793 union sm_arg_u *u)
8794{
8795 outgoing_queue_t *q = u->a_outgoing_queue;
8796 nta_outgoing_t *orq, *orq_next;
8797
8798 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__
, 8799, "outgoing_reclaim_all(%p, %p, %p)\n", (void *)rm, (void
*)msg, (void *)u)) : (void)0)
8799 (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__
, 8799, "outgoing_reclaim_all(%p, %p, %p)\n", (void *)rm, (void
*)msg, (void *)u)) : (void)0)
;
8800
8801 for (orq = q->q_head; orq; orq = orq_next) {
8802 orq_next = orq->orq_next;
8803 outgoing_reclaim(orq);
8804 }
8805}
8806
8807/** @internal Default callback for request */
8808int outgoing_default_cb(nta_outgoing_magic_t *magic,
8809 nta_outgoing_t *orq,
8810 sip_t const *sip)
8811{
8812 if (sip == NULL((void*)0) || sip->sip_status->st_status >= 200)
8813 outgoing_destroy(orq);
8814 return 0;
8815}
8816
8817/** @internal Destroy an outgoing transaction */
8818void outgoing_destroy(nta_outgoing_t *orq)
8819{
8820 if (orq->orq_terminated || orq->orq_default) {
8821 if (!orq->orq_forking && !orq->orq_forks) {
8822 outgoing_free(orq);
8823 return;
8824 }
8825 }
8826 /* Application is expected to handle 200 OK statelessly
8827 => kill transaction immediately */
8828 else if (orq->orq_method == sip_method_invite && !orq->orq_completed
8829 /* (unless transaction has been canceled) */
8830 && !orq->orq_canceled
8831 /* or it has been forked */
8832 && !orq->orq_forking && !orq->orq_forks) {
8833 orq->orq_destroyed = 1;
8834 outgoing_terminate(orq);
8835 return;
8836 }
8837
8838 orq->orq_destroyed = 1;
8839 orq->orq_callback = outgoing_default_cb;
8840 orq->orq_magic = NULL((void*)0);
8841}
8842
8843/** @internal Outgoing transaction timer routine.
8844 *
8845 */
8846static void
8847_nta_outgoing_timer(nta_agent_t *sa)
8848{
8849 uint32_t now = su_time_ms(su_now());
8850 nta_outgoing_t *orq;
8851 outgoing_queue_t rq[1];
8852 size_t retransmitted = 0, terminated = 0, timeout = 0, destroyed;
8853 size_t total = sa->sa_outgoing->oht_used;
8854 size_t trying = sa->sa_out.re_length;
8855 size_t pending = sa->sa_out.trying->q_length +
8856 sa->sa_out.inv_calling->q_length;
8857 size_t completed = sa->sa_out.completed->q_length +
8858 sa->sa_out.inv_completed->q_length;
8859
8860 outgoing_queue_init(sa->sa_out.free = rq, 0);
8861
8862 while ((orq = sa->sa_out.re_list)) {
8863
8864 now = su_time_ms(su_now());
8865
8866 if ((int32_t)(orq->orq_retry - now) > 0)
8867 break;
8868 if (retransmitted >= timer_max_retransmit)
8869 break;
8870
8871 if (orq->orq_reliable) {
8872 outgoing_reset_timer(orq);
8873
8874 if (!tport_is_connected(orq->orq_tport)) {
8875 /*
8876 * Timer N3: try to use UDP if trying to send via TCP
8877 * but no connection is established within SIP T4
8878 */
8879 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__
, 8881, "nta: timer %s fired, %s %s (%u)\n", "N3", "try UDP instead for"
, orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void
)0)
8880 "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__
, 8881, "nta: timer %s fired, %s %s (%u)\n", "N3", "try UDP instead for"
, orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void
)0)
8881 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__
, 8881, "nta: timer %s fired, %s %s (%u)\n", "N3", "try UDP instead for"
, orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void
)0)
;
8882 outgoing_try_udp_instead(orq, 1);
8883 outgoing_remove(orq); /* Reset state - this is no resend! */
8884 outgoing_send(orq, 0); /* Send */
8885 }
8886 continue;
8887 }
8888
8889 assert(!orq->orq_reliable && orq->orq_interval != 0)((!orq->orq_reliable && orq->orq_interval != 0)
? (void) (0) : __assert_fail ("!orq->orq_reliable && orq->orq_interval != 0"
, "nta.c", 8889, __PRETTY_FUNCTION__))
;
8890
8891 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__
, 8893, "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)
8892 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__
, 8893, "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)
8893 "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__
, 8893, "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)
;
8894
8895 outgoing_retransmit(orq);
8896
8897 if (orq->orq_method == sip_method_invite ||
8898 2U * orq->orq_interval < sa->sa_t2)
8899 outgoing_set_timer(orq, 2U * orq->orq_interval);
8900 else
8901 outgoing_set_timer(orq, sa->sa_t2);
8902
8903 if (++retransmitted % 5 == 0)
8904 su_root_yield(sa->sa_root); /* Handle received packets */
8905 }
8906
8907 terminated
8908 = outgoing_timer_dk(sa->sa_out.inv_completed, "D", now)
8909 + outgoing_timer_dk(sa->sa_out.completed, "K", now);
8910
8911 timeout
8912 = outgoing_timer_bf(sa->sa_out.inv_calling, "B", now)
8913 + outgoing_timer_c(sa->sa_out.inv_proceeding, "C", now)
8914 + outgoing_timer_bf(sa->sa_out.trying, "F", now);
8915
8916 destroyed = outgoing_mass_destroy(sa, rq);
8917
8918 sa->sa_out.free = NULL((void*)0);
8919
8920 if (retransmitted || timeout || terminated || destroyed) {
8921 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__
, 8929, "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)
8922 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__
, 8929, "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)
8923 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__
, 8929, "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)
8924 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__
, 8929, "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)
8925 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__
, 8929, "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)
8926 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__
, 8929, "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)
8927 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__
, 8929, "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)
8928 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__
, 8929, "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)
8929 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__
, 8929, "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)
;
8930 }
8931}
8932
8933/** @internal Retransmit the outgoing request. */
8934void outgoing_retransmit(nta_outgoing_t *orq)
8935{
8936 if (orq->orq_prepared && !orq->orq_delayed) {
8937 orq->orq_retries++;
8938
8939 if (orq->orq_retries >= 4 && orq->orq_cc) {
8940 orq->orq_tpn->tpn_comp = NULL((void*)0);
8941 if (orq->orq_retries == 4) {
8942 agent_close_compressor(orq->orq_agent, orq->orq_cc);
8943 nta_compartment_decref(&orq->orq_cc);
8944 }
8945 }
8946
8947 outgoing_send(orq, 1);
8948 }
8949}
8950
8951/** Trying a client transaction. */
8952static
8953void outgoing_trying(nta_outgoing_t *orq)
8954{
8955 if (orq->orq_forked)
8956 ;
8957 else if (orq->orq_method == sip_method_invite)
8958 outgoing_queue(orq->orq_agent->sa_out.inv_calling, orq);
8959 else
8960 outgoing_queue(orq->orq_agent->sa_out.trying, orq);
8961}
8962
8963/** Handle timers B and F */
8964static
8965size_t outgoing_timer_bf(outgoing_queue_t *q,
8966 char const *timer,
8967 uint32_t now)
8968{
8969 nta_outgoing_t *orq;
8970 size_t timeout = 0;
8971
8972 while ((orq = q->q_head)) {
8973 if ((int32_t)(orq->orq_timeout - now) > 0 ||
8974 timeout >= timer_max_timeout)
8975 break;
8976
8977 timeout++;
8978
8979 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__
, 8982, "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)
8980 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__
, 8982, "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)
8981 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__
, 8982, "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)
8982 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__
, 8982, "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)
;
8983
8984 if (orq->orq_method != sip_method_ack)
8985 outgoing_timeout(orq, now);
8986 else
8987 outgoing_terminate(orq);
8988
8989 assert(q->q_head != orq || (int32_t)(orq->orq_timeout - now) > 0)((q->q_head != orq || (int32_t)(orq->orq_timeout - now)
> 0) ? (void) (0) : __assert_fail ("q->q_head != orq || (int32_t)(orq->orq_timeout - now) > 0"
, "nta.c", 8989, __PRETTY_FUNCTION__))
;
8990 }
8991
8992 return timeout;
8993}
8994
8995/** Handle timer C */
8996static
8997size_t outgoing_timer_c(outgoing_queue_t *q,
8998 char const *timer,
8999 uint32_t now)
9000{
9001 nta_outgoing_t *orq;
9002 size_t timeout = 0;
9003
9004 if (q->q_timeout == 0)
9005 return 0;
9006
9007 while ((orq = q->q_head)) {
9008 if ((int32_t)(orq->orq_timeout - now) > 0 || timeout >= timer_max_timeout)
9009 break;
9010
9011 timeout++;
9012
9013 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__
, 9015, "nta: timer %s fired, %s %s (%u)\n", timer, "CANCEL and timeout"
, orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void
)0)
9014 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__
, 9015, "nta: timer %s fired, %s %s (%u)\n", timer, "CANCEL and timeout"
, orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void
)0)
9015 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__
, 9015, "nta: timer %s fired, %s %s (%u)\n", timer, "CANCEL and timeout"
, orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void
)0)
;
9016 /*
9017 * If the client transaction has received a provisional response, the
9018 * proxy MUST generate a CANCEL request matching that transaction.
9019 */
9020 nta_outgoing_tcancel(orq, NULL((void*)0), NULL((void*)0), TAG_NULL()(tag_type_t)0, (tag_value_t)0);
9021 }
9022
9023 return timeout;
9024}
9025
9026/** @internal Signal transaction timeout to the application. */
9027void outgoing_timeout(nta_outgoing_t *orq, uint32_t now)
9028{
9029 nta_outgoing_t *cancel = NULL((void*)0);
9030
9031 if (orq->orq_status || orq->orq_canceled)
9032 ;
9033 else if (outgoing_other_destinations(orq)) {
9034 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__
, 9035, "%s(%p): %s\n", "nta", (void *)orq, "try next after timeout"
)) : (void)0)
9035 "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__
, 9035, "%s(%p): %s\n", "nta", (void *)orq, "try next after timeout"
)) : (void)0)
;
9036 outgoing_try_another(orq);
9037 return;
9038 }
9039
9040 cancel = orq->orq_cancel, orq->orq_cancel = NULL((void*)0);
9041 orq->orq_agent->sa_stats->as_tout_request++;
9042
9043 outgoing_reply(orq, SIP_408_REQUEST_TIMEOUT408, sip_408_Request_timeout, 0);
9044
9045 if (cancel)
9046 outgoing_timeout(cancel, now);
9047}
9048
9049/** Complete a client transaction.
9050 *
9051 * @return True if transaction was free()d.
9052 */
9053static int
9054outgoing_complete(nta_outgoing_t *orq)
9055{
9056 orq->orq_completed = 1;
9057
9058 outgoing_reset_timer(orq); /* Timer A / Timer E */
9059
9060 if (orq->orq_stateless)
9061 return outgoing_terminate(orq);
9062
9063 if (orq->orq_forked) {
9064 outgoing_remove_fork(orq);
9065 return outgoing_terminate(orq);
9066 }
9067
9068 if (orq->orq_reliable) {
9069 if (orq->orq_method != sip_method_invite || !orq->orq_uas)
9070 return outgoing_terminate(orq);
9071 }
9072
9073 if (orq->orq_method == sip_method_invite) {
9074 if (orq->orq_queue != orq->orq_agent->sa_out.inv_completed)
9075 outgoing_queue(orq->orq_agent->sa_out.inv_completed, orq); /* Timer D */
9076 }
9077 else {
9078 outgoing_queue(orq->orq_agent->sa_out.completed, orq); /* Timer K */
9079 }
9080
9081 return 0;
9082}
9083
9084/** Handle timers D and K */
9085static
9086size_t outgoing_timer_dk(outgoing_queue_t *q,
9087 char const *timer,
9088 uint32_t now)
9089{
9090 nta_outgoing_t *orq;
9091 size_t terminated = 0;
9092
9093 while ((orq = q->q_head)) {
9094 if ((int32_t)(orq->orq_timeout - now) > 0 ||
9095 terminated >= timer_max_terminate)
9096 break;
9097
9098 terminated++;
9099
9100 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__
, 9101, "nta: timer %s fired, %s %s (%u)\n", timer, "terminate"
, orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void
)0)
9101 "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__
, 9101, "nta: timer %s fired, %s %s (%u)\n", timer, "terminate"
, orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void
)0)
;
9102
9103 if (orq->orq_method == sip_method_invite)
9104 outgoing_terminate_invite(orq);
9105 else
9106 outgoing_terminate(orq);
9107 }
9108
9109 return terminated;
9110}
9111
9112
9113/** Terminate an INVITE client transaction. */
9114static void
9115outgoing_terminate_invite(nta_outgoing_t *original)
9116{
9117 nta_outgoing_t *orq = original;
9118
9119 while (original->orq_forks) {
9120 orq = original->orq_forks;
9121 original->orq_forks = orq->orq_forks;
9122
9123 assert(orq->orq_forking == original)((orq->orq_forking == original) ? (void) (0) : __assert_fail
("orq->orq_forking == original", "nta.c", 9123, __PRETTY_FUNCTION__
))
;
9124
9125 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__
, 9127, "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)
9126 "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__
, 9127, "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)
9127 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__
, 9127, "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)
;
9128
9129 orq->orq_forking = NULL((void*)0), orq->orq_forks = NULL((void*)0), orq->orq_forked = 0;
9130
9131 if (outgoing_terminate(orq))
9132 continue;
9133
9134 if (orq->orq_status < 200) {
9135 /* Fork has timed out */
9136 orq->orq_agent->sa_stats->as_tout_request++;
9137 outgoing_reply(orq, SIP_408_REQUEST_TIMEOUT408, sip_408_Request_timeout, 0);
9138 }
9139 }
9140
9141 if (outgoing_terminate(orq = original))
9142 return;
9143
9144 if (orq->orq_status < 200) {
9145 /* Original INVITE has timed out */
9146 orq->orq_agent->sa_stats->as_tout_request++;
9147 outgoing_reply(orq, SIP_408_REQUEST_TIMEOUT408, sip_408_Request_timeout, 0);
9148 }
9149}
9150
9151static void
9152outgoing_remove_fork(nta_outgoing_t *orq)
9153{
9154 nta_outgoing_t **slot;
9155
9156 for (slot = &orq->orq_forking->orq_forks;
9157 *slot;
9158 slot = &(*slot)->orq_forks) {
9159 if (orq == *slot) {
9160 *slot = orq->orq_forks;
9161 orq->orq_forks = NULL((void*)0);
9162 orq->orq_forking = NULL((void*)0);
9163 orq->orq_forked = 0;
9164 }
9165 }
9166
9167 assert(orq == NULL)((orq == ((void*)0)) ? (void) (0) : __assert_fail ("orq == ((void*)0)"
, "nta.c", 9167, __PRETTY_FUNCTION__))
;
9168}
9169
9170/** Terminate a client transaction. */
9171static
9172int outgoing_terminate(nta_outgoing_t *orq)
9173{
9174 orq->orq_terminated = 1;
9175
9176 if (!orq->orq_destroyed) {
9177 outgoing_queue(orq->orq_agent->sa_out.terminated, orq);
9178 return 0;
9179 }
9180 else if (orq->orq_agent->sa_out.free) {
9181 outgoing_free_queue(orq->orq_agent->sa_out.free, orq);
9182 return 1;
9183 }
9184 else {
9185 outgoing_free(orq);
9186 return 1;
9187 }
9188}
9189
9190/** Mass destroy client transactions */
9191static
9192size_t outgoing_mass_destroy(nta_agent_t *sa, outgoing_queue_t *q)
9193{
9194 size_t destroyed = q->q_length;
9195
9196 if (destroyed > 2 && *sa->sa_terminator) {
9197 su_msg_r m = SU_MSG_R_INIT{ ((void*)0) };
9198
9199 if (su_msg_create(m,
9200 su_clone_task(sa->sa_terminator),
9201 su_root_task(sa->sa_root),
9202 outgoing_reclaim_queued,
9203 sizeof(outgoing_queue_t)) == SU_SUCCESSsu_success) {
9204 outgoing_queue_t *mq = su_msg_data(m)->a_outgoing_queue;
9205
9206 *mq = *q;
9207
9208 if (su_msg_send(m) == SU_SUCCESSsu_success)
9209 q->q_length = 0;
9210 }
9211 }
9212
9213 if (q->q_length)
9214 outgoing_reclaim_queued(NULL((void*)0), NULL((void*)0), (void*)q);
9215
9216 return destroyed;
9217}
9218
9219/** Find an outgoing request corresponging to a message and @Via line.
9220 *
9221 * Return an outgoing request object based on a message and the @Via line
9222 * given as argument. This function is used when doing loop checking: if we
9223 * have sent the request and it has been routed back to us.
9224 *
9225 * @param agent
9226 * @param msg
9227 * @param sip
9228 * @param v
9229 */
9230nta_outgoing_t *nta_outgoing_find(nta_agent_t const *agent,
9231 msg_t const *msg,
9232 sip_t const *sip,
9233 sip_via_t const *v)
9234{
9235 if (agent == NULL((void*)0) || msg == NULL((void*)0) || sip == NULL((void*)0) || v == NULL((void*)0)) {
9236 su_seterrno(EFAULT14);
9237 return NULL((void*)0);
9238 }
9239
9240 return outgoing_find(agent, msg, sip, v);
9241}
9242
9243/**@internal
9244 *
9245 * Find an outgoing request corresponging to a message and @Via line.
9246 *
9247 */
9248nta_outgoing_t *outgoing_find(nta_agent_t const *sa,
9249 msg_t const *msg,
9250 sip_t const *sip,
9251 sip_via_t const *v)
9252{
9253 nta_outgoing_t **oo, *orq;
9254 outgoing_htable_t const *oht = sa->sa_outgoing;
9255 sip_cseq_t const *cseq = sip->sip_cseq;
9256 sip_call_id_t const *i = sip->sip_call_id;
9257 hash_value_t hash;
9258 sip_method_t method, method2;
9259 unsigned short status = sip->sip_status ? sip->sip_status->st_status : 0;
9260
9261 if (cseq == NULL((void*)0))
9262 return NULL((void*)0);
9263
9264 hash = NTA_HASH(i, cseq->cs_seq)((i)->i_hash + 26839U * (uint32_t)(cseq->cs_seq));
9265
9266 method = cseq->cs_method;
9267
9268 /* Get original invite when ACKing */
9269 if (sip->sip_request && method == sip_method_ack && v == NULL((void*)0))
9270 method = sip_method_invite, method2 = sip_method_invalid;
9271 else if (sa->sa_is_a_uas && 200 <= status && status < 300 && method == sip_method_invite)
9272 method2 = sip_method_ack;
9273 else
9274 method2 = method;
9275
9276 for (oo = outgoing_htable_hash(oht, hash);
9277 (orq = *oo);
9278 oo = outgoing_htable_next(oht, oo)) {
9279 if (orq->orq_stateless)
9280 continue;
9281 /* Accept terminated transactions when looking for original INVITE */
9282 if (orq->orq_terminated && method2 != sip_method_invalid)
9283 continue;
9284 if (hash != orq->orq_hash)
9285 continue;
9286 if (orq->orq_call_id->i_hash != i->i_hash ||
9287 strcmp(orq->orq_call_id->i_id, i->i_id)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(orq->orq_call_id->i_id) && __builtin_constant_p
(i->i_id) && (__s1_len = __builtin_strlen (orq->
orq_call_id->i_id), __s2_len = __builtin_strlen (i->i_id
), (!((size_t)(const void *)((orq->orq_call_id->i_id) +
1) - (size_t)(const void *)(orq->orq_call_id->i_id) ==
1) || __s1_len >= 4) && (!((size_t)(const void *)
((i->i_id) + 1) - (size_t)(const void *)(i->i_id) == 1)
|| __s2_len >= 4)) ? __builtin_strcmp (orq->orq_call_id
->i_id, i->i_id) : (__builtin_constant_p (orq->orq_call_id
->i_id) && ((size_t)(const void *)((orq->orq_call_id
->i_id) + 1) - (size_t)(const void *)(orq->orq_call_id->
i_id) == 1) && (__s1_len = __builtin_strlen (orq->
orq_call_id->i_id), __s1_len < 4) ? (__builtin_constant_p
(i->i_id) && ((size_t)(const void *)((i->i_id)
+ 1) - (size_t)(const void *)(i->i_id) == 1) ? __builtin_strcmp
(orq->orq_call_id->i_id, i->i_id) : (__extension__ (
{ const unsigned char *__s2 = (const unsigned char *) (const char
*) (i->i_id); int __result = (((const unsigned char *) (const
char *) (orq->orq_call_id->i_id))[0] - __s2[0]); if (__s1_len
> 0 && __result == 0) { __result = (((const unsigned
char *) (const char *) (orq->orq_call_id->i_id))[1] - __s2
[1]); if (__s1_len > 1 && __result == 0) { __result
= (((const unsigned char *) (const char *) (orq->orq_call_id
->i_id))[2] - __s2[2]); if (__s1_len > 2 && __result
== 0) __result = (((const unsigned char *) (const char *) (orq
->orq_call_id->i_id))[3] - __s2[3]); } } __result; })))
: (__builtin_constant_p (i->i_id) && ((size_t)(const
void *)((i->i_id) + 1) - (size_t)(const void *)(i->i_id
) == 1) && (__s2_len = __builtin_strlen (i->i_id),
__s2_len < 4) ? (__builtin_constant_p (orq->orq_call_id
->i_id) && ((size_t)(const void *)((orq->orq_call_id
->i_id) + 1) - (size_t)(const void *)(orq->orq_call_id->
i_id) == 1) ? __builtin_strcmp (orq->orq_call_id->i_id,
i->i_id) : (- (__extension__ ({ const unsigned char *__s2
= (const unsigned char *) (const char *) (orq->orq_call_id
->i_id); int __result = (((const unsigned char *) (const char
*) (i->i_id))[0] - __s2[0]); if (__s2_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (i->i_id))[1] - __s2[1]); if (__s2_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (i->i_id))[2] - __s2[2]); if (__s2_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) (i->i_id))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp
(orq->orq_call_id->i_id, i->i_id)))); })
)
9288 continue;
9289 if (orq->orq_cseq->cs_seq != cseq->cs_seq)
9290 continue;
9291 if (method == sip_method_unknown &&
9292 strcmp(orq->orq_cseq->cs_method_name, cseq->cs_method_name)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(orq->orq_cseq->cs_method_name) && __builtin_constant_p
(cseq->cs_method_name) && (__s1_len = __builtin_strlen
(orq->orq_cseq->cs_method_name), __s2_len = __builtin_strlen
(cseq->cs_method_name), (!((size_t)(const void *)((orq->
orq_cseq->cs_method_name) + 1) - (size_t)(const void *)(orq
->orq_cseq->cs_method_name) == 1) || __s1_len >= 4) &&
(!((size_t)(const void *)((cseq->cs_method_name) + 1) - (
size_t)(const void *)(cseq->cs_method_name) == 1) || __s2_len
>= 4)) ? __builtin_strcmp (orq->orq_cseq->cs_method_name
, cseq->cs_method_name) : (__builtin_constant_p (orq->orq_cseq
->cs_method_name) && ((size_t)(const void *)((orq->
orq_cseq->cs_method_name) + 1) - (size_t)(const void *)(orq
->orq_cseq->cs_method_name) == 1) && (__s1_len =
__builtin_strlen (orq->orq_cseq->cs_method_name), __s1_len
< 4) ? (__builtin_constant_p (cseq->cs_method_name) &&
((size_t)(const void *)((cseq->cs_method_name) + 1) - (size_t
)(const void *)(cseq->cs_method_name) == 1) ? __builtin_strcmp
(orq->orq_cseq->cs_method_name, cseq->cs_method_name
) : (__extension__ ({ const unsigned char *__s2 = (const unsigned
char *) (const char *) (cseq->cs_method_name); int __result
= (((const unsigned char *) (const char *) (orq->orq_cseq
->cs_method_name))[0] - __s2[0]); if (__s1_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (orq->orq_cseq->cs_method_name))[1] - __s2[1])
; if (__s1_len > 1 && __result == 0) { __result = (
((const unsigned char *) (const char *) (orq->orq_cseq->
cs_method_name))[2] - __s2[2]); if (__s1_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) (orq->orq_cseq->cs_method_name))[3] - __s2[3]); } }
__result; }))) : (__builtin_constant_p (cseq->cs_method_name
) && ((size_t)(const void *)((cseq->cs_method_name
) + 1) - (size_t)(const void *)(cseq->cs_method_name) == 1
) && (__s2_len = __builtin_strlen (cseq->cs_method_name
), __s2_len < 4) ? (__builtin_constant_p (orq->orq_cseq
->cs_method_name) && ((size_t)(const void *)((orq->
orq_cseq->cs_method_name) + 1) - (size_t)(const void *)(orq
->orq_cseq->cs_method_name) == 1) ? __builtin_strcmp (orq
->orq_cseq->cs_method_name, cseq->cs_method_name) : (
- (__extension__ ({ const unsigned char *__s2 = (const unsigned
char *) (const char *) (orq->orq_cseq->cs_method_name)
; int __result = (((const unsigned char *) (const char *) (cseq
->cs_method_name))[0] - __s2[0]); if (__s2_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (cseq->cs_method_name))[1] - __s2[1]); if (__s2_len
> 1 && __result == 0) { __result = (((const unsigned
char *) (const char *) (cseq->cs_method_name))[2] - __s2[
2]); if (__s2_len > 2 && __result == 0) __result =
(((const unsigned char *) (const char *) (cseq->cs_method_name
))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (orq
->orq_cseq->cs_method_name, cseq->cs_method_name))))
; })
)
9293 continue;
9294 if (orq->orq_method != method && orq->orq_method != method2)
9295 continue;
9296 if (su_strcasecmp(orq->orq_from->a_tag, sip->sip_from->a_tag))
9297 continue;
9298 if (orq->orq_to->a_tag &&
9299 su_strcasecmp(orq->orq_to->a_tag, sip->sip_to->a_tag))
9300 continue;
9301
9302 if (orq->orq_method == sip_method_ack && 300 <= status)
9303 continue;
9304
9305 if (v && !su_casematch(orq->orq_branch + strlen("branch="), v->v_branch))
9306 continue;
9307
9308 break; /* match */
9309 }
9310
9311 return orq;
9312}
9313
9314/** Process a response message. */
9315int outgoing_recv(nta_outgoing_t *_orq,
9316 int status,
9317 msg_t *msg,
9318 sip_t *sip)
9319{
9320 nta_outgoing_t *orq = _orq->orq_forking ? _orq->orq_forking : _orq;
9321 nta_agent_t *sa = orq->orq_agent;
9322 int internal = sip == NULL((void*)0) || (sip->sip_flags & NTA_INTERNAL_MSG(1<<15)) != 0;
9323
9324 assert(!internal || status >= 300)((!internal || status >= 300) ? (void) (0) : __assert_fail
("!internal || status >= 300", "nta.c", 9324, __PRETTY_FUNCTION__
))
;
9325 assert(orq == _orq || orq->orq_method == sip_method_invite)((orq == _orq || orq->orq_method == sip_method_invite) ? (
void) (0) : __assert_fail ("orq == _orq || orq->orq_method == sip_method_invite"
, "nta.c", 9325, __PRETTY_FUNCTION__))
;
9326
9327 if (status < 100) status = 100;
9328
9329 if (!internal && orq->orq_delay == UINT_MAX(2147483647 *2U +1U))
9330 outgoing_estimate_delay(orq, sip);
9331
9332 if (orq->orq_cc)
9333 agent_accept_compressed(orq->orq_agent, msg, orq->orq_cc);
9334
9335 if (orq->orq_cancel) {
9336 nta_outgoing_t *cancel;
9337 cancel = orq->orq_cancel; orq->orq_cancel = NULL((void*)0);
9338 cancel->orq_delayed = 0;
9339
9340 if (status < 200) {
9341 outgoing_send(cancel, 0);
9342 outgoing_complete(orq);
9343 }
9344 else {
9345 outgoing_reply(cancel, SIP_481_NO_TRANSACTION481, sip_481_No_transaction, 0);
9346 }
9347 }
9348
9349 if (orq->orq_pending) {
9350 tport_release(orq->orq_tport, orq->orq_pending, orq->orq_request,
9351 msg, orq, status < 200);
9352 if (status >= 200)
9353 orq->orq_pending = 0;
9354 }
9355
9356 /* The state machines */
9357 if (orq->orq_method == sip_method_invite) {
9358 nta_outgoing_t *original = orq;
9359
9360 orq = _orq;
9361
9362 if (orq->orq_destroyed && 200 <= status && status < 300) {
9363 if (orq->orq_uas && su_strcasecmp(sip->sip_to->a_tag, orq->orq_tag) != 0) {
9364 /* Orphan 200 Ok to INVITE. ACK and BYE it */
9365 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__
, 9365, "nta: Orphan 200 Ok send ACK&BYE %p\n", (void *)orq
)) : (void)0)
;
9366 return nta_msg_ackbye(sa, msg);
9367 }
9368 return -1; /* Proxy statelessly (RFC3261 section 16.11) */
9369 }
9370
9371 outgoing_reset_timer(original); /* Retransmission */
9372
9373 if (status < 200) {
9374 if (original->orq_status < 200)
9375 original->orq_status = status;
9376 if (orq->orq_status < 200)
9377 orq->orq_status = status;
9378
9379 if (original->orq_queue == sa->sa_out.inv_calling) {
9380 outgoing_queue(sa->sa_out.inv_proceeding, original);
9381 }
9382 else if (original->orq_queue == sa->sa_out.inv_proceeding) {
9383 if (sa->sa_out.inv_proceeding->q_timeout) {
9384 outgoing_remove(original);
9385 outgoing_queue(sa->sa_out.inv_proceeding, original);
9386 }
9387 }
9388
9389 /* Handle 100rel */
9390 if (sip && sip->sip_rseq) {
9391 if (outgoing_recv_reliable(orq, msg, sip) < 0) {
9392 msg_destroy(msg);
9393 return 0;
9394 }
9395 }
9396 }
9397 else {
9398 /* Final response */
9399 if (status >= 300 && !internal)
9400 outgoing_ack(original, sip);
9401
9402 if (!original->orq_completed) {
9403 if (outgoing_complete(original))
9404 return 0;
9405
9406 if (orq->orq_uas && sip && orq == original) {
9407 /*
9408 * We silently discard duplicate final responses to INVITE below
9409 * with outgoing_duplicate()
9410 */
9411 su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request));
9412 orq->orq_tag = su_strdup(home, sip->sip_to->a_tag);
9413 }
9414 }
9415 /* Retransmission or response from another fork */
9416 else if (orq->orq_status >= 200) {
9417 /* Once 2xx has been received, non-2xx will not be forwarded */
9418 if (status >= 300)
9419 return outgoing_duplicate(orq, msg, sip);
9420
9421 if (orq->orq_uas) {
9422 if (su_strcasecmp(sip->sip_to->a_tag, orq->orq_tag) == 0)
9423 /* Catch retransmission */
9424 return outgoing_duplicate(orq, msg, sip);
9425
9426 /* Orphan 200 Ok to INVITE. ACK and BYE it */
9427 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__
, 9427, "nta: Orphan 200 Ok send ACK&BYE" "%s", "")) : (void
)0)
;
9428 return nta_msg_ackbye(sa, msg);
9429 }
9430 }
9431
9432 orq->orq_status = status;
9433 }
9434 }
9435 else if (orq->orq_method != sip_method_ack) {
9436 /* Non-INVITE */
9437 if (orq->orq_queue == sa->sa_out.trying ||
9438 orq->orq_queue == sa->sa_out.resolving) {
9439 /* hacked by freeswitch, this is being hit by options 404 status with 404 orq->orq_status and orq_destroyed = 1, orq_completed = 1 */
9440 /* assert(orq->orq_status < 200); */
9441 if (orq->orq_status >= 200) {msg_destroy(msg); return 0;}
9442
9443 if (status < 200) {
9444 /* @RFC3261 17.1.2.1:
9445 * retransmissions continue for unreliable transports,
9446 * but at an interval of T2.
9447 *
9448 * @RFC4321 1.2:
9449 * Note that Timer E is not altered during the transition
9450 * to Proceeding.
9451 */
9452 if (!orq->orq_reliable)
9453 orq->orq_interval = sa->sa_t2;
9454 }
9455 else if (!outgoing_complete(orq)) {
9456 if (orq->orq_sigcomp_zap && orq->orq_tport && orq->orq_cc)
9457 agent_zap_compressor(orq->orq_agent, orq->orq_cc);
9458 }
9459 else /* outgoing_complete */ {
9460 msg_destroy(msg);
9461 return 0;
9462 }
9463 }
9464 else {
9465 /* Already completed or terminated */
9466 assert(orq->orq_queue == sa->sa_out.completed ||((orq->orq_queue == sa->sa_out.completed || orq->orq_queue
== sa->sa_out.terminated) ? (void) (0) : __assert_fail ("orq->orq_queue == sa->sa_out.completed || orq->orq_queue == sa->sa_out.terminated"
, "nta.c", 9467, __PRETTY_FUNCTION__))
9467 orq->orq_queue == sa->sa_out.terminated)((orq->orq_queue == sa->sa_out.completed || orq->orq_queue
== sa->sa_out.terminated) ? (void) (0) : __assert_fail ("orq->orq_queue == sa->sa_out.completed || orq->orq_queue == sa->sa_out.terminated"
, "nta.c", 9467, __PRETTY_FUNCTION__))
;
9468 assert(orq->orq_status >= 200)((orq->orq_status >= 200) ? (void) (0) : __assert_fail (
"orq->orq_status >= 200", "nta.c", 9468, __PRETTY_FUNCTION__
))
;
9469 return outgoing_duplicate(orq, msg, sip);
9470 }
9471
9472 orq->orq_status = status;
9473 }
9474 else {
9475 /* ACK */
9476 if (sip && (sip->sip_flags & NTA_INTERNAL_MSG(1<<15)) == 0)
9477 /* Received re-transmitted final reply to INVITE, retransmit ACK */
9478 outgoing_retransmit(orq);
9479 msg_destroy(msg);
9480 return 0;
9481 }
9482
9483 if (100 >= status + orq->orq_pass_100) {
9484 msg_destroy(msg);
9485 return 0;
9486 }
9487
9488 if (orq->orq_destroyed) {
9489 msg_destroy(msg);
9490 return 0;
9491 }
9492
9493 if (orq->orq_response)
9494 msg_destroy(orq->orq_response);
9495 orq->orq_response = msg;
9496 /* Call callback */
9497 orq->orq_callback(orq->orq_magic, orq, sip);
9498 return 0;
9499}
9500
9501static void outgoing_default_recv(nta_outgoing_t *orq,
9502 int status,
9503 msg_t *msg,
9504 sip_t *sip)
9505{
9506 assert(sip->sip_cseq)((sip->sip_cseq) ? (void) (0) : __assert_fail ("sip->sip_cseq"
, "nta.c", 9506, __PRETTY_FUNCTION__))
;
9507
9508 orq->orq_status = status;
9509 orq->orq_response = msg;
9510 orq->orq_callback(orq->orq_magic, orq, sip);
9511 orq->orq_response = NULL((void*)0);
9512 orq->orq_status = 0;
9513 msg_destroy(msg);
9514}
9515
9516static void outgoing_estimate_delay(nta_outgoing_t *orq, sip_t *sip)
9517{
9518 su_time_t now = su_now();
9519 double diff = 1000 * su_time_diff(now, orq->orq_sent);
9520
9521 if (orq->orq_timestamp && sip->sip_timestamp) {
9522 double diff2, delay = 0.0;
9523 su_time_t timestamp = { 0, 0 };
9524 char const *bad;
9525
9526 sscanf(sip->sip_timestamp->ts_stamp, "%lu.%lu",
9527 &timestamp.tv_sec, &timestamp.tv_usec);
9528
9529 diff2 = 1000 * su_time_diff(now, timestamp);
9530
9531 if (diff2 < 0)
9532 bad = "negative";
9533 else if (diff2 > diff + 1e-3)
9534 bad = "too large";
9535 else {
9536 if (sip->sip_timestamp->ts_delay)
9537 sscanf(sip->sip_timestamp->ts_delay, "%lg", &delay);
9538
9539 if (1000 * delay <= diff2) {
9540 diff = diff2 - 1000 * delay;
9541 orq->orq_delay = (unsigned)diff;
9542 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__
, 9547, "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)
9543 "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__
, 9547, "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)
9544 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__
, 9547, "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)
9545 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__
, 9547, "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)
9546 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__
, 9547, "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)
9547 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__
, 9547, "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)
;
9548 return;
9549 }
9550 bad = "delay";
9551 }
9552
9553 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__
, 9559, "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)
9554 "(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__
, 9559, "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)
9555 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__
, 9559, "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)
9556 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__
, 9559, "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)
9557 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__
, 9559, "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)
9558 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__
, 9559, "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)
9559 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__
, 9559, "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)
;
9560 }
9561
9562 if (diff >= 0 && diff < (double)UINT_MAX(2147483647 *2U +1U)) {
9563 orq->orq_delay = (unsigned)diff;
9564 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__
, 9564, "nta_outgoing: RTT is %g ms\n", diff)) : (void)0)
;
9565 }
9566}
9567
9568/**@typedef nta_response_f
9569 *
9570 * Callback for replies to outgoing requests.
9571 *
9572 * This is a callback function invoked by NTA when it has received a new
9573 * reply to an outgoing request.
9574 *
9575 * @param magic request context
9576 * @param request request handle
9577 * @param sip received status message
9578 *
9579 * @return
9580 * This callback function should return always 0.
9581 *
9582 */
9583
9584/** Process duplicate responses */
9585static int outgoing_duplicate(nta_outgoing_t *orq,
9586 msg_t *msg,
9587 sip_t *sip)
9588{
9589 sip_via_t *v;
9590
9591 if (sip && (sip->sip_flags & NTA_INTERNAL_MSG(1<<15)) == 0) {
9592 v = sip->sip_via;
9593
9594 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__
, 9596, "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)
9595 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__
, 9596, "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)
9596 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__
, 9596, "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)
;
9597 if (v)
9598 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__
, 9603, "\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)
9599 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__
, 9603, "\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)
9600 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__
, 9603, "\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)
9601 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__
, 9603, "\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)
9602 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__
, 9603, "\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)
9603 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__
, 9603, "\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)
;
9604 }
9605
9606 msg_destroy(msg);
9607 return 0;
9608}
9609
9610/** @internal ACK to a final response (300..699).
9611 * These messages are ACK'ed via the original URL (and tport)
9612 */
9613void outgoing_ack(nta_outgoing_t *orq, sip_t *sip)
9614{
9615 msg_t *ackmsg;
9616
9617 assert(orq)((orq) ? (void) (0) : __assert_fail ("orq", "nta.c", 9617, __PRETTY_FUNCTION__
))
;
9618
9619 /* Do not ack internally generated messages... */
9620 if (sip == NULL((void*)0) || sip->sip_flags & NTA_INTERNAL_MSG(1<<15))
9621 return;
9622
9623 assert(sip)((sip) ? (void) (0) : __assert_fail ("sip", "nta.c", 9623, __PRETTY_FUNCTION__
))
; assert(sip->sip_status)((sip->sip_status) ? (void) (0) : __assert_fail ("sip->sip_status"
, "nta.c", 9623, __PRETTY_FUNCTION__))
;
9624 assert(sip->sip_status->st_status >= 300)((sip->sip_status->st_status >= 300) ? (void) (0) : __assert_fail
("sip->sip_status->st_status >= 300", "nta.c", 9624
, __PRETTY_FUNCTION__))
;
9625 assert(orq->orq_tport)((orq->orq_tport) ? (void) (0) : __assert_fail ("orq->orq_tport"
, "nta.c", 9625, __PRETTY_FUNCTION__))
;
9626
9627 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);
9628 if (!ackmsg)
9629 return;
9630
9631 if (!outgoing_create(orq->orq_agent, NULL((void*)0), NULL((void*)0),
9632 NULL((void*)0), orq->orq_tpn, ackmsg,
9633 NTATAG_BRANCH_KEY(sip->sip_via->v_branch)ntatag_branch_key, tag_str_v((sip->sip_via->v_branch)),
9634 NTATAG_USER_VIA(1)ntatag_user_via, tag_bool_v((1)),
9635 NTATAG_STATELESS(1)ntatag_stateless, tag_bool_v((1)),
9636 TAG_END()(tag_type_t)0, (tag_value_t)0))
9637 msg_destroy(ackmsg);
9638}
9639
9640/** Generate messages for hop-by-hop ACK or CANCEL.
9641 */
9642msg_t *outgoing_ackmsg(nta_outgoing_t *orq, sip_method_t m, char const *mname,
9643 tag_type_t tag, tag_value_t value, ...)
9644{
9645 msg_t *msg = nta_msg_create(orq->orq_agent, 0);
9646 su_home_t *home = msg_home(msg)((su_home_t*)(msg));
9647 sip_t *sip = sip_object(msg);
9648 sip_t *old = sip_object(orq->orq_request);
9649 sip_via_t via[1];
9650
9651 if (!sip)
9652 return NULL((void*)0);
9653
9654 if (tag) {
9655 ta_list ta;
9656
9657 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)
;
9658
9659 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
);
9660 /* Bug sf.net # 173323:
9661 * Ensure that request-URI, topmost Via, From, To, Call-ID, CSeq,
9662 * Max-Forward, Route, Accept-Contact, Reject-Contact and
9663 * Request-Disposition are copied from original request
9664 */
9665 if (sip->sip_from)
9666 sip_header_remove(msg, sip, (void *)sip->sip_from);
9667 if (sip->sip_to && m != sip_method_ack)
9668 sip_header_remove(msg, sip, (void *)sip->sip_to);
9669 if (sip->sip_call_id)
9670 sip_header_remove(msg, sip, (void *)sip->sip_call_id);
9671 while (sip->sip_route)
9672 sip_header_remove(msg, sip, (void *)sip->sip_route);
9673 while (sip->sip_accept_contact)
9674 sip_header_remove(msg, sip, (void *)sip->sip_accept_contact);
9675 while (sip->sip_reject_contact)
9676 sip_header_remove(msg, sip, (void *)sip->sip_reject_contact);
9677 if (sip->sip_request_disposition)
9678 sip_header_remove(msg, sip, (void *)sip->sip_request_disposition);
9679 while (sip->sip_via)
9680 sip_header_remove(msg, sip, (void *)sip->sip_via);
9681 if (sip->sip_max_forwards)
9682 sip_header_remove(msg, sip, (void *)sip->sip_max_forwards);
9683
9684 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))
;
9685 }
9686
9687 sip->sip_request =
9688 sip_request_create(home, m, mname, (url_string_t *)orq->orq_url, NULL((void*)0));
9689
9690 if (sip->sip_to == NULL((void*)0))
9691 sip_add_dup(msg, sip, (sip_header_t *)old->sip_to);
9692 sip_add_dup(msg, sip, (sip_header_t *)old->sip_from);
9693 sip_add_dup(msg, sip, (sip_header_t *)old->sip_call_id);
9694 sip_add_dup(msg, sip, (sip_header_t *)old->sip_route);
9695 /* @RFC3841. Bug #1326727. */
9696 sip_add_dup(msg, sip, (sip_header_t *)old->sip_accept_contact);
9697 sip_add_dup(msg, sip, (sip_header_t *)old->sip_reject_contact);
9698 sip_add_dup(msg, sip, (sip_header_t *)old->sip_request_disposition);
9699 sip_add_dup(msg, sip, (sip_header_t *)old->sip_max_forwards);
9700
9701 if (old->sip_via) {
9702 /* Add only the topmost Via header */
9703 *via = *old->sip_via; via->v_next = NULL((void*)0);
9704 sip_add_dup(msg, sip, (sip_header_t *)via);
9705 }
9706
9707 sip->sip_cseq = sip_cseq_create(home, old->sip_cseq->cs_seq, m, mname);
9708
9709 if (sip->sip_request &&
9710 sip->sip_to &&
9711 sip->sip_from &&
9712 sip->sip_call_id &&
9713 (!old->sip_route || sip->sip_route) &&
9714 sip->sip_cseq)
9715 return msg;
9716
9717 msg_destroy(msg);
9718
9719 return NULL((void*)0);
9720}
9721
9722static
9723void outgoing_delayed_recv(su_root_magic_t *rm,
9724 su_msg_r msg,
9725 union sm_arg_u *u);
9726
9727/** Respond internally to a transaction. */
9728int outgoing_reply(nta_outgoing_t *orq, int status, char const *phrase,
9729 int delayed)
9730{
9731 nta_agent_t *agent = orq->orq_agent;
9732 msg_t *msg = NULL((void*)0);
9733 sip_t *sip = NULL((void*)0);
9734
9735 assert(status == 202 || status >= 400)((status == 202 || status >= 400) ? (void) (0) : __assert_fail
("status == 202 || status >= 400", "nta.c", 9735, __PRETTY_FUNCTION__
))
;
9736
9737 if (orq->orq_pending)
9738 tport_release(orq->orq_tport, orq->orq_pending,
9739 orq->orq_request, NULL((void*)0), orq, 0);
9740 orq->orq_pending = 0;
9741
9742 orq->orq_delayed = 0;
9743
9744 if (orq->orq_method == sip_method_ack) {
9745 if (status != delayed)
9746 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__
, 9747, "nta(%p): responding %u %s to ACK!\n", (void *)orq, status
, phrase)) : (void)0)
9747 (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__
, 9747, "nta(%p): responding %u %s to ACK!\n", (void *)orq, status
, phrase)) : (void)0)
;
9748 orq->orq_status = status;
9749 if (orq->orq_queue == NULL((void*)0))
9750 outgoing_trying(orq); /* Timer F */
9751 return 0;
9752 }
9753
9754 if (orq->orq_destroyed) {
9755 if (orq->orq_status < 200)
9756 orq->orq_status = status;
9757 outgoing_complete(orq); /* Timer D / Timer K */
9758 return 0;
9759 }
9760
9761 if (orq->orq_stateless)
9762 ;
9763 else if (orq->orq_queue == NULL((void*)0) ||
9764 orq->orq_queue == orq->orq_agent->sa_out.resolving ||
9765 orq->orq_queue == orq->orq_agent->sa_out.delayed)
9766 outgoing_trying(orq);
9767
9768 /** Insert a dummy Via header */
9769 if (!orq->orq_prepared) {
9770 tport_t *tp = tport_primaries(orq->orq_agent->sa_tports);
9771 outgoing_insert_via(orq, agent_tport_via(tp));
9772 }
9773
9774 /* Create response message, if needed */
9775 if (!orq->orq_stateless &&
9776 !(orq->orq_callback == outgoing_default_cb) &&
9777 !(status == 408 &&
9778 orq->orq_method != sip_method_invite &&
9779 !orq->orq_agent->sa_timeout_408)) {
9780 char const *to_tag;
9781
9782 msg = nta_msg_create(agent, NTA_INTERNAL_MSG(1<<15));
9783
9784 if (complete_response(msg, status, phrase, orq->orq_request) < 0) {
9785 assert(!"complete message")((!"complete message") ? (void) (0) : __assert_fail ("!\"complete message\""
, "nta.c", 9785, __PRETTY_FUNCTION__))
;
9786 return -1;
9787 }
9788
9789 sip = sip_object(msg); assert(sip->sip_flags & NTA_INTERNAL_MSG)((sip->sip_flags & (1<<15)) ? (void) (0) : __assert_fail
("sip->sip_flags & (1<<15)", "nta.c", 9789, __PRETTY_FUNCTION__
))
;
9790 to_tag = nta_agent_newtag(msg_home(msg)((su_home_t*)(msg)), "tag=%s", agent);
9791
9792 if (status > 100 &&
9793 sip->sip_to && !sip->sip_to->a_tag &&
9794 sip->sip_cseq->cs_method != sip_method_cancel &&
9795 sip_to_tag(msg_home(msg)((su_home_t*)(msg)), sip->sip_to, to_tag) < 0) {
9796 assert(!"adding tag")((!"adding tag") ? (void) (0) : __assert_fail ("!\"adding tag\""
, "nta.c", 9796, __PRETTY_FUNCTION__))
;
9797 return -1;
9798 }
9799
9800 if (status > 400 && agent->sa_blacklist) {
9801 sip_retry_after_t af[1];
9802 sip_retry_after_init(af)->af_delta = agent->sa_blacklist;
9803
9804 sip_add_dup(msg, sip, (sip_header_t *)af);
9805 }
9806 }
9807
9808 if (orq->orq_inserted && !delayed) {
9809 outgoing_recv(orq, status, msg, sip);
9810 return 0;
9811 }
9812 else if (orq->orq_stateless && orq->orq_callback == outgoing_default_cb) {
9813 /* Xyzzy */
9814 orq->orq_status = status;
9815 outgoing_complete(orq);
9816 }
9817 else {
9818 /*
9819 * The thread creating outgoing transaction must return to application
9820 * before transaction callback can be invoked. Therefore processing an
9821 * internally generated response message must be delayed until
9822 * transaction creation is completed.
9823 *
9824 * The internally generated message is transmitted using su_msg_send()
9825 * and it is delivered back to NTA when the application next time
9826 * executes the su_root_t event loop.
9827 */
9828 nta_agent_t *agent = orq->orq_agent;
9829 su_root_t *root = agent->sa_root;
9830 su_msg_r su_msg = SU_MSG_R_INIT{ ((void*)0) };
9831
9832 if (su_msg_create(su_msg,
9833 su_root_task(root),
9834 su_root_task(root),
9835 outgoing_delayed_recv,
9836 sizeof(struct outgoing_recv_s)) == SU_SUCCESSsu_success) {
9837 struct outgoing_recv_s *a = su_msg_data(su_msg)->a_outgoing_recv;
9838
9839 a->orq = orq;
9840 a->msg = msg;
9841 a->sip = sip;
9842 a->status = status;
9843
9844 orq->orq_status2b = &a->status;
9845
9846 if (su_msg_send(su_msg) == SU_SUCCESSsu_success) {
9847 return 0;
9848 }
9849 }
9850 }
9851
9852 if (msg)
9853 msg_destroy(msg);
9854
9855 return -1;
9856}
9857
9858static
9859void outgoing_delayed_recv(su_root_magic_t *rm,
9860 su_msg_r msg,
9861 union sm_arg_u *u)
9862{
9863 struct outgoing_recv_s *a = u->a_outgoing_recv;
9864
9865 if (a->status > 0) {
9866 a->orq->orq_status2b = 0;
9867 if (outgoing_recv(a->orq, a->status, a->msg, a->sip) >= 0)
9868 return;
9869 }
9870
9871 msg_destroy(a->msg);
9872}
9873
9874
9875/* ====================================================================== */
9876/* 9) Resolving (SIP) URL */
9877
9878#if HAVE_SOFIA_SRESOLV1
9879
9880struct sipdns_query;
9881
9882/** DNS resolving for (SIP) URLs */
9883struct sipdns_resolver
9884{
9885 tp_name_t sr_tpn[1]; /**< Copy of original transport name */
9886 sres_query_t *sr_query; /**< Current DNS Query */
9887 char const *sr_target; /**< Target for current query */
9888
9889 struct sipdns_query *sr_current; /**< Current query (with results) */
9890 char **sr_results; /**< A/AAAA results to be used */
9891
9892 struct sipdns_query *sr_head; /**< List of intermediate results */
9893 struct sipdns_query **sr_tail; /**< End of intermediate result list */
9894
9895 struct sipdns_query *sr_done; /**< Completed intermediate results */
9896
9897 struct sipdns_tport const *sr_tport; /**< Selected transport */
9898
9899 /** Transports to consider for this request */
9900 struct sipdns_tport const *sr_tports[SIPDNS_TRANSPORTS(6) + 1];
9901
9902 uint16_t sr_a_aaaa1, sr_a_aaaa2; /**< Order of A and/or AAAA queries. */
9903
9904 unsigned
9905 sr_use_naptr:1,
9906 sr_use_srv:1,
9907 sr_use_a_aaaa:1;
9908};
9909
9910/** Intermediate queries */
9911struct sipdns_query
9912{
9913 struct sipdns_query *sq_next;
9914
9915 char const *sq_proto;
9916 char const *sq_domain;
9917 char sq_port[6]; /* port number */
9918 uint16_t sq_otype; /* origin type of query data (0 means request) */
9919 uint16_t sq_type; /* query type */
9920 uint16_t sq_priority; /* priority or preference */
9921 uint16_t sq_weight; /* preference or weight */
9922 uint16_t sq_grayish; /* candidate for graylisting */
9923};
9924
9925static int outgoing_resolve_next(nta_outgoing_t *orq);
9926static int outgoing_resolving(nta_outgoing_t *orq);
9927static int outgoing_resolving_error(nta_outgoing_t *,
9928 int status, char const *phrase);
9929static void outgoing_graylist(nta_outgoing_t *orq, struct sipdns_query *sq);
9930static int outgoing_query_naptr(nta_outgoing_t *orq, char const *domain);
9931static void outgoing_answer_naptr(sres_context_t *orq, sres_query_t *q,
9932 sres_record_t *answers[]);
9933struct sipdns_tport const *outgoing_naptr_tport(nta_outgoing_t *orq,
9934 sres_record_t *answers[]);
9935
9936static int outgoing_make_srv_query(nta_outgoing_t *orq);
9937static int outgoing_make_a_aaaa_query(nta_outgoing_t *orq);
9938
9939static void outgoing_query_all(nta_outgoing_t *orq);
9940
9941static int outgoing_query_srv(nta_outgoing_t *orq, struct sipdns_query *);
9942static void outgoing_answer_srv(sres_context_t *orq, sres_query_t *q,
9943 sres_record_t *answers[]);
9944
9945#if SU_HAVE_IN61
9946static int outgoing_query_aaaa(nta_outgoing_t *orq, struct sipdns_query *);
9947static void outgoing_answer_aaaa(sres_context_t *orq, sres_query_t *q,
9948 sres_record_t *answers[]);
9949#endif
9950
9951static int outgoing_query_a(nta_outgoing_t *orq, struct sipdns_query *);
9952static void outgoing_answer_a(sres_context_t *orq, sres_query_t *q,
9953 sres_record_t *answers[]);
9954
9955static void outgoing_query_results(nta_outgoing_t *orq,
9956 struct sipdns_query *sq,
9957 char *results[],
9958 size_t rlen);
9959
9960
9961#define SIPDNS_503_ERROR503, "DNS Error" 503, "DNS Error"
9962
9963/** Resolve a request destination */
9964static void
9965outgoing_resolve(nta_outgoing_t *orq,
9966 int explicit_transport,
9967 enum nta_res_order_e res_order)
9968{
9969 struct sipdns_resolver *sr = NULL((void*)0);
9970 char const *tpname = orq->orq_tpn->tpn_proto;
9971 int tport_known = strcmp(tpname, "*")__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(tpname) && __builtin_constant_p ("*") && (__s1_len
= __builtin_strlen (tpname), __s2_len = __builtin_strlen ("*"
), (!((size_t)(const void *)((tpname) + 1) - (size_t)(const void
*)(tpname) == 1) || __s1_len >= 4) && (!((size_t)
(const void *)(("*") + 1) - (size_t)(const void *)("*") == 1)
|| __s2_len >= 4)) ? __builtin_strcmp (tpname, "*") : (__builtin_constant_p
(tpname) && ((size_t)(const void *)((tpname) + 1) - (
size_t)(const void *)(tpname) == 1) && (__s1_len = __builtin_strlen
(tpname), __s1_len < 4) ? (__builtin_constant_p ("*") &&
((size_t)(const void *)(("*") + 1) - (size_t)(const void *)(
"*") == 1) ? __builtin_strcmp (tpname, "*") : (__extension__ (
{ const unsigned char *__s2 = (const unsigned char *) (const char
*) ("*"); int __result = (((const unsigned char *) (const char
*) (tpname))[0] - __s2[0]); if (__s1_len > 0 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
tpname))[1] - __s2[1]); if (__s1_len > 1 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
tpname))[2] - __s2[2]); if (__s1_len > 2 && __result
== 0) __result = (((const unsigned char *) (const char *) (tpname
))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p (
"*") && ((size_t)(const void *)(("*") + 1) - (size_t)
(const void *)("*") == 1) && (__s2_len = __builtin_strlen
("*"), __s2_len < 4) ? (__builtin_constant_p (tpname) &&
((size_t)(const void *)((tpname) + 1) - (size_t)(const void *
)(tpname) == 1) ? __builtin_strcmp (tpname, "*") : (- (__extension__
({ const unsigned char *__s2 = (const unsigned char *) (const
char *) (tpname); int __result = (((const unsigned char *) (
const char *) ("*"))[0] - __s2[0]); if (__s2_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) ("*"))[1] - __s2[1]); if (__s2_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) ("*"))[2] - __s2[2]); if (__s2_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) ("*"))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp
(tpname, "*")))); })
!= 0;
9972
9973 if (orq->orq_agent->sa_resolver)
9974 orq->orq_resolver = sr = su_zalloc(orq->orq_agent->sa_home, (sizeof *sr));
9975
9976 if (!sr) {
9977 outgoing_resolving_error(orq, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error);
9978 return;
9979 }
9980
9981 *sr->sr_tpn = *orq->orq_tpn;
9982 sr->sr_use_srv = orq->orq_agent->sa_use_srv;
9983 sr->sr_use_naptr = orq->orq_agent->sa_use_naptr && sr->sr_use_srv;
9984 sr->sr_use_a_aaaa = 1;
9985 sr->sr_tail = &sr->sr_head;
9986
9987 /* RFC 3263:
9988 If the TARGET was not a numeric IP address, but a port is present in
9989 the URI, the client performs an A or AAAA record lookup of the domain
9990 name. The result will be a list of IP addresses, each of which can
9991 be contacted at the specific port from the URI and transport protocol
9992 determined previously. The client SHOULD try the first record. If
9993 an attempt should fail, based on the definition of failure in Section
9994 4.3, the next SHOULD be tried, and if that should fail, the next
9995 SHOULD be tried, and so on.
9996
9997 This is a change from RFC 2543. Previously, if the port was
9998 explicit, but with a value of 5060, SRV records were used. Now, A
9999 or AAAA records will be used.
10000 */
10001 if (sr->sr_tpn->tpn_port)
10002 sr->sr_use_naptr = 0, sr->sr_use_srv = 0;
10003
10004 /* RFC3263:
10005 If [...] a transport was specified explicitly, the client performs an
10006 SRV query for that specific transport,
10007 */
10008 if (explicit_transport)
10009 sr->sr_use_naptr = 0;
10010
10011 {
10012 /* Initialize sr_tports */
10013 tport_t *tport;
10014 char const *ident = sr->sr_tpn->tpn_ident;
10015 int i, j;
10016
10017 for (tport = tport_primary_by_name(orq->orq_agent->sa_tports, orq->orq_tpn);
10018 tport;
10019 tport = tport_next(tport)) {
10020 tp_name_t const *tpn = tport_name(tport);
10021 if (tport_known && !su_casematch(tpn->tpn_proto, tpname))
10022 continue;
10023 if (ident && (tpn->tpn_ident == NULL((void*)0) || strcmp(ident, tpn->tpn_ident)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(ident) && __builtin_constant_p (tpn->tpn_ident) &&
(__s1_len = __builtin_strlen (ident), __s2_len = __builtin_strlen
(tpn->tpn_ident), (!((size_t)(const void *)((ident) + 1) -
(size_t)(const void *)(ident) == 1) || __s1_len >= 4) &&
(!((size_t)(const void *)((tpn->tpn_ident) + 1) - (size_t
)(const void *)(tpn->tpn_ident) == 1) || __s2_len >= 4)
) ? __builtin_strcmp (ident, tpn->tpn_ident) : (__builtin_constant_p
(ident) && ((size_t)(const void *)((ident) + 1) - (size_t
)(const void *)(ident) == 1) && (__s1_len = __builtin_strlen
(ident), __s1_len < 4) ? (__builtin_constant_p (tpn->tpn_ident
) && ((size_t)(const void *)((tpn->tpn_ident) + 1)
- (size_t)(const void *)(tpn->tpn_ident) == 1) ? __builtin_strcmp
(ident, tpn->tpn_ident) : (__extension__ ({ const unsigned
char *__s2 = (const unsigned char *) (const char *) (tpn->
tpn_ident); int __result = (((const unsigned char *) (const char
*) (ident))[0] - __s2[0]); if (__s1_len > 0 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
ident))[1] - __s2[1]); if (__s1_len > 1 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
ident))[2] - __s2[2]); if (__s1_len > 2 && __result
== 0) __result = (((const unsigned char *) (const char *) (ident
))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p (
tpn->tpn_ident) && ((size_t)(const void *)((tpn->
tpn_ident) + 1) - (size_t)(const void *)(tpn->tpn_ident) ==
1) && (__s2_len = __builtin_strlen (tpn->tpn_ident
), __s2_len < 4) ? (__builtin_constant_p (ident) &&
((size_t)(const void *)((ident) + 1) - (size_t)(const void *
)(ident) == 1) ? __builtin_strcmp (ident, tpn->tpn_ident) :
(- (__extension__ ({ const unsigned char *__s2 = (const unsigned
char *) (const char *) (ident); int __result = (((const unsigned
char *) (const char *) (tpn->tpn_ident))[0] - __s2[0]); if
(__s2_len > 0 && __result == 0) { __result = (((const
unsigned char *) (const char *) (tpn->tpn_ident))[1] - __s2
[1]); if (__s2_len > 1 && __result == 0) { __result
= (((const unsigned char *) (const char *) (tpn->tpn_ident
))[2] - __s2[2]); if (__s2_len > 2 && __result == 0
) __result = (((const unsigned char *) (const char *) (tpn->
tpn_ident))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp
(ident, tpn->tpn_ident)))); })
))
10024 continue;
10025
10026 for (j = 0; j < SIPDNS_TRANSPORTS(6); j++)
10027 if (su_casematch(tpn->tpn_proto, sipdns_tports[j].name))
10028 break;
10029
10030 assert(j < SIPDNS_TRANSPORTS)((j < (6)) ? (void) (0) : __assert_fail ("j < (6)", "nta.c"
, 10030, __PRETTY_FUNCTION__))
;
10031 if (j == SIPDNS_TRANSPORTS(6))
10032 /* Someone added transport but did not update sipdns_tports */
10033 continue;
10034
10035 for (i = 0; i < SIPDNS_TRANSPORTS(6); i++) {
10036 if (sipdns_tports + j == sr->sr_tports[i] || sr->sr_tports[i] == NULL((void*)0))
10037 break;
10038 }
10039 sr->sr_tports[i] = sipdns_tports + j;
10040
10041 if (tport_known) /* Looking for only one transport */ {
10042 sr->sr_tport = sipdns_tports + j;
10043 break;
10044 }
10045 }
10046
10047 /* Nothing found */
10048 if (!sr->sr_tports[0]) {
10049 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__
, 10050, "nta(%p): transport %s is not supported%s%s\n", (void
*)orq, tpname, ident ? " by interface " : "", ident ? ident :
"")) : (void)0)
10050 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__
, 10050, "nta(%p): transport %s is not supported%s%s\n", (void
*)orq, tpname, ident ? " by interface " : "", ident ? ident :
"")) : (void)0)
;
10051 outgoing_resolving_error(orq, SIPDNS_503_ERROR503, "DNS Error");
10052 return;
10053 }
10054 }
10055
10056 switch (res_order) {
10057 default:
10058 case nta_res_ip6_ip4:
10059 sr->sr_a_aaaa1 = sres_type_aaaa, sr->sr_a_aaaa2 = sres_type_a;
10060 break;
10061 case nta_res_ip4_ip6:
10062 sr->sr_a_aaaa1 = sres_type_a, sr->sr_a_aaaa2 = sres_type_aaaa;
10063 break;
10064 case nta_res_ip6_only:
10065 sr->sr_a_aaaa1 = sres_type_aaaa, sr->sr_a_aaaa2 = sres_type_aaaa;
10066 break;
10067 case nta_res_ip4_only:
10068 sr->sr_a_aaaa1 = sres_type_a, sr->sr_a_aaaa2 = sres_type_a;
10069 break;
10070 }
10071
10072 outgoing_resolve_next(orq);
10073}
10074
10075/** Resolve next destination. */
10076static int
10077outgoing_resolve_next(nta_outgoing_t *orq)
10078{
10079 struct sipdns_resolver *sr = orq->orq_resolver;
10080
10081 if (sr == NULL((void*)0)) {
10082 outgoing_resolving_error(orq, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error);
10083 return 0;
10084 }
10085
10086 if (sr->sr_results) {
10087 /* Use existing A/AAAA results */
10088 su_free(msg_home(orq->orq_request)((su_home_t*)(orq->orq_request)), sr->sr_results[0]);
10089 sr->sr_results++;
10090 if (sr->sr_results[0]) {
10091 struct sipdns_query *sq = sr->sr_current; assert(sq)((sq) ? (void) (0) : __assert_fail ("sq", "nta.c", 10091, __PRETTY_FUNCTION__
))
;
10092
10093 if (sq->sq_proto)
10094 orq->orq_tpn->tpn_proto = sq->sq_proto;
10095 if (sq->sq_port[0])
10096 orq->orq_tpn->tpn_port = sq->sq_port;
10097
10098 orq->orq_tpn->tpn_host = sr->sr_results[0];
10099
10100 outgoing_reset_timer(orq);
10101 outgoing_queue(orq->orq_agent->sa_out.resolving, orq);
10102 outgoing_prepare_send(orq);
10103 return 1;
10104 }
10105 else {
10106 sr->sr_current = NULL((void*)0);
10107 sr->sr_results = NULL((void*)0);
10108 }
10109 }
10110
10111 if (sr->sr_head)
10112 outgoing_query_all(orq);
10113 else if (sr->sr_use_naptr)
10114 outgoing_query_naptr(orq, sr->sr_tpn->tpn_host); /* NAPTR */
10115 else if (sr->sr_use_srv)
10116 outgoing_make_srv_query(orq); /* SRV */
10117 else if (sr->sr_use_a_aaaa)
10118 outgoing_make_a_aaaa_query(orq); /* A/AAAA */
10119 else
10120 return outgoing_resolving_error(orq, SIPDNS_503_ERROR503, "DNS Error");
10121
10122 return 1;
10123}
10124
10125/** Check if can we retry other destinations? */
10126static int
10127outgoing_other_destinations(nta_outgoing_t const *orq)
10128{
10129 struct sipdns_resolver *sr = orq->orq_resolver;
10130
10131 if (!sr)
10132 return 0;
10133
10134 if (sr->sr_use_a_aaaa || sr->sr_use_srv || sr->sr_use_naptr)
10135 return 1;
10136
10137 if (sr->sr_results && sr->sr_results[1])
10138 return 1;
10139
10140 if (sr->sr_head)
10141 return 1;
10142
10143 return 0;
10144}
10145
10146/** Resolve a request destination */
10147static int
10148outgoing_try_another(nta_outgoing_t *orq)
10149{
10150 struct sipdns_resolver *sr = orq->orq_resolver;
10151
10152 if (sr == NULL((void*)0))
10153 return 0;
10154
10155 *orq->orq_tpn = *sr->sr_tpn;
10156 orq->orq_try_tcp_instead = 0, orq->orq_try_udp_instead = 0;
10157 outgoing_reset_timer(orq);
10158 outgoing_queue(orq->orq_agent->sa_out.resolving, orq);
10159
10160 if (orq->orq_status > 0)
10161 /* PP: don't hack priority if a preliminary response has been received */
10162 ;
10163 else if (orq->orq_agent->sa_graylist == 0)
10164 /* PP: priority hacking disabled */
10165 ;
10166 /* NetModule hack:
10167 * Move server that did not work to end of queue in sres cache
10168 *
10169 * the next request does not try to use the server that is currently down
10170 *
10171 * @TODO: fix cases with only A or AAAA answering, or all servers down.
10172 */
10173 else if (sr && sr->sr_target) {
10174 struct sipdns_query *sq;
10175
10176 /* find latest A/AAAA record */
10177 sq = sr->sr_head;
10178 if (sq && sq->sq_type == sr->sr_a_aaaa2 && sr->sr_a_aaaa1 != sr->sr_a_aaaa2) {
10179 sq->sq_grayish = 1;
10180 }
10181 else {
10182 outgoing_graylist(orq, sr->sr_done);
10183 }
10184 }
10185
10186 return outgoing_resolve_next(orq);
10187}
10188
10189/** Graylist SRV records */
10190static void outgoing_graylist(nta_outgoing_t *orq, struct sipdns_query *sq)
10191{
10192 struct sipdns_resolver *sr = orq->orq_resolver;
10193 char const *target = sq->sq_domain, *proto = sq->sq_proto;
10194 unsigned prio = sq->sq_priority, maxprio = prio;
10195
10196 /* Don't know how to graylist but SRV records */
10197 if (sq->sq_otype != sres_type_srv)
10198 return;
10199
10200 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__
, 10200, "nta: graylisting %s:%s;transport=%s\n", target, sq->
sq_port, proto)) : (void)0)
;
10201
10202 for (sq = sr->sr_head; sq; sq = sq->sq_next)
10203 if (sq->sq_otype == sres_type_srv && sq->sq_priority > maxprio)
10204 maxprio = sq->sq_priority;
10205
10206 for (sq = sr->sr_done; sq; sq = sq->sq_next)
10207 if (sq->sq_otype == sres_type_srv && sq->sq_priority > maxprio)
10208 maxprio = sq->sq_priority;
10209
10210 for (sq = sr->sr_done; sq; sq = sq->sq_next) {
10211 int modified;
10212
10213 if (sq->sq_type != sres_type_srv || strcmp(proto, sq->sq_proto)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(proto) && __builtin_constant_p (sq->sq_proto) &&
(__s1_len = __builtin_strlen (proto), __s2_len = __builtin_strlen
(sq->sq_proto), (!((size_t)(const void *)((proto) + 1) - (
size_t)(const void *)(proto) == 1) || __s1_len >= 4) &&
(!((size_t)(const void *)((sq->sq_proto) + 1) - (size_t)(
const void *)(sq->sq_proto) == 1) || __s2_len >= 4)) ? __builtin_strcmp
(proto, sq->sq_proto) : (__builtin_constant_p (proto) &&
((size_t)(const void *)((proto) + 1) - (size_t)(const void *
)(proto) == 1) && (__s1_len = __builtin_strlen (proto
), __s1_len < 4) ? (__builtin_constant_p (sq->sq_proto)
&& ((size_t)(const void *)((sq->sq_proto) + 1) - (
size_t)(const void *)(sq->sq_proto) == 1) ? __builtin_strcmp
(proto, sq->sq_proto) : (__extension__ ({ const unsigned char
*__s2 = (const unsigned char *) (const char *) (sq->sq_proto
); int __result = (((const unsigned char *) (const char *) (proto
))[0] - __s2[0]); if (__s1_len > 0 && __result == 0
) { __result = (((const unsigned char *) (const char *) (proto
))[1] - __s2[1]); if (__s1_len > 1 && __result == 0
) { __result = (((const unsigned char *) (const char *) (proto
))[2] - __s2[2]); if (__s1_len > 2 && __result == 0
) __result = (((const unsigned char *) (const char *) (proto)
)[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p (
sq->sq_proto) && ((size_t)(const void *)((sq->sq_proto
) + 1) - (size_t)(const void *)(sq->sq_proto) == 1) &&
(__s2_len = __builtin_strlen (sq->sq_proto), __s2_len <
4) ? (__builtin_constant_p (proto) && ((size_t)(const
void *)((proto) + 1) - (size_t)(const void *)(proto) == 1) ?
__builtin_strcmp (proto, sq->sq_proto) : (- (__extension__
({ const unsigned char *__s2 = (const unsigned char *) (const
char *) (proto); int __result = (((const unsigned char *) (const
char *) (sq->sq_proto))[0] - __s2[0]); if (__s2_len > 0
&& __result == 0) { __result = (((const unsigned char
*) (const char *) (sq->sq_proto))[1] - __s2[1]); if (__s2_len
> 1 && __result == 0) { __result = (((const unsigned
char *) (const char *) (sq->sq_proto))[2] - __s2[2]); if (
__s2_len > 2 && __result == 0) __result = (((const
unsigned char *) (const char *) (sq->sq_proto))[3] - __s2
[3]); } } __result; })))) : __builtin_strcmp (proto, sq->sq_proto
)))); })
)
10214 continue;
10215
10216 /* modify the SRV record(s) corresponding to the latest A/AAAA record */
10217 modified = sres_set_cached_srv_priority(
10218 orq->orq_agent->sa_resolver,
10219 sq->sq_domain,
10220 target,
10221 sq->sq_port[0] ? (uint16_t)strtoul(sq->sq_port, NULL((void*)0), 10) : 0,
10222 orq->orq_agent->sa_graylist,
10223 maxprio + 1);
10224
10225 if (modified >= 0)
10226 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__
, 10227, "nta: reduced priority of %d %s SRV records (increase value to %u)\n"
, modified, sq->sq_domain, maxprio + 1)) : (void)0)
10227 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__
, 10227, "nta: reduced priority of %d %s SRV records (increase value to %u)\n"
, modified, sq->sq_domain, maxprio + 1)) : (void)0)
;
10228 else
10229 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__
, 10229, "nta: failed to reduce %s SRV priority\n", sq->sq_domain
)) : (void)0)
;
10230 }
10231}
10232
10233/** Cancel resolver query */
10234su_inlinestatic inline void outgoing_cancel_resolver(nta_outgoing_t *orq)
10235{
10236 struct sipdns_resolver *sr = orq->orq_resolver;
10237
10238 assert(orq->orq_resolver)((orq->orq_resolver) ? (void) (0) : __assert_fail ("orq->orq_resolver"
, "nta.c", 10238, __PRETTY_FUNCTION__))
;
10239
10240 if (sr->sr_query) /* Cancel resolver query */
10241 sres_query_bind(sr->sr_query, NULL((void*)0), NULL((void*)0)), sr->sr_query = NULL((void*)0);
10242}
10243
10244/** Destroy resolver */
10245su_inlinestatic inline void outgoing_destroy_resolver(nta_outgoing_t *orq)
10246{
10247 struct sipdns_resolver *sr = orq->orq_resolver;
10248
10249 assert(orq->orq_resolver)((orq->orq_resolver) ? (void) (0) : __assert_fail ("orq->orq_resolver"
, "nta.c", 10249, __PRETTY_FUNCTION__))
;
10250
10251 outgoing_cancel_resolver(orq);
10252
10253 su_free(orq->orq_agent->sa_home, sr);
10254
10255 orq->orq_resolver = NULL((void*)0);
10256}
10257
10258/** Check if we are resolving. If not, return 503 response. */
10259static
10260int outgoing_resolving(nta_outgoing_t *orq)
10261{
10262 struct sipdns_resolver *sr = orq->orq_resolver;
10263
10264 assert(orq->orq_resolver)((orq->orq_resolver) ? (void) (0) : __assert_fail ("orq->orq_resolver"
, "nta.c", 10264, __PRETTY_FUNCTION__))
;
10265
10266 if (!sr->sr_query) {
10267 return outgoing_resolving_error(orq, SIPDNS_503_ERROR503, "DNS Error");
10268 }
10269 else {
10270 outgoing_queue(orq->orq_agent->sa_out.resolving, orq);
10271 return 0;
10272 }
10273}
10274
10275/** Return 503 response */
10276static
10277int outgoing_resolving_error(nta_outgoing_t *orq, int status, char const *phrase)
10278{
10279 orq->orq_resolved = 1;
10280 outgoing_reply(orq, status, phrase, 0);
10281 return -1;
10282}
10283
10284/* Query SRV records (with the given tport). */
10285static
10286int outgoing_make_srv_query(nta_outgoing_t *orq)
10287{
10288 struct sipdns_resolver *sr = orq->orq_resolver;
10289 su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request));
10290 struct sipdns_query *sq;
10291 char const *host, *prefix;
10292 int i;
10293 size_t hlen, plen;
10294
10295 sr->sr_use_srv = 0;
10296
10297 host = sr->sr_tpn->tpn_host;
10298 hlen = strlen(host) + 1;
10299
10300 for (i = 0; sr->sr_tports[i]; i++) {
10301 if (sr->sr_tport && sr->sr_tports[i] != sr->sr_tport)
10302 continue;
10303
10304 prefix = sr->sr_tports[i]->prefix;
10305 plen = strlen(prefix);
10306
10307 sq = su_zalloc(home, (sizeof *sq) + plen + hlen);
10308 if (sq) {
10309 *sr->sr_tail = sq, sr->sr_tail = &sq->sq_next;
10310 sq->sq_domain = memcpy(sq + 1, prefix, plen);
10311 memcpy((char *)sq->sq_domain + plen, host, hlen);
10312 sq->sq_proto = sr->sr_tports[i]->name;
10313 sq->sq_type = sres_type_srv;
10314 sq->sq_priority = 1;
10315 sq->sq_weight = 1;
10316 }
10317 }
10318
10319 outgoing_query_all(orq);
10320
10321 return 0;
10322}
10323
10324/* Query A/AAAA records. */
10325static
10326int outgoing_make_a_aaaa_query(nta_outgoing_t *orq)
10327{
10328 struct sipdns_resolver *sr = orq->orq_resolver;
10329 su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request));
10330 tp_name_t *tpn = orq->orq_tpn;
10331 struct sipdns_query *sq;
10332
10333 assert(sr)((sr) ? (void) (0) : __assert_fail ("sr", "nta.c", 10333, __PRETTY_FUNCTION__
))
;
10334
10335 sr->sr_use_a_aaaa = 0;
10336
10337 sq = su_zalloc(home, 2 * (sizeof *sq));
10338 if (!sq)
10339 return outgoing_resolving(orq);
10340
10341 sq->sq_type = sr->sr_a_aaaa1;
10342 sq->sq_domain = tpn->tpn_host;
10343 sq->sq_priority = 1;
10344
10345 /* Append */
10346 *sr->sr_tail = sq, sr->sr_tail = &sq->sq_next;
10347
10348 outgoing_query_all(orq);
10349
10350 return 0;
10351}
10352
10353
10354/** Start SRV/A/AAAA queries */
10355static
10356void outgoing_query_all(nta_outgoing_t *orq)
10357{
10358 struct sipdns_resolver *sr = orq->orq_resolver;
10359 struct sipdns_query *sq = sr->sr_head;
10360
10361 if (sq == NULL((void*)0)) {
10362 outgoing_resolving_error(orq, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error);
10363 return;
10364 }
10365
10366 /* Remove from intermediate list */
10367 if (!(sr->sr_head = sq->sq_next))
10368 sr->sr_tail = &sr->sr_head;
10369
10370 if (sq->sq_type == sres_type_srv)
10371 outgoing_query_srv(orq, sq);
10372#if SU_HAVE_IN61
10373 else if (sq->sq_type == sres_type_aaaa)
10374 outgoing_query_aaaa(orq, sq);
10375#endif
10376 else if (sq->sq_type == sres_type_a)
10377 outgoing_query_a(orq, sq);
10378 else
10379 outgoing_resolving_error(orq, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error);
10380}
10381
10382/** Query NAPTR record. */
10383static
10384int outgoing_query_naptr(nta_outgoing_t *orq, char const *domain)
10385{
10386 struct sipdns_resolver *sr = orq->orq_resolver;
10387 sres_record_t **answers;
10388
10389 sr->sr_use_naptr = 0;
10390
10391 sr->sr_target = domain;
10392
10393 answers = sres_cached_answers(orq->orq_agent->sa_resolver,
10394 sres_type_naptr, domain);
10395
10396 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__
, 10398, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, domain, "NAPTR", answers ? " (cached)" : "")) :
(void)0)
10397 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__
, 10398, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, domain, "NAPTR", answers ? " (cached)" : "")) :
(void)0)
10398 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__
, 10398, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, domain, "NAPTR", answers ? " (cached)" : "")) :
(void)0)
;
10399
10400 if (answers) {
10401 outgoing_answer_naptr(orq, NULL((void*)0), answers);
10402 return 0;
10403 }
10404 else {
10405 sr->sr_query = sres_query(orq->orq_agent->sa_resolver,
10406 outgoing_answer_naptr, orq,
10407 sres_type_naptr, domain);
10408 return outgoing_resolving(orq);
10409 }
10410}
10411
10412/* Process NAPTR records */
10413static
10414void outgoing_answer_naptr(sres_context_t *orq,
10415 sres_query_t *q,
10416 sres_record_t *answers[])
10417{
10418 int i, order = -1;
10419 size_t rlen;
10420 su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request));
10421 struct sipdns_resolver *sr = orq->orq_resolver;
10422 tp_name_t tpn[1];
10423 struct sipdns_query *sq, *selected = NULL((void*)0), **tail = &selected, **at;
10424
10425 assert(sr)((sr) ? (void) (0) : __assert_fail ("sr", "nta.c", 10425, __PRETTY_FUNCTION__
))
;
10426
10427 sr->sr_query = NULL((void*)0);
10428
10429 *tpn = *sr->sr_tpn;
10430
10431 /* The NAPTR results are sorted first by Order then by Preference */
10432 sres_sort_answers(orq->orq_agent->sa_resolver, answers);
10433
10434 if (sr->sr_tport == NULL((void*)0))
10435 sr->sr_tport = outgoing_naptr_tport(orq, answers);
10436
10437 for (i = 0; answers && answers[i]; i++) {
10438 sres_naptr_record_t const *na = answers[i]->sr_naptr;
10439 uint16_t type;
10440 int valid_tport;
10441
10442 if (na->na_record->r_status)
10443 continue;
10444 if (na->na_record->r_type != sres_type_naptr)
10445 continue;
10446
10447 /* Check if NAPTR matches our target */
10448 if (!su_casenmatch(na->na_services, "SIP+", 4) &&
10449 !su_casenmatch(na->na_services, "SIPS+", 5))
10450 /* Not a SIP/SIPS service */
10451 continue;
10452
10453 /* Use NAPTR results, don't try extra SRV/A/AAAA records */
10454 sr->sr_use_srv = 0, sr->sr_use_a_aaaa = 0;
10455
10456 valid_tport = sr->sr_tport &&
10457 su_casematch(na->na_services, sr->sr_tport->service);
10458
10459 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__
, 10465, "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)
10460 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__
, 10465, "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)
10461 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__
, 10465, "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)
10462 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__
, 10465, "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)
10463 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__
, 10465, "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)
10464 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__
, 10465, "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)
10465 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__
, 10465, "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)
;
10466
10467 /* RFC 2915 p 4:
10468 * Order
10469 * A 16-bit unsigned integer specifying the order in which the
10470 * NAPTR records MUST be processed to ensure the correct ordering
10471 * of rules. Low numbers are processed before high numbers, and
10472 * once a NAPTR is found whose rule "matches" the target, the
10473 * client MUST NOT consider any NAPTRs with a higher value for
10474 * order (except as noted below for the Flags field).
10475 */
10476 if (order >= 0 && order != na->na_order)
10477 continue;
10478 if (!valid_tport)
10479 continue;
10480
10481 /* OK, we found matching NAPTR */
10482 order = na->na_order;
10483
10484 /*
10485 * The "S" flag means that the next lookup should be for SRV records
10486 * ... "A" means that the next lookup should be for either an A, AAAA,
10487 * or A6 record.
10488 */
10489 if (na->na_flags[0] == 's' || na->na_flags[0] == 'S')
10490 type = sres_type_srv; /* SRV */
10491 else if (na->na_flags[0] == 'a' || na->na_flags[0] == 'A')
10492 type = sr->sr_a_aaaa1; /* A / AAAA */
10493 else
10494 continue;
10495
10496 rlen = strlen(na->na_replace) + 1;
10497 sq = su_zalloc(home, (sizeof *sq) + rlen);
10498
10499 if (sq == NULL((void*)0))
10500 continue;
10501
10502 *tail = sq, tail = &sq->sq_next;
10503 sq->sq_otype = sres_type_naptr;
10504 sq->sq_priority = na->na_prefer;
10505 sq->sq_weight = 1;
10506 sq->sq_type = type;
10507 sq->sq_domain = memcpy(sq + 1, na->na_replace, rlen);
10508 sq->sq_proto = sr->sr_tport->name;
10509 }
10510
10511 sres_free_answers(orq->orq_agent->sa_resolver, answers);
10512
10513 /* RFC2915:
10514 Preference [...] specifies the order in which NAPTR
10515 records with equal "order" values SHOULD be processed, low
10516 numbers being processed before high numbers. */
10517 at = sr->sr_tail;
10518 while (selected) {
10519 sq = selected, selected = sq->sq_next;
10520
10521 for (tail = at; *tail; tail = &(*tail)->sq_next) {
10522 if (sq->sq_priority < (*tail)->sq_priority)
10523 break;
10524 if (sq->sq_priority == (*tail)->sq_priority &&
10525 sq->sq_weight < (*tail)->sq_weight)
10526 break;
10527 }
10528 /* Insert */
10529 sq->sq_next = *tail, *tail = sq;
10530
10531 if (!sq->sq_next) /* Last one */
10532 sr->sr_tail = &sq->sq_next;
10533 }
10534
10535 outgoing_resolve_next(orq);
10536}
10537
10538/* Find first supported protocol in order and preference */
10539struct sipdns_tport const *
10540outgoing_naptr_tport(nta_outgoing_t *orq, sres_record_t *answers[])
10541{
10542 int i, j, order, pref;
10543 int orders[SIPDNS_TRANSPORTS(6)], prefs[SIPDNS_TRANSPORTS(6)];
10544 struct sipdns_tport const *tport;
10545
10546 struct sipdns_resolver *sr = orq->orq_resolver;
10547
10548 for (j = 0; sr->sr_tports[j]; j++) {
10549 tport = sr->sr_tports[j];
10550
10551 orders[j] = 65536, prefs[j] = 65536;
10552
10553 /* Find transport order */
10554 for (i = 0; answers && answers[i]; i++) {
10555 sres_naptr_record_t const *na = answers[i]->sr_naptr;
10556 if (na->na_record->r_status)
10557 continue;
10558 if (na->na_record->r_type != sres_type_naptr)
10559 continue;
10560 /* Check if NAPTR matches transport */
10561 if (!su_casematch(na->na_services, tport->service))
10562 continue;
10563 orders[j] = na->na_order;
10564 prefs[j] = na->na_prefer;
10565 break;
10566 }
10567 }
10568
10569 tport = sr->sr_tports[0], order = orders[0], pref = prefs[0];
10570
10571 for (j = 1; sr->sr_tports[j]; j++) {
10572 if (orders[j] <= order && prefs[j] < pref) {
10573 tport = sr->sr_tports[j], order = orders[j], pref = prefs[j];
10574 }
10575 }
10576
10577 return tport;
10578}
10579
10580
10581/* Query SRV records */
10582static
10583int outgoing_query_srv(nta_outgoing_t *orq,
10584 struct sipdns_query *sq)
10585{
10586 struct sipdns_resolver *sr = orq->orq_resolver;
10587
10588 sres_record_t **answers;
10589
10590 sr->sr_target = sq->sq_domain;
10591 sr->sr_current = sq;
10592
10593 answers = sres_cached_answers(orq->orq_agent->sa_resolver,
10594 sres_type_srv, sq->sq_domain);
10595
10596 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__
, 10598, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, sq->sq_domain, "SRV", answers ? " (cached)"
: "")) : (void)0)
10597 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__
, 10598, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, sq->sq_domain, "SRV", answers ? " (cached)"
: "")) : (void)0)
10598 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__
, 10598, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, sq->sq_domain, "SRV", answers ? " (cached)"
: "")) : (void)0)
;
10599
10600 if (answers) {
10601 outgoing_answer_srv(orq, NULL((void*)0), answers);
10602 return 0;
10603 }
10604 else {
10605 sr->sr_query = sres_query(orq->orq_agent->sa_resolver,
10606 outgoing_answer_srv, orq,
10607 sres_type_srv, sq->sq_domain);
10608 return outgoing_resolving(orq);
10609 }
10610}
10611
10612/* Process SRV records */
10613static
10614void
10615outgoing_answer_srv(sres_context_t *orq, sres_query_t *q,
10616 sres_record_t *answers[])
10617{
10618 struct sipdns_resolver *sr = orq->orq_resolver;
10619 su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request));
10620 struct sipdns_query *sq0, *sq, *selected = NULL((void*)0), **tail = &selected, **at;
10621 int i;
10622 size_t tlen;
10623
10624 sr->sr_query = NULL((void*)0);
10625
10626 sq0 = sr->sr_current;
10627 assert(sq0 && sq0->sq_type == sres_type_srv)((sq0 && sq0->sq_type == sres_type_srv) ? (void) (
0) : __assert_fail ("sq0 && sq0->sq_type == sres_type_srv"
, "nta.c", 10627, __PRETTY_FUNCTION__))
;
10628 assert(sq0->sq_domain)((sq0->sq_domain) ? (void) (0) : __assert_fail ("sq0->sq_domain"
, "nta.c", 10628, __PRETTY_FUNCTION__))
; assert(sq0->sq_proto)((sq0->sq_proto) ? (void) (0) : __assert_fail ("sq0->sq_proto"
, "nta.c", 10628, __PRETTY_FUNCTION__))
;
10629
10630 /* Sort by priority, weight? */
10631 sres_sort_answers(orq->orq_agent->sa_resolver, answers);
10632
10633 for (i = 0; answers && answers[i]; i++) {
10634 sres_srv_record_t const *srv = answers[i]->sr_srv;
10635
10636 if (srv->srv_record->r_status /* There was an error */ ||
10637 srv->srv_record->r_type != sres_type_srv)
10638 continue;
10639
10640 tlen = strlen(srv->srv_target) + 1;
10641
10642 sq = su_zalloc(home, (sizeof *sq) + tlen);
10643
10644 if (sq) {
10645 *tail = sq, tail = &sq->sq_next;
10646
10647 sq->sq_otype = sres_type_srv;
10648 sq->sq_type = sr->sr_a_aaaa1;
10649 sq->sq_proto = sq0->sq_proto;
10650 sq->sq_domain = memcpy(sq + 1, srv->srv_target, tlen);
10651 snprintf(sq->sq_port, sizeof(sq->sq_port), "%u", srv->srv_port);
10652 sq->sq_priority = srv->srv_priority;
10653 sq->sq_weight = srv->srv_weight;
10654 }
10655 }
10656
10657 sres_free_answers(orq->orq_agent->sa_resolver, answers);
10658
10659 at = &sr->sr_head;
10660
10661 /* Insert sorted by priority, randomly select by weigth */
10662 while (selected) {
10663 unsigned long weight = 0;
10664 unsigned N = 0;
10665 uint16_t priority = selected->sq_priority;
10666
10667 /* Total weight of entries with same priority */
10668 for (sq = selected; sq && priority == sq->sq_priority; sq = sq->sq_next) {
10669 weight += sq->sq_weight;
10670 N ++;
10671 }
10672
10673 tail = &selected;
10674
10675 /* Select by weighted random. Entries with weight 0 are kept in order */
10676 if (N > 1 && weight > 0) {
10677 unsigned rand = su_randint(0, weight - 1);
10678
10679 while (rand >= (*tail)->sq_weight) {
10680 rand -= (*tail)->sq_weight;
10681 tail = &(*tail)->sq_next;
10682 }
10683 }
10684
10685 /* Remove selected */
10686 sq = *tail; *tail = sq->sq_next; assert(sq->sq_priority == priority)((sq->sq_priority == priority) ? (void) (0) : __assert_fail
("sq->sq_priority == priority", "nta.c", 10686, __PRETTY_FUNCTION__
))
;
10687
10688 /* Append at *at */
10689 sq->sq_next = *at; *at = sq; at = &sq->sq_next; if (!*at) sr->sr_tail = at;
10690
10691 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__
, 10694, "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)
10692 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__
, 10694, "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)
10693 (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__
, 10694, "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)
10694 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__
, 10694, "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)
;
10695 }
10696
10697 /* This is not needed anymore (?) */
10698 sr->sr_current = NULL((void*)0);
10699 sq0->sq_next = sr->sr_done; sr->sr_done = sq0;
10700
10701 outgoing_resolve_next(orq);
10702}
10703
10704#if SU_HAVE_IN61
10705/* Query AAAA records */
10706static
10707int outgoing_query_aaaa(nta_outgoing_t *orq, struct sipdns_query *sq)
10708{
10709 struct sipdns_resolver *sr = orq->orq_resolver;
10710 sres_record_t **answers;
10711
10712 sr->sr_target = sq->sq_domain;
10713 sr->sr_current = sq;
10714
10715 answers = sres_cached_answers(orq->orq_agent->sa_resolver,
10716 sres_type_aaaa, sq->sq_domain);
10717
10718 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__
, 10720, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, sq->sq_domain, "AAAA", answers ? " (cached)"
: "")) : (void)0)
10719 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__
, 10720, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, sq->sq_domain, "AAAA", answers ? " (cached)"
: "")) : (void)0)
10720 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__
, 10720, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, sq->sq_domain, "AAAA", answers ? " (cached)"
: "")) : (void)0)
;
10721
10722 if (answers) {
10723 outgoing_answer_aaaa(orq, NULL((void*)0), answers);
10724 return 0;
10725 }
10726
10727 sr->sr_query = sres_query(orq->orq_agent->sa_resolver,
10728 outgoing_answer_aaaa, orq,
10729 sres_type_aaaa, sq->sq_domain);
10730
10731 return outgoing_resolving(orq);
10732}
10733
10734/* Process AAAA records */
10735static
10736void outgoing_answer_aaaa(sres_context_t *orq, sres_query_t *q,
10737 sres_record_t *answers[])
10738{
10739 struct sipdns_resolver *sr = orq->orq_resolver;
10740 su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request));
10741 struct sipdns_query *sq = sr->sr_current;
10742
10743 size_t i, j, found;
10744 char *result, **results = NULL((void*)0);
10745
10746 assert(sq)((sq) ? (void) (0) : __assert_fail ("sq", "nta.c", 10746, __PRETTY_FUNCTION__
))
; assert(sq->sq_type == sres_type_aaaa)((sq->sq_type == sres_type_aaaa) ? (void) (0) : __assert_fail
("sq->sq_type == sres_type_aaaa", "nta.c", 10746, __PRETTY_FUNCTION__
))
;
10747
10748 sr->sr_query = NULL((void*)0);
10749
10750 for (i = 0, found = 0; answers && answers[i]; i++) {
10751 sres_aaaa_record_t const *aaaa = answers[i]->sr_aaaa;
10752 if (aaaa->aaaa_record->r_status == 0 &&
10753 aaaa->aaaa_record->r_type == sres_type_aaaa)
10754 found++;
10755 }
10756
10757 if (found > 1)
10758 results = su_zalloc(home, (found + 1) * (sizeof *results));
10759 else if (found)
10760 results = &result;
10761
10762 for (i = j = 0; results && answers && answers[i]; i++) {
10763 char addr[SU_ADDRSIZE(48)];
10764 sres_aaaa_record_t const *aaaa = answers[i]->sr_aaaa;
10765
10766 if (aaaa->aaaa_record->r_status ||
10767 aaaa->aaaa_record->r_type != sres_type_aaaa)
10768 continue; /* There was an error */
10769
10770 su_inet_ntopinet_ntop(AF_INET610, &aaaa->aaaa_addr, addr, sizeof(addr));
10771
10772 if (j == 0)
10773 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__
, 10774, "nta(%p): %s IN AAAA %s\n", (void *)orq, aaaa->aaaa_record
->r_name, addr)) : (void)0)
10774 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__
, 10774, "nta(%p): %s IN AAAA %s\n", (void *)orq, aaaa->aaaa_record
->r_name, addr)) : (void)0)
;
10775 else
10776 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__
, 10776, "nta(%p): AAAA %s\n", (void *)orq, addr)) : (void)0
)
;
10777
10778 assert(j < found)((j < found) ? (void) (0) : __assert_fail ("j < found",
"nta.c", 10778, __PRETTY_FUNCTION__))
;
10779 results[j++] = su_strdup(home, addr);
10780 }
10781
10782 sres_free_answers(orq->orq_agent->sa_resolver, answers);
10783
10784 outgoing_query_results(orq, sq, results, found);
10785}
10786#endif /* SU_HAVE_IN6 */
10787
10788/* Query A records */
10789static
10790int outgoing_query_a(nta_outgoing_t *orq, struct sipdns_query *sq)
10791{
10792 struct sipdns_resolver *sr = orq->orq_resolver;
10793 sres_record_t **answers;
10794
10795 sr->sr_target = sq->sq_domain;
10796 sr->sr_current = sq;
10797
10798 answers = sres_cached_answers(orq->orq_agent->sa_resolver,
10799 sres_type_a, sq->sq_domain);
10800
10801 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__
, 10803, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, sq->sq_domain, "A", answers ? " (cached)" :
"")) : (void)0)
10802 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__
, 10803, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, sq->sq_domain, "A", answers ? " (cached)" :
"")) : (void)0)
10803 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__
, 10803, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn
->tpn_host, sq->sq_domain, "A", answers ? " (cached)" :
"")) : (void)0)
;
10804
10805 if (answers) {
10806 outgoing_answer_a(orq, NULL((void*)0), answers);
10807 return 0;
10808 }
10809
10810 sr->sr_query = sres_query(orq->orq_agent->sa_resolver,
10811 outgoing_answer_a, orq,
10812 sres_type_a, sq->sq_domain);
10813
10814 return outgoing_resolving(orq);
10815}
10816
10817/* Process A records */
10818static
10819void outgoing_answer_a(sres_context_t *orq, sres_query_t *q,
10820 sres_record_t *answers[])
10821{
10822 struct sipdns_resolver *sr = orq->orq_resolver;
10823 su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request));
10824 struct sipdns_query *sq = sr->sr_current;
10825
10826 int i, j, found;
10827 char *result, **results = NULL((void*)0);
10828
10829 assert(sq)((sq) ? (void) (0) : __assert_fail ("sq", "nta.c", 10829, __PRETTY_FUNCTION__
))
; assert(sq->sq_type == sres_type_a)((sq->sq_type == sres_type_a) ? (void) (0) : __assert_fail
("sq->sq_type == sres_type_a", "nta.c", 10829, __PRETTY_FUNCTION__
))
;
10830
10831 sr->sr_query = NULL((void*)0);
10832
10833 for (i = 0, found = 0; answers && answers[i]; i++) {
10834 sres_a_record_t const *a = answers[i]->sr_a;
10835 if (a->a_record->r_status == 0 &&
10836 a->a_record->r_type == sres_type_a)
10837 found++;
10838 }
10839
10840 if (found > 1)
10841 results = su_zalloc(home, (found + 1) * (sizeof *results));
10842 else if (found)
10843 results = &result;
10844
10845 for (i = j = 0; answers && answers[i]; i++) {
10846 char addr[SU_ADDRSIZE(48)];
10847 sres_a_record_t const *a = answers[i]->sr_a;
10848
10849 if (a->a_record->r_status ||
10850 a->a_record->r_type != sres_type_a)
10851 continue; /* There was an error */
10852
10853 su_inet_ntopinet_ntop(AF_INET2, &a->a_addr, addr, sizeof(addr));
10854
10855 if (j == 0)
10856 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__
, 10856, "nta: %s IN A %s\n", a->a_record->r_name, addr
)) : (void)0)
;
10857 else
10858 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__
, 10858, "nta(%p): A %s\n", (void *)orq, addr)) : (void)0)
;
10859
10860 assert(j < found)((j < found) ? (void) (0) : __assert_fail ("j < found",
"nta.c", 10860, __PRETTY_FUNCTION__))
;
10861 results[j++] = su_strdup(home, addr);
10862 }
10863
10864 sres_free_answers(orq->orq_agent->sa_resolver, answers);
10865
10866 outgoing_query_results(orq, sq, results, found);
10867}
10868
10869/** Store A/AAAA query results */
10870static void
10871outgoing_query_results(nta_outgoing_t *orq,
10872 struct sipdns_query *sq,
10873 char *results[],
10874 size_t rlen)
10875{
10876 struct sipdns_resolver *sr = orq->orq_resolver;
10877
10878 if (sq->sq_type == sr->sr_a_aaaa1 &&
10879 sq->sq_type != sr->sr_a_aaaa2) {
10880 sq->sq_type = sr->sr_a_aaaa2;
10881
10882 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__
, 10883, "nta(%p): %s %s record still unresolved\n", (void *)
orq, sq->sq_domain, sq->sq_type == sres_type_a ? "A" : "AAAA"
)) : (void)0)
10883 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__
, 10883, "nta(%p): %s %s record still unresolved\n", (void *)
orq, sq->sq_domain, sq->sq_type == sres_type_a ? "A" : "AAAA"
)) : (void)0)
;
10884
10885 /*
10886 * Three possible policies:
10887 * 1) try each host for AAAA/A, then A/AAAA
10888 * 2) try everything first for AAAA/A, then everything for A/AAAA
10889 * 3) try one SRV record results for AAAA/A, then for A/AAAA,
10890 * then next SRV record
10891 */
10892
10893 /* We use now policy #1 */
10894 if (!(sq->sq_next = sr->sr_head))
10895 sr->sr_tail = &sq->sq_next;
10896 sr->sr_head = sq;
10897 }
10898 else {
10899 sq->sq_next = sr->sr_done, sr->sr_done = sq;
10900
10901 if (rlen == 0 && sq->sq_grayish)
10902 outgoing_graylist(orq, sq);
10903 }
10904
10905 if (rlen > 1)
10906 sr->sr_results = results;
10907 else
10908 sr->sr_current = NULL((void*)0);
10909
10910 if (rlen > 0) {
10911 orq->orq_resolved = 1;
10912 orq->orq_tpn->tpn_host = results[0];
10913 if (sq->sq_proto) orq->orq_tpn->tpn_proto = sq->sq_proto;
10914 if (sq->sq_port[0]) orq->orq_tpn->tpn_port = sq->sq_port;
10915 outgoing_prepare_send(orq);
10916 } else {
10917 outgoing_resolve_next(orq);
10918 }
10919}
10920
10921
10922#endif
10923
10924/* ====================================================================== */
10925/* 10) Reliable responses */
10926
10927static nta_prack_f nta_reliable_destroyed;
10928
10929/**
10930 * Check that server transaction can be used to send reliable provisional
10931 * responses.
10932 */
10933su_inlinestatic inline
10934int reliable_check(nta_incoming_t *irq)
10935{
10936 if (irq == NULL((void*)0) || irq->irq_status >= 200 || !irq->irq_agent)
10937 return 0;
10938
10939 if (irq->irq_reliable && irq->irq_reliable->rel_status >= 200)
10940 return 0;
10941
10942 /* @RSeq is initialized to nonzero when request requires/supports 100rel */
10943 if (irq->irq_rseq == 0)
10944 return 0;
10945
10946 if (irq->irq_rseq == 0xffffffffU) /* already sent >> 2**31 responses */
10947 return 0;
10948
10949 return 1;
10950}
10951
10952/** Respond reliably.
10953 *
10954 * @param irq
10955 * @param callback
10956 * @param rmagic
10957 * @param status
10958 * @param phrase
10959 * @param tag, value, ..
10960 */
10961nta_reliable_t *nta_reliable_treply(nta_incoming_t *irq,
10962 nta_prack_f *callback,
10963 nta_reliable_magic_t *rmagic,
10964 int status, char const *phrase,
10965 tag_type_t tag,
10966 tag_value_t value, ...)
10967{
10968 ta_list ta;
10969 msg_t *msg;
10970 sip_t *sip;
10971 nta_reliable_t *retval = NULL((void*)0);
10972
10973 if (!reliable_check(irq) || (status <= 100 || status >= 200))
10974 return NULL((void*)0);
10975
10976 msg = nta_msg_create(irq->irq_agent, 0);
10977 sip = sip_object(msg);
10978
10979 if (!sip)
10980 return NULL((void*)0);
10981
10982 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)
;
10983
10984 if (0 > nta_incoming_complete_response(irq, msg, status, phrase,
10985 ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
))
10986 msg_destroy(msg);
10987 else if (!(retval = reliable_mreply(irq, callback, rmagic, msg, sip)))
10988 msg_destroy(msg);
10989
10990 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))
;
10991
10992 return retval;
10993}
10994
10995/** Respond reliably with @a msg.
10996 *
10997 * @note
10998 * The stack takes over the ownership of @a msg. (It is destroyed even if
10999 * sending the response fails.)
11000 *
11001 * @param irq
11002 * @param callback
11003 * @param rmagic
11004 * @param msg
11005 */
11006nta_reliable_t *nta_reliable_mreply(nta_incoming_t *irq,
11007 nta_prack_f *callback,
11008 nta_reliable_magic_t *rmagic,
11009 msg_t *msg)
11010{
11011 sip_t *sip = sip_object(msg);
11012
11013 if (!reliable_check(irq)) {
11014 msg_destroy(msg);
11015 return NULL((void*)0);
11016 }
11017
11018 if (sip == NULL((void*)0) || !sip->sip_status || sip->sip_status->st_status <= 100) {
11019 msg_destroy(msg);
11020 return NULL((void*)0);
11021 }
11022
11023 if (sip->sip_status->st_status >= 200) {
11024 incoming_final_failed(irq, msg);
11025 return NULL((void*)0);
11026 }
11027
11028 return reliable_mreply(irq, callback, rmagic, msg, sip);
11029}
11030
11031static
11032nta_reliable_t *reliable_mreply(nta_incoming_t *irq,
11033 nta_prack_f *callback,
11034 nta_reliable_magic_t *rmagic,
11035 msg_t *msg,
11036 sip_t *sip)
11037{
11038 nta_reliable_t *rel;
11039 nta_agent_t *agent;
11040
11041 agent = irq->irq_agent;
11042
11043 if (callback == NULL((void*)0))
11044 callback = nta_reliable_destroyed;
11045
11046 rel = su_zalloc(agent->sa_home, sizeof(*rel));
11047 if (rel) {
11048 rel->rel_irq = irq;
11049 rel->rel_callback = callback;
11050 rel->rel_magic = rmagic;
11051 rel->rel_unsent = msg;
11052 rel->rel_status = sip->sip_status->st_status;
11053 rel->rel_precious = sip->sip_payload != NULL((void*)0);
11054 rel->rel_next = irq->irq_reliable;
11055
11056 /*
11057 * If there already is a un-pr-acknowledged response, queue this one
11058 * until at least one response is pr-acknowledged.
11059 */
11060 if (irq->irq_reliable &&
11061 (irq->irq_reliable->rel_next == NULL((void*)0) ||
11062 irq->irq_reliable->rel_rseq == 0)) {
11063 return irq->irq_reliable = rel;
11064 }
11065
11066 if (reliable_send(irq, rel, msg_ref_create(msg), sip) < 0) {
11067 msg_destroy(msg);
11068 su_free(agent->sa_home, rel);
11069 return NULL((void*)0);
11070 }
11071
11072 irq->irq_reliable = rel;
11073
11074 return callback ? rel : (nta_reliable_t *)-1;
11075 }
11076
11077 msg_destroy(msg);
11078 return NULL((void*)0);
11079}
11080
11081static
11082int reliable_send(nta_incoming_t *irq,
11083 nta_reliable_t *rel,
11084 msg_t *msg,
11085 sip_t *sip)
11086{
11087 nta_agent_t *sa = irq->irq_agent;
11088 su_home_t *home = msg_home(msg)((su_home_t*)(msg));
11089 sip_rseq_t rseq[1];
11090 sip_rseq_init(rseq);
11091
11092 if (sip->sip_require)
11093 msg_header_replace_param(home, sip->sip_require->k_common, "100rel");
11094 else
11095 sip_add_make(msg, sip, sip_require_class, "100rel");
11096
11097 rel->rel_rseq = rseq->rs_response = irq->irq_rseq;
11098 sip_add_dup(msg, sip, (sip_header_t *)rseq);
11099
11100 if (!sip->sip_rseq || incoming_reply(irq, msg, sip) < 0) {
11101 msg_destroy(msg);
11102 return -1;
11103 }
11104
11105 irq->irq_rseq++;
11106
11107 if (irq->irq_queue == sa->sa_in.preliminary)
11108 /* Make sure we are moved to the tail */
11109 incoming_remove(irq);
11110
11111 incoming_queue(sa->sa_in.preliminary, irq); /* P1 */
11112 incoming_set_timer(irq, sa->sa_t1); /* P2 */
11113
11114 return 0;
11115}
11116
11117/** Queue final response when there are unsent precious preliminary responses */
11118static
11119int reliable_final(nta_incoming_t *irq, msg_t *msg, sip_t *sip)
11120{
11121 nta_reliable_t *r;
11122 unsigned already_in_callback;
11123 /*
11124 * We delay sending final response if it's 2XX and
11125 * an unpracked reliable response contains session description
11126 */
11127 /* Get last unpracked response from queue */
11128 if (sip->sip_status->st_status < 300)
11129 for (r = irq->irq_reliable; r; r = r->rel_next)
11130 if (r->rel_unsent && r->rel_precious) {
11131 /* Delay sending 2XX */
11132 reliable_mreply(irq, NULL((void*)0), NULL((void*)0), msg, sip);
11133 return 0;
11134 }
11135
11136 /* Flush unsent responses. */
11137 already_in_callback = irq->irq_in_callback;
11138 irq->irq_in_callback = 1;
11139 reliable_flush(irq);
11140 irq->irq_in_callback = already_in_callback;
11141
11142 if (!already_in_callback && irq->irq_terminated && irq->irq_destroyed) {
11143 incoming_free(irq);
11144 msg_destroy(msg);
11145 return 0;
11146 }
11147
11148 return 1;
11149}
11150
11151/** Get latest reliably sent response */
11152static
11153msg_t *reliable_response(nta_incoming_t *irq)
11154{
11155 nta_reliable_t *r, *rel;
11156
11157 /* Get last unpracked response from queue */
11158 for (rel = NULL((void*)0), r = irq->irq_reliable; r; r = r->rel_next)
11159 if (!r->rel_pracked)
11160 rel = r;
11161
11162 assert(rel)((rel) ? (void) (0) : __assert_fail ("rel", "nta.c", 11162, __PRETTY_FUNCTION__
))
;
11163
11164 return rel->rel_unsent;
11165}
11166
11167/* Find un-PRACKed responses */
11168static
11169nta_reliable_t *reliable_find(nta_agent_t const *agent,
11170 sip_t const *sip)
11171{
11172 incoming_htable_t const *iht = agent->sa_incoming;
11173 nta_incoming_t *irq, **ii;
11174 sip_call_id_t const *i = sip->sip_call_id;
11175 sip_rack_t const *rack = sip->sip_rack;
11176 hash_value_t hash = NTA_HASH(i, rack->ra_cseq)((i)->i_hash + 26839U * (uint32_t)(rack->ra_cseq));
11177
11178 /* XXX - add own hash table for 100rel */
11179
11180 for (ii = incoming_htable_hash(iht, hash);
11181 (irq = *ii);
11182 ii = incoming_htable_next(iht, ii)) {
11183
11184 if (hash == irq->irq_hash &&
11185 irq->irq_call_id->i_hash == i->i_hash &&
11186 irq->irq_cseq->cs_seq == rack->ra_cseq &&
11187 irq->irq_method == sip_method_invite &&
11188 strcmp(irq->irq_call_id->i_id, i->i_id)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(irq->irq_call_id->i_id) && __builtin_constant_p
(i->i_id) && (__s1_len = __builtin_strlen (irq->
irq_call_id->i_id), __s2_len = __builtin_strlen (i->i_id
), (!((size_t)(const void *)((irq->irq_call_id->i_id) +
1) - (size_t)(const void *)(irq->irq_call_id->i_id) ==
1) || __s1_len >= 4) && (!((size_t)(const void *)
((i->i_id) + 1) - (size_t)(const void *)(i->i_id) == 1)
|| __s2_len >= 4)) ? __builtin_strcmp (irq->irq_call_id
->i_id, i->i_id) : (__builtin_constant_p (irq->irq_call_id
->i_id) && ((size_t)(const void *)((irq->irq_call_id
->i_id) + 1) - (size_t)(const void *)(irq->irq_call_id->
i_id) == 1) && (__s1_len = __builtin_strlen (irq->
irq_call_id->i_id), __s1_len < 4) ? (__builtin_constant_p
(i->i_id) && ((size_t)(const void *)((i->i_id)
+ 1) - (size_t)(const void *)(i->i_id) == 1) ? __builtin_strcmp
(irq->irq_call_id->i_id, i->i_id) : (__extension__ (
{ const unsigned char *__s2 = (const unsigned char *) (const char
*) (i->i_id); int __result = (((const unsigned char *) (const
char *) (irq->irq_call_id->i_id))[0] - __s2[0]); if (__s1_len
> 0 && __result == 0) { __result = (((const unsigned
char *) (const char *) (irq->irq_call_id->i_id))[1] - __s2
[1]); if (__s1_len > 1 && __result == 0) { __result
= (((const unsigned char *) (const char *) (irq->irq_call_id
->i_id))[2] - __s2[2]); if (__s1_len > 2 && __result
== 0) __result = (((const unsigned char *) (const char *) (irq
->irq_call_id->i_id))[3] - __s2[3]); } } __result; })))
: (__builtin_constant_p (i->i_id) && ((size_t)(const
void *)((i->i_id) + 1) - (size_t)(const void *)(i->i_id
) == 1) && (__s2_len = __builtin_strlen (i->i_id),
__s2_len < 4) ? (__builtin_constant_p (irq->irq_call_id
->i_id) && ((size_t)(const void *)((irq->irq_call_id
->i_id) + 1) - (size_t)(const void *)(irq->irq_call_id->
i_id) == 1) ? __builtin_strcmp (irq->irq_call_id->i_id,
i->i_id) : (- (__extension__ ({ const unsigned char *__s2
= (const unsigned char *) (const char *) (irq->irq_call_id
->i_id); int __result = (((const unsigned char *) (const char
*) (i->i_id))[0] - __s2[0]); if (__s2_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (i->i_id))[1] - __s2[1]); if (__s2_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (i->i_id))[2] - __s2[2]); if (__s2_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) (i->i_id))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp
(irq->irq_call_id->i_id, i->i_id)))); })
== 0 &&
11189 (irq->irq_to->a_tag == NULL((void*)0) ||
11190 su_casematch(irq->irq_to->a_tag, sip->sip_to->a_tag)) &&
11191 su_casematch(irq->irq_from->a_tag, sip->sip_from->a_tag)) {
11192
11193 nta_reliable_t const *rel;
11194
11195 /* Found matching INVITE */
11196 for (rel = irq->irq_reliable; rel; rel = rel->rel_next)
11197 if (rel->rel_rseq == rack->ra_response)
11198 return (nta_reliable_t *)rel;
11199
11200 }
11201 }
11202
11203 return NULL((void*)0);
11204}
11205
11206/** Process incoming PRACK with matching @RAck field */
11207static
11208int reliable_recv(nta_reliable_t *rel, msg_t *msg, sip_t *sip, tport_t *tp)
11209{
11210 nta_incoming_t *irq = rel->rel_irq;
11211 nta_incoming_t *pr_irq;
11212 int status;
11213
11214 rel->rel_pracked = 1;
11215 msg_ref_destroy(rel->rel_unsent), rel->rel_unsent = NULL((void*)0);
11216
11217 pr_irq = incoming_create(irq->irq_agent, msg, sip, tp, irq->irq_tag);
11218 if (!pr_irq) {
11219 mreply(irq->irq_agent, NULL((void*)0),
11220 SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error, msg,
11221 tp, 0, 0, NULL((void*)0),
11222 TAG_END()(tag_type_t)0, (tag_value_t)0);
11223 return 0;
11224 }
11225
11226 if (irq->irq_status < 200) {
11227 incoming_queue(irq->irq_agent->sa_in.proceeding, irq); /* Reset P1 */
11228 incoming_reset_timer(irq); /* Reset P2 */
11229 }
11230
11231 irq->irq_in_callback = pr_irq->irq_in_callback = 1;
11232 status = rel->rel_callback(rel->rel_magic, rel, pr_irq, sip); rel = NULL((void*)0);
11233 irq->irq_in_callback = pr_irq->irq_in_callback = 0;
11234
11235 if (pr_irq->irq_completed) { /* Already sent final response */
11236 if (pr_irq->irq_terminated && pr_irq->irq_destroyed)
11237 incoming_free(pr_irq);
11238 }
11239 else if (status != 0) {
11240 if (status < 200 || status > 299) {
11241 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__
, 11242, "nta_reliable(): invalid status %03d from callback\n"
, status)) : (void)0)
11242 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__
, 11242, "nta_reliable(): invalid status %03d from callback\n"
, status)) : (void)0)
;
11243 status = 200;
11244 }
11245 nta_incoming_treply(pr_irq, status, "OK", TAG_END()(tag_type_t)0, (tag_value_t)0);
11246 nta_incoming_destroy(pr_irq);
11247 }
11248
11249 /* If there are queued unsent reliable responses, send them all. */
11250 while (irq->irq_reliable && irq->irq_reliable->rel_rseq == 0) {
11251 nta_reliable_t *r;
11252
11253 for (r = irq->irq_reliable; r; r = r->rel_next)
11254 if (r->rel_rseq == 0)
11255 rel = r;
11256
11257 msg = rel->rel_unsent, sip = sip_object(msg);
11258
11259 if (sip->sip_status->st_status < 200) {
11260 if (reliable_send(irq, rel, msg_ref_create(msg), sip) < 0) {
11261 assert(!"send reliable response")((!"send reliable response") ? (void) (0) : __assert_fail ("!\"send reliable response\""
, "nta.c", 11261, __PRETTY_FUNCTION__))
;
11262 }
11263 }
11264 else {
11265 /*
11266 * XXX
11267 * Final response should be delayed until a reliable provisional
11268 * response has been pracked
11269 */
11270 rel->rel_unsent = NULL((void*)0), rel->rel_rseq = (uint32_t)-1;
11271 if (incoming_reply(irq, msg, sip) < 0) {
11272 assert(!"send delayed final response")((!"send delayed final response") ? (void) (0) : __assert_fail
("!\"send delayed final response\"", "nta.c", 11272, __PRETTY_FUNCTION__
))
;
11273 }
11274 }
11275 }
11276
11277 return 0;
11278}
11279
11280/** Flush unacknowledged and unsent reliable responses */
11281void reliable_flush(nta_incoming_t *irq)
11282{
11283 nta_reliable_t *r, *rel;
11284
11285 do {
11286 for (r = irq->irq_reliable, rel = NULL((void*)0); r; r = r->rel_next)
11287 if (r->rel_unsent)
11288 rel = r;
11289
11290 if (rel) {
11291 rel->rel_pracked = 1;
11292 msg_ref_destroy(rel->rel_unsent), rel->rel_unsent = NULL((void*)0);
11293 rel->rel_callback(rel->rel_magic, rel, NULL((void*)0), NULL((void*)0));
11294 }
11295 } while (rel);
11296}
11297
11298void reliable_timeout(nta_incoming_t *irq, int timeout)
11299{
11300 if (timeout)
11301 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__
, 11301, "nta: response timeout with %u\n", irq->irq_status
)) : (void)0)
;
11302
11303 irq->irq_in_callback = 1;
11304
11305 reliable_flush(irq);
11306
11307 if (irq->irq_callback)
11308 irq->irq_callback(irq->irq_magic, irq, NULL((void*)0));
11309
11310 irq->irq_in_callback = 0;
11311
11312 if (!timeout)
11313 return;
11314
11315 if (irq->irq_completed && irq->irq_destroyed)
11316 incoming_free(irq), irq = NULL((void*)0);
11317 else if (irq->irq_status < 200)
11318 nta_incoming_treply(irq, 503, "Reliable Response Time-Out", TAG_END()(tag_type_t)0, (tag_value_t)0);
11319}
11320
11321#if 0 /* Not needed, yet. */
11322/** Use this callback when normal leg callback is supposed to
11323 * process incoming PRACK requests
11324 */
11325int nta_reliable_leg_prack(nta_reliable_magic_t *magic,
11326 nta_reliable_t *rel,
11327 nta_incoming_t *irq,
11328 sip_t const *sip)
11329{
11330 nta_agent_t *agent;
11331 nta_leg_t *leg;
11332 char const *method_name;
11333 url_t url[1];
11334 int retval;
11335
11336 if (irq == NULL((void*)0) || sip == NULL((void*)0) || rel == NULL((void*)0) ||
11337 sip_object(irq->irq_request) != sip)
11338 return 500;
11339
11340 agent = irq->irq_agent;
11341 method_name = sip->sip_request->rq_method_name;
11342 *url = *sip->sip_request->rq_url; url->url_params = NULL((void*)0);
11343 agent_aliases(agent, url, irq->irq_tport); /* canonize urls */
11344
11345 if ((leg = leg_find(irq->irq_agent,
11346 method_name, url,
11347 sip->sip_call_id,
11348 sip->sip_from->a_tag,
11349 sip->sip_to->a_tag))) {
11350 /* Use existing dialog */
11351 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__
, 11353, "nta: %s (%u) %s\n", method_name, sip->sip_cseq->
cs_seq, "PRACK processed by default callback, too")) : (void)
0)
11352 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__
, 11353, "nta: %s (%u) %s\n", method_name, sip->sip_cseq->
cs_seq, "PRACK processed by default callback, too")) : (void)
0)
11353 "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__
, 11353, "nta: %s (%u) %s\n", method_name, sip->sip_cseq->
cs_seq, "PRACK processed by default callback, too")) : (void)
0)
;
11354 retval = leg->leg_callback(leg->leg_magic, leg, irq, sip);
11355 }
11356 else {
11357 retval = 500;
11358 }
11359
11360 nta_reliable_destroy(rel);
11361
11362 return retval;
11363}
11364#endif
11365
11366/** Destroy a reliable response.
11367 *
11368 * Mark a reliable response object for destroyal and free it if possible.
11369 */
11370void nta_reliable_destroy(nta_reliable_t *rel)
11371{
11372 if (rel == NULL((void*)0) || rel == NONE((void *)-1))
11373 return;
11374
11375 if (rel->rel_callback == nta_reliable_destroyed)
11376 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__
, 11376, "%s(%p): %s\n", __func__, (void *)rel, "already destroyed"
)) : (void)0)
;
11377
11378 rel->rel_callback = nta_reliable_destroyed;
11379
11380 if (rel->rel_response)
11381 return;
11382
11383 nta_reliable_destroyed(NULL((void*)0), rel, NULL((void*)0), NULL((void*)0));
11384}
11385
11386/** Free and unallocate the nta_reliable_t structure. */
11387static
11388int nta_reliable_destroyed(nta_reliable_magic_t *rmagic,
11389 nta_reliable_t *rel,
11390 nta_incoming_t *prack,
11391 sip_t const *sip)
11392{
11393 nta_reliable_t **prev;
11394
11395 assert(rel)((rel) ? (void) (0) : __assert_fail ("rel", "nta.c", 11395, __PRETTY_FUNCTION__
))
; assert(rel->rel_irq)((rel->rel_irq) ? (void) (0) : __assert_fail ("rel->rel_irq"
, "nta.c", 11395, __PRETTY_FUNCTION__))
;
11396
11397 for (prev = &rel->rel_irq->irq_reliable; *prev; prev = &(*prev)->rel_next)
11398 if (*prev == rel)
11399 break;
11400
11401 if (!*prev) {
11402 assert(*prev)((*prev) ? (void) (0) : __assert_fail ("*prev", "nta.c", 11402
, __PRETTY_FUNCTION__))
;
11403 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__
, 11403, "%s(%p): %s\n", __func__, (void *)rel, "not linked")
) : (void)0)
;
11404 return 200;
11405 }
11406
11407 *prev = rel->rel_next;
11408
11409 if (rel->rel_unsent)
11410 msg_destroy(rel->rel_unsent), rel->rel_unsent = NULL((void*)0);
11411
11412 su_free(rel->rel_irq->irq_agent->sa_home, rel);
11413
11414 return 200;
11415}
11416
11417/** Validate a reliable response. */
11418int outgoing_recv_reliable(nta_outgoing_t *orq,
11419 msg_t *msg,
11420 sip_t *sip)
11421{
11422 short status = sip->sip_status->st_status;
11423 char const *phrase = sip->sip_status->st_phrase;
11424 uint32_t rseq = sip->sip_rseq->rs_response;
11425
11426 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__
, 11427, "nta: %03u %s is reliably received with RSeq: %u\n",
status, phrase, rseq)) : (void)0)
11427 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__
, 11427, "nta: %03u %s is reliably received with RSeq: %u\n",
status, phrase, rseq)) : (void)0)
;
11428
11429 /* Cannot handle reliable responses unless we have a full dialog */
11430 if (orq->orq_rseq == 0 && !orq->orq_to->a_tag) {
11431 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__
, 11432, "nta: %03u %s with initial RSeq: %u outside dialog\n"
, status, phrase, rseq)) : (void)0)
11432 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__
, 11432, "nta: %03u %s with initial RSeq: %u outside dialog\n"
, status, phrase, rseq)) : (void)0)
;
11433 return 0;
11434 }
11435
11436 if (rseq <= orq->orq_rseq) {
11437 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__
, 11438, "nta: %03u %s already received (RSeq: %u, expecting %u)\n"
, status, phrase, rseq, orq->orq_rseq + 1)) : (void)0)
11438 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__
, 11438, "nta: %03u %s already received (RSeq: %u, expecting %u)\n"
, status, phrase, rseq, orq->orq_rseq + 1)) : (void)0)
;
11439 return -1;
11440 }
11441
11442 if (orq->orq_rseq && orq->orq_rseq + 1 != rseq) {
11443 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__
, 11445, "nta: %03d %s is not expected (RSeq: %u, expecting %u)\n"
, status, sip->sip_status->st_phrase, rseq, orq->orq_rseq
+ 1)) : (void)0)
11444 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__
, 11445, "nta: %03d %s is not expected (RSeq: %u, expecting %u)\n"
, status, sip->sip_status->st_phrase, rseq, orq->orq_rseq
+ 1)) : (void)0)
11445 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__
, 11445, "nta: %03d %s is not expected (RSeq: %u, expecting %u)\n"
, status, sip->sip_status->st_phrase, rseq, orq->orq_rseq
+ 1)) : (void)0)
;
11446 return -1;
11447 }
11448
11449 return 0;
11450}
11451
11452/** Create a tagged fork of outgoing request.
11453 *
11454 * When a dialog-creating INVITE request is forked, each response from
11455 * diffent fork will create an early dialog with a distinct tag in @To
11456 * header. When each fork should be handled separately, a tagged INVITE
11457 * request can be used. It will only receive responses from the specified
11458 * fork. Please note that the tagged transaction should be terminated with
11459 * the final response from another fork, too.
11460 *
11461 * @param orq
11462 * @param callback
11463 * @param magic
11464 * @param to_tag
11465 * @param rseq
11466 *
11467 * @bug Fix the memory leak - either one of the requests is left unreleased
11468 * for ever.
11469 */
11470nta_outgoing_t *nta_outgoing_tagged(nta_outgoing_t *orq,
11471 nta_response_f *callback,
11472 nta_outgoing_magic_t *magic,
11473 char const *to_tag,
11474 sip_rseq_t const *rseq)
11475{
11476 nta_agent_t *agent;
11477 su_home_t *home;
11478 nta_outgoing_t *tagged;
11479 sip_to_t *to;
11480
11481 if (orq == NULL((void*)0) || to_tag == NULL((void*)0))
11482 return NULL((void*)0);
11483
11484 if (orq->orq_to->a_tag) {
11485 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__
, 11486, "%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)
11486 (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__
, 11486, "%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)
;
11487 return NULL((void*)0);
11488 }
11489 if (orq->orq_method != sip_method_invite) {
11490 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__
, 11491, "%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)
11491 (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__
, 11491, "%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)
;
11492 return NULL((void*)0);
11493 }
11494 if (orq->orq_status < 100) {
11495 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__
, 11496, "%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)
11496 (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__
, 11496, "%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)
;
11497 return NULL((void*)0);
11498 }
11499
11500 assert(orq->orq_agent)((orq->orq_agent) ? (void) (0) : __assert_fail ("orq->orq_agent"
, "nta.c", 11500, __PRETTY_FUNCTION__))
; assert(orq->orq_request)((orq->orq_request) ? (void) (0) : __assert_fail ("orq->orq_request"
, "nta.c", 11500, __PRETTY_FUNCTION__))
;
11501
11502 agent = orq->orq_agent;
11503 tagged = su_zalloc(agent->sa_home, sizeof(*tagged));
11504
11505 home = msg_home((msg_t *)orq->orq_request)((su_home_t*)((msg_t *)orq->orq_request));
11506
11507 tagged->orq_hash = orq->orq_hash;
11508 tagged->orq_agent = orq->orq_agent;
11509 tagged->orq_callback = callback;
11510 tagged->orq_magic = magic;
11511
11512 tagged->orq_method = orq->orq_method;
11513 tagged->orq_method_name = orq->orq_method_name;
11514 tagged->orq_url = orq->orq_url;
11515 tagged->orq_from = orq->orq_from;
11516
11517 sip_to_tag(home, to = sip_to_copy(home, orq->orq_to), to_tag);
11518
11519 tagged->orq_to = to;
11520 tagged->orq_tag = to->a_tag;
11521 tagged->orq_cseq = orq->orq_cseq;
11522 tagged->orq_call_id = orq->orq_call_id;
11523
11524 tagged->orq_request = msg_ref_create(orq->orq_request);
11525 tagged->orq_response = msg_ref_create(orq->orq_response);
11526
11527 tagged->orq_status = orq->orq_status;
11528 tagged->orq_via_added = orq->orq_via_added;
11529 tagged->orq_prepared = orq->orq_prepared;
11530 tagged->orq_reliable = orq->orq_reliable;
11531 tagged->orq_sips = orq->orq_sips;
11532 tagged->orq_uas = orq->orq_uas;
11533 tagged->orq_pass_100 = orq->orq_pass_100;
11534 tagged->orq_must_100rel = orq->orq_must_100rel;
11535 tagged->orq_100rel = orq->orq_100rel;
11536 tagged->orq_route = orq->orq_route;
11537 *tagged->orq_tpn = *orq->orq_tpn;
11538 tagged->orq_tport = tport_ref(orq->orq_tport);
11539 if (orq->orq_cc)
11540 tagged->orq_cc = nta_compartment_ref(orq->orq_cc);
11541 tagged->orq_branch = orq->orq_branch;
11542 tagged->orq_via_branch = orq->orq_via_branch;
11543
11544 if (tagged->orq_uas) {
11545 tagged->orq_forking = orq;
11546 tagged->orq_forks = orq->orq_forks;
11547 tagged->orq_forked = 1;
11548 orq->orq_forks = tagged;
11549 }
11550
11551 outgoing_insert(agent, tagged);
11552
11553 return tagged;
11554}
11555
11556/**PRACK a provisional response.
11557 *
11558 * Create and send a PRACK request used to acknowledge a provisional
11559 * response.
11560 *
11561 * The request is sent using the route of the original request @a oorq.
11562 *
11563 * When NTA receives response to the prack request, it invokes the @a
11564 * callback function.
11565 *
11566 * @param leg dialog object
11567 * @param oorq original transaction request
11568 * @param callback callback function (may be @c NULL)
11569 * @param magic application context pointer
11570 * @param route_url optional URL used to route transaction requests
11571 * @param resp (optional) response message to be acknowledged
11572 * @param tag,value,... optional
11573 *
11574 * @return
11575 * If successful, return a pointer to newly created client transaction
11576 * object for PRACK request, NULL otherwise.
11577 *
11578 * @sa
11579 * nta_outgoing_tcreate(), nta_outgoing_tcancel(), nta_outgoing_destroy().
11580 */
11581nta_outgoing_t *nta_outgoing_prack(nta_leg_t *leg,
11582 nta_outgoing_t *oorq,
11583 nta_response_f *callback,
11584 nta_outgoing_magic_t *magic,
11585 url_string_t const *route_url,
11586 sip_t const *resp,
11587 tag_type_t tag, tag_value_t value, ...)
11588{
11589 ta_list ta;
11590 msg_t *msg;
11591 su_home_t *home;
11592 sip_t *sip;
11593 sip_to_t const *to = NULL((void*)0);
11594 sip_route_t *route = NULL((void*)0), r0[1];
11595 nta_outgoing_t *orq = NULL((void*)0);
11596 sip_rack_t *rack = NULL((void*)0), rack0[1];
11597
11598 if (!leg || !oorq) {
11599 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__
, 11599, "%s: invalid arguments\n", __func__)) : (void)0)
;
11600 return NULL((void*)0);
11601 }
11602
11603 sip_rack_init(rack0);
11604
11605 if (resp) {
11606 if (!resp->sip_status) {
11607 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__
, 11607, "%s: invalid arguments\n", __func__)) : (void)0)
;
11608 return NULL((void*)0);
11609 }
11610
11611 if (resp->sip_status->st_status <= 100 ||
11612 resp->sip_status->st_status >= 200) {
11613 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__
, 11614, "%s: %u response cannot be PRACKed\n", __func__, resp
->sip_status->st_status)) : (void)0)
11614 __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__
, 11614, "%s: %u response cannot be PRACKed\n", __func__, resp
->sip_status->st_status)) : (void)0)
;
11615 return NULL((void*)0);
11616 }
11617
11618 if (!resp->sip_rseq) {
11619 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__
, 11620, "%s: %u response missing RSeq\n", __func__, resp->
sip_status->st_status)) : (void)0)
11620 __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__
, 11620, "%s: %u response missing RSeq\n", __func__, resp->
sip_status->st_status)) : (void)0)
;
11621 return NULL((void*)0);
11622 }
11623
11624 if (resp->sip_rseq->rs_response <= oorq->orq_rseq) {
11625 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__
, 11626, "%s: %u response RSeq does not match received RSeq\n"
, __func__, resp->sip_status->st_status)) : (void)0)
11626 __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__
, 11626, "%s: %u response RSeq does not match received RSeq\n"
, __func__, resp->sip_status->st_status)) : (void)0)
;
11627 return NULL((void*)0);
11628 }
11629 if (!oorq->orq_must_100rel &&
11630 !sip_has_feature(resp->sip_require, "100rel")) {
11631 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__
, 11632, "%s: %u response does not require 100rel\n", __func__
, resp->sip_status->st_status)) : (void)0)
11632 __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__
, 11632, "%s: %u response does not require 100rel\n", __func__
, resp->sip_status->st_status)) : (void)0)
;
11633 return NULL((void*)0);
11634 }
11635
11636 if (!resp->sip_to->a_tag) {
11637 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__
, 11638, "%s: %u response has no To tag\n", __func__, resp->
sip_status->st_status)) : (void)0)
11638 __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__
, 11638, "%s: %u response has no To tag\n", __func__, resp->
sip_status->st_status)) : (void)0)
;
11639 return NULL((void*)0);
11640 }
11641 if (su_strcasecmp(resp->sip_to->a_tag, leg->leg_remote->a_tag) ||
11642 su_strcasecmp(resp->sip_to->a_tag, oorq->orq_to->a_tag)) {
11643 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__
, 11644, "%s: %u response To tag does not agree with dialog tag\n"
, __func__, resp->sip_status->st_status)) : (void)0)
11644 __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__
, 11644, "%s: %u response To tag does not agree with dialog tag\n"
, __func__, resp->sip_status->st_status)) : (void)0)
;
11645 return NULL((void*)0);
11646 }
11647
11648 to = resp->sip_to;
11649 rack = rack0;
11650
11651 rack->ra_response = resp->sip_rseq->rs_response;
11652 rack->ra_cseq = resp->sip_cseq->cs_seq;
11653 rack->ra_method = resp->sip_cseq->cs_method;
11654 rack->ra_method_name = resp->sip_cseq->cs_method_name;
11655 }
11656
11657 msg = nta_msg_create(leg->leg_agent, 0);
11658 sip = sip_object(msg); home = msg_home(msg)((su_home_t*)(msg));
11659
11660 if (!sip)
11661 return NULL((void*)0);
11662
11663 if (!leg->leg_route && resp) {
11664 /* Insert contact into route */
11665 if (resp->sip_contact) {
11666 sip_route_init(r0)->r_url[0] = resp->sip_contact->m_url[0];
11667 route = sip_route_dup(home, r0);
11668 }
11669
11670 /* Reverse record route */
11671 if (resp->sip_record_route) {
11672 sip_route_t *r, *r_next;
11673 for (r = sip_route_dup(home, resp->sip_record_route); r; r = r_next) {
11674 r_next = r->r_next, r->r_next = route, route = r;
11675 }
11676 }
11677 }
11678
11679 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)
;
11680
11681 if (!resp) {
11682 tagi_t const *t;
11683
11684 if ((t = tl_find(ta_args(ta)(ta).tl, ntatag_rseq)) && t->t_value) {
11685 rack = rack0;
11686 rack->ra_response = (uint32_t)t->t_value;
11687 }
11688
11689 if (rack) {
11690 rack->ra_cseq = oorq->orq_cseq->cs_seq;
11691 rack->ra_method = oorq->orq_cseq->cs_method;
11692 rack->ra_method_name = oorq->orq_cseq->cs_method_name;
11693 }
11694 }
11695
11696 if (sip_add_tl(msg, sip,
11697 TAG_IF(rack, SIPTAG_RACK(rack))!(rack) ? tag_skip : siptag_rack, siptag_rack_v(rack),
11698 TAG_IF(to, SIPTAG_TO(to))!(to) ? tag_skip : siptag_to, siptag_to_v(to),
11699 ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
) < 0)
11700 ;
11701 else if (route && sip_add_dup(msg, sip, (sip_header_t *)route) < 0)
11702 ;
11703 else if (!sip->sip_rack)
11704 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__
, 11704, "%s: RAck header missing\n", __func__)) : (void)0)
;
11705 else if (nta_msg_request_complete(msg, leg,
11706 SIP_METHOD_PRACKsip_method_prack, "PRACK",
11707 (url_string_t *)oorq->orq_url) < 0)
11708 ;
11709 else
11710 orq = outgoing_create(leg->leg_agent, callback, magic,
11711 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
);
11712
11713 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))
;
11714
11715 if (!orq)
11716 msg_destroy(msg);
11717 else if (rack)
11718 oorq->orq_rseq = rack->ra_response;
11719 else if (sip->sip_rack)
11720 oorq->orq_rseq = sip->sip_rack->ra_response;
11721
11722 return orq;
11723}
11724
11725/** Get @RSeq value stored with client transaction. */
11726uint32_t nta_outgoing_rseq(nta_outgoing_t const *orq)
11727{
11728 return orq ? orq->orq_rseq : 0;
11729}
11730
11731/** Set @RSeq value stored with client transaction.
11732 *
11733 * @return 0 if rseq was set successfully
11734 * @return -1 if rseq is invalid or orq is NULL.
11735 */
11736int nta_outgoing_setrseq(nta_outgoing_t *orq, uint32_t rseq)
11737{
11738 if (orq && orq->orq_rseq <= rseq) {
11739 orq->orq_rseq = rseq;
11740 return 0;
11741 }
11742
11743 return -1;
11744}
11745
11746/* ------------------------------------------------------------------------ */
11747/* 11) SigComp handling and public transport interface */
11748
11749#include <sofia-sip/nta_tport.h>
11750
11751/** Return the master transport for the agent.
11752 *
11753 * @NEW_1_12_11
11754 */
11755tport_t *
11756nta_agent_tports(nta_agent_t *agent)
11757{
11758 return agent ? agent->sa_tports : NULL((void*)0);
11759}
11760
11761su_inlinestatic inline tport_t *
11762nta_transport_(nta_agent_t *agent,
11763 nta_incoming_t *irq,
11764 msg_t *msg)
11765{
11766 if (irq)
11767 return irq->irq_tport;
11768 else if (agent && msg)
11769 return tport_delivered_by(agent->sa_tports, msg);
11770
11771 errno(*__errno_location ()) = EINVAL22;
11772 return NULL((void*)0);
11773}
11774
11775
11776/** Return a new reference to the transaction transport.
11777 *
11778 * @note The referenced transport must be unreferenced with tport_unref()
11779 */
11780tport_t *
11781nta_incoming_transport(nta_agent_t *agent,
11782 nta_incoming_t *irq,
11783 msg_t *msg)
11784{
11785 return tport_ref(nta_transport_(agent, irq, msg));
11786}
11787
11788nta_compressor_t *nta_agent_init_sigcomp(nta_agent_t *sa)
11789{
11790 if (!nta_compressor_vtable || !sa)
11791 return NULL((void*)0);
11792
11793 if (sa->sa_compressor == NULL((void*)0)) {
11794 char const * const *l = sa->sa_sigcomp_option_list;
11795 nta_compressor_t *comp;
11796 comp = nta_compressor_vtable->ncv_init_agent(sa, l);
11797 sa->sa_compressor = comp;
11798 }
11799
11800 return sa->sa_compressor;
11801}
11802
11803void nta_agent_deinit_sigcomp(nta_agent_t *sa)
11804{
11805 if (nta_compressor_vtable && sa && sa->sa_compressor) {
11806 nta_compressor_vtable->ncv_deinit_agent(sa, sa->sa_compressor);
11807 sa->sa_compressor = NULL((void*)0);
11808 }
11809}
11810
11811struct sigcomp_compartment *
11812nta_incoming_compartment(nta_incoming_t *irq)
11813{
11814 if (nta_compressor_vtable && irq && irq->irq_cc)
11815 return nta_compressor_vtable->ncv_compartment_ref(irq->irq_cc);
11816 else
11817 return NULL((void*)0);
11818}
11819
11820tport_t *
11821nta_outgoing_transport(nta_outgoing_t *orq)
11822{
11823 if (orq)
11824 return tport_ref(orq->orq_tport);
11825 else
11826 return NULL((void*)0);
11827}
11828
11829
11830struct sigcomp_compartment *
11831nta_outgoing_compartment(nta_outgoing_t *orq)
11832{
11833 if (nta_compressor_vtable && orq && orq->orq_cc)
11834 return nta_compressor_vtable->ncv_compartment_ref(orq->orq_cc);
11835 else
11836 return NULL((void*)0);
11837}
11838
11839
11840struct sigcomp_compartment *
11841nta_compartment_ref(struct sigcomp_compartment *cc)
11842{
11843 if (nta_compressor_vtable)
11844 return nta_compressor_vtable->ncv_compartment_ref(cc);
11845 else
11846 return NULL((void*)0);
11847}
11848
11849void
11850nta_compartment_decref(struct sigcomp_compartment **pcc)
11851{
11852 if (nta_compressor_vtable && pcc && *pcc)
11853 nta_compressor_vtable->ncv_compartment_unref(*pcc), *pcc = NULL((void*)0);
11854}
11855
11856
11857/** Get compartment for connection, create it when needed. */
11858static
11859struct sigcomp_compartment *
11860agent_compression_compartment(nta_agent_t *sa,
11861 tport_t *tp,
11862 tp_name_t const *tpn,
11863 int new_if_needed)
11864{
11865 if (nta_compressor_vtable) {
11866 char const * const *l = sa->sa_sigcomp_option_list;
11867 return nta_compressor_vtable->
11868 ncv_compartment(sa, tp, sa->sa_compressor, tpn, l, new_if_needed);
11869 }
11870 else
11871 return NULL((void*)0);
11872}
11873
11874static
11875int agent_accept_compressed(nta_agent_t *sa, msg_t *msg,
11876 struct sigcomp_compartment *cc)
11877{
11878 if (nta_compressor_vtable) {
11879 nta_compressor_t *msc = sa->sa_compressor;
11880 tport_compressor_t *sc = NULL((void*)0);
11881 if (tport_delivered_with_comp(sa->sa_tports, msg, &sc) < 0)
11882 return 0;
11883 return nta_compressor_vtable->ncv_accept_compressed(sa, msc, sc, msg, cc);
11884 }
11885 else
11886 return 0;
11887}
11888
11889/** Close compressor (lose its state). */
11890static
11891int agent_close_compressor(nta_agent_t *sa,
11892 struct sigcomp_compartment *cc)
11893{
11894 if (nta_compressor_vtable)
11895 return nta_compressor_vtable->ncv_close_compressor(sa, cc);
11896 return 0;
11897}
11898
11899/** Close both compressor and decompressor */
11900static
11901int agent_zap_compressor(nta_agent_t *sa,
11902 struct sigcomp_compartment *cc)
11903{
11904 if (nta_compressor_vtable)
11905 return nta_compressor_vtable->ncv_zap_compressor(sa, cc);
11906 return 0;
11907}
11908
11909/** Bind transport update callback */
11910int nta_agent_bind_tport_update(nta_agent_t *agent,
11911 nta_update_magic_t *magic,
11912 nta_update_tport_f *callback)
11913{
11914 if (!agent)
11915 return su_seterrno(EFAULT14), -1;
11916 agent->sa_update_magic = magic;
11917 agent->sa_update_tport = callback;
11918 return 0;
11919}
11920
11921/** Bind transport error callback */
11922int nta_agent_bind_tport_error(nta_agent_t *agent,
11923 nta_error_magic_t *magic,
11924 nta_error_tport_f *callback)
11925{
11926 if (!agent)
11927 return su_seterrno(EFAULT14), -1;
11928 agent->sa_error_magic = magic;
11929 agent->sa_error_tport = callback;
11930 return 0;
11931}
11932
11933/** Check if public transport binding is in progress */
11934int nta_agent_tport_is_updating(nta_agent_t *agent)
11935{
11936 return agent && tport_is_updating(agent->sa_tports);
11937}
11938
11939/** Initiate STUN keepalive controller to TPORT */
11940int nta_tport_keepalive(nta_outgoing_t *orq)
11941{
11942 assert(orq)((orq) ? (void) (0) : __assert_fail ("orq", "nta.c", 11942, __PRETTY_FUNCTION__
))
;
11943
11944#if HAVE_SOFIA_STUN
11945 return tport_keepalive(orq->orq_tport, msg_addrinfo(orq->orq_request),
11946 TAG_END()(tag_type_t)0, (tag_value_t)0);
11947#else
11948 return -1;
11949#endif
11950}
11951
11952/** Close all transports. @since Experimental in @VERSION_1_12_2. */
11953int nta_agent_close_tports(nta_agent_t *agent)
11954{
11955 size_t i;
11956 outgoing_htable_t *oht = agent->sa_outgoing;
11957 incoming_htable_t *iht = agent->sa_incoming;
11958
11959 for (i = oht->oht_size; i-- > 0;)
11960 /* while */ if (oht->oht_table[i]) {
11961 nta_outgoing_t *orq = oht->oht_table[i];
11962
11963 if (orq->orq_pending && orq->orq_tport)
11964 tport_release(orq->orq_tport, orq->orq_pending, orq->orq_request,
11965 NULL((void*)0), orq, 0);
11966
11967 orq->orq_pending = 0;
11968 tport_unref(orq->orq_tport), orq->orq_tport = NULL((void*)0);
11969 }
11970
11971
11972 for (i = iht->iht_size; i-- > 0;)
11973 /* while */ if (iht->iht_table[i]) {
11974 nta_incoming_t *irq = iht->iht_table[i];
11975 tport_unref(irq->irq_tport), irq->irq_tport = NULL((void*)0);
11976 }
11977
11978 tport_destroy(agent->sa_tports), agent->sa_tports = NULL((void*)0);
11979
11980 msg_header_free(agent->sa_home, (void *)agent->sa_vias);
11981 agent->sa_vias = NULL((void*)0);
11982 msg_header_free(agent->sa_home, (void *)agent->sa_public_vias);
11983 agent->sa_public_vias = NULL((void*)0);
11984
11985 return 0;
11986}