-
Notifications
You must be signed in to change notification settings - Fork 191
/
Copy pathnta.c
12121 lines (10176 loc) · 332 KB
/
nta.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@nokia.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
/**@CFILE nta.c
* @brief Sofia SIP Transaction API implementation
*
* This source file has been divided into sections as follows:
* 1) agent
* 2) tport handling
* 3) dispatching messages received from network
* 4) message creation and message utility functions
* 5) stateless operation
* 6) dialogs (legs)
* 7) server transactions (incoming)
* 8) client transactions (outgoing)
* 9) resolving URLs for client transactions
* 10) 100rel reliable responses (reliable)
* 11) SigComp handling and public transport interface
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*
* @date Created: Tue Jun 13 02:57:51 2000 ppessi
*
* @sa
* @RFC3261, @RFC4320
*/
#include "config.h"
#ifdef HAVE_ZLIB_COMPRESS
#include <zlib.h>
#endif
#include <sofia-sip/su_string.h>
/** @internal SU message argument structure type */
#define SU_MSG_ARG_T union sm_arg_u
/** @internal SU timer argument pointer type */
#define SU_TIMER_ARG_T struct nta_agent_s
#include <sofia-sip/su_alloc.h>
#include <sofia-sip/su.h>
#include <sofia-sip/su_time.h>
#include <sofia-sip/su_wait.h>
#include <sofia-sip/su_tagarg.h>
#include <sofia-sip/base64.h>
#include <sofia-sip/su_uniqueid.h>
#include <sofia-sip/sip.h>
#include <sofia-sip/sip_header.h>
#include <sofia-sip/sip_util.h>
#include <sofia-sip/sip_status.h>
#include <sofia-sip/hostdomain.h>
#include <sofia-sip/url_tag.h>
#include <sofia-sip/msg_addr.h>
#include <sofia-sip/msg_parser.h>
#include <sofia-sip/htable.h>
/* Resolver context type */
#define SRES_CONTEXT_T nta_outgoing_t
/* We are customer of tport_t */
#define TP_AGENT_T nta_agent_t
#define TP_MAGIC_T sip_via_t
#define TP_CLIENT_T nta_outgoing_t
#include "nta_internal.h"
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <assert.h>
#include <limits.h>
#include <errno.h>
/* From AM_INIT/AC_INIT in our "config.h" */
char const nta_version[] = PACKAGE_VERSION;
#if HAVE_FUNC
#elif HAVE_FUNCTION
#define __func__ __FUNCTION__
#else
static char const __func__[] = "nta";
#endif
#ifndef _MSC_VER
#define NONE ((void *)-1)
#else
#define NONE ((void *)(INT_PTR)-1)
#endif
/* ------------------------------------------------------------------------- */
/** Resolving order */
enum nta_res_order_e
{
nta_res_ip6_ip4,
nta_res_ip4_ip6,
nta_res_ip6_only,
nta_res_ip4_only
};
HTABLE_DECLARE_WITH(leg_htable, lht, nta_leg_t, size_t, hash_value_t);
HTABLE_DECLARE_WITH(outgoing_htable, oht, nta_outgoing_t, size_t, hash_value_t);
HTABLE_DECLARE_WITH(incoming_htable, iht, nta_incoming_t, size_t, hash_value_t);
typedef struct outgoing_queue_t {
nta_outgoing_t **q_tail;
nta_outgoing_t *q_head;
size_t q_length;
unsigned q_timeout;
} outgoing_queue_t;
typedef struct incoming_queue_t {
nta_incoming_t **q_tail;
nta_incoming_t *q_head;
size_t q_length;
unsigned q_timeout;
} incoming_queue_t;
struct nta_agent_s
{
su_home_t sa_home[1];
su_root_t *sa_root;
su_timer_t *sa_timer;
nta_agent_magic_t *sa_magic;
nta_message_f *sa_callback;
nta_update_magic_t *sa_update_magic;
nta_update_tport_f *sa_update_tport;
nta_error_magic_t *sa_error_magic;
nta_error_tport_f *sa_error_tport;
uint32_t sa_next; /**< Timestamp for next agent_timer. */
msg_mclass_t const *sa_mclass;
uint32_t sa_flags; /**< SIP message flags */
unsigned sa_preload; /**< Memory preload for SIP messages. */
tport_t *sa_tports;
sip_contact_t *sa_contact;
sip_via_t *sa_vias; /**< @Via headers for all transports */
sip_via_t *sa_public_vias; /**< @Vias for public transports */
sip_contact_t *sa_aliases;/**< List of aliases for agent */
uint64_t sa_branch; /**< Generator for branch parameters */
uint64_t sa_tags; /**< Generator for tag parameters */
#if HAVE_SOFIA_SRESOLV
sres_resolver_t *sa_resolver; /**< DNS resolver */
enum nta_res_order_e sa_res_order; /** Resolving order (AAAA/A) */
#endif
url_t *sa_default_proxy; /**< Default outbound proxy */
unsigned sa_bad_req_mask; /**< Request error mask */
unsigned sa_bad_resp_mask; /**< Response error mask */
usize_t sa_maxsize; /**< Maximum size of incoming messages */
usize_t sa_max_proceeding; /**< Maximum size of proceeding queue */
usize_t sa_max_recv_requests_per_second; /**< Maximum receiving requests per second */
unsigned sa_udp_mtu; /**< Maximum size of outgoing UDP requests */
unsigned sa_t1; /**< SIP T1 - initial retransmit interval (500 ms) */
unsigned sa_t2; /**< SIP T2 - maximum retransmit interval (4000 ms) */
unsigned sa_t4; /**< SIP T4 - clear message time (5000 ms) */
unsigned sa_t1x64; /**< SIP T1X64 - transaction lifetime (32 s) */
unsigned sa_tls_orq_connect_timeout; /**< Connect Timeout for outgoing requests using TLS (ms) */
unsigned sa_progress; /**< Progress timer.
Interval between retransmitting
provisional responses. */
unsigned sa_timer_c; /**< SIP timer C.
Maximum interval between receiving
provisional responses. */
unsigned sa_graylist; /**< Graylisting period */
unsigned sa_blacklist; /**< Blacklisting period */
unsigned sa_drop_prob : 10; /**< NTA is used to test packet drop */
unsigned sa_is_a_uas : 1; /**< NTA is acting as an User Agent server */
unsigned sa_is_stateless : 1; /**< Process requests statelessly
* unless they match existing dialog.
*/
unsigned sa_user_via:1; /**< Let application provide @Via headers */
unsigned sa_extra_100:1; /**< Allow NTA to return "100 Trying" response
* even if application has not responded.
*/
unsigned sa_pass_100:1; /**< Pass the "100 Trying"
* provisional responses to the application
*/
unsigned sa_timeout_408:1; /**< A "408 Request Timeout" message
* is generated when outgoing request expires.
*/
unsigned sa_pass_408:1; /**< A "408 Request Timeout" responses
* are passed to client.
*/
unsigned sa_merge_482 : 1; /**< A "482 Request Merged" response is returned
* to merged requests.
*/
unsigned sa_cancel_2543 : 1; /**< Send a CANCEL to an INVITE without
* waiting for an provisional response.
*/
unsigned sa_cancel_487 : 1; /**< Return 487 response automatically when
* a CANCEL is received.
*/
unsigned sa_invite_100rel:1; /**< Include 100rel in INVITE requests. */
unsigned sa_timestamp : 1; /**< Insert @Timestamp in requests. */
unsigned sa_tport_ip4 : 1; /**< Transports support IPv4. */
unsigned sa_tport_ip6 : 1; /**< Transports support IPv6. */
unsigned sa_tport_udp : 1; /**< Transports support UDP. */
unsigned sa_tport_tcp : 1; /**< Transports support TCP. */
unsigned sa_tport_sctp : 1; /**< Transports support SCTP. */
unsigned sa_tport_tls : 1; /**< Transports support TLS. */
unsigned sa_tport_ws : 1; /**< Transports support WS. */
unsigned sa_tport_wss : 1; /**< Transports support WSS. */
unsigned sa_use_naptr : 1; /**< Use NAPTR lookup */
unsigned sa_use_srv : 1; /**< Use SRV lookup */
unsigned sa_srv_503 : 1; /**< SRV: choice another destination on 503 RFC 3263 */
unsigned sa_tport_threadpool:1; /**< Transports use threadpool */
unsigned sa_rport:1; /**< Use rport at client */
unsigned sa_server_rport:2; /**< Use rport at server */
unsigned sa_tcp_rport:1; /**< Use rport with tcp, too */
unsigned sa_tls_rport:1; /**< Use rport with tls, too */
unsigned sa_auto_comp:1; /**< Automatically create compartments */
unsigned sa_in_timer:1; /**< Set when executing timers */
unsigned sa_use_timer_c:1; /**< Application has set value for timer C */
unsigned :0;
#if HAVE_SMIME
sm_object_t *sa_smime;
#else
void *sa_smime;
#endif
/** @MaxForwards */
sip_max_forwards_t sa_max_forwards[1];
/** Name of SigComp algorithm */
char const *sa_algorithm;
/** Options for SigComp. */
char const *sa_sigcomp_options;
char const* const *sa_sigcomp_option_list;
char const *sa_sigcomp_option_free;
nta_compressor_t *sa_compressor;
/* Statistics */
struct {
usize_t as_recv_msg;
usize_t as_recv_request;
usize_t as_recv_response;
usize_t as_bad_message;
usize_t as_bad_request;
usize_t as_bad_response;
usize_t as_drop_request;
usize_t as_drop_response;
usize_t as_client_tr;
usize_t as_server_tr;
usize_t as_dialog_tr;
usize_t as_acked_tr;
usize_t as_canceled_tr;
usize_t as_trless_request;
usize_t as_trless_to_tr;
usize_t as_trless_response;
usize_t as_trless_200;
usize_t as_merged_request;
usize_t as_sent_msg;
usize_t as_sent_request;
usize_t as_sent_response;
usize_t as_retry_request;
usize_t as_retry_response;
usize_t as_recv_retry;
usize_t as_tout_request;
usize_t as_tout_response;
} sa_stats[1];
/** Current load in receiving messages per second */
struct {
usize_t as_recv_request_last;
su_time_t last_time;
unsigned requests_per_second;
} sa_load[1];
/** Hash of dialogs. */
leg_htable_t sa_dialogs[1];
/** Default leg */
nta_leg_t *sa_default_leg;
/** Hash of legs without dialogs. */
leg_htable_t sa_defaults[1];
/** Hash table for outgoing transactions */
outgoing_htable_t sa_outgoing[1];
nta_outgoing_t *sa_default_outgoing;
/** Hash table for incoming transactions */
incoming_htable_t sa_incoming[1];
nta_incoming_t *sa_default_incoming;
/* Queues (states) for outgoing client transactions */
struct {
/** Queue for retrying client transactions */
nta_outgoing_t *re_list;
nta_outgoing_t **re_t1; /**< Special place for T1 timer */
size_t re_length; /**< Length of sa_out.re_list */
outgoing_queue_t delayed[1];
outgoing_queue_t resolving[1];
outgoing_queue_t trying[1]; /* Timer F / Timer E */
outgoing_queue_t completed[1]; /* Timer K */
outgoing_queue_t terminated[1];
/* Special queues (states) for outgoing INVITE transactions */
outgoing_queue_t inv_calling[1]; /* Timer B/A */
outgoing_queue_t inv_proceeding[1]; /* Timer C */
outgoing_queue_t inv_completed[1]; /* Timer D */
/* Temporary queue for transactions waiting to be freed */
outgoing_queue_t *free;
} sa_out;
/* Queues (states) for incoming server transactions */
struct {
/** Queue for retransmitting response of server transactions */
nta_incoming_t *re_list;
nta_incoming_t **re_t1; /**< Special place for T1 timer */
size_t re_length; /**< Length of sa_in.re_list */
incoming_queue_t proceeding[1]; /**< Request received */
incoming_queue_t preliminary[1]; /**< 100rel sent */
incoming_queue_t completed[1]; /**< Final answer sent (non-invite). */
incoming_queue_t inv_completed[1]; /**< Final answer sent (INVITE). */
incoming_queue_t inv_confirmed[1]; /**< Final answer sent, ACK recvd. */
incoming_queue_t terminated[1]; /**< Terminated, ready to free. */
incoming_queue_t final_failed[1];
} sa_in;
/* Special task for freeing memory */
su_clone_r sa_terminator;
};
struct nta_leg_s
{
su_home_t leg_home[1];
hash_value_t leg_hash;
unsigned leg_dialog : 1;
unsigned leg_stateless : 1; /**< Process requests statelessly */
#ifdef NTA_STRICT_ROUTING
unsigned leg_contact_set : 1;
#else
unsigned leg_loose_route : 1; /**< Topmost route in set is LR */
#endif
unsigned leg_route_set : 1; /**< Route set has been saved */
unsigned leg_local_is_to : 1; /**< Backwards-compatibility. */
unsigned leg_tagged : 1; /**< Tagged after creation.
*
* Request missing @To tag matches
* a tagged leg even after tagging.
*/
unsigned leg_compressed:1;
unsigned:0;
nta_request_f *leg_callback;
nta_leg_magic_t *leg_magic;
nta_agent_t *leg_agent;
url_t const *leg_url; /**< Match incoming requests. */
char const *leg_method; /**< Match incoming requests. */
uint32_t leg_seq; /**< Sequence number for next transaction */
uint32_t leg_rseq; /**< Remote sequence number */
sip_call_id_t *leg_id; /**< Call ID */
sip_from_t *leg_remote; /**< Remote address (@To/@From) */
sip_to_t *leg_local; /**< Local address (@From/@To) */
sip_route_t *leg_route; /**< @Route for outgoing requests. */
sip_contact_t *leg_target; /**< Remote destination (from @Contact). */
};
struct nta_incoming_s
{
su_home_t *irq_home;
hash_value_t irq_hash;
nta_agent_t *irq_agent;
nta_ack_cancel_f *irq_callback;
nta_incoming_magic_t *irq_magic;
/* Timeout/state queue */
nta_incoming_t **irq_prev;
nta_incoming_t *irq_next;
incoming_queue_t *irq_queue;
/* Retry queue */
nta_incoming_t **irq_rprev;
nta_incoming_t *irq_rnext;
sip_method_t irq_method;
sip_request_t *irq_rq;
sip_from_t *irq_from;
sip_to_t *irq_to;
char const *irq_tag;
sip_cseq_t *irq_cseq;
sip_call_id_t *irq_call_id;
sip_via_t *irq_via;
sip_record_route_t *irq_record_route;
char const *irq_branch;
uint32_t irq_rseq;
sip_timestamp_t *irq_timestamp;
su_time_t irq_received;
uint32_t irq_timeout; /**< Timer H, I, J */
uint32_t irq_retry; /**< Timer G */
unsigned short irq_interval; /**< Next timer */
short irq_status;
unsigned irq_retries:8;
unsigned irq_default:1; /**< Default transaction */
unsigned irq_canceled:1; /**< Transaction is canceled */
unsigned irq_completed:1; /**< Transaction is completed */
unsigned irq_confirmed:1; /**< Response has been acked */
unsigned irq_terminated:1; /**< Transaction is terminated */
unsigned irq_final_failed:1; /**< Sending final response failed */
unsigned irq_destroyed :1; /**< Transaction is destroyed */
unsigned irq_in_callback:1; /**< Callback is being invoked */
unsigned irq_reliable_tp:1; /**< Transport is reliable */
unsigned irq_sigcomp_zap:1; /**< Reset SigComp */
unsigned irq_must_100rel:1; /**< 100rel is required */
unsigned irq_extra_100:1; /**< 100 Trying should be sent */
unsigned irq_tag_set:1; /**< Tag is not from request */
unsigned irq_compressed:1;
unsigned :0;
tp_name_t irq_tpn[1];
tport_t *irq_tport;
struct sigcomp_compartment *irq_cc;
msg_t *irq_request;
msg_t *irq_request2; /**< ACK/CANCEL */
msg_t *irq_response;
nta_reliable_t *irq_reliable; /**< List of reliable responses */
};
struct nta_reliable_s
{
nta_reliable_t *rel_next;
nta_incoming_t *rel_irq;
nta_prack_f *rel_callback;
nta_reliable_magic_t *rel_magic;
uint32_t rel_rseq;
unsigned short rel_status;
unsigned rel_pracked:1;
unsigned rel_precious:1;
msg_t *rel_response;
msg_t *rel_unsent;
};
typedef struct sipdns_resolver sipdns_resolver_t;
struct nta_outgoing_s
{
hash_value_t orq_hash; /**< Hash value */
nta_agent_t *orq_agent;
nta_response_f *orq_callback;
nta_outgoing_magic_t *orq_magic;
/* Timeout/state queue */
nta_outgoing_t **orq_prev;
nta_outgoing_t *orq_next;
outgoing_queue_t *orq_queue;
/* Retry queue */
nta_outgoing_t **orq_rprev;
nta_outgoing_t *orq_rnext;
sip_method_t orq_method;
char const *orq_method_name;
url_t const *orq_url; /**< Original RequestURI */
sip_from_t const *orq_from;
sip_to_t const *orq_to;
char const *orq_tag; /**< Tag from final response. */
sip_cseq_t const *orq_cseq;
sip_call_id_t const *orq_call_id;
msg_t *orq_request;
msg_t *orq_response;
su_time_t orq_sent; /**< When request was sent? */
unsigned orq_delay; /**< RTT estimate */
uint32_t orq_retry; /**< Timer A, E */
uint32_t orq_timeout; /**< Timer B, D, F, K */
unsigned short orq_interval; /**< Next timer A/E */
unsigned short orq_status;
unsigned char orq_retries; /**< Number of tries this far */
unsigned orq_default:1; /**< This is default transaction */
unsigned orq_inserted:1;
unsigned orq_resolved:1;
unsigned orq_via_added:1;
unsigned orq_prepared:1;
unsigned orq_canceled:1;
unsigned orq_terminated:1;
unsigned orq_destroyed:1;
unsigned orq_completed:1;
unsigned orq_delayed:1;
unsigned orq_user_tport:1; /**< Application provided tport - don't retry */
unsigned orq_try_tcp_instead:1;
unsigned orq_try_udp_instead:1;
unsigned orq_reliable:1; /**< Transport is reliable */
unsigned orq_call_tls_connect_timeout_is_set:1; /** Per Call connect timeout for outgoing requests using TLS set flag*/
unsigned orq_forked:1; /**< Tagged fork */
/* Attributes */
unsigned orq_sips:1;
unsigned orq_uas:1; /**< Running this transaction as UAS */
unsigned orq_user_via:1;
unsigned orq_stateless:1;
unsigned orq_pass_100:1;
unsigned orq_sigcomp_new:1; /**< Create compartment if needed */
unsigned orq_sigcomp_zap:1; /**< Reset SigComp after completing */
unsigned orq_must_100rel:1;
unsigned orq_timestamp:1; /**< Insert @Timestamp header. */
unsigned orq_100rel:1; /**< Support 100rel */
unsigned:0; /* pad */
#if HAVE_SOFIA_SRESOLV
sipdns_resolver_t *orq_resolver;
#endif
url_t *orq_route; /**< Route URL */
tp_name_t orq_tpn[1]; /**< Where to send request */
tport_t *orq_tport;
struct sigcomp_compartment *orq_cc;
tagi_t *orq_tags; /**< Tport tag items */
char const *orq_branch; /**< Transaction branch */
char const *orq_via_branch; /**< @Via branch */
int *orq_status2b; /**< Delayed response */
nta_outgoing_t *orq_cancel; /**< Delayed CANCEL transaction */
nta_outgoing_t *orq_forking; /**< Untagged transaction */
nta_outgoing_t *orq_forks; /**< Tagged transactions */
uint32_t orq_rseq; /**< Latest incoming rseq */
int orq_pending; /**< Request is pending in tport */
uint32_t orq_call_tls_connect_timeout; /** Per Call connect timeout for outgoing requests using TLS */
};
/* ------------------------------------------------------------------------- */
/* Internal tags */
/* Delay sending of request */
#define NTATAG_DELAY_SENDING(x) ntatag_delay_sending, tag_bool_v((x))
#define NTATAG_DELAY_SENDING_REF(x) \
ntatag_delay_sending_ref, tag_bool_vr(&(x))
extern tag_typedef_t ntatag_delay_sending;
extern tag_typedef_t ntatag_delay_sending_ref;
/* Allow sending incomplete responses */
#define NTATAG_INCOMPLETE(x) ntatag_incomplete, tag_bool_v((x))
#define NTATAG_INCOMPLETE_REF(x) \
ntatag_incomplete_ref, tag_bool_vr(&(x))
extern tag_typedef_t ntatag_incomplete;
extern tag_typedef_t ntatag_incomplete_ref;
nta_compressor_vtable_t *nta_compressor_vtable = NULL;
/* Agent */
static int agent_tag_init(nta_agent_t *self);
static int agent_timer_init(nta_agent_t *agent);
static void agent_timer(su_root_magic_t *rm, su_timer_t *, nta_agent_t *);
static int agent_launch_terminator(nta_agent_t *agent);
static void agent_kill_terminator(nta_agent_t *agent);
static int agent_set_params(nta_agent_t *agent, tagi_t *tags);
static void agent_set_udp_params(nta_agent_t *self, usize_t udp_mtu);
static int agent_get_params(nta_agent_t *agent, tagi_t *tags);
/* Transport interface */
static sip_via_t const *agent_tport_via(tport_t *tport);
static int outgoing_insert_via(nta_outgoing_t *orq, sip_via_t const *);
static int nta_tpn_by_via(tp_name_t *tpn, sip_via_t const *v, int *using_rport);
static msg_t *nta_msg_create_for_transport(nta_agent_t *agent, int flags,
char const data[], usize_t dlen,
tport_t const *tport,
tp_client_t *via);
static int complete_response(msg_t *response,
int status, char const *phrase,
msg_t *request);
static int mreply(nta_agent_t *agent,
msg_t *reply,
int status, char const *phrase,
msg_t *req_msg,
tport_t *tport,
int incomplete,
int sdwn_after,
char const *to_tag,
tag_type_t tag, tag_value_t value, ...);
#define IF_SIGCOMP_TPTAG_COMPARTMENT(cc) TAG_IF(cc && cc != NONE, TPTAG_COMPARTMENT(cc)),
#define IF_SIGCOMP_TPTAG_COMPARTMENT_REF(cc) TPTAG_COMPARTMENT_REF(cc),
struct sigcomp_compartment;
struct sigcomp_compartment *
nta_compartment_ref(struct sigcomp_compartment *cc);
static
struct sigcomp_compartment *
agent_compression_compartment(nta_agent_t *sa, tport_t *tp, tp_name_t const *tpn,
int new_if_needed);
static
int agent_accept_compressed(nta_agent_t *sa, msg_t *msg,
struct sigcomp_compartment *cc);
static int agent_close_compressor(nta_agent_t *sa,
struct sigcomp_compartment *cc);
static int agent_zap_compressor(nta_agent_t *sa,
struct sigcomp_compartment *cc);
static char const * stateful_branch(su_home_t *home, nta_agent_t *);
static char const * stateless_branch(nta_agent_t *, msg_t *, sip_t const *,
tp_name_t const *tp);
#define NTA_BRANCH_PRIME SU_U64_C(0xB9591D1C361C6521)
#define NTA_TAG_PRIME SU_U64_C(0xB9591D1C361C6521)
#ifndef UINT32_MAX
#define UINT32_MAX (0xffffffffU)
#endif
HTABLE_PROTOS_WITH(leg_htable, lht, nta_leg_t, size_t, hash_value_t);
static nta_leg_t *leg_find(nta_agent_t const *sa,
char const *method_name,
url_t const *request_uri,
sip_call_id_t const *i,
char const *from_tag,
char const *to_tag);
static nta_leg_t *dst_find(nta_agent_t const *sa, url_t const *u0,
char const *method);
static void leg_recv(nta_leg_t *, msg_t *, sip_t *, tport_t *);
static void leg_free(nta_agent_t *sa, nta_leg_t *leg);
#define NTA_HASH(i, cs) ((i)->i_hash + 26839U * (uint32_t)(cs))
HTABLE_PROTOS_WITH(incoming_htable, iht, nta_incoming_t, size_t, hash_value_t);
static nta_incoming_t *incoming_create(nta_agent_t *agent,
msg_t *request,
sip_t *sip,
tport_t *tport,
char const *tag);
static int incoming_callback(nta_leg_t *leg, nta_incoming_t *irq, sip_t *sip);
static void incoming_free(nta_incoming_t *irq);
su_inline void incoming_cut_off(nta_incoming_t *irq);
su_inline void incoming_reclaim(nta_incoming_t *irq);
static void incoming_queue_init(incoming_queue_t *,
unsigned timeout);
static void incoming_queue_adjust(nta_agent_t *sa,
incoming_queue_t *queue,
unsigned timeout);
static nta_incoming_t *incoming_find(nta_agent_t const *agent,
sip_t const *sip,
sip_via_t const *v,
nta_incoming_t **merge,
nta_incoming_t **ack,
nta_incoming_t **cancel);
static int incoming_reply(nta_incoming_t *irq, msg_t *msg, sip_t *sip);
su_inline int incoming_recv(nta_incoming_t *irq, msg_t *msg, sip_t *sip,
tport_t *tport);
su_inline int incoming_ack(nta_incoming_t *irq, msg_t *msg, sip_t *sip,
tport_t *tport);
su_inline int incoming_cancel(nta_incoming_t *irq, msg_t *msg, sip_t *sip,
tport_t *tport);
static void request_merge(nta_agent_t *,
msg_t *msg, sip_t *sip, tport_t *tport,
char const *to_tag);
su_inline int incoming_timestamp(nta_incoming_t *, msg_t *, sip_t *);
static void _nta_incoming_timer(nta_agent_t *);
static nta_reliable_t *reliable_mreply(nta_incoming_t *,
nta_prack_f *, nta_reliable_magic_t *,
msg_t *, sip_t *);
static int reliable_send(nta_incoming_t *, nta_reliable_t *, msg_t *, sip_t *);
static int reliable_final(nta_incoming_t *irq, msg_t *msg, sip_t *sip);
static msg_t *reliable_response(nta_incoming_t *irq);
static nta_reliable_t *reliable_find(nta_agent_t const *, sip_t const *);
static int reliable_recv(nta_reliable_t *rel, msg_t *, sip_t *, tport_t *);
static void reliable_flush(nta_incoming_t *irq);
static void reliable_timeout(nta_incoming_t *irq, int timeout);
HTABLE_PROTOS_WITH(outgoing_htable, oht, nta_outgoing_t, size_t, hash_value_t);
static nta_outgoing_t *outgoing_create(nta_agent_t *agent,
nta_response_f *callback,
nta_outgoing_magic_t *magic,
url_string_t const *route_url,
tp_name_t const *tpn,
msg_t *msg,
tag_type_t tag, tag_value_t value, ...);
static void outgoing_queue_init(outgoing_queue_t *,
unsigned timeout);
static void outgoing_queue_adjust(nta_agent_t *sa,
outgoing_queue_t *queue,
unsigned timeout);
static void outgoing_free(nta_outgoing_t *orq);
su_inline void outgoing_cut_off(nta_outgoing_t *orq);
su_inline void outgoing_reclaim(nta_outgoing_t *orq);
static nta_outgoing_t *outgoing_find(nta_agent_t const *sa,
msg_t const *msg,
sip_t const *sip,
sip_via_t const *v);
static int outgoing_recv(nta_outgoing_t *orq, int status, msg_t *, sip_t *);
static void outgoing_default_recv(nta_outgoing_t *, int, msg_t *, sip_t *);
static void _nta_outgoing_timer(nta_agent_t *);
static int outgoing_recv_reliable(nta_outgoing_t *orq, msg_t *msg, sip_t *sip);
/* Internal message passing */
union sm_arg_u {
struct outgoing_recv_s {
nta_outgoing_t *orq;
msg_t *msg;
sip_t *sip;
int status;
} a_outgoing_recv[1];
incoming_queue_t a_incoming_queue[1];
outgoing_queue_t a_outgoing_queue[1];
};
/* Global module data */
/**@var char const NTA_DEBUG[];
*
* Environment variable determining the default debug log level.
*
* The NTA_DEBUG environment variable is used to determine the default
* debug logging level. The normal level is 3.
*
* @sa <sofia-sip/su_debug.h>, #su_log_global, #SOFIA_DEBUG
*/
#ifdef DOXYGEN
extern char const NTA_DEBUG[]; /* dummy declaration for Doxygen */
#endif
#ifndef SU_DEBUG
#define SU_DEBUG 3
#endif
/**Debug log for @b nta module.
*
* The nta_log is the log object used by @b nta module. The level of
* nta_log is set using #NTA_DEBUG environment variable.
*/
su_log_t nta_log[] = { SU_LOG_INIT("nta", "NTA_DEBUG", SU_DEBUG) };
/* ====================================================================== */
/* 1) Agent */
/**
* Create an NTA agent object.
*
* Create an NTA agent object. The agent
* object creates and binds a server socket with address specified in @e url.
* If the @e host portion of the @e url is @c "*", the agent listens to all
* addresses available on the host.
*
* When a message is received, the agent object parses it. If the result is
* a valid SIP message, the agent object passes the message to the
* application by invoking the nta_message_f @e callback function.
*
* @note
* The @e url can be either parsed url (of type url_t ()), or a valid
* SIP URL as a string.
*
* @note
* If @e url is @c NULL, the default @e url @c "sip:*" is used.
* @par
* If @e url is @c NONE (iow, (void*)-1), no server sockets are bound.
* @par
* If @p transport parameters are specified in @a url, agent uses only
* specified transport type.
*
* @par
* If an @p maddr parameter is specified in @e url, agent binds to the
* specified address, but uses @e host part of @e url when it generates
* @Contact and @Via headers. The @p maddr parameter is also included,
* unless it equals to @c INADDR_ANY (@p 0.0.0.0 or @p [::]).
*
* @param root pointer to a su_root_t used for synchronization
* @param contact_url URL that agent uses to bind the server sockets
* @param callback pointer to callback function
* @param magic pointer to user data
* @param tag,value,... tagged arguments
*
* @TAGS
* NTATAG_ALIASES(),
* NTATAG_BAD_REQ_MASK(), NTATAG_BAD_RESP_MASK(), NTATAG_BLACKLIST(),
* NTATAG_CANCEL_2543(), NTATAG_CANCEL_487(), NTATAG_CLIENT_RPORT(),
* NTATAG_DEBUG_DROP_PROB(), NTATAG_DEFAULT_PROXY(),
* NTATAG_EXTRA_100(), NTATAG_GRAYLIST(),
* NTATAG_MAXSIZE(), NTATAG_MAX_FORWARDS(), NTATAG_MERGE_482(), NTATAG_MCLASS()
* NTATAG_PASS_100(), NTATAG_PASS_408(), NTATAG_PRELOAD(), NTATAG_PROGRESS(),
* NTATAG_REL100(),
* NTATAG_SERVER_RPORT(),
* NTATAG_SIPFLAGS(),
* NTATAG_SIP_T1X64(), NTATAG_SIP_T1(), NTATAG_SIP_T2(), NTATAG_SIP_T4(),
* NTATAG_STATELESS(),
* NTATAG_TAG_3261(), NTATAG_TCP_RPORT(), NTATAG_TIMEOUT_408(),
* NTATAG_TLS_RPORT(), NTATAG_TLS_ORQ_CONNECT_TIMEOUT(),
* NTATAG_TIMER_C(), NTATAG_MAX_PROCEEDING(),
* NTATAG_UA(), NTATAG_UDP_MTU(), NTATAG_USER_VIA(),
* NTATAG_USE_NAPTR(), NTATAG_USE_SRV() and NTATAG_USE_TIMESTAMP().
*
* @note The value from following tags are stored, but they currently do nothing:
* NTATAG_SIGCOMP_ALGORITHM(), NTATAG_SIGCOMP_OPTIONS(), NTATAG_SMIME()
*
* @note It is possible to provide @c (url_string_t*)-1 as @a contact_url.
* In that case, no server sockets are bound.
*
* @retval handle to the agent when successful,
* @retval NULL upon an error.
*
* @sa NUTAG_
*/
nta_agent_t *nta_agent_create(su_root_t *root,
url_string_t const *contact_url,
nta_message_f *callback,
nta_agent_magic_t *magic,
tag_type_t tag, tag_value_t value, ...)
{
nta_agent_t *agent;
ta_list ta;
if (root == NULL)
return su_seterrno(EINVAL), NULL;
ta_start(ta, tag, value);
if ((agent = su_home_new(sizeof(*agent)))) {
unsigned timer_c = 0, timer_d = 32000;
agent->sa_root = root;
agent->sa_callback = callback;
agent->sa_magic = magic;
agent->sa_flags = MSG_DO_CANONIC;
agent->sa_maxsize = 2 * 1024 * 1024; /* 2 MB */
agent->sa_bad_req_mask =
/*
* Bit-wise not of these - what is left is suitable for UAs with
* 100rel, timer, events, publish
*/
(unsigned) ~(sip_mask_response | sip_mask_proxy | sip_mask_registrar |
sip_mask_pref | sip_mask_privacy);
agent->sa_bad_resp_mask =
(unsigned) ~(sip_mask_request | sip_mask_proxy | sip_mask_registrar |
sip_mask_pref | sip_mask_privacy);
agent->sa_t1 = NTA_SIP_T1;
agent->sa_t2 = NTA_SIP_T2;
agent->sa_t4 = NTA_SIP_T4;
agent->sa_t1x64 = 64 * NTA_SIP_T1;
agent->sa_timer_c = 185 * 1000;
agent->sa_graylist = 600;
agent->sa_drop_prob = 0;
agent->sa_is_a_uas = 0;
agent->sa_progress = 60 * 1000;
agent->sa_user_via = 0;
agent->sa_extra_100 = 0;
agent->sa_pass_100 = 0;
agent->sa_timeout_408 = 1;
agent->sa_pass_408 = 0;
agent->sa_merge_482 = 0;
agent->sa_cancel_2543 = 0;
agent->sa_cancel_487 = 1;
agent->sa_invite_100rel = 0;
agent->sa_timestamp = 0;
agent->sa_use_naptr = 1;
agent->sa_use_srv = 1;
agent->sa_srv_503 = 1;
agent->sa_auto_comp = 0;
agent->sa_server_rport = 1;
/* RFC 3261 section 8.1.1.6 */
sip_max_forwards_init(agent->sa_max_forwards);
if (getenv("SIPCOMPACT"))
agent->sa_flags |= MSG_DO_COMPACT;
agent_set_params(agent, ta_args(ta));
if (agent->sa_mclass == NULL)
agent->sa_mclass = sip_default_mclass();
agent->sa_in.re_t1 = &agent->sa_in.re_list;
incoming_queue_init(agent->sa_in.proceeding, 0);
incoming_queue_init(agent->sa_in.preliminary, agent->sa_t1x64); /* P1 */
incoming_queue_init(agent->sa_in.inv_completed, agent->sa_t1x64); /* H */
incoming_queue_init(agent->sa_in.inv_confirmed, agent->sa_t4); /* I */
incoming_queue_init(agent->sa_in.completed, agent->sa_t1x64); /* J */
incoming_queue_init(agent->sa_in.terminated, 0);
incoming_queue_init(agent->sa_in.final_failed, 0);
agent->sa_out.re_t1 = &agent->sa_out.re_list;
if (agent->sa_use_timer_c || !agent->sa_is_a_uas)
timer_c = agent->sa_timer_c;
if (timer_d < agent->sa_t1x64)
timer_d = agent->sa_t1x64;
outgoing_queue_init(agent->sa_out.delayed, 0);
outgoing_queue_init(agent->sa_out.resolving, 0);
outgoing_queue_init(agent->sa_out.trying, agent->sa_t1x64); /* F */
outgoing_queue_init(agent->sa_out.completed, agent->sa_t4); /* K */
outgoing_queue_init(agent->sa_out.terminated, 0);
/* Special queues (states) for outgoing INVITE transactions */
outgoing_queue_init(agent->sa_out.inv_calling, agent->sa_t1x64); /* B */
outgoing_queue_init(agent->sa_out.inv_proceeding, timer_c); /* C */
outgoing_queue_init(agent->sa_out.inv_completed, timer_d); /* D */
if (leg_htable_resize(agent->sa_home, agent->sa_dialogs, 0) < 0 ||
leg_htable_resize(agent->sa_home, agent->sa_defaults, 0) < 0 ||
outgoing_htable_resize(agent->sa_home, agent->sa_outgoing, 0) < 0 ||
incoming_htable_resize(agent->sa_home, agent->sa_incoming, 0) < 0) {
SU_DEBUG_0(("nta_agent_create: failure with %s\n", "hash tables"));
goto deinit;
}
SU_DEBUG_9(("nta_agent_create: initialized %s\n", "hash tables"));
if (contact_url != (url_string_t *)-1 &&
nta_agent_add_tport(agent, contact_url, ta_tags(ta)) < 0) {
SU_DEBUG_7(("nta_agent_create: failure with %s\n", "transport"));
goto deinit;
}
SU_DEBUG_9(("nta_agent_create: initialized %s\n", "transports"));
if (agent_tag_init(agent) < 0) {
SU_DEBUG_3(("nta_agent_create: failure with %s\n", "random identifiers"));
goto deinit;
}
SU_DEBUG_9(("nta_agent_create: initialized %s\n", "random identifiers"));
if (agent_timer_init(agent) < 0) {
SU_DEBUG_0(("nta_agent_create: failure with %s\n", "timer"));
goto deinit;
}
SU_DEBUG_9(("nta_agent_create: initialized %s\n", "timer"));
if (agent_launch_terminator(agent) == 0)
SU_DEBUG_9(("nta_agent_create: initialized %s\n", "threads"));