File: | nta.c |
Warning: | line 2476, column 5 Access to field 'h_data' results in a dereference of a null pointer (loaded from field 'v_common') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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" */ | ||||||||
100 | char const nta_version[] = PACKAGE_VERSION"1.13.15"; | ||||||||
101 | |||||||||
102 | #if HAVE_FUNC1 | ||||||||
103 | #elif HAVE_FUNCTION1 | ||||||||
104 | #define __func__ __FUNCTION__ | ||||||||
105 | #else | ||||||||
106 | static 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 */ | ||||||||
117 | enum 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 | |||||||||
125 | HTABLE_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; | ||||||||
126 | HTABLE_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; | ||||||||
127 | HTABLE_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 | |||||||||
129 | typedef 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 | |||||||||
136 | typedef 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 | |||||||||
143 | struct nta_agent_s | ||||||||
144 | { | ||||||||
145 | su_home_t sa_home[1]; | ||||||||
146 | su_root_t *sa_root; | ||||||||
147 | su_timer_t *sa_timer; | ||||||||
148 | nta_agent_magic_t *sa_magic; | ||||||||
149 | nta_message_f *sa_callback; | ||||||||
150 | |||||||||
151 | nta_update_magic_t *sa_update_magic; | ||||||||
152 | nta_update_tport_f *sa_update_tport; | ||||||||
153 | |||||||||
154 | nta_error_magic_t *sa_error_magic; | ||||||||
155 | nta_error_tport_f *sa_error_tport; | ||||||||
156 | |||||||||
157 | uint32_t sa_next; /**< Timestamp for next agent_timer. */ | ||||||||
158 | |||||||||
159 | msg_mclass_t const *sa_mclass; | ||||||||
160 | uint32_t sa_flags; /**< SIP message flags */ | ||||||||
161 | unsigned sa_preload; /**< Memory preload for SIP messages. */ | ||||||||
162 | |||||||||
163 | tport_t *sa_tports; | ||||||||
164 | sip_contact_t *sa_contact; | ||||||||
165 | sip_via_t *sa_vias; /**< @Via headers for all transports */ | ||||||||
166 | sip_via_t *sa_public_vias; /**< @Vias for public transports */ | ||||||||
167 | sip_contact_t *sa_aliases;/**< List of aliases for agent */ | ||||||||
168 | |||||||||
169 | uint64_t sa_branch; /**< Generator for branch parameters */ | ||||||||
170 | uint64_t sa_tags; /**< Generator for tag parameters */ | ||||||||
171 | |||||||||
172 | #if HAVE_SOFIA_SRESOLV1 | ||||||||
173 | sres_resolver_t *sa_resolver; /**< DNS resolver */ | ||||||||
174 | enum nta_res_order_e sa_res_order; /** Resolving order (AAAA/A) */ | ||||||||
175 | #endif | ||||||||
176 | |||||||||
177 | url_t *sa_default_proxy; /**< Default outbound proxy */ | ||||||||
178 | unsigned sa_bad_req_mask; /**< Request error mask */ | ||||||||
179 | unsigned sa_bad_resp_mask; /**< Response error mask */ | ||||||||
180 | usize_t sa_maxsize; /**< Maximum size of incoming messages */ | ||||||||
181 | usize_t sa_max_proceeding; /**< Maximum size of proceeding queue */ | ||||||||
182 | usize_t sa_max_recv_requests_per_second; /**< Maximum receiving requests per second */ | ||||||||
183 | |||||||||
184 | unsigned sa_udp_mtu; /**< Maximum size of outgoing UDP requests */ | ||||||||
185 | |||||||||
186 | unsigned sa_t1; /**< SIP T1 - initial retransmit interval (500 ms) */ | ||||||||
187 | unsigned sa_t2; /**< SIP T2 - maximum retransmit interval (4000 ms) */ | ||||||||
188 | unsigned sa_t4; /**< SIP T4 - clear message time (5000 ms) */ | ||||||||
189 | |||||||||
190 | |||||||||
191 | unsigned sa_t1x64; /**< SIP T1X64 - transaction lifetime (32 s) */ | ||||||||
192 | |||||||||
193 | unsigned sa_tls_orq_connect_timeout; /**< Connect Timeout for outgoing requests using TLS (ms) */ | ||||||||
194 | |||||||||
195 | unsigned sa_progress; /**< Progress timer. | ||||||||
196 | Interval between retransmitting | ||||||||
197 | provisional responses. */ | ||||||||
198 | |||||||||
199 | unsigned sa_timer_c; /**< SIP timer C. | ||||||||
200 | Maximum interval between receiving | ||||||||
201 | provisional responses. */ | ||||||||
202 | |||||||||
203 | unsigned sa_graylist; /**< Graylisting period */ | ||||||||
204 | unsigned sa_blacklist; /**< Blacklisting period */ | ||||||||
205 | |||||||||
206 | unsigned sa_drop_prob : 10; /**< NTA is used to test packet drop */ | ||||||||
207 | unsigned sa_is_a_uas : 1; /**< NTA is acting as an User Agent server */ | ||||||||
208 | unsigned sa_is_stateless : 1; /**< Process requests statelessly | ||||||||
209 | * unless they match existing dialog. | ||||||||
210 | */ | ||||||||
211 | unsigned sa_user_via:1; /**< Let application provide @Via headers */ | ||||||||
212 | unsigned sa_extra_100:1; /**< Allow NTA to return "100 Trying" response | ||||||||
213 | * even if application has not responded. | ||||||||
214 | */ | ||||||||
215 | unsigned sa_pass_100:1; /**< Pass the "100 Trying" | ||||||||
216 | * provisional responses to the application | ||||||||
217 | */ | ||||||||
218 | unsigned sa_timeout_408:1; /**< A "408 Request Timeout" message | ||||||||
219 | * is generated when outgoing request expires. | ||||||||
220 | */ | ||||||||
221 | unsigned sa_pass_408:1; /**< A "408 Request Timeout" responses | ||||||||
222 | * are passed to client. | ||||||||
223 | */ | ||||||||
224 | unsigned sa_merge_482 : 1; /**< A "482 Request Merged" response is returned | ||||||||
225 | * to merged requests. | ||||||||
226 | */ | ||||||||
227 | unsigned sa_cancel_2543 : 1; /**< Send a CANCEL to an INVITE without | ||||||||
228 | * waiting for an provisional response. | ||||||||
229 | */ | ||||||||
230 | unsigned sa_cancel_487 : 1; /**< Return 487 response automatically when | ||||||||
231 | * a CANCEL is received. | ||||||||
232 | */ | ||||||||
233 | |||||||||
234 | unsigned sa_invite_100rel:1; /**< Include 100rel in INVITE requests. */ | ||||||||
235 | unsigned sa_timestamp : 1; /**< Insert @Timestamp in requests. */ | ||||||||
236 | |||||||||
237 | unsigned sa_tport_ip4 : 1; /**< Transports support IPv4. */ | ||||||||
238 | unsigned sa_tport_ip6 : 1; /**< Transports support IPv6. */ | ||||||||
239 | unsigned sa_tport_udp : 1; /**< Transports support UDP. */ | ||||||||
240 | unsigned sa_tport_tcp : 1; /**< Transports support TCP. */ | ||||||||
241 | unsigned sa_tport_sctp : 1; /**< Transports support SCTP. */ | ||||||||
242 | unsigned sa_tport_tls : 1; /**< Transports support TLS. */ | ||||||||
243 | unsigned sa_tport_ws : 1; /**< Transports support WS. */ | ||||||||
244 | unsigned sa_tport_wss : 1; /**< Transports support WSS. */ | ||||||||
245 | |||||||||
246 | unsigned sa_use_naptr : 1; /**< Use NAPTR lookup */ | ||||||||
247 | unsigned sa_use_srv : 1; /**< Use SRV lookup */ | ||||||||
248 | |||||||||
249 | unsigned sa_srv_503 : 1; /**< SRV: choice another destination on 503 RFC 3263 */ | ||||||||
250 | |||||||||
251 | unsigned sa_tport_threadpool:1; /**< Transports use threadpool */ | ||||||||
252 | |||||||||
253 | unsigned sa_rport:1; /**< Use rport at client */ | ||||||||
254 | unsigned sa_server_rport:2; /**< Use rport at server */ | ||||||||
255 | unsigned sa_tcp_rport:1; /**< Use rport with tcp, too */ | ||||||||
256 | unsigned sa_tls_rport:1; /**< Use rport with tls, too */ | ||||||||
257 | |||||||||
258 | unsigned sa_auto_comp:1; /**< Automatically create compartments */ | ||||||||
259 | unsigned sa_in_timer:1; /**< Set when executing timers */ | ||||||||
260 | unsigned sa_use_timer_c:1; /**< Application has set value for timer C */ | ||||||||
261 | |||||||||
262 | unsigned :0; | ||||||||
263 | |||||||||
264 | #if HAVE_SMIME | ||||||||
265 | sm_object_t *sa_smime; | ||||||||
266 | #else | ||||||||
267 | void *sa_smime; | ||||||||
268 | #endif | ||||||||
269 | |||||||||
270 | /** @MaxForwards */ | ||||||||
271 | sip_max_forwards_t sa_max_forwards[1]; | ||||||||
272 | |||||||||
273 | /** Name of SigComp algorithm */ | ||||||||
274 | char const *sa_algorithm; | ||||||||
275 | /** Options for SigComp. */ | ||||||||
276 | char const *sa_sigcomp_options; | ||||||||
277 | char const* const *sa_sigcomp_option_list; | ||||||||
278 | char const *sa_sigcomp_option_free; | ||||||||
279 | |||||||||
280 | nta_compressor_t *sa_compressor; | ||||||||
281 | |||||||||
282 | /* Statistics */ | ||||||||
283 | struct { | ||||||||
284 | usize_t as_recv_msg; | ||||||||
285 | usize_t as_recv_request; | ||||||||
286 | usize_t as_recv_response; | ||||||||
287 | usize_t as_bad_message; | ||||||||
288 | usize_t as_bad_request; | ||||||||
289 | usize_t as_bad_response; | ||||||||
290 | usize_t as_drop_request; | ||||||||
291 | usize_t as_drop_response; | ||||||||
292 | usize_t as_client_tr; | ||||||||
293 | usize_t as_server_tr; | ||||||||
294 | usize_t as_dialog_tr; | ||||||||
295 | usize_t as_acked_tr; | ||||||||
296 | usize_t as_canceled_tr; | ||||||||
297 | usize_t as_trless_request; | ||||||||
298 | usize_t as_trless_to_tr; | ||||||||
299 | usize_t as_trless_response; | ||||||||
300 | usize_t as_trless_200; | ||||||||
301 | usize_t as_merged_request; | ||||||||
302 | usize_t as_sent_msg; | ||||||||
303 | usize_t as_sent_request; | ||||||||
304 | usize_t as_sent_response; | ||||||||
305 | usize_t as_retry_request; | ||||||||
306 | usize_t as_retry_response; | ||||||||
307 | usize_t as_recv_retry; | ||||||||
308 | usize_t as_tout_request; | ||||||||
309 | usize_t as_tout_response; | ||||||||
310 | } sa_stats[1]; | ||||||||
311 | |||||||||
312 | /** Current load in receiving messages per second */ | ||||||||
313 | struct { | ||||||||
314 | usize_t as_recv_request_last; | ||||||||
315 | su_time_t last_time; | ||||||||
316 | unsigned requests_per_second; | ||||||||
317 | } sa_load[1]; | ||||||||
318 | |||||||||
319 | /** Hash of dialogs. */ | ||||||||
320 | leg_htable_t sa_dialogs[1]; | ||||||||
321 | /** Default leg */ | ||||||||
322 | nta_leg_t *sa_default_leg; | ||||||||
323 | /** Hash of legs without dialogs. */ | ||||||||
324 | leg_htable_t sa_defaults[1]; | ||||||||
325 | /** Hash table for outgoing transactions */ | ||||||||
326 | outgoing_htable_t sa_outgoing[1]; | ||||||||
327 | nta_outgoing_t *sa_default_outgoing; | ||||||||
328 | /** Hash table for incoming transactions */ | ||||||||
329 | incoming_htable_t sa_incoming[1]; | ||||||||
330 | nta_incoming_t *sa_default_incoming; | ||||||||
331 | |||||||||
332 | /* Queues (states) for outgoing client transactions */ | ||||||||
333 | struct { | ||||||||
334 | /** Queue for retrying client transactions */ | ||||||||
335 | nta_outgoing_t *re_list; | ||||||||
336 | nta_outgoing_t **re_t1; /**< Special place for T1 timer */ | ||||||||
337 | size_t re_length; /**< Length of sa_out.re_list */ | ||||||||
338 | |||||||||
339 | outgoing_queue_t delayed[1]; | ||||||||
340 | outgoing_queue_t resolving[1]; | ||||||||
341 | |||||||||
342 | outgoing_queue_t trying[1]; /* Timer F / Timer E */ | ||||||||
343 | outgoing_queue_t completed[1]; /* Timer K */ | ||||||||
344 | outgoing_queue_t terminated[1]; | ||||||||
345 | |||||||||
346 | /* Special queues (states) for outgoing INVITE transactions */ | ||||||||
347 | outgoing_queue_t inv_calling[1]; /* Timer B/A */ | ||||||||
348 | outgoing_queue_t inv_proceeding[1]; /* Timer C */ | ||||||||
349 | outgoing_queue_t inv_completed[1]; /* Timer D */ | ||||||||
350 | |||||||||
351 | /* Temporary queue for transactions waiting to be freed */ | ||||||||
352 | outgoing_queue_t *free; | ||||||||
353 | } sa_out; | ||||||||
354 | |||||||||
355 | /* Queues (states) for incoming server transactions */ | ||||||||
356 | struct { | ||||||||
357 | /** Queue for retransmitting response of server transactions */ | ||||||||
358 | nta_incoming_t *re_list; | ||||||||
359 | nta_incoming_t **re_t1; /**< Special place for T1 timer */ | ||||||||
360 | size_t re_length; /**< Length of sa_in.re_list */ | ||||||||
361 | |||||||||
362 | incoming_queue_t proceeding[1]; /**< Request received */ | ||||||||
363 | incoming_queue_t preliminary[1]; /**< 100rel sent */ | ||||||||
364 | incoming_queue_t completed[1]; /**< Final answer sent (non-invite). */ | ||||||||
365 | incoming_queue_t inv_completed[1]; /**< Final answer sent (INVITE). */ | ||||||||
366 | incoming_queue_t inv_confirmed[1]; /**< Final answer sent, ACK recvd. */ | ||||||||
367 | incoming_queue_t terminated[1]; /**< Terminated, ready to free. */ | ||||||||
368 | incoming_queue_t final_failed[1]; | ||||||||
369 | } sa_in; | ||||||||
370 | |||||||||
371 | /* Special task for freeing memory */ | ||||||||
372 | su_clone_r sa_terminator; | ||||||||
373 | }; | ||||||||
374 | |||||||||
375 | struct nta_leg_s | ||||||||
376 | { | ||||||||
377 | su_home_t leg_home[1]; | ||||||||
378 | hash_value_t leg_hash; | ||||||||
379 | |||||||||
380 | unsigned leg_dialog : 1; | ||||||||
381 | unsigned leg_stateless : 1; /**< Process requests statelessly */ | ||||||||
382 | #ifdef NTA_STRICT_ROUTING | ||||||||
383 | unsigned leg_contact_set : 1; | ||||||||
384 | #else | ||||||||
385 | unsigned leg_loose_route : 1; /**< Topmost route in set is LR */ | ||||||||
386 | #endif | ||||||||
387 | unsigned leg_route_set : 1; /**< Route set has been saved */ | ||||||||
388 | unsigned leg_local_is_to : 1; /**< Backwards-compatibility. */ | ||||||||
389 | unsigned leg_tagged : 1; /**< Tagged after creation. | ||||||||
390 | * | ||||||||
391 | * Request missing @To tag matches | ||||||||
392 | * a tagged leg even after tagging. | ||||||||
393 | */ | ||||||||
394 | unsigned leg_compressed:1; | ||||||||
395 | unsigned:0; | ||||||||
396 | nta_request_f *leg_callback; | ||||||||
397 | nta_leg_magic_t *leg_magic; | ||||||||
398 | nta_agent_t *leg_agent; | ||||||||
399 | |||||||||
400 | url_t const *leg_url; /**< Match incoming requests. */ | ||||||||
401 | char const *leg_method; /**< Match incoming requests. */ | ||||||||
402 | |||||||||
403 | uint32_t leg_seq; /**< Sequence number for next transaction */ | ||||||||
404 | uint32_t leg_rseq; /**< Remote sequence number */ | ||||||||
405 | sip_call_id_t *leg_id; /**< Call ID */ | ||||||||
406 | sip_from_t *leg_remote; /**< Remote address (@To/@From) */ | ||||||||
407 | sip_to_t *leg_local; /**< Local address (@From/@To) */ | ||||||||
408 | |||||||||
409 | sip_route_t *leg_route; /**< @Route for outgoing requests. */ | ||||||||
410 | sip_contact_t *leg_target; /**< Remote destination (from @Contact). */ | ||||||||
411 | }; | ||||||||
412 | |||||||||
413 | struct nta_incoming_s | ||||||||
414 | { | ||||||||
415 | su_home_t *irq_home; | ||||||||
416 | hash_value_t irq_hash; | ||||||||
417 | nta_agent_t *irq_agent; | ||||||||
418 | nta_ack_cancel_f *irq_callback; | ||||||||
419 | nta_incoming_magic_t *irq_magic; | ||||||||
420 | |||||||||
421 | /* Timeout/state queue */ | ||||||||
422 | nta_incoming_t **irq_prev; | ||||||||
423 | nta_incoming_t *irq_next; | ||||||||
424 | incoming_queue_t *irq_queue; | ||||||||
425 | |||||||||
426 | /* Retry queue */ | ||||||||
427 | nta_incoming_t **irq_rprev; | ||||||||
428 | nta_incoming_t *irq_rnext; | ||||||||
429 | |||||||||
430 | sip_method_t irq_method; | ||||||||
431 | sip_request_t *irq_rq; | ||||||||
432 | sip_from_t *irq_from; | ||||||||
433 | sip_to_t *irq_to; | ||||||||
434 | char const *irq_tag; | ||||||||
435 | sip_cseq_t *irq_cseq; | ||||||||
436 | sip_call_id_t *irq_call_id; | ||||||||
437 | sip_via_t *irq_via; | ||||||||
438 | sip_record_route_t *irq_record_route; | ||||||||
439 | char const *irq_branch; | ||||||||
440 | |||||||||
441 | uint32_t irq_rseq; | ||||||||
442 | |||||||||
443 | sip_timestamp_t *irq_timestamp; | ||||||||
444 | su_time_t irq_received; | ||||||||
445 | |||||||||
446 | uint32_t irq_timeout; /**< Timer H, I, J */ | ||||||||
447 | uint32_t irq_retry; /**< Timer G */ | ||||||||
448 | unsigned short irq_interval; /**< Next timer */ | ||||||||
449 | |||||||||
450 | short irq_status; | ||||||||
451 | |||||||||
452 | unsigned irq_retries:8; | ||||||||
453 | unsigned irq_default:1; /**< Default transaction */ | ||||||||
454 | unsigned irq_canceled:1; /**< Transaction is canceled */ | ||||||||
455 | unsigned irq_completed:1; /**< Transaction is completed */ | ||||||||
456 | unsigned irq_confirmed:1; /**< Response has been acked */ | ||||||||
457 | unsigned irq_terminated:1; /**< Transaction is terminated */ | ||||||||
458 | unsigned irq_final_failed:1; /**< Sending final response failed */ | ||||||||
459 | unsigned irq_destroyed :1; /**< Transaction is destroyed */ | ||||||||
460 | unsigned irq_in_callback:1; /**< Callback is being invoked */ | ||||||||
461 | unsigned irq_reliable_tp:1; /**< Transport is reliable */ | ||||||||
462 | unsigned irq_sigcomp_zap:1; /**< Reset SigComp */ | ||||||||
463 | unsigned irq_must_100rel:1; /**< 100rel is required */ | ||||||||
464 | unsigned irq_extra_100:1; /**< 100 Trying should be sent */ | ||||||||
465 | unsigned irq_tag_set:1; /**< Tag is not from request */ | ||||||||
466 | unsigned irq_compressed:1; | ||||||||
467 | unsigned :0; | ||||||||
468 | |||||||||
469 | tp_name_t irq_tpn[1]; | ||||||||
470 | tport_t *irq_tport; | ||||||||
471 | struct sigcomp_compartment *irq_cc; | ||||||||
472 | msg_t *irq_request; | ||||||||
473 | msg_t *irq_request2; /**< ACK/CANCEL */ | ||||||||
474 | msg_t *irq_response; | ||||||||
475 | |||||||||
476 | nta_reliable_t *irq_reliable; /**< List of reliable responses */ | ||||||||
477 | }; | ||||||||
478 | |||||||||
479 | struct nta_reliable_s | ||||||||
480 | { | ||||||||
481 | nta_reliable_t *rel_next; | ||||||||
482 | nta_incoming_t *rel_irq; | ||||||||
483 | nta_prack_f *rel_callback; | ||||||||
484 | nta_reliable_magic_t *rel_magic; | ||||||||
485 | uint32_t rel_rseq; | ||||||||
486 | unsigned short rel_status; | ||||||||
487 | unsigned rel_pracked:1; | ||||||||
488 | unsigned rel_precious:1; | ||||||||
489 | msg_t *rel_response; | ||||||||
490 | msg_t *rel_unsent; | ||||||||
491 | }; | ||||||||
492 | |||||||||
493 | typedef struct sipdns_resolver sipdns_resolver_t; | ||||||||
494 | |||||||||
495 | struct nta_outgoing_s | ||||||||
496 | { | ||||||||
497 | hash_value_t orq_hash; /**< Hash value */ | ||||||||
498 | nta_agent_t *orq_agent; | ||||||||
499 | nta_response_f *orq_callback; | ||||||||
500 | nta_outgoing_magic_t *orq_magic; | ||||||||
501 | |||||||||
502 | /* Timeout/state queue */ | ||||||||
503 | nta_outgoing_t **orq_prev; | ||||||||
504 | nta_outgoing_t *orq_next; | ||||||||
505 | outgoing_queue_t *orq_queue; | ||||||||
506 | |||||||||
507 | /* Retry queue */ | ||||||||
508 | nta_outgoing_t **orq_rprev; | ||||||||
509 | nta_outgoing_t *orq_rnext; | ||||||||
510 | |||||||||
511 | sip_method_t orq_method; | ||||||||
512 | char const *orq_method_name; | ||||||||
513 | url_t const *orq_url; /**< Original RequestURI */ | ||||||||
514 | |||||||||
515 | sip_from_t const *orq_from; | ||||||||
516 | sip_to_t const *orq_to; | ||||||||
517 | char const *orq_tag; /**< Tag from final response. */ | ||||||||
518 | |||||||||
519 | sip_cseq_t const *orq_cseq; | ||||||||
520 | sip_call_id_t const *orq_call_id; | ||||||||
521 | |||||||||
522 | msg_t *orq_request; | ||||||||
523 | msg_t *orq_response; | ||||||||
524 | |||||||||
525 | su_time_t orq_sent; /**< When request was sent? */ | ||||||||
526 | unsigned orq_delay; /**< RTT estimate */ | ||||||||
527 | |||||||||
528 | uint32_t orq_retry; /**< Timer A, E */ | ||||||||
529 | uint32_t orq_timeout; /**< Timer B, D, F, K */ | ||||||||
530 | |||||||||
531 | unsigned short orq_interval; /**< Next timer A/E */ | ||||||||
532 | |||||||||
533 | unsigned short orq_status; | ||||||||
534 | unsigned char orq_retries; /**< Number of tries this far */ | ||||||||
535 | |||||||||
536 | unsigned orq_default:1; /**< This is default transaction */ | ||||||||
537 | unsigned orq_inserted:1; | ||||||||
538 | unsigned orq_resolved:1; | ||||||||
539 | unsigned orq_via_added:1; | ||||||||
540 | unsigned orq_prepared:1; | ||||||||
541 | unsigned orq_canceled:1; | ||||||||
542 | unsigned orq_terminated:1; | ||||||||
543 | unsigned orq_destroyed:1; | ||||||||
544 | unsigned orq_completed:1; | ||||||||
545 | unsigned orq_delayed:1; | ||||||||
546 | unsigned orq_user_tport:1; /**< Application provided tport - don't retry */ | ||||||||
547 | unsigned orq_try_tcp_instead:1; | ||||||||
548 | unsigned orq_try_udp_instead:1; | ||||||||
549 | unsigned orq_reliable:1; /**< Transport is reliable */ | ||||||||
550 | unsigned orq_call_tls_connect_timeout_is_set:1; /** Per Call connect timeout for outgoing requests using TLS set flag*/ | ||||||||
551 | |||||||||
552 | unsigned orq_forked:1; /**< Tagged fork */ | ||||||||
553 | |||||||||
554 | /* Attributes */ | ||||||||
555 | unsigned orq_sips:1; | ||||||||
556 | unsigned orq_uas:1; /**< Running this transaction as UAS */ | ||||||||
557 | unsigned orq_user_via:1; | ||||||||
558 | unsigned orq_stateless:1; | ||||||||
559 | unsigned orq_pass_100:1; | ||||||||
560 | unsigned orq_sigcomp_new:1; /**< Create compartment if needed */ | ||||||||
561 | unsigned orq_sigcomp_zap:1; /**< Reset SigComp after completing */ | ||||||||
562 | unsigned orq_must_100rel:1; | ||||||||
563 | unsigned orq_timestamp:1; /**< Insert @Timestamp header. */ | ||||||||
564 | unsigned orq_100rel:1; /**< Support 100rel */ | ||||||||
565 | unsigned:0; /* pad */ | ||||||||
566 | |||||||||
567 | #if HAVE_SOFIA_SRESOLV1 | ||||||||
568 | sipdns_resolver_t *orq_resolver; | ||||||||
569 | #endif | ||||||||
570 | url_t *orq_route; /**< Route URL */ | ||||||||
571 | tp_name_t orq_tpn[1]; /**< Where to send request */ | ||||||||
572 | |||||||||
573 | tport_t *orq_tport; | ||||||||
574 | struct sigcomp_compartment *orq_cc; | ||||||||
575 | tagi_t *orq_tags; /**< Tport tag items */ | ||||||||
576 | |||||||||
577 | char const *orq_branch; /**< Transaction branch */ | ||||||||
578 | char const *orq_via_branch; /**< @Via branch */ | ||||||||
579 | |||||||||
580 | int *orq_status2b; /**< Delayed response */ | ||||||||
581 | |||||||||
582 | nta_outgoing_t *orq_cancel; /**< Delayed CANCEL transaction */ | ||||||||
583 | |||||||||
584 | nta_outgoing_t *orq_forking; /**< Untagged transaction */ | ||||||||
585 | nta_outgoing_t *orq_forks; /**< Tagged transactions */ | ||||||||
586 | uint32_t orq_rseq; /**< Latest incoming rseq */ | ||||||||
587 | int orq_pending; /**< Request is pending in tport */ | ||||||||
588 | uint32_t orq_call_tls_connect_timeout; /** Per Call connect timeout for outgoing requests using TLS */ | ||||||||
589 | }; | ||||||||
590 | |||||||||
591 | /* ------------------------------------------------------------------------- */ | ||||||||
592 | |||||||||
593 | /* Internal tags */ | ||||||||
594 | |||||||||
595 | /* Delay sending of request */ | ||||||||
596 | #define NTATAG_DELAY_SENDING(x)ntatag_delay_sending, tag_bool_v((x)) ntatag_delay_sending, tag_bool_v((x)) | ||||||||
597 | #define NTATAG_DELAY_SENDING_REF(x)ntatag_delay_sending_ref, tag_bool_vr(&(x)) \ | ||||||||
598 | ntatag_delay_sending_ref, tag_bool_vr(&(x)) | ||||||||
599 | |||||||||
600 | extern tag_typedef_t ntatag_delay_sending; | ||||||||
601 | extern tag_typedef_t ntatag_delay_sending_ref; | ||||||||
602 | |||||||||
603 | /* Allow sending incomplete responses */ | ||||||||
604 | #define NTATAG_INCOMPLETE(x)ntatag_incomplete, tag_bool_v((x)) ntatag_incomplete, tag_bool_v((x)) | ||||||||
605 | #define NTATAG_INCOMPLETE_REF(x)ntatag_incomplete_ref, tag_bool_vr(&(x)) \ | ||||||||
606 | ntatag_incomplete_ref, tag_bool_vr(&(x)) | ||||||||
607 | |||||||||
608 | extern tag_typedef_t ntatag_incomplete; | ||||||||
609 | extern tag_typedef_t ntatag_incomplete_ref; | ||||||||
610 | |||||||||
611 | nta_compressor_vtable_t *nta_compressor_vtable = NULL((void*)0); | ||||||||
612 | |||||||||
613 | /* Agent */ | ||||||||
614 | static int agent_tag_init(nta_agent_t *self); | ||||||||
615 | static int agent_timer_init(nta_agent_t *agent); | ||||||||
616 | static void agent_timer(su_root_magic_t *rm, su_timer_t *, nta_agent_t *); | ||||||||
617 | static int agent_launch_terminator(nta_agent_t *agent); | ||||||||
618 | static void agent_kill_terminator(nta_agent_t *agent); | ||||||||
619 | static int agent_set_params(nta_agent_t *agent, tagi_t *tags); | ||||||||
620 | static void agent_set_udp_params(nta_agent_t *self, usize_t udp_mtu); | ||||||||
621 | static int agent_get_params(nta_agent_t *agent, tagi_t *tags); | ||||||||
622 | |||||||||
623 | /* Transport interface */ | ||||||||
624 | static sip_via_t const *agent_tport_via(tport_t *tport); | ||||||||
625 | static int outgoing_insert_via(nta_outgoing_t *orq, sip_via_t const *); | ||||||||
626 | static int nta_tpn_by_via(tp_name_t *tpn, sip_via_t const *v, int *using_rport); | ||||||||
627 | |||||||||
628 | static msg_t *nta_msg_create_for_transport(nta_agent_t *agent, int flags, | ||||||||
629 | char const data[], usize_t dlen, | ||||||||
630 | tport_t const *tport, | ||||||||
631 | tp_client_t *via); | ||||||||
632 | |||||||||
633 | static int complete_response(msg_t *response, | ||||||||
634 | int status, char const *phrase, | ||||||||
635 | msg_t *request); | ||||||||
636 | |||||||||
637 | static int mreply(nta_agent_t *agent, | ||||||||
638 | msg_t *reply, | ||||||||
639 | int status, char const *phrase, | ||||||||
640 | msg_t *req_msg, | ||||||||
641 | tport_t *tport, | ||||||||
642 | int incomplete, | ||||||||
643 | int sdwn_after, | ||||||||
644 | char const *to_tag, | ||||||||
645 | tag_type_t tag, tag_value_t value, ...); | ||||||||
646 | |||||||||
647 | #define IF_SIGCOMP_TPTAG_COMPARTMENT(cc)!(cc && cc != ((void *)-1)) ? tag_skip : tptag_compartment , tag_ptr_v((cc)), TAG_IF(cc && cc != NONE, TPTAG_COMPARTMENT(cc))!(cc && cc != ((void *)-1)) ? tag_skip : tptag_compartment , tag_ptr_v((cc)), | ||||||||
648 | #define IF_SIGCOMP_TPTAG_COMPARTMENT_REF(cc)tptag_compartment_ref, tag_ptr_vr(&(cc), cc), TPTAG_COMPARTMENT_REF(cc)tptag_compartment_ref, tag_ptr_vr(&(cc), cc), | ||||||||
649 | |||||||||
650 | struct sigcomp_compartment; | ||||||||
651 | |||||||||
652 | struct sigcomp_compartment * | ||||||||
653 | nta_compartment_ref(struct sigcomp_compartment *cc); | ||||||||
654 | |||||||||
655 | static | ||||||||
656 | struct sigcomp_compartment * | ||||||||
657 | agent_compression_compartment(nta_agent_t *sa, tport_t *tp, tp_name_t const *tpn, | ||||||||
658 | int new_if_needed); | ||||||||
659 | |||||||||
660 | static | ||||||||
661 | int agent_accept_compressed(nta_agent_t *sa, msg_t *msg, | ||||||||
662 | struct sigcomp_compartment *cc); | ||||||||
663 | |||||||||
664 | static int agent_close_compressor(nta_agent_t *sa, | ||||||||
665 | struct sigcomp_compartment *cc); | ||||||||
666 | |||||||||
667 | static int agent_zap_compressor(nta_agent_t *sa, | ||||||||
668 | struct sigcomp_compartment *cc); | ||||||||
669 | |||||||||
670 | |||||||||
671 | static char const * stateful_branch(su_home_t *home, nta_agent_t *); | ||||||||
672 | static char const * stateless_branch(nta_agent_t *, msg_t *, sip_t const *, | ||||||||
673 | tp_name_t const *tp); | ||||||||
674 | |||||||||
675 | #define NTA_BRANCH_PRIME(uint64_t)(0xB9591D1C361C6521ULL) SU_U64_C(0xB9591D1C361C6521)(uint64_t)(0xB9591D1C361C6521ULL) | ||||||||
676 | #define NTA_TAG_PRIME(uint64_t)(0xB9591D1C361C6521ULL) SU_U64_C(0xB9591D1C361C6521)(uint64_t)(0xB9591D1C361C6521ULL) | ||||||||
677 | |||||||||
678 | #ifndef UINT32_MAX(4294967295U) | ||||||||
679 | #define UINT32_MAX(4294967295U) (0xffffffffU) | ||||||||
680 | #endif | ||||||||
681 | |||||||||
682 | HTABLE_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); | ||||||||
683 | static nta_leg_t *leg_find(nta_agent_t const *sa, | ||||||||
684 | char const *method_name, | ||||||||
685 | url_t const *request_uri, | ||||||||
686 | sip_call_id_t const *i, | ||||||||
687 | char const *from_tag, | ||||||||
688 | char const *to_tag); | ||||||||
689 | static nta_leg_t *dst_find(nta_agent_t const *sa, url_t const *u0, | ||||||||
690 | char const *method); | ||||||||
691 | static void leg_recv(nta_leg_t *, msg_t *, sip_t *, tport_t *); | ||||||||
692 | static void leg_free(nta_agent_t *sa, nta_leg_t *leg); | ||||||||
693 | |||||||||
694 | #define NTA_HASH(i, cs)((i)->i_hash + 26839U * (uint32_t)(cs)) ((i)->i_hash + 26839U * (uint32_t)(cs)) | ||||||||
695 | |||||||||
696 | HTABLE_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); | ||||||||
697 | static nta_incoming_t *incoming_create(nta_agent_t *agent, | ||||||||
698 | msg_t *request, | ||||||||
699 | sip_t *sip, | ||||||||
700 | tport_t *tport, | ||||||||
701 | char const *tag); | ||||||||
702 | static int incoming_callback(nta_leg_t *leg, nta_incoming_t *irq, sip_t *sip); | ||||||||
703 | static void incoming_free(nta_incoming_t *irq); | ||||||||
704 | su_inlinestatic inline void incoming_cut_off(nta_incoming_t *irq); | ||||||||
705 | su_inlinestatic inline void incoming_reclaim(nta_incoming_t *irq); | ||||||||
706 | static void incoming_queue_init(incoming_queue_t *, | ||||||||
707 | unsigned timeout); | ||||||||
708 | static void incoming_queue_adjust(nta_agent_t *sa, | ||||||||
709 | incoming_queue_t *queue, | ||||||||
710 | unsigned timeout); | ||||||||
711 | |||||||||
712 | static nta_incoming_t *incoming_find(nta_agent_t const *agent, | ||||||||
713 | sip_t const *sip, | ||||||||
714 | sip_via_t const *v, | ||||||||
715 | nta_incoming_t **merge, | ||||||||
716 | nta_incoming_t **ack, | ||||||||
717 | nta_incoming_t **cancel); | ||||||||
718 | static int incoming_reply(nta_incoming_t *irq, msg_t *msg, sip_t *sip); | ||||||||
719 | su_inlinestatic inline int incoming_recv(nta_incoming_t *irq, msg_t *msg, sip_t *sip, | ||||||||
720 | tport_t *tport); | ||||||||
721 | su_inlinestatic inline int incoming_ack(nta_incoming_t *irq, msg_t *msg, sip_t *sip, | ||||||||
722 | tport_t *tport); | ||||||||
723 | su_inlinestatic inline int incoming_cancel(nta_incoming_t *irq, msg_t *msg, sip_t *sip, | ||||||||
724 | tport_t *tport); | ||||||||
725 | static void request_merge(nta_agent_t *, | ||||||||
726 | msg_t *msg, sip_t *sip, tport_t *tport, | ||||||||
727 | char const *to_tag); | ||||||||
728 | su_inlinestatic inline int incoming_timestamp(nta_incoming_t *, msg_t *, sip_t *); | ||||||||
729 | static void _nta_incoming_timer(nta_agent_t *); | ||||||||
730 | |||||||||
731 | static nta_reliable_t *reliable_mreply(nta_incoming_t *, | ||||||||
732 | nta_prack_f *, nta_reliable_magic_t *, | ||||||||
733 | msg_t *, sip_t *); | ||||||||
734 | static int reliable_send(nta_incoming_t *, nta_reliable_t *, msg_t *, sip_t *); | ||||||||
735 | static int reliable_final(nta_incoming_t *irq, msg_t *msg, sip_t *sip); | ||||||||
736 | static msg_t *reliable_response(nta_incoming_t *irq); | ||||||||
737 | static nta_reliable_t *reliable_find(nta_agent_t const *, sip_t const *); | ||||||||
738 | static int reliable_recv(nta_reliable_t *rel, msg_t *, sip_t *, tport_t *); | ||||||||
739 | static void reliable_flush(nta_incoming_t *irq); | ||||||||
740 | static void reliable_timeout(nta_incoming_t *irq, int timeout); | ||||||||
741 | |||||||||
742 | HTABLE_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); | ||||||||
743 | static nta_outgoing_t *outgoing_create(nta_agent_t *agent, | ||||||||
744 | nta_response_f *callback, | ||||||||
745 | nta_outgoing_magic_t *magic, | ||||||||
746 | url_string_t const *route_url, | ||||||||
747 | tp_name_t const *tpn, | ||||||||
748 | msg_t *msg, | ||||||||
749 | tag_type_t tag, tag_value_t value, ...); | ||||||||
750 | static void outgoing_queue_init(outgoing_queue_t *, | ||||||||
751 | unsigned timeout); | ||||||||
752 | static void outgoing_queue_adjust(nta_agent_t *sa, | ||||||||
753 | outgoing_queue_t *queue, | ||||||||
754 | unsigned timeout); | ||||||||
755 | static void outgoing_free(nta_outgoing_t *orq); | ||||||||
756 | su_inlinestatic inline void outgoing_cut_off(nta_outgoing_t *orq); | ||||||||
757 | su_inlinestatic inline void outgoing_reclaim(nta_outgoing_t *orq); | ||||||||
758 | static nta_outgoing_t *outgoing_find(nta_agent_t const *sa, | ||||||||
759 | msg_t const *msg, | ||||||||
760 | sip_t const *sip, | ||||||||
761 | sip_via_t const *v); | ||||||||
762 | static int outgoing_recv(nta_outgoing_t *orq, int status, msg_t *, sip_t *); | ||||||||
763 | static void outgoing_default_recv(nta_outgoing_t *, int, msg_t *, sip_t *); | ||||||||
764 | static void _nta_outgoing_timer(nta_agent_t *); | ||||||||
765 | static int outgoing_recv_reliable(nta_outgoing_t *orq, msg_t *msg, sip_t *sip); | ||||||||
766 | |||||||||
767 | /* Internal message passing */ | ||||||||
768 | union sm_arg_u { | ||||||||
769 | struct outgoing_recv_s { | ||||||||
770 | nta_outgoing_t *orq; | ||||||||
771 | msg_t *msg; | ||||||||
772 | sip_t *sip; | ||||||||
773 | int status; | ||||||||
774 | } a_outgoing_recv[1]; | ||||||||
775 | |||||||||
776 | incoming_queue_t a_incoming_queue[1]; | ||||||||
777 | outgoing_queue_t a_outgoing_queue[1]; | ||||||||
778 | }; | ||||||||
779 | |||||||||
780 | /* Global module data */ | ||||||||
781 | |||||||||
782 | /**@var char const NTA_DEBUG[]; | ||||||||
783 | * | ||||||||
784 | * Environment variable determining the default debug log level. | ||||||||
785 | * | ||||||||
786 | * The NTA_DEBUG environment variable is used to determine the default | ||||||||
787 | * debug logging level. The normal level is 3. | ||||||||
788 | * | ||||||||
789 | * @sa <sofia-sip/su_debug.h>, #su_log_global, #SOFIA_DEBUG | ||||||||
790 | */ | ||||||||
791 | #ifdef DOXYGEN | ||||||||
792 | extern char const NTA_DEBUG[]; /* dummy declaration for Doxygen */ | ||||||||
793 | #endif | ||||||||
794 | |||||||||
795 | #ifndef SU_DEBUG0 | ||||||||
796 | #define SU_DEBUG0 3 | ||||||||
797 | #endif | ||||||||
798 | |||||||||
799 | /**Debug log for @b nta module. | ||||||||
800 | * | ||||||||
801 | * The nta_log is the log object used by @b nta module. The level of | ||||||||
802 | * nta_log is set using #NTA_DEBUG environment variable. | ||||||||
803 | */ | ||||||||
804 | su_log_t nta_log[] = { SU_LOG_INIT("nta", "NTA_DEBUG", SU_DEBUG){ sizeof(su_log_t), "nta", "NTA_DEBUG", 0, SU_LOG_MAX, 0, ((void *)0), ((void*)0), } }; | ||||||||
805 | |||||||||
806 | /* ====================================================================== */ | ||||||||
807 | /* 1) Agent */ | ||||||||
808 | |||||||||
809 | /** | ||||||||
810 | * Create an NTA agent object. | ||||||||
811 | * | ||||||||
812 | * Create an NTA agent object. The agent | ||||||||
813 | * object creates and binds a server socket with address specified in @e url. | ||||||||
814 | * If the @e host portion of the @e url is @c "*", the agent listens to all | ||||||||
815 | * addresses available on the host. | ||||||||
816 | * | ||||||||
817 | * When a message is received, the agent object parses it. If the result is | ||||||||
818 | * a valid SIP message, the agent object passes the message to the | ||||||||
819 | * application by invoking the nta_message_f @e callback function. | ||||||||
820 | * | ||||||||
821 | * @note | ||||||||
822 | * The @e url can be either parsed url (of type url_t ()), or a valid | ||||||||
823 | * SIP URL as a string. | ||||||||
824 | * | ||||||||
825 | * @note | ||||||||
826 | * If @e url is @c NULL, the default @e url @c "sip:*" is used. | ||||||||
827 | * @par | ||||||||
828 | * If @e url is @c NONE (iow, (void*)-1), no server sockets are bound. | ||||||||
829 | * @par | ||||||||
830 | * If @p transport parameters are specified in @a url, agent uses only | ||||||||
831 | * specified transport type. | ||||||||
832 | * | ||||||||
833 | * @par | ||||||||
834 | * If an @p maddr parameter is specified in @e url, agent binds to the | ||||||||
835 | * specified address, but uses @e host part of @e url when it generates | ||||||||
836 | * @Contact and @Via headers. The @p maddr parameter is also included, | ||||||||
837 | * unless it equals to @c INADDR_ANY (@p 0.0.0.0 or @p [::]). | ||||||||
838 | * | ||||||||
839 | * @param root pointer to a su_root_t used for synchronization | ||||||||
840 | * @param contact_url URL that agent uses to bind the server sockets | ||||||||
841 | * @param callback pointer to callback function | ||||||||
842 | * @param magic pointer to user data | ||||||||
843 | * @param tag,value,... tagged arguments | ||||||||
844 | * | ||||||||
845 | * @TAGS | ||||||||
846 | * NTATAG_ALIASES(), | ||||||||
847 | * NTATAG_BAD_REQ_MASK(), NTATAG_BAD_RESP_MASK(), NTATAG_BLACKLIST(), | ||||||||
848 | * NTATAG_CANCEL_2543(), NTATAG_CANCEL_487(), NTATAG_CLIENT_RPORT(), | ||||||||
849 | * NTATAG_DEBUG_DROP_PROB(), NTATAG_DEFAULT_PROXY(), | ||||||||
850 | * NTATAG_EXTRA_100(), NTATAG_GRAYLIST(), | ||||||||
851 | * NTATAG_MAXSIZE(), NTATAG_MAX_FORWARDS(), NTATAG_MERGE_482(), NTATAG_MCLASS() | ||||||||
852 | * NTATAG_PASS_100(), NTATAG_PASS_408(), NTATAG_PRELOAD(), NTATAG_PROGRESS(), | ||||||||
853 | * NTATAG_REL100(), | ||||||||
854 | * NTATAG_SERVER_RPORT(), | ||||||||
855 | * NTATAG_SIPFLAGS(), | ||||||||
856 | * NTATAG_SIP_T1X64(), NTATAG_SIP_T1(), NTATAG_SIP_T2(), NTATAG_SIP_T4(), | ||||||||
857 | * NTATAG_STATELESS(), | ||||||||
858 | * NTATAG_TAG_3261(), NTATAG_TCP_RPORT(), NTATAG_TIMEOUT_408(), | ||||||||
859 | * NTATAG_TLS_RPORT(), NTATAG_TLS_ORQ_CONNECT_TIMEOUT(), | ||||||||
860 | * NTATAG_TIMER_C(), NTATAG_MAX_PROCEEDING(), | ||||||||
861 | * NTATAG_UA(), NTATAG_UDP_MTU(), NTATAG_USER_VIA(), | ||||||||
862 | * NTATAG_USE_NAPTR(), NTATAG_USE_SRV() and NTATAG_USE_TIMESTAMP(). | ||||||||
863 | * | ||||||||
864 | * @note The value from following tags are stored, but they currently do nothing: | ||||||||
865 | * NTATAG_SIGCOMP_ALGORITHM(), NTATAG_SIGCOMP_OPTIONS(), NTATAG_SMIME() | ||||||||
866 | * | ||||||||
867 | * @note It is possible to provide @c (url_string_t*)-1 as @a contact_url. | ||||||||
868 | * In that case, no server sockets are bound. | ||||||||
869 | * | ||||||||
870 | * @retval handle to the agent when successful, | ||||||||
871 | * @retval NULL upon an error. | ||||||||
872 | * | ||||||||
873 | * @sa NUTAG_ | ||||||||
874 | */ | ||||||||
875 | nta_agent_t *nta_agent_create(su_root_t *root, | ||||||||
876 | url_string_t const *contact_url, | ||||||||
877 | nta_message_f *callback, | ||||||||
878 | nta_agent_magic_t *magic, | ||||||||
879 | tag_type_t tag, tag_value_t value, ...) | ||||||||
880 | { | ||||||||
881 | nta_agent_t *agent; | ||||||||
882 | ta_list ta; | ||||||||
883 | |||||||||
884 | if (root == NULL((void*)0)) | ||||||||
885 | return su_seterrno(EINVAL22), NULL((void*)0); | ||||||||
886 | |||||||||
887 | ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value = (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag ) == tag_next && (ta_start__value) != 0) { ta_start__tag = ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag == tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag == tag_next) { ta_start__value = ((tagi_t *)ta_start__value) ->t_value; } else { ta_start__tag = tag_next; break; } } ( ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value ; if (ta_start__tag != ((void*)0) && ta_start__tag != tag_null && ta_start__tag != tag_next) { va_list ta_start__ap ; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag = tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap ); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value = 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0); | ||||||||
888 | |||||||||
889 | if ((agent = su_home_new(sizeof(*agent)))) { | ||||||||
890 | unsigned timer_c = 0, timer_d = 32000; | ||||||||
891 | |||||||||
892 | agent->sa_root = root; | ||||||||
893 | agent->sa_callback = callback; | ||||||||
894 | agent->sa_magic = magic; | ||||||||
895 | agent->sa_flags = MSG_DO_CANONICMSG_FLG_CANONIC; | ||||||||
896 | |||||||||
897 | agent->sa_maxsize = 2 * 1024 * 1024; /* 2 MB */ | ||||||||
898 | agent->sa_bad_req_mask = | ||||||||
899 | /* | ||||||||
900 | * Bit-wise not of these - what is left is suitable for UAs with | ||||||||
901 | * 100rel, timer, events, publish | ||||||||
902 | */ | ||||||||
903 | (unsigned) ~(sip_mask_response | sip_mask_proxy | sip_mask_registrar | | ||||||||
904 | sip_mask_pref | sip_mask_privacy); | ||||||||
905 | agent->sa_bad_resp_mask = | ||||||||
906 | (unsigned) ~(sip_mask_request | sip_mask_proxy | sip_mask_registrar | | ||||||||
907 | sip_mask_pref | sip_mask_privacy); | ||||||||
908 | agent->sa_t1 = NTA_SIP_T1; | ||||||||
909 | agent->sa_t2 = NTA_SIP_T2; | ||||||||
910 | agent->sa_t4 = NTA_SIP_T4; | ||||||||
911 | agent->sa_t1x64 = 64 * NTA_SIP_T1; | ||||||||
912 | agent->sa_timer_c = 185 * 1000; | ||||||||
913 | agent->sa_graylist = 600; | ||||||||
914 | agent->sa_drop_prob = 0; | ||||||||
915 | agent->sa_is_a_uas = 0; | ||||||||
916 | agent->sa_progress = 60 * 1000; | ||||||||
917 | agent->sa_user_via = 0; | ||||||||
918 | agent->sa_extra_100 = 0; | ||||||||
919 | agent->sa_pass_100 = 0; | ||||||||
920 | agent->sa_timeout_408 = 1; | ||||||||
921 | agent->sa_pass_408 = 0; | ||||||||
922 | agent->sa_merge_482 = 0; | ||||||||
923 | agent->sa_cancel_2543 = 0; | ||||||||
924 | agent->sa_cancel_487 = 1; | ||||||||
925 | agent->sa_invite_100rel = 0; | ||||||||
926 | agent->sa_timestamp = 0; | ||||||||
927 | agent->sa_use_naptr = 1; | ||||||||
928 | agent->sa_use_srv = 1; | ||||||||
929 | agent->sa_srv_503 = 1; | ||||||||
930 | agent->sa_auto_comp = 0; | ||||||||
931 | agent->sa_server_rport = 1; | ||||||||
932 | |||||||||
933 | /* RFC 3261 section 8.1.1.6 */ | ||||||||
934 | sip_max_forwards_init(agent->sa_max_forwards); | ||||||||
935 | |||||||||
936 | if (getenv("SIPCOMPACT")) | ||||||||
937 | agent->sa_flags |= MSG_DO_COMPACTMSG_FLG_COMPACT; | ||||||||
938 | |||||||||
939 | agent_set_params(agent, ta_args(ta)(ta).tl); | ||||||||
940 | |||||||||
941 | if (agent->sa_mclass == NULL((void*)0)) | ||||||||
942 | agent->sa_mclass = sip_default_mclass(); | ||||||||
943 | |||||||||
944 | agent->sa_in.re_t1 = &agent->sa_in.re_list; | ||||||||
945 | |||||||||
946 | incoming_queue_init(agent->sa_in.proceeding, 0); | ||||||||
947 | incoming_queue_init(agent->sa_in.preliminary, agent->sa_t1x64); /* P1 */ | ||||||||
948 | incoming_queue_init(agent->sa_in.inv_completed, agent->sa_t1x64); /* H */ | ||||||||
949 | incoming_queue_init(agent->sa_in.inv_confirmed, agent->sa_t4); /* I */ | ||||||||
950 | incoming_queue_init(agent->sa_in.completed, agent->sa_t1x64); /* J */ | ||||||||
951 | incoming_queue_init(agent->sa_in.terminated, 0); | ||||||||
952 | incoming_queue_init(agent->sa_in.final_failed, 0); | ||||||||
953 | |||||||||
954 | agent->sa_out.re_t1 = &agent->sa_out.re_list; | ||||||||
955 | |||||||||
956 | if (agent->sa_use_timer_c || !agent->sa_is_a_uas) | ||||||||
957 | timer_c = agent->sa_timer_c; | ||||||||
958 | if (timer_d < agent->sa_t1x64) | ||||||||
959 | timer_d = agent->sa_t1x64; | ||||||||
960 | |||||||||
961 | outgoing_queue_init(agent->sa_out.delayed, 0); | ||||||||
962 | outgoing_queue_init(agent->sa_out.resolving, 0); | ||||||||
963 | outgoing_queue_init(agent->sa_out.trying, agent->sa_t1x64); /* F */ | ||||||||
964 | outgoing_queue_init(agent->sa_out.completed, agent->sa_t4); /* K */ | ||||||||
965 | outgoing_queue_init(agent->sa_out.terminated, 0); | ||||||||
966 | /* Special queues (states) for outgoing INVITE transactions */ | ||||||||
967 | outgoing_queue_init(agent->sa_out.inv_calling, agent->sa_t1x64); /* B */ | ||||||||
968 | outgoing_queue_init(agent->sa_out.inv_proceeding, timer_c); /* C */ | ||||||||
969 | outgoing_queue_init(agent->sa_out.inv_completed, timer_d); /* D */ | ||||||||
970 | |||||||||
971 | if (leg_htable_resize(agent->sa_home, agent->sa_dialogs, 0) < 0 || | ||||||||
972 | leg_htable_resize(agent->sa_home, agent->sa_defaults, 0) < 0 || | ||||||||
973 | outgoing_htable_resize(agent->sa_home, agent->sa_outgoing, 0) < 0 || | ||||||||
974 | incoming_htable_resize(agent->sa_home, agent->sa_incoming, 0) < 0) { | ||||||||
975 | SU_DEBUG_0(("nta_agent_create: failure with %s\n", "hash tables"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 0 ? (_su_llog(nta_log, 0, "nta.c", (const char *)__func__ , 975, "nta_agent_create: failure with %s\n", "hash tables")) : (void)0); | ||||||||
976 | goto deinit; | ||||||||
977 | } | ||||||||
978 | SU_DEBUG_9(("nta_agent_create: initialized %s\n", "hash tables"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 978, "nta_agent_create: initialized %s\n", "hash tables")) : (void)0); | ||||||||
979 | |||||||||
980 | if (contact_url != (url_string_t *)-1 && | ||||||||
981 | nta_agent_add_tport(agent, contact_url, ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta). tl[1].t_value) < 0) { | ||||||||
982 | SU_DEBUG_7(("nta_agent_create: failure with %s\n", "transport"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__ , 982, "nta_agent_create: failure with %s\n", "transport")) : (void)0); | ||||||||
983 | goto deinit; | ||||||||
984 | } | ||||||||
985 | SU_DEBUG_9(("nta_agent_create: initialized %s\n", "transports"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 985, "nta_agent_create: initialized %s\n", "transports")) : (void)0); | ||||||||
986 | |||||||||
987 | if (agent_tag_init(agent) < 0) { | ||||||||
988 | SU_DEBUG_3(("nta_agent_create: failure with %s\n", "random identifiers"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 988, "nta_agent_create: failure with %s\n", "random identifiers" )) : (void)0); | ||||||||
989 | goto deinit; | ||||||||
990 | } | ||||||||
991 | SU_DEBUG_9(("nta_agent_create: initialized %s\n", "random identifiers"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 991, "nta_agent_create: initialized %s\n", "random identifiers" )) : (void)0); | ||||||||
992 | |||||||||
993 | if (agent_timer_init(agent) < 0) { | ||||||||
994 | SU_DEBUG_0(("nta_agent_create: failure with %s\n", "timer"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 0 ? (_su_llog(nta_log, 0, "nta.c", (const char *)__func__ , 994, "nta_agent_create: failure with %s\n", "timer")) : (void )0); | ||||||||
995 | goto deinit; | ||||||||
996 | } | ||||||||
997 | SU_DEBUG_9(("nta_agent_create: initialized %s\n", "timer"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 997, "nta_agent_create: initialized %s\n", "timer")) : (void )0); | ||||||||
998 | |||||||||
999 | if (agent_launch_terminator(agent) == 0) | ||||||||
1000 | SU_DEBUG_9(("nta_agent_create: initialized %s\n", "threads"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 1000, "nta_agent_create: initialized %s\n", "threads")) : ( void)0); | ||||||||
1001 | |||||||||
1002 | #if HAVE_SOFIA_SRESOLV1 | ||||||||
1003 | agent->sa_resolver = sres_resolver_create(root, NULL((void*)0), ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta). tl[1].t_value); | ||||||||
1004 | if (!agent->sa_resolver) { | ||||||||
1005 | SU_DEBUG_0(("nta_agent_create: failure with %s\n", "resolver"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 0 ? (_su_llog(nta_log, 0, "nta.c", (const char *)__func__ , 1005, "nta_agent_create: failure with %s\n", "resolver")) : (void)0); | ||||||||
1006 | } | ||||||||
1007 | SU_DEBUG_9(("nta_agent_create: initialized %s\n", "resolver"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 1007, "nta_agent_create: initialized %s\n", "resolver")) : ( void)0); | ||||||||
1008 | #endif | ||||||||
1009 | |||||||||
1010 | ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value ))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta) .ap)); | ||||||||
1011 | |||||||||
1012 | return agent; | ||||||||
1013 | |||||||||
1014 | deinit: | ||||||||
1015 | nta_agent_destroy(agent); | ||||||||
1016 | } | ||||||||
1017 | |||||||||
1018 | ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value ))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta) .ap)); | ||||||||
1019 | |||||||||
1020 | return NULL((void*)0); | ||||||||
1021 | } | ||||||||
1022 | |||||||||
1023 | /** | ||||||||
1024 | * Destroy an NTA agent object. | ||||||||
1025 | * | ||||||||
1026 | * @param agent the NTA agent object to be destroyed. | ||||||||
1027 | * | ||||||||
1028 | */ | ||||||||
1029 | void nta_agent_destroy(nta_agent_t *agent) | ||||||||
1030 | { | ||||||||
1031 | if (agent) { | ||||||||
1032 | size_t i; | ||||||||
1033 | outgoing_htable_t *oht = agent->sa_outgoing; | ||||||||
1034 | incoming_htable_t *iht = agent->sa_incoming; | ||||||||
1035 | /* Currently, this is pretty pointless, as legs don't keep any resources */ | ||||||||
1036 | leg_htable_t *lht; | ||||||||
1037 | nta_leg_t *leg; | ||||||||
1038 | |||||||||
1039 | for (i = 0, lht = agent->sa_dialogs; i < lht->lht_size; i++) { | ||||||||
1040 | if ((leg = lht->lht_table[i])) { | ||||||||
1041 | SU_DEBUG_3(("nta_agent_destroy: destroying dialog with <"(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 1043, "nta_agent_destroy: destroying dialog with <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">\n", (leg->leg_remote->a_url)->url_scheme ? (leg ->leg_remote->a_url)->url_scheme : "", (leg->leg_remote ->a_url)->url_type != url_any && (leg->leg_remote ->a_url)->url_scheme && (leg->leg_remote-> a_url)->url_scheme[0] ? ":" : "", (leg->leg_remote-> a_url)->url_root && ((leg->leg_remote->a_url )->url_host || (leg->leg_remote->a_url)->url_user ) ? "//" : "", (leg->leg_remote->a_url)->url_user ? ( leg->leg_remote->a_url)->url_user : "", (leg->leg_remote ->a_url)->url_user && (leg->leg_remote->a_url )->url_password ? ":" : "", (leg->leg_remote->a_url) ->url_user && (leg->leg_remote->a_url)->url_password ? (leg->leg_remote->a_url)->url_password : "", (leg ->leg_remote->a_url)->url_user && (leg->leg_remote ->a_url)->url_host ? "@" : "", (leg->leg_remote-> a_url)->url_host ? (leg->leg_remote->a_url)->url_host : "", (leg->leg_remote->a_url)->url_host && (leg->leg_remote->a_url)->url_port ? ":" : "", (leg ->leg_remote->a_url)->url_host && (leg->leg_remote ->a_url)->url_port ? (leg->leg_remote->a_url)-> url_port : "", (leg->leg_remote->a_url)->url_root && (leg->leg_remote->a_url)->url_path ? "/" : "", (leg ->leg_remote->a_url)->url_path ? (leg->leg_remote ->a_url)->url_path : "", (leg->leg_remote->a_url) ->url_params ? ";" : "", (leg->leg_remote->a_url)-> url_params ? (leg->leg_remote->a_url)->url_params : "" , (leg->leg_remote->a_url)->url_headers ? "?" : "", ( leg->leg_remote->a_url)->url_headers ? (leg->leg_remote ->a_url)->url_headers : "", (leg->leg_remote->a_url )->url_fragment ? "#" : "", (leg->leg_remote->a_url) ->url_fragment ? (leg->leg_remote->a_url)->url_fragment : "")) : (void)0) | ||||||||
1042 | URL_PRINT_FORMAT ">\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 1043, "nta_agent_destroy: destroying dialog with <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">\n", (leg->leg_remote->a_url)->url_scheme ? (leg ->leg_remote->a_url)->url_scheme : "", (leg->leg_remote ->a_url)->url_type != url_any && (leg->leg_remote ->a_url)->url_scheme && (leg->leg_remote-> a_url)->url_scheme[0] ? ":" : "", (leg->leg_remote-> a_url)->url_root && ((leg->leg_remote->a_url )->url_host || (leg->leg_remote->a_url)->url_user ) ? "//" : "", (leg->leg_remote->a_url)->url_user ? ( leg->leg_remote->a_url)->url_user : "", (leg->leg_remote ->a_url)->url_user && (leg->leg_remote->a_url )->url_password ? ":" : "", (leg->leg_remote->a_url) ->url_user && (leg->leg_remote->a_url)->url_password ? (leg->leg_remote->a_url)->url_password : "", (leg ->leg_remote->a_url)->url_user && (leg->leg_remote ->a_url)->url_host ? "@" : "", (leg->leg_remote-> a_url)->url_host ? (leg->leg_remote->a_url)->url_host : "", (leg->leg_remote->a_url)->url_host && (leg->leg_remote->a_url)->url_port ? ":" : "", (leg ->leg_remote->a_url)->url_host && (leg->leg_remote ->a_url)->url_port ? (leg->leg_remote->a_url)-> url_port : "", (leg->leg_remote->a_url)->url_root && (leg->leg_remote->a_url)->url_path ? "/" : "", (leg ->leg_remote->a_url)->url_path ? (leg->leg_remote ->a_url)->url_path : "", (leg->leg_remote->a_url) ->url_params ? ";" : "", (leg->leg_remote->a_url)-> url_params ? (leg->leg_remote->a_url)->url_params : "" , (leg->leg_remote->a_url)->url_headers ? "?" : "", ( leg->leg_remote->a_url)->url_headers ? (leg->leg_remote ->a_url)->url_headers : "", (leg->leg_remote->a_url )->url_fragment ? "#" : "", (leg->leg_remote->a_url) ->url_fragment ? (leg->leg_remote->a_url)->url_fragment : "")) : (void)0) | ||||||||
1043 | URL_PRINT_ARGS(leg->leg_remote->a_url)))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 1043, "nta_agent_destroy: destroying dialog with <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">\n", (leg->leg_remote->a_url)->url_scheme ? (leg ->leg_remote->a_url)->url_scheme : "", (leg->leg_remote ->a_url)->url_type != url_any && (leg->leg_remote ->a_url)->url_scheme && (leg->leg_remote-> a_url)->url_scheme[0] ? ":" : "", (leg->leg_remote-> a_url)->url_root && ((leg->leg_remote->a_url )->url_host || (leg->leg_remote->a_url)->url_user ) ? "//" : "", (leg->leg_remote->a_url)->url_user ? ( leg->leg_remote->a_url)->url_user : "", (leg->leg_remote ->a_url)->url_user && (leg->leg_remote->a_url )->url_password ? ":" : "", (leg->leg_remote->a_url) ->url_user && (leg->leg_remote->a_url)->url_password ? (leg->leg_remote->a_url)->url_password : "", (leg ->leg_remote->a_url)->url_user && (leg->leg_remote ->a_url)->url_host ? "@" : "", (leg->leg_remote-> a_url)->url_host ? (leg->leg_remote->a_url)->url_host : "", (leg->leg_remote->a_url)->url_host && (leg->leg_remote->a_url)->url_port ? ":" : "", (leg ->leg_remote->a_url)->url_host && (leg->leg_remote ->a_url)->url_port ? (leg->leg_remote->a_url)-> url_port : "", (leg->leg_remote->a_url)->url_root && (leg->leg_remote->a_url)->url_path ? "/" : "", (leg ->leg_remote->a_url)->url_path ? (leg->leg_remote ->a_url)->url_path : "", (leg->leg_remote->a_url) ->url_params ? ";" : "", (leg->leg_remote->a_url)-> url_params ? (leg->leg_remote->a_url)->url_params : "" , (leg->leg_remote->a_url)->url_headers ? "?" : "", ( leg->leg_remote->a_url)->url_headers ? (leg->leg_remote ->a_url)->url_headers : "", (leg->leg_remote->a_url )->url_fragment ? "#" : "", (leg->leg_remote->a_url) ->url_fragment ? (leg->leg_remote->a_url)->url_fragment : "")) : (void)0); | ||||||||
1044 | leg_free(agent, leg); | ||||||||
1045 | } | ||||||||
1046 | } | ||||||||
1047 | |||||||||
1048 | for (i = 0, lht = agent->sa_defaults; i < lht->lht_size; i++) { | ||||||||
1049 | if ((leg = lht->lht_table[i])) { | ||||||||
1050 | SU_DEBUG_3(("%s: destroying leg for <"(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 1052, "%s: destroying leg for <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">\n", __func__, (leg->leg_url)->url_scheme ? (leg-> leg_url)->url_scheme : "", (leg->leg_url)->url_type != url_any && (leg->leg_url)->url_scheme && (leg->leg_url)->url_scheme[0] ? ":" : "", (leg->leg_url )->url_root && ((leg->leg_url)->url_host || ( leg->leg_url)->url_user) ? "//" : "", (leg->leg_url) ->url_user ? (leg->leg_url)->url_user : "", (leg-> leg_url)->url_user && (leg->leg_url)->url_password ? ":" : "", (leg->leg_url)->url_user && (leg-> leg_url)->url_password ? (leg->leg_url)->url_password : "", (leg->leg_url)->url_user && (leg->leg_url )->url_host ? "@" : "", (leg->leg_url)->url_host ? ( leg->leg_url)->url_host : "", (leg->leg_url)->url_host && (leg->leg_url)->url_port ? ":" : "", (leg-> leg_url)->url_host && (leg->leg_url)->url_port ? (leg->leg_url)->url_port : "", (leg->leg_url)-> url_root && (leg->leg_url)->url_path ? "/" : "" , (leg->leg_url)->url_path ? (leg->leg_url)->url_path : "", (leg->leg_url)->url_params ? ";" : "", (leg-> leg_url)->url_params ? (leg->leg_url)->url_params : "" , (leg->leg_url)->url_headers ? "?" : "", (leg->leg_url )->url_headers ? (leg->leg_url)->url_headers : "", ( leg->leg_url)->url_fragment ? "#" : "", (leg->leg_url )->url_fragment ? (leg->leg_url)->url_fragment : "") ) : (void)0) | ||||||||
1051 | URL_PRINT_FORMAT ">\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 1052, "%s: destroying leg for <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">\n", __func__, (leg->leg_url)->url_scheme ? (leg-> leg_url)->url_scheme : "", (leg->leg_url)->url_type != url_any && (leg->leg_url)->url_scheme && (leg->leg_url)->url_scheme[0] ? ":" : "", (leg->leg_url )->url_root && ((leg->leg_url)->url_host || ( leg->leg_url)->url_user) ? "//" : "", (leg->leg_url) ->url_user ? (leg->leg_url)->url_user : "", (leg-> leg_url)->url_user && (leg->leg_url)->url_password ? ":" : "", (leg->leg_url)->url_user && (leg-> leg_url)->url_password ? (leg->leg_url)->url_password : "", (leg->leg_url)->url_user && (leg->leg_url )->url_host ? "@" : "", (leg->leg_url)->url_host ? ( leg->leg_url)->url_host : "", (leg->leg_url)->url_host && (leg->leg_url)->url_port ? ":" : "", (leg-> leg_url)->url_host && (leg->leg_url)->url_port ? (leg->leg_url)->url_port : "", (leg->leg_url)-> url_root && (leg->leg_url)->url_path ? "/" : "" , (leg->leg_url)->url_path ? (leg->leg_url)->url_path : "", (leg->leg_url)->url_params ? ";" : "", (leg-> leg_url)->url_params ? (leg->leg_url)->url_params : "" , (leg->leg_url)->url_headers ? "?" : "", (leg->leg_url )->url_headers ? (leg->leg_url)->url_headers : "", ( leg->leg_url)->url_fragment ? "#" : "", (leg->leg_url )->url_fragment ? (leg->leg_url)->url_fragment : "") ) : (void)0) | ||||||||
1052 | __func__, URL_PRINT_ARGS(leg->leg_url)))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 1052, "%s: destroying leg for <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">\n", __func__, (leg->leg_url)->url_scheme ? (leg-> leg_url)->url_scheme : "", (leg->leg_url)->url_type != url_any && (leg->leg_url)->url_scheme && (leg->leg_url)->url_scheme[0] ? ":" : "", (leg->leg_url )->url_root && ((leg->leg_url)->url_host || ( leg->leg_url)->url_user) ? "//" : "", (leg->leg_url) ->url_user ? (leg->leg_url)->url_user : "", (leg-> leg_url)->url_user && (leg->leg_url)->url_password ? ":" : "", (leg->leg_url)->url_user && (leg-> leg_url)->url_password ? (leg->leg_url)->url_password : "", (leg->leg_url)->url_user && (leg->leg_url )->url_host ? "@" : "", (leg->leg_url)->url_host ? ( leg->leg_url)->url_host : "", (leg->leg_url)->url_host && (leg->leg_url)->url_port ? ":" : "", (leg-> leg_url)->url_host && (leg->leg_url)->url_port ? (leg->leg_url)->url_port : "", (leg->leg_url)-> url_root && (leg->leg_url)->url_path ? "/" : "" , (leg->leg_url)->url_path ? (leg->leg_url)->url_path : "", (leg->leg_url)->url_params ? ";" : "", (leg-> leg_url)->url_params ? (leg->leg_url)->url_params : "" , (leg->leg_url)->url_headers ? "?" : "", (leg->leg_url )->url_headers ? (leg->leg_url)->url_headers : "", ( leg->leg_url)->url_fragment ? "#" : "", (leg->leg_url )->url_fragment ? (leg->leg_url)->url_fragment : "") ) : (void)0); | ||||||||
1053 | leg_free(agent, leg); | ||||||||
1054 | } | ||||||||
1055 | } | ||||||||
1056 | |||||||||
1057 | if (agent->sa_default_leg) | ||||||||
1058 | leg_free(agent, agent->sa_default_leg); | ||||||||
1059 | |||||||||
1060 | for (i = iht->iht_size; i-- > 0; ) | ||||||||
1061 | while (iht->iht_table[i]) { | ||||||||
1062 | nta_incoming_t *irq = iht->iht_table[i]; | ||||||||
1063 | |||||||||
1064 | if (!irq->irq_destroyed) | ||||||||
1065 | SU_DEBUG_3(("%s: destroying %s server transaction from <"(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 1068, "%s: destroying %s server transaction from <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">\n", __func__, irq->irq_rq->rq_method_name, (irq-> irq_from->a_url)->url_scheme ? (irq->irq_from->a_url )->url_scheme : "", (irq->irq_from->a_url)->url_type != url_any && (irq->irq_from->a_url)->url_scheme && (irq->irq_from->a_url)->url_scheme[0] ? ":" : "", (irq->irq_from->a_url)->url_root && ( (irq->irq_from->a_url)->url_host || (irq->irq_from ->a_url)->url_user) ? "//" : "", (irq->irq_from-> a_url)->url_user ? (irq->irq_from->a_url)->url_user : "", (irq->irq_from->a_url)->url_user && ( irq->irq_from->a_url)->url_password ? ":" : "", (irq ->irq_from->a_url)->url_user && (irq->irq_from ->a_url)->url_password ? (irq->irq_from->a_url)-> url_password : "", (irq->irq_from->a_url)->url_user && (irq->irq_from->a_url)->url_host ? "@" : "", (irq-> irq_from->a_url)->url_host ? (irq->irq_from->a_url )->url_host : "", (irq->irq_from->a_url)->url_host && (irq->irq_from->a_url)->url_port ? ":" : "", (irq->irq_from->a_url)->url_host && (irq ->irq_from->a_url)->url_port ? (irq->irq_from-> a_url)->url_port : "", (irq->irq_from->a_url)->url_root && (irq->irq_from->a_url)->url_path ? "/" : "", (irq->irq_from->a_url)->url_path ? (irq->irq_from ->a_url)->url_path : "", (irq->irq_from->a_url)-> url_params ? ";" : "", (irq->irq_from->a_url)->url_params ? (irq->irq_from->a_url)->url_params : "", (irq-> irq_from->a_url)->url_headers ? "?" : "", (irq->irq_from ->a_url)->url_headers ? (irq->irq_from->a_url)-> url_headers : "", (irq->irq_from->a_url)->url_fragment ? "#" : "", (irq->irq_from->a_url)->url_fragment ? ( irq->irq_from->a_url)->url_fragment : "")) : (void)0 ) | ||||||||
1066 | URL_PRINT_FORMAT ">\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 1068, "%s: destroying %s server transaction from <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">\n", __func__, irq->irq_rq->rq_method_name, (irq-> irq_from->a_url)->url_scheme ? (irq->irq_from->a_url )->url_scheme : "", (irq->irq_from->a_url)->url_type != url_any && (irq->irq_from->a_url)->url_scheme && (irq->irq_from->a_url)->url_scheme[0] ? ":" : "", (irq->irq_from->a_url)->url_root && ( (irq->irq_from->a_url)->url_host || (irq->irq_from ->a_url)->url_user) ? "//" : "", (irq->irq_from-> a_url)->url_user ? (irq->irq_from->a_url)->url_user : "", (irq->irq_from->a_url)->url_user && ( irq->irq_from->a_url)->url_password ? ":" : "", (irq ->irq_from->a_url)->url_user && (irq->irq_from ->a_url)->url_password ? (irq->irq_from->a_url)-> url_password : "", (irq->irq_from->a_url)->url_user && (irq->irq_from->a_url)->url_host ? "@" : "", (irq-> irq_from->a_url)->url_host ? (irq->irq_from->a_url )->url_host : "", (irq->irq_from->a_url)->url_host && (irq->irq_from->a_url)->url_port ? ":" : "", (irq->irq_from->a_url)->url_host && (irq ->irq_from->a_url)->url_port ? (irq->irq_from-> a_url)->url_port : "", (irq->irq_from->a_url)->url_root && (irq->irq_from->a_url)->url_path ? "/" : "", (irq->irq_from->a_url)->url_path ? (irq->irq_from ->a_url)->url_path : "", (irq->irq_from->a_url)-> url_params ? ";" : "", (irq->irq_from->a_url)->url_params ? (irq->irq_from->a_url)->url_params : "", (irq-> irq_from->a_url)->url_headers ? "?" : "", (irq->irq_from ->a_url)->url_headers ? (irq->irq_from->a_url)-> url_headers : "", (irq->irq_from->a_url)->url_fragment ? "#" : "", (irq->irq_from->a_url)->url_fragment ? ( irq->irq_from->a_url)->url_fragment : "")) : (void)0 ) | ||||||||
1067 | __func__, irq->irq_rq->rq_method_name,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 1068, "%s: destroying %s server transaction from <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">\n", __func__, irq->irq_rq->rq_method_name, (irq-> irq_from->a_url)->url_scheme ? (irq->irq_from->a_url )->url_scheme : "", (irq->irq_from->a_url)->url_type != url_any && (irq->irq_from->a_url)->url_scheme && (irq->irq_from->a_url)->url_scheme[0] ? ":" : "", (irq->irq_from->a_url)->url_root && ( (irq->irq_from->a_url)->url_host || (irq->irq_from ->a_url)->url_user) ? "//" : "", (irq->irq_from-> a_url)->url_user ? (irq->irq_from->a_url)->url_user : "", (irq->irq_from->a_url)->url_user && ( irq->irq_from->a_url)->url_password ? ":" : "", (irq ->irq_from->a_url)->url_user && (irq->irq_from ->a_url)->url_password ? (irq->irq_from->a_url)-> url_password : "", (irq->irq_from->a_url)->url_user && (irq->irq_from->a_url)->url_host ? "@" : "", (irq-> irq_from->a_url)->url_host ? (irq->irq_from->a_url )->url_host : "", (irq->irq_from->a_url)->url_host && (irq->irq_from->a_url)->url_port ? ":" : "", (irq->irq_from->a_url)->url_host && (irq ->irq_from->a_url)->url_port ? (irq->irq_from-> a_url)->url_port : "", (irq->irq_from->a_url)->url_root && (irq->irq_from->a_url)->url_path ? "/" : "", (irq->irq_from->a_url)->url_path ? (irq->irq_from ->a_url)->url_path : "", (irq->irq_from->a_url)-> url_params ? ";" : "", (irq->irq_from->a_url)->url_params ? (irq->irq_from->a_url)->url_params : "", (irq-> irq_from->a_url)->url_headers ? "?" : "", (irq->irq_from ->a_url)->url_headers ? (irq->irq_from->a_url)-> url_headers : "", (irq->irq_from->a_url)->url_fragment ? "#" : "", (irq->irq_from->a_url)->url_fragment ? ( irq->irq_from->a_url)->url_fragment : "")) : (void)0 ) | ||||||||
1068 | URL_PRINT_ARGS(irq->irq_from->a_url)))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 1068, "%s: destroying %s server transaction from <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">\n", __func__, irq->irq_rq->rq_method_name, (irq-> irq_from->a_url)->url_scheme ? (irq->irq_from->a_url )->url_scheme : "", (irq->irq_from->a_url)->url_type != url_any && (irq->irq_from->a_url)->url_scheme && (irq->irq_from->a_url)->url_scheme[0] ? ":" : "", (irq->irq_from->a_url)->url_root && ( (irq->irq_from->a_url)->url_host || (irq->irq_from ->a_url)->url_user) ? "//" : "", (irq->irq_from-> a_url)->url_user ? (irq->irq_from->a_url)->url_user : "", (irq->irq_from->a_url)->url_user && ( irq->irq_from->a_url)->url_password ? ":" : "", (irq ->irq_from->a_url)->url_user && (irq->irq_from ->a_url)->url_password ? (irq->irq_from->a_url)-> url_password : "", (irq->irq_from->a_url)->url_user && (irq->irq_from->a_url)->url_host ? "@" : "", (irq-> irq_from->a_url)->url_host ? (irq->irq_from->a_url )->url_host : "", (irq->irq_from->a_url)->url_host && (irq->irq_from->a_url)->url_port ? ":" : "", (irq->irq_from->a_url)->url_host && (irq ->irq_from->a_url)->url_port ? (irq->irq_from-> a_url)->url_port : "", (irq->irq_from->a_url)->url_root && (irq->irq_from->a_url)->url_path ? "/" : "", (irq->irq_from->a_url)->url_path ? (irq->irq_from ->a_url)->url_path : "", (irq->irq_from->a_url)-> url_params ? ";" : "", (irq->irq_from->a_url)->url_params ? (irq->irq_from->a_url)->url_params : "", (irq-> irq_from->a_url)->url_headers ? "?" : "", (irq->irq_from ->a_url)->url_headers ? (irq->irq_from->a_url)-> url_headers : "", (irq->irq_from->a_url)->url_fragment ? "#" : "", (irq->irq_from->a_url)->url_fragment ? ( irq->irq_from->a_url)->url_fragment : "")) : (void)0 ); | ||||||||
1069 | |||||||||
1070 | incoming_free(irq); | ||||||||
1071 | } | ||||||||
1072 | |||||||||
1073 | for (i = oht->oht_size; i-- > 0;) | ||||||||
1074 | while (oht->oht_table[i]) { | ||||||||
1075 | nta_outgoing_t *orq = oht->oht_table[i]; | ||||||||
1076 | |||||||||
1077 | if (!orq->orq_destroyed) | ||||||||
1078 | SU_DEBUG_3(("%s: destroying %s%s client transaction to <"(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 1083, "%s: destroying %s%s client transaction to <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">\n", __func__, (orq->orq_forking || orq->orq_forks ) ? "forked " : "forking", orq->orq_method_name, (orq-> orq_to->a_url)->url_scheme ? (orq->orq_to->a_url) ->url_scheme : "", (orq->orq_to->a_url)->url_type != url_any && (orq->orq_to->a_url)->url_scheme && (orq->orq_to->a_url)->url_scheme[0] ? ":" : "", (orq->orq_to->a_url)->url_root && ((orq ->orq_to->a_url)->url_host || (orq->orq_to->a_url )->url_user) ? "//" : "", (orq->orq_to->a_url)->url_user ? (orq->orq_to->a_url)->url_user : "", (orq->orq_to ->a_url)->url_user && (orq->orq_to->a_url )->url_password ? ":" : "", (orq->orq_to->a_url)-> url_user && (orq->orq_to->a_url)->url_password ? (orq->orq_to->a_url)->url_password : "", (orq-> orq_to->a_url)->url_user && (orq->orq_to-> a_url)->url_host ? "@" : "", (orq->orq_to->a_url)-> url_host ? (orq->orq_to->a_url)->url_host : "", (orq ->orq_to->a_url)->url_host && (orq->orq_to ->a_url)->url_port ? ":" : "", (orq->orq_to->a_url )->url_host && (orq->orq_to->a_url)->url_port ? (orq->orq_to->a_url)->url_port : "", (orq->orq_to ->a_url)->url_root && (orq->orq_to->a_url )->url_path ? "/" : "", (orq->orq_to->a_url)->url_path ? (orq->orq_to->a_url)->url_path : "", (orq->orq_to ->a_url)->url_params ? ";" : "", (orq->orq_to->a_url )->url_params ? (orq->orq_to->a_url)->url_params : "", (orq->orq_to->a_url)->url_headers ? "?" : "", ( orq->orq_to->a_url)->url_headers ? (orq->orq_to-> a_url)->url_headers : "", (orq->orq_to->a_url)->url_fragment ? "#" : "", (orq->orq_to->a_url)->url_fragment ? (orq ->orq_to->a_url)->url_fragment : "")) : (void)0) | ||||||||
1079 | URL_PRINT_FORMAT ">\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 1083, "%s: destroying %s%s client transaction to <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">\n", __func__, (orq->orq_forking || orq->orq_forks ) ? "forked " : "forking", orq->orq_method_name, (orq-> orq_to->a_url)->url_scheme ? (orq->orq_to->a_url) ->url_scheme : "", (orq->orq_to->a_url)->url_type != url_any && (orq->orq_to->a_url)->url_scheme && (orq->orq_to->a_url)->url_scheme[0] ? ":" : "", (orq->orq_to->a_url)->url_root && ((orq ->orq_to->a_url)->url_host || (orq->orq_to->a_url )->url_user) ? "//" : "", (orq->orq_to->a_url)->url_user ? (orq->orq_to->a_url)->url_user : "", (orq->orq_to ->a_url)->url_user && (orq->orq_to->a_url )->url_password ? ":" : "", (orq->orq_to->a_url)-> url_user && (orq->orq_to->a_url)->url_password ? (orq->orq_to->a_url)->url_password : "", (orq-> orq_to->a_url)->url_user && (orq->orq_to-> a_url)->url_host ? "@" : "", (orq->orq_to->a_url)-> url_host ? (orq->orq_to->a_url)->url_host : "", (orq ->orq_to->a_url)->url_host && (orq->orq_to ->a_url)->url_port ? ":" : "", (orq->orq_to->a_url )->url_host && (orq->orq_to->a_url)->url_port ? (orq->orq_to->a_url)->url_port : "", (orq->orq_to ->a_url)->url_root && (orq->orq_to->a_url )->url_path ? "/" : "", (orq->orq_to->a_url)->url_path ? (orq->orq_to->a_url)->url_path : "", (orq->orq_to ->a_url)->url_params ? ";" : "", (orq->orq_to->a_url )->url_params ? (orq->orq_to->a_url)->url_params : "", (orq->orq_to->a_url)->url_headers ? "?" : "", ( orq->orq_to->a_url)->url_headers ? (orq->orq_to-> a_url)->url_headers : "", (orq->orq_to->a_url)->url_fragment ? "#" : "", (orq->orq_to->a_url)->url_fragment ? (orq ->orq_to->a_url)->url_fragment : "")) : (void)0) | ||||||||
1080 | __func__,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 1083, "%s: destroying %s%s client transaction to <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">\n", __func__, (orq->orq_forking || orq->orq_forks ) ? "forked " : "forking", orq->orq_method_name, (orq-> orq_to->a_url)->url_scheme ? (orq->orq_to->a_url) ->url_scheme : "", (orq->orq_to->a_url)->url_type != url_any && (orq->orq_to->a_url)->url_scheme && (orq->orq_to->a_url)->url_scheme[0] ? ":" : "", (orq->orq_to->a_url)->url_root && ((orq ->orq_to->a_url)->url_host || (orq->orq_to->a_url )->url_user) ? "//" : "", (orq->orq_to->a_url)->url_user ? (orq->orq_to->a_url)->url_user : "", (orq->orq_to ->a_url)->url_user && (orq->orq_to->a_url )->url_password ? ":" : "", (orq->orq_to->a_url)-> url_user && (orq->orq_to->a_url)->url_password ? (orq->orq_to->a_url)->url_password : "", (orq-> orq_to->a_url)->url_user && (orq->orq_to-> a_url)->url_host ? "@" : "", (orq->orq_to->a_url)-> url_host ? (orq->orq_to->a_url)->url_host : "", (orq ->orq_to->a_url)->url_host && (orq->orq_to ->a_url)->url_port ? ":" : "", (orq->orq_to->a_url )->url_host && (orq->orq_to->a_url)->url_port ? (orq->orq_to->a_url)->url_port : "", (orq->orq_to ->a_url)->url_root && (orq->orq_to->a_url )->url_path ? "/" : "", (orq->orq_to->a_url)->url_path ? (orq->orq_to->a_url)->url_path : "", (orq->orq_to ->a_url)->url_params ? ";" : "", (orq->orq_to->a_url )->url_params ? (orq->orq_to->a_url)->url_params : "", (orq->orq_to->a_url)->url_headers ? "?" : "", ( orq->orq_to->a_url)->url_headers ? (orq->orq_to-> a_url)->url_headers : "", (orq->orq_to->a_url)->url_fragment ? "#" : "", (orq->orq_to->a_url)->url_fragment ? (orq ->orq_to->a_url)->url_fragment : "")) : (void)0) | ||||||||
1081 | (orq->orq_forking || orq->orq_forks) ? "forked " : "forking",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 1083, "%s: destroying %s%s client transaction to <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">\n", __func__, (orq->orq_forking || orq->orq_forks ) ? "forked " : "forking", orq->orq_method_name, (orq-> orq_to->a_url)->url_scheme ? (orq->orq_to->a_url) ->url_scheme : "", (orq->orq_to->a_url)->url_type != url_any && (orq->orq_to->a_url)->url_scheme && (orq->orq_to->a_url)->url_scheme[0] ? ":" : "", (orq->orq_to->a_url)->url_root && ((orq ->orq_to->a_url)->url_host || (orq->orq_to->a_url )->url_user) ? "//" : "", (orq->orq_to->a_url)->url_user ? (orq->orq_to->a_url)->url_user : "", (orq->orq_to ->a_url)->url_user && (orq->orq_to->a_url )->url_password ? ":" : "", (orq->orq_to->a_url)-> url_user && (orq->orq_to->a_url)->url_password ? (orq->orq_to->a_url)->url_password : "", (orq-> orq_to->a_url)->url_user && (orq->orq_to-> a_url)->url_host ? "@" : "", (orq->orq_to->a_url)-> url_host ? (orq->orq_to->a_url)->url_host : "", (orq ->orq_to->a_url)->url_host && (orq->orq_to ->a_url)->url_port ? ":" : "", (orq->orq_to->a_url )->url_host && (orq->orq_to->a_url)->url_port ? (orq->orq_to->a_url)->url_port : "", (orq->orq_to ->a_url)->url_root && (orq->orq_to->a_url )->url_path ? "/" : "", (orq->orq_to->a_url)->url_path ? (orq->orq_to->a_url)->url_path : "", (orq->orq_to ->a_url)->url_params ? ";" : "", (orq->orq_to->a_url )->url_params ? (orq->orq_to->a_url)->url_params : "", (orq->orq_to->a_url)->url_headers ? "?" : "", ( orq->orq_to->a_url)->url_headers ? (orq->orq_to-> a_url)->url_headers : "", (orq->orq_to->a_url)->url_fragment ? "#" : "", (orq->orq_to->a_url)->url_fragment ? (orq ->orq_to->a_url)->url_fragment : "")) : (void)0) | ||||||||
1082 | orq->orq_method_name,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 1083, "%s: destroying %s%s client transaction to <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">\n", __func__, (orq->orq_forking || orq->orq_forks ) ? "forked " : "forking", orq->orq_method_name, (orq-> orq_to->a_url)->url_scheme ? (orq->orq_to->a_url) ->url_scheme : "", (orq->orq_to->a_url)->url_type != url_any && (orq->orq_to->a_url)->url_scheme && (orq->orq_to->a_url)->url_scheme[0] ? ":" : "", (orq->orq_to->a_url)->url_root && ((orq ->orq_to->a_url)->url_host || (orq->orq_to->a_url )->url_user) ? "//" : "", (orq->orq_to->a_url)->url_user ? (orq->orq_to->a_url)->url_user : "", (orq->orq_to ->a_url)->url_user && (orq->orq_to->a_url )->url_password ? ":" : "", (orq->orq_to->a_url)-> url_user && (orq->orq_to->a_url)->url_password ? (orq->orq_to->a_url)->url_password : "", (orq-> orq_to->a_url)->url_user && (orq->orq_to-> a_url)->url_host ? "@" : "", (orq->orq_to->a_url)-> url_host ? (orq->orq_to->a_url)->url_host : "", (orq ->orq_to->a_url)->url_host && (orq->orq_to ->a_url)->url_port ? ":" : "", (orq->orq_to->a_url )->url_host && (orq->orq_to->a_url)->url_port ? (orq->orq_to->a_url)->url_port : "", (orq->orq_to ->a_url)->url_root && (orq->orq_to->a_url )->url_path ? "/" : "", (orq->orq_to->a_url)->url_path ? (orq->orq_to->a_url)->url_path : "", (orq->orq_to ->a_url)->url_params ? ";" : "", (orq->orq_to->a_url )->url_params ? (orq->orq_to->a_url)->url_params : "", (orq->orq_to->a_url)->url_headers ? "?" : "", ( orq->orq_to->a_url)->url_headers ? (orq->orq_to-> a_url)->url_headers : "", (orq->orq_to->a_url)->url_fragment ? "#" : "", (orq->orq_to->a_url)->url_fragment ? (orq ->orq_to->a_url)->url_fragment : "")) : (void)0) | ||||||||
1083 | URL_PRINT_ARGS(orq->orq_to->a_url)))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 1083, "%s: destroying %s%s client transaction to <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">\n", __func__, (orq->orq_forking || orq->orq_forks ) ? "forked " : "forking", orq->orq_method_name, (orq-> orq_to->a_url)->url_scheme ? (orq->orq_to->a_url) ->url_scheme : "", (orq->orq_to->a_url)->url_type != url_any && (orq->orq_to->a_url)->url_scheme && (orq->orq_to->a_url)->url_scheme[0] ? ":" : "", (orq->orq_to->a_url)->url_root && ((orq ->orq_to->a_url)->url_host || (orq->orq_to->a_url )->url_user) ? "//" : "", (orq->orq_to->a_url)->url_user ? (orq->orq_to->a_url)->url_user : "", (orq->orq_to ->a_url)->url_user && (orq->orq_to->a_url )->url_password ? ":" : "", (orq->orq_to->a_url)-> url_user && (orq->orq_to->a_url)->url_password ? (orq->orq_to->a_url)->url_password : "", (orq-> orq_to->a_url)->url_user && (orq->orq_to-> a_url)->url_host ? "@" : "", (orq->orq_to->a_url)-> url_host ? (orq->orq_to->a_url)->url_host : "", (orq ->orq_to->a_url)->url_host && (orq->orq_to ->a_url)->url_port ? ":" : "", (orq->orq_to->a_url )->url_host && (orq->orq_to->a_url)->url_port ? (orq->orq_to->a_url)->url_port : "", (orq->orq_to ->a_url)->url_root && (orq->orq_to->a_url )->url_path ? "/" : "", (orq->orq_to->a_url)->url_path ? (orq->orq_to->a_url)->url_path : "", (orq->orq_to ->a_url)->url_params ? ";" : "", (orq->orq_to->a_url )->url_params ? (orq->orq_to->a_url)->url_params : "", (orq->orq_to->a_url)->url_headers ? "?" : "", ( orq->orq_to->a_url)->url_headers ? (orq->orq_to-> a_url)->url_headers : "", (orq->orq_to->a_url)->url_fragment ? "#" : "", (orq->orq_to->a_url)->url_fragment ? (orq ->orq_to->a_url)->url_fragment : "")) : (void)0); | ||||||||
1084 | |||||||||
1085 | orq->orq_forks = NULL((void*)0), orq->orq_forking = NULL((void*)0); | ||||||||
1086 | outgoing_free(orq); | ||||||||
1087 | } | ||||||||
1088 | |||||||||
1089 | su_timer_destroy(agent->sa_timer), agent->sa_timer = NULL((void*)0); | ||||||||
1090 | |||||||||
1091 | # if HAVE_SOFIA_SRESOLV1 | ||||||||
1092 | sres_resolver_destroy(agent->sa_resolver), agent->sa_resolver = NULL((void*)0); | ||||||||
1093 | # endif | ||||||||
1094 | |||||||||
1095 | tport_destroy(agent->sa_tports), agent->sa_tports = NULL((void*)0); | ||||||||
1096 | |||||||||
1097 | agent_kill_terminator(agent); | ||||||||
1098 | |||||||||
1099 | su_home_unref(agent->sa_home); | ||||||||
1100 | } | ||||||||
1101 | } | ||||||||
1102 | |||||||||
1103 | void nta_agent_resolver_clean_cache(nta_agent_t *agent) | ||||||||
1104 | { | ||||||||
1105 | #if HAVE_SOFIA_SRESOLV1 | ||||||||
1106 | if (agent && agent->sa_resolver) { | ||||||||
1107 | sres_resolver_clean_cache(agent->sa_resolver); | ||||||||
1108 | } | ||||||||
1109 | #endif | ||||||||
1110 | } | ||||||||
1111 | |||||||||
1112 | /** Return agent context. */ | ||||||||
1113 | nta_agent_magic_t *nta_agent_magic(nta_agent_t const *agent) | ||||||||
1114 | { | ||||||||
1115 | return agent ? agent->sa_magic : NULL((void*)0); | ||||||||
1116 | } | ||||||||
1117 | |||||||||
1118 | /** Return @Contact header. | ||||||||
1119 | * | ||||||||
1120 | * Get a @Contact header, which can be used to reach @a agent. | ||||||||
1121 | * | ||||||||
1122 | * @param agent NTA agent object | ||||||||
1123 | * | ||||||||
1124 | * User agents can insert the @Contact header in the outgoing REGISTER, | ||||||||
1125 | * INVITE, and ACK requests and replies to incoming INVITE and OPTIONS | ||||||||
1126 | * transactions. | ||||||||
1127 | * | ||||||||
1128 | * Proxies can use the @Contact header to create appropriate @RecordRoute | ||||||||
1129 | * headers: | ||||||||
1130 | * @code | ||||||||
1131 | * r_r = sip_record_route_create(msg_home(msg), | ||||||||
1132 | * sip->sip_request->rq_url, | ||||||||
1133 | * contact->m_url); | ||||||||
1134 | * @endcode | ||||||||
1135 | * | ||||||||
1136 | * @return A sip_contact_t object corresponding to the @a agent. | ||||||||
1137 | */ | ||||||||
1138 | sip_contact_t *nta_agent_contact(nta_agent_t const *agent) | ||||||||
1139 | { | ||||||||
1140 | return agent ? agent->sa_contact : NULL((void*)0); | ||||||||
1141 | } | ||||||||
1142 | |||||||||
1143 | /** Return a list of @Via headers. | ||||||||
1144 | * | ||||||||
1145 | * Get @Via headers for all activated transport. | ||||||||
1146 | * | ||||||||
1147 | * @param agent NTA agent object | ||||||||
1148 | * | ||||||||
1149 | * @return A list of #sip_via_t objects used by the @a agent. | ||||||||
1150 | */ | ||||||||
1151 | sip_via_t *nta_agent_via(nta_agent_t const *agent) | ||||||||
1152 | { | ||||||||
1153 | return agent ? agent->sa_vias : NULL((void*)0); | ||||||||
1154 | } | ||||||||
1155 | |||||||||
1156 | /** Return a list of public (UPnP, STUN) @Via headers. | ||||||||
1157 | * | ||||||||
1158 | * Get public @Via headers for all activated transports. | ||||||||
1159 | * | ||||||||
1160 | * @param agent NTA agent object | ||||||||
1161 | * | ||||||||
1162 | * @return A list of #sip_via_t objects used by the @a agent. | ||||||||
1163 | */ | ||||||||
1164 | sip_via_t *nta_agent_public_via(nta_agent_t const *agent) | ||||||||
1165 | { | ||||||||
1166 | return agent ? agent->sa_public_vias : NULL((void*)0); | ||||||||
1167 | } | ||||||||
1168 | |||||||||
1169 | /** Match a @Via header @a v with @Via headers in @a agent. | ||||||||
1170 | * | ||||||||
1171 | */ | ||||||||
1172 | static | ||||||||
1173 | sip_via_t *agent_has_via(nta_agent_t const *agent, sip_via_t const *via) | ||||||||
1174 | { | ||||||||
1175 | sip_via_t const *v; | ||||||||
1176 | |||||||||
1177 | for (v = agent->sa_public_vias; v; v = v->v_next) { | ||||||||
1178 | if (!su_casematch(via->v_host, v->v_host)) | ||||||||
1179 | continue; | ||||||||
1180 | if (!su_strmatch(via->v_port, v->v_port)) | ||||||||
1181 | continue; | ||||||||
1182 | if (!su_casematch(via->v_protocol, v->v_protocol)) | ||||||||
1183 | continue; | ||||||||
1184 | return (sip_via_t *)v; | ||||||||
1185 | } | ||||||||
1186 | |||||||||
1187 | for (v = agent->sa_vias; v; v = v->v_next) { | ||||||||
1188 | if (!su_casematch(via->v_host, v->v_host)) | ||||||||
1189 | continue; | ||||||||
1190 | if (!su_strmatch(via->v_port, v->v_port)) | ||||||||
1191 | continue; | ||||||||
1192 | if (!su_casematch(via->v_protocol, v->v_protocol)) | ||||||||
1193 | continue; | ||||||||
1194 | return (sip_via_t *)v; | ||||||||
1195 | } | ||||||||
1196 | |||||||||
1197 | return NULL((void*)0); | ||||||||
1198 | } | ||||||||
1199 | |||||||||
1200 | /** Return @UserAgent header. | ||||||||
1201 | * | ||||||||
1202 | * Get @UserAgent information with NTA version. | ||||||||
1203 | * | ||||||||
1204 | * @param agent NTA agent object (may be NULL) | ||||||||
1205 | * | ||||||||
1206 | * @return A string containing the @a agent version. | ||||||||
1207 | */ | ||||||||
1208 | char const *nta_agent_version(nta_agent_t const *agent) | ||||||||
1209 | { | ||||||||
1210 | return "nta" "/" VERSION"1.13.15"; | ||||||||
1211 | } | ||||||||
1212 | |||||||||
1213 | /** Initialize default tag */ | ||||||||
1214 | static int agent_tag_init(nta_agent_t *self) | ||||||||
1215 | { | ||||||||
1216 | sip_contact_t *m = self->sa_contact; | ||||||||
1217 | uint32_t hash = su_random(); | ||||||||
1218 | |||||||||
1219 | if (m) { | ||||||||
1220 | if (m->m_url->url_user) | ||||||||
1221 | hash = 914715421U * hash + msg_hash_string(m->m_url->url_user); | ||||||||
1222 | if (m->m_url->url_host) | ||||||||
1223 | hash = 914715421U * hash + msg_hash_string(m->m_url->url_host); | ||||||||
1224 | if (m->m_url->url_port) | ||||||||
1225 | hash = 914715421U * hash + msg_hash_string(m->m_url->url_port); | ||||||||
1226 | if (m->m_url->url_params) | ||||||||
1227 | hash = 914715421U * hash + msg_hash_string(m->m_url->url_params); | ||||||||
1228 | } | ||||||||
1229 | |||||||||
1230 | if (hash == 0) | ||||||||
1231 | hash = 914715421U; | ||||||||
1232 | |||||||||
1233 | self->sa_branch = NTA_BRANCH_PRIME(uint64_t)(0xB9591D1C361C6521ULL) * (uint64_t)su_nanotime(NULL((void*)0)); | ||||||||
1234 | self->sa_branch *= hash; | ||||||||
1235 | |||||||||
1236 | self->sa_tags = NTA_TAG_PRIME(uint64_t)(0xB9591D1C361C6521ULL) * self->sa_branch; | ||||||||
1237 | |||||||||
1238 | return 0; | ||||||||
1239 | } | ||||||||
1240 | |||||||||
1241 | /** Initialize agent timer. */ | ||||||||
1242 | static | ||||||||
1243 | int agent_timer_init(nta_agent_t *agent) | ||||||||
1244 | { | ||||||||
1245 | agent->sa_timer = su_timer_create(su_root_task(agent->sa_root), | ||||||||
1246 | NTA_SIP_T1 / 8); | ||||||||
1247 | #if 0 | ||||||||
1248 | return su_timer_set(agent->sa_timer, | ||||||||
1249 | agent_timer, | ||||||||
1250 | agent); | ||||||||
1251 | #endif | ||||||||
1252 | return -(agent->sa_timer == NULL((void*)0)); | ||||||||
1253 | } | ||||||||
1254 | |||||||||
1255 | /** | ||||||||
1256 | * Agent timer routine. | ||||||||
1257 | */ | ||||||||
1258 | static | ||||||||
1259 | void agent_timer(su_root_magic_t *rm, su_timer_t *timer, nta_agent_t *agent) | ||||||||
1260 | { | ||||||||
1261 | su_time_t stamp = su_now(); | ||||||||
1262 | uint32_t now = su_time_ms(stamp), next, latest; | ||||||||
1263 | |||||||||
1264 | now += now == 0; | ||||||||
1265 | |||||||||
1266 | agent->sa_next = 0; | ||||||||
1267 | |||||||||
1268 | agent->sa_in_timer = 1; | ||||||||
1269 | |||||||||
1270 | |||||||||
1271 | _nta_outgoing_timer(agent); | ||||||||
1272 | _nta_incoming_timer(agent); | ||||||||
1273 | |||||||||
1274 | agent->sa_in_timer = 0; | ||||||||
1275 | |||||||||
1276 | /* Calculate next timeout */ | ||||||||
1277 | next = latest = now + NTA_TIME_MAX + 1; | ||||||||
1278 | |||||||||
1279 | #define NEXT_TIMEOUT(next, p, f, now) \ | ||||||||
1280 | (void)(p && (int32_t)(p->f - (next)) < 0 && \ | ||||||||
1281 | ((next) = ((int32_t)(p->f - (now)) > 0 ? p->f : (now)))) | ||||||||
1282 | |||||||||
1283 | NEXT_TIMEOUT(next, agent->sa_out.re_list, orq_retry, now); | ||||||||
1284 | NEXT_TIMEOUT(next, agent->sa_out.inv_completed->q_head, orq_timeout, now); | ||||||||
1285 | NEXT_TIMEOUT(next, agent->sa_out.completed->q_head, orq_timeout, now); | ||||||||
1286 | NEXT_TIMEOUT(next, agent->sa_out.inv_calling->q_head, orq_timeout, now); | ||||||||
1287 | if (agent->sa_out.inv_proceeding->q_timeout) | ||||||||
1288 | NEXT_TIMEOUT(next, agent->sa_out.inv_proceeding->q_head, orq_timeout, now); | ||||||||
1289 | NEXT_TIMEOUT(next, agent->sa_out.trying->q_head, orq_timeout, now); | ||||||||
1290 | |||||||||
1291 | NEXT_TIMEOUT(next, agent->sa_in.preliminary->q_head, irq_timeout, now); | ||||||||
1292 | NEXT_TIMEOUT(next, agent->sa_in.inv_completed->q_head, irq_timeout, now); | ||||||||
1293 | NEXT_TIMEOUT(next, agent->sa_in.inv_confirmed->q_head, irq_timeout, now); | ||||||||
1294 | NEXT_TIMEOUT(next, agent->sa_in.completed->q_head, irq_timeout, now); | ||||||||
1295 | NEXT_TIMEOUT(next, agent->sa_in.re_list, irq_retry, now); | ||||||||
1296 | |||||||||
1297 | if (agent->sa_next) | ||||||||
1298 | NEXT_TIMEOUT(next, agent, sa_next, now); | ||||||||
1299 | |||||||||
1300 | #undef NEXT_TIMEOUT | ||||||||
1301 | |||||||||
1302 | if (next == latest) { | ||||||||
1303 | /* Do not set timer? */ | ||||||||
1304 | /* check it there are still things queued, if there are, that means everything scheduled is > 15 days in the future */ | ||||||||
1305 | /* in this case, we had a large time shift, we should schedule for 15 days in the future (which is probably still before now) */ | ||||||||
1306 | /* and this should sort itself out on the next run through */ | ||||||||
1307 | if ( !agent->sa_out.completed->q_head && !agent->sa_out.trying->q_head && !agent->sa_out.inv_calling->q_head && | ||||||||
1308 | !agent->sa_out.re_list && !agent->sa_in.inv_confirmed->q_head && !agent->sa_in.preliminary->q_head && | ||||||||
1309 | !agent->sa_in.completed->q_head && !agent->sa_in.inv_completed->q_head && !agent->sa_in.re_list ) { | ||||||||
1310 | 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__ , 1310, "nta: timer not set\n" "%s", "")) : (void)0); | ||||||||
1311 | return; | ||||||||
1312 | } | ||||||||
1313 | } | ||||||||
1314 | |||||||||
1315 | if (next == now) if (++next == 0) ++next; | ||||||||
1316 | |||||||||
1317 | 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__ , 1317, "nta: timer %s to %ld ms\n", "set next", (long)(next - now))) : (void)0); | ||||||||
1318 | |||||||||
1319 | agent->sa_next = next; | ||||||||
1320 | |||||||||
1321 | su_timer_set_at(timer, agent_timer, agent, su_time_add(stamp, next - now)); | ||||||||
1322 | } | ||||||||
1323 | |||||||||
1324 | /** Add uin32_t milliseconds to the time. */ | ||||||||
1325 | static su_time_t add_milliseconds(su_time_t t0, uint32_t ms) | ||||||||
1326 | { | ||||||||
1327 | unsigned long sec = ms / 1000, usec = (ms % 1000) * 1000; | ||||||||
1328 | |||||||||
1329 | t0.tv_usec += usec; | ||||||||
1330 | t0.tv_sec += sec; | ||||||||
1331 | |||||||||
1332 | if (t0.tv_usec >= 1000000) { | ||||||||
1333 | t0.tv_sec += 1; | ||||||||
1334 | t0.tv_usec -= 1000000; | ||||||||
1335 | } | ||||||||
1336 | |||||||||
1337 | return t0; | ||||||||
1338 | } | ||||||||
1339 | |||||||||
1340 | /** Calculate nonzero value for timeout. | ||||||||
1341 | * | ||||||||
1342 | * Sets or adjusts agent timer when needed. | ||||||||
1343 | * | ||||||||
1344 | * @retval 0 if offset is 0 | ||||||||
1345 | * @retval timeout (millisecond counter) otherwise | ||||||||
1346 | */ | ||||||||
1347 | static | ||||||||
1348 | uint32_t set_timeout(nta_agent_t *agent, uint32_t offset) | ||||||||
1349 | { | ||||||||
1350 | su_time_t now; | ||||||||
1351 | uint32_t next, ms; | ||||||||
1352 | |||||||||
1353 | if (offset == 0) | ||||||||
1354 | return 0; | ||||||||
1355 | |||||||||
1356 | now = su_now(); | ||||||||
1357 | ms = su_time_ms(now); | ||||||||
1358 | |||||||||
1359 | next = ms + offset; | ||||||||
1360 | |||||||||
1361 | if (next == 0) next = 1; | ||||||||
1362 | |||||||||
1363 | if (agent->sa_in_timer) /* Currently executing timer */ | ||||||||
1364 | return next; | ||||||||
1365 | |||||||||
1366 | if (agent->sa_next == 0 || (int32_t)(agent->sa_next - next - 5L) > 0) { | ||||||||
1367 | /* Set timer */ | ||||||||
1368 | if (agent->sa_next) | ||||||||
1369 | 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__ , 1369, "nta: timer %s to %ld ms\n", "shortened", (long)offset )) : (void)0); | ||||||||
1370 | else | ||||||||
1371 | 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__ , 1371, "nta: timer %s to %ld ms\n", "set", (long)offset)) : ( void)0); | ||||||||
1372 | |||||||||
1373 | su_timer_set_at(agent->sa_timer, agent_timer, agent, | ||||||||
1374 | add_milliseconds(now, offset)); | ||||||||
1375 | agent->sa_next = next; | ||||||||
1376 | } | ||||||||
1377 | |||||||||
1378 | return next; | ||||||||
1379 | } | ||||||||
1380 | |||||||||
1381 | |||||||||
1382 | /** Return current timeval. */ | ||||||||
1383 | static | ||||||||
1384 | su_time_t agent_now(nta_agent_t const *agent) | ||||||||
1385 | { | ||||||||
1386 | return su_now(); | ||||||||
1387 | } | ||||||||
1388 | |||||||||
1389 | |||||||||
1390 | /** Launch transaction terminator task */ | ||||||||
1391 | static | ||||||||
1392 | int agent_launch_terminator(nta_agent_t *agent) | ||||||||
1393 | { | ||||||||
1394 | #ifdef TPTAG_THRPSIZE | ||||||||
1395 | if (agent->sa_tport_threadpool) { | ||||||||
1396 | su_home_threadsafe(agent->sa_home); | ||||||||
1397 | return su_clone_start(agent->sa_root, | ||||||||
1398 | agent->sa_terminator, | ||||||||
1399 | NULL((void*)0), | ||||||||
1400 | NULL((void*)0), | ||||||||
1401 | NULL((void*)0)); | ||||||||
1402 | } | ||||||||
1403 | #endif | ||||||||
1404 | return -1; | ||||||||
1405 | } | ||||||||
1406 | |||||||||
1407 | /** Kill transaction terminator task */ | ||||||||
1408 | static | ||||||||
1409 | void agent_kill_terminator(nta_agent_t *agent) | ||||||||
1410 | { | ||||||||
1411 | su_clone_wait(agent->sa_root, agent->sa_terminator); | ||||||||
1412 | } | ||||||||
1413 | |||||||||
1414 | |||||||||
1415 | /**Set NTA Parameters. | ||||||||
1416 | * | ||||||||
1417 | * The nta_agent_set_params() function sets the stack parameters. The | ||||||||
1418 | * parameters determine the way NTA handles the retransmissions, how long | ||||||||
1419 | * NTA keeps transactions alive, does NTA apply proxy or user-agent logic to | ||||||||
1420 | * INVITE transactions, or how the @Via headers are generated. | ||||||||
1421 | * | ||||||||
1422 | * @note | ||||||||
1423 | * Setting the parameters NTATAG_MAXSIZE(), NTATAG_UDP_MTU(), NTATAG_MAX_PROCEEDING(), | ||||||||
1424 | * NTATAG_SIP_T1X64(), NTATAG_SIP_T1(), NTATAG_SIP_T2(), NTATAG_SIP_T4() to | ||||||||
1425 | * 0 selects the default value. | ||||||||
1426 | * | ||||||||
1427 | * @TAGS | ||||||||
1428 | * NTATAG_ALIASES(), | ||||||||
1429 | * NTATAG_BAD_REQ_MASK(), NTATAG_BAD_RESP_MASK(), NTATAG_BLACKLIST(), | ||||||||
1430 | * NTATAG_CANCEL_2543(), NTATAG_CANCEL_487(), NTATAG_CLIENT_RPORT(), | ||||||||
1431 | * NTATAG_DEBUG_DROP_PROB(), NTATAG_DEFAULT_PROXY(), | ||||||||
1432 | * NTATAG_EXTRA_100(), NTATAG_GRAYLIST(), | ||||||||
1433 | * NTATAG_MAXSIZE(), NTATAG_MAX_FORWARDS(), NTATAG_MERGE_482(), NTATAG_MCLASS() | ||||||||
1434 | * NTATAG_PASS_100(), NTATAG_PASS_408(), NTATAG_PRELOAD(), NTATAG_PROGRESS(), | ||||||||
1435 | * NTATAG_REL100(), | ||||||||
1436 | * NTATAG_SERVER_RPORT(), | ||||||||
1437 | * NTATAG_SIPFLAGS(), | ||||||||
1438 | * NTATAG_SIP_T1X64(), NTATAG_SIP_T1(), NTATAG_SIP_T2(), NTATAG_SIP_T4(), | ||||||||
1439 | * NTATAG_STATELESS(), | ||||||||
1440 | * NTATAG_TAG_3261(), NTATAG_TCP_RPORT(), NTATAG_TIMEOUT_408(), | ||||||||
1441 | * NTATAG_TLS_RPORT(), NTATAG_TLS_ORQ_CONNECT_TIMEOUT(), | ||||||||
1442 | * NTATAG_TIMER_C(), NTATAG_MAX_PROCEEDING(), | ||||||||
1443 | * NTATAG_UA(), NTATAG_UDP_MTU(), NTATAG_USER_VIA(), | ||||||||
1444 | * NTATAG_USE_NAPTR(), NTATAG_USE_SRV() and NTATAG_USE_TIMESTAMP(). | ||||||||
1445 | * | ||||||||
1446 | * @note The value from following tags are stored, but they currently do nothing: | ||||||||
1447 | * NTATAG_SIGCOMP_ALGORITHM(), NTATAG_SIGCOMP_OPTIONS(), NTATAG_SMIME() | ||||||||
1448 | */ | ||||||||
1449 | int nta_agent_set_params(nta_agent_t *agent, | ||||||||
1450 | tag_type_t tag, tag_value_t value, ...) | ||||||||
1451 | { | ||||||||
1452 | int retval; | ||||||||
1453 | |||||||||
1454 | if (agent) { | ||||||||
1455 | ta_list ta; | ||||||||
1456 | 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); | ||||||||
1457 | retval = agent_set_params(agent, ta_args(ta)(ta).tl); | ||||||||
1458 | 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)); | ||||||||
1459 | } else { | ||||||||
1460 | su_seterrno(EINVAL22); | ||||||||
1461 | retval = -1; | ||||||||
1462 | } | ||||||||
1463 | |||||||||
1464 | return retval; | ||||||||
1465 | } | ||||||||
1466 | |||||||||
1467 | /** Internal function for setting tags */ | ||||||||
1468 | static | ||||||||
1469 | int agent_set_params(nta_agent_t *agent, tagi_t *tags) | ||||||||
1470 | { | ||||||||
1471 | int n, nC, m; | ||||||||
1472 | unsigned bad_req_mask = agent->sa_bad_req_mask; | ||||||||
1473 | unsigned bad_resp_mask = agent->sa_bad_resp_mask; | ||||||||
1474 | usize_t maxsize = agent->sa_maxsize; | ||||||||
1475 | usize_t max_proceeding = agent->sa_max_proceeding; | ||||||||
1476 | usize_t max_recv_requests_per_second = agent->sa_max_recv_requests_per_second; | ||||||||
1477 | unsigned max_forwards = agent->sa_max_forwards->mf_count; | ||||||||
1478 | unsigned udp_mtu = agent->sa_udp_mtu; | ||||||||
1479 | unsigned sip_t1 = agent->sa_t1; | ||||||||
1480 | unsigned sip_t2 = agent->sa_t2; | ||||||||
1481 | unsigned sip_t4 = agent->sa_t4; | ||||||||
1482 | unsigned sip_t1x64 = agent->sa_t1x64; | ||||||||
1483 | unsigned tls_orq_connect_timeout = agent->sa_tls_orq_connect_timeout; | ||||||||
1484 | unsigned timer_c = agent->sa_timer_c; | ||||||||
1485 | unsigned timer_d = 32000; | ||||||||
1486 | unsigned graylist = agent->sa_graylist; | ||||||||
1487 | unsigned blacklist = agent->sa_blacklist; | ||||||||
1488 | int ua = agent->sa_is_a_uas; | ||||||||
1489 | unsigned progress = agent->sa_progress; | ||||||||
1490 | int stateless = agent->sa_is_stateless; | ||||||||
1491 | unsigned drop_prob = agent->sa_drop_prob; | ||||||||
1492 | int user_via = agent->sa_user_via; | ||||||||
1493 | int extra_100 = agent->sa_extra_100; | ||||||||
1494 | int pass_100 = agent->sa_pass_100; | ||||||||
1495 | int timeout_408 = agent->sa_timeout_408; | ||||||||
1496 | int pass_408 = agent->sa_pass_408; | ||||||||
1497 | int merge_482 = agent->sa_merge_482; | ||||||||
1498 | int cancel_2543 = agent->sa_cancel_2543; | ||||||||
1499 | int cancel_487 = agent->sa_cancel_487; | ||||||||
1500 | int invite_100rel = agent->sa_invite_100rel; | ||||||||
1501 | int use_timestamp = agent->sa_timestamp; | ||||||||
1502 | int use_naptr = agent->sa_use_naptr; | ||||||||
1503 | int use_srv = agent->sa_use_srv; | ||||||||
1504 | int srv_503 = agent->sa_srv_503; | ||||||||
1505 | void *smime = agent->sa_smime; | ||||||||
1506 | uint32_t flags = agent->sa_flags; | ||||||||
1507 | int rport = agent->sa_rport; | ||||||||
1508 | int server_rport = agent->sa_server_rport; | ||||||||
1509 | int tcp_rport = agent->sa_tcp_rport; | ||||||||
1510 | int tls_rport = agent->sa_tls_rport; | ||||||||
1511 | unsigned preload = agent->sa_preload; | ||||||||
1512 | unsigned threadpool = agent->sa_tport_threadpool; | ||||||||
1513 | char const *sigcomp = agent->sa_sigcomp_options; | ||||||||
1514 | char const *algorithm = NONE((void *)-1); | ||||||||
1515 | msg_mclass_t const *mclass = NONE((void *)-1); | ||||||||
1516 | sip_contact_t const *aliases = NONE((void *)-1); | ||||||||
1517 | url_string_t const *proxy = NONE((void *)-1); | ||||||||
1518 | tport_t *tport; | ||||||||
1519 | |||||||||
1520 | su_home_t *home = agent->sa_home; | ||||||||
1521 | |||||||||
1522 | n = tl_gets(tags, | ||||||||
1523 | NTATAG_ALIASES_REF(aliases)ntatag_aliases_ref, siptag_contact_vr(&(aliases)), | ||||||||
1524 | NTATAG_BAD_REQ_MASK_REF(bad_req_mask)ntatag_bad_req_mask_ref, tag_uint_vr(&(bad_req_mask)), | ||||||||
1525 | NTATAG_BAD_RESP_MASK_REF(bad_resp_mask)ntatag_bad_resp_mask_ref, tag_uint_vr(&(bad_resp_mask)), | ||||||||
1526 | NTATAG_BLACKLIST_REF(blacklist)ntatag_blacklist_ref, tag_uint_vr(&(blacklist)), | ||||||||
1527 | NTATAG_CANCEL_2543_REF(cancel_2543)ntatag_cancel_2543_ref, tag_bool_vr(&(cancel_2543)), | ||||||||
1528 | NTATAG_CANCEL_487_REF(cancel_487)ntatag_cancel_487_ref, tag_bool_vr(&(cancel_487)), | ||||||||
1529 | NTATAG_DEBUG_DROP_PROB_REF(drop_prob)ntatag_debug_drop_prob_ref, tag_uint_vr(&(drop_prob)), | ||||||||
1530 | NTATAG_DEFAULT_PROXY_REF(proxy)ntatag_default_proxy_ref, urltag_url_vr(&(proxy)), | ||||||||
1531 | NTATAG_EXTRA_100_REF(extra_100)ntatag_extra_100_ref, tag_bool_vr(&(extra_100)), | ||||||||
1532 | NTATAG_GRAYLIST_REF(graylist)ntatag_graylist_ref, tag_uint_vr(&(graylist)), | ||||||||
1533 | NTATAG_MAXSIZE_REF(maxsize)ntatag_maxsize_ref, tag_usize_vr(&(maxsize)), | ||||||||
1534 | NTATAG_MAX_PROCEEDING_REF(max_proceeding)ntatag_max_proceeding_ref, tag_usize_vr(&(max_proceeding) ), | ||||||||
1535 | NTATAG_MAX_RECV_REQUESTS_PER_SECOND_REF(max_recv_requests_per_second)ntatag_max_recv_requests_per_second_ref, tag_usize_vr(&(max_recv_requests_per_second )), | ||||||||
1536 | NTATAG_MAX_FORWARDS_REF(max_forwards)ntatag_max_forwards_ref, tag_uint_vr(&(max_forwards)), | ||||||||
1537 | NTATAG_MCLASS_REF(mclass)ntatag_mclass_ref, tag_cptr_vr(&(mclass), (mclass)), | ||||||||
1538 | NTATAG_MERGE_482_REF(merge_482)ntatag_merge_482_ref, tag_bool_vr(&(merge_482)), | ||||||||
1539 | NTATAG_PASS_100_REF(pass_100)ntatag_pass_100_ref, tag_bool_vr(&(pass_100)), | ||||||||
1540 | NTATAG_PASS_408_REF(pass_408)ntatag_pass_408_ref, tag_bool_vr(&(pass_408)), | ||||||||
1541 | NTATAG_PRELOAD_REF(preload)ntatag_preload_ref, tag_uint_vr(&(preload)), | ||||||||
1542 | NTATAG_PROGRESS_REF(progress)ntatag_progress_ref, tag_uint_vr(&(progress)), | ||||||||
1543 | NTATAG_REL100_REF(invite_100rel)ntatag_rel100_ref, tag_bool_vr(&(invite_100rel)), | ||||||||
1544 | NTATAG_RPORT_REF(rport)ntatag_client_rport_ref, tag_bool_vr(&(rport)), | ||||||||
1545 | NTATAG_SERVER_RPORT_REF(server_rport)ntatag_server_rport_ref, tag_int_vr(&(server_rport)), | ||||||||
1546 | NTATAG_SIGCOMP_ALGORITHM_REF(algorithm)ntatag_sigcomp_algorithm_ref, tag_str_vr(&(algorithm)), | ||||||||
1547 | NTATAG_SIGCOMP_OPTIONS_REF(sigcomp)ntatag_sigcomp_options_ref, tag_str_vr(&(sigcomp)), | ||||||||
1548 | NTATAG_SIPFLAGS_REF(flags)ntatag_sipflags_ref, tag_uint_vr(&(flags)), | ||||||||
1549 | NTATAG_SIP_T1X64_REF(sip_t1x64)ntatag_sip_t1x64_ref, tag_uint_vr(&(sip_t1x64)), | ||||||||
1550 | NTATAG_SIP_T1_REF(sip_t1)ntatag_sip_t1_ref, tag_uint_vr(&(sip_t1)), | ||||||||
1551 | NTATAG_SIP_T2_REF(sip_t2)ntatag_sip_t2_ref, tag_uint_vr(&(sip_t2)), | ||||||||
1552 | NTATAG_SIP_T4_REF(sip_t4)ntatag_sip_t4_ref, tag_uint_vr(&(sip_t4)), | ||||||||
1553 | #if HAVE_SOFIA_SMIME0 | ||||||||
1554 | NTATAG_SMIME_REF(smime)ntatag_smime_ref, tag_ptr_vr(&(smime), (smime)), | ||||||||
1555 | #endif | ||||||||
1556 | NTATAG_STATELESS_REF(stateless)ntatag_stateless_ref, tag_bool_vr(&(stateless)), | ||||||||
1557 | NTATAG_TCP_RPORT_REF(tcp_rport)ntatag_tcp_rport_ref, tag_bool_vr(&(tcp_rport)), | ||||||||
1558 | NTATAG_TLS_RPORT_REF(tls_rport)ntatag_tls_rport_ref, tag_bool_vr(&(tls_rport)), | ||||||||
1559 | NTATAG_TLS_ORQ_CONNECT_TIMEOUT_REF(tls_orq_connect_timeout)ntatag_tls_orq_connect_timeout_ref, tag_uint_vr(&(tls_orq_connect_timeout )), | ||||||||
1560 | NTATAG_TIMEOUT_408_REF(timeout_408)ntatag_timeout_408_ref, tag_bool_vr(&(timeout_408)), | ||||||||
1561 | NTATAG_UA_REF(ua)ntatag_ua_ref, tag_bool_vr(&(ua)), | ||||||||
1562 | NTATAG_UDP_MTU_REF(udp_mtu)ntatag_udp_mtu_ref, tag_uint_vr(&(udp_mtu)), | ||||||||
1563 | NTATAG_USER_VIA_REF(user_via)ntatag_user_via_ref, tag_bool_vr(&(user_via)), | ||||||||
1564 | NTATAG_USE_NAPTR_REF(use_naptr)ntatag_use_naptr_ref, tag_bool_vr(&(use_naptr)), | ||||||||
1565 | NTATAG_USE_SRV_REF(use_srv)ntatag_use_srv_ref, tag_bool_vr(&(use_srv)), | ||||||||
1566 | NTATAG_USE_TIMESTAMP_REF(use_timestamp)ntatag_use_timestamp_ref, tag_bool_vr(&(use_timestamp)), | ||||||||
1567 | #ifdef TPTAG_THRPSIZE | ||||||||
1568 | /* If threadpool is enabled, start a separate "reaper thread" */ | ||||||||
1569 | TPTAG_THRPSIZE_REF(threadpool)tptag_thrpsize_ref, tag_uint_vr(&(threadpool)), | ||||||||
1570 | #endif | ||||||||
1571 | NTATAG_SRV_503_REF(srv_503)ntatag_srv_503_ref, tag_bool_vr(&(srv_503)), | ||||||||
1572 | TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
1573 | nC = tl_gets(tags, | ||||||||
1574 | NTATAG_TIMER_C_REF(timer_c)ntatag_timer_c_ref, tag_uint_vr(&(timer_c)), | ||||||||
1575 | TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
1576 | n += nC; | ||||||||
1577 | |||||||||
1578 | if (mclass != NONE((void *)-1)) | ||||||||
1579 | agent->sa_mclass = mclass ? mclass : sip_default_mclass(); | ||||||||
1580 | |||||||||
1581 | m = 0; | ||||||||
1582 | for (tport = agent->sa_tports; tport; tport = tport_next(tport)) { | ||||||||
1583 | int m0 = tport_set_params(tport, TAG_NEXT(tags)tag_next, (tag_value_t)(tags)); | ||||||||
1584 | if (m0 < 0) | ||||||||
1585 | return m0; | ||||||||
1586 | if (m0 > m) | ||||||||
1587 | m = m0; | ||||||||
1588 | } | ||||||||
1589 | |||||||||
1590 | n += m; | ||||||||
1591 | |||||||||
1592 | if (aliases != NONE((void *)-1)) { | ||||||||
1593 | sip_contact_t const *m, *m_next; | ||||||||
1594 | |||||||||
1595 | m = agent->sa_aliases; | ||||||||
1596 | agent->sa_aliases = sip_contact_dup(home, aliases); | ||||||||
1597 | |||||||||
1598 | for (; m; m = m_next) { /* Free old aliases */ | ||||||||
1599 | m_next = m->m_next; | ||||||||
1600 | su_free(home, (void *)m); | ||||||||
1601 | } | ||||||||
1602 | } | ||||||||
1603 | |||||||||
1604 | if (proxy != NONE((void *)-1)) { | ||||||||
1605 | url_t *dp = url_hdup(home, proxy->us_url); | ||||||||
1606 | |||||||||
1607 | url_sanitize(dp); | ||||||||
1608 | |||||||||
1609 | if (dp == NULL((void*)0) || dp->url_type == url_sip || dp->url_type == url_sips || dp->url_type == url_urn) { | ||||||||
1610 | if (agent->sa_default_proxy) | ||||||||
1611 | su_free(home, agent->sa_default_proxy); | ||||||||
1612 | agent->sa_default_proxy = dp; | ||||||||
1613 | } | ||||||||
1614 | else | ||||||||
1615 | n = -1; | ||||||||
1616 | } | ||||||||
1617 | |||||||||
1618 | if (algorithm != NONE((void *)-1)) | ||||||||
1619 | agent->sa_algorithm = su_strdup(home, algorithm); | ||||||||
1620 | |||||||||
1621 | if (!su_strmatch(sigcomp, agent->sa_sigcomp_options)) { | ||||||||
1622 | msg_param_t const *l = NULL((void*)0); | ||||||||
1623 | char *s = su_strdup(home, sigcomp); | ||||||||
1624 | char *s1 = su_strdup(home, s), *s2 = s1; | ||||||||
1625 | |||||||||
1626 | if (s && s2 && msg_avlist_d(home, &s2, &l) == 0 && *s2 == '\0') { | ||||||||
1627 | su_free(home, (void *)agent->sa_sigcomp_options); | ||||||||
1628 | su_free(home, (void *)agent->sa_sigcomp_option_list); | ||||||||
1629 | agent->sa_sigcomp_options = s; | ||||||||
1630 | agent->sa_sigcomp_option_free = s1; | ||||||||
1631 | agent->sa_sigcomp_option_list = l; | ||||||||
1632 | } else { | ||||||||
1633 | su_free(home, s); | ||||||||
1634 | su_free(home, s1); | ||||||||
1635 | su_free(home, (void *)l); | ||||||||
1636 | n = -1; | ||||||||
1637 | } | ||||||||
1638 | } | ||||||||
1639 | |||||||||
1640 | if (maxsize == 0) maxsize = 2 * 1024 * 1024; | ||||||||
1641 | if (maxsize > UINT32_MAX(4294967295U)) maxsize = UINT32_MAX(4294967295U); | ||||||||
1642 | agent->sa_maxsize = maxsize; | ||||||||
1643 | |||||||||
1644 | if (max_proceeding == 0) max_proceeding = USIZE_MAX(2147483647 *2U +1U); | ||||||||
1645 | agent->sa_max_proceeding = max_proceeding; | ||||||||
1646 | |||||||||
1647 | agent->sa_max_recv_requests_per_second = max_recv_requests_per_second; | ||||||||
1648 | |||||||||
1649 | if (max_forwards == 0) max_forwards = 70; /* Default value */ | ||||||||
1650 | agent->sa_max_forwards->mf_count = max_forwards; | ||||||||
1651 | |||||||||
1652 | if (udp_mtu == 0) udp_mtu = 1300; | ||||||||
1653 | if (udp_mtu > 65535) udp_mtu = 65535; | ||||||||
1654 | if (agent->sa_udp_mtu != udp_mtu) { | ||||||||
1655 | agent->sa_udp_mtu = udp_mtu; | ||||||||
1656 | agent_set_udp_params(agent, udp_mtu); | ||||||||
1657 | } | ||||||||
1658 | |||||||||
1659 | if (sip_t1 == 0) sip_t1 = NTA_SIP_T1; | ||||||||
1660 | if (sip_t1 > NTA_TIME_MAX) sip_t1 = NTA_TIME_MAX; | ||||||||
1661 | agent->sa_t1 = sip_t1; | ||||||||
1662 | |||||||||
1663 | if (sip_t2 == 0) sip_t2 = NTA_SIP_T2; | ||||||||
1664 | if (sip_t2 > NTA_TIME_MAX) sip_t2 = NTA_TIME_MAX; | ||||||||
1665 | agent->sa_t2 = sip_t2; | ||||||||
1666 | |||||||||
1667 | if (sip_t4 == 0) sip_t4 = NTA_SIP_T4; | ||||||||
1668 | if (sip_t4 > NTA_TIME_MAX) sip_t4 = NTA_TIME_MAX; | ||||||||
1669 | if (agent->sa_t4 != sip_t4) { | ||||||||
1670 | incoming_queue_adjust(agent, agent->sa_in.inv_confirmed, sip_t4); | ||||||||
1671 | outgoing_queue_adjust(agent, agent->sa_out.completed, sip_t4); | ||||||||
1672 | } | ||||||||
1673 | agent->sa_t4 = sip_t4; | ||||||||
1674 | |||||||||
1675 | if (sip_t1x64 == 0) sip_t1x64 = NTA_SIP_T1 * 64; | ||||||||
1676 | if (sip_t1x64 > NTA_TIME_MAX) sip_t1x64 = NTA_TIME_MAX; | ||||||||
1677 | if (agent->sa_t1x64 != sip_t1x64) { | ||||||||
1678 | incoming_queue_adjust(agent, agent->sa_in.preliminary, sip_t1x64); | ||||||||
1679 | incoming_queue_adjust(agent, agent->sa_in.completed, sip_t1x64); | ||||||||
1680 | incoming_queue_adjust(agent, agent->sa_in.inv_completed, sip_t1x64); | ||||||||
1681 | outgoing_queue_adjust(agent, agent->sa_out.trying, sip_t1x64); | ||||||||
1682 | outgoing_queue_adjust(agent, agent->sa_out.inv_calling, sip_t1x64); | ||||||||
1683 | } | ||||||||
1684 | agent->sa_t1x64 = sip_t1x64; | ||||||||
1685 | if (nC == 1) { | ||||||||
1686 | agent->sa_use_timer_c = 1; | ||||||||
1687 | if (timer_c == 0) | ||||||||
1688 | timer_c = 185 * 1000; | ||||||||
1689 | agent->sa_timer_c = timer_c; | ||||||||
1690 | outgoing_queue_adjust(agent, agent->sa_out.inv_proceeding, timer_c); | ||||||||
1691 | } | ||||||||
1692 | if (timer_d < sip_t1x64) | ||||||||
1693 | timer_d = sip_t1x64; | ||||||||
1694 | outgoing_queue_adjust(agent, agent->sa_out.inv_completed, timer_d); | ||||||||
1695 | |||||||||
1696 | if (tls_orq_connect_timeout > NTA_TIME_MAX) tls_orq_connect_timeout = NTA_TIME_MAX; | ||||||||
1697 | agent->sa_tls_orq_connect_timeout = tls_orq_connect_timeout; | ||||||||
1698 | |||||||||
1699 | if (graylist > 24 * 60 * 60) | ||||||||
1700 | graylist = 24 * 60 * 60; | ||||||||
1701 | agent->sa_graylist = graylist; | ||||||||
1702 | |||||||||
1703 | if (blacklist > 24 * 60 * 60) | ||||||||
1704 | blacklist = 24 * 60 * 60; | ||||||||
1705 | agent->sa_blacklist = blacklist; | ||||||||
1706 | |||||||||
1707 | if (progress == 0) | ||||||||
1708 | progress = 60 * 1000; | ||||||||
1709 | agent->sa_progress = progress; | ||||||||
1710 | |||||||||
1711 | if (server_rport > 3) | ||||||||
1712 | server_rport = 1; | ||||||||
1713 | else if (server_rport < 0) | ||||||||
1714 | server_rport = 1; | ||||||||
1715 | agent->sa_server_rport = server_rport; | ||||||||
1716 | |||||||||
1717 | agent->sa_bad_req_mask = bad_req_mask; | ||||||||
1718 | agent->sa_bad_resp_mask = bad_resp_mask; | ||||||||
1719 | |||||||||
1720 | agent->sa_is_a_uas = ua != 0; | ||||||||
1721 | agent->sa_is_stateless = stateless != 0; | ||||||||
1722 | agent->sa_drop_prob = drop_prob < 1000 ? drop_prob : 1000; | ||||||||
1723 | agent->sa_user_via = user_via != 0; | ||||||||
1724 | agent->sa_extra_100 = extra_100 != 0; | ||||||||
1725 | agent->sa_pass_100 = pass_100 != 0; | ||||||||
1726 | agent->sa_timeout_408 = timeout_408 != 0; | ||||||||
1727 | agent->sa_pass_408 = pass_408 != 0; | ||||||||
1728 | agent->sa_merge_482 = merge_482 != 0; | ||||||||
1729 | agent->sa_cancel_2543 = cancel_2543 != 0; | ||||||||
1730 | agent->sa_cancel_487 = cancel_487 != 0; | ||||||||
1731 | agent->sa_invite_100rel = invite_100rel != 0; | ||||||||
1732 | agent->sa_timestamp = use_timestamp != 0; | ||||||||
1733 | agent->sa_use_naptr = use_naptr != 0; | ||||||||
1734 | agent->sa_use_srv = use_srv != 0; | ||||||||
1735 | agent->sa_srv_503 = srv_503 != 0; | ||||||||
1736 | agent->sa_smime = smime; | ||||||||
1737 | agent->sa_flags = flags & MSG_FLG_USERMASK; | ||||||||
1738 | agent->sa_rport = rport != 0; | ||||||||
1739 | agent->sa_tcp_rport = tcp_rport != 0; | ||||||||
1740 | agent->sa_tls_rport = tls_rport != 0; | ||||||||
1741 | agent->sa_preload = preload; | ||||||||
1742 | agent->sa_tport_threadpool = threadpool; | ||||||||
1743 | |||||||||
1744 | return n; | ||||||||
1745 | } | ||||||||
1746 | |||||||||
1747 | static | ||||||||
1748 | void agent_set_udp_params(nta_agent_t *self, usize_t udp_mtu) | ||||||||
1749 | { | ||||||||
1750 | tport_t *tp; | ||||||||
1751 | |||||||||
1752 | /* Set via fields for the tports */ | ||||||||
1753 | for (tp = tport_primaries(self->sa_tports); tp; tp = tport_next(tp)) { | ||||||||
1754 | if (tport_is_udp(tp)) | ||||||||
1755 | tport_set_params(tp, | ||||||||
1756 | TPTAG_TIMEOUT(2 * self->sa_t1x64)tptag_timeout, tag_uint_v((2 * self->sa_t1x64)), | ||||||||
1757 | TPTAG_MTU(udp_mtu)tptag_mtu, tag_usize_v((udp_mtu)), | ||||||||
1758 | TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
1759 | } | ||||||||
1760 | } | ||||||||
1761 | |||||||||
1762 | /**Get NTA Parameters. | ||||||||
1763 | * | ||||||||
1764 | * The nta_agent_get_params() function retrieves the stack parameters. The | ||||||||
1765 | * parameters determine the way NTA handles the retransmissions, how long | ||||||||
1766 | * NTA keeps transactions alive, does NTA apply proxy or user-agent logic to | ||||||||
1767 | * INVITE transactions, or how the @Via headers are generated. | ||||||||
1768 | * | ||||||||
1769 | * @TAGS | ||||||||
1770 | * NTATAG_ALIASES_REF(), NTATAG_BLACKLIST_REF(), | ||||||||
1771 | * NTATAG_CANCEL_2543_REF(), NTATAG_CANCEL_487_REF(), | ||||||||
1772 | * NTATAG_CLIENT_RPORT_REF(), NTATAG_CONTACT_REF(), | ||||||||
1773 | * NTATAG_DEBUG_DROP_PROB_REF(), NTATAG_DEFAULT_PROXY_REF(), | ||||||||
1774 | * NTATAG_EXTRA_100_REF(), NTATAG_GRAYLIST_REF(), | ||||||||
1775 | * NTATAG_MAXSIZE_REF(), NTATAG_MAX_FORWARDS_REF(), NTATAG_MCLASS_REF(), | ||||||||
1776 | * NTATAG_MERGE_482_REF(), NTATAG_MAX_PROCEEDING_REF(), | ||||||||
1777 | * NTATAG_PASS_100_REF(), NTATAG_PASS_408_REF(), NTATAG_PRELOAD_REF(), | ||||||||
1778 | * NTATAG_PROGRESS_REF(), | ||||||||
1779 | * NTATAG_REL100_REF(), | ||||||||
1780 | * NTATAG_SERVER_RPORT_REF(), | ||||||||
1781 | * NTATAG_SIGCOMP_ALGORITHM_REF(), NTATAG_SIGCOMP_OPTIONS_REF(), | ||||||||
1782 | * NTATAG_SIPFLAGS_REF(), | ||||||||
1783 | * NTATAG_SIP_T1_REF(), NTATAG_SIP_T1X64_REF(), NTATAG_SIP_T2_REF(), | ||||||||
1784 | * NTATAG_SIP_T4_REF(), NTATAG_SMIME_REF(), NTATAG_STATELESS_REF(), | ||||||||
1785 | * NTATAG_TAG_3261_REF(), NTATAG_TIMEOUT_408_REF(), NTATAG_TIMER_C_REF(), | ||||||||
1786 | * NTATAG_UA_REF(), NTATAG_UDP_MTU_REF(), NTATAG_USER_VIA_REF(), | ||||||||
1787 | * NTATAG_USE_NAPTR_REF(), NTATAG_USE_SRV_REF(), | ||||||||
1788 | * and NTATAG_USE_TIMESTAMP_REF(). | ||||||||
1789 | * | ||||||||
1790 | */ | ||||||||
1791 | int nta_agent_get_params(nta_agent_t *agent, | ||||||||
1792 | tag_type_t tag, tag_value_t value, ...) | ||||||||
1793 | { | ||||||||
1794 | int n; | ||||||||
1795 | ta_list ta; | ||||||||
1796 | |||||||||
1797 | if (agent) { | ||||||||
1798 | 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); | ||||||||
1799 | n = agent_get_params(agent, ta_args(ta)(ta).tl); | ||||||||
1800 | 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)); | ||||||||
1801 | return n; | ||||||||
1802 | } | ||||||||
1803 | |||||||||
1804 | su_seterrno(EINVAL22); | ||||||||
1805 | return -1; | ||||||||
1806 | } | ||||||||
1807 | |||||||||
1808 | /** Get NTA parameters */ | ||||||||
1809 | static | ||||||||
1810 | int agent_get_params(nta_agent_t *agent, tagi_t *tags) | ||||||||
1811 | { | ||||||||
1812 | return | ||||||||
1813 | tl_tgets(tags, | ||||||||
1814 | NTATAG_ALIASES(agent->sa_aliases)ntatag_aliases, siptag_contact_v((agent->sa_aliases)), | ||||||||
1815 | NTATAG_BLACKLIST(agent->sa_blacklist)ntatag_blacklist, tag_uint_v((agent->sa_blacklist)), | ||||||||
1816 | NTATAG_CANCEL_2543(agent->sa_cancel_2543)ntatag_cancel_2543, tag_bool_v((agent->sa_cancel_2543)), | ||||||||
1817 | NTATAG_CANCEL_487(agent->sa_cancel_487)ntatag_cancel_487, tag_bool_v((agent->sa_cancel_487)), | ||||||||
1818 | NTATAG_CLIENT_RPORT(agent->sa_rport)ntatag_client_rport, tag_bool_v((agent->sa_rport)), | ||||||||
1819 | NTATAG_CONTACT(agent->sa_contact)ntatag_contact, siptag_contact_v((agent->sa_contact)), | ||||||||
1820 | NTATAG_DEBUG_DROP_PROB(agent->sa_drop_prob)ntatag_debug_drop_prob, tag_uint_v((agent->sa_drop_prob)), | ||||||||
1821 | NTATAG_DEFAULT_PROXY(agent->sa_default_proxy)ntatag_default_proxy, urltag_url_v((agent->sa_default_proxy )), | ||||||||
1822 | NTATAG_EXTRA_100(agent->sa_extra_100)ntatag_extra_100, tag_bool_v((agent->sa_extra_100)), | ||||||||
1823 | NTATAG_GRAYLIST(agent->sa_graylist)ntatag_graylist, tag_uint_v((agent->sa_graylist)), | ||||||||
1824 | NTATAG_MAXSIZE(agent->sa_maxsize)ntatag_maxsize, tag_usize_v((agent->sa_maxsize)), | ||||||||
1825 | NTATAG_MAX_PROCEEDING(agent->sa_max_proceeding)ntatag_max_proceeding, tag_usize_v((agent->sa_max_proceeding )), | ||||||||
1826 | NTATAG_MAX_RECV_REQUESTS_PER_SECOND(agent->sa_max_recv_requests_per_second)ntatag_max_recv_requests_per_second, tag_usize_v((agent->sa_max_recv_requests_per_second )), | ||||||||
1827 | NTATAG_MAX_FORWARDS(agent->sa_max_forwards->mf_count)ntatag_max_forwards, tag_uint_v((agent->sa_max_forwards-> mf_count)), | ||||||||
1828 | NTATAG_MCLASS(agent->sa_mclass)ntatag_mclass, tag_cptr_v((agent->sa_mclass)), | ||||||||
1829 | NTATAG_MERGE_482(agent->sa_merge_482)ntatag_merge_482, tag_bool_v((agent->sa_merge_482)), | ||||||||
1830 | NTATAG_PASS_100(agent->sa_pass_100)ntatag_pass_100, tag_bool_v((agent->sa_pass_100)), | ||||||||
1831 | NTATAG_PASS_408(agent->sa_pass_408)ntatag_pass_408, tag_bool_v((agent->sa_pass_408)), | ||||||||
1832 | NTATAG_PRELOAD(agent->sa_preload)ntatag_preload, tag_uint_v((agent->sa_preload)), | ||||||||
1833 | NTATAG_PROGRESS(agent->sa_progress)ntatag_progress, tag_uint_v((agent->sa_progress)), | ||||||||
1834 | NTATAG_REL100(agent->sa_invite_100rel)ntatag_rel100, tag_bool_v((agent->sa_invite_100rel)), | ||||||||
1835 | NTATAG_SERVER_RPORT((int)(agent->sa_server_rport))ntatag_server_rport, tag_int_v(((int)(agent->sa_server_rport ))), | ||||||||
1836 | NTATAG_SIGCOMP_ALGORITHM(agent->sa_algorithm)ntatag_sigcomp_algorithm, tag_str_v((agent->sa_algorithm)), | ||||||||
1837 | NTATAG_SIGCOMP_OPTIONS(agent->sa_sigcomp_options ?ntatag_sigcomp_options, tag_str_v((agent->sa_sigcomp_options ? agent->sa_sigcomp_options : "sip")) | ||||||||
1838 | agent->sa_sigcomp_options :ntatag_sigcomp_options, tag_str_v((agent->sa_sigcomp_options ? agent->sa_sigcomp_options : "sip")) | ||||||||
1839 | "sip")ntatag_sigcomp_options, tag_str_v((agent->sa_sigcomp_options ? agent->sa_sigcomp_options : "sip")), | ||||||||
1840 | NTATAG_SIPFLAGS(agent->sa_flags)ntatag_sipflags, tag_uint_v((agent->sa_flags)), | ||||||||
1841 | NTATAG_SIP_T1(agent->sa_t1)ntatag_sip_t1, tag_uint_v((agent->sa_t1)), | ||||||||
1842 | NTATAG_SIP_T1X64(agent->sa_t1x64)ntatag_sip_t1x64, tag_uint_v((agent->sa_t1x64)), | ||||||||
1843 | NTATAG_SIP_T2(agent->sa_t2)ntatag_sip_t2, tag_uint_v((agent->sa_t2)), | ||||||||
1844 | NTATAG_SIP_T4(agent->sa_t4)ntatag_sip_t4, tag_uint_v((agent->sa_t4)), | ||||||||
1845 | #if HAVE_SOFIA_SMIME0 | ||||||||
1846 | NTATAG_SMIME(agent->sa_smime)ntatag_smime, tag_ptr_v((agent->sa_smime)), | ||||||||
1847 | #else | ||||||||
1848 | NTATAG_SMIME(NULL)ntatag_smime, tag_ptr_v((((void*)0))), | ||||||||
1849 | #endif | ||||||||
1850 | NTATAG_STATELESS(agent->sa_is_stateless)ntatag_stateless, tag_bool_v((agent->sa_is_stateless)), | ||||||||
1851 | NTATAG_TAG_3261(1)ntatag_tag_3261, tag_bool_v((1)), | ||||||||
1852 | NTATAG_TIMEOUT_408(agent->sa_timeout_408)ntatag_timeout_408, tag_bool_v((agent->sa_timeout_408)), | ||||||||
1853 | NTATAG_TIMER_C(agent->sa_timer_c)ntatag_timer_c, tag_uint_v((agent->sa_timer_c)), | ||||||||
1854 | NTATAG_UA(agent->sa_is_a_uas)ntatag_ua, tag_bool_v((agent->sa_is_a_uas)), | ||||||||
1855 | NTATAG_UDP_MTU(agent->sa_udp_mtu)ntatag_udp_mtu, tag_uint_v((agent->sa_udp_mtu)), | ||||||||
1856 | NTATAG_USER_VIA(agent->sa_user_via)ntatag_user_via, tag_bool_v((agent->sa_user_via)), | ||||||||
1857 | NTATAG_USE_NAPTR(agent->sa_use_naptr)ntatag_use_naptr, tag_bool_v((agent->sa_use_naptr)), | ||||||||
1858 | NTATAG_USE_SRV(agent->sa_use_srv)ntatag_use_srv, tag_bool_v((agent->sa_use_srv)), | ||||||||
1859 | NTATAG_USE_TIMESTAMP(agent->sa_timestamp)ntatag_use_timestamp, tag_bool_v((agent->sa_timestamp)), | ||||||||
1860 | NTATAG_SRV_503(agent->sa_srv_503)ntatag_srv_503, tag_bool_v((agent->sa_srv_503)), | ||||||||
1861 | TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
1862 | } | ||||||||
1863 | |||||||||
1864 | /**Get NTA statistics. | ||||||||
1865 | * | ||||||||
1866 | * The nta_agent_get_stats() function retrieves the stack statistics. | ||||||||
1867 | * | ||||||||
1868 | * @TAGS | ||||||||
1869 | * NTATAG_S_ACKED_TR_REF(), | ||||||||
1870 | * NTATAG_S_BAD_MESSAGE_REF(), | ||||||||
1871 | * NTATAG_S_BAD_REQUEST_REF(), | ||||||||
1872 | * NTATAG_S_BAD_RESPONSE_REF(), | ||||||||
1873 | * NTATAG_S_CANCELED_TR_REF(), | ||||||||
1874 | * NTATAG_S_CLIENT_TR_REF(), | ||||||||
1875 | * NTATAG_S_DIALOG_TR_REF(), | ||||||||
1876 | * NTATAG_S_DROP_REQUEST_REF(), | ||||||||
1877 | * NTATAG_S_DROP_RESPONSE_REF(), | ||||||||
1878 | * NTATAG_S_IRQ_HASH_REF(), | ||||||||
1879 | * NTATAG_S_IRQ_HASH_USED_REF(), | ||||||||
1880 | * NTATAG_S_LEG_HASH_REF(), | ||||||||
1881 | * NTATAG_S_LEG_HASH_USED_REF(), | ||||||||
1882 | * NTATAG_S_MERGED_REQUEST_REF(), | ||||||||
1883 | * NTATAG_S_ORQ_HASH_REF(), | ||||||||
1884 | * NTATAG_S_ORQ_HASH_USED_REF(), | ||||||||
1885 | * NTATAG_S_RECV_MSG_REF(), | ||||||||
1886 | * NTATAG_S_RECV_REQUEST_REF(), | ||||||||
1887 | * NTATAG_S_RECV_RESPONSE_REF(), | ||||||||
1888 | * NTATAG_S_RECV_RETRY_REF(), | ||||||||
1889 | * NTATAG_S_RETRY_REQUEST_REF(), | ||||||||
1890 | * NTATAG_S_RETRY_RESPONSE_REF(), | ||||||||
1891 | * NTATAG_S_SENT_MSG_REF(), | ||||||||
1892 | * NTATAG_S_SENT_REQUEST_REF(), | ||||||||
1893 | * NTATAG_S_SENT_RESPONSE_REF(), | ||||||||
1894 | * NTATAG_S_SERVER_TR_REF(), | ||||||||
1895 | * NTATAG_S_TOUT_REQUEST_REF(), | ||||||||
1896 | * NTATAG_S_TOUT_RESPONSE_REF(), | ||||||||
1897 | * NTATAG_S_TRLESS_200_REF(), | ||||||||
1898 | * NTATAG_S_TRLESS_REQUEST_REF(), | ||||||||
1899 | * NTATAG_S_TRLESS_RESPONSE_REF(), and | ||||||||
1900 | * NTATAG_S_TRLESS_TO_TR_REF(), | ||||||||
1901 | */ | ||||||||
1902 | int nta_agent_get_stats(nta_agent_t *agent, | ||||||||
1903 | tag_type_t tag, tag_value_t value, ...) | ||||||||
1904 | { | ||||||||
1905 | int n; | ||||||||
1906 | ta_list ta; | ||||||||
1907 | |||||||||
1908 | if (!agent) | ||||||||
1909 | return su_seterrno(EINVAL22), -1; | ||||||||
1910 | |||||||||
1911 | 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); | ||||||||
1912 | |||||||||
1913 | n = tl_tgets(ta_args(ta)(ta).tl, | ||||||||
1914 | NTATAG_S_IRQ_HASH(agent->sa_incoming->iht_size)ntatag_s_irq_hash, tag_usize_v(agent->sa_incoming->iht_size ), | ||||||||
1915 | NTATAG_S_ORQ_HASH(agent->sa_outgoing->oht_size)ntatag_s_orq_hash, tag_usize_v(agent->sa_outgoing->oht_size ), | ||||||||
1916 | NTATAG_S_LEG_HASH(agent->sa_dialogs->lht_size)ntatag_s_leg_hash, tag_usize_v(agent->sa_dialogs->lht_size ), | ||||||||
1917 | NTATAG_S_IRQ_HASH_USED(agent->sa_incoming->iht_used)ntatag_s_irq_hash_used, tag_usize_v(agent->sa_incoming-> iht_used), | ||||||||
1918 | NTATAG_S_ORQ_HASH_USED(agent->sa_outgoing->oht_used)ntatag_s_orq_hash_used, tag_usize_v(agent->sa_outgoing-> oht_used), | ||||||||
1919 | NTATAG_S_LEG_HASH_USED(agent->sa_dialogs->lht_used)ntatag_s_leg_hash_used, tag_usize_v(agent->sa_dialogs-> lht_used), | ||||||||
1920 | NTATAG_S_RECV_MSG(agent->sa_stats->as_recv_msg)ntatag_s_recv_msg, tag_usize_v(agent->sa_stats->as_recv_msg ), | ||||||||
1921 | NTATAG_S_RECV_REQUEST(agent->sa_stats->as_recv_request)ntatag_s_recv_request, tag_usize_v(agent->sa_stats->as_recv_request ), | ||||||||
1922 | NTATAG_S_RECV_RESPONSE(agent->sa_stats->as_recv_response)ntatag_s_recv_response, tag_usize_v(agent->sa_stats->as_recv_response ), | ||||||||
1923 | NTATAG_S_BAD_MESSAGE(agent->sa_stats->as_bad_message)ntatag_s_bad_message, tag_usize_v(agent->sa_stats->as_bad_message ), | ||||||||
1924 | NTATAG_S_BAD_REQUEST(agent->sa_stats->as_bad_request)ntatag_s_bad_request, tag_usize_v(agent->sa_stats->as_bad_request ), | ||||||||
1925 | NTATAG_S_BAD_RESPONSE(agent->sa_stats->as_bad_response)ntatag_s_bad_response, tag_usize_v(agent->sa_stats->as_bad_response ), | ||||||||
1926 | NTATAG_S_DROP_REQUEST(agent->sa_stats->as_drop_request)ntatag_s_drop_request, tag_usize_v(agent->sa_stats->as_drop_request ), | ||||||||
1927 | NTATAG_S_DROP_RESPONSE(agent->sa_stats->as_drop_response)ntatag_s_drop_response, tag_usize_v(agent->sa_stats->as_drop_response ), | ||||||||
1928 | NTATAG_S_CLIENT_TR(agent->sa_stats->as_client_tr)ntatag_s_client_tr, tag_usize_v(agent->sa_stats->as_client_tr ), | ||||||||
1929 | NTATAG_S_SERVER_TR(agent->sa_stats->as_server_tr)ntatag_s_server_tr, tag_usize_v(agent->sa_stats->as_server_tr ), | ||||||||
1930 | NTATAG_S_DIALOG_TR(agent->sa_stats->as_dialog_tr)ntatag_s_dialog_tr, tag_usize_v(agent->sa_stats->as_dialog_tr ), | ||||||||
1931 | NTATAG_S_ACKED_TR(agent->sa_stats->as_acked_tr)ntatag_s_acked_tr, tag_usize_v(agent->sa_stats->as_acked_tr ), | ||||||||
1932 | NTATAG_S_CANCELED_TR(agent->sa_stats->as_canceled_tr)ntatag_s_canceled_tr, tag_usize_v(agent->sa_stats->as_canceled_tr ), | ||||||||
1933 | NTATAG_S_TRLESS_REQUEST(agent->sa_stats->as_trless_request)ntatag_s_trless_request, tag_usize_v(agent->sa_stats->as_trless_request ), | ||||||||
1934 | 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 ), | ||||||||
1935 | NTATAG_S_TRLESS_RESPONSE(agent->sa_stats->as_trless_response)ntatag_s_trless_response, tag_usize_v(agent->sa_stats-> as_trless_response), | ||||||||
1936 | NTATAG_S_TRLESS_200(agent->sa_stats->as_trless_200)ntatag_s_trless_200, tag_usize_v(agent->sa_stats->as_trless_200 ), | ||||||||
1937 | NTATAG_S_MERGED_REQUEST(agent->sa_stats->as_merged_request)ntatag_s_merged_request, tag_usize_v(agent->sa_stats->as_merged_request ), | ||||||||
1938 | NTATAG_S_SENT_MSG(agent->sa_stats->as_sent_msg)ntatag_s_sent_msg, tag_usize_v(agent->sa_stats->as_sent_msg ), | ||||||||
1939 | NTATAG_S_SENT_REQUEST(agent->sa_stats->as_sent_request)ntatag_s_sent_request, tag_usize_v(agent->sa_stats->as_sent_request ), | ||||||||
1940 | NTATAG_S_SENT_RESPONSE(agent->sa_stats->as_sent_response)ntatag_s_sent_response, tag_usize_v(agent->sa_stats->as_sent_response ), | ||||||||
1941 | NTATAG_S_RETRY_REQUEST(agent->sa_stats->as_retry_request)ntatag_s_retry_request, tag_usize_v(agent->sa_stats->as_retry_request ), | ||||||||
1942 | NTATAG_S_RETRY_RESPONSE(agent->sa_stats->as_retry_response)ntatag_s_retry_response, tag_usize_v(agent->sa_stats->as_retry_response ), | ||||||||
1943 | NTATAG_S_RECV_RETRY(agent->sa_stats->as_recv_retry)ntatag_s_recv_retry, tag_usize_v(agent->sa_stats->as_recv_retry ), | ||||||||
1944 | NTATAG_S_TOUT_REQUEST(agent->sa_stats->as_tout_request)ntatag_s_tout_request, tag_usize_v(agent->sa_stats->as_tout_request ), | ||||||||
1945 | NTATAG_S_TOUT_RESPONSE(agent->sa_stats->as_tout_response)ntatag_s_tout_response, tag_usize_v(agent->sa_stats->as_tout_response ), | ||||||||
1946 | NTATAG_Q_IN_COMPLETED(agent->sa_in.completed->q_length)ntatag_q_in_completed, tag_size_v(agent->sa_in.completed-> q_length), | ||||||||
1947 | NTATAG_Q_IN_FINAL_FAILED(agent->sa_in.final_failed->q_length)ntatag_q_in_final_failed, tag_size_v(agent->sa_in.final_failed ->q_length), | ||||||||
1948 | NTATAG_Q_IN_INV_COMPLETED(agent->sa_in.inv_completed->q_length)ntatag_q_in_inv_completed, tag_size_v(agent->sa_in.inv_completed ->q_length), | ||||||||
1949 | NTATAG_Q_IN_INV_CONFIRMED(agent->sa_in.inv_confirmed->q_length)ntatag_q_in_inv_confirmed, tag_size_v(agent->sa_in.inv_confirmed ->q_length), | ||||||||
1950 | NTATAG_Q_IN_PRELIMINARY(agent->sa_in.preliminary->q_length)ntatag_q_in_preliminary, tag_size_v(agent->sa_in.preliminary ->q_length), | ||||||||
1951 | NTATAG_Q_IN_PROCEEDING(agent->sa_in.proceeding->q_length)ntatag_q_in_proceeding, tag_size_v(agent->sa_in.proceeding ->q_length), | ||||||||
1952 | NTATAG_Q_IN_TERMINATED(agent->sa_in.terminated->q_length)ntatag_q_in_terminated, tag_size_v(agent->sa_in.terminated ->q_length), | ||||||||
1953 | NTATAG_Q_OUT_COMPLETED(agent->sa_out.completed->q_length)ntatag_q_out_completed, tag_size_v(agent->sa_out.completed ->q_length), | ||||||||
1954 | NTATAG_Q_OUT_DELAYED(agent->sa_out.delayed->q_length)ntatag_q_out_delayed, tag_size_v(agent->sa_out.delayed-> q_length), | ||||||||
1955 | NTATAG_Q_OUT_INV_CALLING(agent->sa_out.inv_calling->q_length)ntatag_q_out_inv_calling, tag_size_v(agent->sa_out.inv_calling ->q_length), | ||||||||
1956 | NTATAG_Q_OUT_INV_COMPLETED(agent->sa_out.inv_completed->q_length)ntatag_q_out_inv_completed, tag_size_v(agent->sa_out.inv_completed ->q_length), | ||||||||
1957 | NTATAG_Q_OUT_INV_PROCEEDING(agent->sa_out.inv_proceeding->q_length)ntatag_q_out_inv_proceeding, tag_size_v(agent->sa_out.inv_proceeding ->q_length), | ||||||||
1958 | NTATAG_Q_OUT_RESOLVING(agent->sa_out.resolving->q_length)ntatag_q_out_resolving, tag_size_v(agent->sa_out.resolving ->q_length), | ||||||||
1959 | NTATAG_Q_OUT_TERMINATED(agent->sa_out.terminated->q_length)ntatag_q_out_terminated, tag_size_v(agent->sa_out.terminated ->q_length), | ||||||||
1960 | TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
1961 | |||||||||
1962 | 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)); | ||||||||
1963 | |||||||||
1964 | return n; | ||||||||
1965 | } | ||||||||
1966 | |||||||||
1967 | /**Calculate a new unique tag. | ||||||||
1968 | * | ||||||||
1969 | * This function generates a series of 2**64 unique tags for @From or @To | ||||||||
1970 | * headers. The start of the tag series is derived from the NTP time the NTA | ||||||||
1971 | * agent was initialized. | ||||||||
1972 | * | ||||||||
1973 | */ | ||||||||
1974 | char const *nta_agent_newtag(su_home_t *home, char const *fmt, nta_agent_t *sa) | ||||||||
1975 | { | ||||||||
1976 | char tag[(8 * 8 + 4)/ 5 + 1]; | ||||||||
1977 | |||||||||
1978 | if (sa == NULL((void*)0)) | ||||||||
1979 | return su_seterrno(EINVAL22), NULL((void*)0); | ||||||||
1980 | |||||||||
1981 | /* XXX - use a cryptographically safe func here? */ | ||||||||
1982 | sa->sa_tags += NTA_TAG_PRIME(uint64_t)(0xB9591D1C361C6521ULL); | ||||||||
1983 | |||||||||
1984 | msg_random_token(tag, sizeof(tag) - 1, &sa->sa_tags, sizeof(sa->sa_tags)); | ||||||||
1985 | |||||||||
1986 | if (fmt && fmt[0]) | ||||||||
1987 | return su_sprintf(home, fmt, tag); | ||||||||
1988 | else | ||||||||
1989 | return su_strdup(home, tag); | ||||||||
1990 | } | ||||||||
1991 | |||||||||
1992 | /** | ||||||||
1993 | * Calculate branch value. | ||||||||
1994 | */ | ||||||||
1995 | static char const *stateful_branch(su_home_t *home, nta_agent_t *sa) | ||||||||
1996 | { | ||||||||
1997 | char branch[(8 * 8 + 4)/ 5 + 1]; | ||||||||
1998 | |||||||||
1999 | /* XXX - use a cryptographically safe func here? */ | ||||||||
2000 | sa->sa_branch += NTA_BRANCH_PRIME(uint64_t)(0xB9591D1C361C6521ULL); | ||||||||
2001 | |||||||||
2002 | msg_random_token(branch, sizeof(branch) - 1, | ||||||||
2003 | &sa->sa_branch, sizeof(sa->sa_branch)); | ||||||||
2004 | |||||||||
2005 | return su_sprintf(home, "branch=z9hG4bK%s", branch); | ||||||||
2006 | } | ||||||||
2007 | |||||||||
2008 | #include <sofia-sip/su_md5.h> | ||||||||
2009 | |||||||||
2010 | /** | ||||||||
2011 | * Calculate branch value for stateless operation. | ||||||||
2012 | * | ||||||||
2013 | * XXX - should include HMAC of previous @Via line. | ||||||||
2014 | */ | ||||||||
2015 | static | ||||||||
2016 | char const *stateless_branch(nta_agent_t *sa, | ||||||||
2017 | msg_t *msg, | ||||||||
2018 | sip_t const *sip, | ||||||||
2019 | tp_name_t const *tpn) | ||||||||
2020 | { | ||||||||
2021 | su_md5_t md5[1]; | ||||||||
2022 | uint8_t digest[SU_MD5_DIGEST_SIZE16]; | ||||||||
2023 | char branch[(SU_MD5_DIGEST_SIZE16 * 8 + 4)/ 5 + 1]; | ||||||||
2024 | sip_route_t const *r; | ||||||||
2025 | |||||||||
2026 | assert(sip->sip_request)((void) sizeof ((sip->sip_request) ? 1 : 0), __extension__ ({ if (sip->sip_request) ; else __assert_fail ("sip->sip_request" , "nta.c", 2026, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
2027 | |||||||||
2028 | if (!sip->sip_via) | ||||||||
2029 | return stateful_branch(msg_home(msg)((su_home_t*)(msg)), sa); | ||||||||
2030 | |||||||||
2031 | su_md5_init(md5); | ||||||||
2032 | |||||||||
2033 | su_md5_str0update(md5, tpn->tpn_host); | ||||||||
2034 | su_md5_str0update(md5, tpn->tpn_port); | ||||||||
2035 | |||||||||
2036 | url_update(md5, sip->sip_request->rq_url); | ||||||||
2037 | if (sip->sip_call_id) { | ||||||||
2038 | su_md5_str0update(md5, sip->sip_call_id->i_id); | ||||||||
2039 | } | ||||||||
2040 | if (sip->sip_from) { | ||||||||
2041 | url_update(md5, sip->sip_from->a_url); | ||||||||
2042 | su_md5_stri0update(md5, sip->sip_from->a_tag); | ||||||||
2043 | } | ||||||||
2044 | if (sip->sip_to) { | ||||||||
2045 | url_update(md5, sip->sip_to->a_url); | ||||||||
2046 | /* XXX - some broken implementations include To tag in CANCEL */ | ||||||||
2047 | /* su_md5_str0update(md5, sip->sip_to->a_tag); */ | ||||||||
2048 | } | ||||||||
2049 | if (sip->sip_cseq) { | ||||||||
2050 | uint32_t cseq = htonl(sip->sip_cseq->cs_seq); | ||||||||
2051 | su_md5_update(md5, &cseq, sizeof(cseq)); | ||||||||
2052 | } | ||||||||
2053 | |||||||||
2054 | for (r = sip->sip_route; r; r = r->r_next) | ||||||||
2055 | url_update(md5, r->r_url); | ||||||||
2056 | |||||||||
2057 | su_md5_digest(md5, digest); | ||||||||
2058 | |||||||||
2059 | msg_random_token(branch, sizeof(branch) - 1, digest, sizeof(digest)); | ||||||||
2060 | |||||||||
2061 | return su_sprintf(msg_home(msg)((su_home_t*)(msg)), "branch=z9hG4bK.%s", branch); | ||||||||
2062 | } | ||||||||
2063 | |||||||||
2064 | /* ====================================================================== */ | ||||||||
2065 | /* 2) Transport interface */ | ||||||||
2066 | |||||||||
2067 | /* Local prototypes */ | ||||||||
2068 | static int agent_create_master_transport(nta_agent_t *self, tagi_t *tags); | ||||||||
2069 | static int agent_init_via(nta_agent_t *self, tport_t *primaries, int use_maddr); | ||||||||
2070 | static int agent_init_contact(nta_agent_t *self); | ||||||||
2071 | static void agent_recv_message(nta_agent_t *agent, | ||||||||
2072 | tport_t *tport, | ||||||||
2073 | msg_t *msg, | ||||||||
2074 | sip_via_t *tport_via, | ||||||||
2075 | su_time_t now); | ||||||||
2076 | static void agent_tp_error(nta_agent_t *agent, | ||||||||
2077 | tport_t *tport, | ||||||||
2078 | int errcode, | ||||||||
2079 | char const *remote); | ||||||||
2080 | static void agent_update_tport(nta_agent_t *agent, tport_t *); | ||||||||
2081 | |||||||||
2082 | /**For each transport, we have name used by tport module, SRV prefixes used | ||||||||
2083 | * for resolving, and NAPTR service/conversion. | ||||||||
2084 | */ | ||||||||
2085 | static | ||||||||
2086 | struct sipdns_tport { | ||||||||
2087 | char name[6]; /**< Named used by tport module */ | ||||||||
2088 | char port[6]; /**< Default port number */ | ||||||||
2089 | char prefix[14]; /**< Prefix for SRV domains */ | ||||||||
2090 | char service[10]; /**< NAPTR service */ | ||||||||
2091 | } | ||||||||
2092 | #define SIPDNS_TRANSPORTS(6) (6) | ||||||||
2093 | const sipdns_tports[SIPDNS_TRANSPORTS(6)] = { | ||||||||
2094 | { "udp", "5060", "_sip._udp.", "SIP+D2U" }, | ||||||||
2095 | { "tcp", "5060", "_sip._tcp.", "SIP+D2T" }, | ||||||||
2096 | { "sctp", "5060", "_sip._sctp.", "SIP+D2S" }, | ||||||||
2097 | { "tls", "5061", "_sips._tcp.", "SIPS+D2T" }, | ||||||||
2098 | { "ws", "5080", "_sips._ws.", "SIP+D2W" }, | ||||||||
2099 | { "wss", "5081", "_sips._wss.", "SIPS+D2W" }, | ||||||||
2100 | }; | ||||||||
2101 | |||||||||
2102 | static char const * const tports_sip[] = | ||||||||
2103 | { | ||||||||
2104 | "udp", "tcp", "sctp", "ws", NULL((void*)0) | ||||||||
2105 | }; | ||||||||
2106 | |||||||||
2107 | static char const * const tports_sips[] = | ||||||||
2108 | { | ||||||||
2109 | "tls", "wss", "ws", NULL((void*)0) | ||||||||
2110 | }; | ||||||||
2111 | |||||||||
2112 | static tport_stack_class_t nta_agent_class[1] = | ||||||||
2113 | {{ | ||||||||
2114 | sizeof(nta_agent_class), | ||||||||
2115 | agent_recv_message, | ||||||||
2116 | agent_tp_error, | ||||||||
2117 | nta_msg_create_for_transport, | ||||||||
2118 | agent_update_tport, | ||||||||
2119 | }}; | ||||||||
2120 | |||||||||
2121 | |||||||||
2122 | /** Add a transport to the agent. | ||||||||
2123 | * | ||||||||
2124 | * Creates a new transport and binds it | ||||||||
2125 | * to the port specified by the @a uri. The @a uri must have sip: or sips: | ||||||||
2126 | * scheme or be a wildcard uri ("*"). The @a uri syntax allowed is as | ||||||||
2127 | * follows: | ||||||||
2128 | * | ||||||||
2129 | * @code url <scheme>:<host>[:<port>]<url-params> @endcode | ||||||||
2130 | * where <url-params> may be | ||||||||
2131 | * @code | ||||||||
2132 | * ;transport=<xxx> | ||||||||
2133 | * ;maddr=<actual addr> | ||||||||
2134 | * ;comp=sigcomp | ||||||||
2135 | * @endcode | ||||||||
2136 | * | ||||||||
2137 | * The scheme part determines which transports are used. "sip" implies UDP | ||||||||
2138 | * and TCP, "sips" TLS over TCP. In the future, more transports can be | ||||||||
2139 | * supported, for instance, "sip" can use SCTP or DCCP, "sips" DTLS or TLS | ||||||||
2140 | * over SCTP. | ||||||||
2141 | * | ||||||||
2142 | * The "host" part determines what address/domain name is used in @Contact. | ||||||||
2143 | * An "*" in "host" part is shorthand for any local IP address. 0.0.0.0 | ||||||||
2144 | * means that the only the IPv4 addresses are used. [::] means that only | ||||||||
2145 | * the IPv6 addresses are used. If a domain name or a specific IP address | ||||||||
2146 | * is given as "host" part, an additional "maddr" parameter can be used to | ||||||||
2147 | * control which addresses are used by the stack when binding listen | ||||||||
2148 | * sockets for incoming requests. | ||||||||
2149 | * | ||||||||
2150 | * The "port" determines what port is used in contact, and to which port the | ||||||||
2151 | * stack binds in order to listen for incoming requests. Empty or missing | ||||||||
2152 | * port means that default port should be used (5060 for sip, 5061 for | ||||||||
2153 | * sips). An "*" in "port" part means any port, i.e., the stack binds to an | ||||||||
2154 | * ephemeral port. | ||||||||
2155 | * | ||||||||
2156 | * The "transport" parameter determines the transport protocol that is used | ||||||||
2157 | * and how they are preferred. If no protocol is specified, both UDP and TCP | ||||||||
2158 | * are used for SIP URL and TLS for SIPS URL. The preference can be | ||||||||
2159 | * indicated with a comma-separated list of transports, for instance, | ||||||||
2160 | * parameter @code transport=tcp,udp @endcode indicates that TCP is | ||||||||
2161 | * preferred to UDP. | ||||||||
2162 | * | ||||||||
2163 | * The "maddr" parameter determines to which address the stack binds in | ||||||||
2164 | * order to listen for incoming requests. An "*" in "maddr" parameter is | ||||||||
2165 | * shorthand for any local IP address. 0.0.0.0 means that only IPv4 sockets | ||||||||
2166 | * are created. [::] means that only IPv6 sockets are created. | ||||||||
2167 | * | ||||||||
2168 | * The "comp" parameter determines the supported compression protocol. | ||||||||
2169 | * Currently only sigcomp is supported (with suitable library). | ||||||||
2170 | * | ||||||||
2171 | * @par Examples: | ||||||||
2172 | * @code sip:172.21.40.24;maddr=* @endcode \n | ||||||||
2173 | * @code sip:172.21.40.24:50600;transport=TCP,UDP;comp=sigcomp @endcode \n | ||||||||
2174 | * @code sips:* @endcode | ||||||||
2175 | * | ||||||||
2176 | * @return | ||||||||
2177 | * On success, zero is returned. On error, -1 is returned, and @a errno is | ||||||||
2178 | * set appropriately. | ||||||||
2179 | */ | ||||||||
2180 | int nta_agent_add_tport(nta_agent_t *self, | ||||||||
2181 | url_string_t const *uri, | ||||||||
2182 | tag_type_t tag, tag_value_t value, ...) | ||||||||
2183 | { | ||||||||
2184 | url_t *url; | ||||||||
2185 | char tp[32]; | ||||||||
2186 | char maddr[256]; | ||||||||
2187 | char comp[32]; | ||||||||
2188 | tp_name_t tpn[1] = {{ NULL((void*)0) }}; | ||||||||
2189 | char const * const * tports = tports_sip; | ||||||||
2190 | int error; | ||||||||
2191 | ta_list ta; | ||||||||
2192 | char *tps[9] = {0}; | ||||||||
2193 | |||||||||
2194 | if (self == NULL((void*)0)) { | ||||||||
2195 | su_seterrno(EINVAL22); | ||||||||
2196 | return -1; | ||||||||
2197 | } | ||||||||
2198 | |||||||||
2199 | if (uri == NULL((void*)0)) | ||||||||
2200 | uri = (url_string_t *)"sip:*"; | ||||||||
2201 | else if (url_string_p(uri) ? | ||||||||
2202 | strcmp(uri->us_str, "*") == 0 : | ||||||||
2203 | uri->us_url->url_type == url_any) { | ||||||||
2204 | uri = (url_string_t *)"sip:*:*"; | ||||||||
2205 | } | ||||||||
2206 | |||||||||
2207 | if (!(url = url_hdup(self->sa_home, uri->us_url)) || | ||||||||
2208 | (url->url_type != url_sip && url->url_type != url_sips && url->url_type != url_urn)) { | ||||||||
2209 | if (url_string_p(uri)) | ||||||||
2210 | 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__ , 2210, "nta: %s: invalid bind URL\n", uri->us_str)) : (void )0); | ||||||||
2211 | else | ||||||||
2212 | 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__ , 2212, "nta: invalid bind URL\n" "%s", "")) : (void)0); | ||||||||
2213 | su_seterrno(EINVAL22); | ||||||||
2214 | return -1; | ||||||||
2215 | } | ||||||||
2216 | |||||||||
2217 | tpn->tpn_canon = url->url_host; | ||||||||
2218 | tpn->tpn_host = url->url_host; | ||||||||
2219 | tpn->tpn_port = url_port(url); | ||||||||
2220 | |||||||||
2221 | if (url->url_type == url_sip || url->url_type == url_urn) { | ||||||||
2222 | tpn->tpn_proto = "*"; | ||||||||
2223 | tports = tports_sip; | ||||||||
2224 | if (!tpn->tpn_port || !tpn->tpn_port[0]) | ||||||||
2225 | tpn->tpn_port = SIP_DEFAULT_SERV"5060"; | ||||||||
2226 | } | ||||||||
2227 | else { | ||||||||
2228 | assert(url->url_type == url_sips)((void) sizeof ((url->url_type == url_sips) ? 1 : 0), __extension__ ({ if (url->url_type == url_sips) ; else __assert_fail ("url->url_type == url_sips" , "nta.c", 2228, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
2229 | tpn->tpn_proto = "*"; | ||||||||
2230 | tports = tports_sips; | ||||||||
2231 | if (!tpn->tpn_port || !tpn->tpn_port[0]) | ||||||||
2232 | tpn->tpn_port = SIPS_DEFAULT_SERV"5061"; | ||||||||
2233 | } | ||||||||
2234 | |||||||||
2235 | if (url->url_params) { | ||||||||
2236 | if (url_param(url->url_params, "transport", tp, sizeof(tp)) > 0) { | ||||||||
2237 | if (strchr(tp, ',')) { | ||||||||
2238 | int i; char *t; | ||||||||
2239 | |||||||||
2240 | /* Split tp into transports */ | ||||||||
2241 | for (i = 0, t = tp; t && i < 8; i++) { | ||||||||
2242 | tps[i] = t; | ||||||||
2243 | if ((t = strchr(t, ','))) | ||||||||
2244 | *t++ = '\0'; | ||||||||
2245 | } | ||||||||
2246 | |||||||||
2247 | tps[i] = NULL((void*)0); | ||||||||
2248 | tports = (char const * const *)tps; | ||||||||
2249 | } else { | ||||||||
2250 | tpn->tpn_proto = tp; | ||||||||
2251 | } | ||||||||
2252 | } | ||||||||
2253 | if (url_param(url->url_params, "maddr", maddr, sizeof(maddr)) > 0) | ||||||||
2254 | tpn->tpn_host = maddr; | ||||||||
2255 | if (url_param(url->url_params, "comp", comp, sizeof(comp)) > 0) | ||||||||
2256 | tpn->tpn_comp = comp; | ||||||||
2257 | |||||||||
2258 | if (tpn->tpn_comp && | ||||||||
2259 | (nta_compressor_vtable == NULL((void*)0) || | ||||||||
2260 | !su_casematch(tpn->tpn_comp, nta_compressor_vtable->ncv_name))) { | ||||||||
2261 | 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__ , 2262, "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) | ||||||||
2262 | (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__ , 2262, "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); | ||||||||
2263 | } | ||||||||
2264 | } | ||||||||
2265 | |||||||||
2266 | 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); | ||||||||
2267 | |||||||||
2268 | if (self->sa_tports == NULL((void*)0)) { | ||||||||
2269 | if (agent_create_master_transport(self, ta_args(ta)(ta).tl) < 0) { | ||||||||
2270 | error = su_errno(); | ||||||||
2271 | 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__ , 2272, "nta: cannot create master transport: %s\n", su_strerror (error))) : (void)0) | ||||||||
2272 | 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__ , 2272, "nta: cannot create master transport: %s\n", su_strerror (error))) : (void)0); | ||||||||
2273 | goto error; | ||||||||
2274 | } | ||||||||
2275 | } | ||||||||
2276 | |||||||||
2277 | 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) { | ||||||||
2278 | error = su_errno(); | ||||||||
2279 | 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__ , 2285, "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) | ||||||||
2280 | 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__ , 2285, "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) | ||||||||
2281 | 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__ , 2285, "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) | ||||||||
2282 | 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__ , 2285, "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) | ||||||||
2283 | 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__ , 2285, "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) | ||||||||
2284 | 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__ , 2285, "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) | ||||||||
2285 | 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__ , 2285, "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); | ||||||||
2286 | goto error; | ||||||||
2287 | } | ||||||||
2288 | else | ||||||||
2289 | 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__ , 2294, "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) | ||||||||
2290 | 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__ , 2294, "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) | ||||||||
2291 | 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__ , 2294, "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) | ||||||||
2292 | 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__ , 2294, "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) | ||||||||
2293 | 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__ , 2294, "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) | ||||||||
2294 | 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__ , 2294, "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); | ||||||||
2295 | |||||||||
2296 | /* XXX - when to use maddr? */ | ||||||||
2297 | if ((agent_init_via(self, tport_primaries(self->sa_tports), 0)) < 0) { | ||||||||
2298 | error = su_errno(); | ||||||||
2299 | 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__ , 2299, "nta: cannot create Via headers\n" "%s", "")) : (void )0); | ||||||||
2300 | goto error; | ||||||||
2301 | } | ||||||||
2302 | else | ||||||||
2303 | 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__ , 2303, "nta: Via fields initialized\n" "%s", "")) : (void)0); | ||||||||
2304 | |||||||||
2305 | if ((agent_init_contact(self)) < 0) { | ||||||||
2306 | error = su_errno(); | ||||||||
2307 | 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__ , 2307, "nta: cannot create Contact header\n" "%s", "")) : (void )0); | ||||||||
2308 | goto error; | ||||||||
2309 | } | ||||||||
2310 | else | ||||||||
2311 | 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__ , 2311, "nta: Contact header created\n" "%s", "")) : (void)0); | ||||||||
2312 | |||||||||
2313 | su_free(self->sa_home, url); | ||||||||
2314 | 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)); | ||||||||
2315 | |||||||||
2316 | return 0; | ||||||||
2317 | |||||||||
2318 | error: | ||||||||
2319 | 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)); | ||||||||
2320 | su_seterrno(error); | ||||||||
2321 | return -1; | ||||||||
2322 | } | ||||||||
2323 | |||||||||
2324 | static | ||||||||
2325 | int agent_create_master_transport(nta_agent_t *self, tagi_t *tags) | ||||||||
2326 | { | ||||||||
2327 | self->sa_tports = | ||||||||
2328 | tport_tcreate(self, nta_agent_class, self->sa_root, | ||||||||
2329 | TPTAG_IDLE(1800000)tptag_idle, tag_uint_v((1800000)), | ||||||||
2330 | TAG_NEXT(tags)tag_next, (tag_value_t)(tags)); | ||||||||
2331 | |||||||||
2332 | if (!self->sa_tports) | ||||||||
2333 | return -1; | ||||||||
2334 | |||||||||
2335 | 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__ , 2335, "nta: master transport created\n" "%s", "")) : (void) 0); | ||||||||
2336 | |||||||||
2337 | return 0; | ||||||||
2338 | } | ||||||||
2339 | |||||||||
2340 | |||||||||
2341 | /** Initialize @Via headers. */ | ||||||||
2342 | static | ||||||||
2343 | int agent_init_via(nta_agent_t *self, tport_t *primaries, int use_maddr) | ||||||||
2344 | { | ||||||||
2345 | sip_via_t *via = NULL((void*)0), *new_via, *dup_via, *v, **vv = &via; | ||||||||
2346 | sip_via_t *new_vias, **next_new_via, *new_publics, **next_new_public; | ||||||||
2347 | tport_t *tp; | ||||||||
2348 | su_addrinfo_t const *ai; | ||||||||
2349 | |||||||||
2350 | 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))]; | ||||||||
2351 | |||||||||
2352 | su_home_auto(autohome, sizeof autohome); | ||||||||
2353 | |||||||||
2354 | self->sa_tport_ip4 = 0; | ||||||||
2355 | self->sa_tport_ip6 = 0; | ||||||||
2356 | self->sa_tport_udp = 0; | ||||||||
2357 | self->sa_tport_tcp = 0; | ||||||||
2358 | self->sa_tport_sctp = 0; | ||||||||
2359 | self->sa_tport_tls = 0; | ||||||||
2360 | self->sa_tport_ws = 0; | ||||||||
2361 | self->sa_tport_wss = 0; | ||||||||
2362 | |||||||||
2363 | /* Set via fields for the tports */ | ||||||||
2364 | for (tp = primaries; tp; tp = tport_next(tp)) { | ||||||||
| |||||||||
2365 | int maddr; | ||||||||
2366 | tp_name_t tpn[1]; | ||||||||
2367 | char const *comp = NULL((void*)0); | ||||||||
2368 | |||||||||
2369 | *tpn = *tport_name(tp); | ||||||||
2370 | |||||||||
2371 | assert(tpn->tpn_proto)((void) sizeof ((tpn->tpn_proto) ? 1 : 0), __extension__ ( { if (tpn->tpn_proto) ; else __assert_fail ("tpn->tpn_proto" , "nta.c", 2371, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
2372 | assert(tpn->tpn_canon)((void) sizeof ((tpn->tpn_canon) ? 1 : 0), __extension__ ( { if (tpn->tpn_canon) ; else __assert_fail ("tpn->tpn_canon" , "nta.c", 2372, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
2373 | assert(tpn->tpn_host)((void) sizeof ((tpn->tpn_host) ? 1 : 0), __extension__ ({ if (tpn->tpn_host) ; else __assert_fail ("tpn->tpn_host" , "nta.c", 2373, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
2374 | assert(tpn->tpn_port)((void) sizeof ((tpn->tpn_port) ? 1 : 0), __extension__ ({ if (tpn->tpn_port) ; else __assert_fail ("tpn->tpn_port" , "nta.c", 2374, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
2375 | |||||||||
2376 | #if 0 | ||||||||
2377 | if (getenv("SIP_UDP_CONNECT") | ||||||||
2378 | && strcmp(tpn->tpn_proto, "udp") == 0) | ||||||||
2379 | tport_set_params(tp, TPTAG_CONNECT(1)tptag_connect, tag_bool_v((1)), TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
2380 | #endif | ||||||||
2381 | |||||||||
2382 | if (tport_has_ip4(tp)) self->sa_tport_ip4 = 1; | ||||||||
2383 | |||||||||
2384 | #if SU_HAVE_IN61 | ||||||||
2385 | if (tport_has_ip6(tp)) self->sa_tport_ip6 = 1; | ||||||||
2386 | #endif | ||||||||
2387 | |||||||||
2388 | if (su_casematch(tpn->tpn_proto, "udp")) | ||||||||
2389 | self->sa_tport_udp = 1; | ||||||||
2390 | else if (su_casematch(tpn->tpn_proto, "tcp")) | ||||||||
2391 | self->sa_tport_tcp = 1; | ||||||||
2392 | else if (su_casematch(tpn->tpn_proto, "sctp")) | ||||||||
2393 | self->sa_tport_sctp = 1; | ||||||||
2394 | else if (su_casematch(tpn->tpn_proto, "ws")) | ||||||||
2395 | self->sa_tport_ws = 1; | ||||||||
2396 | else if (su_casematch(tpn->tpn_proto, "wss")) | ||||||||
2397 | self->sa_tport_wss = 1; | ||||||||
2398 | |||||||||
2399 | if (tport_has_tls(tp)) self->sa_tport_tls = 1; | ||||||||
2400 | |||||||||
2401 | ai = tport_get_address(tp); | ||||||||
2402 | |||||||||
2403 | for (; ai; ai = ai->ai_next) { | ||||||||
2404 | char host[TPORT_HOSTPORTSIZE(55)] = ""; | ||||||||
2405 | char sport[8]; | ||||||||
2406 | char const *canon = ai->ai_canonname; | ||||||||
2407 | su_sockaddr_t *su = (void *)ai->ai_addr; | ||||||||
2408 | int port; | ||||||||
2409 | |||||||||
2410 | if (su) { | ||||||||
2411 | 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); | ||||||||
2412 | maddr = use_maddr && !su_casematch(canon, host); | ||||||||
2413 | port = ntohs(su->su_portsu_sin.sin_port); | ||||||||
2414 | } | ||||||||
2415 | else { | ||||||||
2416 | msg_random_token(host, 16, NULL((void*)0), 0); | ||||||||
2417 | canon = strcat(host, ".is.invalid"); | ||||||||
2418 | maddr = 0; | ||||||||
2419 | port = 0; | ||||||||
2420 | } | ||||||||
2421 | |||||||||
2422 | if (su_casenmatch(tpn->tpn_proto, "tls", 3) | ||||||||
2423 | ? port == SIPS_DEFAULT_PORTSIPS_DEFAULT_PORT | ||||||||
2424 | : port == SIP_DEFAULT_PORTSIP_DEFAULT_PORT) | ||||||||
2425 | port = 0; | ||||||||
2426 | |||||||||
2427 | snprintf(sport, sizeof sport, ":%u", port); | ||||||||
2428 | |||||||||
2429 | comp = tpn->tpn_comp; | ||||||||
2430 | |||||||||
2431 | 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__ , 2437, "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) | ||||||||
2432 | "%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__ , 2437, "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) | ||||||||
2433 | 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__ , 2437, "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) | ||||||||
2434 | 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__ , 2437, "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) | ||||||||
2435 | 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__ , 2437, "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) | ||||||||
2436 | 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__ , 2437, "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) | ||||||||
2437 | 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__ , 2437, "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); | ||||||||
2438 | |||||||||
2439 | v = sip_via_format(autohome, | ||||||||
2440 | "%s/%s %s%s%s%s%s%s", | ||||||||
2441 | SIP_VERSION_CURRENTsip_version_2_0, tpn->tpn_proto, | ||||||||
2442 | canon, port
| ||||||||
2443 | maddr
| ||||||||
2444 | comp ? ";comp=" : "", comp
| ||||||||
2445 | if (v == NULL((void*)0)) | ||||||||
2446 | goto error; | ||||||||
2447 | |||||||||
2448 | v->v_comment = tpn->tpn_ident; | ||||||||
2449 | assert(v->v_common)((void) sizeof ((v->v_common) ? 1 : 0), __extension__ ({ if (v->v_common) ; else __assert_fail ("v->v_common", "nta.c" , 2449, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
2450 | v->v_common->h_data = tp; /* Nasty trick */ | ||||||||
2451 | *vv = v; vv = &(*vv)->v_next; | ||||||||
2452 | } | ||||||||
2453 | } | ||||||||
2454 | |||||||||
2455 | if (!via
| ||||||||
2456 | SU_DEBUG_9(("nta: agent_init_via failed\n" VA_NONE))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 2456, "nta: agent_init_via failed\n" "%s", "")) : (void)0); | ||||||||
2457 | goto error; | ||||||||
2458 | } | ||||||||
2459 | |||||||||
2460 | /* Duplicate the list bind to the transports */ | ||||||||
2461 | new_via = sip_via_dup(self->sa_home, via); | ||||||||
2462 | /* Duplicate the complete list shown to the application */ | ||||||||
2463 | dup_via = sip_via_dup(self->sa_home, via); | ||||||||
2464 | |||||||||
2465 | if (via
| ||||||||
2466 | msg_header_free(self->sa_home, (void *)new_via); | ||||||||
2467 | msg_header_free(self->sa_home, (void *)dup_via); | ||||||||
2468 | goto error; | ||||||||
2469 | } | ||||||||
2470 | |||||||||
2471 | new_vias = NULL((void*)0), next_new_via = &new_vias; | ||||||||
2472 | new_publics = NULL((void*)0), next_new_public = &new_publics; | ||||||||
2473 | |||||||||
2474 | /* Set via field magic for the tports */ | ||||||||
2475 | for (tp = primaries; tp; tp = tport_next(tp)) { | ||||||||
2476 | assert(via->v_common->h_data == tp)((void) sizeof ((via->v_common->h_data == tp) ? 1 : 0), __extension__ ({ if (via->v_common->h_data == tp) ; else __assert_fail ("via->v_common->h_data == tp", "nta.c", 2476, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
| |||||||||
2477 | v = tport_magic(tp); | ||||||||
2478 | tport_set_magic(tp, new_via); | ||||||||
2479 | msg_header_free(self->sa_home, (void *)v); | ||||||||
2480 | |||||||||
2481 | if (tport_is_public(tp)) | ||||||||
2482 | *next_new_public = dup_via; | ||||||||
2483 | else | ||||||||
2484 | *next_new_via = dup_via; | ||||||||
2485 | |||||||||
2486 | while (via->v_next && via->v_next->v_common->h_data == tp) | ||||||||
2487 | via = via->v_next, new_via = new_via->v_next, dup_via = dup_via->v_next; | ||||||||
2488 | |||||||||
2489 | via = via->v_next; | ||||||||
2490 | /* Break the link in via list between transports */ | ||||||||
2491 | vv = &new_via->v_next, new_via = *vv, *vv = NULL((void*)0); | ||||||||
2492 | vv = &dup_via->v_next, dup_via = *vv, *vv = NULL((void*)0); | ||||||||
2493 | |||||||||
2494 | if (tport_is_public(tp)) | ||||||||
2495 | while (*next_new_public) next_new_public = &(*next_new_public)->v_next; | ||||||||
2496 | else | ||||||||
2497 | while (*next_new_via) next_new_via = &(*next_new_via)->v_next; | ||||||||
2498 | } | ||||||||
2499 | |||||||||
2500 | assert(dup_via == NULL)((void) sizeof ((dup_via == ((void*)0)) ? 1 : 0), __extension__ ({ if (dup_via == ((void*)0)) ; else __assert_fail ("dup_via == NULL" , "nta.c", 2500, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
2501 | assert(new_via == NULL)((void) sizeof ((new_via == ((void*)0)) ? 1 : 0), __extension__ ({ if (new_via == ((void*)0)) ; else __assert_fail ("new_via == NULL" , "nta.c", 2501, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
2502 | |||||||||
2503 | if (self->sa_tport_udp) | ||||||||
2504 | agent_set_udp_params(self, self->sa_udp_mtu); | ||||||||
2505 | |||||||||
2506 | v = self->sa_vias; | ||||||||
2507 | self->sa_vias = new_vias; | ||||||||
2508 | msg_header_free(self->sa_home, (void *)v); | ||||||||
2509 | |||||||||
2510 | v = self->sa_public_vias; | ||||||||
2511 | self->sa_public_vias = new_publics; | ||||||||
2512 | msg_header_free(self->sa_home, (void *)v); | ||||||||
2513 | |||||||||
2514 | su_home_deinit(autohome); | ||||||||
2515 | |||||||||
2516 | return 0; | ||||||||
2517 | |||||||||
2518 | error: | ||||||||
2519 | su_home_deinit(autohome); | ||||||||
2520 | return -1; | ||||||||
2521 | } | ||||||||
2522 | |||||||||
2523 | |||||||||
2524 | /** Initialize main contact header. */ | ||||||||
2525 | static | ||||||||
2526 | int agent_init_contact(nta_agent_t *self) | ||||||||
2527 | { | ||||||||
2528 | sip_via_t const *v1, *v2; | ||||||||
2529 | char const *tp; | ||||||||
2530 | |||||||||
2531 | if (self->sa_contact) | ||||||||
2532 | return 0; | ||||||||
2533 | |||||||||
2534 | for (v1 = self->sa_vias ? self->sa_vias : self->sa_public_vias; | ||||||||
2535 | v1; | ||||||||
2536 | v1 = v1->v_next) { | ||||||||
2537 | if (host_is_ip_address(v1->v_host)) { | ||||||||
2538 | if (!host_is_local(v1->v_host)) | ||||||||
2539 | break; | ||||||||
2540 | } | ||||||||
2541 | else if (!host_has_domain_invalid(v1->v_host)) { | ||||||||
2542 | break; | ||||||||
2543 | } | ||||||||
2544 | } | ||||||||
2545 | |||||||||
2546 | if (v1 == NULL((void*)0)) | ||||||||
2547 | v1 = self->sa_vias ? self->sa_vias : self->sa_public_vias; | ||||||||
2548 | |||||||||
2549 | if (!v1) | ||||||||
2550 | return -1; | ||||||||
2551 | |||||||||
2552 | tp = strrchr(v1->v_protocol, '/'); | ||||||||
2553 | if (!tp++) | ||||||||
2554 | return -1; | ||||||||
2555 | |||||||||
2556 | v2 = v1->v_next; | ||||||||
2557 | |||||||||
2558 | if (v2 && | ||||||||
2559 | su_casematch(v1->v_host, v2->v_host) && | ||||||||
2560 | su_casematch(v1->v_port, v2->v_port)) { | ||||||||
2561 | char const *p1 = v1->v_protocol, *p2 = v2->v_protocol; | ||||||||
2562 | |||||||||
2563 | if (!su_casematch(p1, sip_transport_udp)) | ||||||||
2564 | p1 = v2->v_protocol, p2 = v1->v_protocol; | ||||||||
2565 | |||||||||
2566 | if (su_casematch(p1, sip_transport_udp) && | ||||||||
2567 | su_casematch(p2, sip_transport_tcp)) | ||||||||
2568 | /* Do not include transport if we have both UDP and TCP */ | ||||||||
2569 | tp = NULL((void*)0); | ||||||||
2570 | } | ||||||||
2571 | |||||||||
2572 | self->sa_contact = | ||||||||
2573 | sip_contact_create_from_via_with_transport(self->sa_home, v1, NULL((void*)0), tp); | ||||||||
2574 | |||||||||
2575 | if (!self->sa_contact) | ||||||||
2576 | return -1; | ||||||||
2577 | |||||||||
2578 | agent_tag_init(self); | ||||||||
2579 | |||||||||
2580 | return 0; | ||||||||
2581 | } | ||||||||
2582 | |||||||||
2583 | /** Return @Via line corresponging to tport. */ | ||||||||
2584 | static | ||||||||
2585 | sip_via_t const *agent_tport_via(tport_t *tport) | ||||||||
2586 | { | ||||||||
2587 | sip_via_t *v = tport_magic(tport); | ||||||||
2588 | while (v && v->v_next) | ||||||||
2589 | v = v->v_next; | ||||||||
2590 | return v; | ||||||||
2591 | } | ||||||||
2592 | |||||||||
2593 | /** Insert @Via to a request message */ | ||||||||
2594 | static | ||||||||
2595 | int outgoing_insert_via(nta_outgoing_t *orq, | ||||||||
2596 | sip_via_t const *via) | ||||||||
2597 | { | ||||||||
2598 | nta_agent_t *self = orq->orq_agent; | ||||||||
2599 | msg_t *msg = orq->orq_request; | ||||||||
2600 | sip_t *sip = sip_object(msg); | ||||||||
2601 | char const *branch = orq->orq_via_branch; | ||||||||
2602 | int already = orq->orq_user_via || orq->orq_via_added; | ||||||||
2603 | int user_via = orq->orq_user_via; | ||||||||
2604 | sip_via_t *v; | ||||||||
2605 | int clear = 0; | ||||||||
2606 | |||||||||
2607 | assert(sip)((void) sizeof ((sip) ? 1 : 0), __extension__ ({ if (sip) ; else __assert_fail ("sip", "nta.c", 2607, __extension__ __PRETTY_FUNCTION__ ); })); assert(via)((void) sizeof ((via) ? 1 : 0), __extension__ ({ if (via) ; else __assert_fail ("via", "nta.c", 2607, __extension__ __PRETTY_FUNCTION__ ); })); | ||||||||
2608 | |||||||||
2609 | if (already && sip->sip_via) { | ||||||||
2610 | /* Use existing @Via */ | ||||||||
2611 | v = sip->sip_via; | ||||||||
2612 | } | ||||||||
2613 | else if (msg && via && sip->sip_request && | ||||||||
2614 | (v = sip_via_copy(msg_home(msg)((su_home_t*)(msg)), via))) { | ||||||||
2615 | if (msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)v) < 0) | ||||||||
2616 | return -1; | ||||||||
2617 | orq->orq_via_added = 1; | ||||||||
2618 | } | ||||||||
2619 | else | ||||||||
2620 | return -1; | ||||||||
2621 | |||||||||
2622 | if (!v->v_rport && | ||||||||
2623 | ((self->sa_rport && v->v_protocol == sip_transport_udp) || | ||||||||
2624 | (self->sa_tcp_rport && v->v_protocol == sip_transport_tcp) || | ||||||||
2625 | (self->sa_tls_rport && v->v_protocol == sip_transport_tls))) | ||||||||
2626 | msg_header_add_param(msg_home(msg)((su_home_t*)(msg)), v->v_common, "rport"); | ||||||||
2627 | |||||||||
2628 | if (!orq->orq_tpn->tpn_comp) | ||||||||
2629 | msg_header_remove_param(v->v_common, "comp"); | ||||||||
2630 | |||||||||
2631 | if (branch && branch != v->v_branch) { | ||||||||
2632 | char const *bvalue = branch + strcspn(branch, "="); | ||||||||
2633 | if (*bvalue) bvalue++; | ||||||||
2634 | if (!v->v_branch || !su_casematch(bvalue, v->v_branch)) | ||||||||
2635 | msg_header_replace_param(msg_home(msg)((su_home_t*)(msg)), v->v_common, branch); | ||||||||
2636 | } | ||||||||
2637 | |||||||||
2638 | if (!su_casematch(via->v_protocol, v->v_protocol)) | ||||||||
2639 | clear = 1, v->v_protocol = via->v_protocol; | ||||||||
2640 | |||||||||
2641 | /* XXX - should we do this? */ | ||||||||
2642 | if ((!user_via || !v->v_host) && | ||||||||
2643 | !su_strmatch(via->v_host, v->v_host)) | ||||||||
2644 | clear = 1, v->v_host = via->v_host; | ||||||||
2645 | |||||||||
2646 | if ((!user_via || !v->v_port || | ||||||||
2647 | /* Replace port in user Via only if we use udp and no rport */ | ||||||||
2648 | (v->v_protocol == sip_transport_udp && !v->v_rport && | ||||||||
2649 | !orq->orq_stateless)) && | ||||||||
2650 | !su_strmatch(via->v_port, v->v_port)) | ||||||||
2651 | clear = 1, v->v_port = via->v_port; | ||||||||
2652 | |||||||||
2653 | if (clear) | ||||||||
2654 | msg_fragment_clear(v->v_common); | ||||||||
2655 | |||||||||
2656 | return 0; | ||||||||
2657 | } | ||||||||
2658 | |||||||||
2659 | /** Get destination name from @Via. | ||||||||
2660 | * | ||||||||
2661 | * If @a using_rport is non-null, try rport. | ||||||||
2662 | * If *using_rport is non-zero, try rport even if <protocol> is not UDP. | ||||||||
2663 | * If <protocol> is UDP, set *using_rport to zero. | ||||||||
2664 | */ | ||||||||
2665 | static | ||||||||
2666 | int nta_tpn_by_via(tp_name_t *tpn, sip_via_t const *v, int *using_rport) | ||||||||
2667 | { | ||||||||
2668 | if (!v) | ||||||||
2669 | return -1; | ||||||||
2670 | |||||||||
2671 | tpn->tpn_proto = sip_via_transport(v); | ||||||||
2672 | tpn->tpn_canon = v->v_host; | ||||||||
2673 | |||||||||
2674 | if (v->v_maddr) | ||||||||
2675 | tpn->tpn_host = v->v_maddr; | ||||||||
2676 | else if (v->v_received) | ||||||||
2677 | tpn->tpn_host = v->v_received; | ||||||||
2678 | else | ||||||||
2679 | tpn->tpn_host = v->v_host; | ||||||||
2680 | |||||||||
2681 | tpn->tpn_port = sip_via_port(v, using_rport); | ||||||||
2682 | tpn->tpn_comp = v->v_comp; | ||||||||
2683 | tpn->tpn_ident = NULL((void*)0); | ||||||||
2684 | |||||||||
2685 | return 0; | ||||||||
2686 | } | ||||||||
2687 | |||||||||
2688 | /** Get transport name from URL. */ | ||||||||
2689 | static int | ||||||||
2690 | nta_tpn_by_url(su_home_t *home, | ||||||||
2691 | tp_name_t *tpn, | ||||||||
2692 | char const **scheme, | ||||||||
2693 | char const **port, | ||||||||
2694 | url_string_t const *us) | ||||||||
2695 | { | ||||||||
2696 | url_t url[1]; | ||||||||
2697 | isize_t n; | ||||||||
2698 | char *b; | ||||||||
2699 | |||||||||
2700 | n = url_xtra(us->us_url); | ||||||||
2701 | b = su_alloc(home, n); | ||||||||
2702 | |||||||||
2703 | if (b == NULL((void*)0) || url_dup(b, n, url, us->us_url) < 0) { | ||||||||
2704 | su_free(home, b); | ||||||||
2705 | return -1; | ||||||||
2706 | } | ||||||||
2707 | |||||||||
2708 | if (url->url_type != url_sip && | ||||||||
2709 | url->url_type != url_urn && | ||||||||
2710 | url->url_type != url_sips && | ||||||||
2711 | url->url_type != url_im && | ||||||||
2712 | url->url_type != url_pres) { | ||||||||
2713 | su_free(home, b); | ||||||||
2714 | return -1; | ||||||||
2715 | } | ||||||||
2716 | |||||||||
2717 | 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__ , 2717, "nta: selecting scheme %s\n", url->url_scheme)) : ( void)0); | ||||||||
2718 | |||||||||
2719 | *scheme = url->url_scheme; | ||||||||
2720 | |||||||||
2721 | tpn->tpn_proto = NULL((void*)0); | ||||||||
2722 | tpn->tpn_canon = url->url_host; | ||||||||
2723 | tpn->tpn_host = url->url_host; | ||||||||
2724 | |||||||||
2725 | if (url->url_params) { | ||||||||
2726 | for (b = (char *)url->url_params; b[0]; b += n) { | ||||||||
2727 | n = strcspn(b, ";"); | ||||||||
2728 | |||||||||
2729 | if (n > 10 && su_casenmatch(b, "transport=", 10)) | ||||||||
2730 | tpn->tpn_proto = b + 10; | ||||||||
2731 | else if (n > 5 && su_casenmatch(b, "comp=", 5)) | ||||||||
2732 | tpn->tpn_comp = b + 5; | ||||||||
2733 | else if (n > 6 && su_casenmatch(b, "maddr=", 6)) | ||||||||
2734 | tpn->tpn_host = b + 6; | ||||||||
2735 | |||||||||
2736 | if (b[n]) | ||||||||
2737 | b[n++] = '\0'; | ||||||||
2738 | } | ||||||||
2739 | } | ||||||||
2740 | |||||||||
2741 | if ((*port = url->url_port)) | ||||||||
2742 | tpn->tpn_port = url->url_port; | ||||||||
2743 | |||||||||
2744 | tpn->tpn_ident = NULL((void*)0); | ||||||||
2745 | |||||||||
2746 | if (tpn->tpn_proto) { | ||||||||
2747 | if (su_casematch(url->url_scheme, "sips") && su_casematch(tpn->tpn_proto, "ws")) { | ||||||||
2748 | tpn->tpn_proto = "wss"; | ||||||||
2749 | } | ||||||||
2750 | return 1; | ||||||||
2751 | } | ||||||||
2752 | |||||||||
2753 | if (su_casematch(url->url_scheme, "sips")) | ||||||||
2754 | tpn->tpn_proto = "tls"; | ||||||||
2755 | else | ||||||||
2756 | tpn->tpn_proto = "*"; | ||||||||
2757 | |||||||||
2758 | return 0; | ||||||||
2759 | } | ||||||||
2760 | |||||||||
2761 | /** Handle transport errors. */ | ||||||||
2762 | static | ||||||||
2763 | void agent_tp_error(nta_agent_t *agent, | ||||||||
2764 | tport_t *tport, | ||||||||
2765 | int errcode, | ||||||||
2766 | char const *remote) | ||||||||
2767 | { | ||||||||
2768 | su_llog(nta_log, 1,_su_llog(nta_log, 1, "nta.c", (const char *)__func__, 2771, "nta_agent: tport: %s%s%s\n" , remote ? remote : "", remote ? ": " : "", su_strerror(errcode )) | ||||||||
2769 | "nta_agent: tport: %s%s%s\n",_su_llog(nta_log, 1, "nta.c", (const char *)__func__, 2771, "nta_agent: tport: %s%s%s\n" , remote ? remote : "", remote ? ": " : "", su_strerror(errcode )) | ||||||||
2770 | remote ? remote : "", remote ? ": " : "",_su_llog(nta_log, 1, "nta.c", (const char *)__func__, 2771, "nta_agent: tport: %s%s%s\n" , remote ? remote : "", remote ? ": " : "", su_strerror(errcode )) | ||||||||
2771 | su_strerror(errcode))_su_llog(nta_log, 1, "nta.c", (const char *)__func__, 2771, "nta_agent: tport: %s%s%s\n" , remote ? remote : "", remote ? ": " : "", su_strerror(errcode )); | ||||||||
2772 | |||||||||
2773 | if (agent->sa_error_tport) { | ||||||||
2774 | agent->sa_error_tport(agent->sa_error_magic, agent, tport); | ||||||||
2775 | } | ||||||||
2776 | } | ||||||||
2777 | |||||||||
2778 | /** Handle updated transport addresses */ | ||||||||
2779 | static void agent_update_tport(nta_agent_t *self, tport_t *tport) | ||||||||
2780 | { | ||||||||
2781 | /* Initialize local Vias first */ | ||||||||
2782 | agent_init_via(self, tport_primaries(self->sa_tports), 0); | ||||||||
2783 | |||||||||
2784 | if (self->sa_update_tport) { | ||||||||
2785 | self->sa_update_tport(self->sa_update_magic, self); | ||||||||
2786 | } | ||||||||
2787 | else { | ||||||||
2788 | /* XXX - we should do something else? */ | ||||||||
2789 | 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__ , 2790, "%s(%p): %s\n", "nta", (void *)self, "transport address updated" )) : (void)0) | ||||||||
2790 | "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__ , 2790, "%s(%p): %s\n", "nta", (void *)self, "transport address updated" )) : (void)0); | ||||||||
2791 | } | ||||||||
2792 | } | ||||||||
2793 | |||||||||
2794 | /* ====================================================================== */ | ||||||||
2795 | /* 3) Message dispatch */ | ||||||||
2796 | |||||||||
2797 | static void agent_recv_request(nta_agent_t *agent, | ||||||||
2798 | msg_t *msg, | ||||||||
2799 | sip_t *sip, | ||||||||
2800 | tport_t *tport); | ||||||||
2801 | static int agent_check_request_via(nta_agent_t *agent, | ||||||||
2802 | msg_t *msg, | ||||||||
2803 | sip_t *sip, | ||||||||
2804 | sip_via_t *v, | ||||||||
2805 | tport_t *tport); | ||||||||
2806 | static int agent_aliases(nta_agent_t const *, url_t [], tport_t *); | ||||||||
2807 | static void agent_recv_response(nta_agent_t*, msg_t *, sip_t *, | ||||||||
2808 | sip_via_t *, tport_t*); | ||||||||
2809 | static void agent_recv_garbage(nta_agent_t*, msg_t*, tport_t*); | ||||||||
2810 | |||||||||
2811 | #if HAVE_SOFIA_SRESOLV1 | ||||||||
2812 | static void outgoing_resolve(nta_outgoing_t *orq, | ||||||||
2813 | int explicit_transport, | ||||||||
2814 | enum nta_res_order_e order); | ||||||||
2815 | su_inlinestatic inline void outgoing_cancel_resolver(nta_outgoing_t *orq); | ||||||||
2816 | su_inlinestatic inline void outgoing_destroy_resolver(nta_outgoing_t *orq); | ||||||||
2817 | static int outgoing_other_destinations(nta_outgoing_t const *orq); | ||||||||
2818 | static int outgoing_try_another(nta_outgoing_t *orq); | ||||||||
2819 | #else | ||||||||
2820 | #define outgoing_other_destinations(orq) (0) | ||||||||
2821 | #define outgoing_try_another(orq) (0) | ||||||||
2822 | #endif | ||||||||
2823 | |||||||||
2824 | /** Handle incoming message. */ | ||||||||
2825 | static | ||||||||
2826 | void agent_recv_message(nta_agent_t *agent, | ||||||||
2827 | tport_t *tport, | ||||||||
2828 | msg_t *msg, | ||||||||
2829 | sip_via_t *tport_via, | ||||||||
2830 | su_time_t now) | ||||||||
2831 | { | ||||||||
2832 | sip_t *sip = sip_object(msg); | ||||||||
2833 | |||||||||
2834 | if (sip && sip->sip_request) { | ||||||||
2835 | agent_recv_request(agent, msg, sip, tport); | ||||||||
2836 | } | ||||||||
2837 | else if (sip && sip->sip_status) { | ||||||||
2838 | agent_recv_response(agent, msg, sip, tport_via, tport); | ||||||||
2839 | } | ||||||||
2840 | else { | ||||||||
2841 | agent_recv_garbage(agent, msg, tport); | ||||||||
2842 | } | ||||||||
2843 | } | ||||||||
2844 | |||||||||
2845 | #ifdef HAVE_ZLIB_COMPRESS1 | ||||||||
2846 | int sip_content_encoding_Xflate(msg_t *msg, sip_t *sip, int inflate, int check) | ||||||||
2847 | { | ||||||||
2848 | char const *method_name; | ||||||||
2849 | unsigned cseq = sip->sip_cseq ? sip->sip_cseq->cs_seq : 0; | ||||||||
2850 | int ok = !check; | ||||||||
2851 | |||||||||
2852 | if (!sip->sip_payload) { | ||||||||
2853 | return 0; | ||||||||
2854 | } | ||||||||
2855 | |||||||||
2856 | if (sip->sip_request) { | ||||||||
2857 | method_name = sip->sip_request->rq_method_name; | ||||||||
2858 | } else if (sip->sip_cseq) { | ||||||||
2859 | method_name = sip->sip_cseq->cs_method_name; | ||||||||
2860 | } else { | ||||||||
2861 | method_name = "Unknown"; | ||||||||
2862 | } | ||||||||
2863 | |||||||||
2864 | if (!ok) { | ||||||||
2865 | if (sip->sip_content_encoding && sip->sip_content_encoding->k_items) { | ||||||||
2866 | const char *val = sip->sip_content_encoding->k_items[0]; | ||||||||
2867 | if (val && (!strcasecmp(val, "gzip") || !strcasecmp(val, "deflate"))) { | ||||||||
2868 | ok = 1; | ||||||||
2869 | } | ||||||||
2870 | } | ||||||||
2871 | } | ||||||||
2872 | |||||||||
2873 | if (ok) { | ||||||||
2874 | unsigned long n = 0; | ||||||||
2875 | void *decoded = NULL((void*)0); | ||||||||
2876 | const char *id = "N/A"; | ||||||||
2877 | const char *orig_payload = sip->sip_payload->pl_data; | ||||||||
2878 | |||||||||
2879 | n = sip->sip_payload->pl_len * 10; | ||||||||
2880 | |||||||||
2881 | decoded = su_alloc(msg_home(msg)((su_home_t*)(msg)), n); | ||||||||
2882 | assert(decoded)((void) sizeof ((decoded) ? 1 : 0), __extension__ ({ if (decoded ) ; else __assert_fail ("decoded", "nta.c", 2882, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
2883 | |||||||||
2884 | if (inflate) { | ||||||||
2885 | uncompress(decoded, &n, (void *)sip->sip_payload->pl_data, (unsigned long)sip->sip_payload->pl_len); | ||||||||
2886 | } else { | ||||||||
2887 | compress(decoded, &n, (void *)sip->sip_payload->pl_data, (unsigned long)sip->sip_payload->pl_len); | ||||||||
2888 | } | ||||||||
2889 | |||||||||
2890 | sip->sip_payload = sip_payload_create(msg_home(msg)((su_home_t*)(msg)), decoded, n); | ||||||||
2891 | sip->sip_content_encoding = sip_content_encoding_make(msg_home(msg)((su_home_t*)(msg)), "deflate"); | ||||||||
2892 | |||||||||
2893 | if (sip->sip_call_id) { | ||||||||
2894 | id = sip->sip_call_id->i_id; | ||||||||
2895 | } | ||||||||
2896 | |||||||||
2897 | if (inflate) { | ||||||||
2898 | 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__ , 2898, "nta: %s (%u) (%s) Inflating compressed body:\n%s\n", method_name, cseq, id, (char *)decoded)) : (void)0); | ||||||||
2899 | } else { | ||||||||
2900 | 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__ , 2900, "nta: %s (%u) (%s) Deflating compressed body:\n%s\n", method_name, cseq, id, orig_payload)) : (void)0); | ||||||||
2901 | } | ||||||||
2902 | |||||||||
2903 | return 1; | ||||||||
2904 | } | ||||||||
2905 | |||||||||
2906 | return 0; | ||||||||
2907 | } | ||||||||
2908 | #endif | ||||||||
2909 | |||||||||
2910 | /** @internal Handle incoming requests. */ | ||||||||
2911 | static | ||||||||
2912 | void agent_recv_request(nta_agent_t *agent, | ||||||||
2913 | msg_t *msg, | ||||||||
2914 | sip_t *sip, | ||||||||
2915 | tport_t *tport) | ||||||||
2916 | { | ||||||||
2917 | nta_leg_t *leg; | ||||||||
2918 | nta_incoming_t *irq, *merge = NULL((void*)0), *ack = NULL((void*)0), *cancel = NULL((void*)0); | ||||||||
2919 | sip_method_t method = sip->sip_request->rq_method; | ||||||||
2920 | char const *method_name = sip->sip_request->rq_method_name; | ||||||||
2921 | url_t url[1]; | ||||||||
2922 | unsigned cseq = sip->sip_cseq ? sip->sip_cseq->cs_seq : 0; | ||||||||
2923 | int insane, errors, stream; | ||||||||
2924 | unsigned compressed = 0; | ||||||||
2925 | su_duration_t sa_load_elapsed_ms = su_duration(su_now(), agent->sa_load->last_time); | ||||||||
2926 | |||||||||
2927 | agent->sa_stats->as_recv_msg++; | ||||||||
2928 | agent->sa_stats->as_recv_request++; | ||||||||
2929 | |||||||||
2930 | if (agent->sa_load->requests_per_second == 0) agent->sa_load->requests_per_second = 1; | ||||||||
2931 | |||||||||
2932 | if (sa_load_elapsed_ms >= 1000) { | ||||||||
2933 | if (agent->sa_load->as_recv_request_last) { | ||||||||
2934 | agent->sa_load->requests_per_second = ((agent->sa_stats->as_recv_request - agent->sa_load->as_recv_request_last) * 1000) / sa_load_elapsed_ms; | ||||||||
2935 | } | ||||||||
2936 | |||||||||
2937 | /** Update */ | ||||||||
2938 | agent->sa_load->last_time = su_now(); | ||||||||
2939 | agent->sa_load->as_recv_request_last = agent->sa_stats->as_recv_request; | ||||||||
2940 | |||||||||
2941 | if (agent->sa_max_recv_requests_per_second && agent->sa_load->requests_per_second > agent->sa_max_recv_requests_per_second) { | ||||||||
2942 | SU_DEBUG_5(("SIP flood: Dropped %u incoming SIP messages, %u message / sec (of %u allowed)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 2943, "SIP flood: Dropped %u incoming SIP messages, %u message / sec (of %u allowed)\n" , agent->sa_stats->as_drop_request + 1, agent->sa_load ->requests_per_second, agent->sa_max_recv_requests_per_second )) : (void)0) | ||||||||
2943 | agent->sa_stats->as_drop_request + 1, agent->sa_load->requests_per_second, agent->sa_max_recv_requests_per_second))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 2943, "SIP flood: Dropped %u incoming SIP messages, %u message / sec (of %u allowed)\n" , agent->sa_stats->as_drop_request + 1, agent->sa_load ->requests_per_second, agent->sa_max_recv_requests_per_second )) : (void)0); | ||||||||
2944 | } | ||||||||
2945 | |||||||||
2946 | } else if (sa_load_elapsed_ms == -SU_DURATION_MAXSU_DURATION_MAX) { | ||||||||
2947 | /** Initialize */ | ||||||||
2948 | agent->sa_load->last_time = su_now(); | ||||||||
2949 | agent->sa_load->as_recv_request_last = agent->sa_stats->as_recv_request; | ||||||||
2950 | } | ||||||||
2951 | |||||||||
2952 | if (agent->sa_max_recv_requests_per_second && agent->sa_load->requests_per_second > agent->sa_max_recv_requests_per_second) { | ||||||||
2953 | agent->sa_stats->as_drop_request++; | ||||||||
2954 | msg_destroy(msg); | ||||||||
2955 | return; | ||||||||
2956 | } | ||||||||
2957 | |||||||||
2958 | SU_DEBUG_5(("nta: received %s " URL_PRINT_FORMAT " %s (CSeq %u) (load: %u rps)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 2961, "nta: received %s " "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" " %s (CSeq %u) (load: %u rps)\n", method_name, (sip->sip_request ->rq_url)->url_scheme ? (sip->sip_request->rq_url )->url_scheme : "", (sip->sip_request->rq_url)->url_type != url_any && (sip->sip_request->rq_url)->url_scheme && (sip->sip_request->rq_url)->url_scheme[0 ] ? ":" : "", (sip->sip_request->rq_url)->url_root && ((sip->sip_request->rq_url)->url_host || (sip->sip_request ->rq_url)->url_user) ? "//" : "", (sip->sip_request-> rq_url)->url_user ? (sip->sip_request->rq_url)->url_user : "", (sip->sip_request->rq_url)->url_user && (sip->sip_request->rq_url)->url_password ? ":" : "" , (sip->sip_request->rq_url)->url_user && (sip ->sip_request->rq_url)->url_password ? (sip->sip_request ->rq_url)->url_password : "", (sip->sip_request-> rq_url)->url_user && (sip->sip_request->rq_url )->url_host ? "@" : "", (sip->sip_request->rq_url)-> url_host ? (sip->sip_request->rq_url)->url_host : "" , (sip->sip_request->rq_url)->url_host && (sip ->sip_request->rq_url)->url_port ? ":" : "", (sip-> sip_request->rq_url)->url_host && (sip->sip_request ->rq_url)->url_port ? (sip->sip_request->rq_url)-> url_port : "", (sip->sip_request->rq_url)->url_root && (sip->sip_request->rq_url)->url_path ? "/" : "", (sip ->sip_request->rq_url)->url_path ? (sip->sip_request ->rq_url)->url_path : "", (sip->sip_request->rq_url )->url_params ? ";" : "", (sip->sip_request->rq_url) ->url_params ? (sip->sip_request->rq_url)->url_params : "", (sip->sip_request->rq_url)->url_headers ? "?" : "", (sip->sip_request->rq_url)->url_headers ? (sip ->sip_request->rq_url)->url_headers : "", (sip->sip_request ->rq_url)->url_fragment ? "#" : "", (sip->sip_request ->rq_url)->url_fragment ? (sip->sip_request->rq_url )->url_fragment : "", sip->sip_request->rq_version, cseq , agent->sa_load->requests_per_second)) : (void)0) | ||||||||
2959 | 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__ , 2961, "nta: received %s " "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" " %s (CSeq %u) (load: %u rps)\n", method_name, (sip->sip_request ->rq_url)->url_scheme ? (sip->sip_request->rq_url )->url_scheme : "", (sip->sip_request->rq_url)->url_type != url_any && (sip->sip_request->rq_url)->url_scheme && (sip->sip_request->rq_url)->url_scheme[0 ] ? ":" : "", (sip->sip_request->rq_url)->url_root && ((sip->sip_request->rq_url)->url_host || (sip->sip_request ->rq_url)->url_user) ? "//" : "", (sip->sip_request-> rq_url)->url_user ? (sip->sip_request->rq_url)->url_user : "", (sip->sip_request->rq_url)->url_user && (sip->sip_request->rq_url)->url_password ? ":" : "" , (sip->sip_request->rq_url)->url_user && (sip ->sip_request->rq_url)->url_password ? (sip->sip_request ->rq_url)->url_password : "", (sip->sip_request-> rq_url)->url_user && (sip->sip_request->rq_url )->url_host ? "@" : "", (sip->sip_request->rq_url)-> url_host ? (sip->sip_request->rq_url)->url_host : "" , (sip->sip_request->rq_url)->url_host && (sip ->sip_request->rq_url)->url_port ? ":" : "", (sip-> sip_request->rq_url)->url_host && (sip->sip_request ->rq_url)->url_port ? (sip->sip_request->rq_url)-> url_port : "", (sip->sip_request->rq_url)->url_root && (sip->sip_request->rq_url)->url_path ? "/" : "", (sip ->sip_request->rq_url)->url_path ? (sip->sip_request ->rq_url)->url_path : "", (sip->sip_request->rq_url )->url_params ? ";" : "", (sip->sip_request->rq_url) ->url_params ? (sip->sip_request->rq_url)->url_params : "", (sip->sip_request->rq_url)->url_headers ? "?" : "", (sip->sip_request->rq_url)->url_headers ? (sip ->sip_request->rq_url)->url_headers : "", (sip->sip_request ->rq_url)->url_fragment ? "#" : "", (sip->sip_request ->rq_url)->url_fragment ? (sip->sip_request->rq_url )->url_fragment : "", sip->sip_request->rq_version, cseq , agent->sa_load->requests_per_second)) : (void)0) | ||||||||
2960 | 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__ , 2961, "nta: received %s " "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" " %s (CSeq %u) (load: %u rps)\n", method_name, (sip->sip_request ->rq_url)->url_scheme ? (sip->sip_request->rq_url )->url_scheme : "", (sip->sip_request->rq_url)->url_type != url_any && (sip->sip_request->rq_url)->url_scheme && (sip->sip_request->rq_url)->url_scheme[0 ] ? ":" : "", (sip->sip_request->rq_url)->url_root && ((sip->sip_request->rq_url)->url_host || (sip->sip_request ->rq_url)->url_user) ? "//" : "", (sip->sip_request-> rq_url)->url_user ? (sip->sip_request->rq_url)->url_user : "", (sip->sip_request->rq_url)->url_user && (sip->sip_request->rq_url)->url_password ? ":" : "" , (sip->sip_request->rq_url)->url_user && (sip ->sip_request->rq_url)->url_password ? (sip->sip_request ->rq_url)->url_password : "", (sip->sip_request-> rq_url)->url_user && (sip->sip_request->rq_url )->url_host ? "@" : "", (sip->sip_request->rq_url)-> url_host ? (sip->sip_request->rq_url)->url_host : "" , (sip->sip_request->rq_url)->url_host && (sip ->sip_request->rq_url)->url_port ? ":" : "", (sip-> sip_request->rq_url)->url_host && (sip->sip_request ->rq_url)->url_port ? (sip->sip_request->rq_url)-> url_port : "", (sip->sip_request->rq_url)->url_root && (sip->sip_request->rq_url)->url_path ? "/" : "", (sip ->sip_request->rq_url)->url_path ? (sip->sip_request ->rq_url)->url_path : "", (sip->sip_request->rq_url )->url_params ? ";" : "", (sip->sip_request->rq_url) ->url_params ? (sip->sip_request->rq_url)->url_params : "", (sip->sip_request->rq_url)->url_headers ? "?" : "", (sip->sip_request->rq_url)->url_headers ? (sip ->sip_request->rq_url)->url_headers : "", (sip->sip_request ->rq_url)->url_fragment ? "#" : "", (sip->sip_request ->rq_url)->url_fragment ? (sip->sip_request->rq_url )->url_fragment : "", sip->sip_request->rq_version, cseq , agent->sa_load->requests_per_second)) : (void)0) | ||||||||
2961 | sip->sip_request->rq_version, cseq, agent->sa_load->requests_per_second))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 2961, "nta: received %s " "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" " %s (CSeq %u) (load: %u rps)\n", method_name, (sip->sip_request ->rq_url)->url_scheme ? (sip->sip_request->rq_url )->url_scheme : "", (sip->sip_request->rq_url)->url_type != url_any && (sip->sip_request->rq_url)->url_scheme && (sip->sip_request->rq_url)->url_scheme[0 ] ? ":" : "", (sip->sip_request->rq_url)->url_root && ((sip->sip_request->rq_url)->url_host || (sip->sip_request ->rq_url)->url_user) ? "//" : "", (sip->sip_request-> rq_url)->url_user ? (sip->sip_request->rq_url)->url_user : "", (sip->sip_request->rq_url)->url_user && (sip->sip_request->rq_url)->url_password ? ":" : "" , (sip->sip_request->rq_url)->url_user && (sip ->sip_request->rq_url)->url_password ? (sip->sip_request ->rq_url)->url_password : "", (sip->sip_request-> rq_url)->url_user && (sip->sip_request->rq_url )->url_host ? "@" : "", (sip->sip_request->rq_url)-> url_host ? (sip->sip_request->rq_url)->url_host : "" , (sip->sip_request->rq_url)->url_host && (sip ->sip_request->rq_url)->url_port ? ":" : "", (sip-> sip_request->rq_url)->url_host && (sip->sip_request ->rq_url)->url_port ? (sip->sip_request->rq_url)-> url_port : "", (sip->sip_request->rq_url)->url_root && (sip->sip_request->rq_url)->url_path ? "/" : "", (sip ->sip_request->rq_url)->url_path ? (sip->sip_request ->rq_url)->url_path : "", (sip->sip_request->rq_url )->url_params ? ";" : "", (sip->sip_request->rq_url) ->url_params ? (sip->sip_request->rq_url)->url_params : "", (sip->sip_request->rq_url)->url_headers ? "?" : "", (sip->sip_request->rq_url)->url_headers ? (sip ->sip_request->rq_url)->url_headers : "", (sip->sip_request ->rq_url)->url_fragment ? "#" : "", (sip->sip_request ->rq_url)->url_fragment ? (sip->sip_request->rq_url )->url_fragment : "", sip->sip_request->rq_version, cseq , agent->sa_load->requests_per_second)) : (void)0); | ||||||||
2962 | |||||||||
2963 | if (agent->sa_drop_prob && !tport_is_reliable(tport)) { | ||||||||
2964 | if ((unsigned)su_randint(0, 1000) < agent->sa_drop_prob) { | ||||||||
2965 | 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__ , 2966, "nta: %s (%u) is %s\n", method_name, cseq, "dropped simulating packet loss" )) : (void)0) | ||||||||
2966 | 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__ , 2966, "nta: %s (%u) is %s\n", method_name, cseq, "dropped simulating packet loss" )) : (void)0); | ||||||||
2967 | agent->sa_stats->as_drop_request++; | ||||||||
2968 | msg_destroy(msg); | ||||||||
2969 | return; | ||||||||
2970 | } | ||||||||
2971 | } | ||||||||
2972 | |||||||||
2973 | stream = tport_is_stream(tport); | ||||||||
2974 | |||||||||
2975 | /* Try to use compression on reverse direction if @Via has comp=sigcomp */ | ||||||||
2976 | if (stream && | ||||||||
2977 | sip->sip_via && sip->sip_via->v_comp && | ||||||||
2978 | tport_can_send_sigcomp(tport) && | ||||||||
2979 | tport_name(tport)->tpn_comp == NULL((void*)0) && | ||||||||
2980 | tport_has_compression(tport_parent(tport), sip->sip_via->v_comp)) { | ||||||||
2981 | tport_set_compression(tport, sip->sip_via->v_comp); | ||||||||
2982 | } | ||||||||
2983 | |||||||||
2984 | if (sip->sip_flags & MSG_FLG_TOOLARGE) { | ||||||||
2985 | 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__ , 2986, "nta: %s (%u) is %s\n", method_name, cseq, sip_413_Request_too_large )) : (void)0) | ||||||||
2986 | 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__ , 2986, "nta: %s (%u) is %s\n", method_name, cseq, sip_413_Request_too_large )) : (void)0); | ||||||||
2987 | agent->sa_stats->as_bad_request++; | ||||||||
2988 | mreply(agent, NULL((void*)0), SIP_413_REQUEST_TOO_LARGE413, sip_413_Request_too_large, msg, | ||||||||
2989 | tport, 1, stream, NULL((void*)0), | ||||||||
2990 | TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
2991 | return; | ||||||||
2992 | } | ||||||||
2993 | |||||||||
2994 | insane = 0; | ||||||||
2995 | |||||||||
2996 | if (agent->sa_bad_req_mask != ~0U) | ||||||||
2997 | errors = msg_extract_errors(msg) & agent->sa_bad_req_mask; | ||||||||
2998 | else | ||||||||
2999 | errors = sip->sip_error != NULL((void*)0); | ||||||||
3000 | |||||||||
3001 | if (errors || | ||||||||
3002 | (sip->sip_flags & MSG_FLG_ERROR) /* Fatal error */ || | ||||||||
3003 | (insane = (sip_sanity_check(sip) < 0))) { | ||||||||
3004 | sip_header_t const *h; | ||||||||
3005 | char const *badname = NULL((void*)0), *phrase; | ||||||||
3006 | |||||||||
3007 | agent->sa_stats->as_bad_message++; | ||||||||
3008 | agent->sa_stats->as_bad_request++; | ||||||||
3009 | |||||||||
3010 | if (insane) | ||||||||
3011 | 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__ , 3012, "nta: %s (%u) %s\n", method_name, cseq, "failed sanity check" )) : (void)0) | ||||||||
3012 | "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__ , 3012, "nta: %s (%u) %s\n", method_name, cseq, "failed sanity check" )) : (void)0); | ||||||||
3013 | |||||||||
3014 | for (h = (sip_header_t const *)sip->sip_error; h; h = h->sh_nextsh_header_next->shn_next) { | ||||||||
3015 | char const *bad; | ||||||||
3016 | |||||||||
3017 | if (h->sh_classsh_common->h_class == sip_error_class) | ||||||||
3018 | bad = h->sh_error->er_name; | ||||||||
3019 | else | ||||||||
3020 | bad = h->sh_classsh_common->h_class->hc_name; | ||||||||
3021 | |||||||||
3022 | if (bad) | ||||||||
3023 | 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__ , 3023, "nta: %s has bad %s header\n", method_name, bad)) : ( void)0); | ||||||||
3024 | |||||||||
3025 | if (!badname) | ||||||||
3026 | badname = bad; | ||||||||
3027 | } | ||||||||
3028 | |||||||||
3029 | if (sip->sip_via && method != sip_method_ack) { | ||||||||
3030 | msg_t *reply = nta_msg_create(agent, 0); | ||||||||
3031 | |||||||||
3032 | agent_check_request_via(agent, msg, sip, sip->sip_via, tport); | ||||||||
3033 | |||||||||
3034 | if (badname && reply) | ||||||||
3035 | phrase = su_sprintf(msg_home(reply)((su_home_t*)(reply)), "Bad %s Header", badname); | ||||||||
3036 | else | ||||||||
3037 | phrase = sip_400_Bad_request; | ||||||||
3038 | |||||||||
3039 | 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__ , 3039, "nta: %s (%u) is %s\n", method_name, cseq, phrase)) : (void)0); | ||||||||
3040 | |||||||||
3041 | mreply(agent, reply, 400, phrase, msg, | ||||||||
3042 | tport, 1, stream, NULL((void*)0), | ||||||||
3043 | TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
3044 | } | ||||||||
3045 | else { | ||||||||
3046 | msg_destroy(msg); | ||||||||
3047 | if (stream) /* Send FIN */ | ||||||||
3048 | tport_shutdown(tport, 1); | ||||||||
3049 | } | ||||||||
3050 | |||||||||
3051 | return; | ||||||||
3052 | } | ||||||||
3053 | |||||||||
3054 | if (!su_casematch(sip->sip_request->rq_version, sip_version_2_0)) { | ||||||||
3055 | agent->sa_stats->as_bad_request++; | ||||||||
3056 | agent->sa_stats->as_bad_message++; | ||||||||
3057 | |||||||||
3058 | 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__ , 3059, "nta: bad version %s for %s (%u)\n", sip->sip_request ->rq_version, method_name, cseq)) : (void)0) | ||||||||
3059 | 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__ , 3059, "nta: bad version %s for %s (%u)\n", sip->sip_request ->rq_version, method_name, cseq)) : (void)0); | ||||||||
3060 | |||||||||
3061 | mreply(agent, NULL((void*)0), SIP_505_VERSION_NOT_SUPPORTED505, sip_505_Version_not_supported, msg, | ||||||||
3062 | tport, 0, stream, NULL((void*)0), | ||||||||
3063 | TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
3064 | |||||||||
3065 | return; | ||||||||
3066 | } | ||||||||
3067 | |||||||||
3068 | if (agent_check_request_via(agent, msg, sip, sip->sip_via, tport) < 0) { | ||||||||
3069 | agent->sa_stats->as_bad_message++; | ||||||||
3070 | agent->sa_stats->as_bad_request++; | ||||||||
3071 | 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__ , 3071, "nta: %s (%u) %s\n", method_name, cseq, "has invalid Via" )) : (void)0); | ||||||||
3072 | msg_destroy(msg); | ||||||||
3073 | return; | ||||||||
3074 | } | ||||||||
3075 | |||||||||
3076 | #ifdef HAVE_ZLIB_COMPRESS1 | ||||||||
3077 | compressed = sip_content_encoding_Xflate(msg, sip, 1, 1); | ||||||||
3078 | #endif | ||||||||
3079 | |||||||||
3080 | /* First, try existing incoming requests */ | ||||||||
3081 | irq = incoming_find(agent, sip, sip->sip_via, | ||||||||
3082 | agent->sa_merge_482 && | ||||||||
3083 | !sip->sip_to->a_tag && | ||||||||
3084 | method != sip_method_ack | ||||||||
3085 | ? &merge | ||||||||
3086 | : NULL((void*)0), | ||||||||
3087 | method == sip_method_ack ? &ack : NULL((void*)0), | ||||||||
3088 | method == sip_method_cancel ? &cancel : NULL((void*)0)); | ||||||||
3089 | |||||||||
3090 | if (irq) { | ||||||||
3091 | /* Match - this is a retransmission */ | ||||||||
3092 | 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__ , 3093, "nta: %s (%u) going to existing %s transaction\n", method_name , cseq, irq->irq_rq->rq_method_name)) : (void)0) | ||||||||
3093 | 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__ , 3093, "nta: %s (%u) going to existing %s transaction\n", method_name , cseq, irq->irq_rq->rq_method_name)) : (void)0); | ||||||||
3094 | if (incoming_recv(irq, msg, sip, tport) >= 0) | ||||||||
3095 | return; | ||||||||
3096 | } | ||||||||
3097 | else if (ack) { | ||||||||
3098 | 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__ , 3100, "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) | ||||||||
3099 | 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__ , 3100, "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) | ||||||||
3100 | 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__ , 3100, "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); | ||||||||
3101 | if (incoming_ack(ack, msg, sip, tport) >= 0) | ||||||||
3102 | return; | ||||||||
3103 | } | ||||||||
3104 | else if (cancel) { | ||||||||
3105 | 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__ , 3107, "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) | ||||||||
3106 | method_name, cseq,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3107, "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) | ||||||||
3107 | 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__ , 3107, "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); | ||||||||
3108 | if (incoming_cancel(cancel, msg, sip, tport) >= 0) | ||||||||
3109 | return; | ||||||||
3110 | } | ||||||||
3111 | else if (merge) { | ||||||||
3112 | 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__ , 3113, "nta: %s (%u) %s\n", method_name, cseq, "is a merged request" )) : (void)0) | ||||||||
3113 | 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__ , 3113, "nta: %s (%u) %s\n", method_name, cseq, "is a merged request" )) : (void)0); | ||||||||
3114 | request_merge(agent, msg, sip, tport, merge->irq_tag); | ||||||||
3115 | return; | ||||||||
3116 | } | ||||||||
3117 | |||||||||
3118 | if (method == sip_method_prack && sip->sip_rack) { | ||||||||
3119 | nta_reliable_t *rel = reliable_find(agent, sip); | ||||||||
3120 | if (rel) { | ||||||||
3121 | 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__ , 3124, "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) | ||||||||
3122 | 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__ , 3124, "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) | ||||||||
3123 | 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__ , 3124, "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) | ||||||||
3124 | 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__ , 3124, "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); | ||||||||
3125 | reliable_recv(rel, msg, sip, tport); | ||||||||
3126 | return; | ||||||||
3127 | } | ||||||||
3128 | } | ||||||||
3129 | |||||||||
3130 | *url = *sip->sip_request->rq_url; | ||||||||
3131 | url->url_params = NULL((void*)0); | ||||||||
3132 | agent_aliases(agent, url, tport); /* canonize urls */ | ||||||||
3133 | |||||||||
3134 | if (method != sip_method_subscribe && (leg = leg_find(agent, | ||||||||
3135 | method_name, url, | ||||||||
3136 | sip->sip_call_id, | ||||||||
3137 | sip->sip_from->a_tag, | ||||||||
3138 | sip->sip_to->a_tag))) { | ||||||||
3139 | /* Try existing dialog */ | ||||||||
3140 | 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__ , 3141, "nta: %s (%u) %s\n", method_name, cseq, "going to existing leg" )) : (void)0) | ||||||||
3141 | 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__ , 3141, "nta: %s (%u) %s\n", method_name, cseq, "going to existing leg" )) : (void)0); | ||||||||
3142 | leg->leg_compressed = compressed; | ||||||||
3143 | leg_recv(leg, msg, sip, tport); | ||||||||
3144 | return; | ||||||||
3145 | } | ||||||||
3146 | else if (!agent->sa_is_stateless && | ||||||||
3147 | (leg = dst_find(agent, url, method_name))) { | ||||||||
3148 | /* Dialogless legs - let application process transactions statefully */ | ||||||||
3149 | 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__ , 3150, "nta: %s (%u) %s\n", method_name, cseq, "going to a dialogless leg" )) : (void)0) | ||||||||
3150 | 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__ , 3150, "nta: %s (%u) %s\n", method_name, cseq, "going to a dialogless leg" )) : (void)0); | ||||||||
3151 | leg->leg_compressed = compressed; | ||||||||
3152 | leg_recv(leg, msg, sip, tport); | ||||||||
3153 | } | ||||||||
3154 | else if (!agent->sa_is_stateless && (leg = agent->sa_default_leg)) { | ||||||||
3155 | if (method == sip_method_invite && | ||||||||
3156 | agent->sa_in.proceeding->q_length >= agent->sa_max_proceeding) { | ||||||||
3157 | 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__ , 3158, "nta: proceeding queue full for %s (%u)\n", method_name , cseq)) : (void)0) | ||||||||
3158 | 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__ , 3158, "nta: proceeding queue full for %s (%u)\n", method_name , cseq)) : (void)0); | ||||||||
3159 | mreply(agent, NULL((void*)0), SIP_503_SERVICE_UNAVAILABLE503, sip_503_Service_unavailable, msg, | ||||||||
3160 | tport, 0, 0, NULL((void*)0), | ||||||||
3161 | TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
3162 | return; | ||||||||
3163 | } | ||||||||
3164 | else { | ||||||||
3165 | 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__ , 3166, "nta: %s (%u) %s\n", method_name, cseq, "going to a default leg" )) : (void)0) | ||||||||
3166 | 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__ , 3166, "nta: %s (%u) %s\n", method_name, cseq, "going to a default leg" )) : (void)0); | ||||||||
3167 | leg->leg_compressed = compressed; | ||||||||
3168 | leg_recv(leg, msg, sip, tport); | ||||||||
3169 | } | ||||||||
3170 | } | ||||||||
3171 | else if (agent->sa_callback) { | ||||||||
3172 | /* Stateless processing for request */ | ||||||||
3173 | agent->sa_stats->as_trless_request++; | ||||||||
3174 | 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__ , 3175, "nta: %s (%u) %s\n", method_name, cseq, "to message callback" )) : (void)0) | ||||||||
3175 | 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__ , 3175, "nta: %s (%u) %s\n", method_name, cseq, "to message callback" )) : (void)0); | ||||||||
3176 | (void)agent->sa_callback(agent->sa_magic, agent, msg, sip); | ||||||||
3177 | } | ||||||||
3178 | else { | ||||||||
3179 | agent->sa_stats->as_trless_request++; | ||||||||
3180 | 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__ , 3182, "nta: %s (%u) %s\n", method_name, cseq, "not processed by application: returning 501" )) : (void)0) | ||||||||
3181 | 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__ , 3182, "nta: %s (%u) %s\n", method_name, cseq, "not processed by application: returning 501" )) : (void)0) | ||||||||
3182 | "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__ , 3182, "nta: %s (%u) %s\n", method_name, cseq, "not processed by application: returning 501" )) : (void)0); | ||||||||
3183 | if (method != sip_method_ack) | ||||||||
3184 | mreply(agent, NULL((void*)0), SIP_501_NOT_IMPLEMENTED501, sip_501_Not_implemented, msg, | ||||||||
3185 | tport, 0, 0, NULL((void*)0), | ||||||||
3186 | TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
3187 | else | ||||||||
3188 | msg_destroy(msg); | ||||||||
3189 | } | ||||||||
3190 | } | ||||||||
3191 | |||||||||
3192 | /** Check @Via header. | ||||||||
3193 | * | ||||||||
3194 | */ | ||||||||
3195 | static | ||||||||
3196 | int agent_check_request_via(nta_agent_t *agent, | ||||||||
3197 | msg_t *msg, | ||||||||
3198 | sip_t *sip, | ||||||||
3199 | sip_via_t *v, | ||||||||
3200 | tport_t *tport) | ||||||||
3201 | { | ||||||||
3202 | enum { receivedlen = sizeof("received=") - 1 }; | ||||||||
3203 | char received[receivedlen + TPORT_HOSTPORTSIZE(55)]; | ||||||||
3204 | char *hostport = received + receivedlen; | ||||||||
3205 | char const *rport; | ||||||||
3206 | su_sockaddr_t const *from; | ||||||||
3207 | sip_via_t const *tpv = agent_tport_via(tport); | ||||||||
3208 | |||||||||
3209 | assert(tport)((void) sizeof ((tport) ? 1 : 0), __extension__ ({ if (tport) ; else __assert_fail ("tport", "nta.c", 3209, __extension__ __PRETTY_FUNCTION__ ); })); assert(msg)((void) sizeof ((msg) ? 1 : 0), __extension__ ({ if (msg) ; else __assert_fail ("msg", "nta.c", 3209, __extension__ __PRETTY_FUNCTION__ ); })); assert(sip)((void) sizeof ((sip) ? 1 : 0), __extension__ ({ if (sip) ; else __assert_fail ("sip", "nta.c", 3209, __extension__ __PRETTY_FUNCTION__ ); })); | ||||||||
3210 | assert(sip->sip_request)((void) sizeof ((sip->sip_request) ? 1 : 0), __extension__ ({ if (sip->sip_request) ; else __assert_fail ("sip->sip_request" , "nta.c", 3210, __extension__ __PRETTY_FUNCTION__); })); assert(tpv)((void) sizeof ((tpv) ? 1 : 0), __extension__ ({ if (tpv) ; else __assert_fail ("tpv", "nta.c", 3210, __extension__ __PRETTY_FUNCTION__ ); })); | ||||||||
3211 | |||||||||
3212 | from = msg_addr(msg); | ||||||||
3213 | |||||||||
3214 | if (v == NULL((void*)0)) { | ||||||||
3215 | /* Make up a via line */ | ||||||||
3216 | v = sip_via_format(msg_home(msg)((su_home_t*)(msg)), "SIP/2.0/%s %s", | ||||||||
3217 | tport_name(tport)->tpn_proto, | ||||||||
3218 | tport_hostport(hostport, TPORT_HOSTPORTSIZE(55), from, 1)); | ||||||||
3219 | msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)v); | ||||||||
3220 | |||||||||
3221 | return v ? 0 : -1; | ||||||||
3222 | } | ||||||||
3223 | |||||||||
3224 | if (!su_strmatch(v->v_protocol, tpv->v_protocol)) { | ||||||||
3225 | tport_hostport(hostport, TPORT_HOSTPORTSIZE(55), from, 1); | ||||||||
3226 | 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__ , 3227, "nta: Via check: invalid transport \"%s\" from %s\n", v->v_protocol, hostport)) : (void)0) | ||||||||
3227 | 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__ , 3227, "nta: Via check: invalid transport \"%s\" from %s\n", v->v_protocol, hostport)) : (void)0); | ||||||||
3228 | return -1; | ||||||||
3229 | } | ||||||||
3230 | |||||||||
3231 | if (v->v_received) { | ||||||||
3232 | /* Nasty, nasty */ | ||||||||
3233 | tport_hostport(hostport, TPORT_HOSTPORTSIZE(55), from, 1); | ||||||||
3234 | 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__ , 3235, "nta: Via check: extra received=%s from %s\n", v-> v_received, hostport)) : (void)0) | ||||||||
3235 | 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__ , 3235, "nta: Via check: extra received=%s from %s\n", v-> v_received, hostport)) : (void)0); | ||||||||
3236 | msg_header_remove_param(v->v_common, "received"); | ||||||||
3237 | } | ||||||||
3238 | |||||||||
3239 | if (!tport_hostport(hostport, TPORT_HOSTPORTSIZE(55), from, 0)) | ||||||||
3240 | return -1; | ||||||||
3241 | |||||||||
3242 | if (!su_casematch(hostport, v->v_host)) { | ||||||||
3243 | size_t rlen; | ||||||||
3244 | /* Add the "received" field */ | ||||||||
3245 | memcpy(received, "received=", receivedlen); | ||||||||
3246 | |||||||||
3247 | if (hostport[0] == '[') { | ||||||||
3248 | rlen = strlen(hostport + 1) - 1; | ||||||||
3249 | memmove(hostport, hostport + 1, rlen); | ||||||||
3250 | hostport[rlen] = '\0'; | ||||||||
3251 | } | ||||||||
3252 | |||||||||
3253 | msg_header_replace_param(msg_home(msg)((su_home_t*)(msg)), v->v_common, | ||||||||
3254 | su_strdup(msg_home(msg)((su_home_t*)(msg)), received)); | ||||||||
3255 | 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__ , 3255, "nta: Via check: %s\n", received)) : (void)0); | ||||||||
3256 | } | ||||||||
3257 | |||||||||
3258 | if (!agent->sa_server_rport) { | ||||||||
3259 | /*Xyzzy*/; | ||||||||
3260 | } | ||||||||
3261 | else if (v->v_rport) { | ||||||||
3262 | rport = su_sprintf(msg_home(msg)((su_home_t*)(msg)), "rport=%u", ntohs(from->su_portsu_sin.sin_port)); | ||||||||
3263 | msg_header_replace_param(msg_home(msg)((su_home_t*)(msg)), v->v_common, rport); | ||||||||
3264 | } | ||||||||
3265 | else if (tport_is_tcp(tport)) { | ||||||||
3266 | rport = su_sprintf(msg_home(msg)((su_home_t*)(msg)), "rport=%u", ntohs(from->su_portsu_sin.sin_port)); | ||||||||
3267 | msg_header_replace_param(msg_home(msg)((su_home_t*)(msg)), v->v_common, rport); | ||||||||
3268 | } | ||||||||
3269 | else if (agent->sa_server_rport == 2 || | ||||||||
3270 | (agent->sa_server_rport == 3 && sip && sip->sip_user_agent && | ||||||||
3271 | sip->sip_user_agent->g_string && | ||||||||
3272 | (!strncasecmp(sip->sip_user_agent->g_string, "Polycom", 7) || | ||||||||
3273 | !strncasecmp(sip->sip_user_agent->g_string, "KIRK Wireless Server", 20) || | ||||||||
3274 | !strncasecmp(sip->sip_user_agent->g_string, "ADTRAN_Total_Access", 19)))) { | ||||||||
3275 | rport = su_sprintf(msg_home(msg)((su_home_t*)(msg)), "rport=%u", ntohs(from->su_portsu_sin.sin_port)); | ||||||||
3276 | msg_header_replace_param(msg_home(msg)((su_home_t*)(msg)), v->v_common, rport); | ||||||||
3277 | } | ||||||||
3278 | |||||||||
3279 | return 0; | ||||||||
3280 | } | ||||||||
3281 | |||||||||
3282 | /** @internal Handle aliases of local node. | ||||||||
3283 | * | ||||||||
3284 | * Return true if @a url is modified. | ||||||||
3285 | */ | ||||||||
3286 | static | ||||||||
3287 | int agent_aliases(nta_agent_t const *agent, url_t url[], tport_t *tport) | ||||||||
3288 | { | ||||||||
3289 | sip_contact_t *m; | ||||||||
3290 | sip_via_t const *lv; | ||||||||
3291 | char const *tport_port = ""; | ||||||||
3292 | |||||||||
3293 | if (!url->url_host) | ||||||||
3294 | return 0; | ||||||||
3295 | |||||||||
3296 | if (tport) | ||||||||
3297 | tport_port = tport_name(tport)->tpn_port; | ||||||||
3298 | |||||||||
3299 | assert(tport_port)((void) sizeof ((tport_port) ? 1 : 0), __extension__ ({ if (tport_port ) ; else __assert_fail ("tport_port", "nta.c", 3299, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
3300 | |||||||||
3301 | for (m = agent->sa_aliases ? agent->sa_aliases : agent->sa_contact; | ||||||||
3302 | m; | ||||||||
3303 | m = m->m_next) { | ||||||||
3304 | if (url->url_type != m->m_url->url_type) | ||||||||
3305 | continue; | ||||||||
3306 | |||||||||
3307 | if (host_cmp(url->url_host, m->m_url->url_host)) | ||||||||
3308 | continue; | ||||||||
3309 | |||||||||
3310 | if (url->url_port == NULL((void*)0)) | ||||||||
3311 | break; | ||||||||
3312 | |||||||||
3313 | if (m->m_url->url_port) { | ||||||||
3314 | if (strcmp(url->url_port, m->m_url->url_port)) | ||||||||
3315 | continue; | ||||||||
3316 | } else { | ||||||||
3317 | if (strcmp(url->url_port, tport_port)) | ||||||||
3318 | continue; | ||||||||
3319 | } | ||||||||
3320 | |||||||||
3321 | break; | ||||||||
3322 | } | ||||||||
3323 | |||||||||
3324 | if (!m) | ||||||||
3325 | return 0; | ||||||||
3326 | |||||||||
3327 | 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__ , 3329, "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) | ||||||||
3328 | 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__ , 3329, "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) | ||||||||
3329 | 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__ , 3329, "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); | ||||||||
3330 | |||||||||
3331 | url->url_host = "%"; | ||||||||
3332 | |||||||||
3333 | if (agent->sa_aliases) { | ||||||||
3334 | url->url_type = agent->sa_aliases->m_url->url_type; | ||||||||
3335 | url->url_scheme = agent->sa_aliases->m_url->url_scheme; | ||||||||
3336 | url->url_port = agent->sa_aliases->m_url->url_port; | ||||||||
3337 | return 1; | ||||||||
3338 | } | ||||||||
3339 | else { | ||||||||
3340 | /* Canonize the request URL port */ | ||||||||
3341 | if (tport) { | ||||||||
3342 | lv = agent_tport_via(tport_parent(tport)); assert(lv)((void) sizeof ((lv) ? 1 : 0), __extension__ ({ if (lv) ; else __assert_fail ("lv", "nta.c", 3342, __extension__ __PRETTY_FUNCTION__ ); })); | ||||||||
3343 | if (lv->v_port) | ||||||||
3344 | /* Add non-default port */ | ||||||||
3345 | url->url_port = lv->v_port; | ||||||||
3346 | return 1; | ||||||||
3347 | } | ||||||||
3348 | if (su_strmatch(url->url_port, url_port_default((enum url_type_e)url->url_type)) || | ||||||||
3349 | su_strmatch(url->url_port, "")) | ||||||||
3350 | /* Remove default or empty port */ | ||||||||
3351 | url->url_port = NULL((void*)0); | ||||||||
3352 | |||||||||
3353 | return 0; | ||||||||
3354 | } | ||||||||
3355 | } | ||||||||
3356 | |||||||||
3357 | /** @internal Handle incoming responses. */ | ||||||||
3358 | static | ||||||||
3359 | void agent_recv_response(nta_agent_t *agent, | ||||||||
3360 | msg_t *msg, | ||||||||
3361 | sip_t *sip, | ||||||||
3362 | sip_via_t *tport_via, | ||||||||
3363 | tport_t *tport) | ||||||||
3364 | { | ||||||||
3365 | int status = sip->sip_status->st_status; | ||||||||
3366 | int errors; | ||||||||
3367 | char const *phrase = sip->sip_status->st_phrase; | ||||||||
3368 | char const *method = | ||||||||
3369 | sip->sip_cseq ? sip->sip_cseq->cs_method_name : "<UNKNOWN>"; | ||||||||
3370 | uint32_t cseq = sip->sip_cseq ? sip->sip_cseq->cs_seq : 0; | ||||||||
3371 | nta_outgoing_t *orq; | ||||||||
3372 | su_home_t *home; | ||||||||
3373 | char const *branch = NONE((void *)-1); | ||||||||
3374 | |||||||||
3375 | |||||||||
3376 | agent->sa_stats->as_recv_msg++; | ||||||||
3377 | agent->sa_stats->as_recv_response++; | ||||||||
3378 | |||||||||
3379 | 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__ , 3380, "nta: received %03d %s for %s (%u)\n", status, phrase , method, cseq)) : (void)0) | ||||||||
3380 | 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__ , 3380, "nta: received %03d %s for %s (%u)\n", status, phrase , method, cseq)) : (void)0); | ||||||||
3381 | |||||||||
3382 | if (agent->sa_drop_prob && !tport_is_reliable(tport)) { | ||||||||
3383 | if ((unsigned)su_randint(0, 1000) < agent->sa_drop_prob) { | ||||||||
3384 | 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__ , 3385, "nta: %03d %s %s\n", status, phrase, "dropped simulating packet loss" )) : (void)0) | ||||||||
3385 | 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__ , 3385, "nta: %03d %s %s\n", status, phrase, "dropped simulating packet loss" )) : (void)0); | ||||||||
3386 | agent->sa_stats->as_drop_response++; | ||||||||
3387 | msg_destroy(msg); | ||||||||
3388 | return; | ||||||||
3389 | } | ||||||||
3390 | } | ||||||||
3391 | |||||||||
3392 | if (agent->sa_bad_resp_mask) | ||||||||
3393 | errors = msg_extract_errors(msg) & agent->sa_bad_resp_mask; | ||||||||
3394 | else | ||||||||
3395 | errors = sip->sip_error != NULL((void*)0); | ||||||||
3396 | |||||||||
3397 | if (errors || | ||||||||
3398 | sip_sanity_check(sip) < 0) { | ||||||||
3399 | sip_header_t const *h; | ||||||||
3400 | |||||||||
3401 | agent->sa_stats->as_bad_response++; | ||||||||
3402 | agent->sa_stats->as_bad_message++; | ||||||||
3403 | |||||||||
3404 | 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__ , 3407, "nta: %03d %s %s\n", status, phrase, errors ? "has fatal syntax errors" : "failed sanity check")) : (void)0) | ||||||||
3405 | 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__ , 3407, "nta: %03d %s %s\n", status, phrase, errors ? "has fatal syntax errors" : "failed sanity check")) : (void)0) | ||||||||
3406 | ? "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__ , 3407, "nta: %03d %s %s\n", status, phrase, errors ? "has fatal syntax errors" : "failed sanity check")) : (void)0) | ||||||||
3407 | : "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__ , 3407, "nta: %03d %s %s\n", status, phrase, errors ? "has fatal syntax errors" : "failed sanity check")) : (void)0); | ||||||||
3408 | |||||||||
3409 | for (h = (sip_header_t const *)sip->sip_error; h; h = h->sh_nextsh_header_next->shn_next) { | ||||||||
3410 | if (h->sh_classsh_common->h_class->hc_name) { | ||||||||
3411 | 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__ , 3412, "nta: %03d has bad %s header\n", status, h->sh_common ->h_class->hc_name)) : (void)0) | ||||||||
3412 | 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__ , 3412, "nta: %03d has bad %s header\n", status, h->sh_common ->h_class->hc_name)) : (void)0); | ||||||||
3413 | } | ||||||||
3414 | } | ||||||||
3415 | |||||||||
3416 | msg_destroy(msg); | ||||||||
3417 | return; | ||||||||
3418 | } | ||||||||
3419 | |||||||||
3420 | if (!su_casematch(sip->sip_status->st_version, sip_version_2_0)) { | ||||||||
3421 | agent->sa_stats->as_bad_response++; | ||||||||
3422 | agent->sa_stats->as_bad_message++; | ||||||||
3423 | |||||||||
3424 | 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__ , 3425, "nta: bad version %s %03d %s\n", sip->sip_status-> st_version, status, phrase)) : (void)0) | ||||||||
3425 | 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__ , 3425, "nta: bad version %s %03d %s\n", sip->sip_status-> st_version, status, phrase)) : (void)0); | ||||||||
3426 | msg_destroy(msg); | ||||||||
3427 | return; | ||||||||
3428 | } | ||||||||
3429 | |||||||||
3430 | if (sip->sip_cseq && sip->sip_cseq->cs_method == sip_method_ack) { | ||||||||
3431 | /* Drop response messages to ACK */ | ||||||||
3432 | agent->sa_stats->as_bad_response++; | ||||||||
3433 | agent->sa_stats->as_bad_message++; | ||||||||
3434 | 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__ , 3434, "nta: %03d %s %s\n", status, phrase, "is response to ACK" )) : (void)0); | ||||||||
3435 | msg_destroy(msg); | ||||||||
3436 | return; | ||||||||
3437 | } | ||||||||
3438 | |||||||||
3439 | /* XXX - should check if msg should be discarded based on via? */ | ||||||||
3440 | |||||||||
3441 | #ifdef HAVE_ZLIB_COMPRESS1 | ||||||||
3442 | sip_content_encoding_Xflate(msg, sip, 1, 1); | ||||||||
3443 | #endif | ||||||||
3444 | |||||||||
3445 | if ((orq = outgoing_find(agent, msg, sip, sip->sip_via))) { | ||||||||
3446 | 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__ , 3447, "nta: %03d %s %s\n", status, phrase, "is going to a transaction" )) : (void)0) | ||||||||
3447 | 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__ , 3447, "nta: %03d %s %s\n", status, phrase, "is going to a transaction" )) : (void)0); | ||||||||
3448 | /* RFC3263 4.3 "503 error response" */ | ||||||||
3449 | if(agent->sa_srv_503 && status == 503 && outgoing_other_destinations(orq)) { | ||||||||
3450 | 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__ , 3450, "%s(%p): <%03d> for <%s>, %s\n", "nta", ( void *)orq, status, method, "try next after timeout")) : (void )0); | ||||||||
3451 | home = msg_home(msg)((su_home_t*)(msg)); | ||||||||
3452 | if (agent->sa_is_stateless) | ||||||||
3453 | branch = stateless_branch(agent, msg, sip, orq->orq_tpn); | ||||||||
3454 | else | ||||||||
3455 | branch = stateful_branch(home, agent); | ||||||||
3456 | |||||||||
3457 | orq->orq_branch = branch; | ||||||||
3458 | orq->orq_via_branch = branch; | ||||||||
3459 | outgoing_try_another(orq); | ||||||||
3460 | return; | ||||||||
3461 | } | ||||||||
3462 | |||||||||
3463 | if (outgoing_recv(orq, status, msg, sip) == 0) | ||||||||
3464 | return; | ||||||||
3465 | } | ||||||||
3466 | |||||||||
3467 | |||||||||
3468 | agent->sa_stats->as_trless_response++; | ||||||||
3469 | |||||||||
3470 | if ((orq = agent->sa_default_outgoing)) { | ||||||||
3471 | 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__ , 3472, "nta: %03d %s %s\n", status, phrase, "to the default transaction" )) : (void)0) | ||||||||
3472 | "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__ , 3472, "nta: %03d %s %s\n", status, phrase, "to the default transaction" )) : (void)0); | ||||||||
3473 | outgoing_default_recv(orq, status, msg, sip); | ||||||||
3474 | return; | ||||||||
3475 | } | ||||||||
3476 | else if (agent->sa_callback) { | ||||||||
3477 | 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__ , 3477, "nta: %03d %s %s\n", status, phrase, "to message callback" )) : (void)0); | ||||||||
3478 | /* | ||||||||
3479 | * Store message and transport to hook for the duration of the callback | ||||||||
3480 | * so that the transport can be obtained by nta_transport(). | ||||||||
3481 | */ | ||||||||
3482 | (void)agent->sa_callback(agent->sa_magic, agent, msg, sip); | ||||||||
3483 | return; | ||||||||
3484 | } | ||||||||
3485 | |||||||||
3486 | if (sip->sip_cseq && sip->sip_cseq->cs_method == sip_method_invite | ||||||||
3487 | && 200 <= sip->sip_status->st_status | ||||||||
3488 | && sip->sip_status->st_status < 300 | ||||||||
3489 | /* Exactly one Via header, belonging to us */ | ||||||||
3490 | && sip->sip_via && !sip->sip_via->v_next | ||||||||
3491 | && agent_has_via(agent, sip->sip_via)) { | ||||||||
3492 | agent->sa_stats->as_trless_200++; | ||||||||
3493 | } | ||||||||
3494 | |||||||||
3495 | 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__ , 3495, "nta: %03d %s %s\n", status, phrase, "was discarded") ) : (void)0); | ||||||||
3496 | msg_destroy(msg); | ||||||||
3497 | } | ||||||||
3498 | |||||||||
3499 | /** @internal Agent receives garbage */ | ||||||||
3500 | static | ||||||||
3501 | void agent_recv_garbage(nta_agent_t *agent, | ||||||||
3502 | msg_t *msg, | ||||||||
3503 | tport_t *tport) | ||||||||
3504 | { | ||||||||
3505 | agent->sa_stats->as_recv_msg++; | ||||||||
3506 | agent->sa_stats->as_bad_message++; | ||||||||
3507 | |||||||||
3508 | #if SU_DEBUG0 >= 3 | ||||||||
3509 | if (nta_log->log_level >= 3) { | ||||||||
3510 | tp_name_t tpn[1]; | ||||||||
3511 | |||||||||
3512 | tport_delivered_from(tport, msg, tpn); | ||||||||
3513 | |||||||||
3514 | 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__ , 3515, "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) | ||||||||
3515 | 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__ , 3515, "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); | ||||||||
3516 | } | ||||||||
3517 | #endif | ||||||||
3518 | |||||||||
3519 | msg_destroy(msg); | ||||||||
3520 | } | ||||||||
3521 | |||||||||
3522 | /* ====================================================================== */ | ||||||||
3523 | /* 4) Message handling - create, complete, destroy */ | ||||||||
3524 | |||||||||
3525 | /** Create a new message belonging to the agent */ | ||||||||
3526 | msg_t *nta_msg_create(nta_agent_t *agent, int flags) | ||||||||
3527 | { | ||||||||
3528 | msg_t *msg; | ||||||||
3529 | |||||||||
3530 | if (agent == NULL((void*)0)) | ||||||||
3531 | return su_seterrno(EINVAL22), NULL((void*)0); | ||||||||
3532 | |||||||||
3533 | msg = msg_create(agent->sa_mclass, agent->sa_flags | flags); | ||||||||
3534 | |||||||||
3535 | if (agent->sa_preload) | ||||||||
3536 | su_home_preload(msg_home(msg)((su_home_t*)(msg)), 1, agent->sa_preload); | ||||||||
3537 | |||||||||
3538 | return msg; | ||||||||
3539 | } | ||||||||
3540 | |||||||||
3541 | /** Create a new message for transport */ | ||||||||
3542 | msg_t *nta_msg_create_for_transport(nta_agent_t *agent, int flags, | ||||||||
3543 | char const data[], usize_t dlen, | ||||||||
3544 | tport_t const *tport, tp_client_t *via) | ||||||||
3545 | { | ||||||||
3546 | msg_t *msg = msg_create(agent->sa_mclass, agent->sa_flags | flags); | ||||||||
3547 | |||||||||
3548 | msg_maxsize(msg, agent->sa_maxsize); | ||||||||
3549 | |||||||||
3550 | if (agent->sa_preload) | ||||||||
3551 | su_home_preload(msg_home(msg)((su_home_t*)(msg)), 1, dlen + agent->sa_preload); | ||||||||
3552 | |||||||||
3553 | return msg; | ||||||||
3554 | } | ||||||||
3555 | |||||||||
3556 | /** Complete a message. */ | ||||||||
3557 | int nta_msg_complete(msg_t *msg) | ||||||||
3558 | { | ||||||||
3559 | return sip_complete_message(msg); | ||||||||
3560 | } | ||||||||
3561 | |||||||||
3562 | /** Discard a message */ | ||||||||
3563 | void nta_msg_discard(nta_agent_t *agent, msg_t *msg) | ||||||||
3564 | { | ||||||||
3565 | msg_destroy(msg); | ||||||||
3566 | } | ||||||||
3567 | |||||||||
3568 | /** Check if the headers are from response generated locally by NTA. */ | ||||||||
3569 | int nta_sip_is_internal(sip_t const *sip) | ||||||||
3570 | { | ||||||||
3571 | return | ||||||||
3572 | sip == NULL((void*)0) /* No message generated */ | ||||||||
3573 | || (sip->sip_flags & NTA_INTERNAL_MSG(1<<15)) == NTA_INTERNAL_MSG(1<<15); | ||||||||
3574 | } | ||||||||
3575 | |||||||||
3576 | /** Check if the message is internally generated by NTA. */ | ||||||||
3577 | int nta_msg_is_internal(msg_t const *msg) | ||||||||
3578 | { | ||||||||
3579 | return msg_get_flags(msg, NTA_INTERNAL_MSG(1<<15)) == NTA_INTERNAL_MSG(1<<15); | ||||||||
3580 | } | ||||||||
3581 | |||||||||
3582 | /** Check if the message is internally generated by NTA. | ||||||||
3583 | * | ||||||||
3584 | * @deprecated Use nta_msg_is_internal() instead | ||||||||
3585 | */ | ||||||||
3586 | int nta_is_internal_msg(msg_t const *msg) { return nta_msg_is_internal(msg); } | ||||||||
3587 | |||||||||
3588 | /* ====================================================================== */ | ||||||||
3589 | /* 5) Stateless operation */ | ||||||||
3590 | |||||||||
3591 | /**Forward a request or response message. | ||||||||
3592 | * | ||||||||
3593 | * @note | ||||||||
3594 | * The ownership of @a msg is taken over by the function even if the | ||||||||
3595 | * function fails. | ||||||||
3596 | */ | ||||||||
3597 | int nta_msg_tsend(nta_agent_t *agent, msg_t *msg, url_string_t const *u, | ||||||||
3598 | tag_type_t tag, tag_value_t value, ...) | ||||||||
3599 | { | ||||||||
3600 | int retval = -1; | ||||||||
3601 | ta_list ta; | ||||||||
3602 | sip_t *sip = sip_object(msg); | ||||||||
3603 | tp_name_t tpn[1] = {{ NULL((void*)0) }}; | ||||||||
3604 | char const *what; | ||||||||
3605 | |||||||||
3606 | if (!sip) { | ||||||||
3607 | msg_destroy(msg); | ||||||||
3608 | return -1; | ||||||||
3609 | } | ||||||||
3610 | |||||||||
3611 | what = | ||||||||
3612 | sip->sip_status ? "nta_msg_tsend(response)" : | ||||||||
3613 | sip->sip_request ? "nta_msg_tsend(request)" : | ||||||||
3614 | "nta_msg_tsend()"; | ||||||||
3615 | |||||||||
3616 | 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); | ||||||||
3617 | |||||||||
3618 | 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) | ||||||||
3619 | 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__ , 3619, "%s: cannot add headers\n", what)) : (void)0); | ||||||||
3620 | else if (sip->sip_status) { | ||||||||
3621 | tport_t *tport = NULL((void*)0); | ||||||||
3622 | int *use_rport = NULL((void*)0); | ||||||||
3623 | int retry_without_rport = 0; | ||||||||
3624 | |||||||||
3625 | struct sigcomp_compartment *cc; cc = NONE((void *)-1); | ||||||||
3626 | |||||||||
3627 | if (agent->sa_server_rport) | ||||||||
3628 | use_rport = &retry_without_rport, retry_without_rport = 1; | ||||||||
3629 | |||||||||
3630 | tl_gets(ta_args(ta)(ta).tl, | ||||||||
3631 | NTATAG_TPORT_REF(tport)ntatag_tport_ref, tag_ptr_vr(&(tport), (tport)), | ||||||||
3632 | IF_SIGCOMP_TPTAG_COMPARTMENT_REF(cc)tptag_compartment_ref, tag_ptr_vr(&(cc), cc), | ||||||||
3633 | /* NTATAG_INCOMPLETE_REF(incomplete), */ | ||||||||
3634 | TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
3635 | |||||||||
3636 | if (!sip->sip_separator && | ||||||||
3637 | !(sip->sip_separator = sip_separator_create(msg_home(msg)((su_home_t*)(msg))))) | ||||||||
3638 | 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__ , 3638, "%s: cannot create sip_separator\n", what)) : (void)0 ); | ||||||||
3639 | else if (msg_serialize(msg, (msg_pub_t *)sip) != 0) | ||||||||
3640 | 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__ , 3640, "%s: sip_serialize() failed\n", what)) : (void)0); | ||||||||
3641 | else if (!sip_via_remove(msg, sip)) | ||||||||
3642 | 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__ , 3642, "%s: cannot remove Via\n", what)) : (void)0); | ||||||||
3643 | else if (nta_tpn_by_via(tpn, sip->sip_via, use_rport) < 0) | ||||||||
3644 | 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__ , 3644, "%s: bad via\n", what)) : (void)0); | ||||||||
3645 | else { | ||||||||
3646 | if (!tport) | ||||||||
3647 | tport = tport_by_name(agent->sa_tports, tpn); | ||||||||
3648 | if (!tport) | ||||||||
3649 | tport = tport_by_protocol(agent->sa_tports, tpn->tpn_proto); | ||||||||
3650 | |||||||||
3651 | if (retry_without_rport) | ||||||||
3652 | tpn->tpn_port = sip_via_port(sip->sip_via, NULL((void*)0)); | ||||||||
3653 | |||||||||
3654 | if (tport && tpn->tpn_comp && cc == NONE((void *)-1)) | ||||||||
3655 | cc = agent_compression_compartment(agent, tport, tpn, -1); | ||||||||
3656 | |||||||||
3657 | if (tport_tsend(tport, msg, tpn, | ||||||||
3658 | IF_SIGCOMP_TPTAG_COMPARTMENT(cc)!(cc && cc != ((void *)-1)) ? tag_skip : tptag_compartment , tag_ptr_v((cc)), | ||||||||
3659 | 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)) { | ||||||||
3660 | agent->sa_stats->as_sent_msg++; | ||||||||
3661 | agent->sa_stats->as_sent_response++; | ||||||||
3662 | retval = 0; | ||||||||
3663 | } | ||||||||
3664 | else { | ||||||||
3665 | 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__ , 3665, "%s: send fails\n", what)) : (void)0); | ||||||||
3666 | } | ||||||||
3667 | } | ||||||||
3668 | } | ||||||||
3669 | else { | ||||||||
3670 | /* Send request */ | ||||||||
3671 | if (outgoing_create(agent, NULL((void*)0), NULL((void*)0), u, NULL((void*)0), msg_ref_create(msg), | ||||||||
3672 | NTATAG_STATELESS(1)ntatag_stateless, tag_bool_v((1)), | ||||||||
3673 | ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta). tl[1].t_value)) | ||||||||
3674 | retval = 0; | ||||||||
3675 | } | ||||||||
3676 | |||||||||
3677 | if (retval == 0) | ||||||||
3678 | 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__ , 3678, "%s\n", what)) : (void)0); | ||||||||
3679 | |||||||||
3680 | 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)); | ||||||||
3681 | |||||||||
3682 | msg_destroy(msg); | ||||||||
3683 | |||||||||
3684 | return retval; | ||||||||
3685 | } | ||||||||
3686 | |||||||||
3687 | /** Reply to a request message. | ||||||||
3688 | * | ||||||||
3689 | * @param agent nta agent object | ||||||||
3690 | * @param req_msg request message | ||||||||
3691 | * @param status status code | ||||||||
3692 | * @param phrase status phrase (may be NULL if status code is well-known) | ||||||||
3693 | * @param tag, value, ... optional additional headers terminated by TAG_END() | ||||||||
3694 | * | ||||||||
3695 | * @retval 0 when succesful | ||||||||
3696 | * @retval -1 upon an error | ||||||||
3697 | * | ||||||||
3698 | * @note | ||||||||
3699 | * The ownership of @a msg is taken over by the function even if the | ||||||||
3700 | * function fails. | ||||||||
3701 | */ | ||||||||
3702 | int nta_msg_treply(nta_agent_t *agent, | ||||||||
3703 | msg_t *req_msg, | ||||||||
3704 | int status, char const *phrase, | ||||||||
3705 | tag_type_t tag, tag_value_t value, ...) | ||||||||
3706 | { | ||||||||
3707 | int retval; | ||||||||
3708 | ta_list ta; | ||||||||
3709 | |||||||||
3710 | 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); | ||||||||
3711 | |||||||||
3712 | retval = mreply(agent, NULL((void*)0), status, phrase, req_msg, | ||||||||
3713 | NULL((void*)0), 0, 0, NULL((void*)0), | ||||||||
3714 | ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta). tl[1].t_value); | ||||||||
3715 | 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)); | ||||||||
3716 | |||||||||
3717 | return retval; | ||||||||
3718 | } | ||||||||
3719 | |||||||||
3720 | /**Reply to the request message. | ||||||||
3721 | * | ||||||||
3722 | * @note | ||||||||
3723 | * The ownership of @a msg is taken over by the function even if the | ||||||||
3724 | * function fails. | ||||||||
3725 | */ | ||||||||
3726 | int nta_msg_mreply(nta_agent_t *agent, | ||||||||
3727 | msg_t *reply, sip_t *sip, | ||||||||
3728 | int status, char const *phrase, | ||||||||
3729 | msg_t *req_msg, | ||||||||
3730 | tag_type_t tag, tag_value_t value, ...) | ||||||||
3731 | { | ||||||||
3732 | int retval = -1; | ||||||||
3733 | ta_list ta; | ||||||||
3734 | |||||||||
3735 | 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); | ||||||||
3736 | |||||||||
3737 | retval = mreply(agent, reply, status, phrase, req_msg, | ||||||||
3738 | NULL((void*)0), 0, 0, NULL((void*)0), | ||||||||
3739 | ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta). tl[1].t_value); | ||||||||
3740 | 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)); | ||||||||
3741 | |||||||||
3742 | return retval; | ||||||||
3743 | } | ||||||||
3744 | |||||||||
3745 | static | ||||||||
3746 | int mreply(nta_agent_t *agent, | ||||||||
3747 | msg_t *reply, | ||||||||
3748 | int status, char const *phrase, | ||||||||
3749 | msg_t *req_msg, | ||||||||
3750 | tport_t *tport, | ||||||||
3751 | int incomplete, | ||||||||
3752 | int sdwn_after, | ||||||||
3753 | char const *to_tag, | ||||||||
3754 | tag_type_t tag, tag_value_t value, ...) | ||||||||
3755 | { | ||||||||
3756 | ta_list ta; | ||||||||
3757 | sip_t *sip; | ||||||||
3758 | int *use_rport = NULL((void*)0); | ||||||||
3759 | int retry_without_rport = 0; | ||||||||
3760 | tp_name_t tpn[1]; | ||||||||
3761 | int retval = -1; | ||||||||
3762 | |||||||||
3763 | if (!agent) | ||||||||
3764 | return -1; | ||||||||
3765 | |||||||||
3766 | if (agent->sa_server_rport) | ||||||||
3767 | use_rport = &retry_without_rport, retry_without_rport = 1; | ||||||||
3768 | |||||||||
3769 | 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); | ||||||||
3770 | |||||||||
3771 | 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); | ||||||||
3772 | |||||||||
3773 | if (reply == NULL((void*)0)) { | ||||||||
3774 | reply = nta_msg_create(agent, 0); | ||||||||
3775 | } | ||||||||
3776 | sip = sip_object(reply); | ||||||||
3777 | |||||||||
3778 | if (!sip) { | ||||||||
3779 | 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__ , 3779, "%s: cannot create response msg\n", __func__)) : (void )0); | ||||||||
3780 | } | ||||||||
3781 | 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) { | ||||||||
3782 | 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__ , 3782, "%s: cannot add user headers\n", __func__)) : (void)0 ); | ||||||||
3783 | } | ||||||||
3784 | else if (complete_response(reply, status, phrase, req_msg) < 0 && | ||||||||
3785 | !incomplete) { | ||||||||
3786 | 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__ , 3786, "%s: cannot complete message\n", __func__)) : (void)0 ); | ||||||||
3787 | } | ||||||||
3788 | else if (sip->sip_status && sip->sip_status->st_status > 100 && | ||||||||
3789 | sip->sip_to && !sip->sip_to->a_tag && | ||||||||
3790 | (to_tag == NONE((void *)-1) ? 0 : | ||||||||
3791 | to_tag != NULL((void*)0) | ||||||||
3792 | ? sip_to_tag(msg_home(reply)((su_home_t*)(reply)), sip->sip_to, to_tag) < 0 | ||||||||
3793 | : sip_to_tag(msg_home(reply)((su_home_t*)(reply)), sip->sip_to, | ||||||||
3794 | nta_agent_newtag(msg_home(reply)((su_home_t*)(reply)), "tag=%s", agent)) < 0)) { | ||||||||
3795 | 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__ , 3795, "%s: cannot add To tag\n", __func__)) : (void)0); | ||||||||
3796 | } | ||||||||
3797 | else if (nta_tpn_by_via(tpn, sip->sip_via, use_rport) < 0) { | ||||||||
3798 | 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__ , 3798, "%s: no Via\n", __func__)) : (void)0); | ||||||||
3799 | } | ||||||||
3800 | else { | ||||||||
3801 | struct sigcomp_compartment *cc = NONE((void *)-1); | ||||||||
3802 | |||||||||
3803 | if (tport == NULL((void*)0)) | ||||||||
3804 | tport = tport_delivered_by(agent->sa_tports, req_msg); | ||||||||
3805 | |||||||||
3806 | if (!tport) { | ||||||||
3807 | tport_t *primary = tport_by_protocol(agent->sa_tports, tpn->tpn_proto); | ||||||||
3808 | |||||||||
3809 | tport = tport_by_name(primary, tpn); | ||||||||
3810 | |||||||||
3811 | if (!tport) | ||||||||
3812 | tport = primary; | ||||||||
3813 | } | ||||||||
3814 | |||||||||
3815 | if (retry_without_rport) | ||||||||
3816 | tpn->tpn_port = sip_via_port(sip->sip_via, NULL((void*)0)); | ||||||||
3817 | |||||||||
3818 | if (tport && tpn->tpn_comp) { | ||||||||
3819 | tl_gets(ta_args(ta)(ta).tl, TPTAG_COMPARTMENT_REF(cc)tptag_compartment_ref, tag_ptr_vr(&(cc), cc), | ||||||||
3820 | /* XXX - should also check ntatag_sigcomp_close() */ | ||||||||
3821 | TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
3822 | if (cc == NONE((void *)-1)) | ||||||||
3823 | cc = agent_compression_compartment(agent, tport, tpn, -1); | ||||||||
3824 | |||||||||
3825 | if (cc != NULL((void*)0) && cc != NONE((void *)-1) && | ||||||||
3826 | tport_delivered_with_comp(tport, req_msg, NULL((void*)0)) != -1) { | ||||||||
3827 | agent_accept_compressed(agent, req_msg, cc); | ||||||||
3828 | } | ||||||||
3829 | } | ||||||||
3830 | |||||||||
3831 | if (tport_tsend(tport, reply, tpn, | ||||||||
3832 | IF_SIGCOMP_TPTAG_COMPARTMENT(cc)!(cc && cc != ((void *)-1)) ? tag_skip : tptag_compartment , tag_ptr_v((cc)), | ||||||||
3833 | TPTAG_MTU(INT_MAX)tptag_mtu, tag_usize_v((2147483647)), | ||||||||
3834 | TPTAG_SDWN_AFTER(sdwn_after)tptag_sdwn_after, tag_bool_v((sdwn_after)), | ||||||||
3835 | ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta). tl[1].t_value)) { | ||||||||
3836 | agent->sa_stats->as_sent_msg++; | ||||||||
3837 | agent->sa_stats->as_sent_response++; | ||||||||
3838 | retval = 0; /* Success! */ | ||||||||
3839 | } | ||||||||
3840 | else { | ||||||||
3841 | 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__ , 3841, "%s: send fails\n", __func__)) : (void)0); | ||||||||
3842 | } | ||||||||
3843 | } | ||||||||
3844 | |||||||||
3845 | msg_destroy(reply); | ||||||||
3846 | msg_destroy(req_msg); | ||||||||
3847 | |||||||||
3848 | 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)); | ||||||||
3849 | |||||||||
3850 | return retval; | ||||||||
3851 | } | ||||||||
3852 | |||||||||
3853 | /** Add headers from the request to the response message. */ | ||||||||
3854 | static | ||||||||
3855 | int complete_response(msg_t *response, | ||||||||
3856 | int status, char const *phrase, | ||||||||
3857 | msg_t *request) | ||||||||
3858 | { | ||||||||
3859 | su_home_t *home = msg_home(response)((su_home_t*)(response)); | ||||||||
3860 | sip_t *response_sip = sip_object(response); | ||||||||
3861 | sip_t const *request_sip = sip_object(request); | ||||||||
3862 | |||||||||
3863 | int incomplete = 0; | ||||||||
3864 | |||||||||
3865 | if (!response_sip || !request_sip || !request_sip->sip_request) | ||||||||
3866 | return -1; | ||||||||
3867 | |||||||||
3868 | if (!response_sip->sip_status) | ||||||||
3869 | response_sip->sip_status = sip_status_create(home, status, phrase, NULL((void*)0)); | ||||||||
3870 | if (!response_sip->sip_via) | ||||||||
3871 | response_sip->sip_via = sip_via_dup(home, request_sip->sip_via); | ||||||||
3872 | if (!response_sip->sip_from) | ||||||||
3873 | response_sip->sip_from = sip_from_dup(home, request_sip->sip_from); | ||||||||
3874 | if (!response_sip->sip_to) | ||||||||
3875 | response_sip->sip_to = sip_to_dup(home, request_sip->sip_to); | ||||||||
3876 | if (!response_sip->sip_call_id) | ||||||||
3877 | response_sip->sip_call_id = | ||||||||
3878 | sip_call_id_dup(home, request_sip->sip_call_id); | ||||||||
3879 | if (!response_sip->sip_cseq) | ||||||||
3880 | response_sip->sip_cseq = sip_cseq_dup(home, request_sip->sip_cseq); | ||||||||
3881 | |||||||||
3882 | if (!response_sip->sip_record_route && request_sip->sip_record_route) | ||||||||
3883 | sip_add_dup(response, response_sip, (void*)request_sip->sip_record_route); | ||||||||
3884 | |||||||||
3885 | incomplete = sip_complete_message(response) < 0; | ||||||||
3886 | |||||||||
3887 | msg_serialize(response, (msg_pub_t *)response_sip); | ||||||||
3888 | |||||||||
3889 | if (incomplete || | ||||||||
3890 | !response_sip->sip_status || | ||||||||
3891 | !response_sip->sip_via || | ||||||||
3892 | !response_sip->sip_from || | ||||||||
3893 | !response_sip->sip_to || | ||||||||
3894 | !response_sip->sip_call_id || | ||||||||
3895 | !response_sip->sip_cseq || | ||||||||
3896 | !response_sip->sip_content_length || | ||||||||
3897 | !response_sip->sip_separator || | ||||||||
3898 | (request_sip->sip_record_route && !response_sip->sip_record_route)) | ||||||||
3899 | return -1; | ||||||||
3900 | |||||||||
3901 | return 0; | ||||||||
3902 | } | ||||||||
3903 | |||||||||
3904 | /** ACK and BYE an unknown 200 OK response to INVITE. | ||||||||
3905 | * | ||||||||
3906 | * A UAS may still return a 2XX series response to client request after the | ||||||||
3907 | * client transactions has been terminated. In that case, the UAC can not | ||||||||
3908 | * really accept the call. This function was used to accept and immediately | ||||||||
3909 | * terminate such a call. | ||||||||
3910 | * | ||||||||
3911 | * @deprecated This was a bad idea: see sf.net bug #1750691. It can be used | ||||||||
3912 | * to amplify DoS attacks. Let UAS take care of retransmission timeout and | ||||||||
3913 | * let it terminate the session. As of @VERSION_1_12_7, this function just | ||||||||
3914 | * returns -1. | ||||||||
3915 | */ | ||||||||
3916 | int nta_msg_ackbye(nta_agent_t *agent, msg_t *msg) | ||||||||
3917 | { | ||||||||
3918 | sip_t *sip = sip_object(msg); | ||||||||
3919 | msg_t *amsg = nta_msg_create(agent, 0); | ||||||||
3920 | sip_t *asip = sip_object(amsg); | ||||||||
3921 | msg_t *bmsg = NULL((void*)0); | ||||||||
3922 | sip_t *bsip; | ||||||||
3923 | url_string_t const *ruri; | ||||||||
3924 | nta_outgoing_t *ack = NULL((void*)0); | ||||||||
3925 | sip_cseq_t *cseq; | ||||||||
3926 | sip_request_t *rq; | ||||||||
3927 | sip_route_t *route = NULL((void*)0), *r, r0[1]; | ||||||||
3928 | su_home_t *home = msg_home(amsg)((su_home_t*)(amsg)); | ||||||||
3929 | |||||||||
3930 | if (asip == NULL((void*)0)) | ||||||||
3931 | return -1; | ||||||||
3932 | |||||||||
3933 | sip_add_tl(amsg, asip, | ||||||||
3934 | SIPTAG_TO(sip->sip_to)siptag_to, siptag_to_v(sip->sip_to), | ||||||||
3935 | SIPTAG_FROM(sip->sip_from)siptag_from, siptag_from_v(sip->sip_from), | ||||||||
3936 | SIPTAG_CALL_ID(sip->sip_call_id)siptag_call_id, siptag_call_id_v(sip->sip_call_id), | ||||||||
3937 | TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
3938 | |||||||||
3939 | if (sip->sip_contact) { | ||||||||
3940 | ruri = (url_string_t const *)sip->sip_contact->m_url; | ||||||||
3941 | } else { | ||||||||
3942 | ruri = (url_string_t const *)sip->sip_to->a_url; | ||||||||
3943 | } | ||||||||
3944 | |||||||||
3945 | /* Reverse (and fix) record route */ | ||||||||
3946 | route = sip_route_reverse(home, sip->sip_record_route); | ||||||||
3947 | |||||||||
3948 | if (route && !url_has_param(route->r_url, "lr")) { | ||||||||
3949 | for (r = route; r->r_next; r = r->r_next) | ||||||||
3950 | ; | ||||||||
3951 | |||||||||
3952 | /* Append r-uri */ | ||||||||
3953 | *sip_route_init(r0)->r_url = *ruri->us_url; | ||||||||
3954 | r->r_next = sip_route_dup(home, r0); | ||||||||
3955 | |||||||||
3956 | /* Use topmost route as request-uri */ | ||||||||
3957 | ruri = (url_string_t const *)route->r_url; | ||||||||
3958 | route = route->r_next; | ||||||||
3959 | } | ||||||||
3960 | |||||||||
3961 | msg_header_insert(amsg, (msg_pub_t *)asip, (msg_header_t *)route); | ||||||||
3962 | |||||||||
3963 | bmsg = msg_copy(amsg); bsip = sip_object(bmsg); | ||||||||
3964 | |||||||||
3965 | if (!(cseq = sip_cseq_create(home, sip->sip_cseq->cs_seq, SIP_METHOD_ACKsip_method_ack, "ACK"))) | ||||||||
3966 | goto err; | ||||||||
3967 | else | ||||||||
3968 | msg_header_insert(amsg, (msg_pub_t *)asip, (msg_header_t *)cseq); | ||||||||
3969 | |||||||||
3970 | if (!(rq = sip_request_create(home, SIP_METHOD_ACKsip_method_ack, "ACK", ruri, NULL((void*)0)))) | ||||||||
3971 | goto err; | ||||||||
3972 | else | ||||||||
3973 | msg_header_insert(amsg, (msg_pub_t *)asip, (msg_header_t *)rq); | ||||||||
3974 | |||||||||
3975 | if (!(ack = nta_outgoing_mcreate(agent, NULL((void*)0), NULL((void*)0), NULL((void*)0), amsg, | ||||||||
3976 | NTATAG_ACK_BRANCH(sip->sip_via->v_branch)ntatag_ack_branch, tag_str_v((sip->sip_via->v_branch)), | ||||||||
3977 | NTATAG_STATELESS(1)ntatag_stateless, tag_bool_v((1)), | ||||||||
3978 | TAG_END()(tag_type_t)0, (tag_value_t)0))) | ||||||||
3979 | goto err; | ||||||||
3980 | else | ||||||||
3981 | nta_outgoing_destroy(ack); | ||||||||
3982 | |||||||||
3983 | home = msg_home(bmsg)((su_home_t*)(bmsg)); | ||||||||
3984 | |||||||||
3985 | if (!(cseq = sip_cseq_create(home, 0x7fffffff, SIP_METHOD_BYEsip_method_bye, "BYE"))) | ||||||||
3986 | goto err; | ||||||||
3987 | else | ||||||||
3988 | msg_header_insert(bmsg, (msg_pub_t *)bsip, (msg_header_t *)cseq); | ||||||||
3989 | |||||||||
3990 | if (!(rq = sip_request_create(home, SIP_METHOD_BYEsip_method_bye, "BYE", ruri, NULL((void*)0)))) | ||||||||
3991 | goto err; | ||||||||
3992 | else | ||||||||
3993 | msg_header_insert(bmsg, (msg_pub_t *)bsip, (msg_header_t *)rq); | ||||||||
3994 | |||||||||
3995 | if (!nta_outgoing_mcreate(agent, NULL((void*)0), NULL((void*)0), NULL((void*)0), bmsg, | ||||||||
3996 | NTATAG_STATELESS(1)ntatag_stateless, tag_bool_v((1)), | ||||||||
3997 | TAG_END()(tag_type_t)0, (tag_value_t)0)) | ||||||||
3998 | goto err; | ||||||||
3999 | |||||||||
4000 | msg_destroy(msg); | ||||||||
4001 | return 0; | ||||||||
4002 | |||||||||
4003 | err: | ||||||||
4004 | |||||||||
4005 | msg_destroy(bmsg); | ||||||||
4006 | msg_destroy(amsg); | ||||||||
4007 | |||||||||
4008 | return -1; | ||||||||
4009 | } | ||||||||
4010 | |||||||||
4011 | /**Complete a request with values from dialog. | ||||||||
4012 | * | ||||||||
4013 | * Complete a request message @a msg belonging to a dialog associated with | ||||||||
4014 | * @a leg. It increments the local @CSeq value, adds @CallID, @To, @From and | ||||||||
4015 | * @Route headers (if there is such headers present in @a leg), and creates | ||||||||
4016 | * a new request line object from @a method, @a method_name and @a | ||||||||
4017 | * request_uri. | ||||||||
4018 | * | ||||||||
4019 | * @param msg pointer to a request message object | ||||||||
4020 | * @param leg pointer to a #nta_leg_t object | ||||||||
4021 | * @param method request method number or #sip_method_unknown | ||||||||
4022 | * @param method_name method name (if @a method == #sip_method_unknown) | ||||||||
4023 | * @param request_uri request URI | ||||||||
4024 | * | ||||||||
4025 | * If @a request_uri contains query part, the query part is converted as SIP | ||||||||
4026 | * headers and added to the request. | ||||||||
4027 | * | ||||||||
4028 | * @retval 0 when successful | ||||||||
4029 | * @retval -1 upon an error | ||||||||
4030 | * | ||||||||
4031 | * @sa nta_outgoing_mcreate(), nta_outgoing_tcreate() | ||||||||
4032 | */ | ||||||||
4033 | int nta_msg_request_complete(msg_t *msg, | ||||||||
4034 | nta_leg_t *leg, | ||||||||
4035 | sip_method_t method, | ||||||||
4036 | char const *method_name, | ||||||||
4037 | url_string_t const *request_uri) | ||||||||
4038 | { | ||||||||
4039 | su_home_t *home = msg_home(msg)((su_home_t*)(msg)); | ||||||||
4040 | sip_t *sip = sip_object(msg); | ||||||||
4041 | sip_to_t const *to; | ||||||||
4042 | uint32_t seq; | ||||||||
4043 | url_t reg_url[1]; | ||||||||
4044 | url_string_t const *original = request_uri; | ||||||||
4045 | |||||||||
4046 | if (!leg || !msg || !sip) | ||||||||
4047 | return -1; | ||||||||
4048 | |||||||||
4049 | if (!sip->sip_route && leg->leg_route) { | ||||||||
4050 | if (leg->leg_loose_route) { | ||||||||
4051 | if (leg->leg_target) { | ||||||||
4052 | request_uri = (url_string_t *)leg->leg_target->m_url; | ||||||||
4053 | } | ||||||||
4054 | sip->sip_route = sip_route_dup(home, leg->leg_route); | ||||||||
4055 | } | ||||||||
4056 | else { | ||||||||
4057 | sip_route_t **rr; | ||||||||
4058 | |||||||||
4059 | request_uri = (url_string_t *)leg->leg_route->r_url; | ||||||||
4060 | sip->sip_route = sip_route_dup(home, leg->leg_route->r_next); | ||||||||
4061 | |||||||||
4062 | for (rr = &sip->sip_route; *rr; rr = &(*rr)->r_next) | ||||||||
4063 | ; | ||||||||
4064 | |||||||||
4065 | if (leg->leg_target) | ||||||||
4066 | *rr = sip_route_dup(home, (sip_route_t *)leg->leg_target); | ||||||||
4067 | } | ||||||||
4068 | } | ||||||||
4069 | else if (leg->leg_target) | ||||||||
4070 | request_uri = (url_string_t *)leg->leg_target->m_url; | ||||||||
4071 | |||||||||
4072 | if (!request_uri && sip->sip_request) | ||||||||
4073 | request_uri = (url_string_t *)sip->sip_request->rq_url; | ||||||||
4074 | |||||||||
4075 | to = sip->sip_to ? sip->sip_to : leg->leg_remote; | ||||||||
4076 | |||||||||
4077 | if (!request_uri && to) { | ||||||||
4078 | if (method != sip_method_register) | ||||||||
4079 | request_uri = (url_string_t *)to->a_url; | ||||||||
4080 | else { | ||||||||
4081 | /* Remove user part from REGISTER requests */ | ||||||||
4082 | *reg_url = *to->a_url; | ||||||||
4083 | reg_url->url_user = reg_url->url_password = NULL((void*)0); | ||||||||
4084 | request_uri = (url_string_t *)reg_url; | ||||||||
4085 | } | ||||||||
4086 | } | ||||||||
4087 | |||||||||
4088 | if (!request_uri) | ||||||||
4089 | return -1; | ||||||||
4090 | |||||||||
4091 | if (method || method_name) { | ||||||||
4092 | sip_request_t *rq = sip->sip_request; | ||||||||
4093 | int use_headers = | ||||||||
4094 | request_uri == original || (url_t *)request_uri == rq->rq_url; | ||||||||
4095 | |||||||||
4096 | if (!rq | ||||||||
4097 | || request_uri != (url_string_t *)rq->rq_url | ||||||||
4098 | || method != rq->rq_method | ||||||||
4099 | || !su_strmatch(method_name, rq->rq_method_name)) | ||||||||
4100 | rq = NULL((void*)0); | ||||||||
4101 | |||||||||
4102 | if (rq == NULL((void*)0)) { | ||||||||
4103 | rq = sip_request_create(home, method, method_name, request_uri, NULL((void*)0)); | ||||||||
4104 | if (msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)rq) < 0) | ||||||||
4105 | return -1; | ||||||||
4106 | } | ||||||||
4107 | |||||||||
4108 | /* @RFC3261 table 1 (page 152): | ||||||||
4109 | * Req-URI cannot contain method parameter or headers | ||||||||
4110 | */ | ||||||||
4111 | if (rq->rq_url->url_params) { | ||||||||
4112 | rq->rq_url->url_params = | ||||||||
4113 | url_strip_param_string((char *)rq->rq_url->url_params, "method"); | ||||||||
4114 | sip_fragment_clear(rq->rq_common)((rq->rq_common)->h_data = ((void*)0), (rq->rq_common )->h_len = 0); | ||||||||
4115 | } | ||||||||
4116 | |||||||||
4117 | if (rq->rq_url->url_headers) { | ||||||||
4118 | if (use_headers) { | ||||||||
4119 | char *s = url_query_as_header_string(msg_home(msg)((su_home_t*)(msg)), | ||||||||
4120 | rq->rq_url->url_headers); | ||||||||
4121 | if (!s) | ||||||||
4122 | return -1; | ||||||||
4123 | msg_header_parse_str(msg, (msg_pub_t*)sip, s); | ||||||||
4124 | } | ||||||||
4125 | 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); | ||||||||
4126 | } | ||||||||
4127 | } | ||||||||
4128 | |||||||||
4129 | if (!sip->sip_request) | ||||||||
4130 | return -1; | ||||||||
4131 | |||||||||
4132 | if (!sip->sip_max_forwards) | ||||||||
4133 | sip_add_dup(msg, sip, (sip_header_t *)leg->leg_agent->sa_max_forwards); | ||||||||
4134 | |||||||||
4135 | if (!sip->sip_from) | ||||||||
4136 | sip->sip_from = sip_from_dup(home, leg->leg_local); | ||||||||
4137 | else if (leg->leg_local && leg->leg_local->a_tag && | ||||||||
4138 | (!sip->sip_from->a_tag || | ||||||||
4139 | !su_casematch(sip->sip_from->a_tag, leg->leg_local->a_tag))) | ||||||||
4140 | sip_from_tag(home, sip->sip_from, leg->leg_local->a_tag); | ||||||||
4141 | |||||||||
4142 | if (sip->sip_from && !sip->sip_from->a_tag) { | ||||||||
4143 | 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); | ||||||||
4144 | sip_from_add_param(home, sip->sip_from, | ||||||||
4145 | nta_agent_newtag(home, "tag=%s", leg->leg_agent)); | ||||||||
4146 | } | ||||||||
4147 | |||||||||
4148 | if (sip->sip_to) { | ||||||||
4149 | if (leg->leg_remote && leg->leg_remote->a_tag) | ||||||||
4150 | sip_to_tag(home, sip->sip_to, leg->leg_remote->a_tag); | ||||||||
4151 | } | ||||||||
4152 | else if (leg->leg_remote) { | ||||||||
4153 | sip->sip_to = sip_to_dup(home, leg->leg_remote); | ||||||||
4154 | } | ||||||||
4155 | else { | ||||||||
4156 | sip_to_t *to = sip_to_create(home, request_uri); | ||||||||
4157 | if (to) sip_aor_strip(to->a_url); | ||||||||
4158 | sip->sip_to = to; | ||||||||
4159 | } | ||||||||
4160 | |||||||||
4161 | if (!sip->sip_from || !sip->sip_from || !sip->sip_to) | ||||||||
4162 | return -1; | ||||||||
4163 | |||||||||
4164 | method = sip->sip_request->rq_method; | ||||||||
4165 | method_name = sip->sip_request->rq_method_name; | ||||||||
4166 | |||||||||
4167 | if (!leg->leg_id && sip->sip_cseq) | ||||||||
4168 | seq = sip->sip_cseq->cs_seq; | ||||||||
4169 | else if (method == sip_method_ack || method == sip_method_cancel) | ||||||||
4170 | /* Dangerous - we may do PRACK/UPDATE meanwhile */ | ||||||||
4171 | seq = sip->sip_cseq ? sip->sip_cseq->cs_seq : leg->leg_seq; | ||||||||
4172 | else if (leg->leg_seq) | ||||||||
4173 | seq = ++leg->leg_seq; | ||||||||
4174 | else if (sip->sip_cseq) /* Obtain initial value from existing CSeq header */ | ||||||||
4175 | seq = leg->leg_seq = sip->sip_cseq->cs_seq; | ||||||||
4176 | else | ||||||||
4177 | seq = leg->leg_seq = (sip_now() >> 1) & 0x7ffffff; | ||||||||
4178 | |||||||||
4179 | if (!sip->sip_call_id) { | ||||||||
4180 | if (leg->leg_id) | ||||||||
4181 | sip->sip_call_id = sip_call_id_dup(home, leg->leg_id); | ||||||||
4182 | else | ||||||||
4183 | sip->sip_call_id = sip_call_id_create(home, NULL((void*)0)); | ||||||||
4184 | } | ||||||||
4185 | |||||||||
4186 | if (!sip->sip_cseq || | ||||||||
4187 | seq != sip->sip_cseq->cs_seq || | ||||||||
4188 | method != sip->sip_cseq->cs_method || | ||||||||
4189 | !su_strmatch(method_name, sip->sip_cseq->cs_method_name)) { | ||||||||
4190 | sip_cseq_t *cseq = sip_cseq_create(home, seq, method, method_name); | ||||||||
4191 | if (msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)cseq) < 0) | ||||||||
4192 | return -1; | ||||||||
4193 | } | ||||||||
4194 | |||||||||
4195 | return 0; | ||||||||
4196 | } | ||||||||
4197 | |||||||||
4198 | /* ====================================================================== */ | ||||||||
4199 | /* 6) Dialogs (legs) */ | ||||||||
4200 | |||||||||
4201 | static void leg_insert(nta_agent_t *agent, nta_leg_t *leg); | ||||||||
4202 | static int leg_route(nta_leg_t *leg, | ||||||||
4203 | sip_record_route_t const *route, | ||||||||
4204 | sip_record_route_t const *reverse, | ||||||||
4205 | sip_contact_t const *contact, | ||||||||
4206 | int reroute); | ||||||||
4207 | static int leg_callback_default(nta_leg_magic_t*, nta_leg_t*, | ||||||||
4208 | nta_incoming_t*, sip_t const *); | ||||||||
4209 | #define HTABLE_HASH_LEG(leg)((leg)->leg_hash) ((leg)->leg_hash) | ||||||||
4210 | |||||||||
4211 | #ifdef __clang__1 | ||||||||
4212 | #pragma clang diagnostic push | ||||||||
4213 | #pragma clang diagnostic ignored "-Wunused-function" | ||||||||
4214 | #endif | ||||||||
4215 | |||||||||
4216 | HTABLE_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; if (new_size == 0) new_size = 2 * lht->lht_size + 1; if (new_size < 31) new_size = 31; if (new_size < 5 * lht->lht_used / 4) new_size = 5 * lht->lht_used / 4; if (!(new_hash = su_zalloc(home, sizeof (*new_hash) * new_size))) return -1; old_size = lht->lht_size ; do for (j = 0; j < old_size; j++) { if (!old_hash[j]) continue ; if (again < 2 && ((old_hash[j])->leg_hash) % old_size > j) { again = 1; continue; } i0 = ((old_hash[j])->leg_hash ) % new_size; for (i = i0; new_hash[i]; i = (i + 1) % new_size , ((void) sizeof ((i != i0) ? 1 : 0), __extension__ ({ if (i != i0) ; else __assert_fail ("i != i0", "nta.c", 4216, __extension__ __PRETTY_FUNCTION__); }))); new_hash[i] = old_hash[j], old_hash [j] = ((void*)0); used++; } while (again++ == 1); lht->lht_table = new_hash, lht->lht_size = new_size; ((void) sizeof ((lht ->lht_used == used) ? 1 : 0), __extension__ ({ if (lht-> lht_used == used) ; else __assert_fail ("lht->lht_used == used" , "nta.c", 4216, __extension__ __PRETTY_FUNCTION__); })); su_free (home, old_hash); return 0; } static inline int leg_htable_is_full (leg_htable_t const *lht) { return lht->lht_table == ((void *)0) || 3 * lht->lht_used > 2 * lht->lht_size; } static inline nta_leg_t **leg_htable_hash(leg_htable_t const *lht, hash_value_t hv) { return lht->lht_table + hv % lht->lht_size; } static inline nta_leg_t **leg_htable_next(leg_htable_t const *lht, nta_leg_t * const *ee) { if (++ee < lht->lht_table + lht->lht_size && ee >= lht->lht_table) return (nta_leg_t **) ee; else return lht->lht_table; } static inline void leg_htable_append (leg_htable_t *lht, nta_leg_t const *e) { nta_leg_t **ee; lht ->lht_used++; for (ee = leg_htable_hash(lht, ((e)->leg_hash )); *ee; ee = leg_htable_next(lht, ee)) ; *ee = (nta_leg_t *) e; } static inline void leg_htable_insert(leg_htable_t *lht, nta_leg_t const *e) { nta_leg_t *e0, **ee; lht->lht_used++; for (ee = leg_htable_hash(lht, ((e)->leg_hash)); (e0 = *ee); ee = leg_htable_next(lht, ee)) *ee = (nta_leg_t *)e, e = e0; *ee = (nta_leg_t *)e; } static inline int leg_htable_remove(leg_htable_t *lht, nta_leg_t const *e) { size_t i, j, k; size_t size = lht ->lht_size; nta_leg_t **htable = lht->lht_table; if (!e ) return -1; for (i = ((e)->leg_hash) % size; htable[i]; i = (i + 1) % size) if (e == htable[i]) break; if (!htable[i]) return -1; for (j = (i + 1) % size; htable[j]; j = (j + 1) % size) { k = ((htable[j])->leg_hash) % size; if (k == j) continue ; if (j > i ? (i < k && k < j) : (i < k || k < j)) continue; htable[i] = htable[j], i = j; } lht-> lht_used--; htable[i] = ((void*)0); return 0; } extern int leg_htable_dummy; | ||||||||
4217 | |||||||||
4218 | #ifdef __clang__1 | ||||||||
4219 | #pragma clang diagnostic pop | ||||||||
4220 | #endif | ||||||||
4221 | |||||||||
4222 | su_inlinestatic inline | ||||||||
4223 | hash_value_t hash_istring(char const *, char const *, hash_value_t); | ||||||||
4224 | |||||||||
4225 | /**@typedef nta_request_f | ||||||||
4226 | * | ||||||||
4227 | * Callback for incoming requests | ||||||||
4228 | * | ||||||||
4229 | * This is a callback function invoked by NTA for each incoming SIP request. | ||||||||
4230 | * | ||||||||
4231 | * @param lmagic call leg context | ||||||||
4232 | * @param leg call leg handle | ||||||||
4233 | * @param ireq incoming request | ||||||||
4234 | * @param sip incoming request contents | ||||||||
4235 | * | ||||||||
4236 | * @retval 100..699 | ||||||||
4237 | * NTA constructs a reply message with given error code and corresponding | ||||||||
4238 | * standard phrase, then sends the reply. | ||||||||
4239 | * | ||||||||
4240 | * @retval 0 | ||||||||
4241 | * The application takes care of sending (or not sending) the reply. | ||||||||
4242 | * | ||||||||
4243 | * @retval other | ||||||||
4244 | * All other return values will be interpreted as | ||||||||
4245 | * @e 500 @e Internal @e server @e error. | ||||||||
4246 | */ | ||||||||
4247 | |||||||||
4248 | |||||||||
4249 | /** | ||||||||
4250 | * Create a new leg object. | ||||||||
4251 | * | ||||||||
4252 | * Creates a leg object, which is used to represent dialogs, partial dialogs | ||||||||
4253 | * (for example, in case of REGISTER), and destinations within a particular | ||||||||
4254 | * NTA object. | ||||||||
4255 | * | ||||||||
4256 | * When a leg is created, a callback pointer and a application context is | ||||||||
4257 | * provided. All other parameters are optional. | ||||||||
4258 | * | ||||||||
4259 | * @param agent agent object | ||||||||
4260 | * @param callback function which is called for each | ||||||||
4261 | * incoming request belonging to this leg | ||||||||
4262 | * @param magic call leg context | ||||||||
4263 | * @param tag,value,... optional extra headers in taglist | ||||||||
4264 | * | ||||||||
4265 | * When a leg representing dialog is created, the tags SIPTAG_CALL_ID(), | ||||||||
4266 | * SIPTAG_FROM(), SIPTAG_TO(), and SIPTAG_CSEQ() (for local @CSeq number) are used | ||||||||
4267 | * to establish dialog context. The SIPTAG_FROM() is used to pass local | ||||||||
4268 | * address (@From header when making a call, @To header when answering | ||||||||
4269 | * to a call) to the newly created leg. Respectively, the SIPTAG_TO() is | ||||||||
4270 | * used to pass remote address (@To header when making a call, @From | ||||||||
4271 | * header when answering to a call). | ||||||||
4272 | * | ||||||||
4273 | * If there is a (preloaded) route associated with the leg, SIPTAG_ROUTE() | ||||||||
4274 | * and NTATAG_TARGET() can be used. A client or server can also set the | ||||||||
4275 | * route using @RecordRoute and @Contact headers from a response or | ||||||||
4276 | * request message with the functions nta_leg_client_route() and | ||||||||
4277 | * nta_leg_server_route(), respectively. | ||||||||
4278 | * | ||||||||
4279 | * When a leg representing a local destination is created, the tags | ||||||||
4280 | * NTATAG_NO_DIALOG(1), NTATAG_METHOD(), and URLTAG_URL() are used. When a | ||||||||
4281 | * request with matching request-URI (URLTAG_URL()) and method | ||||||||
4282 | * (NTATAG_METHOD()) is received, it is passed to the callback function | ||||||||
4283 | * provided with the leg. | ||||||||
4284 | * | ||||||||
4285 | * @sa nta_leg_stateful(), nta_leg_bind(), | ||||||||
4286 | * nta_leg_tag(), nta_leg_rtag(), | ||||||||
4287 | * nta_leg_client_route(), nta_leg_server_route(), | ||||||||
4288 | * nta_leg_destroy(), nta_outgoing_tcreate(), and nta_request_f(). | ||||||||
4289 | * | ||||||||
4290 | * @TAGS | ||||||||
4291 | * NTATAG_NO_DIALOG(), NTATAG_STATELESS(), NTATAG_METHOD(), | ||||||||
4292 | * URLTAG_URL(), SIPTAG_CALL_ID(), SIPTAG_CALL_ID_STR(), SIPTAG_FROM(), | ||||||||
4293 | * SIPTAG_FROM_STR(), SIPTAG_TO(), SIPTAG_TO_STR(), SIPTAG_ROUTE(), | ||||||||
4294 | * NTATAG_TARGET() and SIPTAG_CSEQ(). | ||||||||
4295 | * | ||||||||
4296 | */ | ||||||||
4297 | nta_leg_t *nta_leg_tcreate(nta_agent_t *agent, | ||||||||
4298 | nta_request_f *callback, | ||||||||
4299 | nta_leg_magic_t *magic, | ||||||||
4300 | tag_type_t tag, tag_value_t value, ...) | ||||||||
4301 | { | ||||||||
4302 | sip_route_t const *route = NULL((void*)0); | ||||||||
4303 | sip_contact_t const *contact = NULL((void*)0); | ||||||||
4304 | sip_cseq_t const *cs = NULL((void*)0); | ||||||||
4305 | sip_call_id_t const *i = NULL((void*)0); | ||||||||
4306 | sip_from_t const *from = NULL((void*)0); | ||||||||
4307 | sip_to_t const *to = NULL((void*)0); | ||||||||
4308 | char const *method = NULL((void*)0); | ||||||||
4309 | char const *i_str = NULL((void*)0), *to_str = NULL((void*)0), *from_str = NULL((void*)0), *cs_str = NULL((void*)0); | ||||||||
4310 | url_string_t const *url_string = NULL((void*)0); | ||||||||
4311 | int no_dialog = 0; | ||||||||
4312 | unsigned rseq = 0; | ||||||||
4313 | /* RFC 3261 section 12.2.1.1 */ | ||||||||
4314 | uint32_t seq = 0; | ||||||||
4315 | ta_list ta; | ||||||||
4316 | nta_leg_t *leg; | ||||||||
4317 | su_home_t *home; | ||||||||
4318 | url_t *url; | ||||||||
4319 | char const *what = NULL((void*)0); | ||||||||
4320 | |||||||||
4321 | if (agent == NULL((void*)0)) | ||||||||
4322 | return su_seterrno(EINVAL22), NULL((void*)0); | ||||||||
4323 | |||||||||
4324 | 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); | ||||||||
4325 | |||||||||
4326 | tl_gets(ta_args(ta)(ta).tl, | ||||||||
4327 | NTATAG_NO_DIALOG_REF(no_dialog)ntatag_no_dialog_ref, tag_bool_vr(&(no_dialog)), | ||||||||
4328 | NTATAG_METHOD_REF(method)ntatag_method_ref, tag_str_vr(&(method)), | ||||||||
4329 | URLTAG_URL_REF(url_string)urltag_url_ref, urltag_url_vr(&(url_string)), | ||||||||
4330 | SIPTAG_CALL_ID_REF(i)siptag_call_id_ref, siptag_call_id_vr(&(i)), | ||||||||
4331 | SIPTAG_CALL_ID_STR_REF(i_str)siptag_call_id_str_ref, tag_str_vr(&(i_str)), | ||||||||
4332 | SIPTAG_FROM_REF(from)siptag_from_ref, siptag_from_vr(&(from)), | ||||||||
4333 | SIPTAG_FROM_STR_REF(from_str)siptag_from_str_ref, tag_str_vr(&(from_str)), | ||||||||
4334 | SIPTAG_TO_REF(to)siptag_to_ref, siptag_to_vr(&(to)), | ||||||||
4335 | SIPTAG_TO_STR_REF(to_str)siptag_to_str_ref, tag_str_vr(&(to_str)), | ||||||||
4336 | SIPTAG_ROUTE_REF(route)siptag_route_ref, siptag_route_vr(&(route)), | ||||||||
4337 | NTATAG_TARGET_REF(contact)ntatag_target_ref, siptag_contact_vr(&(contact)), | ||||||||
4338 | NTATAG_REMOTE_CSEQ_REF(rseq)ntatag_remote_cseq_ref, tag_uint_vr(&(rseq)), | ||||||||
4339 | SIPTAG_CSEQ_REF(cs)siptag_cseq_ref, siptag_cseq_vr(&(cs)), | ||||||||
4340 | SIPTAG_CSEQ_STR_REF(cs_str)siptag_cseq_str_ref, tag_str_vr(&(cs_str)), | ||||||||
4341 | TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
4342 | |||||||||
4343 | 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)); | ||||||||
4344 | |||||||||
4345 | if (cs) | ||||||||
4346 | seq = cs->cs_seq; | ||||||||
4347 | else if (cs_str) | ||||||||
4348 | seq = strtoul(cs_str, (char **)&cs_str, 10); | ||||||||
4349 | |||||||||
4350 | if (i == NONE((void *)-1)) /* Magic value, used for compatibility */ | ||||||||
4351 | no_dialog = 1; | ||||||||
4352 | |||||||||
4353 | if (!(leg = su_home_clone(NULL((void*)0), sizeof(*leg)))) | ||||||||
4354 | return NULL((void*)0); | ||||||||
4355 | home = leg->leg_home; | ||||||||
4356 | |||||||||
4357 | leg->leg_agent = agent; | ||||||||
4358 | nta_leg_bind(leg, callback, magic); | ||||||||
4359 | |||||||||
4360 | if (from) { | ||||||||
4361 | /* Now this is kludge */ | ||||||||
4362 | leg->leg_local_is_to = sip_is_to((sip_header_t*)from); | ||||||||
4363 | leg->leg_local = sip_to_dup(home, from); | ||||||||
4364 | } | ||||||||
4365 | else if (from_str) | ||||||||
4366 | leg->leg_local = sip_to_make(home, from_str); | ||||||||
4367 | |||||||||
4368 | if (to && no_dialog) { | ||||||||
4369 | /* Remove tag, if any */ | ||||||||
4370 | sip_to_t to0[1]; *to0 = *to; to0->a_params = NULL((void*)0); | ||||||||
4371 | leg->leg_remote = sip_from_dup(home, to0); | ||||||||
4372 | } | ||||||||
4373 | else if (to) | ||||||||
4374 | leg->leg_remote = sip_from_dup(home, to); | ||||||||
4375 | else if (to_str) | ||||||||
4376 | leg->leg_remote = sip_from_make(home, to_str); | ||||||||
4377 | |||||||||
4378 | if (route && route != NONE((void *)-1)) | ||||||||
4379 | leg->leg_route = sip_route_dup(home, route), leg->leg_route_set = 1; | ||||||||
4380 | |||||||||
4381 | if (contact && contact != NONE((void *)-1)) { | ||||||||
4382 | sip_contact_t m[1]; | ||||||||
4383 | sip_contact_init(m); | ||||||||
4384 | *m->m_url = *contact->m_url; | ||||||||
4385 | m->m_url->url_headers = NULL((void*)0); | ||||||||
4386 | leg->leg_target = sip_contact_dup(home, m); | ||||||||
4387 | } | ||||||||
4388 | |||||||||
4389 | url = url_hdup(home, url_string->us_url); | ||||||||
4390 | |||||||||
4391 | /* Match to local hosts */ | ||||||||
4392 | if (url && agent_aliases(agent, url, NULL((void*)0))) { | ||||||||
4393 | url_t *changed = url_hdup(home, url); | ||||||||
4394 | su_free(home, url); | ||||||||
4395 | url = changed; | ||||||||
4396 | } | ||||||||
4397 | |||||||||
4398 | leg->leg_rseq = rseq; | ||||||||
4399 | leg->leg_seq = seq; | ||||||||
4400 | leg->leg_url = url; | ||||||||
4401 | |||||||||
4402 | if (from && from != NONE((void *)-1) && leg->leg_local == NULL((void*)0)) { | ||||||||
4403 | what = "cannot duplicate local address"; | ||||||||
4404 | goto err; | ||||||||
4405 | } | ||||||||
4406 | else if (to && to != NONE((void *)-1) && leg->leg_remote == NULL((void*)0)) { | ||||||||
4407 | what = "cannot duplicate remote address"; | ||||||||
4408 | goto err; | ||||||||
4409 | } | ||||||||
4410 | else if (route && route != NONE((void *)-1) && leg->leg_route == NULL((void*)0)) { | ||||||||
4411 | what = "cannot duplicate route"; | ||||||||
4412 | goto err; | ||||||||
4413 | } | ||||||||
4414 | else if (contact && contact != NONE((void *)-1) && leg->leg_target == NULL((void*)0)) { | ||||||||
4415 | what = "cannot duplicate target"; | ||||||||
4416 | goto err; | ||||||||
4417 | } | ||||||||
4418 | else if (url_string && leg->leg_url == NULL((void*)0)) { | ||||||||
4419 | what = "cannot duplicate local destination"; | ||||||||
4420 | goto err; | ||||||||
4421 | } | ||||||||
4422 | |||||||||
4423 | if (!no_dialog) { | ||||||||
4424 | if (!leg->leg_local || !leg->leg_remote) { | ||||||||
4425 | /* To and/or From header missing */ | ||||||||
4426 | if (leg->leg_remote) | ||||||||
4427 | what = "Missing local dialog address"; | ||||||||
4428 | else if (leg->leg_local) | ||||||||
4429 | what = "Missing remote dialog address"; | ||||||||
4430 | else | ||||||||
4431 | what = "Missing dialog addresses"; | ||||||||
4432 | goto err; | ||||||||
4433 | } | ||||||||
4434 | |||||||||
4435 | leg->leg_dialog = 1; | ||||||||
4436 | |||||||||
4437 | if (i != NULL((void*)0)) | ||||||||
4438 | leg->leg_id = sip_call_id_dup(home, i); | ||||||||
4439 | else if (i_str != NULL((void*)0)) | ||||||||
4440 | leg->leg_id = sip_call_id_make(home, i_str); | ||||||||
4441 | else | ||||||||
4442 | leg->leg_id = sip_call_id_create(home, NULL((void*)0)); | ||||||||
4443 | |||||||||
4444 | if (!leg->leg_id) { | ||||||||
4445 | what = "cannot create Call-ID"; | ||||||||
4446 | goto err; | ||||||||
4447 | } | ||||||||
4448 | |||||||||
4449 | leg->leg_hash = leg->leg_id->i_hash; | ||||||||
4450 | } | ||||||||
4451 | else if (url) { | ||||||||
4452 | /* This is "default leg" with a destination URL. */ | ||||||||
4453 | hash_value_t hash = 0; | ||||||||
4454 | |||||||||
4455 | if (method) { | ||||||||
4456 | leg->leg_method = su_strdup(home, method); | ||||||||
4457 | } | ||||||||
4458 | #if 0 | ||||||||
4459 | else if (url->url_params) { | ||||||||
4460 | int len = url_param(url->url_params, "method", NULL((void*)0), 0); | ||||||||
4461 | if (len) { | ||||||||
4462 | char *tmp = su_alloc(home, len); | ||||||||
4463 | leg->leg_method = tmp; | ||||||||
4464 | url_param(url->url_params, "method", tmp, len); | ||||||||
4465 | } | ||||||||
4466 | } | ||||||||
4467 | #endif | ||||||||
4468 | |||||||||
4469 | if (url->url_user && strcmp(url->url_user, "") == 0) | ||||||||
4470 | url->url_user = "%"; /* Match to any user */ | ||||||||
4471 | |||||||||
4472 | hash = hash_istring(url->url_scheme, ":", 0); | ||||||||
4473 | hash = hash_istring(url->url_host, "", hash); | ||||||||
4474 | hash = hash_istring(url->url_user, "@", hash); | ||||||||
4475 | |||||||||
4476 | leg->leg_hash = hash; | ||||||||
4477 | } | ||||||||
4478 | else { | ||||||||
4479 | /* This is "default leg" without a destination URL. */ | ||||||||
4480 | if (agent->sa_default_leg) { | ||||||||
4481 | 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__ , 4481, "%s(): %s\n", "nta_leg_tcreate", "tried to create second default leg" )) : (void)0); | ||||||||
4482 | su_seterrno(EEXIST17); | ||||||||
4483 | goto err; | ||||||||
4484 | } | ||||||||
4485 | else { | ||||||||
4486 | agent->sa_default_leg = leg; | ||||||||
4487 | } | ||||||||
4488 | return leg; | ||||||||
4489 | } | ||||||||
4490 | |||||||||
4491 | if (url) { | ||||||||
4492 | /* Parameters are ignored when comparing incoming URLs */ | ||||||||
4493 | url->url_params = NULL((void*)0); | ||||||||
4494 | } | ||||||||
4495 | |||||||||
4496 | leg_insert(agent, leg); | ||||||||
4497 | |||||||||
4498 | 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__ , 4498, "%s(%p)\n", "nta_leg_tcreate", (void *)leg)) : (void) 0); | ||||||||
4499 | |||||||||
4500 | return leg; | ||||||||
4501 | |||||||||
4502 | err: | ||||||||
4503 | if (what) | ||||||||
4504 | 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__ , 4504, "%s(): %s\n", "nta_leg_tcreate", what)) : (void)0); | ||||||||
4505 | |||||||||
4506 | su_home_zap(leg->leg_home)su_home_unref((leg->leg_home)); | ||||||||
4507 | |||||||||
4508 | return NULL((void*)0); | ||||||||
4509 | } | ||||||||
4510 | |||||||||
4511 | /** Return the default leg, if any */ | ||||||||
4512 | nta_leg_t *nta_default_leg(nta_agent_t const *agent) | ||||||||
4513 | { | ||||||||
4514 | return agent ? agent->sa_default_leg : NULL((void*)0); | ||||||||
4515 | } | ||||||||
4516 | |||||||||
4517 | |||||||||
4518 | /** | ||||||||
4519 | * Insert a call leg to agent. | ||||||||
4520 | */ | ||||||||
4521 | static | ||||||||
4522 | void leg_insert(nta_agent_t *sa, nta_leg_t *leg) | ||||||||
4523 | { | ||||||||
4524 | leg_htable_t *leg_hash; | ||||||||
4525 | assert(leg)((void) sizeof ((leg) ? 1 : 0), __extension__ ({ if (leg) ; else __assert_fail ("leg", "nta.c", 4525, __extension__ __PRETTY_FUNCTION__ ); })); | ||||||||
4526 | assert(sa)((void) sizeof ((sa) ? 1 : 0), __extension__ ({ if (sa) ; else __assert_fail ("sa", "nta.c", 4526, __extension__ __PRETTY_FUNCTION__ ); })); | ||||||||
4527 | |||||||||
4528 | if (leg->leg_dialog) | ||||||||
4529 | leg_hash = sa->sa_dialogs; | ||||||||
4530 | else | ||||||||
4531 | leg_hash = sa->sa_defaults; | ||||||||
4532 | |||||||||
4533 | if (leg_htable_is_full(leg_hash)) { | ||||||||
4534 | leg_htable_resize(sa->sa_home, leg_hash, 0); | ||||||||
4535 | assert(leg_hash->lht_table)((void) sizeof ((leg_hash->lht_table) ? 1 : 0), __extension__ ({ if (leg_hash->lht_table) ; else __assert_fail ("leg_hash->lht_table" , "nta.c", 4535, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
4536 | 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__ , 4537, "nta: resized%s leg hash to ""%zu""\n", leg->leg_dialog ? "" : " default", leg_hash->lht_size)) : (void)0) | ||||||||
4537 | 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__ , 4537, "nta: resized%s leg hash to ""%zu""\n", leg->leg_dialog ? "" : " default", leg_hash->lht_size)) : (void)0); | ||||||||
4538 | } | ||||||||
4539 | |||||||||
4540 | /* Insert entry into hash table (before other legs with same hash) */ | ||||||||
4541 | leg_htable_insert(leg_hash, leg); | ||||||||
4542 | } | ||||||||
4543 | |||||||||
4544 | /** | ||||||||
4545 | * Destroy a leg. | ||||||||
4546 | * | ||||||||
4547 | * @param leg leg to be destroyed | ||||||||
4548 | */ | ||||||||
4549 | void nta_leg_destroy(nta_leg_t *leg) | ||||||||
4550 | { | ||||||||
4551 | 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__ , 4551, "nta_leg_destroy(%p)\n", (void *)leg)) : (void)0); | ||||||||
4552 | |||||||||
4553 | if (leg) { | ||||||||
4554 | leg_htable_t *leg_hash; | ||||||||
4555 | nta_agent_t *sa = leg->leg_agent; | ||||||||
4556 | |||||||||
4557 | assert(sa)((void) sizeof ((sa) ? 1 : 0), __extension__ ({ if (sa) ; else __assert_fail ("sa", "nta.c", 4557, __extension__ __PRETTY_FUNCTION__ ); })); | ||||||||
4558 | |||||||||
4559 | if (leg->leg_dialog) { | ||||||||
4560 | assert(sa->sa_dialogs)((void) sizeof ((sa->sa_dialogs) ? 1 : 0), __extension__ ( { if (sa->sa_dialogs) ; else __assert_fail ("sa->sa_dialogs" , "nta.c", 4560, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
4561 | leg_hash = sa->sa_dialogs; | ||||||||
4562 | } | ||||||||
4563 | else if (leg != sa->sa_default_leg) { | ||||||||
4564 | assert(sa->sa_defaults)((void) sizeof ((sa->sa_defaults) ? 1 : 0), __extension__ ( { if (sa->sa_defaults) ; else __assert_fail ("sa->sa_defaults" , "nta.c", 4564, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
4565 | leg_hash = sa->sa_defaults; | ||||||||
4566 | } | ||||||||
4567 | else { | ||||||||
4568 | sa->sa_default_leg = NULL((void*)0); | ||||||||
4569 | leg_hash = NULL((void*)0); | ||||||||
4570 | } | ||||||||
4571 | |||||||||
4572 | if (leg_hash) | ||||||||
4573 | leg_htable_remove(leg_hash, leg); | ||||||||
4574 | |||||||||
4575 | leg_free(sa, leg); | ||||||||
4576 | } | ||||||||
4577 | } | ||||||||
4578 | |||||||||
4579 | static | ||||||||
4580 | void leg_free(nta_agent_t *sa, nta_leg_t *leg) | ||||||||
4581 | { | ||||||||
4582 | //su_free(sa->sa_home, leg); | ||||||||
4583 | su_home_unref((su_home_t *)leg); | ||||||||
4584 | } | ||||||||
4585 | |||||||||
4586 | /** Return application context for the leg */ | ||||||||
4587 | nta_leg_magic_t *nta_leg_magic(nta_leg_t const *leg, | ||||||||
4588 | nta_request_f *callback) | ||||||||
4589 | { | ||||||||
4590 | if (leg) | ||||||||
4591 | if (!callback || leg->leg_callback == callback) | ||||||||
4592 | return leg->leg_magic; | ||||||||
4593 | |||||||||
4594 | return NULL((void*)0); | ||||||||
4595 | } | ||||||||
4596 | |||||||||
4597 | /**Bind a callback function and context to a leg object. | ||||||||
4598 | * | ||||||||
4599 | * Change the callback function and context pointer attached to a leg | ||||||||
4600 | * object. | ||||||||
4601 | * | ||||||||
4602 | * @param leg leg object to be bound | ||||||||
4603 | * @param callback new callback function (or NULL if no callback is desired) | ||||||||
4604 | * @param magic new context pointer | ||||||||
4605 | */ | ||||||||
4606 | void nta_leg_bind(nta_leg_t *leg, | ||||||||
4607 | nta_request_f *callback, | ||||||||
4608 | nta_leg_magic_t *magic) | ||||||||
4609 | { | ||||||||
4610 | if (leg) { | ||||||||
4611 | if (callback) | ||||||||
4612 | leg->leg_callback = callback; | ||||||||
4613 | else | ||||||||
4614 | leg->leg_callback = leg_callback_default; | ||||||||
4615 | leg->leg_magic = magic; | ||||||||
4616 | } | ||||||||
4617 | } | ||||||||
4618 | |||||||||
4619 | /** Add a local tag to the leg. | ||||||||
4620 | * | ||||||||
4621 | * @param leg leg to be tagged | ||||||||
4622 | * @param tag tag to be added (if NULL, a tag generated by @b NTA is added) | ||||||||
4623 | * | ||||||||
4624 | * @return | ||||||||
4625 | * Pointer to tag if successful, NULL otherwise. | ||||||||
4626 | */ | ||||||||
4627 | char const *nta_leg_tag(nta_leg_t *leg, char const *tag) | ||||||||
4628 | { | ||||||||
4629 | if (!leg || !leg->leg_local) | ||||||||
4630 | return su_seterrno(EINVAL22), NULL((void*)0); | ||||||||
4631 | |||||||||
4632 | if (tag && strchr(tag, '=')) | ||||||||
4633 | tag = strchr(tag, '=') + 1; | ||||||||
4634 | |||||||||
4635 | /* If there already is a tag, | ||||||||
4636 | return NULL if it does not match with new one */ | ||||||||
4637 | if (leg->leg_local->a_tag) { | ||||||||
4638 | if (tag == NULL((void*)0) || su_casematch(tag, leg->leg_local->a_tag)) | ||||||||
4639 | return leg->leg_local->a_tag; | ||||||||
4640 | else | ||||||||
4641 | return NULL((void*)0); | ||||||||
4642 | } | ||||||||
4643 | |||||||||
4644 | if (tag) { | ||||||||
4645 | if (sip_to_tag(leg->leg_home, leg->leg_local, tag) < 0) | ||||||||
4646 | return NULL((void*)0); | ||||||||
4647 | leg->leg_tagged = 1; | ||||||||
4648 | return leg->leg_local->a_tag; | ||||||||
4649 | } | ||||||||
4650 | |||||||||
4651 | tag = nta_agent_newtag(leg->leg_home, "tag=%s", leg->leg_agent); | ||||||||
4652 | |||||||||
4653 | if (!tag || sip_to_add_param(leg->leg_home, leg->leg_local, tag) < 0) | ||||||||
4654 | return NULL((void*)0); | ||||||||
4655 | |||||||||
4656 | leg->leg_tagged = 1; | ||||||||
4657 | |||||||||
4658 | return leg->leg_local->a_tag; | ||||||||
4659 | } | ||||||||
4660 | |||||||||
4661 | /** Get local tag. */ | ||||||||
4662 | char const *nta_leg_get_tag(nta_leg_t const *leg) | ||||||||
4663 | { | ||||||||
4664 | if (leg && leg->leg_local) | ||||||||
4665 | return leg->leg_local->a_tag; | ||||||||
4666 | else | ||||||||
4667 | return NULL((void*)0); | ||||||||
4668 | } | ||||||||
4669 | |||||||||
4670 | /** Add a remote tag to the leg. | ||||||||
4671 | * | ||||||||
4672 | * @note No remote tag is ever generated. | ||||||||
4673 | * | ||||||||
4674 | * @param leg leg to be tagged | ||||||||
4675 | * @param tag tag to be added (@b must be non-NULL) | ||||||||
4676 | * | ||||||||
4677 | * @return | ||||||||
4678 | * Pointer to tag if successful, NULL otherwise. | ||||||||
4679 | */ | ||||||||
4680 | char const *nta_leg_rtag(nta_leg_t *leg, char const *tag) | ||||||||
4681 | { | ||||||||
4682 | /* Add a tag parameter, unless there already is a tag */ | ||||||||
4683 | if (leg && leg->leg_remote && tag) { | ||||||||
4684 | if (sip_from_tag(leg->leg_home, leg->leg_remote, tag) < 0) | ||||||||
4685 | return NULL((void*)0); | ||||||||
4686 | } | ||||||||
4687 | |||||||||
4688 | if (leg && leg->leg_remote) | ||||||||
4689 | return leg->leg_remote->a_tag; | ||||||||
4690 | else | ||||||||
4691 | return NULL((void*)0); | ||||||||
4692 | } | ||||||||
4693 | |||||||||
4694 | /** Get remote tag. */ | ||||||||
4695 | char const *nta_leg_get_rtag(nta_leg_t const *leg) | ||||||||
4696 | { | ||||||||
4697 | if (leg && leg->leg_remote) | ||||||||
4698 | return leg->leg_remote->a_tag; | ||||||||
4699 | else | ||||||||
4700 | return NULL((void*)0); | ||||||||
4701 | } | ||||||||
4702 | |||||||||
4703 | /** Get local request sequence number. */ | ||||||||
4704 | uint32_t nta_leg_get_seq(nta_leg_t const *leg) | ||||||||
4705 | { | ||||||||
4706 | return leg ? leg->leg_seq : 0; | ||||||||
4707 | } | ||||||||
4708 | |||||||||
4709 | /** Get remote request sequence number. */ | ||||||||
4710 | uint32_t nta_leg_get_rseq(nta_leg_t const *leg) | ||||||||
4711 | { | ||||||||
4712 | return leg ? leg->leg_rseq : 0; | ||||||||
4713 | } | ||||||||
4714 | |||||||||
4715 | /** Save target and route set at UAC side. | ||||||||
4716 | * | ||||||||
4717 | * @sa nta_leg_client_reroute(), nta_leg_server_route(), @RFC3261 section 12.1.2 | ||||||||
4718 | * | ||||||||
4719 | * @bug Allows modifying the route set after initial transaction, if initial | ||||||||
4720 | * transaction had no @RecordRoute headers. | ||||||||
4721 | * | ||||||||
4722 | * @deprecated Use nta_leg_client_reroute() instead. | ||||||||
4723 | */ | ||||||||
4724 | int nta_leg_client_route(nta_leg_t *leg, | ||||||||
4725 | sip_record_route_t const *route, | ||||||||
4726 | sip_contact_t const *contact) | ||||||||
4727 | { | ||||||||
4728 | return leg_route(leg, NULL((void*)0), route, contact, 0); | ||||||||
4729 | } | ||||||||
4730 | |||||||||
4731 | /** Save target and route set at UAC side. | ||||||||
4732 | * | ||||||||
4733 | * If @a initial is true, the route set is modified even if it has been set | ||||||||
4734 | * earlier. | ||||||||
4735 | * | ||||||||
4736 | * @param leg pointer to dialog leg | ||||||||
4737 | * @param route @RecordRoute headers from response | ||||||||
4738 | * @param contact @Contact header from response | ||||||||
4739 | * @param initial true if response to initial transaction | ||||||||
4740 | * | ||||||||
4741 | * @sa nta_leg_client_route(), nta_leg_server_route(), @RFC3261 section 12.1.2 | ||||||||
4742 | * | ||||||||
4743 | * @NEW_1_12_11 | ||||||||
4744 | */ | ||||||||
4745 | int nta_leg_client_reroute(nta_leg_t *leg, | ||||||||
4746 | sip_record_route_t const *route, | ||||||||
4747 | sip_contact_t const *contact, | ||||||||
4748 | int initial) | ||||||||
4749 | { | ||||||||
4750 | return leg_route(leg, NULL((void*)0), route, contact, initial ? 2 : 1); | ||||||||
4751 | } | ||||||||
4752 | |||||||||
4753 | /** Save target and route set at UAS side. | ||||||||
4754 | * | ||||||||
4755 | * @param leg pointer to dialog leg | ||||||||
4756 | * @param route @RecordRoute headers from request | ||||||||
4757 | * @param contact @Contact header from request | ||||||||
4758 | * | ||||||||
4759 | * @sa nta_leg_client_reroute(), @RFC3261 section 12.1.1 | ||||||||
4760 | */ | ||||||||
4761 | int nta_leg_server_route(nta_leg_t *leg, | ||||||||
4762 | sip_record_route_t const *route, | ||||||||
4763 | sip_contact_t const *contact) | ||||||||
4764 | { | ||||||||
4765 | return leg_route(leg, route, NULL((void*)0), contact, 1); | ||||||||
4766 | } | ||||||||
4767 | |||||||||
4768 | /** Return route components. */ | ||||||||
4769 | int nta_leg_get_route(nta_leg_t *leg, | ||||||||
4770 | sip_route_t const **return_route, | ||||||||
4771 | sip_contact_t const **return_target) | ||||||||
4772 | { | ||||||||
4773 | if (!leg) | ||||||||
4774 | return -1; | ||||||||
4775 | |||||||||
4776 | if (return_route) | ||||||||
4777 | *return_route = leg->leg_route; | ||||||||
4778 | |||||||||
4779 | if (return_target) | ||||||||
4780 | *return_target = leg->leg_target; | ||||||||
4781 | |||||||||
4782 | return 0; | ||||||||
4783 | } | ||||||||
4784 | |||||||||
4785 | /** Generate @Replaces header. | ||||||||
4786 | * | ||||||||
4787 | * @since New in @VERSION_1_12_2. | ||||||||
4788 | */ | ||||||||
4789 | sip_replaces_t * | ||||||||
4790 | nta_leg_make_replaces(nta_leg_t *leg, | ||||||||
4791 | su_home_t *home, | ||||||||
4792 | int early_only) | ||||||||
4793 | { | ||||||||
4794 | char const *from_tag, *to_tag; | ||||||||
4795 | |||||||||
4796 | if (!leg) | ||||||||
4797 | return NULL((void*)0); | ||||||||
4798 | if (!leg->leg_dialog || !leg->leg_local || !leg->leg_remote || !leg->leg_id) | ||||||||
4799 | return NULL((void*)0); | ||||||||
4800 | |||||||||
4801 | from_tag = leg->leg_local->a_tag; if (!from_tag) from_tag = "0"; | ||||||||
4802 | to_tag = leg->leg_remote->a_tag; if (!to_tag) to_tag = "0"; | ||||||||
4803 | |||||||||
4804 | return sip_replaces_format(home, "%s;from-tag=%s;to-tag=%s%s", | ||||||||
4805 | leg->leg_id->i_id, from_tag, to_tag, | ||||||||
4806 | early_only ? ";early-only" : ""); | ||||||||
4807 | } | ||||||||
4808 | |||||||||
4809 | /** Get dialog leg by @Replaces header. | ||||||||
4810 | * | ||||||||
4811 | * @since New in @VERSION_1_12_2. | ||||||||
4812 | */ | ||||||||
4813 | nta_leg_t * | ||||||||
4814 | nta_leg_by_replaces(nta_agent_t *sa, sip_replaces_t const *rp) | ||||||||
4815 | { | ||||||||
4816 | nta_leg_t *leg = NULL((void*)0); | ||||||||
4817 | |||||||||
4818 | if (sa && rp && rp->rp_call_id && rp->rp_from_tag && rp->rp_to_tag) { | ||||||||
4819 | char const *from_tag = rp->rp_from_tag, *to_tag = rp->rp_to_tag; | ||||||||
4820 | sip_call_id_t id[1]; | ||||||||
4821 | sip_call_id_init(id); | ||||||||
4822 | |||||||||
4823 | id->i_hash = msg_hash_string(id->i_id = rp->rp_call_id); | ||||||||
4824 | |||||||||
4825 | leg = leg_find(sa, NULL((void*)0), NULL((void*)0), id, from_tag, to_tag); | ||||||||
4826 | |||||||||
4827 | if (leg == NULL((void*)0) && strcmp(from_tag, "0") == 0) | ||||||||
4828 | leg = leg_find(sa, NULL((void*)0), NULL((void*)0), id, NULL((void*)0), to_tag); | ||||||||
4829 | if (leg == NULL((void*)0) && strcmp(to_tag, "0") == 0) | ||||||||
4830 | leg = leg_find(sa, NULL((void*)0), NULL((void*)0), id, from_tag, NULL((void*)0)); | ||||||||
4831 | } | ||||||||
4832 | |||||||||
4833 | return leg; | ||||||||
4834 | } | ||||||||
4835 | |||||||||
4836 | /**@internal | ||||||||
4837 | * Find a leg corresponding to the request message. | ||||||||
4838 | * | ||||||||
4839 | */ | ||||||||
4840 | static nta_leg_t * | ||||||||
4841 | leg_find_call_id(nta_agent_t const *sa, | ||||||||
4842 | sip_call_id_t const *i) | ||||||||
4843 | { | ||||||||
4844 | hash_value_t hash = i->i_hash; | ||||||||
4845 | leg_htable_t const *lht = sa->sa_dialogs; | ||||||||
4846 | nta_leg_t **ll, *leg = NULL((void*)0); | ||||||||
4847 | |||||||||
4848 | for (ll = leg_htable_hash(lht, hash); | ||||||||
4849 | (leg = *ll); | ||||||||
4850 | ll = leg_htable_next(lht, ll)) { | ||||||||
4851 | sip_call_id_t const *leg_i = leg->leg_id; | ||||||||
4852 | |||||||||
4853 | if (leg->leg_hash != hash) | ||||||||
4854 | continue; | ||||||||
4855 | if (strcmp(leg_i->i_id, i->i_id) != 0) | ||||||||
4856 | continue; | ||||||||
4857 | |||||||||
4858 | return leg; | ||||||||
4859 | } | ||||||||
4860 | |||||||||
4861 | return leg; | ||||||||
4862 | } | ||||||||
4863 | |||||||||
4864 | /** Get dialog leg by @CallID. | ||||||||
4865 | * | ||||||||
4866 | * @note Usually there should be only single dialog per @CallID on | ||||||||
4867 | * User-Agents. However, proxies may fork requests initiating the dialog and | ||||||||
4868 | * result in multiple calls per @CallID. | ||||||||
4869 | * | ||||||||
4870 | * @since New in @VERSION_1_12_9. | ||||||||
4871 | */ | ||||||||
4872 | nta_leg_t * | ||||||||
4873 | nta_leg_by_call_id(nta_agent_t *sa, const char *call_id) | ||||||||
4874 | { | ||||||||
4875 | nta_leg_t *leg = NULL((void*)0); | ||||||||
4876 | |||||||||
4877 | if (call_id) { | ||||||||
4878 | sip_call_id_t id[1]; | ||||||||
4879 | sip_call_id_init(id); | ||||||||
4880 | |||||||||
4881 | id->i_hash = msg_hash_string(id->i_id = call_id); | ||||||||
4882 | |||||||||
4883 | leg = leg_find_call_id(sa, id); | ||||||||
4884 | } | ||||||||
4885 | |||||||||
4886 | return leg; | ||||||||
4887 | } | ||||||||
4888 | |||||||||
4889 | /** Calculate a simple case-insensitive hash over a string */ | ||||||||
4890 | su_inlinestatic inline | ||||||||
4891 | hash_value_t hash_istring(char const *s, char const *term, hash_value_t hash) | ||||||||
4892 | { | ||||||||
4893 | if (s) { | ||||||||
4894 | for (; *s; s++) { | ||||||||
4895 | unsigned char c = *s; | ||||||||
4896 | if ('A' <= c && c <= 'Z') | ||||||||
4897 | c += 'a' - 'A'; | ||||||||
4898 | hash = 38501U * (hash + c); | ||||||||
4899 | } | ||||||||
4900 | for (s = term; *s; s++) { | ||||||||
4901 | unsigned char c = *s; | ||||||||
4902 | hash = 38501U * (hash + c); | ||||||||
4903 | } | ||||||||
4904 | } | ||||||||
4905 | |||||||||
4906 | return hash; | ||||||||
4907 | } | ||||||||
4908 | |||||||||
4909 | /** @internal Handle requests intended for this leg. */ | ||||||||
4910 | static | ||||||||
4911 | void leg_recv(nta_leg_t *leg, msg_t *msg, sip_t *sip, tport_t *tport) | ||||||||
4912 | { | ||||||||
4913 | nta_agent_t *agent = leg->leg_agent; | ||||||||
4914 | nta_incoming_t *irq; | ||||||||
4915 | sip_method_t method = sip->sip_request->rq_method; | ||||||||
4916 | char const *method_name = sip->sip_request->rq_method_name; | ||||||||
4917 | char const *tag = NULL((void*)0); | ||||||||
4918 | int status; | ||||||||
4919 | |||||||||
4920 | if (leg->leg_local) | ||||||||
4921 | tag = leg->leg_local->a_tag; | ||||||||
4922 | |||||||||
4923 | if (leg->leg_dialog) | ||||||||
4924 | agent->sa_stats->as_dialog_tr++; | ||||||||
4925 | |||||||||
4926 | /* RFC-3262 section 3 (page 4) */ | ||||||||
4927 | if (agent->sa_is_a_uas && method == sip_method_prack) { | ||||||||
4928 | mreply(agent, NULL((void*)0), 481, "No such response", msg, | ||||||||
4929 | tport, 0, 0, NULL((void*)0), | ||||||||
4930 | TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
4931 | return; | ||||||||
4932 | } | ||||||||
4933 | |||||||||
4934 | if (!(irq = incoming_create(agent, msg, sip, tport, tag))) { | ||||||||
4935 | 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__ , 4936, "nta: leg_recv(%p): cannot create transaction for %s\n" , (void *)leg, method_name)) : (void)0) | ||||||||
4936 | (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__ , 4936, "nta: leg_recv(%p): cannot create transaction for %s\n" , (void *)leg, method_name)) : (void)0); | ||||||||
4937 | mreply(agent, NULL((void*)0), SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error, msg, | ||||||||
4938 | tport, 0, 0, NULL((void*)0), | ||||||||
4939 | TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
4940 | return; | ||||||||
4941 | } | ||||||||
4942 | |||||||||
4943 | irq->irq_compressed = leg->leg_compressed; | ||||||||
4944 | irq->irq_in_callback = 1; | ||||||||
4945 | status = incoming_callback(leg, irq, sip); | ||||||||
4946 | irq->irq_in_callback = 0; | ||||||||
4947 | |||||||||
4948 | if (irq->irq_destroyed) { | ||||||||
4949 | if (irq->irq_terminated) { | ||||||||
4950 | incoming_free(irq); | ||||||||
4951 | return; | ||||||||
4952 | } | ||||||||
4953 | if (status < 200) | ||||||||
4954 | status = 500; | ||||||||
4955 | } | ||||||||
4956 | |||||||||
4957 | if (status == 0) | ||||||||
4958 | return; | ||||||||
4959 | |||||||||
4960 | if (status < 100 || status > 699) { | ||||||||
4961 | 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__ , 4962, "nta_leg(%p): invalid status %03d from callback\n", ( void *)leg, status)) : (void)0) | ||||||||
4962 | (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__ , 4962, "nta_leg(%p): invalid status %03d from callback\n", ( void *)leg, status)) : (void)0); | ||||||||
4963 | status = 500; | ||||||||
4964 | } | ||||||||
4965 | else if (method == sip_method_invite && status >= 200 && status < 300) { | ||||||||
4966 | 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__ , 4967, "nta_leg(%p): invalid INVITE status %03d from callback\n" , (void *)leg, status)) : (void)0) | ||||||||
4967 | (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__ , 4967, "nta_leg(%p): invalid INVITE status %03d from callback\n" , (void *)leg, status)) : (void)0); | ||||||||
4968 | status = 500; | ||||||||
4969 | } | ||||||||
4970 | |||||||||
4971 | if (status >= 100 && irq->irq_status < 200) | ||||||||
4972 | nta_incoming_treply(irq, status, NULL((void*)0), TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
4973 | |||||||||
4974 | if (status >= 200) | ||||||||
4975 | nta_incoming_destroy(irq); | ||||||||
4976 | } | ||||||||
4977 | |||||||||
4978 | #if 0 | ||||||||
4979 | /**Compare two SIP from/to fields. | ||||||||
4980 | * | ||||||||
4981 | * @retval nonzero if matching. | ||||||||
4982 | * @retval zero if not matching. | ||||||||
4983 | */ | ||||||||
4984 | su_inlinestatic inline | ||||||||
4985 | int addr_cmp(url_t const *a, url_t const *b) | ||||||||
4986 | { | ||||||||
4987 | if (b == NULL((void*)0)) | ||||||||
4988 | return 0; | ||||||||
4989 | else | ||||||||
4990 | return | ||||||||
4991 | host_cmp(a->url_host, b->url_host) || | ||||||||
4992 | su_strcmp(a->url_port, b->url_port) || | ||||||||
4993 | su_strcmp(a->url_user, b->url_user); | ||||||||
4994 | } | ||||||||
4995 | #endif | ||||||||
4996 | |||||||||
4997 | /** Get a leg by dialog. | ||||||||
4998 | * | ||||||||
4999 | * Search for a dialog leg from agent's hash table. The matching rules based | ||||||||
5000 | * on parameters are as follows: | ||||||||
5001 | * | ||||||||
5002 | * @param agent pointer to agent object | ||||||||
5003 | * @param request_uri if non-NULL, and there is destination URI | ||||||||
5004 | * associated with the dialog, these URIs must match | ||||||||
5005 | * @param call_id if non-NULL, must match with @CallID header contents | ||||||||
5006 | * @param remote_tag if there is remote tag | ||||||||
5007 | * associated with dialog, @a remote_tag must match | ||||||||
5008 | * @param remote_uri ignored | ||||||||
5009 | * @param local_tag if non-NULL and there is local tag associated with leg, | ||||||||
5010 | * it must math | ||||||||
5011 | * @param local_uri ignored | ||||||||
5012 | * | ||||||||
5013 | * @note | ||||||||
5014 | * If @a remote_tag or @a local_tag is an empty string (""), the tag is | ||||||||
5015 | * ignored when matching legs. | ||||||||
5016 | */ | ||||||||
5017 | nta_leg_t *nta_leg_by_dialog(nta_agent_t const *agent, | ||||||||
5018 | url_t const *request_uri, | ||||||||
5019 | sip_call_id_t const *call_id, | ||||||||
5020 | char const *remote_tag, | ||||||||
5021 | url_t const *remote_uri, | ||||||||
5022 | char const *local_tag, | ||||||||
5023 | url_t const *local_uri) | ||||||||
5024 | { | ||||||||
5025 | void *to_be_freed = NULL((void*)0); | ||||||||
5026 | url_t *url; | ||||||||
5027 | url_t url0[1]; | ||||||||
5028 | nta_leg_t *leg; | ||||||||
5029 | |||||||||
5030 | if (!agent || !call_id) | ||||||||
5031 | return su_seterrno(EINVAL22), NULL((void*)0); | ||||||||
5032 | |||||||||
5033 | if (request_uri == NULL((void*)0)) { | ||||||||
5034 | url = NULL((void*)0); | ||||||||
5035 | } | ||||||||
5036 | else if (URL_IS_STRING(request_uri)((request_uri) && *((url_string_t*)(request_uri))-> us_str != 0)) { | ||||||||
5037 | /* accept a string as URL */ | ||||||||
5038 | to_be_freed = url = url_hdup(NULL((void*)0), request_uri); | ||||||||
5039 | } | ||||||||
5040 | else { | ||||||||
5041 | *url0 = *request_uri, url = url0; | ||||||||
5042 | } | ||||||||
5043 | |||||||||
5044 | if (url) { | ||||||||
5045 | url->url_params = NULL((void*)0); | ||||||||
5046 | agent_aliases(agent, url, NULL((void*)0)); /* canonize url */ | ||||||||
5047 | } | ||||||||
5048 | |||||||||
5049 | if (remote_tag && remote_tag[0] == '\0') | ||||||||
5050 | remote_tag = NULL((void*)0); | ||||||||
5051 | if (local_tag && local_tag[0] == '\0') | ||||||||
5052 | local_tag = NULL((void*)0); | ||||||||
5053 | |||||||||
5054 | leg = leg_find(agent, | ||||||||
5055 | NULL((void*)0), url, | ||||||||
5056 | call_id, | ||||||||
5057 | remote_tag, | ||||||||
5058 | local_tag); | ||||||||
5059 | |||||||||
5060 | if (to_be_freed) su_free(NULL((void*)0), to_be_freed); | ||||||||
5061 | |||||||||
5062 | return leg; | ||||||||
5063 | } | ||||||||
5064 | |||||||||
5065 | /**@internal | ||||||||
5066 | * Find a leg corresponding to the request message. | ||||||||
5067 | * | ||||||||
5068 | * A leg matches to message if leg_match_request() returns true ("Call-ID", | ||||||||
5069 | * "To"-tag, and "From"-tag match). | ||||||||
5070 | */ | ||||||||
5071 | static | ||||||||
5072 | nta_leg_t *leg_find(nta_agent_t const *sa, | ||||||||
5073 | char const *method_name, | ||||||||
5074 | url_t const *request_uri, | ||||||||
5075 | sip_call_id_t const *i, | ||||||||
5076 | char const *from_tag, | ||||||||
5077 | char const *to_tag) | ||||||||
5078 | { | ||||||||
5079 | hash_value_t hash = i->i_hash; | ||||||||
5080 | leg_htable_t const *lht = sa->sa_dialogs; | ||||||||
5081 | nta_leg_t **ll, *leg, *loose_match = NULL((void*)0); | ||||||||
5082 | |||||||||
5083 | for (ll = leg_htable_hash(lht, hash); | ||||||||
5084 | (leg = *ll); | ||||||||
5085 | ll = leg_htable_next(lht, ll)) { | ||||||||
5086 | sip_call_id_t const *leg_i = leg->leg_id; | ||||||||
5087 | char const *remote_tag = leg->leg_remote->a_tag; | ||||||||
5088 | char const *local_tag = leg->leg_local->a_tag; | ||||||||
5089 | |||||||||
5090 | url_t const *leg_url = leg->leg_url; | ||||||||
5091 | char const *leg_method = leg->leg_method; | ||||||||
5092 | |||||||||
5093 | if (leg->leg_hash != hash) | ||||||||
5094 | continue; | ||||||||
5095 | if (strcmp(leg_i->i_id, i->i_id) != 0) | ||||||||
5096 | continue; | ||||||||
5097 | |||||||||
5098 | /* Do not match if the incoming To has tag, but the local does not */ | ||||||||
5099 | if (!local_tag && to_tag) | ||||||||
5100 | continue; | ||||||||
5101 | |||||||||
5102 | /* | ||||||||
5103 | * Do not match if incoming To has no tag and we have local tag | ||||||||
5104 | * and the tag has been there from the beginning. | ||||||||
5105 | */ | ||||||||
5106 | if (local_tag && !to_tag && !leg->leg_tagged) | ||||||||
5107 | continue; | ||||||||
5108 | |||||||||
5109 | /* Do not match if incoming From has no tag but remote has a tag */ | ||||||||
5110 | if (remote_tag && !from_tag) | ||||||||
5111 | continue; | ||||||||
5112 | |||||||||
5113 | /* Avoid matching with itself */ | ||||||||
5114 | if (!remote_tag != !from_tag && !local_tag != !to_tag) | ||||||||
5115 | continue; | ||||||||
5116 | |||||||||
5117 | if (local_tag && to_tag && !su_casematch(local_tag, to_tag) && to_tag[0]) | ||||||||
5118 | continue; | ||||||||
5119 | if (remote_tag && from_tag && !su_casematch(remote_tag, from_tag) && from_tag[0]) | ||||||||
5120 | continue; | ||||||||
5121 | |||||||||
5122 | if (leg_url && request_uri && url_cmp(leg_url, request_uri)) | ||||||||
5123 | continue; | ||||||||
5124 | if (leg_method && method_name && !su_casematch(method_name, leg_method)) | ||||||||
5125 | continue; | ||||||||
5126 | |||||||||
5127 | /* Perfect match if both local and To have tag | ||||||||
5128 | * or local does not have tag. | ||||||||
5129 | */ | ||||||||
5130 | if ((!local_tag || to_tag)) | ||||||||
5131 | return leg; | ||||||||
5132 | |||||||||
5133 | if (loose_match == NULL((void*)0)) | ||||||||
5134 | loose_match = leg; | ||||||||
5135 | } | ||||||||
5136 | |||||||||
5137 | return loose_match; | ||||||||
5138 | } | ||||||||
5139 | |||||||||
5140 | /** Get leg by destination */ | ||||||||
5141 | nta_leg_t *nta_leg_by_uri(nta_agent_t const *agent, url_string_t const *us) | ||||||||
5142 | { | ||||||||
5143 | url_t *url; | ||||||||
5144 | nta_leg_t *leg = NULL((void*)0); | ||||||||
5145 | |||||||||
5146 | if (!agent) | ||||||||
5147 | return NULL((void*)0); | ||||||||
5148 | |||||||||
5149 | if (!us) | ||||||||
5150 | return agent->sa_default_leg; | ||||||||
5151 | |||||||||
5152 | url = url_hdup(NULL((void*)0), us->us_url); | ||||||||
5153 | |||||||||
5154 | if (url) { | ||||||||
5155 | agent_aliases(agent, url, NULL((void*)0)); | ||||||||
5156 | leg = dst_find(agent, url, NULL((void*)0)); | ||||||||
5157 | su_free(NULL((void*)0), url); | ||||||||
5158 | } | ||||||||
5159 | |||||||||
5160 | return leg; | ||||||||
5161 | } | ||||||||
5162 | |||||||||
5163 | /** Find a non-dialog leg corresponding to the request uri u0 */ | ||||||||
5164 | static | ||||||||
5165 | nta_leg_t *dst_find(nta_agent_t const *sa, | ||||||||
5166 | url_t const *u0, | ||||||||
5167 | char const *method_name) | ||||||||
5168 | { | ||||||||
5169 | hash_value_t hash, hash2; | ||||||||
5170 | leg_htable_t const *lht = sa->sa_defaults; | ||||||||
5171 | nta_leg_t **ll, *leg, *loose_match = NULL((void*)0); | ||||||||
5172 | int again; | ||||||||
5173 | url_t url[1]; | ||||||||
5174 | |||||||||
5175 | *url = *u0; | ||||||||
5176 | hash = hash_istring(url->url_scheme, ":", 0); | ||||||||
5177 | hash = hash_istring(url->url_host, "", hash); | ||||||||
5178 | hash2 = hash_istring("%", "@", hash); | ||||||||
5179 | hash = hash_istring(url->url_user, "@", hash); | ||||||||
5180 | |||||||||
5181 | /* First round, search with user name */ | ||||||||
5182 | /* Second round, search without user name */ | ||||||||
5183 | do { | ||||||||
5184 | for (ll = leg_htable_hash(lht, hash); | ||||||||
5185 | (leg = *ll); | ||||||||
5186 | ll = leg_htable_next(lht, ll)) { | ||||||||
5187 | if (leg->leg_hash != hash) | ||||||||
5188 | continue; | ||||||||
5189 | if (url_cmp(url, leg->leg_url)) | ||||||||
5190 | continue; | ||||||||
5191 | if (!method_name) { | ||||||||
5192 | if (leg->leg_method) | ||||||||
5193 | continue; | ||||||||
5194 | return leg; | ||||||||
5195 | } | ||||||||
5196 | else if (leg->leg_method) { | ||||||||
5197 | if (!su_casematch(method_name, leg->leg_method)) | ||||||||
5198 | continue; | ||||||||
5199 | return leg; | ||||||||
5200 | } | ||||||||
5201 | loose_match = leg; | ||||||||
5202 | } | ||||||||
5203 | if (loose_match) | ||||||||
5204 | return loose_match; | ||||||||
5205 | |||||||||
5206 | again = 0; | ||||||||
5207 | |||||||||
5208 | if (url->url_user && strcmp(url->url_user, "%")) { | ||||||||
5209 | url->url_user = "%"; | ||||||||
5210 | hash = hash2; | ||||||||
5211 | again = 1; | ||||||||
5212 | } | ||||||||
5213 | } while (again); | ||||||||
5214 | |||||||||
5215 | return NULL((void*)0); | ||||||||
5216 | } | ||||||||
5217 | |||||||||
5218 | /** Set leg route and target URL. | ||||||||
5219 | * | ||||||||
5220 | * Sets the leg route and contact using the @RecordRoute and @Contact | ||||||||
5221 | * headers. | ||||||||
5222 | * | ||||||||
5223 | * @param reroute - allow rerouting | ||||||||
5224 | * - if 1, follow @RFC3261 semantics | ||||||||
5225 | * - if 2, response to initial transaction) | ||||||||
5226 | */ | ||||||||
5227 | static | ||||||||
5228 | int leg_route(nta_leg_t *leg, | ||||||||
5229 | sip_record_route_t const *route, | ||||||||
5230 | sip_record_route_t const *reverse, | ||||||||
5231 | sip_contact_t const *contact, | ||||||||
5232 | int reroute) | ||||||||
5233 | { | ||||||||
5234 | su_home_t *home = leg->leg_home; | ||||||||
5235 | sip_route_t *r, r0[1], *old; | ||||||||
5236 | int route_is_set; | ||||||||
5237 | |||||||||
5238 | if (!leg) | ||||||||
5239 | return -1; | ||||||||
5240 | |||||||||
5241 | if (route == NULL((void*)0) && reverse == NULL((void*)0) && contact == NULL((void*)0)) | ||||||||
5242 | return 0; | ||||||||
5243 | |||||||||
5244 | sip_route_init(r0); | ||||||||
5245 | |||||||||
5246 | route_is_set = reroute ? leg->leg_route_set : leg->leg_route != NULL((void*)0); | ||||||||
5247 | |||||||||
5248 | if (route_is_set && reroute <= 1) { | ||||||||
5249 | r = leg->leg_route; | ||||||||
5250 | } | ||||||||
5251 | else if (route) { | ||||||||
5252 | r = sip_route_fixdup(home, route); if (!r) return -1; | ||||||||
5253 | } | ||||||||
5254 | else if (reverse) { | ||||||||
5255 | r = sip_route_reverse(home, reverse); if (!r) return -1; | ||||||||
5256 | } | ||||||||
5257 | else | ||||||||
5258 | r = NULL((void*)0); | ||||||||
5259 | |||||||||
5260 | #ifdef NTA_STRICT_ROUTING | ||||||||
5261 | /* | ||||||||
5262 | * Handle Contact according to the RFC2543bis04 sections 16.1, 16.2 and 16.4. | ||||||||
5263 | */ | ||||||||
5264 | if (contact) { | ||||||||
5265 | *r0->r_url = *contact->m_url; | ||||||||
5266 | |||||||||
5267 | if (!(m_r = sip_route_dup(leg->leg_home, r0))) | ||||||||
5268 | return -1; | ||||||||
5269 | |||||||||
5270 | /* Append, but replace last entry if it was generated from contact */ | ||||||||
5271 | for (rr = &r; *rr; rr = &(*rr)->r_next) | ||||||||
5272 | if (leg->leg_contact_set && (*rr)->r_next == NULL((void*)0)) | ||||||||
5273 | break; | ||||||||
5274 | } | ||||||||
5275 | else | ||||||||
5276 | rr = NULL((void*)0); | ||||||||
5277 | |||||||||
5278 | if (rr) { | ||||||||
5279 | if (*rr) | ||||||||
5280 | su_free(leg->leg_home, *rr); | ||||||||
5281 | *rr = m_r; | ||||||||
5282 | } | ||||||||
5283 | if (m_r != NULL((void*)0)) | ||||||||
5284 | leg->leg_contact_set = 1; | ||||||||
5285 | |||||||||
5286 | #else | ||||||||
5287 | if (r && r->r_url->url_params) | ||||||||
5288 | leg->leg_loose_route = url_has_param(r->r_url, "lr"); | ||||||||
5289 | |||||||||
5290 | if (contact) { | ||||||||
5291 | sip_contact_t *target, m[1], *m0; | ||||||||
5292 | |||||||||
5293 | sip_contact_init(m); | ||||||||
5294 | *m->m_url = *contact->m_url; | ||||||||
5295 | m->m_url->url_headers = NULL((void*)0); | ||||||||
5296 | target = sip_contact_dup(leg->leg_home, m); | ||||||||
5297 | |||||||||
5298 | if (target && target->m_url->url_params) { | ||||||||
5299 | /* Remove ttl, method. @RFC3261 table 1, page 152 */ | ||||||||
5300 | char *p = (char *)target->m_url->url_params; | ||||||||
5301 | p = url_strip_param_string(p, "method"); | ||||||||
5302 | p = url_strip_param_string(p, "ttl"); | ||||||||
5303 | target->m_url->url_params = p; | ||||||||
5304 | } | ||||||||
5305 | |||||||||
5306 | m0 = leg->leg_target, leg->leg_target = target; | ||||||||
5307 | |||||||||
5308 | if (m0) | ||||||||
5309 | su_free(leg->leg_home, m0); | ||||||||
5310 | } | ||||||||
5311 | #endif | ||||||||
5312 | |||||||||
5313 | old = leg->leg_route; | ||||||||
5314 | leg->leg_route = r; | ||||||||
5315 | |||||||||
5316 | if (old && old != r) | ||||||||
5317 | msg_header_free(leg->leg_home, (msg_header_t *)old); | ||||||||
5318 | |||||||||
5319 | leg->leg_route_set = 1; | ||||||||
5320 | |||||||||
5321 | return 0; | ||||||||
5322 | } | ||||||||
5323 | |||||||||
5324 | /** @internal Default leg callback. */ | ||||||||
5325 | static int | ||||||||
5326 | leg_callback_default(nta_leg_magic_t *magic, | ||||||||
5327 | nta_leg_t *leg, | ||||||||
5328 | nta_incoming_t *irq, | ||||||||
5329 | sip_t const *sip) | ||||||||
5330 | { | ||||||||
5331 | nta_incoming_treply(irq, | ||||||||
5332 | SIP_501_NOT_IMPLEMENTED501, sip_501_Not_implemented, | ||||||||
5333 | TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
5334 | return 501; | ||||||||
5335 | } | ||||||||
5336 | |||||||||
5337 | /* ====================================================================== */ | ||||||||
5338 | /* 7) Server-side (incoming) transactions */ | ||||||||
5339 | |||||||||
5340 | #define HTABLE_HASH_IRQ(irq)((irq)->irq_hash) ((irq)->irq_hash) | ||||||||
5341 | HTABLE_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; if (new_size == 0) new_size = 2 * iht->iht_size + 1; if (new_size < 31) new_size = 31; if (new_size < 5 * iht->iht_used / 4) new_size = 5 * iht->iht_used / 4; if (!(new_hash = su_zalloc(home, sizeof (*new_hash) * new_size))) return -1; old_size = iht->iht_size ; do for (j = 0; j < old_size; j++) { if (!old_hash[j]) continue ; if (again < 2 && ((old_hash[j])->irq_hash) % old_size > j) { again = 1; continue; } i0 = ((old_hash[j])->irq_hash ) % new_size; for (i = i0; new_hash[i]; i = (i + 1) % new_size , ((void) sizeof ((i != i0) ? 1 : 0), __extension__ ({ if (i != i0) ; else __assert_fail ("i != i0", "nta.c", 5342, __extension__ __PRETTY_FUNCTION__); }))); new_hash[i] = old_hash[j], old_hash [j] = ((void*)0); used++; } while (again++ == 1); iht->iht_table = new_hash, iht->iht_size = new_size; ((void) sizeof ((iht ->iht_used == used) ? 1 : 0), __extension__ ({ if (iht-> iht_used == used) ; else __assert_fail ("iht->iht_used == used" , "nta.c", 5342, __extension__ __PRETTY_FUNCTION__); })); su_free (home, old_hash); return 0; } static inline int incoming_htable_is_full (incoming_htable_t const *iht) { return iht->iht_table == ( (void*)0) || 3 * iht->iht_used > 2 * iht->iht_size; } static inline nta_incoming_t **incoming_htable_hash(incoming_htable_t const *iht, hash_value_t hv) { return iht->iht_table + hv % iht->iht_size; } static inline nta_incoming_t **incoming_htable_next (incoming_htable_t const *iht, nta_incoming_t * const *ee) { if (++ee < iht->iht_table + iht->iht_size && ee >= iht->iht_table) return (nta_incoming_t **)ee; else return iht->iht_table; } static inline void incoming_htable_append (incoming_htable_t *iht, nta_incoming_t const *e) { nta_incoming_t **ee; iht->iht_used++; for (ee = incoming_htable_hash(iht , ((e)->irq_hash)); *ee; ee = incoming_htable_next(iht, ee )) ; *ee = (nta_incoming_t *)e; } static inline void incoming_htable_insert (incoming_htable_t *iht, nta_incoming_t const *e) { nta_incoming_t *e0, **ee; iht->iht_used++; for (ee = incoming_htable_hash (iht, ((e)->irq_hash)); (e0 = *ee); ee = incoming_htable_next (iht, ee)) *ee = (nta_incoming_t *)e, e = e0; *ee = (nta_incoming_t *)e; } static inline int incoming_htable_remove(incoming_htable_t *iht, nta_incoming_t const *e) { size_t i, j, k; size_t size = iht->iht_size; nta_incoming_t **htable = iht->iht_table ; if (!e) return -1; for (i = ((e)->irq_hash) % size; htable [i]; i = (i + 1) % size) if (e == htable[i]) break; if (!htable [i]) return -1; for (j = (i + 1) % size; htable[j]; j = (j + 1 ) % size) { k = ((htable[j])->irq_hash) % size; if (k == j ) continue; if (j > i ? (i < k && k < j) : ( i < k || k < j)) continue; htable[i] = htable[j], i = j ; } iht->iht_used--; htable[i] = ((void*)0); return 0; } extern int incoming_htable_dummy | ||||||||
5342 | 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; if (new_size == 0) new_size = 2 * iht->iht_size + 1; if (new_size < 31) new_size = 31; if (new_size < 5 * iht->iht_used / 4) new_size = 5 * iht->iht_used / 4; if (!(new_hash = su_zalloc(home, sizeof (*new_hash) * new_size))) return -1; old_size = iht->iht_size ; do for (j = 0; j < old_size; j++) { if (!old_hash[j]) continue ; if (again < 2 && ((old_hash[j])->irq_hash) % old_size > j) { again = 1; continue; } i0 = ((old_hash[j])->irq_hash ) % new_size; for (i = i0; new_hash[i]; i = (i + 1) % new_size , ((void) sizeof ((i != i0) ? 1 : 0), __extension__ ({ if (i != i0) ; else __assert_fail ("i != i0", "nta.c", 5342, __extension__ __PRETTY_FUNCTION__); }))); new_hash[i] = old_hash[j], old_hash [j] = ((void*)0); used++; } while (again++ == 1); iht->iht_table = new_hash, iht->iht_size = new_size; ((void) sizeof ((iht ->iht_used == used) ? 1 : 0), __extension__ ({ if (iht-> iht_used == used) ; else __assert_fail ("iht->iht_used == used" , "nta.c", 5342, __extension__ __PRETTY_FUNCTION__); })); su_free (home, old_hash); return 0; } static inline int incoming_htable_is_full (incoming_htable_t const *iht) { return iht->iht_table == ( (void*)0) || 3 * iht->iht_used > 2 * iht->iht_size; } static inline nta_incoming_t **incoming_htable_hash(incoming_htable_t const *iht, hash_value_t hv) { return iht->iht_table + hv % iht->iht_size; } static inline nta_incoming_t **incoming_htable_next (incoming_htable_t const *iht, nta_incoming_t * const *ee) { if (++ee < iht->iht_table + iht->iht_size && ee >= iht->iht_table) return (nta_incoming_t **)ee; else return iht->iht_table; } static inline void incoming_htable_append (incoming_htable_t *iht, nta_incoming_t const *e) { nta_incoming_t **ee; iht->iht_used++; for (ee = incoming_htable_hash(iht , ((e)->irq_hash)); *ee; ee = incoming_htable_next(iht, ee )) ; *ee = (nta_incoming_t *)e; } static inline void incoming_htable_insert (incoming_htable_t *iht, nta_incoming_t const *e) { nta_incoming_t *e0, **ee; iht->iht_used++; for (ee = incoming_htable_hash (iht, ((e)->irq_hash)); (e0 = *ee); ee = incoming_htable_next (iht, ee)) *ee = (nta_incoming_t *)e, e = e0; *ee = (nta_incoming_t *)e; } static inline int incoming_htable_remove(incoming_htable_t *iht, nta_incoming_t const *e) { size_t i, j, k; size_t size = iht->iht_size; nta_incoming_t **htable = iht->iht_table ; if (!e) return -1; for (i = ((e)->irq_hash) % size; htable [i]; i = (i + 1) % size) if (e == htable[i]) break; if (!htable [i]) return -1; for (j = (i + 1) % size; htable[j]; j = (j + 1 ) % size) { k = ((htable[j])->irq_hash) % size; if (k == j ) continue; if (j > i ? (i < k && k < j) : ( i < k || k < j)) continue; htable[i] = htable[j], i = j ; } iht->iht_used--; htable[i] = ((void*)0); return 0; } extern int incoming_htable_dummy; | ||||||||
5343 | |||||||||
5344 | static void incoming_insert(nta_agent_t *agent, | ||||||||
5345 | incoming_queue_t *queue, | ||||||||
5346 | nta_incoming_t *irq); | ||||||||
5347 | |||||||||
5348 | su_inlinestatic inline int incoming_is_queued(nta_incoming_t const *irq); | ||||||||
5349 | su_inlinestatic inline void incoming_queue(incoming_queue_t *queue, nta_incoming_t *); | ||||||||
5350 | su_inlinestatic inline void incoming_remove(nta_incoming_t *irq); | ||||||||
5351 | su_inlinestatic inline void incoming_set_timer(nta_incoming_t *, uint32_t interval); | ||||||||
5352 | su_inlinestatic inline void incoming_reset_timer(nta_incoming_t *); | ||||||||
5353 | su_inlinestatic inline size_t incoming_mass_destroy(nta_agent_t *, incoming_queue_t *); | ||||||||
5354 | |||||||||
5355 | static int incoming_set_params(nta_incoming_t *irq, tagi_t const *tags); | ||||||||
5356 | su_inlinestatic inline | ||||||||
5357 | int incoming_set_compartment(nta_incoming_t *irq, tport_t *tport, msg_t *msg, | ||||||||
5358 | int create_if_needed); | ||||||||
5359 | |||||||||
5360 | su_inlinestatic inline nta_incoming_t | ||||||||
5361 | *incoming_call_callback(nta_incoming_t *, msg_t *, sip_t *); | ||||||||
5362 | su_inlinestatic inline int incoming_final_failed(nta_incoming_t *irq, msg_t *); | ||||||||
5363 | static void incoming_retransmit_reply(nta_incoming_t *irq, tport_t *tport); | ||||||||
5364 | |||||||||
5365 | /** Create a default server transaction. | ||||||||
5366 | * | ||||||||
5367 | * The default server transaction is used by a proxy to forward responses | ||||||||
5368 | * statelessly. | ||||||||
5369 | * | ||||||||
5370 | * @param agent pointer to agent object | ||||||||
5371 | * | ||||||||
5372 | * @retval pointer to default server transaction object | ||||||||
5373 | * @retval NULL if failed | ||||||||
5374 | */ | ||||||||
5375 | nta_incoming_t *nta_incoming_default(nta_agent_t *agent) | ||||||||
5376 | { | ||||||||
5377 | msg_t *msg; | ||||||||
5378 | su_home_t *home; | ||||||||
5379 | nta_incoming_t *irq; | ||||||||
5380 | |||||||||
5381 | if (agent == NULL((void*)0)) | ||||||||
5382 | return su_seterrno(EFAULT14), NULL((void*)0); | ||||||||
5383 | if (agent->sa_default_incoming) | ||||||||
5384 | return su_seterrno(EEXIST17), NULL((void*)0); | ||||||||
5385 | |||||||||
5386 | msg = nta_msg_create(agent, 0); | ||||||||
5387 | if (!msg) | ||||||||
5388 | return NULL((void*)0); | ||||||||
5389 | |||||||||
5390 | irq = su_zalloc(home = msg_home(msg)((su_home_t*)(msg)), sizeof(*irq)); | ||||||||
5391 | if (!irq) | ||||||||
5392 | return (void)msg_destroy(msg), NULL((void*)0); | ||||||||
5393 | |||||||||
5394 | irq->irq_home = home; | ||||||||
5395 | irq->irq_request = NULL((void*)0); | ||||||||
5396 | irq->irq_agent = agent; | ||||||||
5397 | irq->irq_received = agent_now(agent); | ||||||||
5398 | irq->irq_method = sip_method_invalid; | ||||||||
5399 | |||||||||
5400 | irq->irq_default = 1; | ||||||||
5401 | agent->sa_default_incoming = irq; | ||||||||
5402 | |||||||||
5403 | return irq; | ||||||||
5404 | } | ||||||||
5405 | |||||||||
5406 | /** Create a server transaction. | ||||||||
5407 | * | ||||||||
5408 | * Create a server transaction for a request message. This function is used | ||||||||
5409 | * when an element processing requests statelessly wants to process a | ||||||||
5410 | * particular request statefully. | ||||||||
5411 | * | ||||||||
5412 | * @param agent pointer to agent object | ||||||||
5413 | * @param leg pointer to leg object (either @a agent or @a leg may be NULL) | ||||||||
5414 | * @param msg pointer to message object | ||||||||
5415 | * @param sip pointer to SIP structure (may be NULL) | ||||||||
5416 | * @param tag,value,... optional tagged parameters | ||||||||
5417 | * | ||||||||
5418 | * @note | ||||||||
5419 | * The ownership of @a msg is taken over by the function even if the | ||||||||
5420 | * function fails. | ||||||||
5421 | * | ||||||||
5422 | * @TAGS | ||||||||
5423 | * @TAG NTATAG_TPORT() specifies the transport used to receive the request | ||||||||
5424 | * and also default transport for sending the response. | ||||||||
5425 | * | ||||||||
5426 | * @retval nta_incoming_t pointer to the newly created server transaction | ||||||||
5427 | * @retval NULL if failed | ||||||||
5428 | */ | ||||||||
5429 | nta_incoming_t *nta_incoming_create(nta_agent_t *agent, | ||||||||
5430 | nta_leg_t *leg, | ||||||||
5431 | msg_t *msg, | ||||||||
5432 | sip_t *sip, | ||||||||
5433 | tag_type_t tag, tag_value_t value, ...) | ||||||||
5434 | { | ||||||||
5435 | char const *to_tag = NULL((void*)0); | ||||||||
5436 | tport_t *tport = NULL((void*)0); | ||||||||
5437 | ta_list ta; | ||||||||
5438 | nta_incoming_t *irq; | ||||||||
5439 | |||||||||
5440 | if (msg == NULL((void*)0)) | ||||||||
5441 | return NULL((void*)0); | ||||||||
5442 | |||||||||
5443 | if (agent == NULL((void*)0) && leg != NULL((void*)0)) | ||||||||
5444 | agent = leg->leg_agent; | ||||||||
5445 | |||||||||
5446 | if (sip == NULL((void*)0)) | ||||||||
5447 | sip = sip_object(msg); | ||||||||
5448 | |||||||||
5449 | if (agent == NULL((void*)0) || sip == NULL((void*)0) || !sip->sip_request || !sip->sip_cseq) | ||||||||
5450 | return msg_destroy(msg), NULL((void*)0); | ||||||||
5451 | |||||||||
5452 | 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); | ||||||||
5453 | |||||||||
5454 | tl_gets(ta_args(ta)(ta).tl, | ||||||||
5455 | NTATAG_TPORT_REF(tport)ntatag_tport_ref, tag_ptr_vr(&(tport), (tport)), | ||||||||
5456 | TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
5457 | 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)); | ||||||||
5458 | |||||||||
5459 | if (leg && leg->leg_local) | ||||||||
5460 | to_tag = leg->leg_local->a_tag; | ||||||||
5461 | |||||||||
5462 | if (tport == NULL((void*)0)) | ||||||||
5463 | tport = tport_delivered_by(agent->sa_tports, msg); | ||||||||
5464 | |||||||||
5465 | irq = incoming_create(agent, msg, sip, tport, to_tag); | ||||||||
5466 | |||||||||
5467 | if (!irq) | ||||||||
5468 | msg_destroy(msg); | ||||||||
5469 | |||||||||
5470 | return irq; | ||||||||
5471 | } | ||||||||
5472 | |||||||||
5473 | /** @internal Create a new incoming transaction object. */ | ||||||||
5474 | static | ||||||||
5475 | nta_incoming_t *incoming_create(nta_agent_t *agent, | ||||||||
5476 | msg_t *msg, | ||||||||
5477 | sip_t *sip, | ||||||||
5478 | tport_t *tport, | ||||||||
5479 | char const *tag) | ||||||||
5480 | { | ||||||||
5481 | nta_incoming_t *irq = su_zalloc(msg_home(msg)((su_home_t*)(msg)), sizeof(*irq)); | ||||||||
5482 | |||||||||
5483 | agent->sa_stats->as_server_tr++; | ||||||||
5484 | |||||||||
5485 | if (irq) { | ||||||||
5486 | su_home_t *home; | ||||||||
5487 | incoming_queue_t *queue; | ||||||||
5488 | sip_method_t method = sip->sip_request->rq_method; | ||||||||
5489 | |||||||||
5490 | irq->irq_request = msg; | ||||||||
5491 | irq->irq_home = home = msg_home(msg_ref_create(msg))((su_home_t*)(msg_ref_create(msg))); | ||||||||
5492 | irq->irq_agent = agent; | ||||||||
5493 | |||||||||
5494 | irq->irq_received = agent_now(agent); /* Timestamp originally from tport */ | ||||||||
5495 | |||||||||
5496 | irq->irq_method = method; | ||||||||
5497 | irq->irq_rq = sip_request_copy(home, sip->sip_request); | ||||||||
5498 | irq->irq_from = sip_from_copy(home, sip->sip_from); | ||||||||
5499 | irq->irq_to = sip_to_copy(home, sip->sip_to); | ||||||||
5500 | irq->irq_call_id = sip_call_id_copy(home, sip->sip_call_id); | ||||||||
5501 | irq->irq_cseq = sip_cseq_copy(home, sip->sip_cseq); | ||||||||
5502 | irq->irq_via = sip_via_copy(home, sip->sip_via); | ||||||||
5503 | switch (method) { | ||||||||
5504 | case sip_method_ack: | ||||||||
5505 | case sip_method_cancel: | ||||||||
5506 | case sip_method_bye: | ||||||||
5507 | case sip_method_options: | ||||||||
5508 | case sip_method_register: /* Handling Path is up to application */ | ||||||||
5509 | case sip_method_info: | ||||||||
5510 | case sip_method_prack: | ||||||||
5511 | case sip_method_publish: | ||||||||
5512 | break; | ||||||||
5513 | default: | ||||||||
5514 | irq->irq_record_route = | ||||||||
5515 | sip_record_route_copy(home, sip->sip_record_route); | ||||||||
5516 | } | ||||||||
5517 | irq->irq_branch = sip->sip_via->v_branch; | ||||||||
5518 | irq->irq_reliable_tp = tport_is_reliable(tport); | ||||||||
5519 | irq->irq_extra_100 = 0; /* Sending extra 100 trying false by default */ | ||||||||
5520 | |||||||||
5521 | if (sip->sip_timestamp) | ||||||||
5522 | irq->irq_timestamp = sip_timestamp_copy(home, sip->sip_timestamp); | ||||||||
5523 | |||||||||
5524 | /* Tag transaction */ | ||||||||
5525 | if (tag) | ||||||||
5526 | sip_to_tag(home, irq->irq_to, tag); | ||||||||
5527 | irq->irq_tag = irq->irq_to->a_tag; | ||||||||
5528 | |||||||||
5529 | if (method != sip_method_ack) { | ||||||||
5530 | int *use_rport = NULL((void*)0); | ||||||||
5531 | int retry_without_rport = 0; | ||||||||
5532 | |||||||||
5533 | if (agent->sa_server_rport) | ||||||||
5534 | use_rport = &retry_without_rport, retry_without_rport = 1; | ||||||||
5535 | |||||||||
5536 | if (nta_tpn_by_via(irq->irq_tpn, irq->irq_via, use_rport) < 0) | ||||||||
5537 | 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__ , 5537, "%s: bad via\n", __func__)) : (void)0); | ||||||||
5538 | } | ||||||||
5539 | |||||||||
5540 | incoming_set_compartment(irq, tport, msg, 0); | ||||||||
5541 | |||||||||
5542 | if (method == sip_method_invite) { | ||||||||
5543 | irq->irq_must_100rel = | ||||||||
5544 | sip->sip_require && sip_has_feature(sip->sip_require, "100rel"); | ||||||||
5545 | |||||||||
5546 | if (irq->irq_must_100rel || | ||||||||
5547 | (sip->sip_supported && | ||||||||
5548 | sip_has_feature(sip->sip_supported, "100rel"))) { | ||||||||
5549 | irq->irq_rseq = su_randint(1, 0x7fffffff); /* Initialize rseq */ | ||||||||
5550 | } | ||||||||
5551 | |||||||||
5552 | queue = agent->sa_in.proceeding; | ||||||||
5553 | |||||||||
5554 | if (irq->irq_reliable_tp) | ||||||||
5555 | incoming_set_timer(irq, agent->sa_t2 / 2); /* N1 = T2 / 2 */ | ||||||||
5556 | else | ||||||||
5557 | incoming_set_timer(irq, 200); /* N1 = 200 ms */ | ||||||||
5558 | |||||||||
5559 | irq->irq_tport = tport_ref(tport); | ||||||||
5560 | } | ||||||||
5561 | else if (method == sip_method_ack) { | ||||||||
5562 | irq->irq_status = 700; /* Never send reply to ACK */ | ||||||||
5563 | irq->irq_completed = 1; | ||||||||
5564 | if (irq->irq_reliable_tp || !agent->sa_is_a_uas) { | ||||||||
5565 | queue = agent->sa_in.terminated; | ||||||||
5566 | irq->irq_terminated = 1; | ||||||||
5567 | } | ||||||||
5568 | else { | ||||||||
5569 | queue = agent->sa_in.completed; /* Timer J */ | ||||||||
5570 | } | ||||||||
5571 | } | ||||||||
5572 | else { | ||||||||
5573 | queue = agent->sa_in.proceeding; | ||||||||
5574 | /* RFC 4320 (nit-actions-03): | ||||||||
5575 | |||||||||
5576 | Blacklisting on a late response occurs even over reliable transports. | ||||||||
5577 | Thus, if an element processing a request received over a reliable | ||||||||
5578 | transport is delaying its final response at all, sending a 100 Trying | ||||||||
5579 | well in advance of the timeout will prevent blacklisting. Sending a | ||||||||
5580 | 100 Trying immediately will not harm the transaction as it would over | ||||||||
5581 | UDP, but a policy of always sending such a message results in | ||||||||
5582 | unneccessary traffic. A policy of sending a 100 Trying after the | ||||||||
5583 | period of time in which Timer E reaches T2 had this been a UDP hop is | ||||||||
5584 | one reasonable compromise. | ||||||||
5585 | |||||||||
5586 | */ | ||||||||
5587 | if (agent->sa_extra_100 && irq->irq_reliable_tp) | ||||||||
5588 | incoming_set_timer(irq, agent->sa_t2 / 2); /* T2 / 2 */ | ||||||||
5589 | |||||||||
5590 | irq->irq_tport = tport_ref(tport); | ||||||||
5591 | } | ||||||||
5592 | |||||||||
5593 | 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)); | ||||||||
5594 | |||||||||
5595 | incoming_insert(agent, queue, irq); | ||||||||
5596 | } | ||||||||
5597 | |||||||||
5598 | return irq; | ||||||||
5599 | } | ||||||||
5600 | |||||||||
5601 | /** @internal | ||||||||
5602 | * Insert incoming transaction to hash table. | ||||||||
5603 | */ | ||||||||
5604 | static void | ||||||||
5605 | incoming_insert(nta_agent_t *agent, | ||||||||
5606 | incoming_queue_t *queue, | ||||||||
5607 | nta_incoming_t *irq) | ||||||||
5608 | { | ||||||||
5609 | incoming_queue(queue, irq); | ||||||||
5610 | |||||||||
5611 | if (incoming_htable_is_full(agent->sa_incoming)) | ||||||||
5612 | incoming_htable_resize(agent->sa_home, agent->sa_incoming, 0); | ||||||||
5613 | |||||||||
5614 | if (irq->irq_method != sip_method_ack) | ||||||||
5615 | incoming_htable_insert(agent->sa_incoming, irq); | ||||||||
5616 | else | ||||||||
5617 | /* ACK is appended - final response with tags match with it, | ||||||||
5618 | * not with the original INVITE transaction */ | ||||||||
5619 | /* XXX - what about rfc2543 servers, which do not add tag? */ | ||||||||
5620 | incoming_htable_append(agent->sa_incoming, irq); | ||||||||
5621 | } | ||||||||
5622 | |||||||||
5623 | /** Call callback for incoming request */ | ||||||||
5624 | static | ||||||||
5625 | int incoming_callback(nta_leg_t *leg, nta_incoming_t *irq, sip_t *sip) | ||||||||
5626 | { | ||||||||
5627 | sip_method_t method = sip->sip_request->rq_method; | ||||||||
5628 | char const *method_name = sip->sip_request->rq_method_name; | ||||||||
5629 | |||||||||
5630 | /* RFC-3261 section 12.2.2 (page 76) */ | ||||||||
5631 | if (leg->leg_dialog && | ||||||||
5632 | irq->irq_agent->sa_is_a_uas && | ||||||||
5633 | method != sip_method_ack) { | ||||||||
5634 | uint32_t seq = sip->sip_cseq->cs_seq; | ||||||||
5635 | |||||||||
5636 | if (leg->leg_rseq > sip->sip_cseq->cs_seq) { | ||||||||
5637 | 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__ , 5638, "nta_leg(%p): out-of-order %s (%u < %u)\n", (void * )leg, method_name, seq, leg->leg_rseq)) : (void)0) | ||||||||
5638 | (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__ , 5638, "nta_leg(%p): out-of-order %s (%u < %u)\n", (void * )leg, method_name, seq, leg->leg_rseq)) : (void)0); | ||||||||
5639 | return 500; | ||||||||
5640 | } | ||||||||
5641 | |||||||||
5642 | leg->leg_rseq = seq; | ||||||||
5643 | } | ||||||||
5644 | |||||||||
5645 | return leg->leg_callback(leg->leg_magic, leg, irq, sip); | ||||||||
5646 | } | ||||||||
5647 | |||||||||
5648 | /** | ||||||||
5649 | * Destroy an incoming transaction. | ||||||||
5650 | * | ||||||||
5651 | * This function does not actually free transaction object, but marks it as | ||||||||
5652 | * disposable. The object is freed after a timeout. | ||||||||
5653 | * | ||||||||
5654 | * @param irq incoming request object to be destroyed | ||||||||
5655 | */ | ||||||||
5656 | void nta_incoming_destroy(nta_incoming_t *irq) | ||||||||
5657 | { | ||||||||
5658 | if (irq) { | ||||||||
5659 | irq->irq_callback = NULL((void*)0); | ||||||||
5660 | irq->irq_magic = NULL((void*)0); | ||||||||
5661 | irq->irq_destroyed = 1; | ||||||||
5662 | if (!irq->irq_in_callback) { | ||||||||
5663 | if (irq->irq_terminated || irq->irq_default) | ||||||||
5664 | incoming_free(irq); | ||||||||
5665 | else if (irq->irq_status < 200) | ||||||||
5666 | nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error, TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
5667 | } | ||||||||
5668 | } | ||||||||
5669 | } | ||||||||
5670 | |||||||||
5671 | /** @internal | ||||||||
5672 | * Initialize a queue for incoming transactions. | ||||||||
5673 | */ | ||||||||
5674 | static void | ||||||||
5675 | incoming_queue_init(incoming_queue_t *queue, unsigned timeout) | ||||||||
5676 | { | ||||||||
5677 | memset(queue, 0, sizeof *queue); | ||||||||
5678 | queue->q_tail = &queue->q_head; | ||||||||
5679 | queue->q_timeout = timeout; | ||||||||
5680 | } | ||||||||
5681 | |||||||||
5682 | /** Change the timeout value of a queue */ | ||||||||
5683 | static void | ||||||||
5684 | incoming_queue_adjust(nta_agent_t *sa, | ||||||||
5685 | incoming_queue_t *queue, | ||||||||
5686 | uint32_t timeout) | ||||||||
5687 | { | ||||||||
5688 | nta_incoming_t *irq; | ||||||||
5689 | uint32_t latest; | ||||||||
5690 | |||||||||
5691 | if (timeout >= queue->q_timeout || !queue->q_head) { | ||||||||
5692 | queue->q_timeout = timeout; | ||||||||
5693 | return; | ||||||||
5694 | } | ||||||||
5695 | |||||||||
5696 | latest = set_timeout(sa, queue->q_timeout = timeout); | ||||||||
5697 | |||||||||
5698 | for (irq = queue->q_head; irq; irq = irq->irq_next) { | ||||||||
5699 | if ((int32_t)(irq->irq_timeout - latest) > 0) | ||||||||
5700 | irq->irq_timeout = latest; | ||||||||
5701 | } | ||||||||
5702 | } | ||||||||
5703 | |||||||||
5704 | /** @internal | ||||||||
5705 | * Test if an incoming transaction is in a queue. | ||||||||
5706 | */ | ||||||||
5707 | su_inlinestatic inline | ||||||||
5708 | int incoming_is_queued(nta_incoming_t const *irq) | ||||||||
5709 | { | ||||||||
5710 | return irq && irq->irq_queue; | ||||||||
5711 | } | ||||||||
5712 | |||||||||
5713 | /** @internal | ||||||||
5714 | * Insert an incoming transaction into a queue. | ||||||||
5715 | * | ||||||||
5716 | * Insert a server transaction into a queue, and sets the corresponding | ||||||||
5717 | * timeout at the same time. | ||||||||
5718 | */ | ||||||||
5719 | su_inlinestatic inline | ||||||||
5720 | void incoming_queue(incoming_queue_t *queue, | ||||||||
5721 | nta_incoming_t *irq) | ||||||||
5722 | { | ||||||||
5723 | if (irq->irq_queue == queue) { | ||||||||
5724 | assert(queue && queue->q_timeout == 0)((void) sizeof ((queue && queue->q_timeout == 0) ? 1 : 0), __extension__ ({ if (queue && queue->q_timeout == 0) ; else __assert_fail ("queue && queue->q_timeout == 0" , "nta.c", 5724, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
5725 | return; | ||||||||
5726 | } | ||||||||
5727 | |||||||||
5728 | if (incoming_is_queued(irq)) | ||||||||
5729 | incoming_remove(irq); | ||||||||
5730 | |||||||||
5731 | assert(queue && *queue->q_tail == NULL)((void) sizeof ((queue && *queue->q_tail == ((void *)0)) ? 1 : 0), __extension__ ({ if (queue && *queue-> q_tail == ((void*)0)) ; else __assert_fail ("queue && *queue->q_tail == NULL" , "nta.c", 5731, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
5732 | |||||||||
5733 | irq->irq_timeout = set_timeout(irq->irq_agent, queue->q_timeout); | ||||||||
5734 | |||||||||
5735 | irq->irq_queue = queue; | ||||||||
5736 | irq->irq_prev = queue->q_tail; | ||||||||
5737 | *queue->q_tail = irq; | ||||||||
5738 | queue->q_tail = &irq->irq_next; | ||||||||
5739 | queue->q_length++; | ||||||||
5740 | } | ||||||||
5741 | |||||||||
5742 | /** @internal | ||||||||
5743 | * Remove an incoming transaction from a queue. | ||||||||
5744 | */ | ||||||||
5745 | su_inlinestatic inline | ||||||||
5746 | void incoming_remove(nta_incoming_t *irq) | ||||||||
5747 | { | ||||||||
5748 | assert(incoming_is_queued(irq))((void) sizeof ((incoming_is_queued(irq)) ? 1 : 0), __extension__ ({ if (incoming_is_queued(irq)) ; else __assert_fail ("incoming_is_queued(irq)" , "nta.c", 5748, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
5749 | assert(irq->irq_queue->q_length > 0)((void) sizeof ((irq->irq_queue->q_length > 0) ? 1 : 0), __extension__ ({ if (irq->irq_queue->q_length > 0) ; else __assert_fail ("irq->irq_queue->q_length > 0" , "nta.c", 5749, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
5750 | |||||||||
5751 | if ((*irq->irq_prev = irq->irq_next)) | ||||||||
5752 | irq->irq_next->irq_prev = irq->irq_prev; | ||||||||
5753 | else | ||||||||
5754 | irq->irq_queue->q_tail = irq->irq_prev, assert(!*irq->irq_queue->q_tail)((void) sizeof ((!*irq->irq_queue->q_tail) ? 1 : 0), __extension__ ({ if (!*irq->irq_queue->q_tail) ; else __assert_fail ( "!*irq->irq_queue->q_tail", "nta.c", 5754, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
5755 | |||||||||
5756 | irq->irq_queue->q_length--; | ||||||||
5757 | irq->irq_next = NULL((void*)0); | ||||||||
5758 | irq->irq_prev = NULL((void*)0); | ||||||||
5759 | irq->irq_queue = NULL((void*)0); | ||||||||
5760 | irq->irq_timeout = 0; | ||||||||
5761 | } | ||||||||
5762 | |||||||||
5763 | su_inlinestatic inline | ||||||||
5764 | void incoming_set_timer(nta_incoming_t *irq, uint32_t interval) | ||||||||
5765 | { | ||||||||
5766 | nta_incoming_t **rq; | ||||||||
5767 | |||||||||
5768 | assert(irq)((void) sizeof ((irq) ? 1 : 0), __extension__ ({ if (irq) ; else __assert_fail ("irq", "nta.c", 5768, __extension__ __PRETTY_FUNCTION__ ); })); | ||||||||
5769 | |||||||||
5770 | if (interval == 0) { | ||||||||
5771 | incoming_reset_timer(irq); | ||||||||
5772 | return; | ||||||||
5773 | } | ||||||||
5774 | |||||||||
5775 | if (irq->irq_rprev) { | ||||||||
5776 | if ((*irq->irq_rprev = irq->irq_rnext)) | ||||||||
5777 | irq->irq_rnext->irq_rprev = irq->irq_rprev; | ||||||||
5778 | if (irq->irq_agent->sa_in.re_t1 == &irq->irq_rnext) | ||||||||
5779 | irq->irq_agent->sa_in.re_t1 = irq->irq_rprev; | ||||||||
5780 | } else { | ||||||||
5781 | irq->irq_agent->sa_in.re_length++; | ||||||||
5782 | } | ||||||||
5783 | |||||||||
5784 | irq->irq_retry = set_timeout(irq->irq_agent, irq->irq_interval = interval); | ||||||||
5785 | |||||||||
5786 | rq = irq->irq_agent->sa_in.re_t1; | ||||||||
5787 | |||||||||
5788 | if (!(*rq) || (int32_t)((*rq)->irq_retry - irq->irq_retry) > 0) | ||||||||
5789 | rq = &irq->irq_agent->sa_in.re_list; | ||||||||
5790 | |||||||||
5791 | while (*rq && (int32_t)((*rq)->irq_retry - irq->irq_retry) <= 0) | ||||||||
5792 | rq = &(*rq)->irq_rnext; | ||||||||
5793 | |||||||||
5794 | if ((irq->irq_rnext = *rq)) | ||||||||
5795 | irq->irq_rnext->irq_rprev = &irq->irq_rnext; | ||||||||
5796 | *rq = irq; | ||||||||
5797 | irq->irq_rprev = rq; | ||||||||
5798 | |||||||||
5799 | /* Optimization: keep special place for transactions with T1 interval */ | ||||||||
5800 | if (interval == irq->irq_agent->sa_t1) | ||||||||
5801 | irq->irq_agent->sa_in.re_t1 = rq; | ||||||||
5802 | } | ||||||||
5803 | |||||||||
5804 | su_inlinestatic inline | ||||||||
5805 | void incoming_reset_timer(nta_incoming_t *irq) | ||||||||
5806 | { | ||||||||
5807 | if (irq->irq_rprev) { | ||||||||
5808 | if ((*irq->irq_rprev = irq->irq_rnext)) | ||||||||
5809 | irq->irq_rnext->irq_rprev = irq->irq_rprev; | ||||||||
5810 | if (irq->irq_agent->sa_in.re_t1 == &irq->irq_rnext) | ||||||||
5811 | irq->irq_agent->sa_in.re_t1 = irq->irq_rprev; | ||||||||
5812 | irq->irq_agent->sa_in.re_length--; | ||||||||
5813 | } | ||||||||
5814 | |||||||||
5815 | irq->irq_interval = 0, irq->irq_retry = 0; | ||||||||
5816 | irq->irq_rnext = NULL((void*)0), irq->irq_rprev = NULL((void*)0); | ||||||||
5817 | } | ||||||||
5818 | |||||||||
5819 | /** @internal | ||||||||
5820 | * Free an incoming transaction. | ||||||||
5821 | */ | ||||||||
5822 | static | ||||||||
5823 | void incoming_free(nta_incoming_t *irq) | ||||||||
5824 | { | ||||||||
5825 | 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__ , 5825, "nta: incoming_free(%p)\n", (void *)irq)) : (void)0); | ||||||||
5826 | |||||||||
5827 | incoming_cut_off(irq); | ||||||||
5828 | incoming_reclaim(irq); | ||||||||
5829 | } | ||||||||
5830 | |||||||||
5831 | /** Remove references to the irq */ | ||||||||
5832 | su_inlinestatic inline | ||||||||
5833 | void incoming_cut_off(nta_incoming_t *irq) | ||||||||
5834 | { | ||||||||
5835 | nta_agent_t *agent = irq->irq_agent; | ||||||||
5836 | |||||||||
5837 | assert(agent)((void) sizeof ((agent) ? 1 : 0), __extension__ ({ if (agent) ; else __assert_fail ("agent", "nta.c", 5837, __extension__ __PRETTY_FUNCTION__ ); })); | ||||||||
5838 | |||||||||
5839 | if (irq->irq_default) { | ||||||||
5840 | if (irq == agent->sa_default_incoming) | ||||||||
5841 | agent->sa_default_incoming = NULL((void*)0); | ||||||||
5842 | irq->irq_default = 0; | ||||||||
5843 | return; | ||||||||
5844 | } | ||||||||
5845 | |||||||||
5846 | if (incoming_is_queued(irq)) | ||||||||
5847 | incoming_remove(irq); | ||||||||
5848 | |||||||||
5849 | incoming_reset_timer(irq); | ||||||||
5850 | |||||||||
5851 | incoming_htable_remove(agent->sa_incoming, irq); | ||||||||
5852 | |||||||||
5853 | if (irq->irq_cc) | ||||||||
5854 | nta_compartment_decref(&irq->irq_cc); | ||||||||
5855 | |||||||||
5856 | if (irq->irq_tport) | ||||||||
5857 | tport_decref(&irq->irq_tport); | ||||||||
5858 | } | ||||||||
5859 | |||||||||
5860 | /** Reclaim the memory used by irq */ | ||||||||
5861 | su_inlinestatic inline | ||||||||
5862 | void incoming_reclaim(nta_incoming_t *irq) | ||||||||
5863 | { | ||||||||
5864 | su_home_t *home = irq->irq_home; | ||||||||
5865 | nta_reliable_t *rel, *rel_next; | ||||||||
5866 | |||||||||
5867 | if (irq->irq_request) | ||||||||
5868 | msg_destroy(irq->irq_request), irq->irq_request = NULL((void*)0); | ||||||||
5869 | if (irq->irq_request2) | ||||||||
5870 | msg_destroy(irq->irq_request2), irq->irq_request2 = NULL((void*)0); | ||||||||
5871 | if (irq->irq_response) | ||||||||
5872 | msg_destroy(irq->irq_response), irq->irq_response = NULL((void*)0); | ||||||||
5873 | |||||||||
5874 | for (rel = irq->irq_reliable; rel; rel = rel_next) { | ||||||||
5875 | rel_next = rel->rel_next; | ||||||||
5876 | if (rel->rel_unsent) | ||||||||
5877 | msg_destroy(rel->rel_unsent); | ||||||||
5878 | su_free(irq->irq_agent->sa_home, rel); | ||||||||
5879 | } | ||||||||
5880 | |||||||||
5881 | irq->irq_home = NULL((void*)0); | ||||||||
5882 | |||||||||
5883 | su_free(home, irq); | ||||||||
5884 | |||||||||
5885 | msg_destroy((msg_t *)home); | ||||||||
5886 | } | ||||||||
5887 | |||||||||
5888 | /** Queue request to be freed */ | ||||||||
5889 | su_inlinestatic inline | ||||||||
5890 | void incoming_free_queue(incoming_queue_t *q, nta_incoming_t *irq) | ||||||||
5891 | { | ||||||||
5892 | incoming_cut_off(irq); | ||||||||
5893 | incoming_queue(q, irq); | ||||||||
5894 | } | ||||||||
5895 | |||||||||
5896 | /** Reclaim memory used by queue of requests */ | ||||||||
5897 | static | ||||||||
5898 | void incoming_reclaim_queued(su_root_magic_t *rm, | ||||||||
5899 | su_msg_r msg, | ||||||||
5900 | union sm_arg_u *u) | ||||||||
5901 | { | ||||||||
5902 | incoming_queue_t *q = u->a_incoming_queue; | ||||||||
5903 | nta_incoming_t *irq, *irq_next; | ||||||||
5904 | |||||||||
5905 | 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__ , 5906, "incoming_reclaim_all(%p, %p, %p)\n", (void *)rm, (void *)msg, (void *)u)) : (void)0) | ||||||||
5906 | (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__ , 5906, "incoming_reclaim_all(%p, %p, %p)\n", (void *)rm, (void *)msg, (void *)u)) : (void)0); | ||||||||
5907 | |||||||||
5908 | for (irq = q->q_head; irq; irq = irq_next) { | ||||||||
5909 | irq_next = irq->irq_next; | ||||||||
5910 | incoming_reclaim(irq); | ||||||||
5911 | } | ||||||||
5912 | } | ||||||||
5913 | |||||||||
5914 | /**Bind a callback and context to an incoming transaction object | ||||||||
5915 | * | ||||||||
5916 | * Set the callback function and context pointer attached to an incoming | ||||||||
5917 | * request object. The callback function will be invoked if the incoming | ||||||||
5918 | * request is cancelled, or if the final response to an incoming @b INVITE | ||||||||
5919 | * request has been acknowledged. | ||||||||
5920 | * | ||||||||
5921 | * If the callback is NULL, or no callback has been bound, NTA invokes the | ||||||||
5922 | * request callback of the call leg. | ||||||||
5923 | * | ||||||||
5924 | * @param irq incoming transaction | ||||||||
5925 | * @param callback callback function | ||||||||
5926 | * @param magic application context | ||||||||
5927 | */ | ||||||||
5928 | void nta_incoming_bind(nta_incoming_t *irq, | ||||||||
5929 | nta_ack_cancel_f *callback, | ||||||||
5930 | nta_incoming_magic_t *magic) | ||||||||
5931 | { | ||||||||
5932 | if (irq) { | ||||||||
5933 | irq->irq_callback = callback; | ||||||||
5934 | irq->irq_magic = magic; | ||||||||
5935 | } | ||||||||
5936 | } | ||||||||
5937 | |||||||||
5938 | /** Add a @To tag to incoming request if needed. | ||||||||
5939 | * | ||||||||
5940 | * If @a tag is NULL, a new tag is generated. | ||||||||
5941 | */ | ||||||||
5942 | char const *nta_incoming_tag(nta_incoming_t *irq, char const *tag) | ||||||||
5943 | { | ||||||||
5944 | if (!irq) | ||||||||
5945 | return su_seterrno(EFAULT14), NULL((void*)0); | ||||||||
5946 | |||||||||
5947 | if (irq->irq_default) | ||||||||
5948 | return su_seterrno(EINVAL22), NULL((void*)0); | ||||||||
5949 | |||||||||
5950 | if (tag && strchr(tag, '=')) | ||||||||
5951 | tag = strchr(tag, '=') + 1; | ||||||||
5952 | |||||||||
5953 | if (tag && irq->irq_tag && !su_casematch(tag, irq->irq_tag)) | ||||||||
5954 | return NULL((void*)0); | ||||||||
5955 | |||||||||
5956 | if (!irq->irq_tag) { | ||||||||
5957 | if (tag) | ||||||||
5958 | tag = su_strdup(irq->irq_home, tag); | ||||||||
5959 | else | ||||||||
5960 | tag = nta_agent_newtag(irq->irq_home, NULL((void*)0), irq->irq_agent); | ||||||||
5961 | |||||||||
5962 | if (!tag) | ||||||||
5963 | return tag; | ||||||||
5964 | |||||||||
5965 | irq->irq_tag = tag; | ||||||||
5966 | irq->irq_tag_set = 1; | ||||||||
5967 | } | ||||||||
5968 | |||||||||
5969 | return irq->irq_tag; | ||||||||
5970 | } | ||||||||
5971 | |||||||||
5972 | |||||||||
5973 | /**Get request message. | ||||||||
5974 | * | ||||||||
5975 | * Retrieve the incoming request message of the incoming transaction. Note | ||||||||
5976 | * that the message is not copied, but a new reference to it is created. | ||||||||
5977 | * | ||||||||
5978 | * @param irq incoming transaction handle | ||||||||
5979 | * | ||||||||
5980 | * @retval | ||||||||
5981 | * A pointer to request message is returned. | ||||||||
5982 | */ | ||||||||
5983 | msg_t *nta_incoming_getrequest(nta_incoming_t *irq) | ||||||||
5984 | { | ||||||||
5985 | msg_t *msg = NULL((void*)0); | ||||||||
5986 | |||||||||
5987 | if (irq && !irq->irq_default) | ||||||||
5988 | msg = msg_ref_create(irq->irq_request); | ||||||||
5989 | |||||||||
5990 | return msg; | ||||||||
5991 | } | ||||||||
5992 | |||||||||
5993 | /**Get ACK or CANCEL message. | ||||||||
5994 | * | ||||||||
5995 | * Retrieve the incoming ACK or CANCEL request message of the incoming | ||||||||
5996 | * transaction. Note that the ACK or CANCEL message is not copied, but a new | ||||||||
5997 | * reference to it is created. | ||||||||
5998 | * | ||||||||
5999 | * @param irq incoming transaction handle | ||||||||
6000 | * | ||||||||
6001 | * @retval A pointer to request message is returned, or NULL if there is no | ||||||||
6002 | * CANCEL or ACK received. | ||||||||
6003 | */ | ||||||||
6004 | msg_t *nta_incoming_getrequest_ackcancel(nta_incoming_t *irq) | ||||||||
6005 | { | ||||||||
6006 | msg_t *msg = NULL((void*)0); | ||||||||
6007 | |||||||||
6008 | if (irq && irq->irq_request2) | ||||||||
6009 | msg = msg_ref_create(irq->irq_request2); | ||||||||
6010 | |||||||||
6011 | return msg; | ||||||||
6012 | } | ||||||||
6013 | |||||||||
6014 | /**Get response message. | ||||||||
6015 | * | ||||||||
6016 | * Retrieve the response message latest sent by the server transaction. Note | ||||||||
6017 | * that the message is not copied, but a new reference to it is created. Use | ||||||||
6018 | * msg_dup() or msg_copy() to make a copy of it. | ||||||||
6019 | * | ||||||||
6020 | * @param irq incoming transaction handle | ||||||||
6021 | * | ||||||||
6022 | * @retval | ||||||||
6023 | * A pointer to a response message is returned. | ||||||||
6024 | */ | ||||||||
6025 | msg_t *nta_incoming_getresponse(nta_incoming_t *irq) | ||||||||
6026 | { | ||||||||
6027 | msg_t *msg = NULL((void*)0); | ||||||||
6028 | |||||||||
6029 | if (irq && irq->irq_response) | ||||||||
6030 | msg = msg_ref_create(irq->irq_response); | ||||||||
6031 | |||||||||
6032 | return msg; | ||||||||
6033 | } | ||||||||
6034 | |||||||||
6035 | /** Get method of a server transaction. */ | ||||||||
6036 | sip_method_t nta_incoming_method(nta_incoming_t const *irq) | ||||||||
6037 | { | ||||||||
6038 | return irq ? irq->irq_method : sip_method_invalid; | ||||||||
6039 | } | ||||||||
6040 | |||||||||
6041 | /** Get method name of a server transaction. */ | ||||||||
6042 | char const *nta_incoming_method_name(nta_incoming_t const *irq) | ||||||||
6043 | { | ||||||||
6044 | if (irq == NULL((void*)0)) | ||||||||
6045 | return NULL((void*)0); | ||||||||
6046 | else if (irq->irq_rq) | ||||||||
6047 | return irq->irq_rq->rq_method_name; | ||||||||
6048 | else | ||||||||
6049 | return "*"; | ||||||||
6050 | } | ||||||||
6051 | |||||||||
6052 | /** Get Request-URI of a server transaction */ | ||||||||
6053 | url_t const *nta_incoming_url(nta_incoming_t const *irq) | ||||||||
6054 | { | ||||||||
6055 | return irq && irq->irq_rq ? irq->irq_rq->rq_url : NULL((void*)0); | ||||||||
6056 | } | ||||||||
6057 | |||||||||
6058 | /** Get sequence number of a server transaction. | ||||||||
6059 | */ | ||||||||
6060 | uint32_t nta_incoming_cseq(nta_incoming_t const *irq) | ||||||||
6061 | { | ||||||||
6062 | return irq && irq->irq_cseq ? irq->irq_cseq->cs_seq : 0; | ||||||||
6063 | } | ||||||||
6064 | |||||||||
6065 | /** Get local tag for incoming request */ | ||||||||
6066 | char const *nta_incoming_gettag(nta_incoming_t const *irq) | ||||||||
6067 | { | ||||||||
6068 | return irq ? irq->irq_tag : 0; | ||||||||
6069 | } | ||||||||
6070 | |||||||||
6071 | /** | ||||||||
6072 | * Get status code of a server transaction. | ||||||||
6073 | */ | ||||||||
6074 | int nta_incoming_status(nta_incoming_t const *irq) | ||||||||
6075 | { | ||||||||
6076 | return irq ? irq->irq_status : 400; | ||||||||
6077 | } | ||||||||
6078 | |||||||||
6079 | /** Get application context for a server transaction. | ||||||||
6080 | * | ||||||||
6081 | * @param irq server transaction | ||||||||
6082 | * @param callback callback pointer | ||||||||
6083 | * | ||||||||
6084 | * Return the application context bound to the server transaction. If the @a | ||||||||
6085 | * callback function pointer is given, return application context only if | ||||||||
6086 | * the callback matches with the callback bound to the server transaction. | ||||||||
6087 | * | ||||||||
6088 | */ | ||||||||
6089 | nta_incoming_magic_t *nta_incoming_magic(nta_incoming_t *irq, | ||||||||
6090 | nta_ack_cancel_f *callback) | ||||||||
6091 | { | ||||||||
6092 | return irq && (callback == NULL((void*)0) || irq->irq_callback == callback) | ||||||||
6093 | ? irq->irq_magic : NULL((void*)0); | ||||||||
6094 | } | ||||||||
6095 | |||||||||
6096 | /** When received. | ||||||||
6097 | * | ||||||||
6098 | * Return timestamp from the reception of the initial request. | ||||||||
6099 | * | ||||||||
6100 | * @NEW_1_12_7. | ||||||||
6101 | */ | ||||||||
6102 | sip_time_t nta_incoming_received(nta_incoming_t *irq, | ||||||||
6103 | su_nanotime_t *return_nano) | ||||||||
6104 | { | ||||||||
6105 | su_time_t tv = { 0, 0 }; | ||||||||
6106 | |||||||||
6107 | if (irq) | ||||||||
6108 | tv = irq->irq_received; | ||||||||
6109 | |||||||||
6110 | if (return_nano) | ||||||||
6111 | *return_nano = (su_nanotime_t)tv.tv_sec * 1000000000 + tv.tv_usec * 1000; | ||||||||
6112 | |||||||||
6113 | return tv.tv_sec; | ||||||||
6114 | } | ||||||||
6115 | |||||||||
6116 | /** Find incoming transaction. */ | ||||||||
6117 | nta_incoming_t *nta_incoming_find(nta_agent_t const *agent, | ||||||||
6118 | sip_t const *sip, | ||||||||
6119 | sip_via_t const *v) | ||||||||
6120 | { | ||||||||
6121 | if (agent && sip && v) | ||||||||
6122 | return incoming_find(agent, sip, v, NULL((void*)0), NULL((void*)0), NULL((void*)0)); | ||||||||
6123 | else | ||||||||
6124 | return NULL((void*)0); | ||||||||
6125 | } | ||||||||
6126 | |||||||||
6127 | /** Find a matching server transaction object. | ||||||||
6128 | * | ||||||||
6129 | * Check also for requests to merge, to ACK, or to CANCEL. | ||||||||
6130 | */ | ||||||||
6131 | static nta_incoming_t *incoming_find(nta_agent_t const *agent, | ||||||||
6132 | sip_t const *sip, | ||||||||
6133 | sip_via_t const *v, | ||||||||
6134 | nta_incoming_t **return_merge, | ||||||||
6135 | nta_incoming_t **return_ack, | ||||||||
6136 | nta_incoming_t **return_cancel) | ||||||||
6137 | { | ||||||||
6138 | sip_cseq_t const *cseq = sip->sip_cseq; | ||||||||
6139 | sip_call_id_t const *i = sip->sip_call_id; | ||||||||
6140 | sip_to_t const *to = sip->sip_to; | ||||||||
6141 | sip_from_t const *from = sip->sip_from; | ||||||||
6142 | sip_request_t *rq = sip->sip_request; | ||||||||
6143 | incoming_htable_t const *iht = agent->sa_incoming; | ||||||||
6144 | hash_value_t hash; | ||||||||
6145 | char const *magic_branch; | ||||||||
6146 | |||||||||
6147 | nta_incoming_t **ii, *irq; | ||||||||
6148 | |||||||||
6149 | int is_uas_ack = return_ack && agent->sa_is_a_uas; | ||||||||
6150 | |||||||||
6151 | assert(cseq)((void) sizeof ((cseq) ? 1 : 0), __extension__ ({ if (cseq) ; else __assert_fail ("cseq", "nta.c", 6151, __extension__ __PRETTY_FUNCTION__ ); })); | ||||||||
6152 | |||||||||
6153 | hash = NTA_HASH(i, cseq->cs_seq)((i)->i_hash + 26839U * (uint32_t)(cseq->cs_seq)); | ||||||||
6154 | |||||||||
6155 | if (v->v_branch && su_casenmatch(v->v_branch, "z9hG4bK", 7)) | ||||||||
6156 | magic_branch = v->v_branch + 7; | ||||||||
6157 | else | ||||||||
6158 | magic_branch = NULL((void*)0); | ||||||||
6159 | |||||||||
6160 | for (ii = incoming_htable_hash(iht, hash); | ||||||||
6161 | (irq = *ii); | ||||||||
6162 | ii = incoming_htable_next(iht, ii)) { | ||||||||
6163 | if (hash != irq->irq_hash || | ||||||||
6164 | irq->irq_call_id->i_hash != i->i_hash || | ||||||||
6165 | strcmp(irq->irq_call_id->i_id, i->i_id)) | ||||||||
6166 | continue; | ||||||||
6167 | if (irq->irq_cseq->cs_seq != cseq->cs_seq) | ||||||||
6168 | continue; | ||||||||
6169 | if (su_strcasecmp(irq->irq_from->a_tag, from->a_tag)) | ||||||||
6170 | continue; | ||||||||
6171 | |||||||||
6172 | if (is_uas_ack && | ||||||||
6173 | irq->irq_method == sip_method_invite && | ||||||||
6174 | 200 <= irq->irq_status && irq->irq_status < 300 && | ||||||||
6175 | su_casematch(irq->irq_tag, to->a_tag)) { | ||||||||
6176 | *return_ack = irq; | ||||||||
6177 | return NULL((void*)0); | ||||||||
6178 | } | ||||||||
6179 | |||||||||
6180 | if (magic_branch) { | ||||||||
6181 | /* RFC3261 17.2.3: | ||||||||
6182 | * | ||||||||
6183 | * The request matches a transaction if branch and sent-by in topmost | ||||||||
6184 | * the method of the request matches the one that created the | ||||||||
6185 | * transaction, except for ACK, where the method of the request | ||||||||
6186 | * that created the transaction is INVITE. | ||||||||
6187 | */ | ||||||||
6188 | if (irq->irq_via->v_branch && | ||||||||
6189 | su_casematch(irq->irq_via->v_branch + 7, magic_branch) && | ||||||||
6190 | su_casematch(irq->irq_via->v_host, v->v_host) && | ||||||||
6191 | su_strmatch(irq->irq_via->v_port, v->v_port)) { | ||||||||
6192 | if (irq->irq_method == cseq->cs_method && | ||||||||
6193 | strcmp(irq->irq_cseq->cs_method_name, | ||||||||
6194 | cseq->cs_method_name) == 0) | ||||||||
6195 | return irq; | ||||||||
6196 | if (return_ack && irq->irq_method == sip_method_invite) | ||||||||
6197 | return *return_ack = irq, NULL((void*)0); | ||||||||
6198 | if (return_cancel && irq->irq_method != sip_method_ack) | ||||||||
6199 | return *return_cancel = irq, NULL((void*)0); | ||||||||
6200 | } | ||||||||
6201 | } | ||||||||
6202 | else { | ||||||||
6203 | /* No magic branch */ | ||||||||
6204 | |||||||||
6205 | /* INVITE request matches a transaction if | ||||||||
6206 | the Request-URI, To tag, From tag, Call-ID, CSeq, and | ||||||||
6207 | top Via header match */ | ||||||||
6208 | |||||||||
6209 | /* From tag, Call-ID, and CSeq number has been matched above */ | ||||||||
6210 | |||||||||
6211 | /* Match top Via header field */ | ||||||||
6212 | if (!su_casematch(irq->irq_via->v_branch, v->v_branch) || | ||||||||
6213 | !su_casematch(irq->irq_via->v_host, v->v_host) || | ||||||||
6214 | !su_strmatch(irq->irq_via->v_port, v->v_port)) | ||||||||
6215 | ; | ||||||||
6216 | /* Match Request-URI */ | ||||||||
6217 | else if (url_cmp(irq->irq_rq->rq_url, rq->rq_url)) | ||||||||
6218 | ; | ||||||||
6219 | else { | ||||||||
6220 | /* Match CSeq */ | ||||||||
6221 | if (irq->irq_method == cseq->cs_method && | ||||||||
6222 | su_strmatch(irq->irq_cseq->cs_method_name, cseq->cs_method_name)) { | ||||||||
6223 | /* Match To tag */ | ||||||||
6224 | if (!su_strcasecmp(irq->irq_to->a_tag, to->a_tag)) | ||||||||
6225 | return irq; /* found */ | ||||||||
6226 | } | ||||||||
6227 | else if ( | ||||||||
6228 | /* Tag set by UAS */ | ||||||||
6229 | su_strcasecmp(irq->irq_tag, to->a_tag) && | ||||||||
6230 | /* Original tag */ | ||||||||
6231 | su_strcasecmp(irq->irq_to->a_tag, to->a_tag)) | ||||||||
6232 | ; | ||||||||
6233 | else if (return_ack && irq->irq_method == sip_method_invite) | ||||||||
6234 | return *return_ack = irq, NULL((void*)0); | ||||||||
6235 | else if (return_cancel && irq->irq_method != sip_method_ack) | ||||||||
6236 | return *return_cancel = irq, NULL((void*)0); | ||||||||
6237 | } | ||||||||
6238 | } | ||||||||
6239 | |||||||||
6240 | /* RFC3261 - section 8.2.2.2 Merged Requests */ | ||||||||
6241 | if (return_merge) { | ||||||||
6242 | if (irq->irq_cseq->cs_method == cseq->cs_method && | ||||||||
6243 | strcmp(irq->irq_cseq->cs_method_name, | ||||||||
6244 | cseq->cs_method_name) == 0) | ||||||||
6245 | *return_merge = irq, return_merge = NULL((void*)0); | ||||||||
6246 | } | ||||||||
6247 | } | ||||||||
6248 | |||||||||
6249 | return NULL((void*)0); | ||||||||
6250 | } | ||||||||
6251 | |||||||||
6252 | /** Process retransmitted requests. */ | ||||||||
6253 | su_inlinestatic inline | ||||||||
6254 | int | ||||||||
6255 | incoming_recv(nta_incoming_t *irq, msg_t *msg, sip_t *sip, tport_t *tport) | ||||||||
6256 | { | ||||||||
6257 | nta_agent_t *agent = irq->irq_agent; | ||||||||
6258 | |||||||||
6259 | agent->sa_stats->as_recv_retry++; | ||||||||
6260 | |||||||||
6261 | if (irq->irq_status >= 100) { | ||||||||
6262 | 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__ , 6263, "nta: re-received %s request, retransmitting %u reply\n" , sip->sip_request->rq_method_name, irq->irq_status) ) : (void)0) | ||||||||
6263 | 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__ , 6263, "nta: re-received %s request, retransmitting %u reply\n" , sip->sip_request->rq_method_name, irq->irq_status) ) : (void)0); | ||||||||
6264 | incoming_retransmit_reply(irq, tport); | ||||||||
6265 | } | ||||||||
6266 | else if (irq->irq_agent->sa_extra_100 && | ||||||||
6267 | irq->irq_extra_100) { | ||||||||
6268 | /* Agent and Irq configured to answer automatically with 100 Trying */ | ||||||||
6269 | if (irq->irq_method == sip_method_invite || | ||||||||
6270 | /* | ||||||||
6271 | * Send 100 trying to non-invite if at least half of T2 has expired | ||||||||
6272 | * since the transaction was created. | ||||||||
6273 | */ | ||||||||
6274 | su_duration(agent_now(irq->irq_agent), irq->irq_received) * 2U > | ||||||||
6275 | irq->irq_agent->sa_t2) { | ||||||||
6276 | 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__ , 6277, "nta: re-received %s request, sending 100 Trying\n", sip ->sip_request->rq_method_name)) : (void)0) | ||||||||
6277 | 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__ , 6277, "nta: re-received %s request, sending 100 Trying\n", sip ->sip_request->rq_method_name)) : (void)0); | ||||||||
6278 | 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); | ||||||||
6279 | } | ||||||||
6280 | } | ||||||||
6281 | |||||||||
6282 | msg_destroy(msg); | ||||||||
6283 | |||||||||
6284 | return 0; | ||||||||
6285 | } | ||||||||
6286 | |||||||||
6287 | su_inlinestatic inline | ||||||||
6288 | int incoming_ack(nta_incoming_t *irq, msg_t *msg, sip_t *sip, tport_t *tport) | ||||||||
6289 | { | ||||||||
6290 | nta_agent_t *agent = irq->irq_agent; | ||||||||
6291 | |||||||||
6292 | /* Process ACK separately? */ | ||||||||
6293 | if (irq->irq_status >= 200 && irq->irq_status < 300 && !agent->sa_is_a_uas) | ||||||||
6294 | return -1; | ||||||||
6295 | |||||||||
6296 | if (irq->irq_queue == agent->sa_in.inv_completed) { | ||||||||
6297 | if (!irq->irq_confirmed) | ||||||||
6298 | agent->sa_stats->as_acked_tr++; | ||||||||
6299 | |||||||||
6300 | irq->irq_confirmed = 1; | ||||||||
6301 | incoming_reset_timer(irq); /* Reset timer G */ | ||||||||
6302 | |||||||||
6303 | if (!irq->irq_reliable_tp) { | ||||||||
6304 | incoming_queue(agent->sa_in.inv_confirmed, irq); /* Timer I */ | ||||||||
6305 | } | ||||||||
6306 | else { | ||||||||
6307 | irq->irq_terminated = 1; | ||||||||
6308 | incoming_queue(agent->sa_in.terminated, irq); | ||||||||
6309 | } | ||||||||
6310 | |||||||||
6311 | if (!irq->irq_destroyed) { | ||||||||
6312 | if (!irq->irq_callback) /* Process ACK normally */ | ||||||||
6313 | return -1; | ||||||||
6314 | |||||||||
6315 | incoming_call_callback(irq, msg, sip); /* ACK callback */ | ||||||||
6316 | } | ||||||||
6317 | } else if (irq->irq_queue == agent->sa_in.proceeding || | ||||||||
6318 | irq->irq_queue == agent->sa_in.preliminary) | ||||||||
6319 | return -1; | ||||||||
6320 | else | ||||||||
6321 | assert(irq->irq_queue == agent->sa_in.inv_confirmed ||((void) sizeof ((irq->irq_queue == agent->sa_in.inv_confirmed || irq->irq_queue == agent->sa_in.terminated) ? 1 : 0) , __extension__ ({ if (irq->irq_queue == agent->sa_in.inv_confirmed || irq->irq_queue == agent->sa_in.terminated) ; else __assert_fail ("irq->irq_queue == agent->sa_in.inv_confirmed || irq->irq_queue == agent->sa_in.terminated" , "nta.c", 6322, __extension__ __PRETTY_FUNCTION__); })) | ||||||||
6322 | irq->irq_queue == agent->sa_in.terminated)((void) sizeof ((irq->irq_queue == agent->sa_in.inv_confirmed || irq->irq_queue == agent->sa_in.terminated) ? 1 : 0) , __extension__ ({ if (irq->irq_queue == agent->sa_in.inv_confirmed || irq->irq_queue == agent->sa_in.terminated) ; else __assert_fail ("irq->irq_queue == agent->sa_in.inv_confirmed || irq->irq_queue == agent->sa_in.terminated" , "nta.c", 6322, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
6323 | |||||||||
6324 | msg_destroy(msg); | ||||||||
6325 | |||||||||
6326 | return 0; | ||||||||
6327 | } | ||||||||
6328 | |||||||||
6329 | /** Respond to the CANCEL. */ | ||||||||
6330 | su_inlinestatic inline | ||||||||
6331 | int incoming_cancel(nta_incoming_t *irq, msg_t *msg, sip_t *sip, | ||||||||
6332 | tport_t *tport) | ||||||||
6333 | { | ||||||||
6334 | nta_agent_t *agent = irq->irq_agent; | ||||||||
6335 | |||||||||
6336 | /* According to the RFC 3261, this INVITE has been destroyed */ | ||||||||
6337 | if (irq->irq_method == sip_method_invite && | ||||||||
6338 | 200 <= irq->irq_status && irq->irq_status < 300) { | ||||||||
6339 | mreply(agent, NULL((void*)0), SIP_481_NO_TRANSACTION481, sip_481_No_transaction, msg, | ||||||||
6340 | tport, 0, 0, NULL((void*)0), | ||||||||
6341 | TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
6342 | return 0; | ||||||||
6343 | } | ||||||||
6344 | |||||||||
6345 | /* UAS MUST use same tag in final response to CANCEL and INVITE */ | ||||||||
6346 | if (agent->sa_is_a_uas && irq->irq_tag == NULL((void*)0)) { | ||||||||
6347 | nta_incoming_tag(irq, NULL((void*)0)); | ||||||||
6348 | } | ||||||||
6349 | |||||||||
6350 | mreply(agent, NULL((void*)0), SIP_200_OK200, sip_200_OK, msg_ref_create(msg), | ||||||||
6351 | tport, 0, 0, irq->irq_tag, | ||||||||
6352 | TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
6353 | |||||||||
6354 | /* We have already sent final response */ | ||||||||
6355 | if (irq->irq_completed || irq->irq_method != sip_method_invite) { | ||||||||
6356 | msg_destroy(msg); | ||||||||
6357 | return 0; | ||||||||
6358 | } | ||||||||
6359 | |||||||||
6360 | if (!irq->irq_canceled) { | ||||||||
6361 | irq->irq_canceled = 1; | ||||||||
6362 | agent->sa_stats->as_canceled_tr++; | ||||||||
6363 | irq = incoming_call_callback(irq, msg, sip); | ||||||||
6364 | } | ||||||||
6365 | |||||||||
6366 | if (irq && !irq->irq_completed && agent->sa_cancel_487) | ||||||||
6367 | /* Respond to the cancelled request */ | ||||||||
6368 | nta_incoming_treply(irq, SIP_487_REQUEST_CANCELLED487, sip_487_Request_terminated, TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
6369 | |||||||||
6370 | msg_destroy(msg); | ||||||||
6371 | |||||||||
6372 | return 0; | ||||||||
6373 | } | ||||||||
6374 | |||||||||
6375 | /** Merge request */ | ||||||||
6376 | static | ||||||||
6377 | void request_merge(nta_agent_t *agent, | ||||||||
6378 | msg_t *msg, sip_t *sip, tport_t *tport, | ||||||||
6379 | char const *to_tag) | ||||||||
6380 | { | ||||||||
6381 | nta_incoming_t *irq; | ||||||||
6382 | |||||||||
6383 | agent->sa_stats->as_merged_request++; | ||||||||
6384 | |||||||||
6385 | irq = incoming_create(agent, msg, sip, tport, to_tag); | ||||||||
6386 | |||||||||
6387 | if (irq) { | ||||||||
6388 | nta_incoming_treply(irq, 482, "Request merged", TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
6389 | nta_incoming_destroy(irq); | ||||||||
6390 | } else { | ||||||||
6391 | 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__ , 6392, "nta: request_merge(): cannot create transaction for %s\n" , sip->sip_request->rq_method_name)) : (void)0) | ||||||||
6392 | 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__ , 6392, "nta: request_merge(): cannot create transaction for %s\n" , sip->sip_request->rq_method_name)) : (void)0); | ||||||||
6393 | mreply(agent, NULL((void*)0), 482, "Request merged", msg, | ||||||||
6394 | tport, 0, 0, NULL((void*)0), | ||||||||
6395 | TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
6396 | } | ||||||||
6397 | } | ||||||||
6398 | |||||||||
6399 | /**@typedef nta_ack_cancel_f | ||||||||
6400 | * | ||||||||
6401 | * Callback function prototype for CANCELed/ACKed requests | ||||||||
6402 | * | ||||||||
6403 | * This is a callback function is invoked by NTA when an incoming request | ||||||||
6404 | * has been cancelled or an response to an incoming INVITE request has been | ||||||||
6405 | * acknowledged. | ||||||||
6406 | * | ||||||||
6407 | * @param magic incoming request context | ||||||||
6408 | * @param ireq incoming request | ||||||||
6409 | * @param sip ACK/CANCEL message | ||||||||
6410 | * | ||||||||
6411 | * @retval 0 | ||||||||
6412 | * This callback function should return always 0. | ||||||||
6413 | */ | ||||||||
6414 | |||||||||
6415 | /** Call callback of incoming transaction */ | ||||||||
6416 | su_inlinestatic inline | ||||||||
6417 | nta_incoming_t * | ||||||||
6418 | incoming_call_callback(nta_incoming_t *irq, msg_t *msg, sip_t *sip) | ||||||||
6419 | { | ||||||||
6420 | if (irq->irq_callback) { | ||||||||
6421 | irq->irq_in_callback = 1; | ||||||||
6422 | irq->irq_request2 = msg; | ||||||||
6423 | irq->irq_callback(irq->irq_magic, irq, sip); | ||||||||
6424 | irq->irq_request2 = NULL((void*)0); | ||||||||
6425 | irq->irq_in_callback = 0; | ||||||||
6426 | |||||||||
6427 | if (irq->irq_terminated && irq->irq_destroyed) | ||||||||
6428 | incoming_free(irq), irq = NULL((void*)0); | ||||||||
6429 | } | ||||||||
6430 | return irq; | ||||||||
6431 | } | ||||||||
6432 | |||||||||
6433 | /**Set server transaction parameters. | ||||||||
6434 | * | ||||||||
6435 | * Sets the server transaction parameters. Among others, parameters determine the way | ||||||||
6436 | * the SigComp compression is handled. | ||||||||
6437 | * | ||||||||
6438 | * @TAGS | ||||||||
6439 | * NTATAG_COMP(), NTATAG_SIGCOMP_CLOSE() and NTATAG_EXTRA_100(). | ||||||||
6440 | * | ||||||||
6441 | * @retval number of set parameters when succesful | ||||||||
6442 | * @retval -1 upon an error | ||||||||
6443 | */ | ||||||||
6444 | int nta_incoming_set_params(nta_incoming_t *irq, | ||||||||
6445 | tag_type_t tag, tag_value_t value, ...) | ||||||||
6446 | { | ||||||||
6447 | int retval = -1; | ||||||||
6448 | |||||||||
6449 | if (irq) { | ||||||||
6450 | ta_list ta; | ||||||||
6451 | 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); | ||||||||
6452 | retval = incoming_set_params(irq, ta_args(ta)(ta).tl); | ||||||||
6453 | 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)); | ||||||||
6454 | } | ||||||||
6455 | else { | ||||||||
6456 | su_seterrno(EINVAL22); | ||||||||
6457 | } | ||||||||
6458 | |||||||||
6459 | return retval; | ||||||||
6460 | } | ||||||||
6461 | |||||||||
6462 | static | ||||||||
6463 | int incoming_set_params(nta_incoming_t *irq, tagi_t const *tags) | ||||||||
6464 | { | ||||||||
6465 | int retval = 0; | ||||||||
6466 | |||||||||
6467 | tagi_t const *t; | ||||||||
6468 | char const *comp = NONE((void *)-1); | ||||||||
6469 | struct sigcomp_compartment *cc = NONE((void *)-1); | ||||||||
6470 | |||||||||
6471 | if (irq->irq_default) | ||||||||
6472 | return retval; | ||||||||
6473 | |||||||||
6474 | for (t = tags; t; t = tl_next(t)) { | ||||||||
6475 | tag_type_t tt = t->t_tag; | ||||||||
6476 | |||||||||
6477 | if (ntatag_comp == tt) | ||||||||
6478 | comp = (char const *)t->t_value, retval++; | ||||||||
6479 | |||||||||
6480 | else if (ntatag_sigcomp_close == tt) | ||||||||
6481 | irq->irq_sigcomp_zap = t->t_value != 0, retval++; | ||||||||
6482 | |||||||||
6483 | else if (tptag_compartment == tt) | ||||||||
6484 | cc = (void *)t->t_value, retval++; | ||||||||
6485 | |||||||||
6486 | else if (ntatag_extra_100 == tt) | ||||||||
6487 | irq->irq_extra_100 = t->t_value != 0, retval++; | ||||||||
6488 | } | ||||||||
6489 | |||||||||
6490 | if (cc != NONE((void *)-1)) { | ||||||||
6491 | if (cc) | ||||||||
6492 | agent_accept_compressed(irq->irq_agent, irq->irq_request, cc); | ||||||||
6493 | if (irq->irq_cc) | ||||||||
6494 | nta_compartment_decref(&irq->irq_cc); | ||||||||
6495 | irq->irq_cc = nta_compartment_ref(cc); | ||||||||
6496 | } | ||||||||
6497 | else if (comp != NULL((void*)0) && comp != NONE((void *)-1) && irq->irq_cc == NULL((void*)0)) { | ||||||||
6498 | incoming_set_compartment(irq, irq->irq_tport, irq->irq_request, 1); | ||||||||
6499 | } | ||||||||
6500 | |||||||||
6501 | else if (comp == NULL((void*)0)) { | ||||||||
6502 | irq->irq_tpn->tpn_comp = NULL((void*)0); | ||||||||
6503 | } | ||||||||
6504 | |||||||||
6505 | return retval; | ||||||||
6506 | } | ||||||||
6507 | |||||||||
6508 | su_inlinestatic inline | ||||||||
6509 | int incoming_set_compartment(nta_incoming_t *irq, tport_t *tport, msg_t *msg, | ||||||||
6510 | int create_if_needed) | ||||||||
6511 | { | ||||||||
6512 | if (!nta_compressor_vtable) | ||||||||
6513 | return 0; | ||||||||
6514 | |||||||||
6515 | if (irq->irq_cc == NULL((void*)0) | ||||||||
6516 | || irq->irq_tpn->tpn_comp | ||||||||
6517 | || tport_delivered_with_comp(tport, msg, NULL((void*)0)) != -1) { | ||||||||
6518 | struct sigcomp_compartment *cc; | ||||||||
6519 | |||||||||
6520 | cc = agent_compression_compartment(irq->irq_agent, tport, irq->irq_tpn, | ||||||||
6521 | create_if_needed); | ||||||||
6522 | |||||||||
6523 | if (cc) | ||||||||
6524 | agent_accept_compressed(irq->irq_agent, msg, cc); | ||||||||
6525 | |||||||||
6526 | irq->irq_cc = cc; | ||||||||
6527 | } | ||||||||
6528 | |||||||||
6529 | return 0; | ||||||||
6530 | } | ||||||||
6531 | |||||||||
6532 | /** Add essential headers to the response message */ | ||||||||
6533 | static int nta_incoming_response_headers(nta_incoming_t *irq, | ||||||||
6534 | msg_t *msg, | ||||||||
6535 | sip_t *sip) | ||||||||
6536 | { | ||||||||
6537 | int clone = 0; | ||||||||
6538 | su_home_t *home = msg_home(msg)((su_home_t*)(msg)); | ||||||||
6539 | |||||||||
6540 | if (!sip->sip_from) | ||||||||
6541 | clone = 1, sip->sip_from = sip_from_copy(home, irq->irq_from); | ||||||||
6542 | if (!sip->sip_to) | ||||||||
6543 | clone = 1, sip->sip_to = sip_to_copy(home, irq->irq_to); | ||||||||
6544 | if (!sip->sip_call_id) | ||||||||
6545 | clone = 1, sip->sip_call_id = sip_call_id_copy(home, irq->irq_call_id); | ||||||||
6546 | if (!sip->sip_cseq) | ||||||||
6547 | clone = 1, sip->sip_cseq = sip_cseq_copy(home, irq->irq_cseq); | ||||||||
6548 | if (!sip->sip_via) { | ||||||||
6549 | clone = 1; | ||||||||
6550 | /* 100 responses are not forwarded by proxies, so only include the topmost Via header */ | ||||||||
6551 | if (sip->sip_status && sip->sip_status->st_status == 100) | ||||||||
6552 | sip->sip_via = (sip_via_t *)msg_header_copy_one(home, (msg_header_t const *)irq->irq_via); | ||||||||
6553 | else | ||||||||
6554 | sip->sip_via = sip_via_copy(home, irq->irq_via); | ||||||||
6555 | } | ||||||||
6556 | |||||||||
6557 | if (clone) | ||||||||
6558 | msg_set_parent(msg, (msg_t *)irq->irq_home); | ||||||||
6559 | |||||||||
6560 | if (!sip->sip_from || !sip->sip_to || !sip->sip_call_id || !sip->sip_cseq || !sip->sip_via) | ||||||||
6561 | return -1; | ||||||||
6562 | |||||||||
6563 | return 0; | ||||||||
6564 | } | ||||||||
6565 | |||||||||
6566 | /** Complete a response message. | ||||||||
6567 | * | ||||||||
6568 | * @param irq server transaction object | ||||||||
6569 | * @param msg response message to be completed | ||||||||
6570 | * @param status status code (in range 100 - 699) | ||||||||
6571 | * @param phrase status phrase (may be NULL) | ||||||||
6572 | * @param tag,value,... taged argument list | ||||||||
6573 | * | ||||||||
6574 | * Generate status structure based on @a status and @a phrase. | ||||||||
6575 | * Add essential headers to the response message: | ||||||||
6576 | * @From, @To, @CallID, @CSeq, @Via, and optionally | ||||||||
6577 | * @RecordRoute. | ||||||||
6578 | */ | ||||||||
6579 | int nta_incoming_complete_response(nta_incoming_t *irq, | ||||||||
6580 | msg_t *msg, | ||||||||
6581 | int status, | ||||||||
6582 | char const *phrase, | ||||||||
6583 | tag_type_t tag, tag_value_t value, ...) | ||||||||
6584 | { | ||||||||
6585 | su_home_t *home = msg_home(msg)((su_home_t*)(msg)); | ||||||||
6586 | sip_t *sip = sip_object(msg); | ||||||||
6587 | int retval; | ||||||||
6588 | ta_list ta; | ||||||||
6589 | |||||||||
6590 | if (irq == NULL((void*)0) || sip == NULL((void*)0)) | ||||||||
6591 | return su_seterrno(EFAULT14), -1; | ||||||||
6592 | |||||||||
6593 | if (status != 0 && (status < 100 || status > 699)) | ||||||||
6594 | return su_seterrno(EINVAL22), -1; | ||||||||
6595 | |||||||||
6596 | if (status != 0 && !sip->sip_status) | ||||||||
6597 | sip->sip_status = sip_status_create(home, status, phrase, NULL((void*)0)); | ||||||||
6598 | |||||||||
6599 | 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); | ||||||||
6600 | 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); | ||||||||
6601 | 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)); | ||||||||
6602 | |||||||||
6603 | if (retval < 0) | ||||||||
6604 | return -1; | ||||||||
6605 | |||||||||
6606 | if (irq->irq_default) | ||||||||
6607 | return sip_complete_message(msg); | ||||||||
6608 | |||||||||
6609 | if (status > 100 && !irq->irq_tag) { | ||||||||
6610 | if (sip->sip_to) | ||||||||
6611 | nta_incoming_tag(irq, sip->sip_to->a_tag); | ||||||||
6612 | else | ||||||||
6613 | nta_incoming_tag(irq, NULL((void*)0)); | ||||||||
6614 | } | ||||||||
6615 | |||||||||
6616 | if (nta_incoming_response_headers(irq, msg, sip) < 0) | ||||||||
6617 | return -1; | ||||||||
6618 | |||||||||
6619 | if (sip->sip_status && sip->sip_status->st_status > 100 && | ||||||||
6620 | irq->irq_tag && sip->sip_to && !sip->sip_to->a_tag) | ||||||||
6621 | if (sip_to_tag(home, sip->sip_to, irq->irq_tag) < 0) | ||||||||
6622 | return -1; | ||||||||
6623 | |||||||||
6624 | if (status > 100 && status < 300 && !sip->sip_record_route && irq->irq_record_route) | ||||||||
6625 | if (sip_add_dup(msg, sip, (sip_header_t *)irq->irq_record_route) < 0) | ||||||||
6626 | return -1; | ||||||||
6627 | |||||||||
6628 | return sip_complete_message(msg); | ||||||||
6629 | } | ||||||||
6630 | |||||||||
6631 | |||||||||
6632 | /** Create a response message for request. | ||||||||
6633 | * | ||||||||
6634 | * @NEW_1_12_5. | ||||||||
6635 | */ | ||||||||
6636 | msg_t *nta_incoming_create_response(nta_incoming_t *irq, | ||||||||
6637 | int status, char const *phrase) | ||||||||
6638 | { | ||||||||
6639 | msg_t *msg = NULL((void*)0); | ||||||||
6640 | sip_t *sip; | ||||||||
6641 | |||||||||
6642 | if (irq) { | ||||||||
6643 | msg = nta_msg_create(irq->irq_agent, 0); | ||||||||
6644 | sip = sip_object(msg); | ||||||||
6645 | |||||||||
6646 | if (sip) { | ||||||||
6647 | if (status != 0) | ||||||||
6648 | sip->sip_status = sip_status_create(msg_home(msg)((su_home_t*)(msg)), status, phrase, NULL((void*)0)); | ||||||||
6649 | |||||||||
6650 | if (nta_incoming_response_headers(irq, msg, sip) < 0) | ||||||||
6651 | msg_destroy(msg), msg = NULL((void*)0); | ||||||||
6652 | } | ||||||||
6653 | } | ||||||||
6654 | |||||||||
6655 | return msg; | ||||||||
6656 | } | ||||||||
6657 | |||||||||
6658 | |||||||||
6659 | /**Reply to an incoming transaction request. | ||||||||
6660 | * | ||||||||
6661 | * This function creates a response message to an incoming request and sends | ||||||||
6662 | * it to the client. | ||||||||
6663 | * | ||||||||
6664 | * @note | ||||||||
6665 | * It is possible to send several non-final (1xx) responses, but only one | ||||||||
6666 | * final response. | ||||||||
6667 | * | ||||||||
6668 | * @param irq incoming request | ||||||||
6669 | * @param status status code | ||||||||
6670 | * @param phrase status phrase (may be NULL if status code is well-known) | ||||||||
6671 | * @param tag,value,... optional additional headers terminated by TAG_END() | ||||||||
6672 | * | ||||||||
6673 | * @retval 0 when succesful | ||||||||
6674 | * @retval -1 upon an error | ||||||||
6675 | */ | ||||||||
6676 | int nta_incoming_treply(nta_incoming_t *irq, | ||||||||
6677 | int status, | ||||||||
6678 | char const *phrase, | ||||||||
6679 | tag_type_t tag, tag_value_t value, ...) | ||||||||
6680 | { | ||||||||
6681 | int retval = -1; | ||||||||
6682 | |||||||||
6683 | if (irq && | ||||||||
6684 | (irq->irq_status < 200 || status < 200 || | ||||||||
6685 | (irq->irq_method == sip_method_invite && status < 300))) { | ||||||||
6686 | ta_list ta; | ||||||||
6687 | msg_t *msg = nta_msg_create(irq->irq_agent, 0); | ||||||||
6688 | |||||||||
6689 | 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); | ||||||||
6690 | |||||||||
6691 | if (!msg) | ||||||||
6692 | ; | ||||||||
6693 | else if (nta_incoming_complete_response(irq, msg, status, phrase, | ||||||||
6694 | ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta). tl[1].t_value) < 0) | ||||||||
6695 | msg_destroy(msg); | ||||||||
6696 | else if (incoming_set_params(irq, ta_args(ta)(ta).tl) < 0) | ||||||||
6697 | msg_destroy(msg); | ||||||||
6698 | else | ||||||||
6699 | retval = nta_incoming_mreply(irq, msg); | ||||||||
6700 | |||||||||
6701 | 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)); | ||||||||
6702 | |||||||||
6703 | if (retval < 0 && status >= 200) | ||||||||
6704 | incoming_final_failed(irq, NULL((void*)0)); | ||||||||
6705 | } | ||||||||
6706 | |||||||||
6707 | return retval; | ||||||||
6708 | } | ||||||||
6709 | |||||||||
6710 | /** | ||||||||
6711 | * Return a response message to client. | ||||||||
6712 | * | ||||||||
6713 | * @note | ||||||||
6714 | * The ownership of @a msg is taken over by the function even if the | ||||||||
6715 | * function fails. | ||||||||
6716 | * | ||||||||
6717 | * @retval 0 when succesful | ||||||||
6718 | * @retval -1 upon an error | ||||||||
6719 | */ | ||||||||
6720 | int nta_incoming_mreply(nta_incoming_t *irq, msg_t *msg) | ||||||||
6721 | { | ||||||||
6722 | sip_t *sip = sip_object(msg); | ||||||||
6723 | |||||||||
6724 | int status; | ||||||||
6725 | |||||||||
6726 | if (irq == NULL((void*)0)) { | ||||||||
6727 | msg_destroy(msg); | ||||||||
6728 | return -1; | ||||||||
6729 | } | ||||||||
6730 | |||||||||
6731 | if (msg == NULL((void*)0) || sip == NULL((void*)0)) | ||||||||
6732 | return -1; | ||||||||
6733 | |||||||||
6734 | if (msg == irq->irq_response) | ||||||||
6735 | return 0; | ||||||||
6736 | |||||||||
6737 | if (!sip->sip_status || !sip->sip_via || !sip->sip_cseq) | ||||||||
6738 | return incoming_final_failed(irq, msg); | ||||||||
6739 | |||||||||
6740 | assert (sip->sip_cseq->cs_method == irq->irq_method || irq->irq_default)((void) sizeof ((sip->sip_cseq->cs_method == irq->irq_method || irq->irq_default) ? 1 : 0), __extension__ ({ if (sip-> sip_cseq->cs_method == irq->irq_method || irq->irq_default ) ; else __assert_fail ("sip->sip_cseq->cs_method == irq->irq_method || irq->irq_default" , "nta.c", 6740, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
6741 | |||||||||
6742 | status = sip->sip_status->st_status; | ||||||||
6743 | |||||||||
6744 | if (!irq->irq_tag && status > 100 && !irq->irq_default) | ||||||||
6745 | nta_incoming_tag(irq, NULL((void*)0)); | ||||||||
6746 | |||||||||
6747 | if (/* (irq->irq_confirmed && status >= 200) || */ | ||||||||
6748 | (irq->irq_completed && status >= 300)) { | ||||||||
6749 | 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__ , 6750, "%s: already %s transaction\n", __func__, irq->irq_confirmed ? "confirmed" : "completed")) : (void)0) | ||||||||
6750 | 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__ , 6750, "%s: already %s transaction\n", __func__, irq->irq_confirmed ? "confirmed" : "completed")) : (void)0); | ||||||||
6751 | msg_destroy(msg); | ||||||||
6752 | return -1; | ||||||||
6753 | } | ||||||||
6754 | |||||||||
6755 | #ifdef HAVE_ZLIB_COMPRESS1 | ||||||||
6756 | if (irq->irq_compressed) { | ||||||||
6757 | sip_content_encoding_Xflate(msg, sip, 0, 0); | ||||||||
6758 | } | ||||||||
6759 | #endif | ||||||||
6760 | |||||||||
6761 | if (irq->irq_must_100rel && !sip->sip_rseq && status > 100 && status < 200) { | ||||||||
6762 | /* This nta_reliable_t object will be destroyed by PRACK or timeout */ | ||||||||
6763 | if (nta_reliable_mreply(irq, NULL((void*)0), NULL((void*)0), msg)) | ||||||||
6764 | return 0; | ||||||||
6765 | |||||||||
6766 | return -1; | ||||||||
6767 | } | ||||||||
6768 | |||||||||
6769 | if (status >= 200 && irq->irq_reliable && irq->irq_reliable->rel_unsent) { | ||||||||
6770 | if (reliable_final(irq, msg, sip) == 0) | ||||||||
6771 | return 0; | ||||||||
6772 | } | ||||||||
6773 | |||||||||
6774 | return incoming_reply(irq, msg, sip); | ||||||||
6775 | } | ||||||||
6776 | |||||||||
6777 | |||||||||
6778 | |||||||||
6779 | /** Send the response message. | ||||||||
6780 | * | ||||||||
6781 | * @note The ownership of msg is handled to incoming_reply(). | ||||||||
6782 | */ | ||||||||
6783 | int incoming_reply(nta_incoming_t *irq, msg_t *msg, sip_t *sip) | ||||||||
6784 | { | ||||||||
6785 | nta_agent_t *agent = irq->irq_agent; | ||||||||
6786 | int status = sip->sip_status->st_status; | ||||||||
6787 | int sending = 1; | ||||||||
6788 | int *use_rport = NULL((void*)0); | ||||||||
6789 | int retry_without_rport = 0; | ||||||||
6790 | tp_name_t *tpn, default_tpn[1]; | ||||||||
6791 | |||||||||
6792 | if (status == 408 && | ||||||||
6793 | irq->irq_method != sip_method_invite && | ||||||||
6794 | !agent->sa_pass_408 && | ||||||||
6795 | !irq->irq_default) { | ||||||||
6796 | /* RFC 4320 nit-actions-03 Action 2: | ||||||||
6797 | |||||||||
6798 | A transaction-stateful SIP element MUST NOT send a response with | ||||||||
6799 | Status-Code of 408 to a non-INVITE request. As a consequence, an | ||||||||
6800 | element that can not respond before the transaction expires will not | ||||||||
6801 | send a final response at all. | ||||||||
6802 | */ | ||||||||
6803 | sending = 0; | ||||||||
6804 | } | ||||||||
6805 | |||||||||
6806 | if (irq->irq_status == 0 && irq->irq_timestamp && !sip->sip_timestamp) | ||||||||
6807 | incoming_timestamp(irq, msg, sip); | ||||||||
6808 | |||||||||
6809 | if (irq->irq_default) { | ||||||||
6810 | if (agent->sa_server_rport) | ||||||||
6811 | use_rport = &retry_without_rport, retry_without_rport = 1; | ||||||||
6812 | tpn = default_tpn; | ||||||||
6813 | if (nta_tpn_by_via(tpn, sip->sip_via, use_rport) < 0) | ||||||||
6814 | tpn = NULL((void*)0); | ||||||||
6815 | } | ||||||||
6816 | else { | ||||||||
6817 | tpn = irq->irq_tpn; | ||||||||
6818 | } | ||||||||
6819 | |||||||||
6820 | if (sip_complete_message(msg) < 0) | ||||||||
6821 | 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__ , 6821, "%s: sip_complete_message() failed\n", __func__)) : ( void)0); | ||||||||
6822 | else if (msg_serialize(msg, (msg_pub_t *)sip) < 0) | ||||||||
6823 | 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__ , 6823, "%s: sip_serialize() failed\n", __func__)) : (void)0); | ||||||||
6824 | else if (!(irq->irq_tport) && | ||||||||
6825 | !(tport_decref(&irq->irq_tport), | ||||||||
6826 | irq->irq_tport = tpn ? tport_by_name(agent->sa_tports, tpn) : 0)) | ||||||||
6827 | 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__ , 6827, "%s: no tport\n", __func__)) : (void)0); | ||||||||
6828 | else { | ||||||||
6829 | int i, err = 0; | ||||||||
6830 | tport_t *tp = NULL((void*)0); | ||||||||
6831 | incoming_queue_t *queue; | ||||||||
6832 | |||||||||
6833 | char const *method_name; | ||||||||
6834 | uint32_t cseq; | ||||||||
6835 | |||||||||
6836 | if (irq->irq_default) { | ||||||||
6837 | assert(sip->sip_cseq)((void) sizeof ((sip->sip_cseq) ? 1 : 0), __extension__ ({ if (sip->sip_cseq) ; else __assert_fail ("sip->sip_cseq" , "nta.c", 6837, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
6838 | method_name = sip->sip_cseq->cs_method_name, cseq = sip->sip_cseq->cs_seq; | ||||||||
6839 | } | ||||||||
6840 | else { | ||||||||
6841 | method_name = irq->irq_rq->rq_method_name, cseq = irq->irq_cseq->cs_seq; | ||||||||
6842 | } | ||||||||
6843 | |||||||||
6844 | if (sending) { | ||||||||
6845 | for (i = 0; i < 3; i++) { | ||||||||
6846 | tp = tport_tsend(irq->irq_tport, msg, tpn, | ||||||||
6847 | 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)), | ||||||||
6848 | TPTAG_MTU(INT_MAX)tptag_mtu, tag_usize_v((2147483647)), | ||||||||
6849 | TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
6850 | if (tp) | ||||||||
6851 | break; | ||||||||
6852 | |||||||||
6853 | err = msg_errno(msg); | ||||||||
6854 | 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__ , 6856, "%s: tport_tsend: %s%s\n", __func__, su_strerror(err) , err == 32 ? "(retrying)" : "")) : (void)0) | ||||||||
6855 | __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__ , 6856, "%s: tport_tsend: %s%s\n", __func__, su_strerror(err) , err == 32 ? "(retrying)" : "")) : (void)0) | ||||||||
6856 | 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__ , 6856, "%s: tport_tsend: %s%s\n", __func__, su_strerror(err) , err == 32 ? "(retrying)" : "")) : (void)0); | ||||||||
6857 | |||||||||
6858 | if (err != EPIPE32 && err != ECONNREFUSED111) | ||||||||
6859 | break; | ||||||||
6860 | tport_decref(&irq->irq_tport); | ||||||||
6861 | irq->irq_tport = tport_ref(tport_by_name(agent->sa_tports, tpn)); | ||||||||
6862 | } | ||||||||
6863 | |||||||||
6864 | if (!tp) { | ||||||||
6865 | 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__ , 6868, "%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) | ||||||||
6866 | "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__ , 6868, "%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) | ||||||||
6867 | __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__ , 6868, "%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) | ||||||||
6868 | status, sip->sip_status->st_phrase, method_name, cseq))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 6868, "%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); | ||||||||
6869 | if (status < 200) | ||||||||
6870 | msg_destroy(msg); | ||||||||
6871 | else | ||||||||
6872 | incoming_final_failed(irq, msg); | ||||||||
6873 | return 0; | ||||||||
6874 | } | ||||||||
6875 | |||||||||
6876 | agent->sa_stats->as_sent_msg++; | ||||||||
6877 | agent->sa_stats->as_sent_response++; | ||||||||
6878 | } | ||||||||
6879 | |||||||||
6880 | 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__ , 6882, "nta: %s %u %s for %s (%u)\n", sending ? "sent" : "not sending" , status, sip->sip_status->st_phrase, method_name, cseq )) : (void)0) | ||||||||
6881 | 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__ , 6882, "nta: %s %u %s for %s (%u)\n", sending ? "sent" : "not sending" , status, sip->sip_status->st_phrase, method_name, cseq )) : (void)0) | ||||||||
6882 | 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__ , 6882, "nta: %s %u %s for %s (%u)\n", sending ? "sent" : "not sending" , status, sip->sip_status->st_phrase, method_name, cseq )) : (void)0); | ||||||||
6883 | |||||||||
6884 | if (irq->irq_default) { | ||||||||
6885 | msg_destroy(msg); | ||||||||
6886 | return 0; | ||||||||
6887 | } | ||||||||
6888 | |||||||||
6889 | incoming_reset_timer(irq); | ||||||||
6890 | |||||||||
6891 | if (status < 200) { | ||||||||
6892 | queue = agent->sa_in.proceeding; | ||||||||
6893 | |||||||||
6894 | if (irq->irq_method == sip_method_invite && status > 100 && | ||||||||
6895 | agent->sa_progress != UINT_MAX(2147483647 *2U +1U) && agent->sa_is_a_uas) { | ||||||||
6896 | /* Retransmit preliminary responses in regular intervals */ | ||||||||
6897 | incoming_set_timer(irq, agent->sa_progress); /* N2 */ | ||||||||
6898 | } | ||||||||
6899 | } | ||||||||
6900 | else { | ||||||||
6901 | irq->irq_completed = 1; | ||||||||
6902 | |||||||||
6903 | /* XXX - we should do this only after message has actually been sent! */ | ||||||||
6904 | if (irq->irq_sigcomp_zap && irq->irq_cc) | ||||||||
6905 | agent_close_compressor(irq->irq_agent, irq->irq_cc); | ||||||||
6906 | |||||||||
6907 | if (irq->irq_method != sip_method_invite) { | ||||||||
6908 | irq->irq_confirmed = 1; | ||||||||
6909 | |||||||||
6910 | if (irq->irq_reliable_tp) { | ||||||||
6911 | irq->irq_terminated = 1; | ||||||||
6912 | queue = agent->sa_in.terminated ; /* J - set for 0 seconds */ | ||||||||
6913 | } else { | ||||||||
6914 | queue = agent->sa_in.completed; /* J */ | ||||||||
6915 | } | ||||||||
6916 | |||||||||
6917 | tport_decref(&irq->irq_tport); | ||||||||
6918 | } | ||||||||
6919 | else if (status >= 300 || agent->sa_is_a_uas) { | ||||||||
6920 | if (status < 300 || !irq->irq_reliable_tp) | ||||||||
6921 | incoming_set_timer(irq, agent->sa_t1); /* G */ | ||||||||
6922 | queue = agent->sa_in.inv_completed; /* H */ | ||||||||
6923 | } | ||||||||
6924 | else { | ||||||||
6925 | #if 1 | ||||||||
6926 | /* Avoid bug in @RFC3261: | ||||||||
6927 | Keep INVITE transaction around in order to catch | ||||||||
6928 | retransmitted INVITEs | ||||||||
6929 | */ | ||||||||
6930 | irq->irq_confirmed = 1; | ||||||||
6931 | queue = agent->sa_in.inv_confirmed; /* H */ | ||||||||
6932 | #else | ||||||||
6933 | irq->irq_terminated = 1; | ||||||||
6934 | queue = agent->sa_in.terminated; | ||||||||
6935 | #endif | ||||||||
6936 | } | ||||||||
6937 | } | ||||||||
6938 | |||||||||
6939 | if (irq->irq_queue != queue) | ||||||||
6940 | incoming_queue(queue, irq); | ||||||||
6941 | |||||||||
6942 | if (status >= 200 || irq->irq_status < 200) { | ||||||||
6943 | if (irq->irq_response) | ||||||||
6944 | msg_destroy(irq->irq_response); | ||||||||
6945 | assert(msg_home(msg) != irq->irq_home)((void) sizeof ((((su_home_t*)(msg)) != irq->irq_home) ? 1 : 0), __extension__ ({ if (((su_home_t*)(msg)) != irq->irq_home ) ; else __assert_fail ("msg_home(msg) != irq->irq_home", "nta.c" , 6945, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
6946 | irq->irq_response = msg; | ||||||||
6947 | } | ||||||||
6948 | else { | ||||||||
6949 | msg_destroy(msg); | ||||||||
6950 | } | ||||||||
6951 | |||||||||
6952 | if (sip->sip_cseq->cs_method == irq->irq_method && | ||||||||
6953 | irq->irq_status < 200 && status > irq->irq_status) | ||||||||
6954 | irq->irq_status = status; | ||||||||
6955 | |||||||||
6956 | return 0; | ||||||||
6957 | } | ||||||||
6958 | |||||||||
6959 | /* | ||||||||
6960 | * XXX - handling error is very problematic. | ||||||||
6961 | * Nobody checks return code from nta_incoming_*reply() | ||||||||
6962 | */ | ||||||||
6963 | if (status < 200) { | ||||||||
6964 | msg_destroy(msg); | ||||||||
6965 | return -1; | ||||||||
6966 | } | ||||||||
6967 | |||||||||
6968 | /* We could not send final response. */ | ||||||||
6969 | return incoming_final_failed(irq, msg); | ||||||||
6970 | } | ||||||||
6971 | |||||||||
6972 | |||||||||
6973 | /** @internal Sending final response has failed. | ||||||||
6974 | * | ||||||||
6975 | * Put transaction into its own queue, try later to send the response. | ||||||||
6976 | */ | ||||||||
6977 | su_inlinestatic inline | ||||||||
6978 | int incoming_final_failed(nta_incoming_t *irq, msg_t *msg) | ||||||||
6979 | { | ||||||||
6980 | msg_destroy(msg); | ||||||||
6981 | |||||||||
6982 | if (!irq->irq_default) { | ||||||||
6983 | irq->irq_final_failed = 1; | ||||||||
6984 | incoming_queue(irq->irq_agent->sa_in.final_failed, irq); | ||||||||
6985 | } | ||||||||
6986 | |||||||||
6987 | return -1; | ||||||||
6988 | } | ||||||||
6989 | |||||||||
6990 | /** @internal Retransmit the reply */ | ||||||||
6991 | static | ||||||||
6992 | void incoming_retransmit_reply(nta_incoming_t *irq, tport_t *tport) | ||||||||
6993 | { | ||||||||
6994 | msg_t *msg = NULL((void*)0); | ||||||||
6995 | |||||||||
6996 | if (irq->irq_final_failed) | ||||||||
6997 | return; | ||||||||
6998 | |||||||||
6999 | if (tport == NULL((void*)0)) | ||||||||
7000 | tport = irq->irq_tport; | ||||||||
7001 | |||||||||
7002 | /* Answer with existing reply */ | ||||||||
7003 | if (irq->irq_reliable && !irq->irq_reliable->rel_pracked) | ||||||||
7004 | msg = reliable_response(irq); | ||||||||
7005 | else | ||||||||
7006 | msg = irq->irq_response; | ||||||||
7007 | |||||||||
7008 | if (msg && tport) { | ||||||||
7009 | irq->irq_retries++; | ||||||||
7010 | |||||||||
7011 | if (irq->irq_retries == 2 && irq->irq_tpn->tpn_comp) { | ||||||||
7012 | irq->irq_tpn->tpn_comp = NULL((void*)0); | ||||||||
7013 | |||||||||
7014 | if (irq->irq_cc) { | ||||||||
7015 | agent_close_compressor(irq->irq_agent, irq->irq_cc); | ||||||||
7016 | nta_compartment_decref(&irq->irq_cc); | ||||||||
7017 | } | ||||||||
7018 | } | ||||||||
7019 | |||||||||
7020 | tport_tsend(tport, msg, irq->irq_tpn, | ||||||||
7021 | 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)), | ||||||||
7022 | TPTAG_MTU(INT_MAX)tptag_mtu, tag_usize_v((2147483647)), TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
7023 | irq->irq_agent->sa_stats->as_sent_msg++; | ||||||||
7024 | irq->irq_agent->sa_stats->as_sent_response++; | ||||||||
7025 | } | ||||||||
7026 | } | ||||||||
7027 | |||||||||
7028 | /** @internal Create timestamp header for response */ | ||||||||
7029 | static | ||||||||
7030 | int incoming_timestamp(nta_incoming_t *irq, msg_t *msg, sip_t *sip) | ||||||||
7031 | { | ||||||||
7032 | sip_timestamp_t ts[1]; | ||||||||
7033 | su_time_t now = su_now(); | ||||||||
7034 | char delay[32]; | ||||||||
7035 | double diff = su_time_diff(now, irq->irq_received); | ||||||||
7036 | |||||||||
7037 | snprintf(delay, sizeof delay, "%.06f", diff); | ||||||||
7038 | |||||||||
7039 | *ts = *irq->irq_timestamp; | ||||||||
7040 | ts->ts_delay = delay; | ||||||||
7041 | |||||||||
7042 | return sip_add_dup(msg, sip, (sip_header_t *)ts); | ||||||||
7043 | } | ||||||||
7044 | |||||||||
7045 | enum { | ||||||||
7046 | timer_max_retransmit = 30, | ||||||||
7047 | timer_max_terminate = 100000, | ||||||||
7048 | timer_max_timeout = 100 | ||||||||
7049 | }; | ||||||||
7050 | |||||||||
7051 | /** @internal Timer routine for the incoming request. */ | ||||||||
7052 | static void | ||||||||
7053 | _nta_incoming_timer(nta_agent_t *sa) | ||||||||
7054 | { | ||||||||
7055 | uint32_t now; | ||||||||
7056 | nta_incoming_t *irq, *irq_next; | ||||||||
7057 | size_t retransmitted = 0, timeout = 0, terminated = 0, destroyed = 0; | ||||||||
7058 | size_t unconfirmed = | ||||||||
7059 | sa->sa_in.inv_completed->q_length + | ||||||||
7060 | sa->sa_in.preliminary->q_length; | ||||||||
7061 | size_t unterminated = | ||||||||
7062 | sa->sa_in.inv_confirmed->q_length + | ||||||||
7063 | sa->sa_in.completed->q_length; | ||||||||
7064 | size_t total = sa->sa_incoming->iht_used; | ||||||||
7065 | |||||||||
7066 | incoming_queue_t rq[1]; | ||||||||
7067 | |||||||||
7068 | incoming_queue_init(rq, 0); | ||||||||
7069 | |||||||||
7070 | /* Handle retry queue */ | ||||||||
7071 | while ((irq = sa->sa_in.re_list)) { | ||||||||
7072 | |||||||||
7073 | now = su_time_ms(su_now()); | ||||||||
7074 | |||||||||
7075 | if ((int32_t)(irq->irq_retry - now) > 0) | ||||||||
7076 | break; | ||||||||
7077 | if (retransmitted >= timer_max_retransmit) | ||||||||
7078 | break; | ||||||||
7079 | |||||||||
7080 | if (irq->irq_method == sip_method_invite && irq->irq_status >= 200) { | ||||||||
7081 | /* Timer G */ | ||||||||
7082 | assert(irq->irq_queue == sa->sa_in.inv_completed)((void) sizeof ((irq->irq_queue == sa->sa_in.inv_completed ) ? 1 : 0), __extension__ ({ if (irq->irq_queue == sa-> sa_in.inv_completed) ; else __assert_fail ("irq->irq_queue == sa->sa_in.inv_completed" , "nta.c", 7082, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
7083 | |||||||||
7084 | retransmitted++; | ||||||||
7085 | |||||||||
7086 | SU_DEBUG_5(("nta: timer %s fired, retransmitting %u reply\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 7087, "nta: timer %s fired, retransmitting %u reply\n", "G" , irq->irq_status)) : (void)0) | ||||||||
7087 | "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__ , 7087, "nta: timer %s fired, retransmitting %u reply\n", "G" , irq->irq_status)) : (void)0); | ||||||||
7088 | |||||||||
7089 | incoming_retransmit_reply(irq, irq->irq_tport); | ||||||||
7090 | |||||||||
7091 | if (2U * irq->irq_interval < sa->sa_t2) | ||||||||
7092 | incoming_set_timer(irq, 2U * irq->irq_interval); /* G */ | ||||||||
7093 | else | ||||||||
7094 | incoming_set_timer(irq, sa->sa_t2); /* G */ | ||||||||
7095 | } | ||||||||
7096 | else if (irq->irq_method == sip_method_invite && irq->irq_status >= 100) { | ||||||||
7097 | if (irq->irq_queue == sa->sa_in.preliminary) { | ||||||||
7098 | /* Timer P1 - PRACK timer */ | ||||||||
7099 | retransmitted++; | ||||||||
7100 | 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__ , 7101, "nta: timer %s fired, retransmitting %u reply\n", "P1" , irq->irq_status)) : (void)0) | ||||||||
7101 | "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__ , 7101, "nta: timer %s fired, retransmitting %u reply\n", "P1" , irq->irq_status)) : (void)0); | ||||||||
7102 | |||||||||
7103 | incoming_retransmit_reply(irq, irq->irq_tport); | ||||||||
7104 | |||||||||
7105 | incoming_set_timer(irq, 2 * irq->irq_interval); /* P1 */ | ||||||||
7106 | } | ||||||||
7107 | else { | ||||||||
7108 | /* Retransmitting provisional responses */ | ||||||||
7109 | 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__ , 7110, "nta: timer %s fired, retransmitting %u reply\n", "N2" , irq->irq_status)) : (void)0) | ||||||||
7110 | "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__ , 7110, "nta: timer %s fired, retransmitting %u reply\n", "N2" , irq->irq_status)) : (void)0); | ||||||||
7111 | incoming_set_timer(irq, sa->sa_progress); | ||||||||
7112 | retransmitted++; | ||||||||
7113 | incoming_retransmit_reply(irq, irq->irq_tport); | ||||||||
7114 | } | ||||||||
7115 | } | ||||||||
7116 | else { | ||||||||
7117 | /* Timer N1 */ | ||||||||
7118 | incoming_reset_timer(irq); | ||||||||
7119 | |||||||||
7120 | if(irq->irq_extra_100) { | ||||||||
7121 | 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__ , 7121, "nta: timer N1 fired, sending %u %s\n", 100, sip_100_Trying )) : (void)0); | ||||||||
7122 | nta_incoming_treply(irq, SIP_100_TRYING100, sip_100_Trying, TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
7123 | } | ||||||||
7124 | else { | ||||||||
7125 | 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__ , 7126, "nta: timer N1 fired, but avoided sending %u %s\n", 100 , sip_100_Trying)) : (void)0) | ||||||||
7126 | 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__ , 7126, "nta: timer N1 fired, but avoided sending %u %s\n", 100 , sip_100_Trying)) : (void)0); | ||||||||
7127 | } | ||||||||
7128 | } | ||||||||
7129 | } | ||||||||
7130 | |||||||||
7131 | while ((irq = sa->sa_in.final_failed->q_head)) { | ||||||||
7132 | |||||||||
7133 | |||||||||
7134 | incoming_remove(irq); | ||||||||
7135 | irq->irq_final_failed = 0; | ||||||||
7136 | |||||||||
7137 | /* Report error to application */ | ||||||||
7138 | 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__ , 7139, "nta: sending final response failed, timeout %u response\n" , irq->irq_status)) : (void)0) | ||||||||
7139 | 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__ , 7139, "nta: sending final response failed, timeout %u response\n" , irq->irq_status)) : (void)0); | ||||||||
7140 | reliable_timeout(irq, 0); | ||||||||
7141 | |||||||||
7142 | nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error, TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
7143 | |||||||||
7144 | if (!irq->irq_final_failed) /* We have taken care of the error... */ | ||||||||
7145 | continue; | ||||||||
7146 | |||||||||
7147 | if (irq->irq_destroyed) { | ||||||||
7148 | incoming_free_queue(rq, irq); | ||||||||
7149 | continue; | ||||||||
7150 | } | ||||||||
7151 | |||||||||
7152 | incoming_reset_timer(irq); | ||||||||
7153 | irq->irq_confirmed = 1; | ||||||||
7154 | irq->irq_terminated = 1; | ||||||||
7155 | incoming_queue(sa->sa_in.terminated, irq); | ||||||||
7156 | } | ||||||||
7157 | |||||||||
7158 | /* Timeouts. | ||||||||
7159 | * For each state the request is in, there is always a queue of its own | ||||||||
7160 | */ | ||||||||
7161 | while ((irq = sa->sa_in.preliminary->q_head)) { | ||||||||
7162 | assert(irq->irq_status < 200)((void) sizeof ((irq->irq_status < 200) ? 1 : 0), __extension__ ({ if (irq->irq_status < 200) ; else __assert_fail ("irq->irq_status < 200" , "nta.c", 7162, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
7163 | assert(irq->irq_timeout)((void) sizeof ((irq->irq_timeout) ? 1 : 0), __extension__ ({ if (irq->irq_timeout) ; else __assert_fail ("irq->irq_timeout" , "nta.c", 7163, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
7164 | |||||||||
7165 | now = su_time_ms(su_now()); | ||||||||
7166 | |||||||||
7167 | if ((int32_t)(irq->irq_timeout - now) > 0) | ||||||||
7168 | break; | ||||||||
7169 | if (timeout >= timer_max_timeout) | ||||||||
7170 | break; | ||||||||
7171 | |||||||||
7172 | timeout++; | ||||||||
7173 | |||||||||
7174 | /* Timer P2 - PRACK timer */ | ||||||||
7175 | 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__ , 7176, "nta: timer %s fired, %s %u response\n", "P2", "timeout" , irq->irq_status)) : (void)0) | ||||||||
7176 | "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__ , 7176, "nta: timer %s fired, %s %u response\n", "P2", "timeout" , irq->irq_status)) : (void)0); | ||||||||
7177 | incoming_reset_timer(irq); | ||||||||
7178 | irq->irq_timeout = 0; | ||||||||
7179 | reliable_timeout(irq, 1); | ||||||||
7180 | } | ||||||||
7181 | |||||||||
7182 | while ((irq = sa->sa_in.inv_completed->q_head)) { | ||||||||
7183 | assert(irq->irq_status >= 200)((void) sizeof ((irq->irq_status >= 200) ? 1 : 0), __extension__ ({ if (irq->irq_status >= 200) ; else __assert_fail ("irq->irq_status >= 200" , "nta.c", 7183, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
7184 | assert(irq->irq_timeout)((void) sizeof ((irq->irq_timeout) ? 1 : 0), __extension__ ({ if (irq->irq_timeout) ; else __assert_fail ("irq->irq_timeout" , "nta.c", 7184, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
7185 | assert(irq->irq_method == sip_method_invite)((void) sizeof ((irq->irq_method == sip_method_invite) ? 1 : 0), __extension__ ({ if (irq->irq_method == sip_method_invite ) ; else __assert_fail ("irq->irq_method == sip_method_invite" , "nta.c", 7185, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
7186 | |||||||||
7187 | now = su_time_ms(su_now()); | ||||||||
7188 | |||||||||
7189 | if ((int32_t)(irq->irq_timeout - now) > 0 || | ||||||||
7190 | timeout >= timer_max_timeout || | ||||||||
7191 | terminated >= timer_max_terminate) | ||||||||
7192 | break; | ||||||||
7193 | |||||||||
7194 | /* Timer H */ | ||||||||
7195 | 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__ , 7196, "nta: timer %s fired, %s %u response\n", "H", "timeout and terminate" , irq->irq_status)) : (void)0) | ||||||||
7196 | "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__ , 7196, "nta: timer %s fired, %s %u response\n", "H", "timeout and terminate" , irq->irq_status)) : (void)0); | ||||||||
7197 | irq->irq_confirmed = 1; | ||||||||
7198 | irq->irq_terminated = 1; | ||||||||
7199 | incoming_reset_timer(irq); | ||||||||
7200 | if (!irq->irq_destroyed) { | ||||||||
7201 | timeout++; | ||||||||
7202 | incoming_queue(sa->sa_in.terminated, irq); | ||||||||
7203 | /* report timeout error to user */ | ||||||||
7204 | incoming_call_callback(irq, NULL((void*)0), NULL((void*)0)); | ||||||||
7205 | } else { | ||||||||
7206 | timeout++; | ||||||||
7207 | terminated++; | ||||||||
7208 | incoming_free_queue(rq, irq); | ||||||||
7209 | } | ||||||||
7210 | } | ||||||||
7211 | |||||||||
7212 | while ((irq = sa->sa_in.inv_confirmed->q_head)) { | ||||||||
7213 | assert(irq->irq_timeout)((void) sizeof ((irq->irq_timeout) ? 1 : 0), __extension__ ({ if (irq->irq_timeout) ; else __assert_fail ("irq->irq_timeout" , "nta.c", 7213, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
7214 | assert(irq->irq_status >= 200)((void) sizeof ((irq->irq_status >= 200) ? 1 : 0), __extension__ ({ if (irq->irq_status >= 200) ; else __assert_fail ("irq->irq_status >= 200" , "nta.c", 7214, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
7215 | assert(irq->irq_method == sip_method_invite)((void) sizeof ((irq->irq_method == sip_method_invite) ? 1 : 0), __extension__ ({ if (irq->irq_method == sip_method_invite ) ; else __assert_fail ("irq->irq_method == sip_method_invite" , "nta.c", 7215, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
7216 | |||||||||
7217 | now = su_time_ms(su_now()); | ||||||||
7218 | |||||||||
7219 | if ((int32_t)(irq->irq_timeout - now) > 0 || | ||||||||
7220 | terminated >= timer_max_terminate) | ||||||||
7221 | break; | ||||||||
7222 | |||||||||
7223 | /* Timer I */ | ||||||||
7224 | 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__ , 7225, "nta: timer %s fired, %s %u response\n", "I", "terminate" , irq->irq_status)) : (void)0) | ||||||||
7225 | "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__ , 7225, "nta: timer %s fired, %s %u response\n", "I", "terminate" , irq->irq_status)) : (void)0); | ||||||||
7226 | |||||||||
7227 | terminated++; | ||||||||
7228 | irq->irq_terminated = 1; | ||||||||
7229 | |||||||||
7230 | if (!irq->irq_destroyed) | ||||||||
7231 | incoming_queue(sa->sa_in.terminated, irq); | ||||||||
7232 | else | ||||||||
7233 | incoming_free_queue(rq, irq); | ||||||||
7234 | } | ||||||||
7235 | |||||||||
7236 | while ((irq = sa->sa_in.completed->q_head)) { | ||||||||
7237 | assert(irq->irq_status >= 200)((void) sizeof ((irq->irq_status >= 200) ? 1 : 0), __extension__ ({ if (irq->irq_status >= 200) ; else __assert_fail ("irq->irq_status >= 200" , "nta.c", 7237, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
7238 | assert(irq->irq_timeout)((void) sizeof ((irq->irq_timeout) ? 1 : 0), __extension__ ({ if (irq->irq_timeout) ; else __assert_fail ("irq->irq_timeout" , "nta.c", 7238, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
7239 | assert(irq->irq_method != sip_method_invite)((void) sizeof ((irq->irq_method != sip_method_invite) ? 1 : 0), __extension__ ({ if (irq->irq_method != sip_method_invite ) ; else __assert_fail ("irq->irq_method != sip_method_invite" , "nta.c", 7239, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
7240 | |||||||||
7241 | now = su_time_ms(su_now()); | ||||||||
7242 | |||||||||
7243 | if ((int32_t)(irq->irq_timeout - now) > 0 || | ||||||||
7244 | terminated >= timer_max_terminate) | ||||||||
7245 | break; | ||||||||
7246 | |||||||||
7247 | /* Timer J */ | ||||||||
7248 | |||||||||
7249 | 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__ , 7250, "nta: timer %s fired, %s %u response\n", "J", "terminate" , irq->irq_status)) : (void)0) | ||||||||
7250 | "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__ , 7250, "nta: timer %s fired, %s %u response\n", "J", "terminate" , irq->irq_status)) : (void)0); | ||||||||
7251 | |||||||||
7252 | terminated++; | ||||||||
7253 | irq->irq_terminated = 1; | ||||||||
7254 | |||||||||
7255 | if (!irq->irq_destroyed) | ||||||||
7256 | incoming_queue(sa->sa_in.terminated, irq); | ||||||||
7257 | else | ||||||||
7258 | incoming_free_queue(rq, irq); | ||||||||
7259 | } | ||||||||
7260 | |||||||||
7261 | for (irq = sa->sa_in.terminated->q_head; irq; irq = irq_next) { | ||||||||
7262 | |||||||||
7263 | irq_next = irq->irq_next; | ||||||||
7264 | if (irq->irq_destroyed) | ||||||||
7265 | incoming_free_queue(rq, irq); | ||||||||
7266 | } | ||||||||
7267 | |||||||||
7268 | destroyed = incoming_mass_destroy(sa, rq); | ||||||||
7269 | |||||||||
7270 | if (retransmitted || timeout || terminated || destroyed) | ||||||||
7271 | 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__ , 7279, "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) | ||||||||
7272 | 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__ , 7279, "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) | ||||||||
7273 | 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__ , 7279, "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) | ||||||||
7274 | 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__ , 7279, "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) | ||||||||
7275 | 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__ , 7279, "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) | ||||||||
7276 | 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__ , 7279, "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) | ||||||||
7277 | 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__ , 7279, "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) | ||||||||
7278 | 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__ , 7279, "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) | ||||||||
7279 | 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__ , 7279, "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); | ||||||||
7280 | } | ||||||||
7281 | |||||||||
7282 | /** Mass destroy server transactions */ | ||||||||
7283 | su_inlinestatic inline | ||||||||
7284 | size_t incoming_mass_destroy(nta_agent_t *sa, incoming_queue_t *q) | ||||||||
7285 | { | ||||||||
7286 | size_t destroyed = q->q_length; | ||||||||
7287 | |||||||||
7288 | if (destroyed > 2 && *sa->sa_terminator) { | ||||||||
7289 | su_msg_r m = SU_MSG_R_INIT{ ((void*)0) }; | ||||||||
7290 | |||||||||
7291 | if (su_msg_create(m, | ||||||||
7292 | su_clone_task(sa->sa_terminator), | ||||||||
7293 | su_root_task(sa->sa_root), | ||||||||
7294 | incoming_reclaim_queued, | ||||||||
7295 | sizeof(incoming_queue_t)) == SU_SUCCESSsu_success) { | ||||||||
7296 | incoming_queue_t *mq = su_msg_data(m)->a_incoming_queue; | ||||||||
7297 | |||||||||
7298 | *mq = *q; | ||||||||
7299 | |||||||||
7300 | if (su_msg_send(m) == SU_SUCCESSsu_success) | ||||||||
7301 | q->q_length = 0; | ||||||||
7302 | } | ||||||||
7303 | } | ||||||||
7304 | |||||||||
7305 | if (q->q_length > 0) | ||||||||
7306 | incoming_reclaim_queued(NULL((void*)0), NULL((void*)0), (void *)q); | ||||||||
7307 | |||||||||
7308 | return destroyed; | ||||||||
7309 | } | ||||||||
7310 | |||||||||
7311 | /* ====================================================================== */ | ||||||||
7312 | /* 8) Client-side (outgoing) transactions */ | ||||||||
7313 | |||||||||
7314 | #define HTABLE_HASH_ORQ(orq)((orq)->orq_hash) ((orq)->orq_hash) | ||||||||
7315 | |||||||||
7316 | #ifdef __clang__1 | ||||||||
7317 | #pragma clang diagnostic push | ||||||||
7318 | #pragma clang diagnostic ignored "-Wunused-function" | ||||||||
7319 | #endif | ||||||||
7320 | |||||||||
7321 | HTABLE_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; if (new_size == 0) new_size = 2 * oht->oht_size + 1; if (new_size < 31) new_size = 31; if (new_size < 5 * oht->oht_used / 4) new_size = 5 * oht->oht_used / 4; if (!(new_hash = su_zalloc(home, sizeof (*new_hash) * new_size))) return -1; old_size = oht->oht_size ; do for (j = 0; j < old_size; j++) { if (!old_hash[j]) continue ; if (again < 2 && ((old_hash[j])->orq_hash) % old_size > j) { again = 1; continue; } i0 = ((old_hash[j])->orq_hash ) % new_size; for (i = i0; new_hash[i]; i = (i + 1) % new_size , ((void) sizeof ((i != i0) ? 1 : 0), __extension__ ({ if (i != i0) ; else __assert_fail ("i != i0", "nta.c", 7322, __extension__ __PRETTY_FUNCTION__); }))); new_hash[i] = old_hash[j], old_hash [j] = ((void*)0); used++; } while (again++ == 1); oht->oht_table = new_hash, oht->oht_size = new_size; ((void) sizeof ((oht ->oht_used == used) ? 1 : 0), __extension__ ({ if (oht-> oht_used == used) ; else __assert_fail ("oht->oht_used == used" , "nta.c", 7322, __extension__ __PRETTY_FUNCTION__); })); su_free (home, old_hash); return 0; } static inline int outgoing_htable_is_full (outgoing_htable_t const *oht) { return oht->oht_table == ( (void*)0) || 3 * oht->oht_used > 2 * oht->oht_size; } static inline nta_outgoing_t **outgoing_htable_hash(outgoing_htable_t const *oht, hash_value_t hv) { return oht->oht_table + hv % oht->oht_size; } static inline nta_outgoing_t **outgoing_htable_next (outgoing_htable_t const *oht, nta_outgoing_t * const *ee) { if (++ee < oht->oht_table + oht->oht_size && ee >= oht->oht_table) return (nta_outgoing_t **)ee; else return oht->oht_table; } static inline void outgoing_htable_append (outgoing_htable_t *oht, nta_outgoing_t const *e) { nta_outgoing_t **ee; oht->oht_used++; for (ee = outgoing_htable_hash(oht , ((e)->orq_hash)); *ee; ee = outgoing_htable_next(oht, ee )) ; *ee = (nta_outgoing_t *)e; } static inline void outgoing_htable_insert (outgoing_htable_t *oht, nta_outgoing_t const *e) { nta_outgoing_t *e0, **ee; oht->oht_used++; for (ee = outgoing_htable_hash (oht, ((e)->orq_hash)); (e0 = *ee); ee = outgoing_htable_next (oht, ee)) *ee = (nta_outgoing_t *)e, e = e0; *ee = (nta_outgoing_t *)e; } static inline int outgoing_htable_remove(outgoing_htable_t *oht, nta_outgoing_t const *e) { size_t i, j, k; size_t size = oht->oht_size; nta_outgoing_t **htable = oht->oht_table ; if (!e) return -1; for (i = ((e)->orq_hash) % size; htable [i]; i = (i + 1) % size) if (e == htable[i]) break; if (!htable [i]) return -1; for (j = (i + 1) % size; htable[j]; j = (j + 1 ) % size) { k = ((htable[j])->orq_hash) % size; if (k == j ) continue; if (j > i ? (i < k && k < j) : ( i < k || k < j)) continue; htable[i] = htable[j], i = j ; } oht->oht_used--; htable[i] = ((void*)0); return 0; } extern int outgoing_htable_dummy | ||||||||
7322 | 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; if (new_size == 0) new_size = 2 * oht->oht_size + 1; if (new_size < 31) new_size = 31; if (new_size < 5 * oht->oht_used / 4) new_size = 5 * oht->oht_used / 4; if (!(new_hash = su_zalloc(home, sizeof (*new_hash) * new_size))) return -1; old_size = oht->oht_size ; do for (j = 0; j < old_size; j++) { if (!old_hash[j]) continue ; if (again < 2 && ((old_hash[j])->orq_hash) % old_size > j) { again = 1; continue; } i0 = ((old_hash[j])->orq_hash ) % new_size; for (i = i0; new_hash[i]; i = (i + 1) % new_size , ((void) sizeof ((i != i0) ? 1 : 0), __extension__ ({ if (i != i0) ; else __assert_fail ("i != i0", "nta.c", 7322, __extension__ __PRETTY_FUNCTION__); }))); new_hash[i] = old_hash[j], old_hash [j] = ((void*)0); used++; } while (again++ == 1); oht->oht_table = new_hash, oht->oht_size = new_size; ((void) sizeof ((oht ->oht_used == used) ? 1 : 0), __extension__ ({ if (oht-> oht_used == used) ; else __assert_fail ("oht->oht_used == used" , "nta.c", 7322, __extension__ __PRETTY_FUNCTION__); })); su_free (home, old_hash); return 0; } static inline int outgoing_htable_is_full (outgoing_htable_t const *oht) { return oht->oht_table == ( (void*)0) || 3 * oht->oht_used > 2 * oht->oht_size; } static inline nta_outgoing_t **outgoing_htable_hash(outgoing_htable_t const *oht, hash_value_t hv) { return oht->oht_table + hv % oht->oht_size; } static inline nta_outgoing_t **outgoing_htable_next (outgoing_htable_t const *oht, nta_outgoing_t * const *ee) { if (++ee < oht->oht_table + oht->oht_size && ee >= oht->oht_table) return (nta_outgoing_t **)ee; else return oht->oht_table; } static inline void outgoing_htable_append (outgoing_htable_t *oht, nta_outgoing_t const *e) { nta_outgoing_t **ee; oht->oht_used++; for (ee = outgoing_htable_hash(oht , ((e)->orq_hash)); *ee; ee = outgoing_htable_next(oht, ee )) ; *ee = (nta_outgoing_t *)e; } static inline void outgoing_htable_insert (outgoing_htable_t *oht, nta_outgoing_t const *e) { nta_outgoing_t *e0, **ee; oht->oht_used++; for (ee = outgoing_htable_hash (oht, ((e)->orq_hash)); (e0 = *ee); ee = outgoing_htable_next (oht, ee)) *ee = (nta_outgoing_t *)e, e = e0; *ee = (nta_outgoing_t *)e; } static inline int outgoing_htable_remove(outgoing_htable_t *oht, nta_outgoing_t const *e) { size_t i, j, k; size_t size = oht->oht_size; nta_outgoing_t **htable = oht->oht_table ; if (!e) return -1; for (i = ((e)->orq_hash) % size; htable [i]; i = (i + 1) % size) if (e == htable[i]) break; if (!htable [i]) return -1; for (j = (i + 1) % size; htable[j]; j = (j + 1 ) % size) { k = ((htable[j])->orq_hash) % size; if (k == j ) continue; if (j > i ? (i < k && k < j) : ( i < k || k < j)) continue; htable[i] = htable[j], i = j ; } oht->oht_used--; htable[i] = ((void*)0); return 0; } extern int outgoing_htable_dummy; | ||||||||
7323 | |||||||||
7324 | #ifdef __clang__1 | ||||||||
7325 | #pragma clang diagnostic pop | ||||||||
7326 | #endif | ||||||||
7327 | |||||||||
7328 | static int outgoing_features(nta_agent_t *agent, nta_outgoing_t *orq, | ||||||||
7329 | msg_t *msg, sip_t *sip, | ||||||||
7330 | tagi_t *tags); | ||||||||
7331 | static void outgoing_prepare_send(nta_outgoing_t *orq); | ||||||||
7332 | static void outgoing_send_via(nta_outgoing_t *orq, tport_t *tp); | ||||||||
7333 | static void outgoing_send(nta_outgoing_t *orq, int retransmit); | ||||||||
7334 | static void outgoing_try_tcp_instead(nta_outgoing_t *orq); | ||||||||
7335 | static void outgoing_try_udp_instead(nta_outgoing_t *orq, int timeout); | ||||||||
7336 | static void outgoing_tport_error(nta_agent_t *agent, nta_outgoing_t *orq, | ||||||||
7337 | tport_t *tp, msg_t *msg, int error); | ||||||||
7338 | static void outgoing_print_tport_error(nta_outgoing_t *orq, | ||||||||
7339 | int level, char *todo, | ||||||||
7340 | tp_name_t const *, msg_t *, int error); | ||||||||
7341 | static void outgoing_insert(nta_agent_t *sa, nta_outgoing_t *orq); | ||||||||
7342 | static void outgoing_destroy(nta_outgoing_t *orq); | ||||||||
7343 | su_inlinestatic inline int outgoing_is_queued(nta_outgoing_t const *orq); | ||||||||
7344 | su_inlinestatic inline void outgoing_queue(outgoing_queue_t *queue, | ||||||||
7345 | nta_outgoing_t *orq); | ||||||||
7346 | su_inlinestatic inline void outgoing_remove(nta_outgoing_t *orq); | ||||||||
7347 | su_inlinestatic inline void outgoing_set_timer(nta_outgoing_t *orq, uint32_t interval); | ||||||||
7348 | static void outgoing_reset_timer(nta_outgoing_t *orq); | ||||||||
7349 | static size_t outgoing_timer_dk(outgoing_queue_t *q, | ||||||||
7350 | char const *timer, | ||||||||
7351 | uint32_t now); | ||||||||
7352 | static size_t outgoing_timer_bf(outgoing_queue_t *q, | ||||||||
7353 | char const *timer, | ||||||||
7354 | uint32_t now); | ||||||||
7355 | static size_t outgoing_timer_c(outgoing_queue_t *q, | ||||||||
7356 | char const *timer, | ||||||||
7357 | uint32_t now); | ||||||||
7358 | |||||||||
7359 | static void outgoing_ack(nta_outgoing_t *orq, sip_t *sip); | ||||||||
7360 | static msg_t *outgoing_ackmsg(nta_outgoing_t *, sip_method_t, char const *, | ||||||||
7361 | tag_type_t tag, tag_value_t value, ...); | ||||||||
7362 | static void outgoing_retransmit(nta_outgoing_t *orq); | ||||||||
7363 | static void outgoing_trying(nta_outgoing_t *orq); | ||||||||
7364 | static void outgoing_timeout(nta_outgoing_t *orq, uint32_t now); | ||||||||
7365 | static int outgoing_complete(nta_outgoing_t *orq); | ||||||||
7366 | static void outgoing_terminate_invite(nta_outgoing_t *); | ||||||||
7367 | static void outgoing_remove_fork(nta_outgoing_t *orq); | ||||||||
7368 | static int outgoing_terminate(nta_outgoing_t *orq); | ||||||||
7369 | static size_t outgoing_mass_destroy(nta_agent_t *sa, outgoing_queue_t *q); | ||||||||
7370 | static void outgoing_estimate_delay(nta_outgoing_t *orq, sip_t *sip); | ||||||||
7371 | static int outgoing_duplicate(nta_outgoing_t *orq, | ||||||||
7372 | msg_t *msg, | ||||||||
7373 | sip_t *sip); | ||||||||
7374 | static int outgoing_reply(nta_outgoing_t *orq, | ||||||||
7375 | int status, char const *phrase, | ||||||||
7376 | int delayed); | ||||||||
7377 | |||||||||
7378 | static int outgoing_default_cb(nta_outgoing_magic_t *magic, | ||||||||
7379 | nta_outgoing_t *request, | ||||||||
7380 | sip_t const *sip); | ||||||||
7381 | |||||||||
7382 | |||||||||
7383 | /** Create a default outgoing transaction. | ||||||||
7384 | * | ||||||||
7385 | * The default outgoing transaction is used when agent receives responses | ||||||||
7386 | * not belonging to any transaction. | ||||||||
7387 | * | ||||||||
7388 | * @sa nta_leg_default(), nta_incoming_default(). | ||||||||
7389 | */ | ||||||||
7390 | nta_outgoing_t *nta_outgoing_default(nta_agent_t *agent, | ||||||||
7391 | nta_response_f *callback, | ||||||||
7392 | nta_outgoing_magic_t *magic) | ||||||||
7393 | { | ||||||||
7394 | nta_outgoing_t *orq; | ||||||||
7395 | |||||||||
7396 | if (agent == NULL((void*)0)) | ||||||||
7397 | return NULL((void*)0); | ||||||||
7398 | |||||||||
7399 | if (agent->sa_default_outgoing) | ||||||||
7400 | return NULL((void*)0); | ||||||||
7401 | |||||||||
7402 | orq = su_zalloc(agent->sa_home, sizeof *orq); | ||||||||
7403 | if (!orq) | ||||||||
7404 | return NULL((void*)0); | ||||||||
7405 | |||||||||
7406 | orq->orq_agent = agent; | ||||||||
7407 | orq->orq_callback = callback; | ||||||||
7408 | orq->orq_magic = magic; | ||||||||
7409 | orq->orq_method = sip_method_invalid; | ||||||||
7410 | orq->orq_method_name = "*"; | ||||||||
7411 | orq->orq_default = 1; | ||||||||
7412 | orq->orq_stateless = 1; | ||||||||
7413 | orq->orq_delay = UINT_MAX(2147483647 *2U +1U); | ||||||||
7414 | |||||||||
7415 | return agent->sa_default_outgoing = orq; | ||||||||
7416 | } | ||||||||
7417 | |||||||||
7418 | /**Create an outgoing request and client transaction belonging to the leg. | ||||||||
7419 | * | ||||||||
7420 | * Create a request message and pass the request message to an outgoing | ||||||||
7421 | * client transaction object. The request is sent to the @a route_url (if | ||||||||
7422 | * non-NULL), default proxy (if defined by NTATAG_DEFAULT_PROXY()), or to | ||||||||
7423 | * the address specified by @a request_uri. If no @a request_uri is | ||||||||
7424 | * specified, it is taken from route-set target or from the @To header. | ||||||||
7425 | * | ||||||||
7426 | * When NTA receives response to the request, it invokes the @a callback | ||||||||
7427 | * function. | ||||||||
7428 | * | ||||||||
7429 | * @param leg call leg object | ||||||||
7430 | * @param callback callback function (may be @c NULL) | ||||||||
7431 | * @param magic application context pointer | ||||||||
7432 | * @param route_url optional URL used to route transaction requests | ||||||||
7433 | * @param method method type | ||||||||
7434 | * @param name method name | ||||||||
7435 | * @param request_uri Request-URI | ||||||||
7436 | * @param tag, value, ... list of tagged arguments | ||||||||
7437 | * | ||||||||
7438 | * @return | ||||||||
7439 | * A pointer to a newly created outgoing transaction object if successful, | ||||||||
7440 | * and NULL otherwise. | ||||||||
7441 | * | ||||||||
7442 | * @note If NTATAG_STATELESS(1) tag is given and the @a callback is NULL, | ||||||||
7443 | * the transaction object is marked as destroyed from the beginning. In that | ||||||||
7444 | * case, the function may return @code (nta_outgoing_t *)-1 @endcode if the | ||||||||
7445 | * transaction is freed before returning from the function. | ||||||||
7446 | * | ||||||||
7447 | * @sa | ||||||||
7448 | * nta_outgoing_mcreate(), nta_outgoing_tcancel(), nta_outgoing_destroy(). | ||||||||
7449 | * | ||||||||
7450 | * @TAGS | ||||||||
7451 | * NTATAG_STATELESS(), NTATAG_DELAY_SENDING(), NTATAG_BRANCH_KEY(), | ||||||||
7452 | * NTATAG_ACK_BRANCH(), NTATAG_DEFAULT_PROXY(), NTATAG_PASS_100(), | ||||||||
7453 | * NTATAG_USE_TIMESTAMP(), NTATAG_USER_VIA(), TPTAG_IDENT(), NTATAG_TPORT(). All | ||||||||
7454 | * SIP tags from <sofia-sip/sip_tag.h> can be used to manipulate the request message. | ||||||||
7455 | * SIP tags after SIPTAG_END() are ignored, however. | ||||||||
7456 | */ | ||||||||
7457 | nta_outgoing_t *nta_outgoing_tcreate(nta_leg_t *leg, | ||||||||
7458 | nta_response_f *callback, | ||||||||
7459 | nta_outgoing_magic_t *magic, | ||||||||
7460 | url_string_t const *route_url, | ||||||||
7461 | sip_method_t method, | ||||||||
7462 | char const *name, | ||||||||
7463 | url_string_t const *request_uri, | ||||||||
7464 | tag_type_t tag, tag_value_t value, ...) | ||||||||
7465 | { | ||||||||
7466 | nta_agent_t *agent; | ||||||||
7467 | msg_t *msg; | ||||||||
7468 | sip_t *sip; | ||||||||
7469 | nta_outgoing_t *orq = NULL((void*)0); | ||||||||
7470 | ta_list ta; | ||||||||
7471 | tagi_t const *tagi; | ||||||||
7472 | |||||||||
7473 | if (leg == NULL((void*)0)) | ||||||||
7474 | return NULL((void*)0); | ||||||||
7475 | |||||||||
7476 | agent = leg->leg_agent; | ||||||||
7477 | msg = nta_msg_create(agent, 0); | ||||||||
7478 | sip = sip_object(msg); | ||||||||
7479 | |||||||||
7480 | if (route_url == NULL((void*)0)) | ||||||||
7481 | route_url = (url_string_t *)agent->sa_default_proxy; | ||||||||
7482 | |||||||||
7483 | 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); | ||||||||
7484 | |||||||||
7485 | tagi = ta_args(ta)(ta).tl; | ||||||||
7486 | |||||||||
7487 | if (sip_add_tagis(msg, sip, &tagi) < 0) { | ||||||||
7488 | if (tagi && tagi->t_tag) { | ||||||||
7489 | tag_type_t t = tagi->t_tag; | ||||||||
7490 | 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__ , 7491, "%s(): bad tag %s::%s\n", __func__, t->tt_ns ? t-> tt_ns : "", t->tt_name ? t->tt_name : "")) : (void)0) | ||||||||
7491 | 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__ , 7491, "%s(): bad tag %s::%s\n", __func__, t->tt_ns ? t-> tt_ns : "", t->tt_name ? t->tt_name : "")) : (void)0); | ||||||||
7492 | } | ||||||||
7493 | } | ||||||||
7494 | else if (route_url == NULL((void*)0) && leg->leg_route && | ||||||||
7495 | leg->leg_loose_route && | ||||||||
7496 | !(route_url = (url_string_t *)leg->leg_route->r_url)) | ||||||||
7497 | ; | ||||||||
7498 | else if (nta_msg_request_complete(msg, leg, method, name, request_uri) < 0) | ||||||||
7499 | ; | ||||||||
7500 | else | ||||||||
7501 | orq = outgoing_create(agent, callback, magic, route_url, NULL((void*)0), msg, | ||||||||
7502 | ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta). tl[1].t_value); | ||||||||
7503 | |||||||||
7504 | 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)); | ||||||||
7505 | |||||||||
7506 | if (!orq) | ||||||||
7507 | msg_destroy(msg); | ||||||||
7508 | |||||||||
7509 | return orq; | ||||||||
7510 | } | ||||||||
7511 | |||||||||
7512 | /**Create an outgoing client transaction. | ||||||||
7513 | * | ||||||||
7514 | * Create an outgoing transaction object. The request message is passed to | ||||||||
7515 | * the transaction object, which sends the request to the network. The | ||||||||
7516 | * request is sent to the @a route_url (if non-NULL), default proxy (if | ||||||||
7517 | * defined by NTATAG_DEFAULT_PROXY()), or to the address specified by @a | ||||||||
7518 | * request_uri. If no @a request_uri is specified, it is taken from | ||||||||
7519 | * route-set target or from the @To header. | ||||||||
7520 | * | ||||||||
7521 | * When NTA receives response to the request, it invokes the @a callback | ||||||||
7522 | * function. | ||||||||
7523 | * | ||||||||
7524 | * @param agent NTA agent object | ||||||||
7525 | * @param callback callback function (may be @c NULL) | ||||||||
7526 | * @param magic application context pointer | ||||||||
7527 | * @param route_url optional URL used to route transaction requests | ||||||||
7528 | * @param msg request message | ||||||||
7529 | * @param tag, value, ... tagged parameter list | ||||||||
7530 | * | ||||||||
7531 | * @return | ||||||||
7532 | * Returns a pointer to newly created outgoing transaction object if | ||||||||
7533 | * successful, and NULL otherwise. | ||||||||
7534 | * | ||||||||
7535 | * @note The caller is responsible for destroying the request message @a msg | ||||||||
7536 | * upon failure. | ||||||||
7537 | * | ||||||||
7538 | * @note If NTATAG_STATELESS(1) tag is given and the @a callback is NULL, | ||||||||
7539 | * the transaction object is marked as destroyed from the beginning. In that | ||||||||
7540 | * case, the function may return @code (nta_outgoing_t *)-1 @endcode if the | ||||||||
7541 | * transaction is freed before returning from the function. | ||||||||
7542 | * | ||||||||
7543 | * @sa | ||||||||
7544 | * nta_outgoing_tcreate(), nta_outgoing_tcancel(), nta_outgoing_destroy(). | ||||||||
7545 | * | ||||||||
7546 | * @TAGS | ||||||||
7547 | * NTATAG_STATELESS(), NTATAG_DELAY_SENDING(), NTATAG_BRANCH_KEY(), | ||||||||
7548 | * NTATAG_ACK_BRANCH(), NTATAG_DEFAULT_PROXY(), NTATAG_PASS_100(), | ||||||||
7549 | * NTATAG_USE_TIMESTAMP(), NTATAG_USER_VIA(), TPTAG_IDENT(), NTATAG_TPORT(). All | ||||||||
7550 | * SIP tags from <sofia-sip/sip_tag.h> can be used to manipulate the request message. | ||||||||
7551 | * SIP tags after SIPTAG_END() are ignored, however. | ||||||||
7552 | */ | ||||||||
7553 | nta_outgoing_t *nta_outgoing_mcreate(nta_agent_t *agent, | ||||||||
7554 | nta_response_f *callback, | ||||||||
7555 | nta_outgoing_magic_t *magic, | ||||||||
7556 | url_string_t const *route_url, | ||||||||
7557 | msg_t *msg, | ||||||||
7558 | tag_type_t tag, tag_value_t value, ...) | ||||||||
7559 | { | ||||||||
7560 | nta_outgoing_t *orq = NULL((void*)0); | ||||||||
7561 | int cleanup = 0; | ||||||||
7562 | |||||||||
7563 | if (msg == NONE((void *)-1)) | ||||||||
7564 | msg = nta_msg_create(agent, 0), cleanup = 1; | ||||||||
7565 | |||||||||
7566 | if (msg && agent) { | ||||||||
7567 | ta_list ta; | ||||||||
7568 | 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); | ||||||||
7569 | 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) | ||||||||
7570 | orq = outgoing_create(agent, callback, magic, route_url, NULL((void*)0), msg, | ||||||||
7571 | ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta). tl[1].t_value); | ||||||||
7572 | 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)); | ||||||||
7573 | } | ||||||||
7574 | |||||||||
7575 | if (!orq && cleanup) | ||||||||
7576 | msg_destroy(msg); | ||||||||
7577 | |||||||||
7578 | return orq; | ||||||||
7579 | } | ||||||||
7580 | |||||||||
7581 | /** Cancel the request. */ | ||||||||
7582 | int nta_outgoing_cancel(nta_outgoing_t *orq) | ||||||||
7583 | { | ||||||||
7584 | nta_outgoing_t *cancel = | ||||||||
7585 | nta_outgoing_tcancel(orq, NULL((void*)0), NULL((void*)0), TAG_NULL()(tag_type_t)0, (tag_value_t)0); | ||||||||
7586 | |||||||||
7587 | return (cancel != NULL((void*)0)) - 1; | ||||||||
7588 | } | ||||||||
7589 | |||||||||
7590 | /** Cancel the request. | ||||||||
7591 | * | ||||||||
7592 | * Initiate a cancel transaction for client transaction @a orq. | ||||||||
7593 | * | ||||||||
7594 | * @param orq client transaction to cancel | ||||||||
7595 | * @param callback callback function (may be @c NULL) | ||||||||
7596 | * @param magic application context pointer | ||||||||
7597 | * @param tag, value, ... list of extra arguments | ||||||||
7598 | * | ||||||||
7599 | * @note The function may return @code (nta_outgoing_t *)-1 @endcode (NONE) | ||||||||
7600 | * if callback is NULL. | ||||||||
7601 | * | ||||||||
7602 | * @TAGS | ||||||||
7603 | * NTATAG_CANCEL_2534(), NTATAG_CANCEL_408() and all the tags that are | ||||||||
7604 | * accepted by nta_outgoing_tcreate(). | ||||||||
7605 | * | ||||||||
7606 | * If NTATAG_CANCEL_408(1) or NTATAG_CANCEL_2543(1) is given, the stack | ||||||||
7607 | * generates a 487 response to the request internally. If | ||||||||
7608 | * NTATAG_CANCEL_408(1) is given, no CANCEL request is actually sent. | ||||||||
7609 | * | ||||||||
7610 | * @note | ||||||||
7611 | * nta_outgoing_tcancel() refuses to send a CANCEL request for non-INVITE | ||||||||
7612 | * requests. | ||||||||
7613 | */ | ||||||||
7614 | nta_outgoing_t *nta_outgoing_tcancel(nta_outgoing_t *orq, | ||||||||
7615 | nta_response_f *callback, | ||||||||
7616 | nta_outgoing_magic_t *magic, | ||||||||
7617 | tag_type_t tag, tag_value_t value, ...) | ||||||||
7618 | { | ||||||||
7619 | msg_t *msg; | ||||||||
7620 | int cancel_2543, cancel_408; | ||||||||
7621 | ta_list ta; | ||||||||
7622 | int delay_sending; | ||||||||
7623 | |||||||||
7624 | if (orq == NULL((void*)0) || orq == NONE((void *)-1)) | ||||||||
7625 | return NULL((void*)0); | ||||||||
7626 | |||||||||
7627 | if (orq->orq_destroyed) { | ||||||||
7628 | 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__ , 7628, "%s: trying to cancel destroyed request\n", __func__) ) : (void)0); | ||||||||
7629 | return NULL((void*)0); | ||||||||
7630 | } | ||||||||
7631 | if (orq->orq_method != sip_method_invite) { | ||||||||
7632 | 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__ , 7632, "%s: trying to cancel non-INVITE request\n", __func__ )) : (void)0); | ||||||||
7633 | return NULL((void*)0); | ||||||||
7634 | } | ||||||||
7635 | |||||||||
7636 | if (orq->orq_forking) | ||||||||
7637 | orq = orq->orq_forking; | ||||||||
7638 | |||||||||
7639 | if (orq->orq_status >= 200 | ||||||||
7640 | /* && orq->orq_method != sip_method_invite ... !multicast */) { | ||||||||
7641 | 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__ , 7641, "%s: trying to cancel completed request\n", __func__) ) : (void)0); | ||||||||
7642 | return NULL((void*)0); | ||||||||
7643 | } | ||||||||
7644 | if (orq->orq_canceled) { | ||||||||
7645 | 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__ , 7645, "%s: trying to cancel cancelled request\n", __func__) ) : (void)0); | ||||||||
7646 | return NULL((void*)0); | ||||||||
7647 | } | ||||||||
7648 | orq->orq_canceled = 1; | ||||||||
7649 | |||||||||
7650 | #if HAVE_SOFIA_SRESOLV1 | ||||||||
7651 | if (!orq->orq_resolved) { | ||||||||
7652 | outgoing_destroy_resolver(orq); | ||||||||
7653 | outgoing_reply(orq, SIP_487_REQUEST_CANCELLED487, sip_487_Request_terminated, 1); | ||||||||
7654 | return NULL((void*)0); /* XXX - Does anyone care about reply? */ | ||||||||
7655 | } | ||||||||
7656 | #endif | ||||||||
7657 | |||||||||
7658 | cancel_408 = 0; /* Don't really CANCEL, this is timeout. */ | ||||||||
7659 | cancel_2543 = orq->orq_agent->sa_cancel_2543; | ||||||||
7660 | /* CANCEL may be sent only after a provisional response has been received. */ | ||||||||
7661 | delay_sending = orq->orq_status < 100; | ||||||||
7662 | |||||||||
7663 | 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); | ||||||||
7664 | |||||||||
7665 | tl_gets(ta_args(ta)(ta).tl, | ||||||||
7666 | NTATAG_CANCEL_408_REF(cancel_408)ntatag_cancel_408_ref, tag_bool_vr(&(cancel_408)), | ||||||||
7667 | NTATAG_CANCEL_2543_REF(cancel_2543)ntatag_cancel_2543_ref, tag_bool_vr(&(cancel_2543)), | ||||||||
7668 | TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
7669 | |||||||||
7670 | if (!cancel_408) | ||||||||
7671 | 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); | ||||||||
7672 | else | ||||||||
7673 | msg = NULL((void*)0); | ||||||||
7674 | |||||||||
7675 | 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)); | ||||||||
7676 | |||||||||
7677 | if ((cancel_2543 || cancel_408) && !orq->orq_stateless) | ||||||||
7678 | outgoing_reply(orq, SIP_487_REQUEST_CANCELLED487, sip_487_Request_terminated, 1); | ||||||||
7679 | |||||||||
7680 | if (msg) { | ||||||||
7681 | nta_outgoing_t *cancel; | ||||||||
7682 | if (cancel_2543) /* Follow RFC 2543 semantics for CANCEL */ | ||||||||
7683 | delay_sending = 0; | ||||||||
7684 | |||||||||
7685 | cancel = outgoing_create(orq->orq_agent, callback, magic, | ||||||||
7686 | NULL((void*)0), orq->orq_tpn, msg, | ||||||||
7687 | NTATAG_BRANCH_KEY(orq->orq_branch)ntatag_branch_key, tag_str_v((orq->orq_branch)), | ||||||||
7688 | NTATAG_DELAY_SENDING(delay_sending)ntatag_delay_sending, tag_bool_v((delay_sending)), | ||||||||
7689 | NTATAG_USER_VIA(1)ntatag_user_via, tag_bool_v((1)), | ||||||||
7690 | TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
7691 | |||||||||
7692 | if (delay_sending) | ||||||||
7693 | orq->orq_cancel = cancel; | ||||||||
7694 | |||||||||
7695 | if (cancel) { | ||||||||
7696 | if (!delay_sending) | ||||||||
7697 | outgoing_complete(orq); | ||||||||
7698 | return cancel; | ||||||||
7699 | } | ||||||||
7700 | |||||||||
7701 | msg_destroy(msg); | ||||||||
7702 | } | ||||||||
7703 | |||||||||
7704 | return NULL((void*)0); | ||||||||
7705 | } | ||||||||
7706 | |||||||||
7707 | /**Bind callback and application context to a client transaction. | ||||||||
7708 | * | ||||||||
7709 | * @param orq outgoing client transaction | ||||||||
7710 | * @param callback callback function (may be NULL) | ||||||||
7711 | * @param magic application context pointer | ||||||||
7712 | * (given as argument to @a callback) | ||||||||
7713 | * | ||||||||
7714 | * @NEW_1_12_9 | ||||||||
7715 | */ | ||||||||
7716 | int | ||||||||
7717 | nta_outgoing_bind(nta_outgoing_t *orq, | ||||||||
7718 | nta_response_f *callback, | ||||||||
7719 | nta_outgoing_magic_t *magic) | ||||||||
7720 | { | ||||||||
7721 | if (orq && !orq->orq_destroyed) { | ||||||||
7722 | if (callback == NULL((void*)0)) | ||||||||
7723 | callback = outgoing_default_cb; | ||||||||
7724 | orq->orq_callback = callback; | ||||||||
7725 | orq->orq_magic = magic; | ||||||||
7726 | return 0; | ||||||||
7727 | } | ||||||||
7728 | return -1; | ||||||||
7729 | } | ||||||||
7730 | |||||||||
7731 | /**Get application context bound to a client transaction. | ||||||||
7732 | * | ||||||||
7733 | * @param orq outgoing client transaction | ||||||||
7734 | * @param callback callback function (may be NULL) | ||||||||
7735 | * | ||||||||
7736 | * Return the application context bound to a client transaction. If the @a | ||||||||
7737 | * callback function pointer is given, return application context only if | ||||||||
7738 | * the callback matches with the callback bound to the client transaction. | ||||||||
7739 | * | ||||||||
7740 | * @NEW_1_12_11 | ||||||||
7741 | */ | ||||||||
7742 | nta_outgoing_magic_t * | ||||||||
7743 | nta_outgoing_magic(nta_outgoing_t const *orq, | ||||||||
7744 | nta_response_f *callback) | ||||||||
7745 | { | ||||||||
7746 | if (orq && (callback == NULL((void*)0) || callback == orq->orq_callback)) | ||||||||
7747 | return orq->orq_magic; | ||||||||
7748 | else | ||||||||
7749 | return NULL((void*)0); | ||||||||
7750 | } | ||||||||
7751 | |||||||||
7752 | |||||||||
7753 | /** | ||||||||
7754 | * Destroy a request object. | ||||||||
7755 | * | ||||||||
7756 | * @note | ||||||||
7757 | * This function does not actually free the object, but marks it as | ||||||||
7758 | * disposable. The object is freed after a timeout. | ||||||||
7759 | */ | ||||||||
7760 | void nta_outgoing_destroy(nta_outgoing_t *orq) | ||||||||
7761 | { | ||||||||
7762 | if (orq == NULL((void*)0) || orq == NONE((void *)-1)) | ||||||||
7763 | return; | ||||||||
7764 | |||||||||
7765 | if (orq->orq_destroyed) { | ||||||||
7766 | 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__ , 7767, "%s(%p): %s\n", "nta_outgoing_destroy", (void *)orq, "already destroyed" )) : (void)0) | ||||||||
7767 | "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__ , 7767, "%s(%p): %s\n", "nta_outgoing_destroy", (void *)orq, "already destroyed" )) : (void)0); | ||||||||
7768 | return; | ||||||||
7769 | } | ||||||||
7770 | |||||||||
7771 | outgoing_destroy(orq); | ||||||||
7772 | } | ||||||||
7773 | |||||||||
7774 | /** Return the request URI */ | ||||||||
7775 | url_t const *nta_outgoing_request_uri(nta_outgoing_t const *orq) | ||||||||
7776 | { | ||||||||
7777 | return orq != NULL((void*)0) && orq != NONE((void *)-1) ? orq->orq_url : NULL((void*)0); | ||||||||
7778 | } | ||||||||
7779 | |||||||||
7780 | /** Return the URI used to route the request */ | ||||||||
7781 | url_t const *nta_outgoing_route_uri(nta_outgoing_t const *orq) | ||||||||
7782 | { | ||||||||
7783 | return orq != NULL((void*)0) && orq != NONE((void *)-1) ? orq->orq_route : NULL((void*)0); | ||||||||
7784 | } | ||||||||
7785 | |||||||||
7786 | /** Return method of the client transaction */ | ||||||||
7787 | sip_method_t nta_outgoing_method(nta_outgoing_t const *orq) | ||||||||
7788 | { | ||||||||
7789 | return orq != NULL((void*)0) && orq != NONE((void *)-1) ? orq->orq_method : sip_method_invalid; | ||||||||
7790 | } | ||||||||
7791 | |||||||||
7792 | /** Return method name of the client transaction */ | ||||||||
7793 | char const *nta_outgoing_method_name(nta_outgoing_t const *orq) | ||||||||
7794 | { | ||||||||
7795 | return orq != NULL((void*)0) && orq != NONE((void *)-1) ? orq->orq_method_name : NULL((void*)0); | ||||||||
7796 | } | ||||||||
7797 | |||||||||
7798 | /** Get sequence number of a client transaction. | ||||||||
7799 | */ | ||||||||
7800 | uint32_t nta_outgoing_cseq(nta_outgoing_t const *orq) | ||||||||
7801 | { | ||||||||
7802 | return orq != NULL((void*)0) && orq != NONE((void *)-1) && orq->orq_cseq | ||||||||
7803 | ? orq->orq_cseq->cs_seq : 0; | ||||||||
7804 | } | ||||||||
7805 | |||||||||
7806 | /** | ||||||||
7807 | * Get the status code of a client transaction. | ||||||||
7808 | */ | ||||||||
7809 | int nta_outgoing_status(nta_outgoing_t const *orq) | ||||||||
7810 | { | ||||||||
7811 | /* Return 500 Internal server error for invalid handles. */ | ||||||||
7812 | return orq != NULL((void*)0) && orq != NONE((void *)-1) ? orq->orq_status : 500; | ||||||||
7813 | } | ||||||||
7814 | |||||||||
7815 | /** Get the RTT delay measured using @Timestamp header. */ | ||||||||
7816 | unsigned nta_outgoing_delay(nta_outgoing_t const *orq) | ||||||||
7817 | { | ||||||||
7818 | return orq != NULL((void*)0) && orq != NONE((void *)-1) ? orq->orq_delay : UINT_MAX(2147483647 *2U +1U); | ||||||||
7819 | } | ||||||||
7820 | |||||||||
7821 | /** Get the branch parameter. @NEW_1_12_7. */ | ||||||||
7822 | char const *nta_outgoing_branch(nta_outgoing_t const *orq) | ||||||||
7823 | { | ||||||||
7824 | return orq != NULL((void*)0) && orq != NONE((void *)-1) && orq->orq_branch | ||||||||
7825 | ? orq->orq_branch + strlen("branch=") | ||||||||
7826 | : NULL((void*)0); | ||||||||
7827 | } | ||||||||
7828 | |||||||||
7829 | /**Get reference to response message. | ||||||||
7830 | * | ||||||||
7831 | * Retrieve the latest incoming response message to the outgoing | ||||||||
7832 | * transaction. Note that the message is not copied, but a new reference to | ||||||||
7833 | * it is created instead. | ||||||||
7834 | * | ||||||||
7835 | * @param orq outgoing transaction handle | ||||||||
7836 | * | ||||||||
7837 | * @retval | ||||||||
7838 | * A pointer to response message is returned, or NULL if no response message | ||||||||
7839 | * has been received. | ||||||||
7840 | */ | ||||||||
7841 | msg_t *nta_outgoing_getresponse(nta_outgoing_t *orq) | ||||||||
7842 | { | ||||||||
7843 | if (orq != NULL((void*)0) && orq != NONE((void *)-1)) | ||||||||
7844 | return msg_ref_create(orq->orq_response); | ||||||||
7845 | else | ||||||||
7846 | return NULL((void*)0); | ||||||||
7847 | } | ||||||||
7848 | |||||||||
7849 | /**Get request message. | ||||||||
7850 | * | ||||||||
7851 | * Retrieves the request message sent to the network. Note that the request | ||||||||
7852 | * message is @b not copied, but a new reference to it is created. | ||||||||
7853 | * | ||||||||
7854 | * @retval | ||||||||
7855 | * A pointer to the request message is returned, or NULL if an error | ||||||||
7856 | * occurred. | ||||||||
7857 | */ | ||||||||
7858 | msg_t *nta_outgoing_getrequest(nta_outgoing_t *orq) | ||||||||
7859 | { | ||||||||
7860 | if (orq != NULL((void*)0) && orq != NONE((void *)-1)) | ||||||||
7861 | return msg_ref_create(orq->orq_request); | ||||||||
7862 | else | ||||||||
7863 | return NULL((void*)0); | ||||||||
7864 | } | ||||||||
7865 | |||||||||
7866 | /**Create an outgoing request. | ||||||||
7867 | * | ||||||||
7868 | * Create an outgoing transaction object and send the request to the | ||||||||
7869 | * network. The request is sent to the @a route_url (if non-NULL), default | ||||||||
7870 | * proxy (if defined by NTATAG_DEFAULT_PROXY()), or to the address specified | ||||||||
7871 | * by @a sip->sip_request->rq_url. | ||||||||
7872 | * | ||||||||
7873 | * When NTA receives response to the request, it invokes the @a callback | ||||||||
7874 | * function. | ||||||||
7875 | * | ||||||||
7876 | * @param agent nta agent object | ||||||||
7877 | * @param callback callback function (may be @c NULL) | ||||||||
7878 | * @param magic application context pointer | ||||||||
7879 | * @param route_url optional URL used to route transaction requests | ||||||||
7880 | * @param msg request message | ||||||||
7881 | * @param tpn (optional) transport name | ||||||||
7882 | * @param msg request message to | ||||||||
7883 | * @param tag, value, ... tagged arguments | ||||||||
7884 | * | ||||||||
7885 | * @return | ||||||||
7886 | * Returns a pointer to newly created outgoing transaction object if | ||||||||
7887 | * successful, and NULL otherwise. | ||||||||
7888 | * | ||||||||
7889 | * @note If NTATAG_STATELESS(1) tag is given and the @a callback is NULL, | ||||||||
7890 | * the transaction object is marked as destroyed from the beginning. In that | ||||||||
7891 | * case, the function may return @code (nta_outgoing_t *)-1 @endcode if the | ||||||||
7892 | * transaction is freed before returning from the function. | ||||||||
7893 | * | ||||||||
7894 | * @TAG NTATAG_TPORT must point to an existing transport object for | ||||||||
7895 | * 'agent' (the passed tport is otherwise ignored). | ||||||||
7896 | * | ||||||||
7897 | * @sa | ||||||||
7898 | * nta_outgoing_tcreate(), nta_outgoing_tcancel(), nta_outgoing_destroy(). | ||||||||
7899 | */ | ||||||||
7900 | nta_outgoing_t *outgoing_create(nta_agent_t *agent, | ||||||||
7901 | nta_response_f *callback, | ||||||||
7902 | nta_outgoing_magic_t *magic, | ||||||||
7903 | url_string_t const *route_url, | ||||||||
7904 | tp_name_t const *tpn, | ||||||||
7905 | msg_t *msg, | ||||||||
7906 | tag_type_t tag, tag_value_t value, ...) | ||||||||
7907 | { | ||||||||
7908 | nta_outgoing_t *orq; | ||||||||
7909 | sip_t *sip; | ||||||||
7910 | su_home_t *home; | ||||||||
7911 | char const *comp = NONE((void *)-1); | ||||||||
7912 | char const *branch = NONE((void *)-1); | ||||||||
7913 | char const *ack_branch = NONE((void *)-1); | ||||||||
7914 | char const *tp_ident; | ||||||||
7915 | int delay_sending = 0, sigcomp_zap = 0; | ||||||||
7916 | int pass_100 = agent->sa_pass_100, use_timestamp = agent->sa_timestamp; | ||||||||
7917 | enum nta_res_order_e res_order = agent->sa_res_order; | ||||||||
7918 | struct sigcomp_compartment *cc = NULL((void*)0); | ||||||||
7919 | ta_list ta; | ||||||||
7920 | char const *scheme = NULL((void*)0); | ||||||||
7921 | char const *port = NULL((void*)0); | ||||||||
7922 | int invalid, resolved = 0, stateless = 0, user_via = agent->sa_user_via; | ||||||||
7923 | int invite_100rel = agent->sa_invite_100rel; | ||||||||
7924 | int explicit_transport = 1; | ||||||||
7925 | int call_tls_orq_connect_timeout_is_set = 0; | ||||||||
7926 | int call_tls_orq_connect_timeout = 0; | ||||||||
7927 | |||||||||
7928 | tagi_t const *t; | ||||||||
7929 | tport_t *override_tport = NULL((void*)0); | ||||||||
7930 | |||||||||
7931 | if (!agent->sa_tport_ip6) | ||||||||
7932 | res_order = nta_res_ip4_only; | ||||||||
7933 | else if (!agent->sa_tport_ip4) | ||||||||
7934 | res_order = nta_res_ip6_only; | ||||||||
7935 | |||||||||
7936 | if (!callback) | ||||||||
7937 | callback = outgoing_default_cb; | ||||||||
7938 | if (!route_url) | ||||||||
7939 | route_url = (url_string_t *)agent->sa_default_proxy; | ||||||||
7940 | |||||||||
7941 | sip = sip_object(msg); | ||||||||
7942 | home = msg_home(msg)((su_home_t*)(msg)); | ||||||||
7943 | |||||||||
7944 | #ifdef HAVE_ZLIB_COMPRESS1 | ||||||||
7945 | sip_content_encoding_Xflate(msg, sip_object(msg), 0, 1); | ||||||||
7946 | #endif | ||||||||
7947 | |||||||||
7948 | if (!sip->sip_request || sip_complete_message(msg) < 0) { | ||||||||
7949 | 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__ , 7949, "nta: outgoing_create: incomplete request\n" "%s", "" )) : (void)0); | ||||||||
7950 | return NULL((void*)0); | ||||||||
7951 | } | ||||||||
7952 | |||||||||
7953 | if (!route_url && !tpn && sip->sip_route && | ||||||||
7954 | sip->sip_route->r_url->url_params && | ||||||||
7955 | url_param(sip->sip_route->r_url->url_params, "lr", NULL((void*)0), 0)) | ||||||||
7956 | route_url = (url_string_t *)sip->sip_route->r_url; | ||||||||
7957 | |||||||||
7958 | if (!(orq = su_zalloc(agent->sa_home, sizeof(*orq)))) | ||||||||
7959 | return NULL((void*)0); | ||||||||
7960 | |||||||||
7961 | tp_ident = tpn ? tpn->tpn_ident : NULL((void*)0); | ||||||||
7962 | |||||||||
7963 | 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); | ||||||||
7964 | |||||||||
7965 | /* tl_gets() is a bit too slow here... */ | ||||||||
7966 | for (t = ta_args(ta)(ta).tl; t; t = tl_next(t)) { | ||||||||
7967 | tag_type_t tt = t->t_tag; | ||||||||
7968 | |||||||||
7969 | if (ntatag_stateless == tt) | ||||||||
7970 | stateless = t->t_value != 0; | ||||||||
7971 | else if (ntatag_delay_sending == tt) | ||||||||
7972 | delay_sending = t->t_value != 0; | ||||||||
7973 | else if (ntatag_branch_key == tt) | ||||||||
7974 | branch = (void *)t->t_value; | ||||||||
7975 | else if (ntatag_pass_100 == tt) | ||||||||
7976 | pass_100 = t->t_value != 0; | ||||||||
7977 | else if (ntatag_use_timestamp == tt) | ||||||||
7978 | use_timestamp = t->t_value != 0; | ||||||||
7979 | else if (ntatag_user_via == tt) | ||||||||
7980 | user_via = t->t_value != 0; | ||||||||
7981 | else if (ntatag_ack_branch == tt) | ||||||||
7982 | ack_branch = (void *)t->t_value; | ||||||||
7983 | else if (ntatag_default_proxy == tt) | ||||||||
7984 | route_url = (void *)t->t_value; | ||||||||
7985 | else if (tptag_ident == tt) | ||||||||
7986 | tp_ident = (void *)t->t_value; | ||||||||
7987 | else if (ntatag_comp == tt) | ||||||||
7988 | comp = (char const *)t->t_value; | ||||||||
7989 | else if (ntatag_sigcomp_close == tt) | ||||||||
7990 | sigcomp_zap = t->t_value != 0; | ||||||||
7991 | else if (tptag_compartment == tt) | ||||||||
7992 | cc = (void *)t->t_value; | ||||||||
7993 | else if (ntatag_tport == tt) { | ||||||||
7994 | override_tport = (tport_t *)t->t_value; | ||||||||
7995 | } | ||||||||
7996 | else if (ntatag_rel100 == tt) { | ||||||||
7997 | invite_100rel = t->t_value != 0; | ||||||||
7998 | } | ||||||||
7999 | else if (ntatag_tls_orq_connect_timeout == tt) { | ||||||||
8000 | call_tls_orq_connect_timeout_is_set = 1; | ||||||||
8001 | call_tls_orq_connect_timeout = t->t_value; | ||||||||
8002 | if (call_tls_orq_connect_timeout > NTA_TIME_MAX) call_tls_orq_connect_timeout = NTA_TIME_MAX; | ||||||||
8003 | } | ||||||||
8004 | } | ||||||||
8005 | |||||||||
8006 | orq->orq_agent = agent; | ||||||||
8007 | orq->orq_callback = callback; | ||||||||
8008 | orq->orq_magic = magic; | ||||||||
8009 | orq->orq_method = sip->sip_request->rq_method; | ||||||||
8010 | orq->orq_method_name = sip->sip_request->rq_method_name; | ||||||||
8011 | orq->orq_cseq = sip->sip_cseq; | ||||||||
8012 | orq->orq_to = sip->sip_to; | ||||||||
8013 | orq->orq_from = sip->sip_from; | ||||||||
8014 | orq->orq_call_id = sip->sip_call_id; | ||||||||
8015 | orq->orq_tags = tl_afilter(home, tport_tags, ta_args(ta)(ta).tl); | ||||||||
8016 | orq->orq_delayed = delay_sending != 0; | ||||||||
8017 | orq->orq_pass_100 = pass_100 != 0; | ||||||||
8018 | orq->orq_sigcomp_zap = sigcomp_zap; | ||||||||
8019 | orq->orq_sigcomp_new = comp != NONE((void *)-1) && comp != NULL((void*)0); | ||||||||
8020 | orq->orq_timestamp = use_timestamp; | ||||||||
8021 | orq->orq_delay = UINT_MAX(2147483647 *2U +1U); | ||||||||
8022 | orq->orq_stateless = stateless != 0; | ||||||||
8023 | orq->orq_user_via = user_via != 0 && sip->sip_via; | ||||||||
8024 | orq->orq_100rel = invite_100rel; | ||||||||
8025 | orq->orq_uas = !stateless && agent->sa_is_a_uas; | ||||||||
8026 | orq->orq_call_tls_connect_timeout_is_set = call_tls_orq_connect_timeout_is_set; | ||||||||
8027 | orq->orq_call_tls_connect_timeout = (call_tls_orq_connect_timeout > 0) ? call_tls_orq_connect_timeout : 0; | ||||||||
8028 | |||||||||
8029 | if (cc) | ||||||||
8030 | orq->orq_cc = nta_compartment_ref(cc); | ||||||||
8031 | |||||||||
8032 | /* Add supported features */ | ||||||||
8033 | outgoing_features(agent, orq, msg, sip, ta_args(ta)(ta).tl); | ||||||||
8034 | |||||||||
8035 | 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)); | ||||||||
8036 | |||||||||
8037 | /* select the tport to use for the outgoing message */ | ||||||||
8038 | if (override_tport) { | ||||||||
8039 | /* note: no ref taken to the tport as its only used once here */ | ||||||||
8040 | if (tport_is_secondary(override_tport)) { | ||||||||
8041 | tpn = tport_name(override_tport); | ||||||||
8042 | orq->orq_user_tport = 1; | ||||||||
8043 | } | ||||||||
8044 | } | ||||||||
8045 | |||||||||
8046 | if (tpn) { | ||||||||
8047 | /* CANCEL or ACK to [3456]XX */ | ||||||||
8048 | invalid = tport_name_dup(home, orq->orq_tpn, tpn); | ||||||||
8049 | #if 0 //HAVE_SOFIA_SRESOLV | ||||||||
8050 | /* We send ACK or CANCEL only if original request was really sent */ | ||||||||
8051 | assert(tport_name_is_resolved(orq->orq_tpn))((void) sizeof ((tport_name_is_resolved(orq->orq_tpn)) ? 1 : 0), __extension__ ({ if (tport_name_is_resolved(orq->orq_tpn )) ; else __assert_fail ("tport_name_is_resolved(orq->orq_tpn)" , "nta.c", 8051, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
8052 | #endif | ||||||||
8053 | resolved = tport_name_is_resolved(orq->orq_tpn); | ||||||||
8054 | orq->orq_url = url_hdup(home, sip->sip_request->rq_url); | ||||||||
8055 | } | ||||||||
8056 | else if (route_url && !orq->orq_user_tport) { | ||||||||
8057 | invalid = nta_tpn_by_url(home, orq->orq_tpn, &scheme, &port, route_url); | ||||||||
8058 | if (invalid >= 0) { | ||||||||
8059 | explicit_transport = invalid > 0; | ||||||||
8060 | if (override_tport) { /* Use transport protocol name from transport */ | ||||||||
8061 | if (strcmp(orq->orq_tpn->tpn_proto, "*") == 0) | ||||||||
8062 | orq->orq_tpn->tpn_proto = tport_name(override_tport)->tpn_proto; | ||||||||
8063 | } | ||||||||
8064 | |||||||||
8065 | resolved = tport_name_is_resolved(orq->orq_tpn); | ||||||||
8066 | orq->orq_url = url_hdup(home, sip->sip_request->rq_url); | ||||||||
8067 | if (route_url != (url_string_t *)agent->sa_default_proxy) | ||||||||
8068 | orq->orq_route = url_hdup(home, route_url->us_url); | ||||||||
8069 | } | ||||||||
8070 | } | ||||||||
8071 | else { | ||||||||
8072 | invalid = nta_tpn_by_url(home, orq->orq_tpn, &scheme, &port, | ||||||||
8073 | (url_string_t *)sip->sip_request->rq_url); | ||||||||
8074 | if (invalid >= 0) { | ||||||||
8075 | explicit_transport = invalid > 0; | ||||||||
8076 | resolved = tport_name_is_resolved(orq->orq_tpn); | ||||||||
8077 | 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); | ||||||||
8078 | } | ||||||||
8079 | orq->orq_url = url_hdup(home, sip->sip_request->rq_url); | ||||||||
8080 | } | ||||||||
8081 | |||||||||
8082 | if (!override_tport) | ||||||||
8083 | orq->orq_tpn->tpn_ident = tp_ident; | ||||||||
8084 | else | ||||||||
8085 | orq->orq_tpn->tpn_ident = tport_name(override_tport)->tpn_ident; | ||||||||
8086 | |||||||||
8087 | if (comp == NULL((void*)0)) | ||||||||
8088 | orq->orq_tpn->tpn_comp = comp; | ||||||||
8089 | |||||||||
8090 | if (orq->orq_user_via && su_strmatch(orq->orq_tpn->tpn_proto, "*")) { | ||||||||
8091 | char const *proto = sip_via_transport(sip->sip_via); | ||||||||
8092 | if (proto) orq->orq_tpn->tpn_proto = proto; | ||||||||
8093 | } | ||||||||
8094 | |||||||||
8095 | if (branch && branch != NONE((void *)-1)) { | ||||||||
8096 | if (su_casenmatch(branch, "branch=", 7)) | ||||||||
8097 | branch = su_strdup(home, branch); | ||||||||
8098 | else | ||||||||
8099 | branch = su_sprintf(home, "branch=%s", branch); | ||||||||
8100 | } | ||||||||
8101 | else if (orq->orq_user_via && sip->sip_via->v_branch && orq->orq_method != sip_method_invite ) | ||||||||
8102 | branch = su_sprintf(home, "branch=%s", sip->sip_via->v_branch); | ||||||||
8103 | else if (stateless) | ||||||||
8104 | branch = stateless_branch(agent, msg, sip, orq->orq_tpn); | ||||||||
8105 | else | ||||||||
8106 | branch = stateful_branch(home, agent); | ||||||||
8107 | |||||||||
8108 | orq->orq_branch = branch; | ||||||||
8109 | orq->orq_via_branch = branch; | ||||||||
8110 | |||||||||
8111 | if (orq->orq_method == sip_method_ack) { | ||||||||
8112 | /* Find the original INVITE which we are ACKing */ | ||||||||
8113 | if (ack_branch != NULL((void*)0) && ack_branch != NONE((void *)-1)) { | ||||||||
8114 | if (su_casenmatch(ack_branch, "branch=", 7)) | ||||||||
8115 | orq->orq_branch = su_strdup(home, ack_branch); | ||||||||
8116 | else | ||||||||
8117 | orq->orq_branch = su_sprintf(home, "branch=%s", ack_branch); | ||||||||
8118 | } | ||||||||
8119 | else if (orq->orq_uas) { | ||||||||
8120 | /* | ||||||||
8121 | * ACK redirects further 2XX messages to it. | ||||||||
8122 | * | ||||||||
8123 | * Use orq_branch from INVITE, but put a different branch in topmost Via. | ||||||||
8124 | */ | ||||||||
8125 | nta_outgoing_t *invite = outgoing_find(agent, msg, sip, NULL((void*)0)); | ||||||||
8126 | |||||||||
8127 | if (invite) { | ||||||||
8128 | sip_t const *inv = sip_object(invite->orq_request); | ||||||||
8129 | |||||||||
8130 | orq->orq_branch = su_strdup(home, invite->orq_branch); | ||||||||
8131 | |||||||||
8132 | /* @RFC3261 section 13.2.2.4 - | ||||||||
8133 | * The ACK MUST contain the same credentials as the INVITE. | ||||||||
8134 | */ | ||||||||
8135 | if (!sip->sip_proxy_authorization && !sip->sip_authorization) { | ||||||||
8136 | if (inv->sip_proxy_authorization) | ||||||||
8137 | sip_add_dup(msg, sip, (void *)inv->sip_proxy_authorization); | ||||||||
8138 | if (inv->sip_authorization) | ||||||||
8139 | sip_add_dup(msg, sip, (void *)inv->sip_authorization); | ||||||||
8140 | } | ||||||||
8141 | } | ||||||||
8142 | else { | ||||||||
8143 | 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__ , 8143, "outgoing_create: ACK without INVITE\n" "%s", "")) : ( void)0); | ||||||||
8144 | assert(!"INVITE found for ACK")((void) sizeof ((!"INVITE found for ACK") ? 1 : 0), __extension__ ({ if (!"INVITE found for ACK") ; else __assert_fail ("!\"INVITE found for ACK\"" , "nta.c", 8144, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
8145 | } | ||||||||
8146 | } | ||||||||
8147 | } | ||||||||
8148 | |||||||||
8149 | #if HAVE_SOFIA_SRESOLV1 | ||||||||
8150 | if (!resolved) | ||||||||
8151 | orq->orq_tpn->tpn_port = port; | ||||||||
8152 | orq->orq_resolved = resolved; | ||||||||
8153 | #else | ||||||||
8154 | orq->orq_resolved = resolved = 1; | ||||||||
8155 | #endif | ||||||||
8156 | orq->orq_sips = su_casematch(scheme, "sips"); | ||||||||
8157 | |||||||||
8158 | if (invalid < 0 || !orq->orq_branch || msg_serialize(msg, (void *)sip) < 0) { | ||||||||
8159 | 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__ , 8161, "nta outgoing create: %s\n", invalid < 0 ? "invalid URI" : !orq->orq_branch ? "no branch" : "invalid message")) : ( void)0) | ||||||||
8160 | 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__ , 8161, "nta outgoing create: %s\n", invalid < 0 ? "invalid URI" : !orq->orq_branch ? "no branch" : "invalid message")) : ( void)0) | ||||||||
8161 | !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__ , 8161, "nta outgoing create: %s\n", invalid < 0 ? "invalid URI" : !orq->orq_branch ? "no branch" : "invalid message")) : ( void)0); | ||||||||
8162 | outgoing_free(orq); | ||||||||
8163 | return NULL((void*)0); | ||||||||
8164 | } | ||||||||
8165 | |||||||||
8166 | /* Now we are committed in sending the transaction */ | ||||||||
8167 | orq->orq_request = msg; | ||||||||
8168 | agent->sa_stats->as_client_tr++; | ||||||||
8169 | 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)); | ||||||||
8170 | |||||||||
8171 | if (orq->orq_user_tport) | ||||||||
8172 | outgoing_send_via(orq, override_tport); | ||||||||
8173 | else if (resolved) | ||||||||
8174 | outgoing_prepare_send(orq); | ||||||||
8175 | #if HAVE_SOFIA_SRESOLV1 | ||||||||
8176 | else | ||||||||
8177 | outgoing_resolve(orq, explicit_transport, res_order); | ||||||||
8178 | #endif | ||||||||
8179 | |||||||||
8180 | if (stateless && | ||||||||
8181 | orq->orq_status >= 200 && | ||||||||
8182 | callback == outgoing_default_cb) { | ||||||||
8183 | void *retval; | ||||||||
8184 | |||||||||
8185 | if (orq->orq_status < 300) | ||||||||
8186 | retval = (void *)-1; /* NONE */ | ||||||||
8187 | else | ||||||||
8188 | retval = NULL((void*)0), orq->orq_request = NULL((void*)0); | ||||||||
8189 | |||||||||
8190 | outgoing_free(orq); | ||||||||
8191 | |||||||||
8192 | return retval; | ||||||||
8193 | } | ||||||||
8194 | |||||||||
8195 | assert(orq->orq_queue)((void) sizeof ((orq->orq_queue) ? 1 : 0), __extension__ ( { if (orq->orq_queue) ; else __assert_fail ("orq->orq_queue" , "nta.c", 8195, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
8196 | |||||||||
8197 | outgoing_insert(agent, orq); | ||||||||
8198 | |||||||||
8199 | return orq; | ||||||||
8200 | } | ||||||||
8201 | |||||||||
8202 | /** Prepare sending a request */ | ||||||||
8203 | static void | ||||||||
8204 | outgoing_prepare_send(nta_outgoing_t *orq) | ||||||||
8205 | { | ||||||||
8206 | nta_agent_t *sa = orq->orq_agent; | ||||||||
8207 | tport_t *tp; | ||||||||
8208 | tp_name_t *tpn = orq->orq_tpn; | ||||||||
8209 | |||||||||
8210 | /* Select transport by scheme */ | ||||||||
8211 | if (orq->orq_sips && strcmp(tpn->tpn_proto, "*") == 0) | ||||||||
8212 | tpn->tpn_proto = "tls"; | ||||||||
8213 | |||||||||
8214 | if (!tpn->tpn_port) | ||||||||
8215 | tpn->tpn_port = ""; | ||||||||
8216 | |||||||||
8217 | tp = tport_by_name(sa->sa_tports, tpn); | ||||||||
8218 | |||||||||
8219 | if (tpn->tpn_port[0] == '\0') { | ||||||||
8220 | if (orq->orq_sips || tport_has_tls(tp)) | ||||||||
8221 | tpn->tpn_port = "5061"; | ||||||||
8222 | else | ||||||||
8223 | tpn->tpn_port = "5060"; | ||||||||
8224 | } | ||||||||
8225 | |||||||||
8226 | if (tp) { | ||||||||
8227 | outgoing_send_via(orq, tp); | ||||||||
8228 | } | ||||||||
8229 | else if (orq->orq_sips) { | ||||||||
8230 | 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__ , 8230, "nta outgoing create: no secure transport\n" "%s", "" )) : (void)0); | ||||||||
8231 | outgoing_reply(orq, SIP_416_UNSUPPORTED_URI416, sip_416_Unsupported_uri, 1); | ||||||||
8232 | } | ||||||||
8233 | else { | ||||||||
8234 | 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__ , 8234, "nta outgoing create: no transport protocol\n" "%s", "" )) : (void)0); | ||||||||
8235 | outgoing_reply(orq, 503, "No transport", 1); | ||||||||
8236 | } | ||||||||
8237 | } | ||||||||
8238 | |||||||||
8239 | /** Send request using given transport */ | ||||||||
8240 | static void | ||||||||
8241 | outgoing_send_via(nta_outgoing_t *orq, tport_t *tp) | ||||||||
8242 | { | ||||||||
8243 | tport_t *old_tp = orq->orq_tport; | ||||||||
8244 | |||||||||
8245 | orq->orq_tport = tport_ref(tp); | ||||||||
8246 | |||||||||
8247 | if (orq->orq_pending && tp != old_tp) { | ||||||||
8248 | tport_release(old_tp, orq->orq_pending, | ||||||||
8249 | orq->orq_request, NULL((void*)0), orq, 0); | ||||||||
8250 | orq->orq_pending = 0; | ||||||||
8251 | } | ||||||||
8252 | |||||||||
8253 | if (old_tp) tport_unref(old_tp); | ||||||||
8254 | |||||||||
8255 | if (outgoing_insert_via(orq, agent_tport_via(tp)) < 0) { | ||||||||
8256 | 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__ , 8256, "nta outgoing create: cannot insert Via line\n" "%s", "")) : (void)0); | ||||||||
8257 | outgoing_reply(orq, 503, "Cannot insert Via", 1); | ||||||||
8258 | return; | ||||||||
8259 | } | ||||||||
8260 | |||||||||
8261 | #if HAVE_SOFIA_SMIME0 | ||||||||
8262 | { | ||||||||
8263 | sm_object_t *smime = sa->sa_smime; | ||||||||
8264 | sip_t *sip = sip_object(orq->orq_request); | ||||||||
8265 | |||||||||
8266 | if (sa->sa_smime && | ||||||||
8267 | (sip->sip_request->rq_method == sip_method_invite || | ||||||||
8268 | sip->sip_request->rq_method == sip_method_message)) { | ||||||||
8269 | msg_prepare(orq->orq_request); | ||||||||
8270 | if (sm_encode_message(smime, msg, sip, SM_ID_NULL) < 0) { | ||||||||
8271 | outgoing_tport_error(sa, orq, NULL((void*)0), | ||||||||
8272 | orq->orq_request, su_errno()); | ||||||||
8273 | return; | ||||||||
8274 | } | ||||||||
8275 | } | ||||||||
8276 | } | ||||||||
8277 | #endif | ||||||||
8278 | |||||||||
8279 | orq->orq_prepared = 1; | ||||||||
8280 | |||||||||
8281 | if (orq->orq_delayed) { | ||||||||
8282 | 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__ , 8283, "nta: delayed sending %s (%u)\n", orq->orq_method_name , orq->orq_cseq->cs_seq)) : (void)0) | ||||||||
8283 | 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__ , 8283, "nta: delayed sending %s (%u)\n", orq->orq_method_name , orq->orq_cseq->cs_seq)) : (void)0); | ||||||||
8284 | outgoing_queue(orq->orq_agent->sa_out.delayed, orq); | ||||||||
8285 | return; | ||||||||
8286 | } | ||||||||
8287 | |||||||||
8288 | outgoing_send(orq, 0); | ||||||||
8289 | } | ||||||||
8290 | |||||||||
8291 | |||||||||
8292 | /** Send a request */ | ||||||||
8293 | static void | ||||||||
8294 | outgoing_send(nta_outgoing_t *orq, int retransmit) | ||||||||
8295 | { | ||||||||
8296 | int err; | ||||||||
8297 | tp_name_t const *tpn = orq->orq_tpn; | ||||||||
8298 | msg_t *msg = orq->orq_request; | ||||||||
8299 | nta_agent_t *agent = orq->orq_agent; | ||||||||
8300 | tport_t *tp; | ||||||||
8301 | int once = 0; | ||||||||
8302 | su_time_t now = su_now(); | ||||||||
8303 | tag_type_t tag = tag_skip; | ||||||||
8304 | tag_value_t value = 0; | ||||||||
8305 | struct sigcomp_compartment *cc; cc = NULL((void*)0); | ||||||||
8306 | |||||||||
8307 | /* tport can be NULL if we are just switching network */ | ||||||||
8308 | if (orq->orq_tport == NULL((void*)0)) { | ||||||||
8309 | outgoing_tport_error(agent, orq, NULL((void*)0), orq->orq_request, ENETRESET102); | ||||||||
8310 | return; | ||||||||
8311 | } | ||||||||
8312 | |||||||||
8313 | if (orq->orq_user_tport && !tport_is_clear_to_send(orq->orq_tport)) { | ||||||||
8314 | outgoing_tport_error(agent, orq, NULL((void*)0), orq->orq_request, EPIPE32); | ||||||||
8315 | return; | ||||||||
8316 | } | ||||||||
8317 | |||||||||
8318 | if (!retransmit) | ||||||||
8319 | orq->orq_sent = now; | ||||||||
8320 | |||||||||
8321 | if (orq->orq_timestamp) { | ||||||||
8322 | sip_t *sip = sip_object(msg); | ||||||||
8323 | sip_timestamp_t *ts = | ||||||||
8324 | sip_timestamp_format(msg_home(msg)((su_home_t*)(msg)), "%lu.%06lu", | ||||||||
8325 | now.tv_sec, now.tv_usec); | ||||||||
8326 | |||||||||
8327 | if (ts) { | ||||||||
8328 | if (sip->sip_timestamp) | ||||||||
8329 | msg_header_remove(msg, (msg_pub_t *)sip, (msg_header_t *)sip->sip_timestamp); | ||||||||
8330 | msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)ts); | ||||||||
8331 | } | ||||||||
8332 | } | ||||||||
8333 | |||||||||
8334 | for (;;) { | ||||||||
8335 | if (tpn->tpn_comp == NULL((void*)0)) { | ||||||||
8336 | /* xyzzy */ | ||||||||
8337 | } | ||||||||
8338 | else if (orq->orq_cc) { | ||||||||
8339 | cc = orq->orq_cc, orq->orq_cc = NULL((void*)0); | ||||||||
8340 | } | ||||||||
8341 | else { | ||||||||
8342 | cc = agent_compression_compartment(agent, orq->orq_tport, tpn, | ||||||||
8343 | orq->orq_sigcomp_new); | ||||||||
8344 | } | ||||||||
8345 | |||||||||
8346 | if (orq->orq_try_udp_instead) | ||||||||
8347 | tag = tptag_mtu, value = 65535; | ||||||||
8348 | |||||||||
8349 | if (orq->orq_pending) { | ||||||||
8350 | tport_release(orq->orq_tport, orq->orq_pending, | ||||||||
8351 | orq->orq_request, NULL((void*)0), orq, 0); | ||||||||
8352 | orq->orq_pending = 0; | ||||||||
8353 | } | ||||||||
8354 | |||||||||
8355 | tp = tport_tsend(orq->orq_tport, msg, tpn, | ||||||||
8356 | tag, value, | ||||||||
8357 | IF_SIGCOMP_TPTAG_COMPARTMENT(cc)!(cc && cc != ((void *)-1)) ? tag_skip : tptag_compartment , tag_ptr_v((cc)), | ||||||||
8358 | TAG_NEXT(orq->orq_tags)tag_next, (tag_value_t)(orq->orq_tags)); | ||||||||
8359 | if (tp) | ||||||||
8360 | break; | ||||||||
8361 | |||||||||
8362 | err = msg_errno(orq->orq_request); | ||||||||
8363 | |||||||||
8364 | if (cc) | ||||||||
8365 | nta_compartment_decref(&cc); | ||||||||
8366 | |||||||||
8367 | if (orq->orq_user_tport) | ||||||||
8368 | /* No retries */; | ||||||||
8369 | /* RFC3261, 18.1.1 */ | ||||||||
8370 | else if (err == EMSGSIZE90 && !orq->orq_try_tcp_instead) { | ||||||||
8371 | if (su_casematch(tpn->tpn_proto, "udp") || | ||||||||
8372 | su_casematch(tpn->tpn_proto, "*")) { | ||||||||
8373 | outgoing_try_tcp_instead(orq); | ||||||||
8374 | continue; | ||||||||
8375 | } | ||||||||
8376 | } | ||||||||
8377 | else if (err == ECONNREFUSED111 && orq->orq_try_tcp_instead) { | ||||||||
8378 | if (su_casematch(tpn->tpn_proto, "tcp") && msg_size(msg) <= 65535) { | ||||||||
8379 | outgoing_try_udp_instead(orq, 0); | ||||||||
8380 | continue; | ||||||||
8381 | } | ||||||||
8382 | } | ||||||||
8383 | else if (err == EPIPE32) { | ||||||||
8384 | /* Connection was closed */ | ||||||||
8385 | if (!once++) { | ||||||||
8386 | orq->orq_retries++; | ||||||||
8387 | continue; | ||||||||
8388 | } | ||||||||
8389 | } | ||||||||
8390 | |||||||||
8391 | outgoing_tport_error(agent, orq, NULL((void*)0), orq->orq_request, err); | ||||||||
8392 | |||||||||
8393 | return; | ||||||||
8394 | } | ||||||||
8395 | |||||||||
8396 | agent->sa_stats->as_sent_msg++; | ||||||||
8397 | agent->sa_stats->as_sent_request++; | ||||||||
8398 | if (retransmit) | ||||||||
8399 | agent->sa_stats->as_retry_request++; | ||||||||
8400 | |||||||||
8401 | 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__ , 8404, "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) | ||||||||
8402 | 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__ , 8404, "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) | ||||||||
8403 | 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__ , 8404, "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) | ||||||||
8404 | 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__ , 8404, "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); | ||||||||
8405 | |||||||||
8406 | if (cc) { | ||||||||
8407 | if (orq->orq_cc) | ||||||||
8408 | nta_compartment_decref(&orq->orq_cc); | ||||||||
8409 | } | ||||||||
8410 | |||||||||
8411 | if (orq->orq_pending) { | ||||||||
8412 | assert(orq->orq_tport)((void) sizeof ((orq->orq_tport) ? 1 : 0), __extension__ ( { if (orq->orq_tport) ; else __assert_fail ("orq->orq_tport" , "nta.c", 8412, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
8413 | tport_release(orq->orq_tport, orq->orq_pending, | ||||||||
8414 | orq->orq_request, NULL((void*)0), orq, 0); | ||||||||
8415 | orq->orq_pending = 0; | ||||||||
8416 | } | ||||||||
8417 | |||||||||
8418 | if (orq->orq_stateless) { | ||||||||
8419 | outgoing_reply(orq, 202, NULL((void*)0), 202); | ||||||||
8420 | return; | ||||||||
8421 | } | ||||||||
8422 | |||||||||
8423 | if (orq->orq_method != sip_method_ack) { | ||||||||
8424 | orq->orq_pending = tport_pend(tp, orq->orq_request, | ||||||||
8425 | outgoing_tport_error, orq); | ||||||||
8426 | if (orq->orq_pending < 0) | ||||||||
8427 | orq->orq_pending = 0; | ||||||||
8428 | } | ||||||||
8429 | |||||||||
8430 | if (tp != orq->orq_tport) { | ||||||||
8431 | tport_decref(&orq->orq_tport); | ||||||||
8432 | orq->orq_tport = tport_ref(tp); | ||||||||
8433 | } | ||||||||
8434 | |||||||||
8435 | orq->orq_reliable = tport_is_reliable(tp); | ||||||||
8436 | |||||||||
8437 | if (retransmit) | ||||||||
8438 | return; | ||||||||
8439 | |||||||||
8440 | outgoing_trying(orq); /* Timer B / F */ | ||||||||
8441 | |||||||||
8442 | if (orq->orq_method == sip_method_ack) | ||||||||
8443 | ; | ||||||||
8444 | else if (!orq->orq_reliable) { | ||||||||
8445 | /* race condition on initial t1 timer timeout, set minimum initial timeout to 1000ms */ | ||||||||
8446 | unsigned t1_timer = agent->sa_t1; | ||||||||
8447 | if (t1_timer < 1000) t1_timer = 1000; | ||||||||
8448 | outgoing_set_timer(orq, t1_timer); /* Timer A/E */ | ||||||||
8449 | } else if (orq->orq_try_tcp_instead && !tport_is_connected(tp)) { | ||||||||
8450 | outgoing_set_timer(orq, agent->sa_t4); /* Timer N3 */ | ||||||||
8451 | } else if (su_casenmatch(orq->orq_tpn->tpn_proto, "tls", 3) && !tport_is_connected(tp)) { | ||||||||
8452 | unsigned tls_reconect_interval = (orq->orq_call_tls_connect_timeout_is_set) ? | ||||||||
8453 | orq->orq_call_tls_connect_timeout : agent->sa_tls_orq_connect_timeout; | ||||||||
8454 | if (tls_reconect_interval) { | ||||||||
8455 | if (tls_reconect_interval < 1000) tls_reconect_interval = 1000; | ||||||||
8456 | outgoing_set_timer(orq, tls_reconect_interval); /* Timer N3 set to (min 1000 ms if set) */ | ||||||||
8457 | } | ||||||||
8458 | } | ||||||||
8459 | } | ||||||||
8460 | |||||||||
8461 | static void | ||||||||
8462 | outgoing_try_tcp_instead(nta_outgoing_t *orq) | ||||||||
8463 | { | ||||||||
8464 | tport_t *tp; | ||||||||
8465 | tp_name_t tpn[1]; | ||||||||
8466 | |||||||||
8467 | assert(orq->orq_pending == 0)((void) sizeof ((orq->orq_pending == 0) ? 1 : 0), __extension__ ({ if (orq->orq_pending == 0) ; else __assert_fail ("orq->orq_pending == 0" , "nta.c", 8467, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
8468 | |||||||||
8469 | *tpn = *orq->orq_tpn; | ||||||||
8470 | tpn->tpn_proto = "tcp"; | ||||||||
8471 | orq->orq_try_tcp_instead = 1; | ||||||||
8472 | |||||||||
8473 | tp = tport_by_name(orq->orq_agent->sa_tports, tpn); | ||||||||
8474 | if (tp && tp != orq->orq_tport) { | ||||||||
8475 | sip_t *sip = sip_object(orq->orq_request); | ||||||||
8476 | 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); | ||||||||
8477 | sip->sip_via->v_protocol = sip_transport_tcp; | ||||||||
8478 | |||||||||
8479 | 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__ , 8480, "nta: %s (%u) too large for UDP, trying TCP\n", orq-> orq_method_name, orq->orq_cseq->cs_seq)) : (void)0) | ||||||||
8480 | 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__ , 8480, "nta: %s (%u) too large for UDP, trying TCP\n", orq-> orq_method_name, orq->orq_cseq->cs_seq)) : (void)0); | ||||||||
8481 | |||||||||
8482 | orq->orq_tpn->tpn_proto = "tcp"; | ||||||||
8483 | tport_decref(&orq->orq_tport); | ||||||||
8484 | orq->orq_tport = tport_ref(tp); | ||||||||
8485 | |||||||||
8486 | return; | ||||||||
8487 | } | ||||||||
8488 | |||||||||
8489 | /* No TCP - try again with UDP without SIP MTU limit */ | ||||||||
8490 | tpn->tpn_proto = "udp"; | ||||||||
8491 | orq->orq_try_udp_instead = 1; | ||||||||
8492 | |||||||||
8493 | tp = tport_by_name(orq->orq_agent->sa_tports, tpn); | ||||||||
8494 | if (tp && tp != orq->orq_tport) { | ||||||||
8495 | 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__ , 8496, "nta: %s (%u) exceed normal UDP size limit\n", orq-> orq_method_name, orq->orq_cseq->cs_seq)) : (void)0) | ||||||||
8496 | 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__ , 8496, "nta: %s (%u) exceed normal UDP size limit\n", orq-> orq_method_name, orq->orq_cseq->cs_seq)) : (void)0); | ||||||||
8497 | |||||||||
8498 | tport_decref(&orq->orq_tport); | ||||||||
8499 | orq->orq_tport = tport_ref(tp); | ||||||||
8500 | } | ||||||||
8501 | } | ||||||||
8502 | |||||||||
8503 | static void | ||||||||
8504 | outgoing_try_udp_instead(nta_outgoing_t *orq, int timeout) | ||||||||
8505 | { | ||||||||
8506 | tport_t *tp; | ||||||||
8507 | tp_name_t tpn[1]; | ||||||||
8508 | |||||||||
8509 | if (orq->orq_pending) { | ||||||||
8510 | tport_release(orq->orq_tport, orq->orq_pending, | ||||||||
8511 | orq->orq_request, NULL((void*)0), orq, 0); | ||||||||
8512 | orq->orq_pending = 0; | ||||||||
8513 | } | ||||||||
8514 | |||||||||
8515 | *tpn = *orq->orq_tpn; | ||||||||
8516 | tpn->tpn_proto = "udp"; | ||||||||
8517 | orq->orq_try_udp_instead = 1; | ||||||||
8518 | |||||||||
8519 | tp = tport_by_name(orq->orq_agent->sa_tports, tpn); | ||||||||
8520 | if (tp && tp != orq->orq_tport) { | ||||||||
8521 | sip_t *sip = sip_object(orq->orq_request); | ||||||||
8522 | |||||||||
8523 | 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); | ||||||||
8524 | sip->sip_via->v_protocol = sip_transport_udp; | ||||||||
8525 | |||||||||
8526 | 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__ , 8528, "nta: %s (%u) TCP %s, trying UDP\n", orq->orq_method_name , orq->orq_cseq->cs_seq, timeout ? "times out" : "refused" )) : (void)0) | ||||||||
8527 | 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__ , 8528, "nta: %s (%u) TCP %s, trying UDP\n", orq->orq_method_name , orq->orq_cseq->cs_seq, timeout ? "times out" : "refused" )) : (void)0) | ||||||||
8528 | 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__ , 8528, "nta: %s (%u) TCP %s, trying UDP\n", orq->orq_method_name , orq->orq_cseq->cs_seq, timeout ? "times out" : "refused" )) : (void)0); | ||||||||
8529 | |||||||||
8530 | orq->orq_tpn->tpn_proto = "udp"; | ||||||||
8531 | tport_decref(&orq->orq_tport); | ||||||||
8532 | orq->orq_tport = tport_ref(tp); | ||||||||
8533 | } | ||||||||
8534 | } | ||||||||
8535 | |||||||||
8536 | |||||||||
8537 | /** @internal Report transport errors. */ | ||||||||
8538 | void | ||||||||
8539 | outgoing_tport_error(nta_agent_t *agent, nta_outgoing_t *orq, | ||||||||
8540 | tport_t *tp, msg_t *msg, int error) | ||||||||
8541 | { | ||||||||
8542 | tp_name_t const *tpn = tp ? tport_name(tp) : orq->orq_tpn; | ||||||||
8543 | |||||||||
8544 | if (orq->orq_pending) { | ||||||||
8545 | assert(orq->orq_tport)((void) sizeof ((orq->orq_tport) ? 1 : 0), __extension__ ( { if (orq->orq_tport) ; else __assert_fail ("orq->orq_tport" , "nta.c", 8545, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
8546 | tport_release(orq->orq_tport, orq->orq_pending, orq->orq_request, | ||||||||
8547 | NULL((void*)0), orq, 0); | ||||||||
8548 | orq->orq_pending = 0; | ||||||||
8549 | } | ||||||||
8550 | |||||||||
8551 | if (error == EPIPE32 && orq->orq_retries++ == 0) { | ||||||||
8552 | /* XXX - we should retry only if the transport is not newly created */ | ||||||||
8553 | outgoing_print_tport_error(orq, 5, "retrying once after ", | ||||||||
8554 | tpn, msg, error); | ||||||||
8555 | outgoing_send(orq, 1); | ||||||||
8556 | return; | ||||||||
8557 | } | ||||||||
8558 | else if (error == ECONNREFUSED111 && orq->orq_try_tcp_instead) { | ||||||||
8559 | /* RFC3261, 18.1.1 */ | ||||||||
8560 | if (su_casematch(tpn->tpn_proto, "tcp") && msg_size(msg) <= 65535) { | ||||||||
8561 | outgoing_print_tport_error(orq, 5, "retrying with UDP after ", | ||||||||
8562 | tpn, msg, error); | ||||||||
8563 | outgoing_try_udp_instead(orq, 0); | ||||||||
8564 | outgoing_remove(orq); /* Reset state - this is no resend! */ | ||||||||
8565 | outgoing_send(orq, 0); /* Send */ | ||||||||
8566 | return; | ||||||||
8567 | } | ||||||||
8568 | } | ||||||||
8569 | else if (error == 0) { | ||||||||
8570 | /* | ||||||||
8571 | * Server closed connection. RFC3261: | ||||||||
8572 | * "there is no coupling between TCP connection state and SIP | ||||||||
8573 | * processing." | ||||||||
8574 | */ | ||||||||
8575 | return; | ||||||||
8576 | } | ||||||||
8577 | |||||||||
8578 | if (outgoing_other_destinations(orq)) { | ||||||||
8579 | outgoing_print_tport_error(orq, 5, "trying alternative server after ", | ||||||||
8580 | tpn, msg, error); | ||||||||
8581 | outgoing_try_another(orq); | ||||||||
8582 | return; | ||||||||
8583 | } | ||||||||
8584 | |||||||||
8585 | outgoing_print_tport_error(orq, 3, "", tpn, msg, error); | ||||||||
8586 | |||||||||
8587 | outgoing_reply(orq, SIP_503_SERVICE_UNAVAILABLE503, sip_503_Service_unavailable, 0); | ||||||||
8588 | } | ||||||||
8589 | |||||||||
8590 | static | ||||||||
8591 | void | ||||||||
8592 | outgoing_print_tport_error(nta_outgoing_t *orq, int level, char *todo, | ||||||||
8593 | tp_name_t const *tpn, msg_t *msg, int error) | ||||||||
8594 | { | ||||||||
8595 | su_sockaddr_t const *su = msg_addr(msg); | ||||||||
8596 | char addr[SU_ADDRSIZE(48)]; | ||||||||
8597 | |||||||||
8598 | su_llog(nta_log, level,_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8604 , "nta: %s (%u): %s%s (%u) with %s/[%s]:%u\n", orq->orq_method_name , orq->orq_cseq->cs_seq, todo, su_strerror(error), error , tpn->tpn_proto, inet_ntop(su->su_sa.sa_family, ((su)-> su_sa.sa_family == 2 ? (void *)&(su)->su_sin.sin_addr : ((su)->su_sa.sa_family == 10 ? (void *)&(su)->su_sin6 .sin6_addr : (void *)&(su)->su_sa.sa_data)), addr, sizeof (addr)), htons(su->su_sin.sin_port)) | ||||||||
8599 | "nta: %s (%u): %s%s (%u) with %s/[%s]:%u\n",_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8604 , "nta: %s (%u): %s%s (%u) with %s/[%s]:%u\n", orq->orq_method_name , orq->orq_cseq->cs_seq, todo, su_strerror(error), error , tpn->tpn_proto, inet_ntop(su->su_sa.sa_family, ((su)-> su_sa.sa_family == 2 ? (void *)&(su)->su_sin.sin_addr : ((su)->su_sa.sa_family == 10 ? (void *)&(su)->su_sin6 .sin6_addr : (void *)&(su)->su_sa.sa_data)), addr, sizeof (addr)), htons(su->su_sin.sin_port)) | ||||||||
8600 | orq->orq_method_name, orq->orq_cseq->cs_seq,_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8604 , "nta: %s (%u): %s%s (%u) with %s/[%s]:%u\n", orq->orq_method_name , orq->orq_cseq->cs_seq, todo, su_strerror(error), error , tpn->tpn_proto, inet_ntop(su->su_sa.sa_family, ((su)-> su_sa.sa_family == 2 ? (void *)&(su)->su_sin.sin_addr : ((su)->su_sa.sa_family == 10 ? (void *)&(su)->su_sin6 .sin6_addr : (void *)&(su)->su_sa.sa_data)), addr, sizeof (addr)), htons(su->su_sin.sin_port)) | ||||||||
8601 | todo, su_strerror(error), error,_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8604 , "nta: %s (%u): %s%s (%u) with %s/[%s]:%u\n", orq->orq_method_name , orq->orq_cseq->cs_seq, todo, su_strerror(error), error , tpn->tpn_proto, inet_ntop(su->su_sa.sa_family, ((su)-> su_sa.sa_family == 2 ? (void *)&(su)->su_sin.sin_addr : ((su)->su_sa.sa_family == 10 ? (void *)&(su)->su_sin6 .sin6_addr : (void *)&(su)->su_sa.sa_data)), addr, sizeof (addr)), htons(su->su_sin.sin_port)) | ||||||||
8602 | tpn->tpn_proto,_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8604 , "nta: %s (%u): %s%s (%u) with %s/[%s]:%u\n", orq->orq_method_name , orq->orq_cseq->cs_seq, todo, su_strerror(error), error , tpn->tpn_proto, inet_ntop(su->su_sa.sa_family, ((su)-> su_sa.sa_family == 2 ? (void *)&(su)->su_sin.sin_addr : ((su)->su_sa.sa_family == 10 ? (void *)&(su)->su_sin6 .sin6_addr : (void *)&(su)->su_sa.sa_data)), addr, sizeof (addr)), htons(su->su_sin.sin_port)) | ||||||||
8603 | su_inet_ntop(su->su_family, SU_ADDR(su), addr, sizeof(addr)),_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8604 , "nta: %s (%u): %s%s (%u) with %s/[%s]:%u\n", orq->orq_method_name , orq->orq_cseq->cs_seq, todo, su_strerror(error), error , tpn->tpn_proto, inet_ntop(su->su_sa.sa_family, ((su)-> su_sa.sa_family == 2 ? (void *)&(su)->su_sin.sin_addr : ((su)->su_sa.sa_family == 10 ? (void *)&(su)->su_sin6 .sin6_addr : (void *)&(su)->su_sa.sa_data)), addr, sizeof (addr)), htons(su->su_sin.sin_port)) | ||||||||
8604 | htons(su->su_port))_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8604 , "nta: %s (%u): %s%s (%u) with %s/[%s]:%u\n", orq->orq_method_name , orq->orq_cseq->cs_seq, todo, su_strerror(error), error , tpn->tpn_proto, inet_ntop(su->su_sa.sa_family, ((su)-> su_sa.sa_family == 2 ? (void *)&(su)->su_sin.sin_addr : ((su)->su_sa.sa_family == 10 ? (void *)&(su)->su_sin6 .sin6_addr : (void *)&(su)->su_sa.sa_data)), addr, sizeof (addr)), htons(su->su_sin.sin_port)); | ||||||||
8605 | } | ||||||||
8606 | |||||||||
8607 | /**@internal | ||||||||
8608 | * Add features supported. | ||||||||
8609 | */ | ||||||||
8610 | static | ||||||||
8611 | int outgoing_features(nta_agent_t *agent, nta_outgoing_t *orq, | ||||||||
8612 | msg_t *msg, sip_t *sip, | ||||||||
8613 | tagi_t *tags) | ||||||||
8614 | { | ||||||||
8615 | char const *supported[8]; | ||||||||
8616 | int i; | ||||||||
8617 | |||||||||
8618 | if (orq->orq_method != sip_method_invite) /* fast path for now */ | ||||||||
8619 | return 0; | ||||||||
8620 | |||||||||
8621 | supported[i = 0] = NULL((void*)0); | ||||||||
8622 | |||||||||
8623 | if (orq->orq_method == sip_method_invite) { | ||||||||
8624 | int require_100rel = sip_has_feature(sip->sip_require, "100rel"); | ||||||||
8625 | |||||||||
8626 | if (require_100rel) { | ||||||||
8627 | orq->orq_must_100rel = 1; | ||||||||
8628 | orq->orq_100rel = 1; | ||||||||
8629 | } | ||||||||
8630 | else if (sip_has_feature(sip->sip_supported, "100rel")) { | ||||||||
8631 | orq->orq_100rel = 1; | ||||||||
8632 | } | ||||||||
8633 | else if (orq->orq_100rel) { | ||||||||
8634 | supported[i++] = "100rel"; | ||||||||
8635 | } | ||||||||
8636 | } | ||||||||
8637 | |||||||||
8638 | if (i) { | ||||||||
8639 | supported[i] = NULL((void*)0); | ||||||||
8640 | |||||||||
8641 | if (sip->sip_supported) { | ||||||||
8642 | su_home_t *home = msg_home(msg)((su_home_t*)(msg)); | ||||||||
8643 | return msg_list_append_items(home, sip->sip_supported, supported); | ||||||||
8644 | } | ||||||||
8645 | else { | ||||||||
8646 | sip_supported_t s[1]; | ||||||||
8647 | sip_supported_init(s); | ||||||||
8648 | s->k_items = supported; | ||||||||
8649 | return sip_add_dup(msg, sip, (sip_header_t *)s); | ||||||||
8650 | } | ||||||||
8651 | } | ||||||||
8652 | |||||||||
8653 | return 0; | ||||||||
8654 | } | ||||||||
8655 | |||||||||
8656 | |||||||||
8657 | /**@internal | ||||||||
8658 | * Insert outgoing request to agent hash table | ||||||||
8659 | */ | ||||||||
8660 | static | ||||||||
8661 | void outgoing_insert(nta_agent_t *agent, nta_outgoing_t *orq) | ||||||||
8662 | { | ||||||||
8663 | if (outgoing_htable_is_full(agent->sa_outgoing)) | ||||||||
8664 | outgoing_htable_resize(agent->sa_home, agent->sa_outgoing, 0); | ||||||||
8665 | outgoing_htable_insert(agent->sa_outgoing, orq); | ||||||||
8666 | orq->orq_inserted = 1; | ||||||||
8667 | } | ||||||||
8668 | |||||||||
8669 | /** @internal | ||||||||
8670 | * Initialize a queue for outgoing transactions. | ||||||||
8671 | */ | ||||||||
8672 | static void | ||||||||
8673 | outgoing_queue_init(outgoing_queue_t *queue, unsigned timeout) | ||||||||
8674 | { | ||||||||
8675 | memset(queue, 0, sizeof *queue); | ||||||||
8676 | queue->q_tail = &queue->q_head; | ||||||||
8677 | queue->q_timeout = timeout; | ||||||||
8678 | } | ||||||||
8679 | |||||||||
8680 | /** Change the timeout value of a queue */ | ||||||||
8681 | static void | ||||||||
8682 | outgoing_queue_adjust(nta_agent_t *sa, | ||||||||
8683 | outgoing_queue_t *queue, | ||||||||
8684 | unsigned timeout) | ||||||||
8685 | { | ||||||||
8686 | nta_outgoing_t *orq; | ||||||||
8687 | uint32_t latest; | ||||||||
8688 | |||||||||
8689 | if (timeout >= queue->q_timeout || !queue->q_head) { | ||||||||
8690 | queue->q_timeout = timeout; | ||||||||
8691 | return; | ||||||||
8692 | } | ||||||||
8693 | |||||||||
8694 | latest = set_timeout(sa, queue->q_timeout = timeout); | ||||||||
8695 | |||||||||
8696 | for (orq = queue->q_head; orq; orq = orq->orq_next) { | ||||||||
8697 | if (orq->orq_timeout == 0 || | ||||||||
8698 | (int32_t)(orq->orq_timeout - latest) > 0) | ||||||||
8699 | orq->orq_timeout = latest; | ||||||||
8700 | } | ||||||||
8701 | } | ||||||||
8702 | |||||||||
8703 | /** @internal | ||||||||
8704 | * Test if an outgoing transaction is in a queue. | ||||||||
8705 | */ | ||||||||
8706 | su_inlinestatic inline int | ||||||||
8707 | outgoing_is_queued(nta_outgoing_t const *orq) | ||||||||
8708 | { | ||||||||
8709 | return orq && orq->orq_queue; | ||||||||
8710 | } | ||||||||
8711 | |||||||||
8712 | /** @internal | ||||||||
8713 | * Insert an outgoing transaction into a queue. | ||||||||
8714 | * | ||||||||
8715 | * Insert a client transaction into a queue and set the corresponding | ||||||||
8716 | * timeout at the same time. | ||||||||
8717 | */ | ||||||||
8718 | static void | ||||||||
8719 | outgoing_queue(outgoing_queue_t *queue, | ||||||||
8720 | nta_outgoing_t *orq) | ||||||||
8721 | { | ||||||||
8722 | if (orq->orq_queue == queue) { | ||||||||
8723 | //assert(queue->q_timeout == 0); | ||||||||
8724 | return; | ||||||||
8725 | } | ||||||||
8726 | |||||||||
8727 | assert(!orq->orq_forked)((void) sizeof ((!orq->orq_forked) ? 1 : 0), __extension__ ({ if (!orq->orq_forked) ; else __assert_fail ("!orq->orq_forked" , "nta.c", 8727, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
8728 | |||||||||
8729 | if (outgoing_is_queued(orq)) | ||||||||
8730 | outgoing_remove(orq); | ||||||||
8731 | |||||||||
8732 | orq->orq_timeout = set_timeout(orq->orq_agent, queue->q_timeout); | ||||||||
8733 | |||||||||
8734 | orq->orq_queue = queue; | ||||||||
8735 | orq->orq_prev = queue->q_tail; | ||||||||
8736 | *queue->q_tail = orq; | ||||||||
8737 | queue->q_tail = &orq->orq_next; | ||||||||
8738 | queue->q_length++; | ||||||||
8739 | } | ||||||||
8740 | |||||||||
8741 | /** @internal | ||||||||
8742 | * Remove an outgoing transaction from a queue. | ||||||||
8743 | */ | ||||||||
8744 | su_inlinestatic inline | ||||||||
8745 | void outgoing_remove(nta_outgoing_t *orq) | ||||||||
8746 | { | ||||||||
8747 | assert(outgoing_is_queued(orq))((void) sizeof ((outgoing_is_queued(orq)) ? 1 : 0), __extension__ ({ if (outgoing_is_queued(orq)) ; else __assert_fail ("outgoing_is_queued(orq)" , "nta.c", 8747, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
8748 | assert(orq->orq_queue->q_length > 0)((void) sizeof ((orq->orq_queue->q_length > 0) ? 1 : 0), __extension__ ({ if (orq->orq_queue->q_length > 0) ; else __assert_fail ("orq->orq_queue->q_length > 0" , "nta.c", 8748, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
8749 | |||||||||
8750 | if ((*orq->orq_prev = orq->orq_next)) | ||||||||
8751 | orq->orq_next->orq_prev = orq->orq_prev; | ||||||||
8752 | else | ||||||||
8753 | orq->orq_queue->q_tail = orq->orq_prev; | ||||||||
8754 | |||||||||
8755 | orq->orq_queue->q_length--; | ||||||||
8756 | orq->orq_next = NULL((void*)0); | ||||||||
8757 | orq->orq_prev = NULL((void*)0); | ||||||||
8758 | orq->orq_queue = NULL((void*)0); | ||||||||
8759 | orq->orq_timeout = 0; | ||||||||
8760 | } | ||||||||
8761 | |||||||||
8762 | /** Set retransmit timer (orq_retry). | ||||||||
8763 | * | ||||||||
8764 | * Set the retry timer (B/D) on the outgoing request (client transaction). | ||||||||
8765 | */ | ||||||||
8766 | su_inlinestatic inline | ||||||||
8767 | void outgoing_set_timer(nta_outgoing_t *orq, uint32_t interval) | ||||||||
8768 | { | ||||||||
8769 | nta_outgoing_t **rq; | ||||||||
8770 | |||||||||
8771 | assert(orq)((void) sizeof ((orq) ? 1 : 0), __extension__ ({ if (orq) ; else __assert_fail ("orq", "nta.c", 8771, __extension__ __PRETTY_FUNCTION__ ); })); | ||||||||
8772 | |||||||||
8773 | if (interval == 0) { | ||||||||
8774 | outgoing_reset_timer(orq); | ||||||||
8775 | return; | ||||||||
8776 | } | ||||||||
8777 | |||||||||
8778 | if (orq->orq_rprev) { | ||||||||
8779 | /* Remove transaction from retry dequeue, re-insert it later. */ | ||||||||
8780 | if ((*orq->orq_rprev = orq->orq_rnext)) | ||||||||
8781 | orq->orq_rnext->orq_rprev = orq->orq_rprev; | ||||||||
8782 | if (orq->orq_agent->sa_out.re_t1 == &orq->orq_rnext) | ||||||||
8783 | orq->orq_agent->sa_out.re_t1 = orq->orq_rprev; | ||||||||
8784 | } | ||||||||
8785 | else { | ||||||||
8786 | orq->orq_agent->sa_out.re_length++; | ||||||||
8787 | } | ||||||||
8788 | |||||||||
8789 | orq->orq_retry = set_timeout(orq->orq_agent, orq->orq_interval = interval); | ||||||||
8790 | |||||||||
8791 | /* Shortcut into queue at SIP T1 */ | ||||||||
8792 | rq = orq->orq_agent->sa_out.re_t1; | ||||||||
8793 | |||||||||
8794 | if (!(*rq) || (int32_t)((*rq)->orq_retry - orq->orq_retry) > 0) | ||||||||
8795 | rq = &orq->orq_agent->sa_out.re_list; | ||||||||
8796 | |||||||||
8797 | while (*rq && (int32_t)((*rq)->orq_retry - orq->orq_retry) <= 0) | ||||||||
8798 | rq = &(*rq)->orq_rnext; | ||||||||
8799 | |||||||||
8800 | if ((orq->orq_rnext = *rq)) | ||||||||
8801 | orq->orq_rnext->orq_rprev = &orq->orq_rnext; | ||||||||
8802 | *rq = orq; | ||||||||
8803 | orq->orq_rprev = rq; | ||||||||
8804 | |||||||||
8805 | if (interval == orq->orq_agent->sa_t1) | ||||||||
8806 | orq->orq_agent->sa_out.re_t1 = rq; | ||||||||
8807 | } | ||||||||
8808 | |||||||||
8809 | static | ||||||||
8810 | void outgoing_reset_timer(nta_outgoing_t *orq) | ||||||||
8811 | { | ||||||||
8812 | if (orq->orq_rprev) { | ||||||||
8813 | if ((*orq->orq_rprev = orq->orq_rnext)) | ||||||||
8814 | orq->orq_rnext->orq_rprev = orq->orq_rprev; | ||||||||
8815 | if (orq->orq_agent->sa_out.re_t1 == &orq->orq_rnext) | ||||||||
8816 | orq->orq_agent->sa_out.re_t1 = orq->orq_rprev; | ||||||||
8817 | orq->orq_agent->sa_out.re_length--; | ||||||||
8818 | } | ||||||||
8819 | |||||||||
8820 | orq->orq_interval = 0, orq->orq_retry = 0; | ||||||||
8821 | orq->orq_rnext = NULL((void*)0), orq->orq_rprev = NULL((void*)0); | ||||||||
8822 | } | ||||||||
8823 | |||||||||
8824 | /** @internal | ||||||||
8825 | * Free resources associated with the request. | ||||||||
8826 | */ | ||||||||
8827 | static | ||||||||
8828 | void outgoing_free(nta_outgoing_t *orq) | ||||||||
8829 | { | ||||||||
8830 | 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__ , 8830, "nta: outgoing_free(%p)\n", (void *)orq)) : (void)0); | ||||||||
8831 | assert(orq->orq_forks == NULL && orq->orq_forking == NULL)((void) sizeof ((orq->orq_forks == ((void*)0) && orq ->orq_forking == ((void*)0)) ? 1 : 0), __extension__ ({ if (orq->orq_forks == ((void*)0) && orq->orq_forking == ((void*)0)) ; else __assert_fail ("orq->orq_forks == NULL && orq->orq_forking == NULL" , "nta.c", 8831, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
8832 | outgoing_cut_off(orq); | ||||||||
8833 | outgoing_reclaim(orq); | ||||||||
8834 | } | ||||||||
8835 | |||||||||
8836 | /** Remove outgoing request from hash tables */ | ||||||||
8837 | su_inlinestatic inline void | ||||||||
8838 | outgoing_cut_off(nta_outgoing_t *orq) | ||||||||
8839 | { | ||||||||
8840 | nta_agent_t *agent = orq->orq_agent; | ||||||||
8841 | |||||||||
8842 | if (orq->orq_default) | ||||||||
8843 | agent->sa_default_outgoing = NULL((void*)0); | ||||||||
8844 | |||||||||
8845 | if (orq->orq_inserted) | ||||||||
8846 | outgoing_htable_remove(agent->sa_outgoing, orq), orq->orq_inserted = 0; | ||||||||
8847 | |||||||||
8848 | if (outgoing_is_queued(orq)) | ||||||||
8849 | outgoing_remove(orq); | ||||||||
8850 | |||||||||
8851 | #if 0 | ||||||||
8852 | if (orq->orq_forked) | ||||||||
8853 | outgoing_remove_fork(orq); | ||||||||
8854 | #endif | ||||||||
8855 | |||||||||
8856 | outgoing_reset_timer(orq); | ||||||||
8857 | |||||||||
8858 | if (orq->orq_pending) { | ||||||||
8859 | tport_release(orq->orq_tport, orq->orq_pending, | ||||||||
8860 | orq->orq_request, NULL((void*)0), orq, 0); | ||||||||
8861 | } | ||||||||
8862 | orq->orq_pending = 0; | ||||||||
8863 | |||||||||
8864 | if (orq->orq_cc) | ||||||||
8865 | nta_compartment_decref(&orq->orq_cc); | ||||||||
8866 | |||||||||
8867 | if (orq->orq_tport) | ||||||||
8868 | tport_decref(&orq->orq_tport); | ||||||||
8869 | } | ||||||||
8870 | |||||||||
8871 | /** Reclaim outgoing request */ | ||||||||
8872 | su_inlinestatic inline | ||||||||
8873 | void outgoing_reclaim(nta_outgoing_t *orq) | ||||||||
8874 | { | ||||||||
8875 | if (orq->orq_status2b) | ||||||||
8876 | *orq->orq_status2b = -1; | ||||||||
8877 | |||||||||
8878 | if (orq->orq_request) | ||||||||
8879 | msg_destroy(orq->orq_request), orq->orq_request = NULL((void*)0); | ||||||||
8880 | if (orq->orq_response) | ||||||||
8881 | msg_destroy(orq->orq_response), orq->orq_response = NULL((void*)0); | ||||||||
8882 | #if HAVE_SOFIA_SRESOLV1 | ||||||||
8883 | if (orq->orq_resolver) | ||||||||
8884 | outgoing_destroy_resolver(orq); | ||||||||
8885 | #endif | ||||||||
8886 | su_free(orq->orq_agent->sa_home, orq); | ||||||||
8887 | } | ||||||||
8888 | |||||||||
8889 | /** Queue request to be freed */ | ||||||||
8890 | su_inlinestatic inline | ||||||||
8891 | void outgoing_free_queue(outgoing_queue_t *q, nta_outgoing_t *orq) | ||||||||
8892 | { | ||||||||
8893 | outgoing_cut_off(orq); | ||||||||
8894 | outgoing_queue(q, orq); | ||||||||
8895 | } | ||||||||
8896 | |||||||||
8897 | /** Reclaim memory used by queue of requests */ | ||||||||
8898 | static | ||||||||
8899 | void outgoing_reclaim_queued(su_root_magic_t *rm, | ||||||||
8900 | su_msg_r msg, | ||||||||
8901 | union sm_arg_u *u) | ||||||||
8902 | { | ||||||||
8903 | outgoing_queue_t *q = u->a_outgoing_queue; | ||||||||
8904 | nta_outgoing_t *orq, *orq_next; | ||||||||
8905 | |||||||||
8906 | 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__ , 8907, "outgoing_reclaim_all(%p, %p, %p)\n", (void *)rm, (void *)msg, (void *)u)) : (void)0) | ||||||||
8907 | (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__ , 8907, "outgoing_reclaim_all(%p, %p, %p)\n", (void *)rm, (void *)msg, (void *)u)) : (void)0); | ||||||||
8908 | |||||||||
8909 | for (orq = q->q_head; orq; orq = orq_next) { | ||||||||
8910 | orq_next = orq->orq_next; | ||||||||
8911 | outgoing_reclaim(orq); | ||||||||
8912 | } | ||||||||
8913 | } | ||||||||
8914 | |||||||||
8915 | /** @internal Default callback for request */ | ||||||||
8916 | int outgoing_default_cb(nta_outgoing_magic_t *magic, | ||||||||
8917 | nta_outgoing_t *orq, | ||||||||
8918 | sip_t const *sip) | ||||||||
8919 | { | ||||||||
8920 | if (sip == NULL((void*)0) || sip->sip_status->st_status >= 200) | ||||||||
8921 | outgoing_destroy(orq); | ||||||||
8922 | return 0; | ||||||||
8923 | } | ||||||||
8924 | |||||||||
8925 | /** @internal Destroy an outgoing transaction */ | ||||||||
8926 | void outgoing_destroy(nta_outgoing_t *orq) | ||||||||
8927 | { | ||||||||
8928 | if (orq->orq_terminated || orq->orq_default) { | ||||||||
8929 | if (!orq->orq_forking && !orq->orq_forks) { | ||||||||
8930 | outgoing_free(orq); | ||||||||
8931 | return; | ||||||||
8932 | } | ||||||||
8933 | } | ||||||||
8934 | /* Application is expected to handle 200 OK statelessly | ||||||||
8935 | => kill transaction immediately */ | ||||||||
8936 | else if (orq->orq_method == sip_method_invite && !orq->orq_completed | ||||||||
8937 | /* (unless transaction has been canceled) */ | ||||||||
8938 | && !orq->orq_canceled | ||||||||
8939 | /* or it has been forked */ | ||||||||
8940 | && !orq->orq_forking && !orq->orq_forks) { | ||||||||
8941 | orq->orq_destroyed = 1; | ||||||||
8942 | outgoing_terminate(orq); | ||||||||
8943 | return; | ||||||||
8944 | } | ||||||||
8945 | |||||||||
8946 | orq->orq_destroyed = 1; | ||||||||
8947 | orq->orq_callback = outgoing_default_cb; | ||||||||
8948 | orq->orq_magic = NULL((void*)0); | ||||||||
8949 | } | ||||||||
8950 | |||||||||
8951 | /** @internal Outgoing transaction timer routine. | ||||||||
8952 | * | ||||||||
8953 | */ | ||||||||
8954 | static void | ||||||||
8955 | _nta_outgoing_timer(nta_agent_t *sa) | ||||||||
8956 | { | ||||||||
8957 | uint32_t now = su_time_ms(su_now()); | ||||||||
8958 | nta_outgoing_t *orq; | ||||||||
8959 | outgoing_queue_t rq[1]; | ||||||||
8960 | size_t retransmitted = 0, terminated = 0, timeout = 0, destroyed; | ||||||||
8961 | size_t total = sa->sa_outgoing->oht_used; | ||||||||
8962 | size_t trying = sa->sa_out.re_length; | ||||||||
8963 | size_t pending = sa->sa_out.trying->q_length + | ||||||||
8964 | sa->sa_out.inv_calling->q_length; | ||||||||
8965 | size_t completed = sa->sa_out.completed->q_length + | ||||||||
8966 | sa->sa_out.inv_completed->q_length; | ||||||||
8967 | |||||||||
8968 | outgoing_queue_init(sa->sa_out.free = rq, 0); | ||||||||
8969 | |||||||||
8970 | while ((orq = sa->sa_out.re_list)) { | ||||||||
8971 | |||||||||
8972 | now = su_time_ms(su_now()); | ||||||||
8973 | |||||||||
8974 | if ((int32_t)(orq->orq_retry - now) > 0) | ||||||||
8975 | break; | ||||||||
8976 | if (retransmitted >= timer_max_retransmit) | ||||||||
8977 | break; | ||||||||
8978 | |||||||||
8979 | if (orq->orq_reliable) { | ||||||||
8980 | outgoing_reset_timer(orq); | ||||||||
8981 | |||||||||
8982 | if (!tport_is_connected(orq->orq_tport)) { | ||||||||
8983 | uint32_t tls_connect_timeout = (orq->orq_call_tls_connect_timeout_is_set) ? | ||||||||
8984 | orq->orq_call_tls_connect_timeout : sa->sa_tls_orq_connect_timeout; | ||||||||
8985 | if (su_casenmatch(orq->orq_tpn->tpn_proto, "tls", 3) && tls_connect_timeout) { | ||||||||
8986 | outgoing_remove(orq); /* Reset state - this is no resend! */ | ||||||||
8987 | if (outgoing_other_destinations(orq)) { | ||||||||
8988 | SU_DEBUG_5(("nta: timer %s fired (proto: %s), %s %s (%u)\n", "N3",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8990, "nta: timer %s fired (proto: %s), %s %s (%u)\n", "N3" , orq->orq_tpn->tpn_proto, "trying alternative server for" , orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void )0) | ||||||||
8989 | orq->orq_tpn->tpn_proto, "trying alternative server for",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8990, "nta: timer %s fired (proto: %s), %s %s (%u)\n", "N3" , orq->orq_tpn->tpn_proto, "trying alternative server for" , orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void )0) | ||||||||
8990 | 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__ , 8990, "nta: timer %s fired (proto: %s), %s %s (%u)\n", "N3" , orq->orq_tpn->tpn_proto, "trying alternative server for" , orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void )0); | ||||||||
8991 | outgoing_try_another(orq); | ||||||||
8992 | } else { | ||||||||
8993 | SU_DEBUG_5(("nta: timer %s fired (proto: %s), %s %s (%u)\n", "N3",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8995, "nta: timer %s fired (proto: %s), %s %s (%u)\n", "N3" , orq->orq_tpn->tpn_proto, "retrying for", orq->orq_method_name , orq->orq_cseq->cs_seq)) : (void)0) | ||||||||
8994 | orq->orq_tpn->tpn_proto, "retrying for",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8995, "nta: timer %s fired (proto: %s), %s %s (%u)\n", "N3" , orq->orq_tpn->tpn_proto, "retrying for", orq->orq_method_name , orq->orq_cseq->cs_seq)) : (void)0) | ||||||||
8995 | 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__ , 8995, "nta: timer %s fired (proto: %s), %s %s (%u)\n", "N3" , orq->orq_tpn->tpn_proto, "retrying for", orq->orq_method_name , orq->orq_cseq->cs_seq)) : (void)0); | ||||||||
8996 | outgoing_send(orq, 0); /* Send */ | ||||||||
8997 | } | ||||||||
8998 | } else { | ||||||||
8999 | /* | ||||||||
9000 | * Timer N3: try to use UDP if trying to send via TCP | ||||||||
9001 | * but no connection is established within SIP T4 | ||||||||
9002 | */ | ||||||||
9003 | 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__ , 9005, "nta: timer %s fired, %s %s (%u)\n", "N3", "try UDP instead for" , orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void )0) | ||||||||
9004 | "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__ , 9005, "nta: timer %s fired, %s %s (%u)\n", "N3", "try UDP instead for" , orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void )0) | ||||||||
9005 | 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__ , 9005, "nta: timer %s fired, %s %s (%u)\n", "N3", "try UDP instead for" , orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void )0); | ||||||||
9006 | outgoing_try_udp_instead(orq, 1); | ||||||||
9007 | outgoing_remove(orq); /* Reset state - this is no resend! */ | ||||||||
9008 | outgoing_send(orq, 0); /* Send */ | ||||||||
9009 | } | ||||||||
9010 | } | ||||||||
9011 | continue; | ||||||||
9012 | } | ||||||||
9013 | |||||||||
9014 | assert(!orq->orq_reliable && orq->orq_interval != 0)((void) sizeof ((!orq->orq_reliable && orq->orq_interval != 0) ? 1 : 0), __extension__ ({ if (!orq->orq_reliable && orq->orq_interval != 0) ; else __assert_fail ("!orq->orq_reliable && orq->orq_interval != 0" , "nta.c", 9014, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
9015 | |||||||||
9016 | 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__ , 9018, "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) | ||||||||
9017 | 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__ , 9018, "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) | ||||||||
9018 | "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__ , 9018, "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); | ||||||||
9019 | |||||||||
9020 | outgoing_retransmit(orq); | ||||||||
9021 | |||||||||
9022 | if (orq->orq_method == sip_method_invite || | ||||||||
9023 | 2U * orq->orq_interval < sa->sa_t2) | ||||||||
9024 | outgoing_set_timer(orq, 2U * orq->orq_interval); | ||||||||
9025 | else | ||||||||
9026 | outgoing_set_timer(orq, sa->sa_t2); | ||||||||
9027 | |||||||||
9028 | if (++retransmitted % 5 == 0) | ||||||||
9029 | su_root_yield(sa->sa_root); /* Handle received packets */ | ||||||||
9030 | } | ||||||||
9031 | |||||||||
9032 | terminated | ||||||||
9033 | = outgoing_timer_dk(sa->sa_out.inv_completed, "D", now) | ||||||||
9034 | + outgoing_timer_dk(sa->sa_out.completed, "K", now); | ||||||||
9035 | |||||||||
9036 | timeout | ||||||||
9037 | = outgoing_timer_bf(sa->sa_out.inv_calling, "B", now) | ||||||||
9038 | + outgoing_timer_c(sa->sa_out.inv_proceeding, "C", now) | ||||||||
9039 | + outgoing_timer_bf(sa->sa_out.trying, "F", now); | ||||||||
9040 | |||||||||
9041 | destroyed = outgoing_mass_destroy(sa, rq); | ||||||||
9042 | |||||||||
9043 | sa->sa_out.free = NULL((void*)0); | ||||||||
9044 | |||||||||
9045 | if (retransmitted || timeout || terminated || destroyed) { | ||||||||
9046 | 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__ , 9054, "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) | ||||||||
9047 | 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__ , 9054, "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) | ||||||||
9048 | 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__ , 9054, "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) | ||||||||
9049 | 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__ , 9054, "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) | ||||||||
9050 | 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__ , 9054, "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) | ||||||||
9051 | 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__ , 9054, "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) | ||||||||
9052 | 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__ , 9054, "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) | ||||||||
9053 | 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__ , 9054, "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) | ||||||||
9054 | 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__ , 9054, "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); | ||||||||
9055 | } | ||||||||
9056 | } | ||||||||
9057 | |||||||||
9058 | /** @internal Retransmit the outgoing request. */ | ||||||||
9059 | void outgoing_retransmit(nta_outgoing_t *orq) | ||||||||
9060 | { | ||||||||
9061 | if (orq->orq_prepared && !orq->orq_delayed) { | ||||||||
9062 | orq->orq_retries++; | ||||||||
9063 | |||||||||
9064 | if (orq->orq_retries >= 4 && orq->orq_cc) { | ||||||||
9065 | orq->orq_tpn->tpn_comp = NULL((void*)0); | ||||||||
9066 | if (orq->orq_retries == 4) { | ||||||||
9067 | agent_close_compressor(orq->orq_agent, orq->orq_cc); | ||||||||
9068 | nta_compartment_decref(&orq->orq_cc); | ||||||||
9069 | } | ||||||||
9070 | } | ||||||||
9071 | |||||||||
9072 | outgoing_send(orq, 1); | ||||||||
9073 | } | ||||||||
9074 | } | ||||||||
9075 | |||||||||
9076 | /** Trying a client transaction. */ | ||||||||
9077 | static | ||||||||
9078 | void outgoing_trying(nta_outgoing_t *orq) | ||||||||
9079 | { | ||||||||
9080 | if (orq->orq_forked) | ||||||||
9081 | ; | ||||||||
9082 | else if (orq->orq_method == sip_method_invite) { | ||||||||
9083 | if (!orq->orq_completed) { | ||||||||
9084 | outgoing_queue(orq->orq_agent->sa_out.inv_calling, orq); | ||||||||
9085 | } else { | ||||||||
9086 | SU_DEBUG_5(("nta(%p): completed request can not be put into inv_calling queue (%u)\n", (void *)orq, orq->orq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 9086, "nta(%p): completed request can not be put into inv_calling queue (%u)\n" , (void *)orq, orq->orq_cseq->cs_seq)) : (void)0); | ||||||||
9087 | if (orq->orq_queue != orq->orq_agent->sa_out.inv_completed) { | ||||||||
9088 | /* Put back into inv_completed if it's not there by any reason */ | ||||||||
9089 | outgoing_queue(orq->orq_agent->sa_out.inv_completed, orq); /* Timer D */ | ||||||||
9090 | } | ||||||||
9091 | } | ||||||||
9092 | } | ||||||||
9093 | else | ||||||||
9094 | outgoing_queue(orq->orq_agent->sa_out.trying, orq); | ||||||||
9095 | } | ||||||||
9096 | |||||||||
9097 | /** Handle timers B and F */ | ||||||||
9098 | static | ||||||||
9099 | size_t outgoing_timer_bf(outgoing_queue_t *q, | ||||||||
9100 | char const *timer, | ||||||||
9101 | uint32_t now) | ||||||||
9102 | { | ||||||||
9103 | nta_outgoing_t *orq; | ||||||||
9104 | size_t timeout = 0; | ||||||||
9105 | |||||||||
9106 | while ((orq = q->q_head)) { | ||||||||
9107 | if ((int32_t)(orq->orq_timeout - now) > 0 || | ||||||||
9108 | timeout >= timer_max_timeout) | ||||||||
9109 | break; | ||||||||
9110 | |||||||||
9111 | timeout++; | ||||||||
9112 | |||||||||
9113 | 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__ , 9116, "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) | ||||||||
9114 | 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__ , 9116, "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) | ||||||||
9115 | 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__ , 9116, "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) | ||||||||
9116 | 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__ , 9116, "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); | ||||||||
9117 | |||||||||
9118 | if (orq->orq_method != sip_method_ack) | ||||||||
9119 | outgoing_timeout(orq, now); | ||||||||
9120 | else | ||||||||
9121 | outgoing_terminate(orq); | ||||||||
9122 | |||||||||
9123 | assert(q->q_head != orq || (int32_t)(orq->orq_timeout - now) > 0)((void) sizeof ((q->q_head != orq || (int32_t)(orq->orq_timeout - now) > 0) ? 1 : 0), __extension__ ({ if (q->q_head != orq || (int32_t)(orq->orq_timeout - now) > 0) ; else __assert_fail ("q->q_head != orq || (int32_t)(orq->orq_timeout - now) > 0" , "nta.c", 9123, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
9124 | } | ||||||||
9125 | |||||||||
9126 | return timeout; | ||||||||
9127 | } | ||||||||
9128 | |||||||||
9129 | /** Handle timer C */ | ||||||||
9130 | static | ||||||||
9131 | size_t outgoing_timer_c(outgoing_queue_t *q, | ||||||||
9132 | char const *timer, | ||||||||
9133 | uint32_t now) | ||||||||
9134 | { | ||||||||
9135 | nta_outgoing_t *orq; | ||||||||
9136 | size_t timeout = 0; | ||||||||
9137 | |||||||||
9138 | if (q->q_timeout == 0) | ||||||||
9139 | return 0; | ||||||||
9140 | |||||||||
9141 | while ((orq = q->q_head)) { | ||||||||
9142 | if ((int32_t)(orq->orq_timeout - now) > 0 || timeout >= timer_max_timeout) | ||||||||
9143 | break; | ||||||||
9144 | |||||||||
9145 | timeout++; | ||||||||
9146 | |||||||||
9147 | 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__ , 9149, "nta: timer %s fired, %s %s (%u)\n", timer, "CANCEL and timeout" , orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void )0) | ||||||||
9148 | 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__ , 9149, "nta: timer %s fired, %s %s (%u)\n", timer, "CANCEL and timeout" , orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void )0) | ||||||||
9149 | 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__ , 9149, "nta: timer %s fired, %s %s (%u)\n", timer, "CANCEL and timeout" , orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void )0); | ||||||||
9150 | /* | ||||||||
9151 | * If the client transaction has received a provisional response, the | ||||||||
9152 | * proxy MUST generate a CANCEL request matching that transaction. | ||||||||
9153 | */ | ||||||||
9154 | nta_outgoing_tcancel(orq, NULL((void*)0), NULL((void*)0), TAG_NULL()(tag_type_t)0, (tag_value_t)0); | ||||||||
9155 | } | ||||||||
9156 | |||||||||
9157 | return timeout; | ||||||||
9158 | } | ||||||||
9159 | |||||||||
9160 | /** @internal Signal transaction timeout to the application. */ | ||||||||
9161 | void outgoing_timeout(nta_outgoing_t *orq, uint32_t now) | ||||||||
9162 | { | ||||||||
9163 | nta_outgoing_t *cancel = NULL((void*)0); | ||||||||
9164 | |||||||||
9165 | if (orq->orq_status || orq->orq_canceled) | ||||||||
9166 | ; | ||||||||
9167 | else if (outgoing_other_destinations(orq)) { | ||||||||
9168 | 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__ , 9169, "%s(%p): %s\n", "nta", (void *)orq, "try next after timeout" )) : (void)0) | ||||||||
9169 | "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__ , 9169, "%s(%p): %s\n", "nta", (void *)orq, "try next after timeout" )) : (void)0); | ||||||||
9170 | outgoing_try_another(orq); | ||||||||
9171 | return; | ||||||||
9172 | } | ||||||||
9173 | |||||||||
9174 | cancel = orq->orq_cancel, orq->orq_cancel = NULL((void*)0); | ||||||||
9175 | orq->orq_agent->sa_stats->as_tout_request++; | ||||||||
9176 | |||||||||
9177 | outgoing_reply(orq, SIP_408_REQUEST_TIMEOUT408, sip_408_Request_timeout, 0); | ||||||||
9178 | |||||||||
9179 | if (cancel) | ||||||||
9180 | outgoing_timeout(cancel, now); | ||||||||
9181 | } | ||||||||
9182 | |||||||||
9183 | /** Complete a client transaction. | ||||||||
9184 | * | ||||||||
9185 | * @return True if transaction was free()d. | ||||||||
9186 | */ | ||||||||
9187 | static int | ||||||||
9188 | outgoing_complete(nta_outgoing_t *orq) | ||||||||
9189 | { | ||||||||
9190 | orq->orq_completed = 1; | ||||||||
9191 | |||||||||
9192 | outgoing_reset_timer(orq); /* Timer A / Timer E */ | ||||||||
9193 | |||||||||
9194 | if (orq->orq_stateless) | ||||||||
9195 | return outgoing_terminate(orq); | ||||||||
9196 | |||||||||
9197 | if (orq->orq_forked) { | ||||||||
9198 | outgoing_remove_fork(orq); | ||||||||
9199 | return outgoing_terminate(orq); | ||||||||
9200 | } | ||||||||
9201 | |||||||||
9202 | if (orq->orq_reliable) { | ||||||||
9203 | if (orq->orq_method != sip_method_invite || !orq->orq_uas) | ||||||||
9204 | return outgoing_terminate(orq); | ||||||||
9205 | } | ||||||||
9206 | |||||||||
9207 | if (orq->orq_method == sip_method_invite) { | ||||||||
9208 | if (orq->orq_queue != orq->orq_agent->sa_out.inv_completed) | ||||||||
9209 | outgoing_queue(orq->orq_agent->sa_out.inv_completed, orq); /* Timer D */ | ||||||||
9210 | } | ||||||||
9211 | else { | ||||||||
9212 | outgoing_queue(orq->orq_agent->sa_out.completed, orq); /* Timer K */ | ||||||||
9213 | } | ||||||||
9214 | |||||||||
9215 | return 0; | ||||||||
9216 | } | ||||||||
9217 | |||||||||
9218 | /** Handle timers D and K */ | ||||||||
9219 | static | ||||||||
9220 | size_t outgoing_timer_dk(outgoing_queue_t *q, | ||||||||
9221 | char const *timer, | ||||||||
9222 | uint32_t now) | ||||||||
9223 | { | ||||||||
9224 | nta_outgoing_t *orq; | ||||||||
9225 | size_t terminated = 0; | ||||||||
9226 | |||||||||
9227 | while ((orq = q->q_head)) { | ||||||||
9228 | if ((int32_t)(orq->orq_timeout - now) > 0 || | ||||||||
9229 | terminated >= timer_max_terminate) | ||||||||
9230 | break; | ||||||||
9231 | |||||||||
9232 | terminated++; | ||||||||
9233 | |||||||||
9234 | 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__ , 9235, "nta: timer %s fired, %s %s (%u)\n", timer, "terminate" , orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void )0) | ||||||||
9235 | "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__ , 9235, "nta: timer %s fired, %s %s (%u)\n", timer, "terminate" , orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void )0); | ||||||||
9236 | |||||||||
9237 | if (orq->orq_method == sip_method_invite) | ||||||||
9238 | outgoing_terminate_invite(orq); | ||||||||
9239 | else | ||||||||
9240 | outgoing_terminate(orq); | ||||||||
9241 | } | ||||||||
9242 | |||||||||
9243 | return terminated; | ||||||||
9244 | } | ||||||||
9245 | |||||||||
9246 | |||||||||
9247 | /** Terminate an INVITE client transaction. */ | ||||||||
9248 | static void | ||||||||
9249 | outgoing_terminate_invite(nta_outgoing_t *original) | ||||||||
9250 | { | ||||||||
9251 | nta_outgoing_t *orq = original; | ||||||||
9252 | |||||||||
9253 | while (original->orq_forks) { | ||||||||
9254 | orq = original->orq_forks; | ||||||||
9255 | original->orq_forks = orq->orq_forks; | ||||||||
9256 | |||||||||
9257 | assert(orq->orq_forking == original)((void) sizeof ((orq->orq_forking == original) ? 1 : 0), __extension__ ({ if (orq->orq_forking == original) ; else __assert_fail ("orq->orq_forking == original", "nta.c", 9257, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
9258 | |||||||||
9259 | 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__ , 9261, "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) | ||||||||
9260 | "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__ , 9261, "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) | ||||||||
9261 | 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__ , 9261, "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); | ||||||||
9262 | |||||||||
9263 | orq->orq_forking = NULL((void*)0), orq->orq_forks = NULL((void*)0), orq->orq_forked = 0; | ||||||||
9264 | |||||||||
9265 | if (outgoing_terminate(orq)) | ||||||||
9266 | continue; | ||||||||
9267 | |||||||||
9268 | if (orq->orq_status < 200) { | ||||||||
9269 | /* Fork has timed out */ | ||||||||
9270 | orq->orq_agent->sa_stats->as_tout_request++; | ||||||||
9271 | outgoing_reply(orq, SIP_408_REQUEST_TIMEOUT408, sip_408_Request_timeout, 0); | ||||||||
9272 | } | ||||||||
9273 | } | ||||||||
9274 | |||||||||
9275 | if (outgoing_terminate(orq = original)) | ||||||||
9276 | return; | ||||||||
9277 | |||||||||
9278 | if (orq->orq_status < 200) { | ||||||||
9279 | /* Original INVITE has timed out */ | ||||||||
9280 | orq->orq_agent->sa_stats->as_tout_request++; | ||||||||
9281 | outgoing_reply(orq, SIP_408_REQUEST_TIMEOUT408, sip_408_Request_timeout, 0); | ||||||||
9282 | } | ||||||||
9283 | } | ||||||||
9284 | |||||||||
9285 | static void | ||||||||
9286 | outgoing_remove_fork(nta_outgoing_t *orq) | ||||||||
9287 | { | ||||||||
9288 | nta_outgoing_t **slot; | ||||||||
9289 | |||||||||
9290 | for (slot = &orq->orq_forking->orq_forks; | ||||||||
9291 | slot && *slot; | ||||||||
9292 | slot = &(*slot)->orq_forks) { | ||||||||
9293 | if (orq == *slot) { | ||||||||
9294 | *slot = orq->orq_forks; | ||||||||
9295 | orq->orq_forks = NULL((void*)0); | ||||||||
9296 | orq->orq_forking = NULL((void*)0); | ||||||||
9297 | orq->orq_forked = 0; | ||||||||
9298 | } | ||||||||
9299 | } | ||||||||
9300 | |||||||||
9301 | assert(orq == NULL)((void) sizeof ((orq == ((void*)0)) ? 1 : 0), __extension__ ( { if (orq == ((void*)0)) ; else __assert_fail ("orq == NULL", "nta.c", 9301, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
9302 | } | ||||||||
9303 | |||||||||
9304 | /** Terminate a client transaction. */ | ||||||||
9305 | static | ||||||||
9306 | int outgoing_terminate(nta_outgoing_t *orq) | ||||||||
9307 | { | ||||||||
9308 | orq->orq_terminated = 1; | ||||||||
9309 | |||||||||
9310 | if (!orq->orq_destroyed) { | ||||||||
9311 | outgoing_queue(orq->orq_agent->sa_out.terminated, orq); | ||||||||
9312 | return 0; | ||||||||
9313 | } | ||||||||
9314 | else if (orq->orq_agent->sa_out.free) { | ||||||||
9315 | outgoing_free_queue(orq->orq_agent->sa_out.free, orq); | ||||||||
9316 | return 1; | ||||||||
9317 | } | ||||||||
9318 | else { | ||||||||
9319 | outgoing_free(orq); | ||||||||
9320 | return 1; | ||||||||
9321 | } | ||||||||
9322 | } | ||||||||
9323 | |||||||||
9324 | /** Mass destroy client transactions */ | ||||||||
9325 | static | ||||||||
9326 | size_t outgoing_mass_destroy(nta_agent_t *sa, outgoing_queue_t *q) | ||||||||
9327 | { | ||||||||
9328 | size_t destroyed = q->q_length; | ||||||||
9329 | |||||||||
9330 | if (destroyed > 2 && *sa->sa_terminator) { | ||||||||
9331 | su_msg_r m = SU_MSG_R_INIT{ ((void*)0) }; | ||||||||
9332 | |||||||||
9333 | if (su_msg_create(m, | ||||||||
9334 | su_clone_task(sa->sa_terminator), | ||||||||
9335 | su_root_task(sa->sa_root), | ||||||||
9336 | outgoing_reclaim_queued, | ||||||||
9337 | sizeof(outgoing_queue_t)) == SU_SUCCESSsu_success) { | ||||||||
9338 | outgoing_queue_t *mq = su_msg_data(m)->a_outgoing_queue; | ||||||||
9339 | |||||||||
9340 | *mq = *q; | ||||||||
9341 | |||||||||
9342 | if (su_msg_send(m) == SU_SUCCESSsu_success) | ||||||||
9343 | q->q_length = 0; | ||||||||
9344 | } | ||||||||
9345 | } | ||||||||
9346 | |||||||||
9347 | if (q->q_length) | ||||||||
9348 | outgoing_reclaim_queued(NULL((void*)0), NULL((void*)0), (void*)q); | ||||||||
9349 | |||||||||
9350 | return destroyed; | ||||||||
9351 | } | ||||||||
9352 | |||||||||
9353 | /** Find an outgoing request corresponging to a message and @Via line. | ||||||||
9354 | * | ||||||||
9355 | * Return an outgoing request object based on a message and the @Via line | ||||||||
9356 | * given as argument. This function is used when doing loop checking: if we | ||||||||
9357 | * have sent the request and it has been routed back to us. | ||||||||
9358 | * | ||||||||
9359 | * @param agent | ||||||||
9360 | * @param msg | ||||||||
9361 | * @param sip | ||||||||
9362 | * @param v | ||||||||
9363 | */ | ||||||||
9364 | nta_outgoing_t *nta_outgoing_find(nta_agent_t const *agent, | ||||||||
9365 | msg_t const *msg, | ||||||||
9366 | sip_t const *sip, | ||||||||
9367 | sip_via_t const *v) | ||||||||
9368 | { | ||||||||
9369 | if (agent == NULL((void*)0) || msg == NULL((void*)0) || sip == NULL((void*)0) || v == NULL((void*)0)) { | ||||||||
9370 | su_seterrno(EFAULT14); | ||||||||
9371 | return NULL((void*)0); | ||||||||
9372 | } | ||||||||
9373 | |||||||||
9374 | return outgoing_find(agent, msg, sip, v); | ||||||||
9375 | } | ||||||||
9376 | |||||||||
9377 | /**@internal | ||||||||
9378 | * | ||||||||
9379 | * Find an outgoing request corresponging to a message and @Via line. | ||||||||
9380 | * | ||||||||
9381 | */ | ||||||||
9382 | nta_outgoing_t *outgoing_find(nta_agent_t const *sa, | ||||||||
9383 | msg_t const *msg, | ||||||||
9384 | sip_t const *sip, | ||||||||
9385 | sip_via_t const *v) | ||||||||
9386 | { | ||||||||
9387 | nta_outgoing_t **oo, *orq; | ||||||||
9388 | outgoing_htable_t const *oht = sa->sa_outgoing; | ||||||||
9389 | sip_cseq_t const *cseq = sip->sip_cseq; | ||||||||
9390 | sip_call_id_t const *i = sip->sip_call_id; | ||||||||
9391 | hash_value_t hash; | ||||||||
9392 | sip_method_t method, method2; | ||||||||
9393 | unsigned short status = sip->sip_status ? sip->sip_status->st_status : 0; | ||||||||
9394 | |||||||||
9395 | if (cseq == NULL((void*)0)) | ||||||||
9396 | return NULL((void*)0); | ||||||||
9397 | |||||||||
9398 | hash = NTA_HASH(i, cseq->cs_seq)((i)->i_hash + 26839U * (uint32_t)(cseq->cs_seq)); | ||||||||
9399 | |||||||||
9400 | method = cseq->cs_method; | ||||||||
9401 | |||||||||
9402 | /* Get original invite when ACKing */ | ||||||||
9403 | if (sip->sip_request && method == sip_method_ack && v == NULL((void*)0)) | ||||||||
9404 | method = sip_method_invite, method2 = sip_method_invalid; | ||||||||
9405 | else if (sa->sa_is_a_uas && 200 <= status && status < 300 && method == sip_method_invite) | ||||||||
9406 | method2 = sip_method_ack; | ||||||||
9407 | else | ||||||||
9408 | method2 = method; | ||||||||
9409 | |||||||||
9410 | for (oo = outgoing_htable_hash(oht, hash); | ||||||||
9411 | (orq = *oo); | ||||||||
9412 | oo = outgoing_htable_next(oht, oo)) { | ||||||||
9413 | if (orq->orq_stateless) | ||||||||
9414 | continue; | ||||||||
9415 | /* Accept terminated transactions when looking for original INVITE */ | ||||||||
9416 | if (orq->orq_terminated && method2 != sip_method_invalid) | ||||||||
9417 | continue; | ||||||||
9418 | if (hash != orq->orq_hash) | ||||||||
9419 | continue; | ||||||||
9420 | if (orq->orq_call_id->i_hash != i->i_hash || | ||||||||
9421 | strcmp(orq->orq_call_id->i_id, i->i_id)) | ||||||||
9422 | continue; | ||||||||
9423 | if (orq->orq_cseq->cs_seq != cseq->cs_seq) | ||||||||
9424 | continue; | ||||||||
9425 | if (method == sip_method_unknown && | ||||||||
9426 | strcmp(orq->orq_cseq->cs_method_name, cseq->cs_method_name)) | ||||||||
9427 | continue; | ||||||||
9428 | if (orq->orq_method != method && orq->orq_method != method2) | ||||||||
9429 | continue; | ||||||||
9430 | if (su_strcasecmp(orq->orq_from->a_tag, sip->sip_from->a_tag)) | ||||||||
9431 | continue; | ||||||||
9432 | if (orq->orq_to->a_tag && | ||||||||
9433 | su_strcasecmp(orq->orq_to->a_tag, sip->sip_to->a_tag)) | ||||||||
9434 | continue; | ||||||||
9435 | |||||||||
9436 | if (orq->orq_method == sip_method_ack && 300 <= status) | ||||||||
9437 | continue; | ||||||||
9438 | |||||||||
9439 | if (v && !su_casematch(orq->orq_branch + strlen("branch="), v->v_branch)) | ||||||||
9440 | continue; | ||||||||
9441 | |||||||||
9442 | break; /* match */ | ||||||||
9443 | } | ||||||||
9444 | |||||||||
9445 | return orq; | ||||||||
9446 | } | ||||||||
9447 | |||||||||
9448 | /** Process a response message. */ | ||||||||
9449 | int outgoing_recv(nta_outgoing_t *_orq, | ||||||||
9450 | int status, | ||||||||
9451 | msg_t *msg, | ||||||||
9452 | sip_t *sip) | ||||||||
9453 | { | ||||||||
9454 | nta_outgoing_t *orq = _orq->orq_forking ? _orq->orq_forking : _orq; | ||||||||
9455 | nta_agent_t *sa = orq->orq_agent; | ||||||||
9456 | int internal = sip == NULL((void*)0) || (sip->sip_flags & NTA_INTERNAL_MSG(1<<15)) != 0; | ||||||||
9457 | |||||||||
9458 | assert(!internal || status >= 300)((void) sizeof ((!internal || status >= 300) ? 1 : 0), __extension__ ({ if (!internal || status >= 300) ; else __assert_fail ( "!internal || status >= 300", "nta.c", 9458, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
9459 | assert(orq == _orq || orq->orq_method == sip_method_invite)((void) sizeof ((orq == _orq || orq->orq_method == sip_method_invite ) ? 1 : 0), __extension__ ({ if (orq == _orq || orq->orq_method == sip_method_invite) ; else __assert_fail ("orq == _orq || orq->orq_method == sip_method_invite" , "nta.c", 9459, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
9460 | |||||||||
9461 | if (status < 100) status = 100; | ||||||||
9462 | |||||||||
9463 | if (!internal && orq->orq_delay == UINT_MAX(2147483647 *2U +1U)) | ||||||||
9464 | outgoing_estimate_delay(orq, sip); | ||||||||
9465 | |||||||||
9466 | if (orq->orq_cc) | ||||||||
9467 | agent_accept_compressed(orq->orq_agent, msg, orq->orq_cc); | ||||||||
9468 | |||||||||
9469 | if (orq->orq_cancel) { | ||||||||
9470 | nta_outgoing_t *cancel; | ||||||||
9471 | cancel = orq->orq_cancel; orq->orq_cancel = NULL((void*)0); | ||||||||
9472 | cancel->orq_delayed = 0; | ||||||||
9473 | |||||||||
9474 | if (status < 200) { | ||||||||
9475 | outgoing_send(cancel, 0); | ||||||||
9476 | outgoing_complete(orq); | ||||||||
9477 | } | ||||||||
9478 | else { | ||||||||
9479 | outgoing_reply(cancel, SIP_481_NO_TRANSACTION481, sip_481_No_transaction, 0); | ||||||||
9480 | } | ||||||||
9481 | } | ||||||||
9482 | |||||||||
9483 | if (orq->orq_pending) { | ||||||||
9484 | tport_release(orq->orq_tport, orq->orq_pending, orq->orq_request, | ||||||||
9485 | msg, orq, status < 200); | ||||||||
9486 | if (status >= 200) | ||||||||
9487 | orq->orq_pending = 0; | ||||||||
9488 | } | ||||||||
9489 | |||||||||
9490 | /* The state machines */ | ||||||||
9491 | if (orq->orq_method == sip_method_invite) { | ||||||||
9492 | nta_outgoing_t *original = orq; | ||||||||
9493 | |||||||||
9494 | orq = _orq; | ||||||||
9495 | |||||||||
9496 | if (orq->orq_destroyed && 200 <= status && status < 300) { | ||||||||
9497 | if (orq->orq_uas && su_strcasecmp(sip->sip_to->a_tag, orq->orq_tag) != 0) { | ||||||||
9498 | /* Orphan 200 Ok to INVITE. ACK and BYE it */ | ||||||||
9499 | 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__ , 9499, "nta: Orphan 200 Ok send ACK&BYE %p\n", (void *)orq )) : (void)0); | ||||||||
9500 | return nta_msg_ackbye(sa, msg); | ||||||||
9501 | } | ||||||||
9502 | return -1; /* Proxy statelessly (RFC3261 section 16.11) */ | ||||||||
9503 | } | ||||||||
9504 | |||||||||
9505 | outgoing_reset_timer(original); /* Retransmission */ | ||||||||
9506 | |||||||||
9507 | if (status < 200) { | ||||||||
9508 | if (original->orq_status < 200) | ||||||||
9509 | original->orq_status = status; | ||||||||
9510 | if (orq->orq_status < 200) | ||||||||
9511 | orq->orq_status = status; | ||||||||
9512 | |||||||||
9513 | if (original->orq_queue == sa->sa_out.inv_calling) { | ||||||||
9514 | outgoing_queue(sa->sa_out.inv_proceeding, original); | ||||||||
9515 | } | ||||||||
9516 | else if (original->orq_queue == sa->sa_out.inv_proceeding) { | ||||||||
9517 | if (sa->sa_out.inv_proceeding->q_timeout) { | ||||||||
9518 | outgoing_remove(original); | ||||||||
9519 | outgoing_queue(sa->sa_out.inv_proceeding, original); | ||||||||
9520 | } | ||||||||
9521 | } | ||||||||
9522 | |||||||||
9523 | /* Handle 100rel */ | ||||||||
9524 | if (sip && sip->sip_rseq) { | ||||||||
9525 | if (outgoing_recv_reliable(orq, msg, sip) < 0) { | ||||||||
9526 | msg_destroy(msg); | ||||||||
9527 | return 0; | ||||||||
9528 | } | ||||||||
9529 | } | ||||||||
9530 | } | ||||||||
9531 | else { | ||||||||
9532 | /* Final response */ | ||||||||
9533 | if (status >= 300 && !internal) | ||||||||
9534 | outgoing_ack(original, sip); | ||||||||
9535 | |||||||||
9536 | if (!original->orq_completed) { | ||||||||
9537 | if (outgoing_complete(original)) | ||||||||
9538 | return 0; | ||||||||
9539 | |||||||||
9540 | if (orq->orq_uas && sip && orq == original) { | ||||||||
9541 | /* | ||||||||
9542 | * We silently discard duplicate final responses to INVITE below | ||||||||
9543 | * with outgoing_duplicate() | ||||||||
9544 | */ | ||||||||
9545 | su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request)); | ||||||||
9546 | orq->orq_tag = su_strdup(home, sip->sip_to->a_tag); | ||||||||
9547 | } | ||||||||
9548 | } | ||||||||
9549 | /* Retransmission or response from another fork */ | ||||||||
9550 | else if (orq->orq_status >= 200) { | ||||||||
9551 | /* Once 2xx has been received, non-2xx will not be forwarded */ | ||||||||
9552 | if (status >= 300) | ||||||||
9553 | return outgoing_duplicate(orq, msg, sip); | ||||||||
9554 | |||||||||
9555 | if (orq->orq_uas) { | ||||||||
9556 | if (su_strcasecmp(sip->sip_to->a_tag, orq->orq_tag) == 0) | ||||||||
9557 | /* Catch retransmission */ | ||||||||
9558 | return outgoing_duplicate(orq, msg, sip); | ||||||||
9559 | |||||||||
9560 | /* Orphan 200 Ok to INVITE. ACK and BYE it */ | ||||||||
9561 | 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__ , 9561, "nta: Orphan 200 Ok send ACK&BYE" "%s", "")) : (void )0); | ||||||||
9562 | return nta_msg_ackbye(sa, msg); | ||||||||
9563 | } | ||||||||
9564 | } | ||||||||
9565 | |||||||||
9566 | orq->orq_status = status; | ||||||||
9567 | } | ||||||||
9568 | } | ||||||||
9569 | else if (orq->orq_method != sip_method_ack) { | ||||||||
9570 | /* Non-INVITE */ | ||||||||
9571 | if (orq->orq_queue == sa->sa_out.trying || | ||||||||
9572 | orq->orq_queue == sa->sa_out.resolving) { | ||||||||
9573 | /* hacked by freeswitch, this is being hit by options 404 status with 404 orq->orq_status and orq_destroyed = 1, orq_completed = 1 */ | ||||||||
9574 | /* assert(orq->orq_status < 200); */ | ||||||||
9575 | if (orq->orq_status >= 200) {msg_destroy(msg); return 0;} | ||||||||
9576 | |||||||||
9577 | if (status < 200) { | ||||||||
9578 | /* @RFC3261 17.1.2.1: | ||||||||
9579 | * retransmissions continue for unreliable transports, | ||||||||
9580 | * but at an interval of T2. | ||||||||
9581 | * | ||||||||
9582 | * @RFC4321 1.2: | ||||||||
9583 | * Note that Timer E is not altered during the transition | ||||||||
9584 | * to Proceeding. | ||||||||
9585 | */ | ||||||||
9586 | if (!orq->orq_reliable) | ||||||||
9587 | orq->orq_interval = sa->sa_t2; | ||||||||
9588 | } | ||||||||
9589 | else if (!outgoing_complete(orq)) { | ||||||||
9590 | if (orq->orq_sigcomp_zap && orq->orq_tport && orq->orq_cc) | ||||||||
9591 | agent_zap_compressor(orq->orq_agent, orq->orq_cc); | ||||||||
9592 | } | ||||||||
9593 | else /* outgoing_complete */ { | ||||||||
9594 | msg_destroy(msg); | ||||||||
9595 | return 0; | ||||||||
9596 | } | ||||||||
9597 | } | ||||||||
9598 | else { | ||||||||
9599 | /* Already completed or terminated */ | ||||||||
9600 | assert(orq->orq_queue == sa->sa_out.completed ||((void) sizeof ((orq->orq_queue == sa->sa_out.completed || orq->orq_queue == sa->sa_out.terminated) ? 1 : 0), __extension__ ({ if (orq->orq_queue == sa->sa_out.completed || orq-> orq_queue == sa->sa_out.terminated) ; else __assert_fail ( "orq->orq_queue == sa->sa_out.completed || orq->orq_queue == sa->sa_out.terminated" , "nta.c", 9601, __extension__ __PRETTY_FUNCTION__); })) | ||||||||
9601 | orq->orq_queue == sa->sa_out.terminated)((void) sizeof ((orq->orq_queue == sa->sa_out.completed || orq->orq_queue == sa->sa_out.terminated) ? 1 : 0), __extension__ ({ if (orq->orq_queue == sa->sa_out.completed || orq-> orq_queue == sa->sa_out.terminated) ; else __assert_fail ( "orq->orq_queue == sa->sa_out.completed || orq->orq_queue == sa->sa_out.terminated" , "nta.c", 9601, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
9602 | assert(orq->orq_status >= 200)((void) sizeof ((orq->orq_status >= 200) ? 1 : 0), __extension__ ({ if (orq->orq_status >= 200) ; else __assert_fail ("orq->orq_status >= 200" , "nta.c", 9602, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
9603 | return outgoing_duplicate(orq, msg, sip); | ||||||||
9604 | } | ||||||||
9605 | |||||||||
9606 | orq->orq_status = status; | ||||||||
9607 | } | ||||||||
9608 | else { | ||||||||
9609 | /* ACK */ | ||||||||
9610 | if (sip && (sip->sip_flags & NTA_INTERNAL_MSG(1<<15)) == 0) | ||||||||
9611 | /* Received re-transmitted final reply to INVITE, retransmit ACK */ | ||||||||
9612 | outgoing_retransmit(orq); | ||||||||
9613 | msg_destroy(msg); | ||||||||
9614 | return 0; | ||||||||
9615 | } | ||||||||
9616 | |||||||||
9617 | if (100 >= status + orq->orq_pass_100) { | ||||||||
9618 | msg_destroy(msg); | ||||||||
9619 | return 0; | ||||||||
9620 | } | ||||||||
9621 | |||||||||
9622 | if (orq->orq_destroyed) { | ||||||||
9623 | msg_destroy(msg); | ||||||||
9624 | return 0; | ||||||||
9625 | } | ||||||||
9626 | |||||||||
9627 | if (orq->orq_response) | ||||||||
9628 | msg_destroy(orq->orq_response); | ||||||||
9629 | orq->orq_response = msg; | ||||||||
9630 | /* Call callback */ | ||||||||
9631 | orq->orq_callback(orq->orq_magic, orq, sip); | ||||||||
9632 | return 0; | ||||||||
9633 | } | ||||||||
9634 | |||||||||
9635 | static void outgoing_default_recv(nta_outgoing_t *orq, | ||||||||
9636 | int status, | ||||||||
9637 | msg_t *msg, | ||||||||
9638 | sip_t *sip) | ||||||||
9639 | { | ||||||||
9640 | assert(sip->sip_cseq)((void) sizeof ((sip->sip_cseq) ? 1 : 0), __extension__ ({ if (sip->sip_cseq) ; else __assert_fail ("sip->sip_cseq" , "nta.c", 9640, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
9641 | |||||||||
9642 | orq->orq_status = status; | ||||||||
9643 | orq->orq_response = msg; | ||||||||
9644 | orq->orq_callback(orq->orq_magic, orq, sip); | ||||||||
9645 | orq->orq_response = NULL((void*)0); | ||||||||
9646 | orq->orq_status = 0; | ||||||||
9647 | msg_destroy(msg); | ||||||||
9648 | } | ||||||||
9649 | |||||||||
9650 | static void outgoing_estimate_delay(nta_outgoing_t *orq, sip_t *sip) | ||||||||
9651 | { | ||||||||
9652 | su_time_t now = su_now(); | ||||||||
9653 | double diff = 1000 * su_time_diff(now, orq->orq_sent); | ||||||||
9654 | |||||||||
9655 | if (orq->orq_timestamp && sip->sip_timestamp) { | ||||||||
9656 | double diff2, delay = 0.0; | ||||||||
9657 | su_time_t timestamp = { 0, 0 }; | ||||||||
9658 | char const *bad; | ||||||||
9659 | |||||||||
9660 | sscanf(sip->sip_timestamp->ts_stamp, "%lu.%lu", | ||||||||
9661 | ×tamp.tv_sec, ×tamp.tv_usec); | ||||||||
9662 | |||||||||
9663 | diff2 = 1000 * su_time_diff(now, timestamp); | ||||||||
9664 | |||||||||
9665 | if (diff2 < 0) | ||||||||
9666 | bad = "negative"; | ||||||||
9667 | else if (diff2 > diff + 1e-3) | ||||||||
9668 | bad = "too large"; | ||||||||
9669 | else { | ||||||||
9670 | if (sip->sip_timestamp->ts_delay) | ||||||||
9671 | sscanf(sip->sip_timestamp->ts_delay, "%lg", &delay); | ||||||||
9672 | |||||||||
9673 | if (1000 * delay <= diff2) { | ||||||||
9674 | diff = diff2 - 1000 * delay; | ||||||||
9675 | orq->orq_delay = (unsigned)diff; | ||||||||
9676 | 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__ , 9681, "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) | ||||||||
9677 | "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__ , 9681, "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) | ||||||||
9678 | 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__ , 9681, "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) | ||||||||
9679 | 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__ , 9681, "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) | ||||||||
9680 | 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__ , 9681, "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) | ||||||||
9681 | 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__ , 9681, "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); | ||||||||
9682 | return; | ||||||||
9683 | } | ||||||||
9684 | bad = "delay"; | ||||||||
9685 | } | ||||||||
9686 | |||||||||
9687 | 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__ , 9693, "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) | ||||||||
9688 | "(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__ , 9693, "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) | ||||||||
9689 | 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__ , 9693, "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) | ||||||||
9690 | 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__ , 9693, "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) | ||||||||
9691 | 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__ , 9693, "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) | ||||||||
9692 | 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__ , 9693, "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) | ||||||||
9693 | 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__ , 9693, "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); | ||||||||
9694 | } | ||||||||
9695 | |||||||||
9696 | if (diff >= 0 && diff < (double)UINT_MAX(2147483647 *2U +1U)) { | ||||||||
9697 | orq->orq_delay = (unsigned)diff; | ||||||||
9698 | 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__ , 9698, "nta_outgoing: RTT is %g ms\n", diff)) : (void)0); | ||||||||
9699 | } | ||||||||
9700 | } | ||||||||
9701 | |||||||||
9702 | /**@typedef nta_response_f | ||||||||
9703 | * | ||||||||
9704 | * Callback for replies to outgoing requests. | ||||||||
9705 | * | ||||||||
9706 | * This is a callback function invoked by NTA when it has received a new | ||||||||
9707 | * reply to an outgoing request. | ||||||||
9708 | * | ||||||||
9709 | * @param magic request context | ||||||||
9710 | * @param request request handle | ||||||||
9711 | * @param sip received status message | ||||||||
9712 | * | ||||||||
9713 | * @return | ||||||||
9714 | * This callback function should return always 0. | ||||||||
9715 | * | ||||||||
9716 | */ | ||||||||
9717 | |||||||||
9718 | /** Process duplicate responses */ | ||||||||
9719 | static int outgoing_duplicate(nta_outgoing_t *orq, | ||||||||
9720 | msg_t *msg, | ||||||||
9721 | sip_t *sip) | ||||||||
9722 | { | ||||||||
9723 | sip_via_t *v; | ||||||||
9724 | |||||||||
9725 | if (sip && (sip->sip_flags & NTA_INTERNAL_MSG(1<<15)) == 0) { | ||||||||
9726 | v = sip->sip_via; | ||||||||
9727 | |||||||||
9728 | 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__ , 9730, "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) | ||||||||
9729 | 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__ , 9730, "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) | ||||||||
9730 | 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__ , 9730, "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); | ||||||||
9731 | if (v) | ||||||||
9732 | 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__ , 9737, "\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) | ||||||||
9733 | 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__ , 9737, "\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) | ||||||||
9734 | 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__ , 9737, "\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) | ||||||||
9735 | 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__ , 9737, "\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) | ||||||||
9736 | 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__ , 9737, "\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) | ||||||||
9737 | 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__ , 9737, "\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); | ||||||||
9738 | } | ||||||||
9739 | |||||||||
9740 | msg_destroy(msg); | ||||||||
9741 | return 0; | ||||||||
9742 | } | ||||||||
9743 | |||||||||
9744 | /** @internal ACK to a final response (300..699). | ||||||||
9745 | * These messages are ACK'ed via the original URL (and tport) | ||||||||
9746 | */ | ||||||||
9747 | void outgoing_ack(nta_outgoing_t *orq, sip_t *sip) | ||||||||
9748 | { | ||||||||
9749 | msg_t *ackmsg; | ||||||||
9750 | |||||||||
9751 | assert(orq)((void) sizeof ((orq) ? 1 : 0), __extension__ ({ if (orq) ; else __assert_fail ("orq", "nta.c", 9751, __extension__ __PRETTY_FUNCTION__ ); })); | ||||||||
9752 | |||||||||
9753 | /* Do not ack internally generated messages... */ | ||||||||
9754 | if (sip == NULL((void*)0) || sip->sip_flags & NTA_INTERNAL_MSG(1<<15)) | ||||||||
9755 | return; | ||||||||
9756 | |||||||||
9757 | assert(sip)((void) sizeof ((sip) ? 1 : 0), __extension__ ({ if (sip) ; else __assert_fail ("sip", "nta.c", 9757, __extension__ __PRETTY_FUNCTION__ ); })); assert(sip->sip_status)((void) sizeof ((sip->sip_status) ? 1 : 0), __extension__ ( { if (sip->sip_status) ; else __assert_fail ("sip->sip_status" , "nta.c", 9757, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
9758 | assert(sip->sip_status->st_status >= 300)((void) sizeof ((sip->sip_status->st_status >= 300) ? 1 : 0), __extension__ ({ if (sip->sip_status->st_status >= 300) ; else __assert_fail ("sip->sip_status->st_status >= 300" , "nta.c", 9758, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
9759 | assert(orq->orq_tport)((void) sizeof ((orq->orq_tport) ? 1 : 0), __extension__ ( { if (orq->orq_tport) ; else __assert_fail ("orq->orq_tport" , "nta.c", 9759, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
9760 | |||||||||
9761 | 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); | ||||||||
9762 | if (!ackmsg) | ||||||||
9763 | return; | ||||||||
9764 | |||||||||
9765 | if (!outgoing_create(orq->orq_agent, NULL((void*)0), NULL((void*)0), | ||||||||
9766 | NULL((void*)0), orq->orq_tpn, ackmsg, | ||||||||
9767 | NTATAG_BRANCH_KEY(sip->sip_via->v_branch)ntatag_branch_key, tag_str_v((sip->sip_via->v_branch)), | ||||||||
9768 | NTATAG_USER_VIA(1)ntatag_user_via, tag_bool_v((1)), | ||||||||
9769 | NTATAG_STATELESS(1)ntatag_stateless, tag_bool_v((1)), | ||||||||
9770 | TAG_END()(tag_type_t)0, (tag_value_t)0)) | ||||||||
9771 | msg_destroy(ackmsg); | ||||||||
9772 | } | ||||||||
9773 | |||||||||
9774 | /** Generate messages for hop-by-hop ACK or CANCEL. | ||||||||
9775 | */ | ||||||||
9776 | msg_t *outgoing_ackmsg(nta_outgoing_t *orq, sip_method_t m, char const *mname, | ||||||||
9777 | tag_type_t tag, tag_value_t value, ...) | ||||||||
9778 | { | ||||||||
9779 | msg_t *msg = nta_msg_create(orq->orq_agent, 0); | ||||||||
9780 | su_home_t *home = msg_home(msg)((su_home_t*)(msg)); | ||||||||
9781 | sip_t *sip = sip_object(msg); | ||||||||
9782 | sip_t *old = sip_object(orq->orq_request); | ||||||||
9783 | sip_via_t via[1]; | ||||||||
9784 | |||||||||
9785 | if (!sip) | ||||||||
9786 | return NULL((void*)0); | ||||||||
9787 | |||||||||
9788 | if (tag) { | ||||||||
9789 | ta_list ta; | ||||||||
9790 | |||||||||
9791 | 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); | ||||||||
9792 | |||||||||
9793 | 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); | ||||||||
9794 | /* Bug sf.net # 173323: | ||||||||
9795 | * Ensure that request-URI, topmost Via, From, To, Call-ID, CSeq, | ||||||||
9796 | * Max-Forward, Route, Accept-Contact, Reject-Contact and | ||||||||
9797 | * Request-Disposition are copied from original request | ||||||||
9798 | */ | ||||||||
9799 | if (sip->sip_from) | ||||||||
9800 | sip_header_remove(msg, sip, (void *)sip->sip_from); | ||||||||
9801 | if (sip->sip_to && m != sip_method_ack) | ||||||||
9802 | sip_header_remove(msg, sip, (void *)sip->sip_to); | ||||||||
9803 | if (sip->sip_call_id) | ||||||||
9804 | sip_header_remove(msg, sip, (void *)sip->sip_call_id); | ||||||||
9805 | while (sip->sip_route) | ||||||||
9806 | sip_header_remove(msg, sip, (void *)sip->sip_route); | ||||||||
9807 | while (sip->sip_accept_contact) | ||||||||
9808 | sip_header_remove(msg, sip, (void *)sip->sip_accept_contact); | ||||||||
9809 | while (sip->sip_reject_contact) | ||||||||
9810 | sip_header_remove(msg, sip, (void *)sip->sip_reject_contact); | ||||||||
9811 | if (sip->sip_request_disposition) | ||||||||
9812 | sip_header_remove(msg, sip, (void *)sip->sip_request_disposition); | ||||||||
9813 | while (sip->sip_via) | ||||||||
9814 | sip_header_remove(msg, sip, (void *)sip->sip_via); | ||||||||
9815 | if (sip->sip_max_forwards) | ||||||||
9816 | sip_header_remove(msg, sip, (void *)sip->sip_max_forwards); | ||||||||
9817 | |||||||||
9818 | 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)); | ||||||||
9819 | } | ||||||||
9820 | |||||||||
9821 | sip->sip_request = | ||||||||
9822 | sip_request_create(home, m, mname, (url_string_t *)orq->orq_url, NULL((void*)0)); | ||||||||
9823 | |||||||||
9824 | if (sip->sip_to == NULL((void*)0)) | ||||||||
9825 | sip_add_dup(msg, sip, (sip_header_t *)old->sip_to); | ||||||||
9826 | sip_add_dup(msg, sip, (sip_header_t *)old->sip_from); | ||||||||
9827 | sip_add_dup(msg, sip, (sip_header_t *)old->sip_call_id); | ||||||||
9828 | sip_add_dup(msg, sip, (sip_header_t *)old->sip_route); | ||||||||
9829 | /* @RFC3841. Bug #1326727. */ | ||||||||
9830 | sip_add_dup(msg, sip, (sip_header_t *)old->sip_accept_contact); | ||||||||
9831 | sip_add_dup(msg, sip, (sip_header_t *)old->sip_reject_contact); | ||||||||
9832 | sip_add_dup(msg, sip, (sip_header_t *)old->sip_request_disposition); | ||||||||
9833 | sip_add_dup(msg, sip, (sip_header_t *)old->sip_max_forwards); | ||||||||
9834 | |||||||||
9835 | if (old->sip_via) { | ||||||||
9836 | /* Add only the topmost Via header */ | ||||||||
9837 | *via = *old->sip_via; via->v_next = NULL((void*)0); | ||||||||
9838 | sip_add_dup(msg, sip, (sip_header_t *)via); | ||||||||
9839 | } | ||||||||
9840 | |||||||||
9841 | sip->sip_cseq = sip_cseq_create(home, old->sip_cseq->cs_seq, m, mname); | ||||||||
9842 | |||||||||
9843 | if (sip->sip_request && | ||||||||
9844 | sip->sip_to && | ||||||||
9845 | sip->sip_from && | ||||||||
9846 | sip->sip_call_id && | ||||||||
9847 | (!old->sip_route || sip->sip_route) && | ||||||||
9848 | sip->sip_cseq) | ||||||||
9849 | return msg; | ||||||||
9850 | |||||||||
9851 | msg_destroy(msg); | ||||||||
9852 | |||||||||
9853 | return NULL((void*)0); | ||||||||
9854 | } | ||||||||
9855 | |||||||||
9856 | static | ||||||||
9857 | void outgoing_delayed_recv(su_root_magic_t *rm, | ||||||||
9858 | su_msg_r msg, | ||||||||
9859 | union sm_arg_u *u); | ||||||||
9860 | |||||||||
9861 | /** Respond internally to a transaction. */ | ||||||||
9862 | int outgoing_reply(nta_outgoing_t *orq, int status, char const *phrase, | ||||||||
9863 | int delayed) | ||||||||
9864 | { | ||||||||
9865 | nta_agent_t *agent = orq->orq_agent; | ||||||||
9866 | msg_t *msg = NULL((void*)0); | ||||||||
9867 | sip_t *sip = NULL((void*)0); | ||||||||
9868 | |||||||||
9869 | assert(status == 202 || status >= 400)((void) sizeof ((status == 202 || status >= 400) ? 1 : 0), __extension__ ({ if (status == 202 || status >= 400) ; else __assert_fail ("status == 202 || status >= 400", "nta.c", 9869, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
9870 | |||||||||
9871 | if (orq->orq_pending) | ||||||||
9872 | tport_release(orq->orq_tport, orq->orq_pending, | ||||||||
9873 | orq->orq_request, NULL((void*)0), orq, 0); | ||||||||
9874 | orq->orq_pending = 0; | ||||||||
9875 | |||||||||
9876 | orq->orq_delayed = 0; | ||||||||
9877 | |||||||||
9878 | if (orq->orq_method == sip_method_ack) { | ||||||||
9879 | if (status != delayed) | ||||||||
9880 | 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__ , 9881, "nta(%p): responding %u %s to ACK!\n", (void *)orq, status , phrase)) : (void)0) | ||||||||
9881 | (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__ , 9881, "nta(%p): responding %u %s to ACK!\n", (void *)orq, status , phrase)) : (void)0); | ||||||||
9882 | orq->orq_status = status; | ||||||||
9883 | if (orq->orq_queue == NULL((void*)0)) | ||||||||
9884 | outgoing_trying(orq); /* Timer F */ | ||||||||
9885 | return 0; | ||||||||
9886 | } | ||||||||
9887 | |||||||||
9888 | if (orq->orq_destroyed) { | ||||||||
9889 | if (orq->orq_status < 200) | ||||||||
9890 | orq->orq_status = status; | ||||||||
9891 | outgoing_complete(orq); /* Timer D / Timer K */ | ||||||||
9892 | return 0; | ||||||||
9893 | } | ||||||||
9894 | |||||||||
9895 | if (orq->orq_stateless) | ||||||||
9896 | ; | ||||||||
9897 | else if (orq->orq_queue == NULL((void*)0) || | ||||||||
9898 | orq->orq_queue == orq->orq_agent->sa_out.resolving || | ||||||||
9899 | orq->orq_queue == orq->orq_agent->sa_out.delayed) | ||||||||
9900 | outgoing_trying(orq); | ||||||||
9901 | |||||||||
9902 | /** Insert a dummy Via header */ | ||||||||
9903 | if (!orq->orq_prepared) { | ||||||||
9904 | tport_t *tp = tport_primaries(orq->orq_agent->sa_tports); | ||||||||
9905 | outgoing_insert_via(orq, agent_tport_via(tp)); | ||||||||
9906 | } | ||||||||
9907 | |||||||||
9908 | /* Create response message, if needed */ | ||||||||
9909 | if (!orq->orq_stateless && | ||||||||
9910 | !(orq->orq_callback == outgoing_default_cb) && | ||||||||
9911 | !(status == 408 && | ||||||||
9912 | orq->orq_method != sip_method_invite && | ||||||||
9913 | !orq->orq_agent->sa_timeout_408)) { | ||||||||
9914 | char const *to_tag; | ||||||||
9915 | |||||||||
9916 | msg = nta_msg_create(agent, NTA_INTERNAL_MSG(1<<15)); | ||||||||
9917 | |||||||||
9918 | if (complete_response(msg, status, phrase, orq->orq_request) < 0) { | ||||||||
9919 | assert(!"complete message")((void) sizeof ((!"complete message") ? 1 : 0), __extension__ ({ if (!"complete message") ; else __assert_fail ("!\"complete message\"" , "nta.c", 9919, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
9920 | return -1; | ||||||||
9921 | } | ||||||||
9922 | |||||||||
9923 | sip = sip_object(msg); assert(sip->sip_flags & NTA_INTERNAL_MSG)((void) sizeof ((sip->sip_flags & (1<<15)) ? 1 : 0), __extension__ ({ if (sip->sip_flags & (1<<15 )) ; else __assert_fail ("sip->sip_flags & NTA_INTERNAL_MSG" , "nta.c", 9923, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
9924 | to_tag = nta_agent_newtag(msg_home(msg)((su_home_t*)(msg)), "tag=%s", agent); | ||||||||
9925 | |||||||||
9926 | if (status > 100 && | ||||||||
9927 | sip->sip_to && !sip->sip_to->a_tag && | ||||||||
9928 | sip->sip_cseq->cs_method != sip_method_cancel && | ||||||||
9929 | sip_to_tag(msg_home(msg)((su_home_t*)(msg)), sip->sip_to, to_tag) < 0) { | ||||||||
9930 | assert(!"adding tag")((void) sizeof ((!"adding tag") ? 1 : 0), __extension__ ({ if (!"adding tag") ; else __assert_fail ("!\"adding tag\"", "nta.c" , 9930, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
9931 | return -1; | ||||||||
9932 | } | ||||||||
9933 | |||||||||
9934 | if (status > 400 && agent->sa_blacklist) { | ||||||||
9935 | sip_retry_after_t af[1]; | ||||||||
9936 | sip_retry_after_init(af)->af_delta = agent->sa_blacklist; | ||||||||
9937 | |||||||||
9938 | sip_add_dup(msg, sip, (sip_header_t *)af); | ||||||||
9939 | } | ||||||||
9940 | } | ||||||||
9941 | |||||||||
9942 | if (orq->orq_inserted && !delayed) { | ||||||||
9943 | outgoing_recv(orq, status, msg, sip); | ||||||||
9944 | return 0; | ||||||||
9945 | } | ||||||||
9946 | else if (orq->orq_stateless && orq->orq_callback == outgoing_default_cb) { | ||||||||
9947 | /* Xyzzy */ | ||||||||
9948 | orq->orq_status = status; | ||||||||
9949 | outgoing_complete(orq); | ||||||||
9950 | } | ||||||||
9951 | else { | ||||||||
9952 | /* | ||||||||
9953 | * The thread creating outgoing transaction must return to application | ||||||||
9954 | * before transaction callback can be invoked. Therefore processing an | ||||||||
9955 | * internally generated response message must be delayed until | ||||||||
9956 | * transaction creation is completed. | ||||||||
9957 | * | ||||||||
9958 | * The internally generated message is transmitted using su_msg_send() | ||||||||
9959 | * and it is delivered back to NTA when the application next time | ||||||||
9960 | * executes the su_root_t event loop. | ||||||||
9961 | */ | ||||||||
9962 | nta_agent_t *agent = orq->orq_agent; | ||||||||
9963 | su_root_t *root = agent->sa_root; | ||||||||
9964 | su_msg_r su_msg = SU_MSG_R_INIT{ ((void*)0) }; | ||||||||
9965 | |||||||||
9966 | if (su_msg_create(su_msg, | ||||||||
9967 | su_root_task(root), | ||||||||
9968 | su_root_task(root), | ||||||||
9969 | outgoing_delayed_recv, | ||||||||
9970 | sizeof(struct outgoing_recv_s)) == SU_SUCCESSsu_success) { | ||||||||
9971 | struct outgoing_recv_s *a = su_msg_data(su_msg)->a_outgoing_recv; | ||||||||
9972 | |||||||||
9973 | a->orq = orq; | ||||||||
9974 | a->msg = msg; | ||||||||
9975 | a->sip = sip; | ||||||||
9976 | a->status = status; | ||||||||
9977 | |||||||||
9978 | orq->orq_status2b = &a->status; | ||||||||
9979 | |||||||||
9980 | if (su_msg_send(su_msg) == SU_SUCCESSsu_success) { | ||||||||
9981 | return 0; | ||||||||
9982 | } | ||||||||
9983 | } | ||||||||
9984 | } | ||||||||
9985 | |||||||||
9986 | if (msg) | ||||||||
9987 | msg_destroy(msg); | ||||||||
9988 | |||||||||
9989 | return -1; | ||||||||
9990 | } | ||||||||
9991 | |||||||||
9992 | static | ||||||||
9993 | void outgoing_delayed_recv(su_root_magic_t *rm, | ||||||||
9994 | su_msg_r msg, | ||||||||
9995 | union sm_arg_u *u) | ||||||||
9996 | { | ||||||||
9997 | struct outgoing_recv_s *a = u->a_outgoing_recv; | ||||||||
9998 | |||||||||
9999 | if (a->status > 0) { | ||||||||
10000 | a->orq->orq_status2b = 0; | ||||||||
10001 | if (outgoing_recv(a->orq, a->status, a->msg, a->sip) >= 0) | ||||||||
10002 | return; | ||||||||
10003 | } | ||||||||
10004 | |||||||||
10005 | msg_destroy(a->msg); | ||||||||
10006 | } | ||||||||
10007 | |||||||||
10008 | |||||||||
10009 | /* ====================================================================== */ | ||||||||
10010 | /* 9) Resolving (SIP) URL */ | ||||||||
10011 | |||||||||
10012 | #if HAVE_SOFIA_SRESOLV1 | ||||||||
10013 | |||||||||
10014 | struct sipdns_query; | ||||||||
10015 | |||||||||
10016 | /** DNS resolving for (SIP) URLs */ | ||||||||
10017 | struct sipdns_resolver | ||||||||
10018 | { | ||||||||
10019 | tp_name_t sr_tpn[1]; /**< Copy of original transport name */ | ||||||||
10020 | sres_query_t *sr_query; /**< Current DNS Query */ | ||||||||
10021 | char const *sr_target; /**< Target for current query */ | ||||||||
10022 | |||||||||
10023 | struct sipdns_query *sr_current; /**< Current query (with results) */ | ||||||||
10024 | char **sr_results; /**< A/AAAA results to be used */ | ||||||||
10025 | |||||||||
10026 | struct sipdns_query *sr_head; /**< List of intermediate results */ | ||||||||
10027 | struct sipdns_query **sr_tail; /**< End of intermediate result list */ | ||||||||
10028 | |||||||||
10029 | struct sipdns_query *sr_done; /**< Completed intermediate results */ | ||||||||
10030 | |||||||||
10031 | struct sipdns_tport const *sr_tport; /**< Selected transport */ | ||||||||
10032 | |||||||||
10033 | /** Transports to consider for this request */ | ||||||||
10034 | struct sipdns_tport const *sr_tports[SIPDNS_TRANSPORTS(6) + 1]; | ||||||||
10035 | |||||||||
10036 | uint16_t sr_a_aaaa1, sr_a_aaaa2; /**< Order of A and/or AAAA queries. */ | ||||||||
10037 | |||||||||
10038 | unsigned | ||||||||
10039 | sr_use_naptr:1, | ||||||||
10040 | sr_use_srv:1, | ||||||||
10041 | sr_use_a_aaaa:1; | ||||||||
10042 | }; | ||||||||
10043 | |||||||||
10044 | /** Intermediate queries */ | ||||||||
10045 | struct sipdns_query | ||||||||
10046 | { | ||||||||
10047 | struct sipdns_query *sq_next; | ||||||||
10048 | |||||||||
10049 | char const *sq_proto; | ||||||||
10050 | char const *sq_domain; | ||||||||
10051 | char sq_port[6]; /* port number */ | ||||||||
10052 | uint16_t sq_otype; /* origin type of query data (0 means request) */ | ||||||||
10053 | uint16_t sq_type; /* query type */ | ||||||||
10054 | uint16_t sq_priority; /* priority or preference */ | ||||||||
10055 | uint16_t sq_weight; /* preference or weight */ | ||||||||
10056 | uint16_t sq_grayish; /* candidate for graylisting */ | ||||||||
10057 | }; | ||||||||
10058 | |||||||||
10059 | static int outgoing_resolve_next(nta_outgoing_t *orq); | ||||||||
10060 | static int outgoing_resolving(nta_outgoing_t *orq); | ||||||||
10061 | static int outgoing_resolving_error(nta_outgoing_t *, | ||||||||
10062 | int status, char const *phrase); | ||||||||
10063 | static void outgoing_graylist(nta_outgoing_t *orq, struct sipdns_query *sq); | ||||||||
10064 | static int outgoing_query_naptr(nta_outgoing_t *orq, char const *domain); | ||||||||
10065 | static void outgoing_answer_naptr(sres_context_t *orq, sres_query_t *q, | ||||||||
10066 | sres_record_t *answers[]); | ||||||||
10067 | struct sipdns_tport const *outgoing_naptr_tport(nta_outgoing_t *orq, | ||||||||
10068 | sres_record_t *answers[]); | ||||||||
10069 | |||||||||
10070 | static int outgoing_make_srv_query(nta_outgoing_t *orq); | ||||||||
10071 | static int outgoing_make_a_aaaa_query(nta_outgoing_t *orq); | ||||||||
10072 | |||||||||
10073 | static void outgoing_query_all(nta_outgoing_t *orq); | ||||||||
10074 | |||||||||
10075 | static int outgoing_query_srv(nta_outgoing_t *orq, struct sipdns_query *); | ||||||||
10076 | static void outgoing_answer_srv(sres_context_t *orq, sres_query_t *q, | ||||||||
10077 | sres_record_t *answers[]); | ||||||||
10078 | |||||||||
10079 | #if SU_HAVE_IN61 | ||||||||
10080 | static int outgoing_query_aaaa(nta_outgoing_t *orq, struct sipdns_query *); | ||||||||
10081 | static void outgoing_answer_aaaa(sres_context_t *orq, sres_query_t *q, | ||||||||
10082 | sres_record_t *answers[]); | ||||||||
10083 | #endif | ||||||||
10084 | |||||||||
10085 | static int outgoing_query_a(nta_outgoing_t *orq, struct sipdns_query *); | ||||||||
10086 | static void outgoing_answer_a(sres_context_t *orq, sres_query_t *q, | ||||||||
10087 | sres_record_t *answers[]); | ||||||||
10088 | |||||||||
10089 | #ifdef __clang_analyzer__1 | ||||||||
10090 | #define FUNC_ATTR_NONNULL(...)__attribute__((nonnull(...))) __attribute__((nonnull(__VA_ARGS__))) | ||||||||
10091 | #else | ||||||||
10092 | #define FUNC_ATTR_NONNULL(...)__attribute__((nonnull(...))) | ||||||||
10093 | #endif | ||||||||
10094 | |||||||||
10095 | static void outgoing_query_results(nta_outgoing_t *orq, | ||||||||
10096 | struct sipdns_query *sq, | ||||||||
10097 | char *results[], | ||||||||
10098 | size_t rlen) FUNC_ATTR_NONNULL(3)__attribute__((nonnull(3))); | ||||||||
10099 | |||||||||
10100 | |||||||||
10101 | #define SIPDNS_503_ERROR503, "DNS Error" 503, "DNS Error" | ||||||||
10102 | |||||||||
10103 | /** Resolve a request destination */ | ||||||||
10104 | static void | ||||||||
10105 | outgoing_resolve(nta_outgoing_t *orq, | ||||||||
10106 | int explicit_transport, | ||||||||
10107 | enum nta_res_order_e res_order) | ||||||||
10108 | { | ||||||||
10109 | struct sipdns_resolver *sr = NULL((void*)0); | ||||||||
10110 | char const *tpname = orq->orq_tpn->tpn_proto; | ||||||||
10111 | int tport_known = strcmp(tpname, "*") != 0; | ||||||||
10112 | |||||||||
10113 | if (orq->orq_agent->sa_resolver) | ||||||||
10114 | orq->orq_resolver = sr = su_zalloc(orq->orq_agent->sa_home, (sizeof *sr)); | ||||||||
10115 | |||||||||
10116 | if (!sr) { | ||||||||
10117 | outgoing_resolving_error(orq, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error); | ||||||||
10118 | return; | ||||||||
10119 | } | ||||||||
10120 | |||||||||
10121 | *sr->sr_tpn = *orq->orq_tpn; | ||||||||
10122 | sr->sr_use_srv = orq->orq_agent->sa_use_srv; | ||||||||
10123 | sr->sr_use_naptr = orq->orq_agent->sa_use_naptr && sr->sr_use_srv; | ||||||||
10124 | sr->sr_use_a_aaaa = 1; | ||||||||
10125 | sr->sr_tail = &sr->sr_head; | ||||||||
10126 | |||||||||
10127 | /* RFC 3263: | ||||||||
10128 | If the TARGET was not a numeric IP address, but a port is present in | ||||||||
10129 | the URI, the client performs an A or AAAA record lookup of the domain | ||||||||
10130 | name. The result will be a list of IP addresses, each of which can | ||||||||
10131 | be contacted at the specific port from the URI and transport protocol | ||||||||
10132 | determined previously. The client SHOULD try the first record. If | ||||||||
10133 | an attempt should fail, based on the definition of failure in Section | ||||||||
10134 | 4.3, the next SHOULD be tried, and if that should fail, the next | ||||||||
10135 | SHOULD be tried, and so on. | ||||||||
10136 | |||||||||
10137 | This is a change from RFC 2543. Previously, if the port was | ||||||||
10138 | explicit, but with a value of 5060, SRV records were used. Now, A | ||||||||
10139 | or AAAA records will be used. | ||||||||
10140 | */ | ||||||||
10141 | if (sr->sr_tpn->tpn_port) | ||||||||
10142 | sr->sr_use_naptr = 0, sr->sr_use_srv = 0; | ||||||||
10143 | |||||||||
10144 | /* RFC3263: | ||||||||
10145 | If [...] a transport was specified explicitly, the client performs an | ||||||||
10146 | SRV query for that specific transport, | ||||||||
10147 | */ | ||||||||
10148 | if (explicit_transport) | ||||||||
10149 | sr->sr_use_naptr = 0; | ||||||||
10150 | |||||||||
10151 | { | ||||||||
10152 | /* Initialize sr_tports */ | ||||||||
10153 | tport_t *tport; | ||||||||
10154 | char const *ident = sr->sr_tpn->tpn_ident; | ||||||||
10155 | int i, j; | ||||||||
10156 | |||||||||
10157 | for (tport = tport_primary_by_name(orq->orq_agent->sa_tports, orq->orq_tpn); | ||||||||
10158 | tport; | ||||||||
10159 | tport = tport_next(tport)) { | ||||||||
10160 | tp_name_t const *tpn = tport_name(tport); | ||||||||
10161 | if (tport_known && !su_casematch(tpn->tpn_proto, tpname)) | ||||||||
10162 | continue; | ||||||||
10163 | if (ident && (tpn->tpn_ident == NULL((void*)0) || strcmp(ident, tpn->tpn_ident))) | ||||||||
10164 | continue; | ||||||||
10165 | |||||||||
10166 | for (j = 0; j < SIPDNS_TRANSPORTS(6); j++) | ||||||||
10167 | if (su_casematch(tpn->tpn_proto, sipdns_tports[j].name)) | ||||||||
10168 | break; | ||||||||
10169 | |||||||||
10170 | assert(j < SIPDNS_TRANSPORTS)((void) sizeof ((j < (6)) ? 1 : 0), __extension__ ({ if (j < (6)) ; else __assert_fail ("j < SIPDNS_TRANSPORTS", "nta.c" , 10170, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
10171 | if (j == SIPDNS_TRANSPORTS(6)) | ||||||||
10172 | /* Someone added transport but did not update sipdns_tports */ | ||||||||
10173 | continue; | ||||||||
10174 | |||||||||
10175 | for (i = 0; i < SIPDNS_TRANSPORTS(6); i++) { | ||||||||
10176 | if (sipdns_tports + j == sr->sr_tports[i] || sr->sr_tports[i] == NULL((void*)0)) | ||||||||
10177 | break; | ||||||||
10178 | } | ||||||||
10179 | sr->sr_tports[i] = sipdns_tports + j; | ||||||||
10180 | |||||||||
10181 | if (tport_known) /* Looking for only one transport */ { | ||||||||
10182 | sr->sr_tport = sipdns_tports + j; | ||||||||
10183 | break; | ||||||||
10184 | } | ||||||||
10185 | } | ||||||||
10186 | |||||||||
10187 | /* Nothing found */ | ||||||||
10188 | if (!sr->sr_tports[0]) { | ||||||||
10189 | 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__ , 10190, "nta(%p): transport %s is not supported%s%s\n", (void *)orq, tpname, ident ? " by interface " : "", ident ? ident : "")) : (void)0) | ||||||||
10190 | 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__ , 10190, "nta(%p): transport %s is not supported%s%s\n", (void *)orq, tpname, ident ? " by interface " : "", ident ? ident : "")) : (void)0); | ||||||||
10191 | outgoing_resolving_error(orq, SIPDNS_503_ERROR503, "DNS Error"); | ||||||||
10192 | return; | ||||||||
10193 | } | ||||||||
10194 | } | ||||||||
10195 | |||||||||
10196 | switch (res_order) { | ||||||||
10197 | default: | ||||||||
10198 | case nta_res_ip6_ip4: | ||||||||
10199 | sr->sr_a_aaaa1 = sres_type_aaaa, sr->sr_a_aaaa2 = sres_type_a; | ||||||||
10200 | break; | ||||||||
10201 | case nta_res_ip4_ip6: | ||||||||
10202 | sr->sr_a_aaaa1 = sres_type_a, sr->sr_a_aaaa2 = sres_type_aaaa; | ||||||||
10203 | break; | ||||||||
10204 | case nta_res_ip6_only: | ||||||||
10205 | sr->sr_a_aaaa1 = sres_type_aaaa, sr->sr_a_aaaa2 = sres_type_aaaa; | ||||||||
10206 | break; | ||||||||
10207 | case nta_res_ip4_only: | ||||||||
10208 | sr->sr_a_aaaa1 = sres_type_a, sr->sr_a_aaaa2 = sres_type_a; | ||||||||
10209 | break; | ||||||||
10210 | } | ||||||||
10211 | |||||||||
10212 | outgoing_resolve_next(orq); | ||||||||
10213 | } | ||||||||
10214 | |||||||||
10215 | /** Resolve next destination. */ | ||||||||
10216 | static int | ||||||||
10217 | outgoing_resolve_next(nta_outgoing_t *orq) | ||||||||
10218 | { | ||||||||
10219 | struct sipdns_resolver *sr = orq->orq_resolver; | ||||||||
10220 | |||||||||
10221 | if (sr == NULL((void*)0)) { | ||||||||
10222 | outgoing_resolving_error(orq, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error); | ||||||||
10223 | return 0; | ||||||||
10224 | } | ||||||||
10225 | |||||||||
10226 | if (sr->sr_results) { | ||||||||
10227 | /* Use existing A/AAAA results */ | ||||||||
10228 | su_free(msg_home(orq->orq_request)((su_home_t*)(orq->orq_request)), sr->sr_results[0]); | ||||||||
10229 | sr->sr_results++; | ||||||||
10230 | if (sr->sr_results[0]) { | ||||||||
10231 | struct sipdns_query *sq = sr->sr_current; assert(sq)((void) sizeof ((sq) ? 1 : 0), __extension__ ({ if (sq) ; else __assert_fail ("sq", "nta.c", 10231, __extension__ __PRETTY_FUNCTION__ ); })); | ||||||||
10232 | |||||||||
10233 | if (sq->sq_proto) | ||||||||
10234 | orq->orq_tpn->tpn_proto = sq->sq_proto; | ||||||||
10235 | if (sq->sq_port[0]) | ||||||||
10236 | orq->orq_tpn->tpn_port = sq->sq_port; | ||||||||
10237 | |||||||||
10238 | orq->orq_tpn->tpn_host = sr->sr_results[0]; | ||||||||
10239 | |||||||||
10240 | outgoing_reset_timer(orq); | ||||||||
10241 | outgoing_queue(orq->orq_agent->sa_out.resolving, orq); | ||||||||
10242 | outgoing_prepare_send(orq); | ||||||||
10243 | return 1; | ||||||||
10244 | } | ||||||||
10245 | else { | ||||||||
10246 | sr->sr_current = NULL((void*)0); | ||||||||
10247 | sr->sr_results = NULL((void*)0); | ||||||||
10248 | } | ||||||||
10249 | } | ||||||||
10250 | |||||||||
10251 | if (sr->sr_head) | ||||||||
10252 | outgoing_query_all(orq); | ||||||||
10253 | else if (sr->sr_use_naptr) | ||||||||
10254 | outgoing_query_naptr(orq, sr->sr_tpn->tpn_host); /* NAPTR */ | ||||||||
10255 | else if (sr->sr_use_srv) | ||||||||
10256 | outgoing_make_srv_query(orq); /* SRV */ | ||||||||
10257 | else if (sr->sr_use_a_aaaa) | ||||||||
10258 | outgoing_make_a_aaaa_query(orq); /* A/AAAA */ | ||||||||
10259 | else | ||||||||
10260 | return outgoing_resolving_error(orq, SIPDNS_503_ERROR503, "DNS Error"); | ||||||||
10261 | |||||||||
10262 | return 1; | ||||||||
10263 | } | ||||||||
10264 | |||||||||
10265 | /** Check if can we retry other destinations? */ | ||||||||
10266 | static int | ||||||||
10267 | outgoing_other_destinations(nta_outgoing_t const *orq) | ||||||||
10268 | { | ||||||||
10269 | struct sipdns_resolver *sr = orq->orq_resolver; | ||||||||
10270 | |||||||||
10271 | if (!sr) | ||||||||
10272 | return 0; | ||||||||
10273 | |||||||||
10274 | if (sr->sr_use_a_aaaa || sr->sr_use_srv || sr->sr_use_naptr) | ||||||||
10275 | return 1; | ||||||||
10276 | |||||||||
10277 | if (sr->sr_results && sr->sr_results[1]) | ||||||||
10278 | return 1; | ||||||||
10279 | |||||||||
10280 | if (sr->sr_head) | ||||||||
10281 | return 1; | ||||||||
10282 | |||||||||
10283 | return 0; | ||||||||
10284 | } | ||||||||
10285 | |||||||||
10286 | /** Resolve a request destination */ | ||||||||
10287 | static int | ||||||||
10288 | outgoing_try_another(nta_outgoing_t *orq) | ||||||||
10289 | { | ||||||||
10290 | struct sipdns_resolver *sr = orq->orq_resolver; | ||||||||
10291 | |||||||||
10292 | if (sr == NULL((void*)0)) | ||||||||
10293 | return 0; | ||||||||
10294 | |||||||||
10295 | *orq->orq_tpn = *sr->sr_tpn; | ||||||||
10296 | orq->orq_try_tcp_instead = 0, orq->orq_try_udp_instead = 0; | ||||||||
10297 | outgoing_reset_timer(orq); | ||||||||
10298 | outgoing_queue(orq->orq_agent->sa_out.resolving, orq); | ||||||||
10299 | |||||||||
10300 | if (orq->orq_status > 0) | ||||||||
10301 | /* PP: don't hack priority if a preliminary response has been received */ | ||||||||
10302 | ; | ||||||||
10303 | else if (orq->orq_agent->sa_graylist == 0) | ||||||||
10304 | /* PP: priority hacking disabled */ | ||||||||
10305 | ; | ||||||||
10306 | /* NetModule hack: | ||||||||
10307 | * Move server that did not work to end of queue in sres cache | ||||||||
10308 | * | ||||||||
10309 | * the next request does not try to use the server that is currently down | ||||||||
10310 | * | ||||||||
10311 | * @TODO: fix cases with only A or AAAA answering, or all servers down. | ||||||||
10312 | */ | ||||||||
10313 | else if (sr && sr->sr_target) { | ||||||||
10314 | struct sipdns_query *sq; | ||||||||
10315 | |||||||||
10316 | /* find latest A/AAAA record */ | ||||||||
10317 | sq = sr->sr_head; | ||||||||
10318 | if (sq && sq->sq_type == sr->sr_a_aaaa2 && sr->sr_a_aaaa1 != sr->sr_a_aaaa2) { | ||||||||
10319 | sq->sq_grayish = 1; | ||||||||
10320 | } | ||||||||
10321 | else { | ||||||||
10322 | outgoing_graylist(orq, sr->sr_done); | ||||||||
10323 | } | ||||||||
10324 | } | ||||||||
10325 | |||||||||
10326 | return outgoing_resolve_next(orq); | ||||||||
10327 | } | ||||||||
10328 | |||||||||
10329 | /** Graylist SRV records */ | ||||||||
10330 | static void outgoing_graylist(nta_outgoing_t *orq, struct sipdns_query *sq) | ||||||||
10331 | { | ||||||||
10332 | struct sipdns_resolver *sr = orq->orq_resolver; | ||||||||
10333 | char const *target = sq->sq_domain, *proto = sq->sq_proto; | ||||||||
10334 | unsigned prio = sq->sq_priority, maxprio = prio; | ||||||||
10335 | |||||||||
10336 | /* Don't know how to graylist but SRV records */ | ||||||||
10337 | if (sq->sq_otype != sres_type_srv) | ||||||||
10338 | return; | ||||||||
10339 | |||||||||
10340 | 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__ , 10340, "nta: graylisting %s:%s;transport=%s\n", target, sq-> sq_port, proto)) : (void)0); | ||||||||
10341 | |||||||||
10342 | for (sq = sr->sr_head; sq; sq = sq->sq_next) | ||||||||
10343 | if (sq->sq_otype == sres_type_srv && sq->sq_priority > maxprio) | ||||||||
10344 | maxprio = sq->sq_priority; | ||||||||
10345 | |||||||||
10346 | for (sq = sr->sr_done; sq; sq = sq->sq_next) | ||||||||
10347 | if (sq->sq_otype == sres_type_srv && sq->sq_priority > maxprio) | ||||||||
10348 | maxprio = sq->sq_priority; | ||||||||
10349 | |||||||||
10350 | for (sq = sr->sr_done; sq; sq = sq->sq_next) { | ||||||||
10351 | int modified; | ||||||||
10352 | |||||||||
10353 | if (sq->sq_type != sres_type_srv || strcmp(proto, sq->sq_proto)) | ||||||||
10354 | continue; | ||||||||
10355 | |||||||||
10356 | /* modify the SRV record(s) corresponding to the latest A/AAAA record */ | ||||||||
10357 | modified = sres_set_cached_srv_priority( | ||||||||
10358 | orq->orq_agent->sa_resolver, | ||||||||
10359 | sq->sq_domain, | ||||||||
10360 | target, | ||||||||
10361 | sq->sq_port[0] ? (uint16_t)strtoul(sq->sq_port, NULL((void*)0), 10) : 0, | ||||||||
10362 | orq->orq_agent->sa_graylist, | ||||||||
10363 | maxprio + 1); | ||||||||
10364 | |||||||||
10365 | if (modified >= 0) | ||||||||
10366 | 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__ , 10367, "nta: reduced priority of %d %s SRV records (increase value to %u)\n" , modified, sq->sq_domain, maxprio + 1)) : (void)0) | ||||||||
10367 | 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__ , 10367, "nta: reduced priority of %d %s SRV records (increase value to %u)\n" , modified, sq->sq_domain, maxprio + 1)) : (void)0); | ||||||||
10368 | else | ||||||||
10369 | 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__ , 10369, "nta: failed to reduce %s SRV priority\n", sq->sq_domain )) : (void)0); | ||||||||
10370 | } | ||||||||
10371 | } | ||||||||
10372 | |||||||||
10373 | /** Cancel resolver query */ | ||||||||
10374 | su_inlinestatic inline void outgoing_cancel_resolver(nta_outgoing_t *orq) | ||||||||
10375 | { | ||||||||
10376 | struct sipdns_resolver *sr = orq->orq_resolver; | ||||||||
10377 | |||||||||
10378 | assert(orq->orq_resolver)((void) sizeof ((orq->orq_resolver) ? 1 : 0), __extension__ ({ if (orq->orq_resolver) ; else __assert_fail ("orq->orq_resolver" , "nta.c", 10378, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
10379 | |||||||||
10380 | if (sr->sr_query) /* Cancel resolver query */ | ||||||||
10381 | sres_query_bind(sr->sr_query, NULL((void*)0), NULL((void*)0)), sr->sr_query = NULL((void*)0); | ||||||||
10382 | } | ||||||||
10383 | |||||||||
10384 | /** Destroy resolver */ | ||||||||
10385 | su_inlinestatic inline void outgoing_destroy_resolver(nta_outgoing_t *orq) | ||||||||
10386 | { | ||||||||
10387 | struct sipdns_resolver *sr = orq->orq_resolver; | ||||||||
10388 | |||||||||
10389 | assert(orq->orq_resolver)((void) sizeof ((orq->orq_resolver) ? 1 : 0), __extension__ ({ if (orq->orq_resolver) ; else __assert_fail ("orq->orq_resolver" , "nta.c", 10389, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
10390 | |||||||||
10391 | outgoing_cancel_resolver(orq); | ||||||||
10392 | |||||||||
10393 | su_free(orq->orq_agent->sa_home, sr); | ||||||||
10394 | |||||||||
10395 | orq->orq_resolver = NULL((void*)0); | ||||||||
10396 | } | ||||||||
10397 | |||||||||
10398 | /** Check if we are resolving. If not, return 503 response. */ | ||||||||
10399 | static | ||||||||
10400 | int outgoing_resolving(nta_outgoing_t *orq) | ||||||||
10401 | { | ||||||||
10402 | struct sipdns_resolver *sr = orq->orq_resolver; | ||||||||
10403 | |||||||||
10404 | assert(orq->orq_resolver)((void) sizeof ((orq->orq_resolver) ? 1 : 0), __extension__ ({ if (orq->orq_resolver) ; else __assert_fail ("orq->orq_resolver" , "nta.c", 10404, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
10405 | |||||||||
10406 | if (!sr->sr_query) { | ||||||||
10407 | return outgoing_resolving_error(orq, SIPDNS_503_ERROR503, "DNS Error"); | ||||||||
10408 | } | ||||||||
10409 | else { | ||||||||
10410 | outgoing_queue(orq->orq_agent->sa_out.resolving, orq); | ||||||||
10411 | return 0; | ||||||||
10412 | } | ||||||||
10413 | } | ||||||||
10414 | |||||||||
10415 | /** Return 503 response */ | ||||||||
10416 | static | ||||||||
10417 | int outgoing_resolving_error(nta_outgoing_t *orq, int status, char const *phrase) | ||||||||
10418 | { | ||||||||
10419 | orq->orq_resolved = 1; | ||||||||
10420 | outgoing_reply(orq, status, phrase, 0); | ||||||||
10421 | return -1; | ||||||||
10422 | } | ||||||||
10423 | |||||||||
10424 | /* Query SRV records (with the given tport). */ | ||||||||
10425 | static | ||||||||
10426 | int outgoing_make_srv_query(nta_outgoing_t *orq) | ||||||||
10427 | { | ||||||||
10428 | struct sipdns_resolver *sr = orq->orq_resolver; | ||||||||
10429 | su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request)); | ||||||||
10430 | struct sipdns_query *sq; | ||||||||
10431 | char const *host, *prefix; | ||||||||
10432 | int i; | ||||||||
10433 | size_t hlen, plen; | ||||||||
10434 | |||||||||
10435 | sr->sr_use_srv = 0; | ||||||||
10436 | |||||||||
10437 | host = sr->sr_tpn->tpn_host; | ||||||||
10438 | hlen = strlen(host) + 1; | ||||||||
10439 | |||||||||
10440 | for (i = 0; sr->sr_tports[i]; i++) { | ||||||||
10441 | if (sr->sr_tport && sr->sr_tports[i] != sr->sr_tport) | ||||||||
10442 | continue; | ||||||||
10443 | |||||||||
10444 | prefix = sr->sr_tports[i]->prefix; | ||||||||
10445 | plen = strlen(prefix); | ||||||||
10446 | |||||||||
10447 | sq = su_zalloc(home, (sizeof *sq) + plen + hlen); | ||||||||
10448 | if (sq) { | ||||||||
10449 | *sr->sr_tail = sq, sr->sr_tail = &sq->sq_next; | ||||||||
10450 | sq->sq_domain = memcpy(sq + 1, prefix, plen); | ||||||||
10451 | memcpy((char *)sq->sq_domain + plen, host, hlen); | ||||||||
10452 | sq->sq_proto = sr->sr_tports[i]->name; | ||||||||
10453 | sq->sq_type = sres_type_srv; | ||||||||
10454 | sq->sq_priority = 1; | ||||||||
10455 | sq->sq_weight = 1; | ||||||||
10456 | } | ||||||||
10457 | } | ||||||||
10458 | |||||||||
10459 | outgoing_query_all(orq); | ||||||||
10460 | |||||||||
10461 | return 0; | ||||||||
10462 | } | ||||||||
10463 | |||||||||
10464 | /* Query A/AAAA records. */ | ||||||||
10465 | static | ||||||||
10466 | int outgoing_make_a_aaaa_query(nta_outgoing_t *orq) | ||||||||
10467 | { | ||||||||
10468 | struct sipdns_resolver *sr = orq->orq_resolver; | ||||||||
10469 | su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request)); | ||||||||
10470 | tp_name_t *tpn = orq->orq_tpn; | ||||||||
10471 | struct sipdns_query *sq; | ||||||||
10472 | |||||||||
10473 | assert(sr)((void) sizeof ((sr) ? 1 : 0), __extension__ ({ if (sr) ; else __assert_fail ("sr", "nta.c", 10473, __extension__ __PRETTY_FUNCTION__ ); })); | ||||||||
10474 | |||||||||
10475 | sr->sr_use_a_aaaa = 0; | ||||||||
10476 | |||||||||
10477 | sq = su_zalloc(home, 2 * (sizeof *sq)); | ||||||||
10478 | if (!sq) | ||||||||
10479 | return outgoing_resolving(orq); | ||||||||
10480 | |||||||||
10481 | sq->sq_type = sr->sr_a_aaaa1; | ||||||||
10482 | sq->sq_domain = tpn->tpn_host; | ||||||||
10483 | sq->sq_priority = 1; | ||||||||
10484 | |||||||||
10485 | /* Append */ | ||||||||
10486 | *sr->sr_tail = sq, sr->sr_tail = &sq->sq_next; | ||||||||
10487 | |||||||||
10488 | outgoing_query_all(orq); | ||||||||
10489 | |||||||||
10490 | return 0; | ||||||||
10491 | } | ||||||||
10492 | |||||||||
10493 | |||||||||
10494 | /** Start SRV/A/AAAA queries */ | ||||||||
10495 | static | ||||||||
10496 | void outgoing_query_all(nta_outgoing_t *orq) | ||||||||
10497 | { | ||||||||
10498 | struct sipdns_resolver *sr = orq->orq_resolver; | ||||||||
10499 | struct sipdns_query *sq = sr->sr_head; | ||||||||
10500 | |||||||||
10501 | if (sq == NULL((void*)0)) { | ||||||||
10502 | outgoing_resolving_error(orq, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error); | ||||||||
10503 | return; | ||||||||
10504 | } | ||||||||
10505 | |||||||||
10506 | /* Remove from intermediate list */ | ||||||||
10507 | if (!(sr->sr_head = sq->sq_next)) | ||||||||
10508 | sr->sr_tail = &sr->sr_head; | ||||||||
10509 | |||||||||
10510 | if (sq->sq_type == sres_type_srv) | ||||||||
10511 | outgoing_query_srv(orq, sq); | ||||||||
10512 | #if SU_HAVE_IN61 | ||||||||
10513 | else if (sq->sq_type == sres_type_aaaa) | ||||||||
10514 | outgoing_query_aaaa(orq, sq); | ||||||||
10515 | #endif | ||||||||
10516 | else if (sq->sq_type == sres_type_a) | ||||||||
10517 | outgoing_query_a(orq, sq); | ||||||||
10518 | else | ||||||||
10519 | outgoing_resolving_error(orq, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error); | ||||||||
10520 | } | ||||||||
10521 | |||||||||
10522 | /** Query NAPTR record. */ | ||||||||
10523 | static | ||||||||
10524 | int outgoing_query_naptr(nta_outgoing_t *orq, char const *domain) | ||||||||
10525 | { | ||||||||
10526 | struct sipdns_resolver *sr = orq->orq_resolver; | ||||||||
10527 | sres_record_t **answers; | ||||||||
10528 | |||||||||
10529 | sr->sr_use_naptr = 0; | ||||||||
10530 | |||||||||
10531 | sr->sr_target = domain; | ||||||||
10532 | |||||||||
10533 | answers = sres_cached_answers(orq->orq_agent->sa_resolver, | ||||||||
10534 | sres_type_naptr, domain); | ||||||||
10535 | |||||||||
10536 | 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__ , 10538, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn ->tpn_host, domain, "NAPTR", answers ? " (cached)" : "")) : (void)0) | ||||||||
10537 | 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__ , 10538, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn ->tpn_host, domain, "NAPTR", answers ? " (cached)" : "")) : (void)0) | ||||||||
10538 | 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__ , 10538, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn ->tpn_host, domain, "NAPTR", answers ? " (cached)" : "")) : (void)0); | ||||||||
10539 | |||||||||
10540 | if (answers) { | ||||||||
10541 | outgoing_answer_naptr(orq, NULL((void*)0), answers); | ||||||||
10542 | return 0; | ||||||||
10543 | } | ||||||||
10544 | else { | ||||||||
10545 | sr->sr_query = sres_query(orq->orq_agent->sa_resolver, | ||||||||
10546 | outgoing_answer_naptr, orq, | ||||||||
10547 | sres_type_naptr, domain); | ||||||||
10548 | return outgoing_resolving(orq); | ||||||||
10549 | } | ||||||||
10550 | } | ||||||||
10551 | |||||||||
10552 | /* Process NAPTR records */ | ||||||||
10553 | static | ||||||||
10554 | void outgoing_answer_naptr(sres_context_t *orq, | ||||||||
10555 | sres_query_t *q, | ||||||||
10556 | sres_record_t *answers[]) | ||||||||
10557 | { | ||||||||
10558 | int i, order = -1; | ||||||||
10559 | size_t rlen; | ||||||||
10560 | su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request)); | ||||||||
10561 | struct sipdns_resolver *sr = orq->orq_resolver; | ||||||||
10562 | tp_name_t tpn[1]; | ||||||||
10563 | struct sipdns_query *sq, *selected = NULL((void*)0), **tail = &selected, **at; | ||||||||
10564 | |||||||||
10565 | assert(sr)((void) sizeof ((sr) ? 1 : 0), __extension__ ({ if (sr) ; else __assert_fail ("sr", "nta.c", 10565, __extension__ __PRETTY_FUNCTION__ ); })); | ||||||||
10566 | |||||||||
10567 | sr->sr_query = NULL((void*)0); | ||||||||
10568 | |||||||||
10569 | *tpn = *sr->sr_tpn; | ||||||||
10570 | |||||||||
10571 | /* The NAPTR results are sorted first by Order then by Preference */ | ||||||||
10572 | sres_sort_answers(orq->orq_agent->sa_resolver, answers); | ||||||||
10573 | |||||||||
10574 | if (sr->sr_tport == NULL((void*)0)) | ||||||||
10575 | sr->sr_tport = outgoing_naptr_tport(orq, answers); | ||||||||
10576 | |||||||||
10577 | for (i = 0; answers && answers[i]; i++) { | ||||||||
10578 | sres_naptr_record_t const *na = answers[i]->sr_naptr; | ||||||||
10579 | uint16_t type; | ||||||||
10580 | int valid_tport; | ||||||||
10581 | |||||||||
10582 | if (na->na_record->r_status) | ||||||||
10583 | continue; | ||||||||
10584 | if (na->na_record->r_type != sres_type_naptr) | ||||||||
10585 | continue; | ||||||||
10586 | |||||||||
10587 | /* Check if NAPTR matches our target */ | ||||||||
10588 | if (!su_casenmatch(na->na_services, "SIP+", 4) && | ||||||||
10589 | !su_casenmatch(na->na_services, "SIPS+", 5)) | ||||||||
10590 | /* Not a SIP/SIPS service */ | ||||||||
10591 | continue; | ||||||||
10592 | |||||||||
10593 | /* Use NAPTR results, don't try extra SRV/A/AAAA records */ | ||||||||
10594 | sr->sr_use_srv = 0, sr->sr_use_a_aaaa = 0; | ||||||||
10595 | |||||||||
10596 | valid_tport = sr->sr_tport && | ||||||||
10597 | su_casematch(na->na_services, sr->sr_tport->service); | ||||||||
10598 | |||||||||
10599 | 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__ , 10605, "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) | ||||||||
10600 | 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__ , 10605, "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) | ||||||||
10601 | 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__ , 10605, "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) | ||||||||
10602 | 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__ , 10605, "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) | ||||||||
10603 | 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__ , 10605, "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) | ||||||||
10604 | 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__ , 10605, "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) | ||||||||
10605 | 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__ , 10605, "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); | ||||||||
10606 | |||||||||
10607 | /* RFC 2915 p 4: | ||||||||
10608 | * Order | ||||||||
10609 | * A 16-bit unsigned integer specifying the order in which the | ||||||||
10610 | * NAPTR records MUST be processed to ensure the correct ordering | ||||||||
10611 | * of rules. Low numbers are processed before high numbers, and | ||||||||
10612 | * once a NAPTR is found whose rule "matches" the target, the | ||||||||
10613 | * client MUST NOT consider any NAPTRs with a higher value for | ||||||||
10614 | * order (except as noted below for the Flags field). | ||||||||
10615 | */ | ||||||||
10616 | if (order >= 0 && order != na->na_order) | ||||||||
10617 | continue; | ||||||||
10618 | if (!valid_tport) | ||||||||
10619 | continue; | ||||||||
10620 | |||||||||
10621 | /* OK, we found matching NAPTR */ | ||||||||
10622 | order = na->na_order; | ||||||||
10623 | |||||||||
10624 | /* | ||||||||
10625 | * The "S" flag means that the next lookup should be for SRV records | ||||||||
10626 | * ... "A" means that the next lookup should be for either an A, AAAA, | ||||||||
10627 | * or A6 record. | ||||||||
10628 | */ | ||||||||
10629 | if (na->na_flags[0] == 's' || na->na_flags[0] == 'S') | ||||||||
10630 | type = sres_type_srv; /* SRV */ | ||||||||
10631 | else if (na->na_flags[0] == 'a' || na->na_flags[0] == 'A') | ||||||||
10632 | type = sr->sr_a_aaaa1; /* A / AAAA */ | ||||||||
10633 | else | ||||||||
10634 | continue; | ||||||||
10635 | |||||||||
10636 | rlen = strlen(na->na_replace) + 1; | ||||||||
10637 | sq = su_zalloc(home, (sizeof *sq) + rlen); | ||||||||
10638 | |||||||||
10639 | if (sq == NULL((void*)0)) | ||||||||
10640 | continue; | ||||||||
10641 | |||||||||
10642 | *tail = sq, tail = &sq->sq_next; | ||||||||
10643 | sq->sq_otype = sres_type_naptr; | ||||||||
10644 | sq->sq_priority = na->na_prefer; | ||||||||
10645 | sq->sq_weight = 1; | ||||||||
10646 | sq->sq_type = type; | ||||||||
10647 | sq->sq_domain = memcpy(sq + 1, na->na_replace, rlen); | ||||||||
10648 | sq->sq_proto = sr->sr_tport->name; | ||||||||
10649 | } | ||||||||
10650 | |||||||||
10651 | sres_free_answers(orq->orq_agent->sa_resolver, answers); | ||||||||
10652 | |||||||||
10653 | /* RFC2915: | ||||||||
10654 | Preference [...] specifies the order in which NAPTR | ||||||||
10655 | records with equal "order" values SHOULD be processed, low | ||||||||
10656 | numbers being processed before high numbers. */ | ||||||||
10657 | at = sr->sr_tail; | ||||||||
10658 | while (selected) { | ||||||||
10659 | sq = selected, selected = sq->sq_next; | ||||||||
10660 | |||||||||
10661 | for (tail = at; *tail; tail = &(*tail)->sq_next) { | ||||||||
10662 | if (sq->sq_priority < (*tail)->sq_priority) | ||||||||
10663 | break; | ||||||||
10664 | if (sq->sq_priority == (*tail)->sq_priority && | ||||||||
10665 | sq->sq_weight < (*tail)->sq_weight) | ||||||||
10666 | break; | ||||||||
10667 | } | ||||||||
10668 | /* Insert */ | ||||||||
10669 | sq->sq_next = *tail, *tail = sq; | ||||||||
10670 | |||||||||
10671 | if (!sq->sq_next) /* Last one */ | ||||||||
10672 | sr->sr_tail = &sq->sq_next; | ||||||||
10673 | } | ||||||||
10674 | |||||||||
10675 | outgoing_resolve_next(orq); | ||||||||
10676 | } | ||||||||
10677 | |||||||||
10678 | /* Find first supported protocol in order and preference */ | ||||||||
10679 | struct sipdns_tport const * | ||||||||
10680 | outgoing_naptr_tport(nta_outgoing_t *orq, sres_record_t *answers[]) | ||||||||
10681 | { | ||||||||
10682 | int i, j, order, pref; | ||||||||
10683 | int orders[SIPDNS_TRANSPORTS(6)] = {0}, prefs[SIPDNS_TRANSPORTS(6)] = {0}; | ||||||||
10684 | struct sipdns_tport const *tport; | ||||||||
10685 | |||||||||
10686 | struct sipdns_resolver *sr = orq->orq_resolver; | ||||||||
10687 | |||||||||
10688 | prefs[0] = 0; | ||||||||
10689 | for (j = 0; sr->sr_tports[j]; j++) { | ||||||||
10690 | tport = sr->sr_tports[j]; | ||||||||
10691 | |||||||||
10692 | orders[j] = 65536, prefs[j] = 65536; | ||||||||
10693 | |||||||||
10694 | /* Find transport order */ | ||||||||
10695 | for (i = 0; answers && answers[i]; i++) { | ||||||||
10696 | sres_naptr_record_t const *na = answers[i]->sr_naptr; | ||||||||
10697 | if (na->na_record->r_status) | ||||||||
10698 | continue; | ||||||||
10699 | if (na->na_record->r_type != sres_type_naptr) | ||||||||
10700 | continue; | ||||||||
10701 | /* Check if NAPTR matches transport */ | ||||||||
10702 | if (!su_casematch(na->na_services, tport->service)) | ||||||||
10703 | continue; | ||||||||
10704 | orders[j] = na->na_order; | ||||||||
10705 | prefs[j] = na->na_prefer; | ||||||||
10706 | break; | ||||||||
10707 | } | ||||||||
10708 | } | ||||||||
10709 | |||||||||
10710 | tport = sr->sr_tports[0], order = orders[0], pref = prefs[0]; | ||||||||
10711 | |||||||||
10712 | for (j = 1; sr->sr_tports[j]; j++) { | ||||||||
10713 | if (orders[j] <= order && prefs[j] < pref) { | ||||||||
10714 | tport = sr->sr_tports[j], order = orders[j], pref = prefs[j]; | ||||||||
10715 | } | ||||||||
10716 | } | ||||||||
10717 | |||||||||
10718 | return tport; | ||||||||
10719 | } | ||||||||
10720 | |||||||||
10721 | |||||||||
10722 | /* Query SRV records */ | ||||||||
10723 | static | ||||||||
10724 | int outgoing_query_srv(nta_outgoing_t *orq, | ||||||||
10725 | struct sipdns_query *sq) | ||||||||
10726 | { | ||||||||
10727 | struct sipdns_resolver *sr = orq->orq_resolver; | ||||||||
10728 | |||||||||
10729 | sres_record_t **answers; | ||||||||
10730 | |||||||||
10731 | sr->sr_target = sq->sq_domain; | ||||||||
10732 | sr->sr_current = sq; | ||||||||
10733 | |||||||||
10734 | answers = sres_cached_answers(orq->orq_agent->sa_resolver, | ||||||||
10735 | sres_type_srv, sq->sq_domain); | ||||||||
10736 | |||||||||
10737 | 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__ , 10739, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn ->tpn_host, sq->sq_domain, "SRV", answers ? " (cached)" : "")) : (void)0) | ||||||||
10738 | 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__ , 10739, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn ->tpn_host, sq->sq_domain, "SRV", answers ? " (cached)" : "")) : (void)0) | ||||||||
10739 | 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__ , 10739, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn ->tpn_host, sq->sq_domain, "SRV", answers ? " (cached)" : "")) : (void)0); | ||||||||
10740 | |||||||||
10741 | if (answers) { | ||||||||
10742 | outgoing_answer_srv(orq, NULL((void*)0), answers); | ||||||||
10743 | return 0; | ||||||||
10744 | } | ||||||||
10745 | else { | ||||||||
10746 | sr->sr_query = sres_query(orq->orq_agent->sa_resolver, | ||||||||
10747 | outgoing_answer_srv, orq, | ||||||||
10748 | sres_type_srv, sq->sq_domain); | ||||||||
10749 | return outgoing_resolving(orq); | ||||||||
10750 | } | ||||||||
10751 | } | ||||||||
10752 | |||||||||
10753 | /* Process SRV records */ | ||||||||
10754 | static | ||||||||
10755 | void | ||||||||
10756 | outgoing_answer_srv(sres_context_t *orq, sres_query_t *q, | ||||||||
10757 | sres_record_t *answers[]) | ||||||||
10758 | { | ||||||||
10759 | struct sipdns_resolver *sr = orq->orq_resolver; | ||||||||
10760 | su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request)); | ||||||||
10761 | struct sipdns_query *sq0, *sq, *selected = NULL((void*)0), **tail = &selected, **at; | ||||||||
10762 | int i; | ||||||||
10763 | size_t tlen; | ||||||||
10764 | |||||||||
10765 | sr->sr_query = NULL((void*)0); | ||||||||
10766 | |||||||||
10767 | sq0 = sr->sr_current; | ||||||||
10768 | assert(sq0 && sq0->sq_type == sres_type_srv)((void) sizeof ((sq0 && sq0->sq_type == sres_type_srv ) ? 1 : 0), __extension__ ({ if (sq0 && sq0->sq_type == sres_type_srv) ; else __assert_fail ("sq0 && sq0->sq_type == sres_type_srv" , "nta.c", 10768, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
10769 | assert(sq0->sq_domain)((void) sizeof ((sq0->sq_domain) ? 1 : 0), __extension__ ( { if (sq0->sq_domain) ; else __assert_fail ("sq0->sq_domain" , "nta.c", 10769, __extension__ __PRETTY_FUNCTION__); })); assert(sq0->sq_proto)((void) sizeof ((sq0->sq_proto) ? 1 : 0), __extension__ ({ if (sq0->sq_proto) ; else __assert_fail ("sq0->sq_proto" , "nta.c", 10769, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
10770 | |||||||||
10771 | /* Sort by priority, weight? */ | ||||||||
10772 | sres_sort_answers(orq->orq_agent->sa_resolver, answers); | ||||||||
10773 | |||||||||
10774 | for (i = 0; answers && answers[i]; i++) { | ||||||||
10775 | sres_srv_record_t const *srv = answers[i]->sr_srv; | ||||||||
10776 | |||||||||
10777 | if (srv->srv_record->r_status /* There was an error */ || | ||||||||
10778 | srv->srv_record->r_type != sres_type_srv) | ||||||||
10779 | continue; | ||||||||
10780 | |||||||||
10781 | tlen = strlen(srv->srv_target) + 1; | ||||||||
10782 | |||||||||
10783 | sq = su_zalloc(home, (sizeof *sq) + tlen); | ||||||||
10784 | |||||||||
10785 | if (sq) { | ||||||||
10786 | *tail = sq, tail = &sq->sq_next; | ||||||||
10787 | |||||||||
10788 | sq->sq_otype = sres_type_srv; | ||||||||
10789 | sq->sq_type = sr->sr_a_aaaa1; | ||||||||
10790 | sq->sq_proto = sq0->sq_proto; | ||||||||
10791 | sq->sq_domain = memcpy(sq + 1, srv->srv_target, tlen); | ||||||||
10792 | snprintf(sq->sq_port, sizeof(sq->sq_port), "%u", srv->srv_port); | ||||||||
10793 | sq->sq_priority = srv->srv_priority; | ||||||||
10794 | sq->sq_weight = srv->srv_weight; | ||||||||
10795 | } | ||||||||
10796 | } | ||||||||
10797 | |||||||||
10798 | sres_free_answers(orq->orq_agent->sa_resolver, answers); | ||||||||
10799 | |||||||||
10800 | at = &sr->sr_head; | ||||||||
10801 | |||||||||
10802 | /* Insert sorted by priority, randomly select by weigth */ | ||||||||
10803 | while (selected) { | ||||||||
10804 | unsigned long weight = 0; | ||||||||
10805 | unsigned N = 0; | ||||||||
10806 | uint16_t priority = selected->sq_priority; | ||||||||
10807 | |||||||||
10808 | /* Total weight of entries with same priority */ | ||||||||
10809 | for (sq = selected; sq && priority == sq->sq_priority; sq = sq->sq_next) { | ||||||||
10810 | weight += sq->sq_weight; | ||||||||
10811 | N ++; | ||||||||
10812 | } | ||||||||
10813 | |||||||||
10814 | tail = &selected; | ||||||||
10815 | |||||||||
10816 | /* Select by weighted random. Entries with weight 0 are kept in order */ | ||||||||
10817 | if (N > 1 && weight > 0) { | ||||||||
10818 | unsigned rand = su_randint(0, weight - 1); | ||||||||
10819 | |||||||||
10820 | while (*tail && rand >= (*tail)->sq_weight) { | ||||||||
10821 | rand -= (*tail)->sq_weight; | ||||||||
10822 | tail = &(*tail)->sq_next; | ||||||||
10823 | } | ||||||||
10824 | } | ||||||||
10825 | |||||||||
10826 | /* Remove selected */ | ||||||||
10827 | if (*tail) { | ||||||||
10828 | sq = *tail; *tail = sq->sq_next; assert(sq->sq_priority == priority)((void) sizeof ((sq->sq_priority == priority) ? 1 : 0), __extension__ ({ if (sq->sq_priority == priority) ; else __assert_fail ( "sq->sq_priority == priority", "nta.c", 10828, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
10829 | |||||||||
10830 | /* Append at *at */ | ||||||||
10831 | sq->sq_next = *at; *at = sq; at = &sq->sq_next; if (!*at) sr->sr_tail = at; | ||||||||
10832 | |||||||||
10833 | 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__ , 10836, "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) | ||||||||
10834 | 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__ , 10836, "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) | ||||||||
10835 | (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__ , 10836, "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) | ||||||||
10836 | 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__ , 10836, "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); | ||||||||
10837 | } | ||||||||
10838 | } | ||||||||
10839 | |||||||||
10840 | /* This is not needed anymore (?) */ | ||||||||
10841 | sr->sr_current = NULL((void*)0); | ||||||||
10842 | sq0->sq_next = sr->sr_done; sr->sr_done = sq0; | ||||||||
10843 | |||||||||
10844 | outgoing_resolve_next(orq); | ||||||||
10845 | } | ||||||||
10846 | |||||||||
10847 | #if SU_HAVE_IN61 | ||||||||
10848 | /* Query AAAA records */ | ||||||||
10849 | static | ||||||||
10850 | int outgoing_query_aaaa(nta_outgoing_t *orq, struct sipdns_query *sq) | ||||||||
10851 | { | ||||||||
10852 | struct sipdns_resolver *sr = orq->orq_resolver; | ||||||||
10853 | sres_record_t **answers; | ||||||||
10854 | |||||||||
10855 | sr->sr_target = sq->sq_domain; | ||||||||
10856 | sr->sr_current = sq; | ||||||||
10857 | |||||||||
10858 | answers = sres_cached_answers(orq->orq_agent->sa_resolver, | ||||||||
10859 | sres_type_aaaa, sq->sq_domain); | ||||||||
10860 | |||||||||
10861 | 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__ , 10863, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn ->tpn_host, sq->sq_domain, "AAAA", answers ? " (cached)" : "")) : (void)0) | ||||||||
10862 | 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__ , 10863, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn ->tpn_host, sq->sq_domain, "AAAA", answers ? " (cached)" : "")) : (void)0) | ||||||||
10863 | 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__ , 10863, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn ->tpn_host, sq->sq_domain, "AAAA", answers ? " (cached)" : "")) : (void)0); | ||||||||
10864 | |||||||||
10865 | if (answers) { | ||||||||
10866 | outgoing_answer_aaaa(orq, NULL((void*)0), answers); | ||||||||
10867 | return 0; | ||||||||
10868 | } | ||||||||
10869 | |||||||||
10870 | sr->sr_query = sres_query(orq->orq_agent->sa_resolver, | ||||||||
10871 | outgoing_answer_aaaa, orq, | ||||||||
10872 | sres_type_aaaa, sq->sq_domain); | ||||||||
10873 | |||||||||
10874 | return outgoing_resolving(orq); | ||||||||
10875 | } | ||||||||
10876 | |||||||||
10877 | /* Process AAAA records */ | ||||||||
10878 | static | ||||||||
10879 | void outgoing_answer_aaaa(sres_context_t *orq, sres_query_t *q, | ||||||||
10880 | sres_record_t *answers[]) | ||||||||
10881 | { | ||||||||
10882 | struct sipdns_resolver *sr = orq->orq_resolver; | ||||||||
10883 | su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request)); | ||||||||
10884 | struct sipdns_query *sq = sr->sr_current; | ||||||||
10885 | |||||||||
10886 | size_t i, j, found; | ||||||||
10887 | char *result, **results = NULL((void*)0); | ||||||||
10888 | |||||||||
10889 | assert(sq)((void) sizeof ((sq) ? 1 : 0), __extension__ ({ if (sq) ; else __assert_fail ("sq", "nta.c", 10889, __extension__ __PRETTY_FUNCTION__ ); })); assert(sq->sq_type == sres_type_aaaa)((void) sizeof ((sq->sq_type == sres_type_aaaa) ? 1 : 0), __extension__ ({ if (sq->sq_type == sres_type_aaaa) ; else __assert_fail ("sq->sq_type == sres_type_aaaa", "nta.c", 10889, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
10890 | |||||||||
10891 | sr->sr_query = NULL((void*)0); | ||||||||
10892 | |||||||||
10893 | for (i = 0, found = 0; answers && answers[i]; i++) { | ||||||||
10894 | sres_aaaa_record_t const *aaaa = answers[i]->sr_aaaa; | ||||||||
10895 | if (aaaa->aaaa_record->r_status == 0 && | ||||||||
10896 | aaaa->aaaa_record->r_type == sres_type_aaaa) | ||||||||
10897 | found++; | ||||||||
10898 | } | ||||||||
10899 | |||||||||
10900 | if (found > 1) | ||||||||
10901 | results = su_zalloc(home, (found + 1) * (sizeof *results)); | ||||||||
10902 | else if (found) | ||||||||
10903 | results = &result; | ||||||||
10904 | |||||||||
10905 | for (i = j = 0; results && answers && answers[i]; i++) { | ||||||||
10906 | char addr[SU_ADDRSIZE(48)]; | ||||||||
10907 | sres_aaaa_record_t const *aaaa = answers[i]->sr_aaaa; | ||||||||
10908 | |||||||||
10909 | if (aaaa->aaaa_record->r_status || | ||||||||
10910 | aaaa->aaaa_record->r_type != sres_type_aaaa) | ||||||||
10911 | continue; /* There was an error */ | ||||||||
10912 | |||||||||
10913 | su_inet_ntopinet_ntop(AF_INET610, &aaaa->aaaa_addr, addr, sizeof(addr)); | ||||||||
10914 | |||||||||
10915 | if (j == 0) | ||||||||
10916 | 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__ , 10917, "nta(%p): %s IN AAAA %s\n", (void *)orq, aaaa->aaaa_record ->r_name, addr)) : (void)0) | ||||||||
10917 | 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__ , 10917, "nta(%p): %s IN AAAA %s\n", (void *)orq, aaaa->aaaa_record ->r_name, addr)) : (void)0); | ||||||||
10918 | else | ||||||||
10919 | 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__ , 10919, "nta(%p): AAAA %s\n", (void *)orq, addr)) : (void)0 ); | ||||||||
10920 | |||||||||
10921 | assert(j < found)((void) sizeof ((j < found) ? 1 : 0), __extension__ ({ if ( j < found) ; else __assert_fail ("j < found", "nta.c", 10921 , __extension__ __PRETTY_FUNCTION__); })); | ||||||||
10922 | results[j++] = su_strdup(home, addr); | ||||||||
10923 | } | ||||||||
10924 | |||||||||
10925 | sres_free_answers(orq->orq_agent->sa_resolver, answers); | ||||||||
10926 | |||||||||
10927 | if (results) | ||||||||
10928 | outgoing_query_results(orq, sq, results, found); | ||||||||
10929 | else if (!q) | ||||||||
10930 | outgoing_resolving_error(orq, SIPDNS_503_ERROR503, "DNS Error"); | ||||||||
10931 | } | ||||||||
10932 | #endif /* SU_HAVE_IN6 */ | ||||||||
10933 | |||||||||
10934 | /* Query A records */ | ||||||||
10935 | static | ||||||||
10936 | int outgoing_query_a(nta_outgoing_t *orq, struct sipdns_query *sq) | ||||||||
10937 | { | ||||||||
10938 | struct sipdns_resolver *sr = orq->orq_resolver; | ||||||||
10939 | sres_record_t **answers; | ||||||||
10940 | |||||||||
10941 | sr->sr_target = sq->sq_domain; | ||||||||
10942 | sr->sr_current = sq; | ||||||||
10943 | |||||||||
10944 | answers = sres_cached_answers(orq->orq_agent->sa_resolver, | ||||||||
10945 | sres_type_a, sq->sq_domain); | ||||||||
10946 | |||||||||
10947 | 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__ , 10949, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn ->tpn_host, sq->sq_domain, "A", answers ? " (cached)" : "")) : (void)0) | ||||||||
10948 | 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__ , 10949, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn ->tpn_host, sq->sq_domain, "A", answers ? " (cached)" : "")) : (void)0) | ||||||||
10949 | 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__ , 10949, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn ->tpn_host, sq->sq_domain, "A", answers ? " (cached)" : "")) : (void)0); | ||||||||
10950 | |||||||||
10951 | if (answers) { | ||||||||
10952 | outgoing_answer_a(orq, NULL((void*)0), answers); | ||||||||
10953 | return 0; | ||||||||
10954 | } | ||||||||
10955 | |||||||||
10956 | sr->sr_query = sres_query(orq->orq_agent->sa_resolver, | ||||||||
10957 | outgoing_answer_a, orq, | ||||||||
10958 | sres_type_a, sq->sq_domain); | ||||||||
10959 | |||||||||
10960 | return outgoing_resolving(orq); | ||||||||
10961 | } | ||||||||
10962 | |||||||||
10963 | /* Process A records */ | ||||||||
10964 | static | ||||||||
10965 | void outgoing_answer_a(sres_context_t *orq, sres_query_t *q, | ||||||||
10966 | sres_record_t *answers[]) | ||||||||
10967 | { | ||||||||
10968 | struct sipdns_resolver *sr = orq->orq_resolver; | ||||||||
10969 | su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request)); | ||||||||
10970 | struct sipdns_query *sq = sr->sr_current; | ||||||||
10971 | |||||||||
10972 | int i, j, found; | ||||||||
10973 | char *result, **results = NULL((void*)0); | ||||||||
10974 | |||||||||
10975 | assert(sq)((void) sizeof ((sq) ? 1 : 0), __extension__ ({ if (sq) ; else __assert_fail ("sq", "nta.c", 10975, __extension__ __PRETTY_FUNCTION__ ); })); assert(sq->sq_type == sres_type_a)((void) sizeof ((sq->sq_type == sres_type_a) ? 1 : 0), __extension__ ({ if (sq->sq_type == sres_type_a) ; else __assert_fail ( "sq->sq_type == sres_type_a", "nta.c", 10975, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
10976 | |||||||||
10977 | sr->sr_query = NULL((void*)0); | ||||||||
10978 | |||||||||
10979 | for (i = 0, found = 0; answers && answers[i]; i++) { | ||||||||
10980 | sres_a_record_t const *a = answers[i]->sr_a; | ||||||||
10981 | if (a->a_record->r_status == 0 && | ||||||||
10982 | a->a_record->r_type == sres_type_a) | ||||||||
10983 | found++; | ||||||||
10984 | } | ||||||||
10985 | |||||||||
10986 | if (found > 1) | ||||||||
10987 | results = su_zalloc(home, (found + 1) * (sizeof *results)); | ||||||||
10988 | else if (found) | ||||||||
10989 | results = &result; | ||||||||
10990 | |||||||||
10991 | for (i = j = 0; answers && answers[i]; i++) { | ||||||||
10992 | char addr[SU_ADDRSIZE(48)]; | ||||||||
10993 | sres_a_record_t const *a = answers[i]->sr_a; | ||||||||
10994 | |||||||||
10995 | if (a->a_record->r_status || | ||||||||
10996 | a->a_record->r_type != sres_type_a) | ||||||||
10997 | continue; /* There was an error */ | ||||||||
10998 | |||||||||
10999 | su_inet_ntopinet_ntop(AF_INET2, &a->a_addr, addr, sizeof(addr)); | ||||||||
11000 | |||||||||
11001 | if (j == 0) | ||||||||
11002 | 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__ , 11002, "nta: %s IN A %s\n", a->a_record->r_name, addr )) : (void)0); | ||||||||
11003 | else | ||||||||
11004 | 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__ , 11004, "nta(%p): A %s\n", (void *)orq, addr)) : (void)0); | ||||||||
11005 | |||||||||
11006 | assert(j < found)((void) sizeof ((j < found) ? 1 : 0), __extension__ ({ if ( j < found) ; else __assert_fail ("j < found", "nta.c", 11006 , __extension__ __PRETTY_FUNCTION__); })); | ||||||||
11007 | results[j++] = su_strdup(home, addr); | ||||||||
11008 | } | ||||||||
11009 | |||||||||
11010 | sres_free_answers(orq->orq_agent->sa_resolver, answers); | ||||||||
11011 | |||||||||
11012 | if (results) | ||||||||
11013 | outgoing_query_results(orq, sq, results, found); | ||||||||
11014 | else if (!q) | ||||||||
11015 | outgoing_resolving_error(orq, SIPDNS_503_ERROR503, "DNS Error"); | ||||||||
11016 | } | ||||||||
11017 | |||||||||
11018 | /** Store A/AAAA query results */ | ||||||||
11019 | static void | ||||||||
11020 | outgoing_query_results(nta_outgoing_t *orq, | ||||||||
11021 | struct sipdns_query *sq, | ||||||||
11022 | char *results[], | ||||||||
11023 | size_t rlen) | ||||||||
11024 | { | ||||||||
11025 | struct sipdns_resolver *sr = orq->orq_resolver; | ||||||||
11026 | |||||||||
11027 | if (sq->sq_type == sr->sr_a_aaaa1 && | ||||||||
11028 | sq->sq_type != sr->sr_a_aaaa2) { | ||||||||
11029 | sq->sq_type = sr->sr_a_aaaa2; | ||||||||
11030 | |||||||||
11031 | 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__ , 11032, "nta(%p): %s %s record still unresolved\n", (void *) orq, sq->sq_domain, sq->sq_type == sres_type_a ? "A" : "AAAA" )) : (void)0) | ||||||||
11032 | 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__ , 11032, "nta(%p): %s %s record still unresolved\n", (void *) orq, sq->sq_domain, sq->sq_type == sres_type_a ? "A" : "AAAA" )) : (void)0); | ||||||||
11033 | |||||||||
11034 | /* | ||||||||
11035 | * Three possible policies: | ||||||||
11036 | * 1) try each host for AAAA/A, then A/AAAA | ||||||||
11037 | * 2) try everything first for AAAA/A, then everything for A/AAAA | ||||||||
11038 | * 3) try one SRV record results for AAAA/A, then for A/AAAA, | ||||||||
11039 | * then next SRV record | ||||||||
11040 | */ | ||||||||
11041 | |||||||||
11042 | /* We use now policy #1 */ | ||||||||
11043 | if (!(sq->sq_next = sr->sr_head)) | ||||||||
11044 | sr->sr_tail = &sq->sq_next; | ||||||||
11045 | sr->sr_head = sq; | ||||||||
11046 | } | ||||||||
11047 | else { | ||||||||
11048 | sq->sq_next = sr->sr_done, sr->sr_done = sq; | ||||||||
11049 | |||||||||
11050 | if (rlen == 0 && sq->sq_grayish) | ||||||||
11051 | outgoing_graylist(orq, sq); | ||||||||
11052 | } | ||||||||
11053 | |||||||||
11054 | if (rlen > 1) | ||||||||
11055 | sr->sr_results = results; | ||||||||
11056 | else | ||||||||
11057 | sr->sr_current = NULL((void*)0); | ||||||||
11058 | |||||||||
11059 | if (rlen > 0) { | ||||||||
11060 | orq->orq_resolved = 1; | ||||||||
11061 | orq->orq_tpn->tpn_host = results[0]; | ||||||||
11062 | if (sq->sq_proto) orq->orq_tpn->tpn_proto = sq->sq_proto; | ||||||||
11063 | if (sq->sq_port[0]) orq->orq_tpn->tpn_port = sq->sq_port; | ||||||||
11064 | outgoing_prepare_send(orq); | ||||||||
11065 | } else { | ||||||||
11066 | outgoing_resolve_next(orq); | ||||||||
11067 | } | ||||||||
11068 | } | ||||||||
11069 | |||||||||
11070 | |||||||||
11071 | #endif | ||||||||
11072 | |||||||||
11073 | /* ====================================================================== */ | ||||||||
11074 | /* 10) Reliable responses */ | ||||||||
11075 | |||||||||
11076 | static nta_prack_f nta_reliable_destroyed; | ||||||||
11077 | |||||||||
11078 | /** | ||||||||
11079 | * Check that server transaction can be used to send reliable provisional | ||||||||
11080 | * responses. | ||||||||
11081 | */ | ||||||||
11082 | su_inlinestatic inline | ||||||||
11083 | int reliable_check(nta_incoming_t *irq) | ||||||||
11084 | { | ||||||||
11085 | if (irq == NULL((void*)0) || irq->irq_status >= 200 || !irq->irq_agent) | ||||||||
11086 | return 0; | ||||||||
11087 | |||||||||
11088 | if (irq->irq_reliable && irq->irq_reliable->rel_status >= 200) | ||||||||
11089 | return 0; | ||||||||
11090 | |||||||||
11091 | /* @RSeq is initialized to nonzero when request requires/supports 100rel */ | ||||||||
11092 | if (irq->irq_rseq == 0) | ||||||||
11093 | return 0; | ||||||||
11094 | |||||||||
11095 | if (irq->irq_rseq == 0xffffffffU) /* already sent >> 2**31 responses */ | ||||||||
11096 | return 0; | ||||||||
11097 | |||||||||
11098 | return 1; | ||||||||
11099 | } | ||||||||
11100 | |||||||||
11101 | /** Respond reliably. | ||||||||
11102 | * | ||||||||
11103 | * @param irq | ||||||||
11104 | * @param callback | ||||||||
11105 | * @param rmagic | ||||||||
11106 | * @param status | ||||||||
11107 | * @param phrase | ||||||||
11108 | * @param tag, value, .. | ||||||||
11109 | */ | ||||||||
11110 | nta_reliable_t *nta_reliable_treply(nta_incoming_t *irq, | ||||||||
11111 | nta_prack_f *callback, | ||||||||
11112 | nta_reliable_magic_t *rmagic, | ||||||||
11113 | int status, char const *phrase, | ||||||||
11114 | tag_type_t tag, | ||||||||
11115 | tag_value_t value, ...) | ||||||||
11116 | { | ||||||||
11117 | ta_list ta; | ||||||||
11118 | msg_t *msg; | ||||||||
11119 | sip_t *sip; | ||||||||
11120 | nta_reliable_t *retval = NULL((void*)0); | ||||||||
11121 | |||||||||
11122 | if (!reliable_check(irq) || (status <= 100 || status >= 200)) | ||||||||
11123 | return NULL((void*)0); | ||||||||
11124 | |||||||||
11125 | msg = nta_msg_create(irq->irq_agent, 0); | ||||||||
11126 | sip = sip_object(msg); | ||||||||
11127 | |||||||||
11128 | if (!sip) | ||||||||
11129 | return NULL((void*)0); | ||||||||
11130 | |||||||||
11131 | 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); | ||||||||
11132 | |||||||||
11133 | if (0 > nta_incoming_complete_response(irq, msg, status, phrase, | ||||||||
11134 | ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta). tl[1].t_value)) | ||||||||
11135 | msg_destroy(msg); | ||||||||
11136 | else if (!(retval = reliable_mreply(irq, callback, rmagic, msg, sip))) | ||||||||
11137 | msg_destroy(msg); | ||||||||
11138 | |||||||||
11139 | 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)); | ||||||||
11140 | |||||||||
11141 | return retval; | ||||||||
11142 | } | ||||||||
11143 | |||||||||
11144 | /** Respond reliably with @a msg. | ||||||||
11145 | * | ||||||||
11146 | * @note | ||||||||
11147 | * The stack takes over the ownership of @a msg. (It is destroyed even if | ||||||||
11148 | * sending the response fails.) | ||||||||
11149 | * | ||||||||
11150 | * @param irq | ||||||||
11151 | * @param callback | ||||||||
11152 | * @param rmagic | ||||||||
11153 | * @param msg | ||||||||
11154 | */ | ||||||||
11155 | nta_reliable_t *nta_reliable_mreply(nta_incoming_t *irq, | ||||||||
11156 | nta_prack_f *callback, | ||||||||
11157 | nta_reliable_magic_t *rmagic, | ||||||||
11158 | msg_t *msg) | ||||||||
11159 | { | ||||||||
11160 | sip_t *sip = sip_object(msg); | ||||||||
11161 | |||||||||
11162 | if (!reliable_check(irq)) { | ||||||||
11163 | msg_destroy(msg); | ||||||||
11164 | return NULL((void*)0); | ||||||||
11165 | } | ||||||||
11166 | |||||||||
11167 | if (sip == NULL((void*)0) || !sip->sip_status || sip->sip_status->st_status <= 100) { | ||||||||
11168 | msg_destroy(msg); | ||||||||
11169 | return NULL((void*)0); | ||||||||
11170 | } | ||||||||
11171 | |||||||||
11172 | if (sip->sip_status->st_status >= 200) { | ||||||||
11173 | incoming_final_failed(irq, msg); | ||||||||
11174 | return NULL((void*)0); | ||||||||
11175 | } | ||||||||
11176 | |||||||||
11177 | return reliable_mreply(irq, callback, rmagic, msg, sip); | ||||||||
11178 | } | ||||||||
11179 | |||||||||
11180 | static | ||||||||
11181 | nta_reliable_t *reliable_mreply(nta_incoming_t *irq, | ||||||||
11182 | nta_prack_f *callback, | ||||||||
11183 | nta_reliable_magic_t *rmagic, | ||||||||
11184 | msg_t *msg, | ||||||||
11185 | sip_t *sip) | ||||||||
11186 | { | ||||||||
11187 | nta_reliable_t *rel; | ||||||||
11188 | nta_agent_t *agent; | ||||||||
11189 | |||||||||
11190 | agent = irq->irq_agent; | ||||||||
11191 | |||||||||
11192 | if (callback == NULL((void*)0)) | ||||||||
11193 | callback = nta_reliable_destroyed; | ||||||||
11194 | |||||||||
11195 | rel = su_zalloc(agent->sa_home, sizeof(*rel)); | ||||||||
11196 | if (rel) { | ||||||||
11197 | rel->rel_irq = irq; | ||||||||
11198 | rel->rel_callback = callback; | ||||||||
11199 | rel->rel_magic = rmagic; | ||||||||
11200 | rel->rel_unsent = msg; | ||||||||
11201 | rel->rel_status = sip->sip_status->st_status; | ||||||||
11202 | rel->rel_precious = sip->sip_payload != NULL((void*)0); | ||||||||
11203 | rel->rel_next = irq->irq_reliable; | ||||||||
11204 | |||||||||
11205 | /* | ||||||||
11206 | * If there already is a un-pr-acknowledged response, queue this one | ||||||||
11207 | * until at least one response is pr-acknowledged. | ||||||||
11208 | */ | ||||||||
11209 | if (irq->irq_reliable && | ||||||||
11210 | (irq->irq_reliable->rel_next == NULL((void*)0) || | ||||||||
11211 | irq->irq_reliable->rel_rseq == 0)) { | ||||||||
11212 | return irq->irq_reliable = rel; | ||||||||
11213 | } | ||||||||
11214 | |||||||||
11215 | if (reliable_send(irq, rel, msg_ref_create(msg), sip) < 0) { | ||||||||
11216 | msg_destroy(msg); | ||||||||
11217 | su_free(agent->sa_home, rel); | ||||||||
11218 | return NULL((void*)0); | ||||||||
11219 | } | ||||||||
11220 | |||||||||
11221 | irq->irq_reliable = rel; | ||||||||
11222 | |||||||||
11223 | return callback ? rel : (nta_reliable_t *)-1; | ||||||||
11224 | } | ||||||||
11225 | |||||||||
11226 | msg_destroy(msg); | ||||||||
11227 | return NULL((void*)0); | ||||||||
11228 | } | ||||||||
11229 | |||||||||
11230 | static | ||||||||
11231 | int reliable_send(nta_incoming_t *irq, | ||||||||
11232 | nta_reliable_t *rel, | ||||||||
11233 | msg_t *msg, | ||||||||
11234 | sip_t *sip) | ||||||||
11235 | { | ||||||||
11236 | nta_agent_t *sa = irq->irq_agent; | ||||||||
11237 | su_home_t *home = msg_home(msg)((su_home_t*)(msg)); | ||||||||
11238 | sip_rseq_t rseq[1]; | ||||||||
11239 | sip_rseq_init(rseq); | ||||||||
11240 | |||||||||
11241 | if (sip->sip_require) | ||||||||
11242 | msg_header_replace_param(home, sip->sip_require->k_common, "100rel"); | ||||||||
11243 | else | ||||||||
11244 | sip_add_make(msg, sip, sip_require_class, "100rel"); | ||||||||
11245 | |||||||||
11246 | rel->rel_rseq = rseq->rs_response = irq->irq_rseq; | ||||||||
11247 | sip_add_dup(msg, sip, (sip_header_t *)rseq); | ||||||||
11248 | |||||||||
11249 | if (!sip->sip_rseq || incoming_reply(irq, msg, sip) < 0) { | ||||||||
11250 | msg_destroy(msg); | ||||||||
11251 | return -1; | ||||||||
11252 | } | ||||||||
11253 | |||||||||
11254 | irq->irq_rseq++; | ||||||||
11255 | |||||||||
11256 | if (irq->irq_queue == sa->sa_in.preliminary) | ||||||||
11257 | /* Make sure we are moved to the tail */ | ||||||||
11258 | incoming_remove(irq); | ||||||||
11259 | |||||||||
11260 | incoming_queue(sa->sa_in.preliminary, irq); /* P1 */ | ||||||||
11261 | incoming_set_timer(irq, sa->sa_t1); /* P2 */ | ||||||||
11262 | |||||||||
11263 | return 0; | ||||||||
11264 | } | ||||||||
11265 | |||||||||
11266 | /** Queue final response when there are unsent precious preliminary responses */ | ||||||||
11267 | static | ||||||||
11268 | int reliable_final(nta_incoming_t *irq, msg_t *msg, sip_t *sip) | ||||||||
11269 | { | ||||||||
11270 | nta_reliable_t *r; | ||||||||
11271 | unsigned already_in_callback; | ||||||||
11272 | /* | ||||||||
11273 | * We delay sending final response if it's 2XX and | ||||||||
11274 | * an unpracked reliable response contains session description | ||||||||
11275 | */ | ||||||||
11276 | /* Get last unpracked response from queue */ | ||||||||
11277 | if (sip->sip_status->st_status < 300) | ||||||||
11278 | for (r = irq->irq_reliable; r; r = r->rel_next) | ||||||||
11279 | if (r->rel_unsent && r->rel_precious) { | ||||||||
11280 | /* Delay sending 2XX */ | ||||||||
11281 | reliable_mreply(irq, NULL((void*)0), NULL((void*)0), msg, sip); | ||||||||
11282 | return 0; | ||||||||
11283 | } | ||||||||
11284 | |||||||||
11285 | /* Flush unsent responses. */ | ||||||||
11286 | already_in_callback = irq->irq_in_callback; | ||||||||
11287 | irq->irq_in_callback = 1; | ||||||||
11288 | reliable_flush(irq); | ||||||||
11289 | irq->irq_in_callback = already_in_callback; | ||||||||
11290 | |||||||||
11291 | if (!already_in_callback && irq->irq_terminated && irq->irq_destroyed) { | ||||||||
11292 | incoming_free(irq); | ||||||||
11293 | msg_destroy(msg); | ||||||||
11294 | return 0; | ||||||||
11295 | } | ||||||||
11296 | |||||||||
11297 | return 1; | ||||||||
11298 | } | ||||||||
11299 | |||||||||
11300 | /** Get latest reliably sent response */ | ||||||||
11301 | static | ||||||||
11302 | msg_t *reliable_response(nta_incoming_t *irq) | ||||||||
11303 | { | ||||||||
11304 | nta_reliable_t *r, *rel; | ||||||||
11305 | |||||||||
11306 | /* Get last unpracked response from queue */ | ||||||||
11307 | for (rel = NULL((void*)0), r = irq->irq_reliable; r; r = r->rel_next) | ||||||||
11308 | if (!r->rel_pracked) | ||||||||
11309 | rel = r; | ||||||||
11310 | |||||||||
11311 | assert(rel)((void) sizeof ((rel) ? 1 : 0), __extension__ ({ if (rel) ; else __assert_fail ("rel", "nta.c", 11311, __extension__ __PRETTY_FUNCTION__ ); })); | ||||||||
11312 | |||||||||
11313 | return rel->rel_unsent; | ||||||||
11314 | } | ||||||||
11315 | |||||||||
11316 | /* Find un-PRACKed responses */ | ||||||||
11317 | static | ||||||||
11318 | nta_reliable_t *reliable_find(nta_agent_t const *agent, | ||||||||
11319 | sip_t const *sip) | ||||||||
11320 | { | ||||||||
11321 | incoming_htable_t const *iht = agent->sa_incoming; | ||||||||
11322 | nta_incoming_t *irq, **ii; | ||||||||
11323 | sip_call_id_t const *i = sip->sip_call_id; | ||||||||
11324 | sip_rack_t const *rack = sip->sip_rack; | ||||||||
11325 | hash_value_t hash = NTA_HASH(i, rack->ra_cseq)((i)->i_hash + 26839U * (uint32_t)(rack->ra_cseq)); | ||||||||
11326 | |||||||||
11327 | /* XXX - add own hash table for 100rel */ | ||||||||
11328 | |||||||||
11329 | for (ii = incoming_htable_hash(iht, hash); | ||||||||
11330 | (irq = *ii); | ||||||||
11331 | ii = incoming_htable_next(iht, ii)) { | ||||||||
11332 | |||||||||
11333 | if (hash == irq->irq_hash && | ||||||||
11334 | irq->irq_call_id->i_hash == i->i_hash && | ||||||||
11335 | irq->irq_cseq->cs_seq == rack->ra_cseq && | ||||||||
11336 | irq->irq_method == sip_method_invite && | ||||||||
11337 | strcmp(irq->irq_call_id->i_id, i->i_id) == 0 && | ||||||||
11338 | (irq->irq_to->a_tag == NULL((void*)0) || | ||||||||
11339 | su_casematch(irq->irq_to->a_tag, sip->sip_to->a_tag)) && | ||||||||
11340 | su_casematch(irq->irq_from->a_tag, sip->sip_from->a_tag)) { | ||||||||
11341 | |||||||||
11342 | nta_reliable_t const *rel; | ||||||||
11343 | |||||||||
11344 | /* Found matching INVITE */ | ||||||||
11345 | for (rel = irq->irq_reliable; rel; rel = rel->rel_next) | ||||||||
11346 | if (rel->rel_rseq == rack->ra_response) | ||||||||
11347 | return (nta_reliable_t *)rel; | ||||||||
11348 | |||||||||
11349 | } | ||||||||
11350 | } | ||||||||
11351 | |||||||||
11352 | return NULL((void*)0); | ||||||||
11353 | } | ||||||||
11354 | |||||||||
11355 | /** Process incoming PRACK with matching @RAck field */ | ||||||||
11356 | static | ||||||||
11357 | int reliable_recv(nta_reliable_t *rel, msg_t *msg, sip_t *sip, tport_t *tp) | ||||||||
11358 | { | ||||||||
11359 | nta_incoming_t *irq = rel->rel_irq; | ||||||||
11360 | nta_incoming_t *pr_irq; | ||||||||
11361 | int status; | ||||||||
11362 | |||||||||
11363 | rel->rel_pracked = 1; | ||||||||
11364 | msg_ref_destroy(rel->rel_unsent), rel->rel_unsent = NULL((void*)0); | ||||||||
11365 | |||||||||
11366 | pr_irq = incoming_create(irq->irq_agent, msg, sip, tp, irq->irq_tag); | ||||||||
11367 | if (!pr_irq) { | ||||||||
11368 | mreply(irq->irq_agent, NULL((void*)0), | ||||||||
11369 | SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error, msg, | ||||||||
11370 | tp, 0, 0, NULL((void*)0), | ||||||||
11371 | TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
11372 | return 0; | ||||||||
11373 | } | ||||||||
11374 | |||||||||
11375 | if (irq->irq_status < 200) { | ||||||||
11376 | incoming_queue(irq->irq_agent->sa_in.proceeding, irq); /* Reset P1 */ | ||||||||
11377 | incoming_reset_timer(irq); /* Reset P2 */ | ||||||||
11378 | } | ||||||||
11379 | |||||||||
11380 | irq->irq_in_callback = pr_irq->irq_in_callback = 1; | ||||||||
11381 | status = rel->rel_callback(rel->rel_magic, rel, pr_irq, sip); rel = NULL((void*)0); | ||||||||
11382 | irq->irq_in_callback = pr_irq->irq_in_callback = 0; | ||||||||
11383 | |||||||||
11384 | if (pr_irq->irq_completed) { /* Already sent final response */ | ||||||||
11385 | if (pr_irq->irq_terminated && pr_irq->irq_destroyed) | ||||||||
11386 | incoming_free(pr_irq); | ||||||||
11387 | } | ||||||||
11388 | else if (status != 0) { | ||||||||
11389 | if (status < 200 || status > 299) { | ||||||||
11390 | 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__ , 11391, "nta_reliable(): invalid status %03d from callback\n" , status)) : (void)0) | ||||||||
11391 | 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__ , 11391, "nta_reliable(): invalid status %03d from callback\n" , status)) : (void)0); | ||||||||
11392 | status = 200; | ||||||||
11393 | } | ||||||||
11394 | nta_incoming_treply(pr_irq, status, "OK", TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
11395 | nta_incoming_destroy(pr_irq); | ||||||||
11396 | } | ||||||||
11397 | |||||||||
11398 | /* If there are queued unsent reliable responses, send them all. */ | ||||||||
11399 | while (irq->irq_reliable && irq->irq_reliable->rel_rseq == 0) { | ||||||||
11400 | nta_reliable_t *r; | ||||||||
11401 | |||||||||
11402 | for (r = irq->irq_reliable; r; r = r->rel_next) | ||||||||
11403 | if (r->rel_rseq == 0) | ||||||||
11404 | rel = r; | ||||||||
11405 | |||||||||
11406 | msg = rel->rel_unsent, sip = sip_object(msg); | ||||||||
11407 | |||||||||
11408 | if (sip->sip_status->st_status < 200) { | ||||||||
11409 | if (reliable_send(irq, rel, msg_ref_create(msg), sip) < 0) { | ||||||||
11410 | assert(!"send reliable response")((void) sizeof ((!"send reliable response") ? 1 : 0), __extension__ ({ if (!"send reliable response") ; else __assert_fail ("!\"send reliable response\"" , "nta.c", 11410, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
11411 | } | ||||||||
11412 | } | ||||||||
11413 | else { | ||||||||
11414 | /* | ||||||||
11415 | * XXX | ||||||||
11416 | * Final response should be delayed until a reliable provisional | ||||||||
11417 | * response has been pracked | ||||||||
11418 | */ | ||||||||
11419 | rel->rel_unsent = NULL((void*)0), rel->rel_rseq = (uint32_t)-1; | ||||||||
11420 | if (incoming_reply(irq, msg, sip) < 0) { | ||||||||
11421 | assert(!"send delayed final response")((void) sizeof ((!"send delayed final response") ? 1 : 0), __extension__ ({ if (!"send delayed final response") ; else __assert_fail ( "!\"send delayed final response\"", "nta.c", 11421, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
11422 | } | ||||||||
11423 | } | ||||||||
11424 | } | ||||||||
11425 | |||||||||
11426 | return 0; | ||||||||
11427 | } | ||||||||
11428 | |||||||||
11429 | /** Flush unacknowledged and unsent reliable responses */ | ||||||||
11430 | void reliable_flush(nta_incoming_t *irq) | ||||||||
11431 | { | ||||||||
11432 | nta_reliable_t *r, *rel; | ||||||||
11433 | |||||||||
11434 | do { | ||||||||
11435 | for (r = irq->irq_reliable, rel = NULL((void*)0); r; r = r->rel_next) | ||||||||
11436 | if (r->rel_unsent) | ||||||||
11437 | rel = r; | ||||||||
11438 | |||||||||
11439 | if (rel) { | ||||||||
11440 | rel->rel_pracked = 1; | ||||||||
11441 | msg_ref_destroy(rel->rel_unsent), rel->rel_unsent = NULL((void*)0); | ||||||||
11442 | rel->rel_callback(rel->rel_magic, rel, NULL((void*)0), NULL((void*)0)); | ||||||||
11443 | } | ||||||||
11444 | } while (rel); | ||||||||
11445 | } | ||||||||
11446 | |||||||||
11447 | void reliable_timeout(nta_incoming_t *irq, int timeout) | ||||||||
11448 | { | ||||||||
11449 | if (timeout) | ||||||||
11450 | 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__ , 11450, "nta: response timeout with %u\n", irq->irq_status )) : (void)0); | ||||||||
11451 | |||||||||
11452 | irq->irq_in_callback = 1; | ||||||||
11453 | |||||||||
11454 | reliable_flush(irq); | ||||||||
11455 | |||||||||
11456 | if (irq->irq_callback) | ||||||||
11457 | irq->irq_callback(irq->irq_magic, irq, NULL((void*)0)); | ||||||||
11458 | |||||||||
11459 | irq->irq_in_callback = 0; | ||||||||
11460 | |||||||||
11461 | if (!timeout) | ||||||||
11462 | return; | ||||||||
11463 | |||||||||
11464 | if (irq->irq_completed && irq->irq_destroyed) | ||||||||
11465 | incoming_free(irq), irq = NULL((void*)0); | ||||||||
11466 | else if (irq->irq_status < 200) | ||||||||
11467 | nta_incoming_treply(irq, 503, "Reliable Response Time-Out", TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
11468 | } | ||||||||
11469 | |||||||||
11470 | #if 0 /* Not needed, yet. */ | ||||||||
11471 | /** Use this callback when normal leg callback is supposed to | ||||||||
11472 | * process incoming PRACK requests | ||||||||
11473 | */ | ||||||||
11474 | int nta_reliable_leg_prack(nta_reliable_magic_t *magic, | ||||||||
11475 | nta_reliable_t *rel, | ||||||||
11476 | nta_incoming_t *irq, | ||||||||
11477 | sip_t const *sip) | ||||||||
11478 | { | ||||||||
11479 | nta_agent_t *agent; | ||||||||
11480 | nta_leg_t *leg; | ||||||||
11481 | char const *method_name; | ||||||||
11482 | url_t url[1]; | ||||||||
11483 | int retval; | ||||||||
11484 | |||||||||
11485 | if (irq == NULL((void*)0) || sip == NULL((void*)0) || rel == NULL((void*)0) || | ||||||||
11486 | sip_object(irq->irq_request) != sip) | ||||||||
11487 | return 500; | ||||||||
11488 | |||||||||
11489 | agent = irq->irq_agent; | ||||||||
11490 | method_name = sip->sip_request->rq_method_name; | ||||||||
11491 | *url = *sip->sip_request->rq_url; url->url_params = NULL((void*)0); | ||||||||
11492 | agent_aliases(agent, url, irq->irq_tport); /* canonize urls */ | ||||||||
11493 | |||||||||
11494 | if ((leg = leg_find(irq->irq_agent, | ||||||||
11495 | method_name, url, | ||||||||
11496 | sip->sip_call_id, | ||||||||
11497 | sip->sip_from->a_tag, | ||||||||
11498 | sip->sip_to->a_tag))) { | ||||||||
11499 | /* Use existing dialog */ | ||||||||
11500 | 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__ , 11502, "nta: %s (%u) %s\n", method_name, sip->sip_cseq-> cs_seq, "PRACK processed by default callback, too")) : (void) 0) | ||||||||
11501 | 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__ , 11502, "nta: %s (%u) %s\n", method_name, sip->sip_cseq-> cs_seq, "PRACK processed by default callback, too")) : (void) 0) | ||||||||
11502 | "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__ , 11502, "nta: %s (%u) %s\n", method_name, sip->sip_cseq-> cs_seq, "PRACK processed by default callback, too")) : (void) 0); | ||||||||
11503 | retval = leg->leg_callback(leg->leg_magic, leg, irq, sip); | ||||||||
11504 | } | ||||||||
11505 | else { | ||||||||
11506 | retval = 500; | ||||||||
11507 | } | ||||||||
11508 | |||||||||
11509 | nta_reliable_destroy(rel); | ||||||||
11510 | |||||||||
11511 | return retval; | ||||||||
11512 | } | ||||||||
11513 | #endif | ||||||||
11514 | |||||||||
11515 | /** Destroy a reliable response. | ||||||||
11516 | * | ||||||||
11517 | * Mark a reliable response object for destroyal and free it if possible. | ||||||||
11518 | */ | ||||||||
11519 | void nta_reliable_destroy(nta_reliable_t *rel) | ||||||||
11520 | { | ||||||||
11521 | if (rel == NULL((void*)0) || rel == NONE((void *)-1)) | ||||||||
11522 | return; | ||||||||
11523 | |||||||||
11524 | if (rel->rel_callback == nta_reliable_destroyed) | ||||||||
11525 | 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__ , 11525, "%s(%p): %s\n", __func__, (void *)rel, "already destroyed" )) : (void)0); | ||||||||
11526 | |||||||||
11527 | rel->rel_callback = nta_reliable_destroyed; | ||||||||
11528 | |||||||||
11529 | if (rel->rel_response) | ||||||||
11530 | return; | ||||||||
11531 | |||||||||
11532 | nta_reliable_destroyed(NULL((void*)0), rel, NULL((void*)0), NULL((void*)0)); | ||||||||
11533 | } | ||||||||
11534 | |||||||||
11535 | /** Free and unallocate the nta_reliable_t structure. */ | ||||||||
11536 | static | ||||||||
11537 | int nta_reliable_destroyed(nta_reliable_magic_t *rmagic, | ||||||||
11538 | nta_reliable_t *rel, | ||||||||
11539 | nta_incoming_t *prack, | ||||||||
11540 | sip_t const *sip) | ||||||||
11541 | { | ||||||||
11542 | nta_reliable_t **prev; | ||||||||
11543 | |||||||||
11544 | assert(rel)((void) sizeof ((rel) ? 1 : 0), __extension__ ({ if (rel) ; else __assert_fail ("rel", "nta.c", 11544, __extension__ __PRETTY_FUNCTION__ ); })); assert(rel->rel_irq)((void) sizeof ((rel->rel_irq) ? 1 : 0), __extension__ ({ if (rel->rel_irq) ; else __assert_fail ("rel->rel_irq", "nta.c" , 11544, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
11545 | |||||||||
11546 | for (prev = &rel->rel_irq->irq_reliable; *prev; prev = &(*prev)->rel_next) | ||||||||
11547 | if (*prev == rel) | ||||||||
11548 | break; | ||||||||
11549 | |||||||||
11550 | if (!*prev) { | ||||||||
11551 | assert(*prev)((void) sizeof ((*prev) ? 1 : 0), __extension__ ({ if (*prev) ; else __assert_fail ("*prev", "nta.c", 11551, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
11552 | 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__ , 11552, "%s(%p): %s\n", __func__, (void *)rel, "not linked") ) : (void)0); | ||||||||
11553 | return 200; | ||||||||
11554 | } | ||||||||
11555 | |||||||||
11556 | *prev = rel->rel_next; | ||||||||
11557 | |||||||||
11558 | if (rel->rel_unsent) | ||||||||
11559 | msg_destroy(rel->rel_unsent), rel->rel_unsent = NULL((void*)0); | ||||||||
11560 | |||||||||
11561 | su_free(rel->rel_irq->irq_agent->sa_home, rel); | ||||||||
11562 | |||||||||
11563 | return 200; | ||||||||
11564 | } | ||||||||
11565 | |||||||||
11566 | /** Validate a reliable response. */ | ||||||||
11567 | int outgoing_recv_reliable(nta_outgoing_t *orq, | ||||||||
11568 | msg_t *msg, | ||||||||
11569 | sip_t *sip) | ||||||||
11570 | { | ||||||||
11571 | short status = sip->sip_status->st_status; | ||||||||
11572 | char const *phrase = sip->sip_status->st_phrase; | ||||||||
11573 | uint32_t rseq = sip->sip_rseq->rs_response; | ||||||||
11574 | |||||||||
11575 | 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__ , 11576, "nta: %03u %s is reliably received with RSeq: %u\n", status, phrase, rseq)) : (void)0) | ||||||||
11576 | 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__ , 11576, "nta: %03u %s is reliably received with RSeq: %u\n", status, phrase, rseq)) : (void)0); | ||||||||
11577 | |||||||||
11578 | /* Cannot handle reliable responses unless we have a full dialog */ | ||||||||
11579 | if (orq->orq_rseq == 0 && !orq->orq_to->a_tag) { | ||||||||
11580 | 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__ , 11581, "nta: %03u %s with initial RSeq: %u outside dialog\n" , status, phrase, rseq)) : (void)0) | ||||||||
11581 | 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__ , 11581, "nta: %03u %s with initial RSeq: %u outside dialog\n" , status, phrase, rseq)) : (void)0); | ||||||||
11582 | return 0; | ||||||||
11583 | } | ||||||||
11584 | |||||||||
11585 | if (rseq <= orq->orq_rseq) { | ||||||||
11586 | 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__ , 11587, "nta: %03u %s already received (RSeq: %u, expecting %u)\n" , status, phrase, rseq, orq->orq_rseq + 1)) : (void)0) | ||||||||
11587 | 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__ , 11587, "nta: %03u %s already received (RSeq: %u, expecting %u)\n" , status, phrase, rseq, orq->orq_rseq + 1)) : (void)0); | ||||||||
11588 | return -1; | ||||||||
11589 | } | ||||||||
11590 | |||||||||
11591 | if (orq->orq_rseq && orq->orq_rseq + 1 != rseq) { | ||||||||
11592 | 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__ , 11594, "nta: %03d %s is not expected (RSeq: %u, expecting %u)\n" , status, sip->sip_status->st_phrase, rseq, orq->orq_rseq + 1)) : (void)0) | ||||||||
11593 | 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__ , 11594, "nta: %03d %s is not expected (RSeq: %u, expecting %u)\n" , status, sip->sip_status->st_phrase, rseq, orq->orq_rseq + 1)) : (void)0) | ||||||||
11594 | 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__ , 11594, "nta: %03d %s is not expected (RSeq: %u, expecting %u)\n" , status, sip->sip_status->st_phrase, rseq, orq->orq_rseq + 1)) : (void)0); | ||||||||
11595 | return -1; | ||||||||
11596 | } | ||||||||
11597 | |||||||||
11598 | return 0; | ||||||||
11599 | } | ||||||||
11600 | |||||||||
11601 | /** Create a tagged fork of outgoing request. | ||||||||
11602 | * | ||||||||
11603 | * When a dialog-creating INVITE request is forked, each response from | ||||||||
11604 | * diffent fork will create an early dialog with a distinct tag in @To | ||||||||
11605 | * header. When each fork should be handled separately, a tagged INVITE | ||||||||
11606 | * request can be used. It will only receive responses from the specified | ||||||||
11607 | * fork. Please note that the tagged transaction should be terminated with | ||||||||
11608 | * the final response from another fork, too. | ||||||||
11609 | * | ||||||||
11610 | * @param orq | ||||||||
11611 | * @param callback | ||||||||
11612 | * @param magic | ||||||||
11613 | * @param to_tag | ||||||||
11614 | * @param rseq | ||||||||
11615 | * | ||||||||
11616 | * @bug Fix the memory leak - either one of the requests is left unreleased | ||||||||
11617 | * for ever. | ||||||||
11618 | */ | ||||||||
11619 | nta_outgoing_t *nta_outgoing_tagged(nta_outgoing_t *orq, | ||||||||
11620 | nta_response_f *callback, | ||||||||
11621 | nta_outgoing_magic_t *magic, | ||||||||
11622 | char const *to_tag, | ||||||||
11623 | sip_rseq_t const *rseq) | ||||||||
11624 | { | ||||||||
11625 | nta_agent_t *agent; | ||||||||
11626 | su_home_t *home; | ||||||||
11627 | nta_outgoing_t *tagged; | ||||||||
11628 | sip_to_t *to; | ||||||||
11629 | |||||||||
11630 | if (orq == NULL((void*)0) || to_tag == NULL((void*)0)) | ||||||||
11631 | return NULL((void*)0); | ||||||||
11632 | |||||||||
11633 | if (orq->orq_to->a_tag) { | ||||||||
11634 | 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__ , 11635, "%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) | ||||||||
11635 | (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__ , 11635, "%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); | ||||||||
11636 | return NULL((void*)0); | ||||||||
11637 | } | ||||||||
11638 | if (orq->orq_method != sip_method_invite) { | ||||||||
11639 | 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__ , 11640, "%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) | ||||||||
11640 | (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__ , 11640, "%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); | ||||||||
11641 | return NULL((void*)0); | ||||||||
11642 | } | ||||||||
11643 | if (orq->orq_status < 100) { | ||||||||
11644 | 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__ , 11645, "%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) | ||||||||
11645 | (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__ , 11645, "%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); | ||||||||
11646 | return NULL((void*)0); | ||||||||
11647 | } | ||||||||
11648 | |||||||||
11649 | assert(orq->orq_agent)((void) sizeof ((orq->orq_agent) ? 1 : 0), __extension__ ( { if (orq->orq_agent) ; else __assert_fail ("orq->orq_agent" , "nta.c", 11649, __extension__ __PRETTY_FUNCTION__); })); assert(orq->orq_request)((void) sizeof ((orq->orq_request) ? 1 : 0), __extension__ ({ if (orq->orq_request) ; else __assert_fail ("orq->orq_request" , "nta.c", 11649, __extension__ __PRETTY_FUNCTION__); })); | ||||||||
11650 | |||||||||
11651 | agent = orq->orq_agent; | ||||||||
11652 | tagged = su_zalloc(agent->sa_home, sizeof(*tagged)); | ||||||||
11653 | |||||||||
11654 | home = msg_home((msg_t *)orq->orq_request)((su_home_t*)((msg_t *)orq->orq_request)); | ||||||||
11655 | |||||||||
11656 | tagged->orq_hash = orq->orq_hash; | ||||||||
11657 | tagged->orq_agent = orq->orq_agent; | ||||||||
11658 | tagged->orq_callback = callback; | ||||||||
11659 | tagged->orq_magic = magic; | ||||||||
11660 | |||||||||
11661 | tagged->orq_method = orq->orq_method; | ||||||||
11662 | tagged->orq_method_name = orq->orq_method_name; | ||||||||
11663 | tagged->orq_url = orq->orq_url; | ||||||||
11664 | tagged->orq_from = orq->orq_from; | ||||||||
11665 | |||||||||
11666 | sip_to_tag(home, to = sip_to_copy(home, orq->orq_to), to_tag); | ||||||||
11667 | |||||||||
11668 | tagged->orq_to = to; | ||||||||
11669 | tagged->orq_tag = to->a_tag; | ||||||||
11670 | tagged->orq_cseq = orq->orq_cseq; | ||||||||
11671 | tagged->orq_call_id = orq->orq_call_id; | ||||||||
11672 | |||||||||
11673 | tagged->orq_request = msg_ref_create(orq->orq_request); | ||||||||
11674 | tagged->orq_response = msg_ref_create(orq->orq_response); | ||||||||
11675 | |||||||||
11676 | tagged->orq_status = orq->orq_status; | ||||||||
11677 | tagged->orq_via_added = orq->orq_via_added; | ||||||||
11678 | tagged->orq_prepared = orq->orq_prepared; | ||||||||
11679 | tagged->orq_reliable = orq->orq_reliable; | ||||||||
11680 | tagged->orq_sips = orq->orq_sips; | ||||||||
11681 | tagged->orq_uas = orq->orq_uas; | ||||||||
11682 | tagged->orq_pass_100 = orq->orq_pass_100; | ||||||||
11683 | tagged->orq_must_100rel = orq->orq_must_100rel; | ||||||||
11684 | tagged->orq_100rel = orq->orq_100rel; | ||||||||
11685 | tagged->orq_route = orq->orq_route; | ||||||||
11686 | *tagged->orq_tpn = *orq->orq_tpn; | ||||||||
11687 | tagged->orq_tport = tport_ref(orq->orq_tport); | ||||||||
11688 | if (orq->orq_cc) | ||||||||
11689 | tagged->orq_cc = nta_compartment_ref(orq->orq_cc); | ||||||||
11690 | tagged->orq_branch = orq->orq_branch; | ||||||||
11691 | tagged->orq_via_branch = orq->orq_via_branch; | ||||||||
11692 | |||||||||
11693 | if (tagged->orq_uas) { | ||||||||
11694 | tagged->orq_forking = orq; | ||||||||
11695 | tagged->orq_forks = orq->orq_forks; | ||||||||
11696 | tagged->orq_forked = 1; | ||||||||
11697 | orq->orq_forks = tagged; | ||||||||
11698 | } | ||||||||
11699 | |||||||||
11700 | outgoing_insert(agent, tagged); | ||||||||
11701 | |||||||||
11702 | return tagged; | ||||||||
11703 | } | ||||||||
11704 | |||||||||
11705 | /**PRACK a provisional response. | ||||||||
11706 | * | ||||||||
11707 | * Create and send a PRACK request used to acknowledge a provisional | ||||||||
11708 | * response. | ||||||||
11709 | * | ||||||||
11710 | * The request is sent using the route of the original request @a oorq. | ||||||||
11711 | * | ||||||||
11712 | * When NTA receives response to the prack request, it invokes the @a | ||||||||
11713 | * callback function. | ||||||||
11714 | * | ||||||||
11715 | * @param leg dialog object | ||||||||
11716 | * @param oorq original transaction request | ||||||||
11717 | * @param callback callback function (may be @c NULL) | ||||||||
11718 | * @param magic application context pointer | ||||||||
11719 | * @param route_url optional URL used to route transaction requests | ||||||||
11720 | * @param resp (optional) response message to be acknowledged | ||||||||
11721 | * @param tag,value,... optional | ||||||||
11722 | * | ||||||||
11723 | * @return | ||||||||
11724 | * If successful, return a pointer to newly created client transaction | ||||||||
11725 | * object for PRACK request, NULL otherwise. | ||||||||
11726 | * | ||||||||
11727 | * @sa | ||||||||
11728 | * nta_outgoing_tcreate(), nta_outgoing_tcancel(), nta_outgoing_destroy(). | ||||||||
11729 | */ | ||||||||
11730 | nta_outgoing_t *nta_outgoing_prack(nta_leg_t *leg, | ||||||||
11731 | nta_outgoing_t *oorq, | ||||||||
11732 | nta_response_f *callback, | ||||||||
11733 | nta_outgoing_magic_t *magic, | ||||||||
11734 | url_string_t const *route_url, | ||||||||
11735 | sip_t const *resp, | ||||||||
11736 | tag_type_t tag, tag_value_t value, ...) | ||||||||
11737 | { | ||||||||
11738 | ta_list ta; | ||||||||
11739 | msg_t *msg; | ||||||||
11740 | su_home_t *home; | ||||||||
11741 | sip_t *sip; | ||||||||
11742 | sip_to_t const *to = NULL((void*)0); | ||||||||
11743 | sip_route_t *route = NULL((void*)0), r0[1]; | ||||||||
11744 | nta_outgoing_t *orq = NULL((void*)0); | ||||||||
11745 | sip_rack_t *rack = NULL((void*)0), rack0[1]; | ||||||||
11746 | |||||||||
11747 | if (!leg || !oorq) { | ||||||||
11748 | 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__ , 11748, "%s: invalid arguments\n", __func__)) : (void)0); | ||||||||
11749 | return NULL((void*)0); | ||||||||
11750 | } | ||||||||
11751 | |||||||||
11752 | sip_rack_init(rack0); | ||||||||
11753 | |||||||||
11754 | if (resp) { | ||||||||
11755 | if (!resp->sip_status) { | ||||||||
11756 | 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__ , 11756, "%s: invalid arguments\n", __func__)) : (void)0); | ||||||||
11757 | return NULL((void*)0); | ||||||||
11758 | } | ||||||||
11759 | |||||||||
11760 | if (resp->sip_status->st_status <= 100 || | ||||||||
11761 | resp->sip_status->st_status >= 200) { | ||||||||
11762 | 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__ , 11763, "%s: %u response cannot be PRACKed\n", __func__, resp ->sip_status->st_status)) : (void)0) | ||||||||
11763 | __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__ , 11763, "%s: %u response cannot be PRACKed\n", __func__, resp ->sip_status->st_status)) : (void)0); | ||||||||
11764 | return NULL((void*)0); | ||||||||
11765 | } | ||||||||
11766 | |||||||||
11767 | if (!resp->sip_rseq) { | ||||||||
11768 | 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__ , 11769, "%s: %u response missing RSeq\n", __func__, resp-> sip_status->st_status)) : (void)0) | ||||||||
11769 | __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__ , 11769, "%s: %u response missing RSeq\n", __func__, resp-> sip_status->st_status)) : (void)0); | ||||||||
11770 | return NULL((void*)0); | ||||||||
11771 | } | ||||||||
11772 | |||||||||
11773 | if (resp->sip_rseq->rs_response <= oorq->orq_rseq) { | ||||||||
11774 | 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__ , 11775, "%s: %u response RSeq does not match received RSeq\n" , __func__, resp->sip_status->st_status)) : (void)0) | ||||||||
11775 | __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__ , 11775, "%s: %u response RSeq does not match received RSeq\n" , __func__, resp->sip_status->st_status)) : (void)0); | ||||||||
11776 | return NULL((void*)0); | ||||||||
11777 | } | ||||||||
11778 | if (!oorq->orq_must_100rel && | ||||||||
11779 | !sip_has_feature(resp->sip_require, "100rel")) { | ||||||||
11780 | 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__ , 11781, "%s: %u response does not require 100rel\n", __func__ , resp->sip_status->st_status)) : (void)0) | ||||||||
11781 | __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__ , 11781, "%s: %u response does not require 100rel\n", __func__ , resp->sip_status->st_status)) : (void)0); | ||||||||
11782 | return NULL((void*)0); | ||||||||
11783 | } | ||||||||
11784 | |||||||||
11785 | if (!resp->sip_to->a_tag) { | ||||||||
11786 | 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__ , 11787, "%s: %u response has no To tag\n", __func__, resp-> sip_status->st_status)) : (void)0) | ||||||||
11787 | __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__ , 11787, "%s: %u response has no To tag\n", __func__, resp-> sip_status->st_status)) : (void)0); | ||||||||
11788 | return NULL((void*)0); | ||||||||
11789 | } | ||||||||
11790 | if (su_strcasecmp(resp->sip_to->a_tag, leg->leg_remote->a_tag) || | ||||||||
11791 | su_strcasecmp(resp->sip_to->a_tag, oorq->orq_to->a_tag)) { | ||||||||
11792 | 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__ , 11793, "%s: %u response To tag does not agree with dialog tag\n" , __func__, resp->sip_status->st_status)) : (void)0) | ||||||||
11793 | __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__ , 11793, "%s: %u response To tag does not agree with dialog tag\n" , __func__, resp->sip_status->st_status)) : (void)0); | ||||||||
11794 | return NULL((void*)0); | ||||||||
11795 | } | ||||||||
11796 | |||||||||
11797 | to = resp->sip_to; | ||||||||
11798 | rack = rack0; | ||||||||
11799 | |||||||||
11800 | rack->ra_response = resp->sip_rseq->rs_response; | ||||||||
11801 | rack->ra_cseq = resp->sip_cseq->cs_seq; | ||||||||
11802 | rack->ra_method = resp->sip_cseq->cs_method; | ||||||||
11803 | rack->ra_method_name = resp->sip_cseq->cs_method_name; | ||||||||
11804 | } | ||||||||
11805 | |||||||||
11806 | msg = nta_msg_create(leg->leg_agent, 0); | ||||||||
11807 | sip = sip_object(msg); home = msg_home(msg)((su_home_t*)(msg)); | ||||||||
11808 | |||||||||
11809 | if (!sip) | ||||||||
11810 | return NULL((void*)0); | ||||||||
11811 | |||||||||
11812 | if (!leg->leg_route && resp) { | ||||||||
11813 | /* Insert contact into route */ | ||||||||
11814 | if (resp->sip_contact) { | ||||||||
11815 | sip_route_init(r0)->r_url[0] = resp->sip_contact->m_url[0]; | ||||||||
11816 | route = sip_route_dup(home, r0); | ||||||||
11817 | } | ||||||||
11818 | |||||||||
11819 | /* Reverse record route */ | ||||||||
11820 | if (resp->sip_record_route) { | ||||||||
11821 | sip_route_t *r, *r_next; | ||||||||
11822 | for (r = sip_route_dup(home, resp->sip_record_route); r; r = r_next) { | ||||||||
11823 | r_next = r->r_next, r->r_next = route, route = r; | ||||||||
11824 | } | ||||||||
11825 | } | ||||||||
11826 | } | ||||||||
11827 | |||||||||
11828 | 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); | ||||||||
11829 | |||||||||
11830 | if (!resp) { | ||||||||
11831 | tagi_t const *t; | ||||||||
11832 | |||||||||
11833 | if ((t = tl_find(ta_args(ta)(ta).tl, ntatag_rseq)) && t->t_value) { | ||||||||
11834 | rack = rack0; | ||||||||
11835 | rack->ra_response = (uint32_t)t->t_value; | ||||||||
11836 | } | ||||||||
11837 | |||||||||
11838 | if (rack) { | ||||||||
11839 | rack->ra_cseq = oorq->orq_cseq->cs_seq; | ||||||||
11840 | rack->ra_method = oorq->orq_cseq->cs_method; | ||||||||
11841 | rack->ra_method_name = oorq->orq_cseq->cs_method_name; | ||||||||
11842 | } | ||||||||
11843 | } | ||||||||
11844 | |||||||||
11845 | if (sip_add_tl(msg, sip, | ||||||||
11846 | TAG_IF(rack, SIPTAG_RACK(rack))!(rack) ? tag_skip : siptag_rack, siptag_rack_v(rack), | ||||||||
11847 | TAG_IF(to, SIPTAG_TO(to))!(to) ? tag_skip : siptag_to, siptag_to_v(to), | ||||||||
11848 | ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta). tl[1].t_value) < 0) | ||||||||
11849 | ; | ||||||||
11850 | else if (route && sip_add_dup(msg, sip, (sip_header_t *)route) < 0) | ||||||||
11851 | ; | ||||||||
11852 | else if (!sip->sip_rack) | ||||||||
11853 | 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__ , 11853, "%s: RAck header missing\n", __func__)) : (void)0); | ||||||||
11854 | else if (nta_msg_request_complete(msg, leg, | ||||||||
11855 | SIP_METHOD_PRACKsip_method_prack, "PRACK", | ||||||||
11856 | (url_string_t *)oorq->orq_url) < 0) | ||||||||
11857 | ; | ||||||||
11858 | else | ||||||||
11859 | orq = outgoing_create(leg->leg_agent, callback, magic, | ||||||||
11860 | 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); | ||||||||
11861 | |||||||||
11862 | 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)); | ||||||||
11863 | |||||||||
11864 | if (!orq) | ||||||||
11865 | msg_destroy(msg); | ||||||||
11866 | else if (rack) | ||||||||
11867 | oorq->orq_rseq = rack->ra_response; | ||||||||
11868 | else if (sip->sip_rack) | ||||||||
11869 | oorq->orq_rseq = sip->sip_rack->ra_response; | ||||||||
11870 | |||||||||
11871 | return orq; | ||||||||
11872 | } | ||||||||
11873 | |||||||||
11874 | /** Get @RSeq value stored with client transaction. */ | ||||||||
11875 | uint32_t nta_outgoing_rseq(nta_outgoing_t const *orq) | ||||||||
11876 | { | ||||||||
11877 | return orq ? orq->orq_rseq : 0; | ||||||||
11878 | } | ||||||||
11879 | |||||||||
11880 | /** Set @RSeq value stored with client transaction. | ||||||||
11881 | * | ||||||||
11882 | * @return 0 if rseq was set successfully | ||||||||
11883 | * @return -1 if rseq is invalid or orq is NULL. | ||||||||
11884 | */ | ||||||||
11885 | int nta_outgoing_setrseq(nta_outgoing_t *orq, uint32_t rseq) | ||||||||
11886 | { | ||||||||
11887 | if (orq && orq->orq_rseq <= rseq) { | ||||||||
11888 | orq->orq_rseq = rseq; | ||||||||
11889 | return 0; | ||||||||
11890 | } | ||||||||
11891 | |||||||||
11892 | return -1; | ||||||||
11893 | } | ||||||||
11894 | |||||||||
11895 | /* ------------------------------------------------------------------------ */ | ||||||||
11896 | /* 11) SigComp handling and public transport interface */ | ||||||||
11897 | |||||||||
11898 | #include <sofia-sip/nta_tport.h> | ||||||||
11899 | |||||||||
11900 | /** Return the master transport for the agent. | ||||||||
11901 | * | ||||||||
11902 | * @NEW_1_12_11 | ||||||||
11903 | */ | ||||||||
11904 | tport_t * | ||||||||
11905 | nta_agent_tports(nta_agent_t *agent) | ||||||||
11906 | { | ||||||||
11907 | return agent ? agent->sa_tports : NULL((void*)0); | ||||||||
11908 | } | ||||||||
11909 | |||||||||
11910 | su_inlinestatic inline tport_t * | ||||||||
11911 | nta_transport_(nta_agent_t *agent, | ||||||||
11912 | nta_incoming_t *irq, | ||||||||
11913 | msg_t *msg) | ||||||||
11914 | { | ||||||||
11915 | if (irq) | ||||||||
11916 | return irq->irq_tport; | ||||||||
11917 | else if (agent && msg) | ||||||||
11918 | return tport_delivered_by(agent->sa_tports, msg); | ||||||||
11919 | |||||||||
11920 | errno(*__errno_location ()) = EINVAL22; | ||||||||
11921 | return NULL((void*)0); | ||||||||
11922 | } | ||||||||
11923 | |||||||||
11924 | |||||||||
11925 | /** Return a new reference to the transaction transport. | ||||||||
11926 | * | ||||||||
11927 | * @note The referenced transport must be unreferenced with tport_unref() | ||||||||
11928 | */ | ||||||||
11929 | tport_t * | ||||||||
11930 | nta_incoming_transport(nta_agent_t *agent, | ||||||||
11931 | nta_incoming_t *irq, | ||||||||
11932 | msg_t *msg) | ||||||||
11933 | { | ||||||||
11934 | return tport_ref(nta_transport_(agent, irq, msg)); | ||||||||
11935 | } | ||||||||
11936 | |||||||||
11937 | nta_compressor_t *nta_agent_init_sigcomp(nta_agent_t *sa) | ||||||||
11938 | { | ||||||||
11939 | if (!nta_compressor_vtable || !sa) | ||||||||
11940 | return NULL((void*)0); | ||||||||
11941 | |||||||||
11942 | if (sa->sa_compressor == NULL((void*)0)) { | ||||||||
11943 | char const * const *l = sa->sa_sigcomp_option_list; | ||||||||
11944 | nta_compressor_t *comp; | ||||||||
11945 | comp = nta_compressor_vtable->ncv_init_agent(sa, l); | ||||||||
11946 | sa->sa_compressor = comp; | ||||||||
11947 | } | ||||||||
11948 | |||||||||
11949 | return sa->sa_compressor; | ||||||||
11950 | } | ||||||||
11951 | |||||||||
11952 | void nta_agent_deinit_sigcomp(nta_agent_t *sa) | ||||||||
11953 | { | ||||||||
11954 | if (nta_compressor_vtable && sa && sa->sa_compressor) { | ||||||||
11955 | nta_compressor_vtable->ncv_deinit_agent(sa, sa->sa_compressor); | ||||||||
11956 | sa->sa_compressor = NULL((void*)0); | ||||||||
11957 | } | ||||||||
11958 | } | ||||||||
11959 | |||||||||
11960 | struct sigcomp_compartment * | ||||||||
11961 | nta_incoming_compartment(nta_incoming_t *irq) | ||||||||
11962 | { | ||||||||
11963 | if (nta_compressor_vtable && irq && irq->irq_cc) | ||||||||
11964 | return nta_compressor_vtable->ncv_compartment_ref(irq->irq_cc); | ||||||||
11965 | else | ||||||||
11966 | return NULL((void*)0); | ||||||||
11967 | } | ||||||||
11968 | |||||||||
11969 | tport_t * | ||||||||
11970 | nta_outgoing_transport(nta_outgoing_t *orq) | ||||||||
11971 | { | ||||||||
11972 | if (orq) | ||||||||
11973 | return tport_ref(orq->orq_tport); | ||||||||
11974 | else | ||||||||
11975 | return NULL((void*)0); | ||||||||
11976 | } | ||||||||
11977 | |||||||||
11978 | |||||||||
11979 | struct sigcomp_compartment * | ||||||||
11980 | nta_outgoing_compartment(nta_outgoing_t *orq) | ||||||||
11981 | { | ||||||||
11982 | if (nta_compressor_vtable && orq && orq->orq_cc) | ||||||||
11983 | return nta_compressor_vtable->ncv_compartment_ref(orq->orq_cc); | ||||||||
11984 | else | ||||||||
11985 | return NULL((void*)0); | ||||||||
11986 | } | ||||||||
11987 | |||||||||
11988 | |||||||||
11989 | struct sigcomp_compartment * | ||||||||
11990 | nta_compartment_ref(struct sigcomp_compartment *cc) | ||||||||
11991 | { | ||||||||
11992 | if (nta_compressor_vtable) | ||||||||
11993 | return nta_compressor_vtable->ncv_compartment_ref(cc); | ||||||||
11994 | else | ||||||||
11995 | return NULL((void*)0); | ||||||||
11996 | } | ||||||||
11997 | |||||||||
11998 | void | ||||||||
11999 | nta_compartment_decref(struct sigcomp_compartment **pcc) | ||||||||
12000 | { | ||||||||
12001 | if (nta_compressor_vtable && pcc && *pcc) | ||||||||
12002 | nta_compressor_vtable->ncv_compartment_unref(*pcc), *pcc = NULL((void*)0); | ||||||||
12003 | } | ||||||||
12004 | |||||||||
12005 | |||||||||
12006 | /** Get compartment for connection, create it when needed. */ | ||||||||
12007 | static | ||||||||
12008 | struct sigcomp_compartment * | ||||||||
12009 | agent_compression_compartment(nta_agent_t *sa, | ||||||||
12010 | tport_t *tp, | ||||||||
12011 | tp_name_t const *tpn, | ||||||||
12012 | int new_if_needed) | ||||||||
12013 | { | ||||||||
12014 | if (nta_compressor_vtable) { | ||||||||
12015 | char const * const *l = sa->sa_sigcomp_option_list; | ||||||||
12016 | return nta_compressor_vtable-> | ||||||||
12017 | ncv_compartment(sa, tp, sa->sa_compressor, tpn, l, new_if_needed); | ||||||||
12018 | } | ||||||||
12019 | else | ||||||||
12020 | return NULL((void*)0); | ||||||||
12021 | } | ||||||||
12022 | |||||||||
12023 | static | ||||||||
12024 | int agent_accept_compressed(nta_agent_t *sa, msg_t *msg, | ||||||||
12025 | struct sigcomp_compartment *cc) | ||||||||
12026 | { | ||||||||
12027 | if (nta_compressor_vtable) { | ||||||||
12028 | nta_compressor_t *msc = sa->sa_compressor; | ||||||||
12029 | tport_compressor_t *sc = NULL((void*)0); | ||||||||
12030 | if (tport_delivered_with_comp(sa->sa_tports, msg, &sc) < 0) | ||||||||
12031 | return 0; | ||||||||
12032 | return nta_compressor_vtable->ncv_accept_compressed(sa, msc, sc, msg, cc); | ||||||||
12033 | } | ||||||||
12034 | else | ||||||||
12035 | return 0; | ||||||||
12036 | } | ||||||||
12037 | |||||||||
12038 | /** Close compressor (lose its state). */ | ||||||||
12039 | static | ||||||||
12040 | int agent_close_compressor(nta_agent_t *sa, | ||||||||
12041 | struct sigcomp_compartment *cc) | ||||||||
12042 | { | ||||||||
12043 | if (nta_compressor_vtable) | ||||||||
12044 | return nta_compressor_vtable->ncv_close_compressor(sa, cc); | ||||||||
12045 | return 0; | ||||||||
12046 | } | ||||||||
12047 | |||||||||
12048 | /** Close both compressor and decompressor */ | ||||||||
12049 | static | ||||||||
12050 | int agent_zap_compressor(nta_agent_t *sa, | ||||||||
12051 | struct sigcomp_compartment *cc) | ||||||||
12052 | { | ||||||||
12053 | if (nta_compressor_vtable) | ||||||||
12054 | return nta_compressor_vtable->ncv_zap_compressor(sa, cc); | ||||||||
12055 | return 0; | ||||||||
12056 | } | ||||||||
12057 | |||||||||
12058 | /** Bind transport update callback */ | ||||||||
12059 | int nta_agent_bind_tport_update(nta_agent_t *agent, | ||||||||
12060 | nta_update_magic_t *magic, | ||||||||
12061 | nta_update_tport_f *callback) | ||||||||
12062 | { | ||||||||
12063 | if (!agent) | ||||||||
12064 | return su_seterrno(EFAULT14), -1; | ||||||||
12065 | agent->sa_update_magic = magic; | ||||||||
12066 | agent->sa_update_tport = callback; | ||||||||
12067 | return 0; | ||||||||
12068 | } | ||||||||
12069 | |||||||||
12070 | /** Bind transport error callback */ | ||||||||
12071 | int nta_agent_bind_tport_error(nta_agent_t *agent, | ||||||||
12072 | nta_error_magic_t *magic, | ||||||||
12073 | nta_error_tport_f *callback) | ||||||||
12074 | { | ||||||||
12075 | if (!agent) | ||||||||
12076 | return su_seterrno(EFAULT14), -1; | ||||||||
12077 | agent->sa_error_magic = magic; | ||||||||
12078 | agent->sa_error_tport = callback; | ||||||||
12079 | return 0; | ||||||||
12080 | } | ||||||||
12081 | |||||||||
12082 | /** Check if public transport binding is in progress */ | ||||||||
12083 | int nta_agent_tport_is_updating(nta_agent_t *agent) | ||||||||
12084 | { | ||||||||
12085 | return agent && tport_is_updating(agent->sa_tports); | ||||||||
12086 | } | ||||||||
12087 | |||||||||
12088 | /** Initiate STUN keepalive controller to TPORT */ | ||||||||
12089 | int nta_tport_keepalive(nta_outgoing_t *orq) | ||||||||
12090 | { | ||||||||
12091 | assert(orq)((void) sizeof ((orq) ? 1 : 0), __extension__ ({ if (orq) ; else __assert_fail ("orq", "nta.c", 12091, __extension__ __PRETTY_FUNCTION__ ); })); | ||||||||
12092 | |||||||||
12093 | #if HAVE_SOFIA_STUN | ||||||||
12094 | return tport_keepalive(orq->orq_tport, msg_addrinfo(orq->orq_request), | ||||||||
12095 | TAG_END()(tag_type_t)0, (tag_value_t)0); | ||||||||
12096 | #else | ||||||||
12097 | return -1; | ||||||||
12098 | #endif | ||||||||
12099 | } | ||||||||
12100 | |||||||||
12101 | /** Close all transports. @since Experimental in @VERSION_1_12_2. */ | ||||||||
12102 | int nta_agent_close_tports(nta_agent_t *agent) | ||||||||
12103 | { | ||||||||
12104 | size_t i; | ||||||||
12105 | outgoing_htable_t *oht = agent->sa_outgoing; | ||||||||
12106 | incoming_htable_t *iht = agent->sa_incoming; | ||||||||
12107 | |||||||||
12108 | for (i = oht->oht_size; i-- > 0;) | ||||||||
12109 | /* while */ if (oht->oht_table[i]) { | ||||||||
12110 | nta_outgoing_t *orq = oht->oht_table[i]; | ||||||||
12111 | |||||||||
12112 | if (orq->orq_pending && orq->orq_tport) | ||||||||
12113 | tport_release(orq->orq_tport, orq->orq_pending, orq->orq_request, | ||||||||
12114 | NULL((void*)0), orq, 0); | ||||||||
12115 | |||||||||
12116 | orq->orq_pending = 0; | ||||||||
12117 | tport_unref(orq->orq_tport), orq->orq_tport = NULL((void*)0); | ||||||||
12118 | } | ||||||||
12119 | |||||||||
12120 | |||||||||
12121 | for (i = iht->iht_size; i-- > 0;) | ||||||||
12122 | /* while */ if (iht->iht_table[i]) { | ||||||||
12123 | nta_incoming_t *irq = iht->iht_table[i]; | ||||||||
12124 | tport_unref(irq->irq_tport), irq->irq_tport = NULL((void*)0); | ||||||||
12125 | } | ||||||||
12126 | |||||||||
12127 | tport_destroy(agent->sa_tports), agent->sa_tports = NULL((void*)0); | ||||||||
12128 | |||||||||
12129 | msg_header_free(agent->sa_home, (void *)agent->sa_vias); | ||||||||
12130 | agent->sa_vias = NULL((void*)0); | ||||||||
12131 | msg_header_free(agent->sa_home, (void *)agent->sa_public_vias); | ||||||||
12132 | agent->sa_public_vias = NULL((void*)0); | ||||||||
12133 | |||||||||
12134 | return 0; | ||||||||
12135 | } |
1 | /* -*- C -*- |
2 | * |
3 | * This file is part of the Sofia-SIP package |
4 | * |
5 | * Copyright (C) 2005 Nokia Corporation. |
6 | * |
7 | * Contact: Pekka Pessi <pekka.pessi@nokia.com> |
8 | * |
9 | * This library is free software; you can redistribute it and/or |
10 | * modify it under the terms of the GNU Lesser General Public License |
11 | * as published by the Free Software Foundation; either version 2.1 of |
12 | * the License, or (at your option) any later version. |
13 | * |
14 | * This library is distributed in the hope that it will be useful, but |
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 | * Lesser General Public License for more details. |
18 | * |
19 | * You should have received a copy of the GNU Lesser General Public |
20 | * License along with this library; if not, write to the Free Software |
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA |
22 | * 02110-1301 USA |
23 | * |
24 | */ |
25 | |
26 | #ifndef SIP_PROTOS_H |
27 | /** Defined when <sofia-sip/sip_protos.h> has been included. */ |
28 | #define SIP_PROTOS_H |
29 | |
30 | /**@file sofia-sip/sip_protos.h |
31 | * |
32 | * SIP prototypes and macros for each header. |
33 | * |
34 | * This file is automatically generated from <sip.h> by msg_parser.awk. |
35 | * |
36 | * @author Pekka Pessi <Pekka.Pessi@nokia.com>. |
37 | * |
38 | */ |
39 | |
40 | #include <sofia-sip/su_config.h> |
41 | |
42 | #ifndef SIP_HEADER_H |
43 | #include <sofia-sip/sip_header.h> |
44 | #endif |
45 | |
46 | #ifndef SIP_HCLASSES_H |
47 | #include <sofia-sip/sip_hclasses.h> |
48 | #endif |
49 | |
50 | SOFIA_BEGIN_DECLS |
51 | |
52 | #if SU_HAVE_INLINE1 |
53 | /** Get SIP structure from msg. */ |
54 | su_inlinestatic inline |
55 | sip_t *sip_object(msg_t const *msg) |
56 | { |
57 | return (sip_t *)msg_public(msg, SIP_PROTOCOL_TAG((void *)0x53495020)); |
58 | } |
59 | |
60 | /** Insert a (list of) header(s) to the header structure and fragment chain. |
61 | * |
62 | * The function @c sip_header_insert() inserts header or list of headers |
63 | * into a SIP message. It also inserts them into the the message fragment |
64 | * chain, if it exists. |
65 | * |
66 | * When inserting headers into the fragment chain, a request (or status) is |
67 | * inserted first and replaces the existing request (or status). The Via |
68 | * headers are inserted after the request or status, and rest of the headers |
69 | * after request, status, or Via headers. |
70 | * |
71 | * If the header is a singleton, existing headers with the same class are |
72 | * removed. |
73 | * |
74 | * @param msg message owning the fragment chain |
75 | * @param sip SIP message structure to which header is added |
76 | * @param h list of header(s) to be added |
77 | */ |
78 | su_inlinestatic inline |
79 | int sip_header_insert(msg_t *msg, sip_t *sip, sip_header_t *h) |
80 | { |
81 | return msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)h); |
82 | } |
83 | |
84 | /** Remove a header from a SIP message. */ |
85 | su_inlinestatic inline |
86 | int sip_header_remove(msg_t *msg, sip_t *sip, sip_header_t *h) |
87 | { |
88 | return msg_header_remove(msg, (msg_pub_t *)sip, (msg_header_t *)h); |
89 | } |
90 | |
91 | /** Return name of the header. */ |
92 | su_inlinestatic inline |
93 | char const *sip_header_name(sip_header_t const *h, int compact) |
94 | { |
95 | if (compact && h->sh_classsh_common->h_class->hc_short[0]) |
96 | return h->sh_classsh_common->h_class->hc_short; |
97 | else |
98 | return h->sh_classsh_common->h_class->hc_name; |
99 | } |
100 | |
101 | /** Return data after header structure. */ |
102 | su_inlinestatic inline |
103 | void *sip_header_data(sip_header_t *h) |
104 | { |
105 | return h && h != SIP_NONE((void const *)-1L) ? h->sh_classsh_common->h_class->hc_size + (char *)h : NULL((void*)0); |
106 | } |
107 | #else |
108 | sip_t *sip_object(msg_t *msg); |
109 | int sip_header_insert(msg_t *msg, sip_t *sip, sip_header_t *h); |
110 | int sip_header_remove(msg_t *msg, sip_t *sip, sip_header_t *h); |
111 | char const *sip_header_name(sip_header_t const *h, int compact); |
112 | void *sip_header_data(sip_header_t *h); |
113 | #endif |
114 | |
115 | /**@addtogroup sip_request |
116 | * @{ |
117 | */ |
118 | |
119 | /** Parse a SIP @ref sip_request "request line". @internal */ |
120 | SOFIAPUBFUN issize_t sip_request_d(su_home_t *, msg_header_t *, |
121 | char *s, isize_t slen); |
122 | |
123 | /** Print a SIP @ref sip_request "request line". @internal */ |
124 | SOFIAPUBFUN issize_t sip_request_e(char b[], isize_t bsiz, |
125 | msg_header_t const *h, int flags); |
126 | |
127 | /**Access a SIP @ref sip_request "request line" |
128 | * structure #sip_request_t from #sip_t. |
129 | * |
130 | */ |
131 | #define sip_request(sip)((sip_request_t *)msg_header_access((msg_pub_t*)(sip), sip_request_class )) \ |
132 | ((sip_request_t *)msg_header_access((msg_pub_t*)(sip), sip_request_class)) |
133 | |
134 | /**Initializer for structure #sip_request_t. |
135 | * |
136 | * A static #sip_request_t structure for |
137 | * @ref sip_request "request line" must be initialized with |
138 | * the SIP_REQUEST_INIT() macro. |
139 | * For instance, |
140 | * @code |
141 | * |
142 | * sip_request_t sip_request = SIP_REQUEST_INIT; |
143 | * |
144 | * @endcode |
145 | * @HI |
146 | * |
147 | */ |
148 | #define SIP_REQUEST_INIT(){{{ 0, 0, sip_request_class }}} SIP_HDR_INIT(request){{{ 0, 0, sip_request_class }}} |
149 | |
150 | /**Initialize a structure #sip_request_t. |
151 | * |
152 | * An #sip_request_t structure for |
153 | * @ref sip_request "request line" can be initialized with the |
154 | * sip_request_init() function/macro. For instance, |
155 | * @code |
156 | * |
157 | * sip_request_t sip_request; |
158 | * |
159 | * sip_request_init(&sip_request); |
160 | * |
161 | * @endcode |
162 | * @HI |
163 | * |
164 | */ |
165 | #if SU_HAVE_INLINE1 |
166 | su_inlinestatic inline sip_request_t *sip_request_init(sip_request_t x[1]) |
167 | { |
168 | return SIP_HEADER_INIT(x, sip_request_class, sizeof(sip_request_t))((void)memset((x), 0, (sizeof(sip_request_t))), (void)(((sip_common_t *)(x))->h_class = (sip_request_class)), (x)); |
169 | } |
170 | #else |
171 | #define sip_request_init(x) \ |
172 | SIP_HEADER_INIT(x, sip_request_class, sizeof(sip_request_t))((void)memset((x), 0, (sizeof(sip_request_t))), (void)(((sip_common_t *)(x))->h_class = (sip_request_class)), (x)) |
173 | #endif |
174 | |
175 | /**Test if header object is instance of #sip_request_t. |
176 | * |
177 | * Check if the header class is an instance of |
178 | * @ref sip_request "request line" object and return true (nonzero), |
179 | * otherwise return false (zero). |
180 | * |
181 | * @param header pointer to the header structure to be tested |
182 | * |
183 | * @retval 1 (true) if the @a header is an instance of header request |
184 | * @retval 0 (false) otherwise |
185 | * |
186 | */ |
187 | #if SU_HAVE_INLINE1 |
188 | su_inlinestatic inline int sip_is_request(sip_header_t const *header) |
189 | { |
190 | return header && header->sh_classsh_common->h_class->hc_hash == sip_request_hash; |
191 | } |
192 | #else |
193 | int sip_is_request(sip_header_t const *header); |
194 | #endif |
195 | |
196 | #define sip_request_p(h)sip_is_request((h)) sip_is_request((h)) |
197 | |
198 | |
199 | /**Duplicate a list of @ref sip_request "request line" header structures #sip_request_t. |
200 | * |
201 | * Duplicate a header |
202 | * structure @a hdr. If the header structure @a hdr |
203 | * contains a reference (@c hdr->x_next) to a list of |
204 | * headers, all the headers in the list are duplicated, too. |
205 | * |
206 | * @param home memory home used to allocate new structure |
207 | * @param hdr header structure to be duplicated |
208 | * |
209 | * When duplicating, all parameter lists and non-constant |
210 | * strings attached to the header are copied, too. The |
211 | * function uses given memory @a home to allocate all the |
212 | * memory areas used to copy the header. |
213 | * |
214 | * @par Example |
215 | * @code |
216 | * |
217 | * request = sip_request_dup(home, sip->sip_request); |
218 | * |
219 | * @endcode |
220 | * |
221 | * @return |
222 | * A pointer to the |
223 | * newly duplicated #sip_request_t header structure, or NULL |
224 | * upon an error. |
225 | * |
226 | */ |
227 | #if SU_HAVE_INLINE1 |
228 | su_inlinestatic inline |
229 | #endif |
230 | sip_request_t *sip_request_dup(su_home_t *home, sip_request_t const *hdr) |
231 | __attribute__((__malloc__)); |
232 | |
233 | #if SU_HAVE_INLINE1 |
234 | su_inlinestatic inline |
235 | sip_request_t *sip_request_dup(su_home_t *home, sip_request_t const *hdr) |
236 | { |
237 | return (sip_request_t *) |
238 | msg_header_dup_as(home, sip_request_class, (msg_header_t const *)hdr); |
239 | } |
240 | #endif |
241 | |
242 | /**Copy a list of @ref sip_request "request line" header structures #sip_request_t. |
243 | * |
244 | * The function sip_request_copy() copies a header structure @a |
245 | * hdr. If the header structure @a hdr contains a reference (@c |
246 | * hdr->h_next) to a list of headers, all the headers in that |
247 | * list are copied, too. The function uses given memory @a home |
248 | * to allocate all the memory areas used to copy the list of header |
249 | * structure @a hdr. |
250 | * |
251 | * @param home memory home used to allocate new structure |
252 | * @param hdr pointer to the header structure to be copied |
253 | * |
254 | * When copying, only the header structure and parameter lists attached to |
255 | * it are duplicated. The new header structure retains all the references to |
256 | * the strings within the old @a hdr header, including the encoding of the |
257 | * old header, if present. |
258 | * |
259 | * @par Example |
260 | * @code |
261 | * |
262 | * request = sip_request_copy(home, sip->sip_request); |
263 | * |
264 | * @endcode |
265 | * |
266 | * @return |
267 | * A pointer to newly copied header structure, or NULL upon an error. |
268 | * |
269 | */ |
270 | #if SU_HAVE_INLINE1 |
271 | su_inlinestatic inline |
272 | #endif |
273 | sip_request_t *sip_request_copy(su_home_t *home, sip_request_t const *hdr) |
274 | __attribute__((__malloc__)); |
275 | |
276 | #if SU_HAVE_INLINE1 |
277 | su_inlinestatic inline |
278 | sip_request_t *sip_request_copy(su_home_t *home, sip_request_t const *hdr) |
279 | { |
280 | return (sip_request_t *) |
281 | msg_header_copy_as(home, sip_request_class, (msg_header_t const *)hdr); |
282 | } |
283 | #endif |
284 | |
285 | /**Make a @ref sip_request "request line" structure #sip_request_t. |
286 | * |
287 | * The function sip_request_make() makes a new |
288 | * #sip_request_t header structure. It allocates a new |
289 | * header structure, and decodes the string @a s as the |
290 | * value of the structure. |
291 | * |
292 | * @param home memory home used to allocate new header structure. |
293 | * @param s string to be decoded as value of the new header structure |
294 | * |
295 | * @return |
296 | * A pointer to newly maked #sip_request_t header structure, or NULL upon an |
297 | * error. |
298 | * |
299 | */ |
300 | #if SU_HAVE_INLINE1 |
301 | su_inlinestatic inline |
302 | #endif |
303 | sip_request_t *sip_request_make(su_home_t *home, char const *s) |
304 | __attribute__((__malloc__)); |
305 | |
306 | #if SU_HAVE_INLINE1 |
307 | su_inlinestatic inline sip_request_t *sip_request_make(su_home_t *home, char const *s) |
308 | { |
309 | return (sip_request_t *)sip_header_make(home, sip_request_class, s)((sip_header_t *)msg_header_make((home), (sip_request_class), (s))); |
310 | } |
311 | #endif |
312 | |
313 | /**Make a @ref sip_request "request line" from formatting result. |
314 | * |
315 | * Make a new #sip_request_t object using formatting result as its value. |
316 | * The function first prints the arguments according to the format @a fmt |
317 | * specified. Then it allocates a new header structure, and parses the |
318 | * formatting result to the structure #sip_request_t. |
319 | * |
320 | * @param home memory home used to allocate new header structure. |
321 | * @param fmt string used as a printf()-style format |
322 | * @param ... argument list for format |
323 | * |
324 | * @return |
325 | * A pointer to newly |
326 | * makes header structure, or NULL upon an error. |
327 | * |
328 | * @HIDE |
329 | * |
330 | */ |
331 | #if SU_HAVE_INLINE1 |
332 | su_inlinestatic inline |
333 | #endif |
334 | sip_request_t *sip_request_format(su_home_t *home, char const *fmt, ...) |
335 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
336 | |
337 | #if SU_HAVE_INLINE1 |
338 | su_inlinestatic inline sip_request_t *sip_request_format(su_home_t *home, char const *fmt, ...) |
339 | { |
340 | sip_header_t *h; |
341 | va_list ap; |
342 | |
343 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
344 | h = sip_header_vformat(home, sip_request_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_request_class ), (fmt), (ap))); |
345 | va_end(ap)__builtin_va_end(ap); |
346 | |
347 | return (sip_request_t *)h; |
348 | } |
349 | #endif |
350 | |
351 | /** @} */ |
352 | |
353 | /**@addtogroup sip_status |
354 | * @{ |
355 | */ |
356 | |
357 | /** Parse a SIP @ref sip_status "status line". @internal */ |
358 | SOFIAPUBFUN issize_t sip_status_d(su_home_t *, msg_header_t *, |
359 | char *s, isize_t slen); |
360 | |
361 | /** Print a SIP @ref sip_status "status line". @internal */ |
362 | SOFIAPUBFUN issize_t sip_status_e(char b[], isize_t bsiz, |
363 | msg_header_t const *h, int flags); |
364 | |
365 | /**Access a SIP @ref sip_status "status line" |
366 | * structure #sip_status_t from #sip_t. |
367 | * |
368 | */ |
369 | #define sip_status(sip)((sip_status_t *)msg_header_access((msg_pub_t*)(sip), sip_status_class )) \ |
370 | ((sip_status_t *)msg_header_access((msg_pub_t*)(sip), sip_status_class)) |
371 | |
372 | /**Initializer for structure #sip_status_t. |
373 | * |
374 | * A static #sip_status_t structure for |
375 | * @ref sip_status "status line" must be initialized with |
376 | * the SIP_STATUS_INIT() macro. |
377 | * For instance, |
378 | * @code |
379 | * |
380 | * sip_status_t sip_status = SIP_STATUS_INIT; |
381 | * |
382 | * @endcode |
383 | * @HI |
384 | * |
385 | */ |
386 | #define SIP_STATUS_INIT(){{{ 0, 0, sip_status_class }}} SIP_HDR_INIT(status){{{ 0, 0, sip_status_class }}} |
387 | |
388 | /**Initialize a structure #sip_status_t. |
389 | * |
390 | * An #sip_status_t structure for |
391 | * @ref sip_status "status line" can be initialized with the |
392 | * sip_status_init() function/macro. For instance, |
393 | * @code |
394 | * |
395 | * sip_status_t sip_status; |
396 | * |
397 | * sip_status_init(&sip_status); |
398 | * |
399 | * @endcode |
400 | * @HI |
401 | * |
402 | */ |
403 | #if SU_HAVE_INLINE1 |
404 | su_inlinestatic inline sip_status_t *sip_status_init(sip_status_t x[1]) |
405 | { |
406 | return SIP_HEADER_INIT(x, sip_status_class, sizeof(sip_status_t))((void)memset((x), 0, (sizeof(sip_status_t))), (void)(((sip_common_t *)(x))->h_class = (sip_status_class)), (x)); |
407 | } |
408 | #else |
409 | #define sip_status_init(x) \ |
410 | SIP_HEADER_INIT(x, sip_status_class, sizeof(sip_status_t))((void)memset((x), 0, (sizeof(sip_status_t))), (void)(((sip_common_t *)(x))->h_class = (sip_status_class)), (x)) |
411 | #endif |
412 | |
413 | /**Test if header object is instance of #sip_status_t. |
414 | * |
415 | * Check if the header class is an instance of |
416 | * @ref sip_status "status line" object and return true (nonzero), |
417 | * otherwise return false (zero). |
418 | * |
419 | * @param header pointer to the header structure to be tested |
420 | * |
421 | * @retval 1 (true) if the @a header is an instance of header status |
422 | * @retval 0 (false) otherwise |
423 | * |
424 | */ |
425 | #if SU_HAVE_INLINE1 |
426 | su_inlinestatic inline int sip_is_status(sip_header_t const *header) |
427 | { |
428 | return header && header->sh_classsh_common->h_class->hc_hash == sip_status_hash; |
429 | } |
430 | #else |
431 | int sip_is_status(sip_header_t const *header); |
432 | #endif |
433 | |
434 | #define sip_status_p(h)sip_is_status((h)) sip_is_status((h)) |
435 | |
436 | |
437 | /**Duplicate a list of @ref sip_status "status line" header structures #sip_status_t. |
438 | * |
439 | * Duplicate a header |
440 | * structure @a hdr. If the header structure @a hdr |
441 | * contains a reference (@c hdr->x_next) to a list of |
442 | * headers, all the headers in the list are duplicated, too. |
443 | * |
444 | * @param home memory home used to allocate new structure |
445 | * @param hdr header structure to be duplicated |
446 | * |
447 | * When duplicating, all parameter lists and non-constant |
448 | * strings attached to the header are copied, too. The |
449 | * function uses given memory @a home to allocate all the |
450 | * memory areas used to copy the header. |
451 | * |
452 | * @par Example |
453 | * @code |
454 | * |
455 | * status = sip_status_dup(home, sip->sip_status); |
456 | * |
457 | * @endcode |
458 | * |
459 | * @return |
460 | * A pointer to the |
461 | * newly duplicated #sip_status_t header structure, or NULL |
462 | * upon an error. |
463 | * |
464 | */ |
465 | #if SU_HAVE_INLINE1 |
466 | su_inlinestatic inline |
467 | #endif |
468 | sip_status_t *sip_status_dup(su_home_t *home, sip_status_t const *hdr) |
469 | __attribute__((__malloc__)); |
470 | |
471 | #if SU_HAVE_INLINE1 |
472 | su_inlinestatic inline |
473 | sip_status_t *sip_status_dup(su_home_t *home, sip_status_t const *hdr) |
474 | { |
475 | return (sip_status_t *) |
476 | msg_header_dup_as(home, sip_status_class, (msg_header_t const *)hdr); |
477 | } |
478 | #endif |
479 | |
480 | /**Copy a list of @ref sip_status "status line" header structures #sip_status_t. |
481 | * |
482 | * The function sip_status_copy() copies a header structure @a |
483 | * hdr. If the header structure @a hdr contains a reference (@c |
484 | * hdr->h_next) to a list of headers, all the headers in that |
485 | * list are copied, too. The function uses given memory @a home |
486 | * to allocate all the memory areas used to copy the list of header |
487 | * structure @a hdr. |
488 | * |
489 | * @param home memory home used to allocate new structure |
490 | * @param hdr pointer to the header structure to be copied |
491 | * |
492 | * When copying, only the header structure and parameter lists attached to |
493 | * it are duplicated. The new header structure retains all the references to |
494 | * the strings within the old @a hdr header, including the encoding of the |
495 | * old header, if present. |
496 | * |
497 | * @par Example |
498 | * @code |
499 | * |
500 | * status = sip_status_copy(home, sip->sip_status); |
501 | * |
502 | * @endcode |
503 | * |
504 | * @return |
505 | * A pointer to newly copied header structure, or NULL upon an error. |
506 | * |
507 | */ |
508 | #if SU_HAVE_INLINE1 |
509 | su_inlinestatic inline |
510 | #endif |
511 | sip_status_t *sip_status_copy(su_home_t *home, sip_status_t const *hdr) |
512 | __attribute__((__malloc__)); |
513 | |
514 | #if SU_HAVE_INLINE1 |
515 | su_inlinestatic inline |
516 | sip_status_t *sip_status_copy(su_home_t *home, sip_status_t const *hdr) |
517 | { |
518 | return (sip_status_t *) |
519 | msg_header_copy_as(home, sip_status_class, (msg_header_t const *)hdr); |
520 | } |
521 | #endif |
522 | |
523 | /**Make a @ref sip_status "status line" structure #sip_status_t. |
524 | * |
525 | * The function sip_status_make() makes a new |
526 | * #sip_status_t header structure. It allocates a new |
527 | * header structure, and decodes the string @a s as the |
528 | * value of the structure. |
529 | * |
530 | * @param home memory home used to allocate new header structure. |
531 | * @param s string to be decoded as value of the new header structure |
532 | * |
533 | * @return |
534 | * A pointer to newly maked #sip_status_t header structure, or NULL upon an |
535 | * error. |
536 | * |
537 | */ |
538 | #if SU_HAVE_INLINE1 |
539 | su_inlinestatic inline |
540 | #endif |
541 | sip_status_t *sip_status_make(su_home_t *home, char const *s) |
542 | __attribute__((__malloc__)); |
543 | |
544 | #if SU_HAVE_INLINE1 |
545 | su_inlinestatic inline sip_status_t *sip_status_make(su_home_t *home, char const *s) |
546 | { |
547 | return (sip_status_t *)sip_header_make(home, sip_status_class, s)((sip_header_t *)msg_header_make((home), (sip_status_class), ( s))); |
548 | } |
549 | #endif |
550 | |
551 | /**Make a @ref sip_status "status line" from formatting result. |
552 | * |
553 | * Make a new #sip_status_t object using formatting result as its value. |
554 | * The function first prints the arguments according to the format @a fmt |
555 | * specified. Then it allocates a new header structure, and parses the |
556 | * formatting result to the structure #sip_status_t. |
557 | * |
558 | * @param home memory home used to allocate new header structure. |
559 | * @param fmt string used as a printf()-style format |
560 | * @param ... argument list for format |
561 | * |
562 | * @return |
563 | * A pointer to newly |
564 | * makes header structure, or NULL upon an error. |
565 | * |
566 | * @HIDE |
567 | * |
568 | */ |
569 | #if SU_HAVE_INLINE1 |
570 | su_inlinestatic inline |
571 | #endif |
572 | sip_status_t *sip_status_format(su_home_t *home, char const *fmt, ...) |
573 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
574 | |
575 | #if SU_HAVE_INLINE1 |
576 | su_inlinestatic inline sip_status_t *sip_status_format(su_home_t *home, char const *fmt, ...) |
577 | { |
578 | sip_header_t *h; |
579 | va_list ap; |
580 | |
581 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
582 | h = sip_header_vformat(home, sip_status_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_status_class ), (fmt), (ap))); |
583 | va_end(ap)__builtin_va_end(ap); |
584 | |
585 | return (sip_status_t *)h; |
586 | } |
587 | #endif |
588 | |
589 | /** @} */ |
590 | |
591 | /**@addtogroup sip_via |
592 | * @{ |
593 | */ |
594 | |
595 | /** Parse a SIP @ref sip_via "Via header". @internal */ |
596 | SOFIAPUBFUN issize_t sip_via_d(su_home_t *, msg_header_t *, |
597 | char *s, isize_t slen); |
598 | |
599 | /** Print a SIP @ref sip_via "Via header". @internal */ |
600 | SOFIAPUBFUN issize_t sip_via_e(char b[], isize_t bsiz, |
601 | msg_header_t const *h, int flags); |
602 | |
603 | /**Access a SIP @ref sip_via "Via header" |
604 | * structure #sip_via_t from #sip_t. |
605 | * |
606 | */ |
607 | #define sip_via(sip)((sip_via_t *)msg_header_access((msg_pub_t*)(sip), sip_via_class )) \ |
608 | ((sip_via_t *)msg_header_access((msg_pub_t*)(sip), sip_via_class)) |
609 | |
610 | /**Initializer for structure #sip_via_t. |
611 | * |
612 | * A static #sip_via_t structure for |
613 | * @ref sip_via "Via header" must be initialized with |
614 | * the SIP_VIA_INIT() macro. |
615 | * For instance, |
616 | * @code |
617 | * |
618 | * sip_via_t sip_via = SIP_VIA_INIT; |
619 | * |
620 | * @endcode |
621 | * @HI |
622 | * |
623 | */ |
624 | #define SIP_VIA_INIT(){{{ 0, 0, sip_via_class }}} SIP_HDR_INIT(via){{{ 0, 0, sip_via_class }}} |
625 | |
626 | /**Initialize a structure #sip_via_t. |
627 | * |
628 | * An #sip_via_t structure for |
629 | * @ref sip_via "Via header" can be initialized with the |
630 | * sip_via_init() function/macro. For instance, |
631 | * @code |
632 | * |
633 | * sip_via_t sip_via; |
634 | * |
635 | * sip_via_init(&sip_via); |
636 | * |
637 | * @endcode |
638 | * @HI |
639 | * |
640 | */ |
641 | #if SU_HAVE_INLINE1 |
642 | su_inlinestatic inline sip_via_t *sip_via_init(sip_via_t x[1]) |
643 | { |
644 | return SIP_HEADER_INIT(x, sip_via_class, sizeof(sip_via_t))((void)memset((x), 0, (sizeof(sip_via_t))), (void)(((sip_common_t *)(x))->h_class = (sip_via_class)), (x)); |
645 | } |
646 | #else |
647 | #define sip_via_init(x) \ |
648 | SIP_HEADER_INIT(x, sip_via_class, sizeof(sip_via_t))((void)memset((x), 0, (sizeof(sip_via_t))), (void)(((sip_common_t *)(x))->h_class = (sip_via_class)), (x)) |
649 | #endif |
650 | |
651 | /**Test if header object is instance of #sip_via_t. |
652 | * |
653 | * Check if the header class is an instance of |
654 | * @ref sip_via "Via header" object and return true (nonzero), |
655 | * otherwise return false (zero). |
656 | * |
657 | * @param header pointer to the header structure to be tested |
658 | * |
659 | * @retval 1 (true) if the @a header is an instance of header via |
660 | * @retval 0 (false) otherwise |
661 | * |
662 | */ |
663 | #if SU_HAVE_INLINE1 |
664 | su_inlinestatic inline int sip_is_via(sip_header_t const *header) |
665 | { |
666 | return header && header->sh_classsh_common->h_class->hc_hash == sip_via_hash; |
667 | } |
668 | #else |
669 | int sip_is_via(sip_header_t const *header); |
670 | #endif |
671 | |
672 | #define sip_via_p(h)sip_is_via((h)) sip_is_via((h)) |
673 | |
674 | |
675 | /**Duplicate a list of @ref sip_via "Via header" header structures #sip_via_t. |
676 | * |
677 | * Duplicate a header |
678 | * structure @a hdr. If the header structure @a hdr |
679 | * contains a reference (@c hdr->x_next) to a list of |
680 | * headers, all the headers in the list are duplicated, too. |
681 | * |
682 | * @param home memory home used to allocate new structure |
683 | * @param hdr header structure to be duplicated |
684 | * |
685 | * When duplicating, all parameter lists and non-constant |
686 | * strings attached to the header are copied, too. The |
687 | * function uses given memory @a home to allocate all the |
688 | * memory areas used to copy the header. |
689 | * |
690 | * @par Example |
691 | * @code |
692 | * |
693 | * via = sip_via_dup(home, sip->sip_via); |
694 | * |
695 | * @endcode |
696 | * |
697 | * @return |
698 | * A pointer to the |
699 | * newly duplicated #sip_via_t header structure, or NULL |
700 | * upon an error. |
701 | * |
702 | */ |
703 | #if SU_HAVE_INLINE1 |
704 | su_inlinestatic inline |
705 | #endif |
706 | sip_via_t *sip_via_dup(su_home_t *home, sip_via_t const *hdr) |
707 | __attribute__((__malloc__)); |
708 | |
709 | #if SU_HAVE_INLINE1 |
710 | su_inlinestatic inline |
711 | sip_via_t *sip_via_dup(su_home_t *home, sip_via_t const *hdr) |
712 | { |
713 | return (sip_via_t *) |
714 | msg_header_dup_as(home, sip_via_class, (msg_header_t const *)hdr); |
715 | } |
716 | #endif |
717 | |
718 | /**Copy a list of @ref sip_via "Via header" header structures #sip_via_t. |
719 | * |
720 | * The function sip_via_copy() copies a header structure @a |
721 | * hdr. If the header structure @a hdr contains a reference (@c |
722 | * hdr->h_next) to a list of headers, all the headers in that |
723 | * list are copied, too. The function uses given memory @a home |
724 | * to allocate all the memory areas used to copy the list of header |
725 | * structure @a hdr. |
726 | * |
727 | * @param home memory home used to allocate new structure |
728 | * @param hdr pointer to the header structure to be copied |
729 | * |
730 | * When copying, only the header structure and parameter lists attached to |
731 | * it are duplicated. The new header structure retains all the references to |
732 | * the strings within the old @a hdr header, including the encoding of the |
733 | * old header, if present. |
734 | * |
735 | * @par Example |
736 | * @code |
737 | * |
738 | * via = sip_via_copy(home, sip->sip_via); |
739 | * |
740 | * @endcode |
741 | * |
742 | * @return |
743 | * A pointer to newly copied header structure, or NULL upon an error. |
744 | * |
745 | */ |
746 | #if SU_HAVE_INLINE1 |
747 | su_inlinestatic inline |
748 | #endif |
749 | sip_via_t *sip_via_copy(su_home_t *home, sip_via_t const *hdr) |
750 | __attribute__((__malloc__)); |
751 | |
752 | #if SU_HAVE_INLINE1 |
753 | su_inlinestatic inline |
754 | sip_via_t *sip_via_copy(su_home_t *home, sip_via_t const *hdr) |
755 | { |
756 | return (sip_via_t *) |
757 | msg_header_copy_as(home, sip_via_class, (msg_header_t const *)hdr); |
758 | } |
759 | #endif |
760 | |
761 | /**Make a @ref sip_via "Via header" structure #sip_via_t. |
762 | * |
763 | * The function sip_via_make() makes a new |
764 | * #sip_via_t header structure. It allocates a new |
765 | * header structure, and decodes the string @a s as the |
766 | * value of the structure. |
767 | * |
768 | * @param home memory home used to allocate new header structure. |
769 | * @param s string to be decoded as value of the new header structure |
770 | * |
771 | * @return |
772 | * A pointer to newly maked #sip_via_t header structure, or NULL upon an |
773 | * error. |
774 | * |
775 | */ |
776 | #if SU_HAVE_INLINE1 |
777 | su_inlinestatic inline |
778 | #endif |
779 | sip_via_t *sip_via_make(su_home_t *home, char const *s) |
780 | __attribute__((__malloc__)); |
781 | |
782 | #if SU_HAVE_INLINE1 |
783 | su_inlinestatic inline sip_via_t *sip_via_make(su_home_t *home, char const *s) |
784 | { |
785 | return (sip_via_t *)sip_header_make(home, sip_via_class, s)((sip_header_t *)msg_header_make((home), (sip_via_class), (s) )); |
786 | } |
787 | #endif |
788 | |
789 | /**Make a @ref sip_via "Via header" from formatting result. |
790 | * |
791 | * Make a new #sip_via_t object using formatting result as its value. |
792 | * The function first prints the arguments according to the format @a fmt |
793 | * specified. Then it allocates a new header structure, and parses the |
794 | * formatting result to the structure #sip_via_t. |
795 | * |
796 | * @param home memory home used to allocate new header structure. |
797 | * @param fmt string used as a printf()-style format |
798 | * @param ... argument list for format |
799 | * |
800 | * @return |
801 | * A pointer to newly |
802 | * makes header structure, or NULL upon an error. |
803 | * |
804 | * @HIDE |
805 | * |
806 | */ |
807 | #if SU_HAVE_INLINE1 |
808 | su_inlinestatic inline |
809 | #endif |
810 | sip_via_t *sip_via_format(su_home_t *home, char const *fmt, ...) |
811 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
812 | |
813 | #if SU_HAVE_INLINE1 |
814 | su_inlinestatic inline sip_via_t *sip_via_format(su_home_t *home, char const *fmt, ...) |
815 | { |
816 | sip_header_t *h; |
817 | va_list ap; |
818 | |
819 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
820 | h = sip_header_vformat(home, sip_via_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_via_class), ( fmt), (ap))); |
821 | va_end(ap)__builtin_va_end(ap); |
822 | |
823 | return (sip_via_t *)h; |
824 | } |
825 | #endif |
826 | |
827 | /** @} */ |
828 | |
829 | /**@addtogroup sip_route |
830 | * @{ |
831 | */ |
832 | |
833 | /** Parse a SIP @ref sip_route "Route header". @internal */ |
834 | SOFIAPUBFUN issize_t sip_route_d(su_home_t *, msg_header_t *, |
835 | char *s, isize_t slen); |
836 | |
837 | /** Print a SIP @ref sip_route "Route header". @internal */ |
838 | SOFIAPUBFUN issize_t sip_route_e(char b[], isize_t bsiz, |
839 | msg_header_t const *h, int flags); |
840 | |
841 | /**Access a SIP @ref sip_route "Route header" |
842 | * structure #sip_route_t from #sip_t. |
843 | * |
844 | */ |
845 | #define sip_route(sip)((sip_route_t *)msg_header_access((msg_pub_t*)(sip), sip_route_class )) \ |
846 | ((sip_route_t *)msg_header_access((msg_pub_t*)(sip), sip_route_class)) |
847 | |
848 | /**Initializer for structure #sip_route_t. |
849 | * |
850 | * A static #sip_route_t structure for |
851 | * @ref sip_route "Route header" must be initialized with |
852 | * the SIP_ROUTE_INIT() macro. |
853 | * For instance, |
854 | * @code |
855 | * |
856 | * sip_route_t sip_route = SIP_ROUTE_INIT; |
857 | * |
858 | * @endcode |
859 | * @HI |
860 | * |
861 | */ |
862 | #define SIP_ROUTE_INIT(){{{ 0, 0, sip_route_class }}} SIP_HDR_INIT(route){{{ 0, 0, sip_route_class }}} |
863 | |
864 | /**Initialize a structure #sip_route_t. |
865 | * |
866 | * An #sip_route_t structure for |
867 | * @ref sip_route "Route header" can be initialized with the |
868 | * sip_route_init() function/macro. For instance, |
869 | * @code |
870 | * |
871 | * sip_route_t sip_route; |
872 | * |
873 | * sip_route_init(&sip_route); |
874 | * |
875 | * @endcode |
876 | * @HI |
877 | * |
878 | */ |
879 | #if SU_HAVE_INLINE1 |
880 | su_inlinestatic inline sip_route_t *sip_route_init(sip_route_t x[1]) |
881 | { |
882 | return SIP_HEADER_INIT(x, sip_route_class, sizeof(sip_route_t))((void)memset((x), 0, (sizeof(sip_route_t))), (void)(((sip_common_t *)(x))->h_class = (sip_route_class)), (x)); |
883 | } |
884 | #else |
885 | #define sip_route_init(x) \ |
886 | SIP_HEADER_INIT(x, sip_route_class, sizeof(sip_route_t))((void)memset((x), 0, (sizeof(sip_route_t))), (void)(((sip_common_t *)(x))->h_class = (sip_route_class)), (x)) |
887 | #endif |
888 | |
889 | /**Test if header object is instance of #sip_route_t. |
890 | * |
891 | * Check if the header class is an instance of |
892 | * @ref sip_route "Route header" object and return true (nonzero), |
893 | * otherwise return false (zero). |
894 | * |
895 | * @param header pointer to the header structure to be tested |
896 | * |
897 | * @retval 1 (true) if the @a header is an instance of header route |
898 | * @retval 0 (false) otherwise |
899 | * |
900 | */ |
901 | #if SU_HAVE_INLINE1 |
902 | su_inlinestatic inline int sip_is_route(sip_header_t const *header) |
903 | { |
904 | return header && header->sh_classsh_common->h_class->hc_hash == sip_route_hash; |
905 | } |
906 | #else |
907 | int sip_is_route(sip_header_t const *header); |
908 | #endif |
909 | |
910 | #define sip_route_p(h)sip_is_route((h)) sip_is_route((h)) |
911 | |
912 | |
913 | /**Duplicate a list of @ref sip_route "Route header" header structures #sip_route_t. |
914 | * |
915 | * Duplicate a header |
916 | * structure @a hdr. If the header structure @a hdr |
917 | * contains a reference (@c hdr->x_next) to a list of |
918 | * headers, all the headers in the list are duplicated, too. |
919 | * |
920 | * @param home memory home used to allocate new structure |
921 | * @param hdr header structure to be duplicated |
922 | * |
923 | * When duplicating, all parameter lists and non-constant |
924 | * strings attached to the header are copied, too. The |
925 | * function uses given memory @a home to allocate all the |
926 | * memory areas used to copy the header. |
927 | * |
928 | * @par Example |
929 | * @code |
930 | * |
931 | * route = sip_route_dup(home, sip->sip_route); |
932 | * |
933 | * @endcode |
934 | * |
935 | * @return |
936 | * A pointer to the |
937 | * newly duplicated #sip_route_t header structure, or NULL |
938 | * upon an error. |
939 | * |
940 | */ |
941 | #if SU_HAVE_INLINE1 |
942 | su_inlinestatic inline |
943 | #endif |
944 | sip_route_t *sip_route_dup(su_home_t *home, sip_route_t const *hdr) |
945 | __attribute__((__malloc__)); |
946 | |
947 | #if SU_HAVE_INLINE1 |
948 | su_inlinestatic inline |
949 | sip_route_t *sip_route_dup(su_home_t *home, sip_route_t const *hdr) |
950 | { |
951 | return (sip_route_t *) |
952 | msg_header_dup_as(home, sip_route_class, (msg_header_t const *)hdr); |
953 | } |
954 | #endif |
955 | |
956 | /**Copy a list of @ref sip_route "Route header" header structures #sip_route_t. |
957 | * |
958 | * The function sip_route_copy() copies a header structure @a |
959 | * hdr. If the header structure @a hdr contains a reference (@c |
960 | * hdr->h_next) to a list of headers, all the headers in that |
961 | * list are copied, too. The function uses given memory @a home |
962 | * to allocate all the memory areas used to copy the list of header |
963 | * structure @a hdr. |
964 | * |
965 | * @param home memory home used to allocate new structure |
966 | * @param hdr pointer to the header structure to be copied |
967 | * |
968 | * When copying, only the header structure and parameter lists attached to |
969 | * it are duplicated. The new header structure retains all the references to |
970 | * the strings within the old @a hdr header, including the encoding of the |
971 | * old header, if present. |
972 | * |
973 | * @par Example |
974 | * @code |
975 | * |
976 | * route = sip_route_copy(home, sip->sip_route); |
977 | * |
978 | * @endcode |
979 | * |
980 | * @return |
981 | * A pointer to newly copied header structure, or NULL upon an error. |
982 | * |
983 | */ |
984 | #if SU_HAVE_INLINE1 |
985 | su_inlinestatic inline |
986 | #endif |
987 | sip_route_t *sip_route_copy(su_home_t *home, sip_route_t const *hdr) |
988 | __attribute__((__malloc__)); |
989 | |
990 | #if SU_HAVE_INLINE1 |
991 | su_inlinestatic inline |
992 | sip_route_t *sip_route_copy(su_home_t *home, sip_route_t const *hdr) |
993 | { |
994 | return (sip_route_t *) |
995 | msg_header_copy_as(home, sip_route_class, (msg_header_t const *)hdr); |
996 | } |
997 | #endif |
998 | |
999 | /**Make a @ref sip_route "Route header" structure #sip_route_t. |
1000 | * |
1001 | * The function sip_route_make() makes a new |
1002 | * #sip_route_t header structure. It allocates a new |
1003 | * header structure, and decodes the string @a s as the |
1004 | * value of the structure. |
1005 | * |
1006 | * @param home memory home used to allocate new header structure. |
1007 | * @param s string to be decoded as value of the new header structure |
1008 | * |
1009 | * @return |
1010 | * A pointer to newly maked #sip_route_t header structure, or NULL upon an |
1011 | * error. |
1012 | * |
1013 | */ |
1014 | #if SU_HAVE_INLINE1 |
1015 | su_inlinestatic inline |
1016 | #endif |
1017 | sip_route_t *sip_route_make(su_home_t *home, char const *s) |
1018 | __attribute__((__malloc__)); |
1019 | |
1020 | #if SU_HAVE_INLINE1 |
1021 | su_inlinestatic inline sip_route_t *sip_route_make(su_home_t *home, char const *s) |
1022 | { |
1023 | return (sip_route_t *)sip_header_make(home, sip_route_class, s)((sip_header_t *)msg_header_make((home), (sip_route_class), ( s))); |
1024 | } |
1025 | #endif |
1026 | |
1027 | /**Make a @ref sip_route "Route header" from formatting result. |
1028 | * |
1029 | * Make a new #sip_route_t object using formatting result as its value. |
1030 | * The function first prints the arguments according to the format @a fmt |
1031 | * specified. Then it allocates a new header structure, and parses the |
1032 | * formatting result to the structure #sip_route_t. |
1033 | * |
1034 | * @param home memory home used to allocate new header structure. |
1035 | * @param fmt string used as a printf()-style format |
1036 | * @param ... argument list for format |
1037 | * |
1038 | * @return |
1039 | * A pointer to newly |
1040 | * makes header structure, or NULL upon an error. |
1041 | * |
1042 | * @HIDE |
1043 | * |
1044 | */ |
1045 | #if SU_HAVE_INLINE1 |
1046 | su_inlinestatic inline |
1047 | #endif |
1048 | sip_route_t *sip_route_format(su_home_t *home, char const *fmt, ...) |
1049 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
1050 | |
1051 | #if SU_HAVE_INLINE1 |
1052 | su_inlinestatic inline sip_route_t *sip_route_format(su_home_t *home, char const *fmt, ...) |
1053 | { |
1054 | sip_header_t *h; |
1055 | va_list ap; |
1056 | |
1057 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
1058 | h = sip_header_vformat(home, sip_route_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_route_class) , (fmt), (ap))); |
1059 | va_end(ap)__builtin_va_end(ap); |
1060 | |
1061 | return (sip_route_t *)h; |
1062 | } |
1063 | #endif |
1064 | |
1065 | /** @} */ |
1066 | |
1067 | /**@addtogroup sip_record_route |
1068 | * @{ |
1069 | */ |
1070 | |
1071 | /** Parse a SIP @ref sip_record_route "Record-Route header". @internal */ |
1072 | SOFIAPUBFUN issize_t sip_record_route_d(su_home_t *, msg_header_t *, |
1073 | char *s, isize_t slen); |
1074 | |
1075 | /** Print a SIP @ref sip_record_route "Record-Route header". @internal */ |
1076 | SOFIAPUBFUN issize_t sip_record_route_e(char b[], isize_t bsiz, |
1077 | msg_header_t const *h, int flags); |
1078 | |
1079 | /**Access a SIP @ref sip_record_route "Record-Route header" |
1080 | * structure #sip_record_route_t from #sip_t. |
1081 | * |
1082 | */ |
1083 | #define sip_record_route(sip)((sip_record_route_t *)msg_header_access((msg_pub_t*)(sip), sip_record_route_class )) \ |
1084 | ((sip_record_route_t *)msg_header_access((msg_pub_t*)(sip), sip_record_route_class)) |
1085 | |
1086 | /**Initializer for structure #sip_record_route_t. |
1087 | * |
1088 | * A static #sip_record_route_t structure for |
1089 | * @ref sip_record_route "Record-Route header" must be initialized with |
1090 | * the SIP_RECORD_ROUTE_INIT() macro. |
1091 | * For instance, |
1092 | * @code |
1093 | * |
1094 | * sip_record_route_t sip_record_route = SIP_RECORD_ROUTE_INIT; |
1095 | * |
1096 | * @endcode |
1097 | * @HI |
1098 | * |
1099 | */ |
1100 | #define SIP_RECORD_ROUTE_INIT(){{{ 0, 0, sip_record_route_class }}} SIP_HDR_INIT(record_route){{{ 0, 0, sip_record_route_class }}} |
1101 | |
1102 | /**Initialize a structure #sip_record_route_t. |
1103 | * |
1104 | * An #sip_record_route_t structure for |
1105 | * @ref sip_record_route "Record-Route header" can be initialized with the |
1106 | * sip_record_route_init() function/macro. For instance, |
1107 | * @code |
1108 | * |
1109 | * sip_record_route_t sip_record_route; |
1110 | * |
1111 | * sip_record_route_init(&sip_record_route); |
1112 | * |
1113 | * @endcode |
1114 | * @HI |
1115 | * |
1116 | */ |
1117 | #if SU_HAVE_INLINE1 |
1118 | su_inlinestatic inline sip_record_route_t *sip_record_route_init(sip_record_route_t x[1]) |
1119 | { |
1120 | return SIP_HEADER_INIT(x, sip_record_route_class, sizeof(sip_record_route_t))((void)memset((x), 0, (sizeof(sip_record_route_t))), (void)(( (sip_common_t *)(x))->h_class = (sip_record_route_class)), (x)); |
1121 | } |
1122 | #else |
1123 | #define sip_record_route_init(x) \ |
1124 | SIP_HEADER_INIT(x, sip_record_route_class, sizeof(sip_record_route_t))((void)memset((x), 0, (sizeof(sip_record_route_t))), (void)(( (sip_common_t *)(x))->h_class = (sip_record_route_class)), (x)) |
1125 | #endif |
1126 | |
1127 | /**Test if header object is instance of #sip_record_route_t. |
1128 | * |
1129 | * Check if the header class is an instance of |
1130 | * @ref sip_record_route "Record-Route header" object and return true (nonzero), |
1131 | * otherwise return false (zero). |
1132 | * |
1133 | * @param header pointer to the header structure to be tested |
1134 | * |
1135 | * @retval 1 (true) if the @a header is an instance of header record_route |
1136 | * @retval 0 (false) otherwise |
1137 | * |
1138 | */ |
1139 | #if SU_HAVE_INLINE1 |
1140 | su_inlinestatic inline int sip_is_record_route(sip_header_t const *header) |
1141 | { |
1142 | return header && header->sh_classsh_common->h_class->hc_hash == sip_record_route_hash; |
1143 | } |
1144 | #else |
1145 | int sip_is_record_route(sip_header_t const *header); |
1146 | #endif |
1147 | |
1148 | #define sip_record_route_p(h)sip_is_record_route((h)) sip_is_record_route((h)) |
1149 | |
1150 | |
1151 | /**Duplicate a list of @ref sip_record_route "Record-Route header" header structures #sip_record_route_t. |
1152 | * |
1153 | * Duplicate a header |
1154 | * structure @a hdr. If the header structure @a hdr |
1155 | * contains a reference (@c hdr->x_next) to a list of |
1156 | * headers, all the headers in the list are duplicated, too. |
1157 | * |
1158 | * @param home memory home used to allocate new structure |
1159 | * @param hdr header structure to be duplicated |
1160 | * |
1161 | * When duplicating, all parameter lists and non-constant |
1162 | * strings attached to the header are copied, too. The |
1163 | * function uses given memory @a home to allocate all the |
1164 | * memory areas used to copy the header. |
1165 | * |
1166 | * @par Example |
1167 | * @code |
1168 | * |
1169 | * record_route = sip_record_route_dup(home, sip->sip_record_route); |
1170 | * |
1171 | * @endcode |
1172 | * |
1173 | * @return |
1174 | * A pointer to the |
1175 | * newly duplicated #sip_record_route_t header structure, or NULL |
1176 | * upon an error. |
1177 | * |
1178 | */ |
1179 | #if SU_HAVE_INLINE1 |
1180 | su_inlinestatic inline |
1181 | #endif |
1182 | sip_record_route_t *sip_record_route_dup(su_home_t *home, sip_record_route_t const *hdr) |
1183 | __attribute__((__malloc__)); |
1184 | |
1185 | #if SU_HAVE_INLINE1 |
1186 | su_inlinestatic inline |
1187 | sip_record_route_t *sip_record_route_dup(su_home_t *home, sip_record_route_t const *hdr) |
1188 | { |
1189 | return (sip_record_route_t *) |
1190 | msg_header_dup_as(home, sip_record_route_class, (msg_header_t const *)hdr); |
1191 | } |
1192 | #endif |
1193 | |
1194 | /**Copy a list of @ref sip_record_route "Record-Route header" header structures #sip_record_route_t. |
1195 | * |
1196 | * The function sip_record_route_copy() copies a header structure @a |
1197 | * hdr. If the header structure @a hdr contains a reference (@c |
1198 | * hdr->h_next) to a list of headers, all the headers in that |
1199 | * list are copied, too. The function uses given memory @a home |
1200 | * to allocate all the memory areas used to copy the list of header |
1201 | * structure @a hdr. |
1202 | * |
1203 | * @param home memory home used to allocate new structure |
1204 | * @param hdr pointer to the header structure to be copied |
1205 | * |
1206 | * When copying, only the header structure and parameter lists attached to |
1207 | * it are duplicated. The new header structure retains all the references to |
1208 | * the strings within the old @a hdr header, including the encoding of the |
1209 | * old header, if present. |
1210 | * |
1211 | * @par Example |
1212 | * @code |
1213 | * |
1214 | * record_route = sip_record_route_copy(home, sip->sip_record_route); |
1215 | * |
1216 | * @endcode |
1217 | * |
1218 | * @return |
1219 | * A pointer to newly copied header structure, or NULL upon an error. |
1220 | * |
1221 | */ |
1222 | #if SU_HAVE_INLINE1 |
1223 | su_inlinestatic inline |
1224 | #endif |
1225 | sip_record_route_t *sip_record_route_copy(su_home_t *home, sip_record_route_t const *hdr) |
1226 | __attribute__((__malloc__)); |
1227 | |
1228 | #if SU_HAVE_INLINE1 |
1229 | su_inlinestatic inline |
1230 | sip_record_route_t *sip_record_route_copy(su_home_t *home, sip_record_route_t const *hdr) |
1231 | { |
1232 | return (sip_record_route_t *) |
1233 | msg_header_copy_as(home, sip_record_route_class, (msg_header_t const *)hdr); |
1234 | } |
1235 | #endif |
1236 | |
1237 | /**Make a @ref sip_record_route "Record-Route header" structure #sip_record_route_t. |
1238 | * |
1239 | * The function sip_record_route_make() makes a new |
1240 | * #sip_record_route_t header structure. It allocates a new |
1241 | * header structure, and decodes the string @a s as the |
1242 | * value of the structure. |
1243 | * |
1244 | * @param home memory home used to allocate new header structure. |
1245 | * @param s string to be decoded as value of the new header structure |
1246 | * |
1247 | * @return |
1248 | * A pointer to newly maked #sip_record_route_t header structure, or NULL upon an |
1249 | * error. |
1250 | * |
1251 | */ |
1252 | #if SU_HAVE_INLINE1 |
1253 | su_inlinestatic inline |
1254 | #endif |
1255 | sip_record_route_t *sip_record_route_make(su_home_t *home, char const *s) |
1256 | __attribute__((__malloc__)); |
1257 | |
1258 | #if SU_HAVE_INLINE1 |
1259 | su_inlinestatic inline sip_record_route_t *sip_record_route_make(su_home_t *home, char const *s) |
1260 | { |
1261 | return (sip_record_route_t *)sip_header_make(home, sip_record_route_class, s)((sip_header_t *)msg_header_make((home), (sip_record_route_class ), (s))); |
1262 | } |
1263 | #endif |
1264 | |
1265 | /**Make a @ref sip_record_route "Record-Route header" from formatting result. |
1266 | * |
1267 | * Make a new #sip_record_route_t object using formatting result as its value. |
1268 | * The function first prints the arguments according to the format @a fmt |
1269 | * specified. Then it allocates a new header structure, and parses the |
1270 | * formatting result to the structure #sip_record_route_t. |
1271 | * |
1272 | * @param home memory home used to allocate new header structure. |
1273 | * @param fmt string used as a printf()-style format |
1274 | * @param ... argument list for format |
1275 | * |
1276 | * @return |
1277 | * A pointer to newly |
1278 | * makes header structure, or NULL upon an error. |
1279 | * |
1280 | * @HIDE |
1281 | * |
1282 | */ |
1283 | #if SU_HAVE_INLINE1 |
1284 | su_inlinestatic inline |
1285 | #endif |
1286 | sip_record_route_t *sip_record_route_format(su_home_t *home, char const *fmt, ...) |
1287 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
1288 | |
1289 | #if SU_HAVE_INLINE1 |
1290 | su_inlinestatic inline sip_record_route_t *sip_record_route_format(su_home_t *home, char const *fmt, ...) |
1291 | { |
1292 | sip_header_t *h; |
1293 | va_list ap; |
1294 | |
1295 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
1296 | h = sip_header_vformat(home, sip_record_route_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_record_route_class ), (fmt), (ap))); |
1297 | va_end(ap)__builtin_va_end(ap); |
1298 | |
1299 | return (sip_record_route_t *)h; |
1300 | } |
1301 | #endif |
1302 | |
1303 | /** @} */ |
1304 | |
1305 | /**@addtogroup sip_max_forwards |
1306 | * @{ |
1307 | */ |
1308 | |
1309 | /** Parse a SIP @ref sip_max_forwards "Max-Forwards header". @internal */ |
1310 | SOFIAPUBFUN issize_t sip_max_forwards_d(su_home_t *, msg_header_t *, |
1311 | char *s, isize_t slen); |
1312 | |
1313 | /** Print a SIP @ref sip_max_forwards "Max-Forwards header". @internal */ |
1314 | SOFIAPUBFUN issize_t sip_max_forwards_e(char b[], isize_t bsiz, |
1315 | msg_header_t const *h, int flags); |
1316 | |
1317 | /**Access a SIP @ref sip_max_forwards "Max-Forwards header" |
1318 | * structure #sip_max_forwards_t from #sip_t. |
1319 | * |
1320 | */ |
1321 | #define sip_max_forwards(sip)((sip_max_forwards_t *)msg_header_access((msg_pub_t*)(sip), sip_max_forwards_class )) \ |
1322 | ((sip_max_forwards_t *)msg_header_access((msg_pub_t*)(sip), sip_max_forwards_class)) |
1323 | |
1324 | /**Initializer for structure #sip_max_forwards_t. |
1325 | * |
1326 | * A static #sip_max_forwards_t structure for |
1327 | * @ref sip_max_forwards "Max-Forwards header" must be initialized with |
1328 | * the SIP_MAX_FORWARDS_INIT() macro. |
1329 | * For instance, |
1330 | * @code |
1331 | * |
1332 | * sip_max_forwards_t sip_max_forwards = SIP_MAX_FORWARDS_INIT; |
1333 | * |
1334 | * @endcode |
1335 | * @HI |
1336 | * |
1337 | */ |
1338 | #define SIP_MAX_FORWARDS_INIT(){{{ 0, 0, sip_max_forwards_class }}} SIP_HDR_INIT(max_forwards){{{ 0, 0, sip_max_forwards_class }}} |
1339 | |
1340 | /**Initialize a structure #sip_max_forwards_t. |
1341 | * |
1342 | * An #sip_max_forwards_t structure for |
1343 | * @ref sip_max_forwards "Max-Forwards header" can be initialized with the |
1344 | * sip_max_forwards_init() function/macro. For instance, |
1345 | * @code |
1346 | * |
1347 | * sip_max_forwards_t sip_max_forwards; |
1348 | * |
1349 | * sip_max_forwards_init(&sip_max_forwards); |
1350 | * |
1351 | * @endcode |
1352 | * @HI |
1353 | * |
1354 | */ |
1355 | #if SU_HAVE_INLINE1 |
1356 | su_inlinestatic inline sip_max_forwards_t *sip_max_forwards_init(sip_max_forwards_t x[1]) |
1357 | { |
1358 | return SIP_HEADER_INIT(x, sip_max_forwards_class, sizeof(sip_max_forwards_t))((void)memset((x), 0, (sizeof(sip_max_forwards_t))), (void)(( (sip_common_t *)(x))->h_class = (sip_max_forwards_class)), (x)); |
1359 | } |
1360 | #else |
1361 | #define sip_max_forwards_init(x) \ |
1362 | SIP_HEADER_INIT(x, sip_max_forwards_class, sizeof(sip_max_forwards_t))((void)memset((x), 0, (sizeof(sip_max_forwards_t))), (void)(( (sip_common_t *)(x))->h_class = (sip_max_forwards_class)), (x)) |
1363 | #endif |
1364 | |
1365 | /**Test if header object is instance of #sip_max_forwards_t. |
1366 | * |
1367 | * Check if the header class is an instance of |
1368 | * @ref sip_max_forwards "Max-Forwards header" object and return true (nonzero), |
1369 | * otherwise return false (zero). |
1370 | * |
1371 | * @param header pointer to the header structure to be tested |
1372 | * |
1373 | * @retval 1 (true) if the @a header is an instance of header max_forwards |
1374 | * @retval 0 (false) otherwise |
1375 | * |
1376 | */ |
1377 | #if SU_HAVE_INLINE1 |
1378 | su_inlinestatic inline int sip_is_max_forwards(sip_header_t const *header) |
1379 | { |
1380 | return header && header->sh_classsh_common->h_class->hc_hash == sip_max_forwards_hash; |
1381 | } |
1382 | #else |
1383 | int sip_is_max_forwards(sip_header_t const *header); |
1384 | #endif |
1385 | |
1386 | #define sip_max_forwards_p(h)sip_is_max_forwards((h)) sip_is_max_forwards((h)) |
1387 | |
1388 | |
1389 | /**Duplicate a list of @ref sip_max_forwards "Max-Forwards header" header structures #sip_max_forwards_t. |
1390 | * |
1391 | * Duplicate a header |
1392 | * structure @a hdr. If the header structure @a hdr |
1393 | * contains a reference (@c hdr->x_next) to a list of |
1394 | * headers, all the headers in the list are duplicated, too. |
1395 | * |
1396 | * @param home memory home used to allocate new structure |
1397 | * @param hdr header structure to be duplicated |
1398 | * |
1399 | * When duplicating, all parameter lists and non-constant |
1400 | * strings attached to the header are copied, too. The |
1401 | * function uses given memory @a home to allocate all the |
1402 | * memory areas used to copy the header. |
1403 | * |
1404 | * @par Example |
1405 | * @code |
1406 | * |
1407 | * max_forwards = sip_max_forwards_dup(home, sip->sip_max_forwards); |
1408 | * |
1409 | * @endcode |
1410 | * |
1411 | * @return |
1412 | * A pointer to the |
1413 | * newly duplicated #sip_max_forwards_t header structure, or NULL |
1414 | * upon an error. |
1415 | * |
1416 | */ |
1417 | #if SU_HAVE_INLINE1 |
1418 | su_inlinestatic inline |
1419 | #endif |
1420 | sip_max_forwards_t *sip_max_forwards_dup(su_home_t *home, sip_max_forwards_t const *hdr) |
1421 | __attribute__((__malloc__)); |
1422 | |
1423 | #if SU_HAVE_INLINE1 |
1424 | su_inlinestatic inline |
1425 | sip_max_forwards_t *sip_max_forwards_dup(su_home_t *home, sip_max_forwards_t const *hdr) |
1426 | { |
1427 | return (sip_max_forwards_t *) |
1428 | msg_header_dup_as(home, sip_max_forwards_class, (msg_header_t const *)hdr); |
1429 | } |
1430 | #endif |
1431 | |
1432 | /**Copy a list of @ref sip_max_forwards "Max-Forwards header" header structures #sip_max_forwards_t. |
1433 | * |
1434 | * The function sip_max_forwards_copy() copies a header structure @a |
1435 | * hdr. If the header structure @a hdr contains a reference (@c |
1436 | * hdr->h_next) to a list of headers, all the headers in that |
1437 | * list are copied, too. The function uses given memory @a home |
1438 | * to allocate all the memory areas used to copy the list of header |
1439 | * structure @a hdr. |
1440 | * |
1441 | * @param home memory home used to allocate new structure |
1442 | * @param hdr pointer to the header structure to be copied |
1443 | * |
1444 | * When copying, only the header structure and parameter lists attached to |
1445 | * it are duplicated. The new header structure retains all the references to |
1446 | * the strings within the old @a hdr header, including the encoding of the |
1447 | * old header, if present. |
1448 | * |
1449 | * @par Example |
1450 | * @code |
1451 | * |
1452 | * max_forwards = sip_max_forwards_copy(home, sip->sip_max_forwards); |
1453 | * |
1454 | * @endcode |
1455 | * |
1456 | * @return |
1457 | * A pointer to newly copied header structure, or NULL upon an error. |
1458 | * |
1459 | */ |
1460 | #if SU_HAVE_INLINE1 |
1461 | su_inlinestatic inline |
1462 | #endif |
1463 | sip_max_forwards_t *sip_max_forwards_copy(su_home_t *home, sip_max_forwards_t const *hdr) |
1464 | __attribute__((__malloc__)); |
1465 | |
1466 | #if SU_HAVE_INLINE1 |
1467 | su_inlinestatic inline |
1468 | sip_max_forwards_t *sip_max_forwards_copy(su_home_t *home, sip_max_forwards_t const *hdr) |
1469 | { |
1470 | return (sip_max_forwards_t *) |
1471 | msg_header_copy_as(home, sip_max_forwards_class, (msg_header_t const *)hdr); |
1472 | } |
1473 | #endif |
1474 | |
1475 | /**Make a @ref sip_max_forwards "Max-Forwards header" structure #sip_max_forwards_t. |
1476 | * |
1477 | * The function sip_max_forwards_make() makes a new |
1478 | * #sip_max_forwards_t header structure. It allocates a new |
1479 | * header structure, and decodes the string @a s as the |
1480 | * value of the structure. |
1481 | * |
1482 | * @param home memory home used to allocate new header structure. |
1483 | * @param s string to be decoded as value of the new header structure |
1484 | * |
1485 | * @return |
1486 | * A pointer to newly maked #sip_max_forwards_t header structure, or NULL upon an |
1487 | * error. |
1488 | * |
1489 | */ |
1490 | #if SU_HAVE_INLINE1 |
1491 | su_inlinestatic inline |
1492 | #endif |
1493 | sip_max_forwards_t *sip_max_forwards_make(su_home_t *home, char const *s) |
1494 | __attribute__((__malloc__)); |
1495 | |
1496 | #if SU_HAVE_INLINE1 |
1497 | su_inlinestatic inline sip_max_forwards_t *sip_max_forwards_make(su_home_t *home, char const *s) |
1498 | { |
1499 | return (sip_max_forwards_t *)sip_header_make(home, sip_max_forwards_class, s)((sip_header_t *)msg_header_make((home), (sip_max_forwards_class ), (s))); |
1500 | } |
1501 | #endif |
1502 | |
1503 | /**Make a @ref sip_max_forwards "Max-Forwards header" from formatting result. |
1504 | * |
1505 | * Make a new #sip_max_forwards_t object using formatting result as its value. |
1506 | * The function first prints the arguments according to the format @a fmt |
1507 | * specified. Then it allocates a new header structure, and parses the |
1508 | * formatting result to the structure #sip_max_forwards_t. |
1509 | * |
1510 | * @param home memory home used to allocate new header structure. |
1511 | * @param fmt string used as a printf()-style format |
1512 | * @param ... argument list for format |
1513 | * |
1514 | * @return |
1515 | * A pointer to newly |
1516 | * makes header structure, or NULL upon an error. |
1517 | * |
1518 | * @HIDE |
1519 | * |
1520 | */ |
1521 | #if SU_HAVE_INLINE1 |
1522 | su_inlinestatic inline |
1523 | #endif |
1524 | sip_max_forwards_t *sip_max_forwards_format(su_home_t *home, char const *fmt, ...) |
1525 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
1526 | |
1527 | #if SU_HAVE_INLINE1 |
1528 | su_inlinestatic inline sip_max_forwards_t *sip_max_forwards_format(su_home_t *home, char const *fmt, ...) |
1529 | { |
1530 | sip_header_t *h; |
1531 | va_list ap; |
1532 | |
1533 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
1534 | h = sip_header_vformat(home, sip_max_forwards_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_max_forwards_class ), (fmt), (ap))); |
1535 | va_end(ap)__builtin_va_end(ap); |
1536 | |
1537 | return (sip_max_forwards_t *)h; |
1538 | } |
1539 | #endif |
1540 | |
1541 | /** @} */ |
1542 | |
1543 | /**@addtogroup sip_proxy_require |
1544 | * @{ |
1545 | */ |
1546 | |
1547 | /** Parse a SIP @ref sip_proxy_require "Proxy-Require header". @internal */ |
1548 | SOFIAPUBFUN issize_t sip_proxy_require_d(su_home_t *, msg_header_t *, |
1549 | char *s, isize_t slen); |
1550 | |
1551 | /** Print a SIP @ref sip_proxy_require "Proxy-Require header". @internal */ |
1552 | SOFIAPUBFUN issize_t sip_proxy_require_e(char b[], isize_t bsiz, |
1553 | msg_header_t const *h, int flags); |
1554 | |
1555 | /**Access a SIP @ref sip_proxy_require "Proxy-Require header" |
1556 | * structure #sip_proxy_require_t from #sip_t. |
1557 | * |
1558 | */ |
1559 | #define sip_proxy_require(sip)((sip_proxy_require_t *)msg_header_access((msg_pub_t*)(sip), sip_proxy_require_class )) \ |
1560 | ((sip_proxy_require_t *)msg_header_access((msg_pub_t*)(sip), sip_proxy_require_class)) |
1561 | |
1562 | /**Initializer for structure #sip_proxy_require_t. |
1563 | * |
1564 | * A static #sip_proxy_require_t structure for |
1565 | * @ref sip_proxy_require "Proxy-Require header" must be initialized with |
1566 | * the SIP_PROXY_REQUIRE_INIT() macro. |
1567 | * For instance, |
1568 | * @code |
1569 | * |
1570 | * sip_proxy_require_t sip_proxy_require = SIP_PROXY_REQUIRE_INIT; |
1571 | * |
1572 | * @endcode |
1573 | * @HI |
1574 | * |
1575 | */ |
1576 | #define SIP_PROXY_REQUIRE_INIT(){{{ 0, 0, sip_proxy_require_class }}} SIP_HDR_INIT(proxy_require){{{ 0, 0, sip_proxy_require_class }}} |
1577 | |
1578 | /**Initialize a structure #sip_proxy_require_t. |
1579 | * |
1580 | * An #sip_proxy_require_t structure for |
1581 | * @ref sip_proxy_require "Proxy-Require header" can be initialized with the |
1582 | * sip_proxy_require_init() function/macro. For instance, |
1583 | * @code |
1584 | * |
1585 | * sip_proxy_require_t sip_proxy_require; |
1586 | * |
1587 | * sip_proxy_require_init(&sip_proxy_require); |
1588 | * |
1589 | * @endcode |
1590 | * @HI |
1591 | * |
1592 | */ |
1593 | #if SU_HAVE_INLINE1 |
1594 | su_inlinestatic inline sip_proxy_require_t *sip_proxy_require_init(sip_proxy_require_t x[1]) |
1595 | { |
1596 | return SIP_HEADER_INIT(x, sip_proxy_require_class, sizeof(sip_proxy_require_t))((void)memset((x), 0, (sizeof(sip_proxy_require_t))), (void)( ((sip_common_t *)(x))->h_class = (sip_proxy_require_class) ), (x)); |
1597 | } |
1598 | #else |
1599 | #define sip_proxy_require_init(x) \ |
1600 | SIP_HEADER_INIT(x, sip_proxy_require_class, sizeof(sip_proxy_require_t))((void)memset((x), 0, (sizeof(sip_proxy_require_t))), (void)( ((sip_common_t *)(x))->h_class = (sip_proxy_require_class) ), (x)) |
1601 | #endif |
1602 | |
1603 | /**Test if header object is instance of #sip_proxy_require_t. |
1604 | * |
1605 | * Check if the header class is an instance of |
1606 | * @ref sip_proxy_require "Proxy-Require header" object and return true (nonzero), |
1607 | * otherwise return false (zero). |
1608 | * |
1609 | * @param header pointer to the header structure to be tested |
1610 | * |
1611 | * @retval 1 (true) if the @a header is an instance of header proxy_require |
1612 | * @retval 0 (false) otherwise |
1613 | * |
1614 | */ |
1615 | #if SU_HAVE_INLINE1 |
1616 | su_inlinestatic inline int sip_is_proxy_require(sip_header_t const *header) |
1617 | { |
1618 | return header && header->sh_classsh_common->h_class->hc_hash == sip_proxy_require_hash; |
1619 | } |
1620 | #else |
1621 | int sip_is_proxy_require(sip_header_t const *header); |
1622 | #endif |
1623 | |
1624 | #define sip_proxy_require_p(h)sip_is_proxy_require((h)) sip_is_proxy_require((h)) |
1625 | |
1626 | |
1627 | /**Duplicate a list of @ref sip_proxy_require "Proxy-Require header" header structures #sip_proxy_require_t. |
1628 | * |
1629 | * Duplicate a header |
1630 | * structure @a hdr. If the header structure @a hdr |
1631 | * contains a reference (@c hdr->x_next) to a list of |
1632 | * headers, all the headers in the list are duplicated, too. |
1633 | * |
1634 | * @param home memory home used to allocate new structure |
1635 | * @param hdr header structure to be duplicated |
1636 | * |
1637 | * When duplicating, all parameter lists and non-constant |
1638 | * strings attached to the header are copied, too. The |
1639 | * function uses given memory @a home to allocate all the |
1640 | * memory areas used to copy the header. |
1641 | * |
1642 | * @par Example |
1643 | * @code |
1644 | * |
1645 | * proxy_require = sip_proxy_require_dup(home, sip->sip_proxy_require); |
1646 | * |
1647 | * @endcode |
1648 | * |
1649 | * @return |
1650 | * A pointer to the |
1651 | * newly duplicated #sip_proxy_require_t header structure, or NULL |
1652 | * upon an error. |
1653 | * |
1654 | */ |
1655 | #if SU_HAVE_INLINE1 |
1656 | su_inlinestatic inline |
1657 | #endif |
1658 | sip_proxy_require_t *sip_proxy_require_dup(su_home_t *home, sip_proxy_require_t const *hdr) |
1659 | __attribute__((__malloc__)); |
1660 | |
1661 | #if SU_HAVE_INLINE1 |
1662 | su_inlinestatic inline |
1663 | sip_proxy_require_t *sip_proxy_require_dup(su_home_t *home, sip_proxy_require_t const *hdr) |
1664 | { |
1665 | return (sip_proxy_require_t *) |
1666 | msg_header_dup_as(home, sip_proxy_require_class, (msg_header_t const *)hdr); |
1667 | } |
1668 | #endif |
1669 | |
1670 | /**Copy a list of @ref sip_proxy_require "Proxy-Require header" header structures #sip_proxy_require_t. |
1671 | * |
1672 | * The function sip_proxy_require_copy() copies a header structure @a |
1673 | * hdr. If the header structure @a hdr contains a reference (@c |
1674 | * hdr->h_next) to a list of headers, all the headers in that |
1675 | * list are copied, too. The function uses given memory @a home |
1676 | * to allocate all the memory areas used to copy the list of header |
1677 | * structure @a hdr. |
1678 | * |
1679 | * @param home memory home used to allocate new structure |
1680 | * @param hdr pointer to the header structure to be copied |
1681 | * |
1682 | * When copying, only the header structure and parameter lists attached to |
1683 | * it are duplicated. The new header structure retains all the references to |
1684 | * the strings within the old @a hdr header, including the encoding of the |
1685 | * old header, if present. |
1686 | * |
1687 | * @par Example |
1688 | * @code |
1689 | * |
1690 | * proxy_require = sip_proxy_require_copy(home, sip->sip_proxy_require); |
1691 | * |
1692 | * @endcode |
1693 | * |
1694 | * @return |
1695 | * A pointer to newly copied header structure, or NULL upon an error. |
1696 | * |
1697 | */ |
1698 | #if SU_HAVE_INLINE1 |
1699 | su_inlinestatic inline |
1700 | #endif |
1701 | sip_proxy_require_t *sip_proxy_require_copy(su_home_t *home, sip_proxy_require_t const *hdr) |
1702 | __attribute__((__malloc__)); |
1703 | |
1704 | #if SU_HAVE_INLINE1 |
1705 | su_inlinestatic inline |
1706 | sip_proxy_require_t *sip_proxy_require_copy(su_home_t *home, sip_proxy_require_t const *hdr) |
1707 | { |
1708 | return (sip_proxy_require_t *) |
1709 | msg_header_copy_as(home, sip_proxy_require_class, (msg_header_t const *)hdr); |
1710 | } |
1711 | #endif |
1712 | |
1713 | /**Make a @ref sip_proxy_require "Proxy-Require header" structure #sip_proxy_require_t. |
1714 | * |
1715 | * The function sip_proxy_require_make() makes a new |
1716 | * #sip_proxy_require_t header structure. It allocates a new |
1717 | * header structure, and decodes the string @a s as the |
1718 | * value of the structure. |
1719 | * |
1720 | * @param home memory home used to allocate new header structure. |
1721 | * @param s string to be decoded as value of the new header structure |
1722 | * |
1723 | * @return |
1724 | * A pointer to newly maked #sip_proxy_require_t header structure, or NULL upon an |
1725 | * error. |
1726 | * |
1727 | */ |
1728 | #if SU_HAVE_INLINE1 |
1729 | su_inlinestatic inline |
1730 | #endif |
1731 | sip_proxy_require_t *sip_proxy_require_make(su_home_t *home, char const *s) |
1732 | __attribute__((__malloc__)); |
1733 | |
1734 | #if SU_HAVE_INLINE1 |
1735 | su_inlinestatic inline sip_proxy_require_t *sip_proxy_require_make(su_home_t *home, char const *s) |
1736 | { |
1737 | return (sip_proxy_require_t *)sip_header_make(home, sip_proxy_require_class, s)((sip_header_t *)msg_header_make((home), (sip_proxy_require_class ), (s))); |
1738 | } |
1739 | #endif |
1740 | |
1741 | /**Make a @ref sip_proxy_require "Proxy-Require header" from formatting result. |
1742 | * |
1743 | * Make a new #sip_proxy_require_t object using formatting result as its value. |
1744 | * The function first prints the arguments according to the format @a fmt |
1745 | * specified. Then it allocates a new header structure, and parses the |
1746 | * formatting result to the structure #sip_proxy_require_t. |
1747 | * |
1748 | * @param home memory home used to allocate new header structure. |
1749 | * @param fmt string used as a printf()-style format |
1750 | * @param ... argument list for format |
1751 | * |
1752 | * @return |
1753 | * A pointer to newly |
1754 | * makes header structure, or NULL upon an error. |
1755 | * |
1756 | * @HIDE |
1757 | * |
1758 | */ |
1759 | #if SU_HAVE_INLINE1 |
1760 | su_inlinestatic inline |
1761 | #endif |
1762 | sip_proxy_require_t *sip_proxy_require_format(su_home_t *home, char const *fmt, ...) |
1763 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
1764 | |
1765 | #if SU_HAVE_INLINE1 |
1766 | su_inlinestatic inline sip_proxy_require_t *sip_proxy_require_format(su_home_t *home, char const *fmt, ...) |
1767 | { |
1768 | sip_header_t *h; |
1769 | va_list ap; |
1770 | |
1771 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
1772 | h = sip_header_vformat(home, sip_proxy_require_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_proxy_require_class ), (fmt), (ap))); |
1773 | va_end(ap)__builtin_va_end(ap); |
1774 | |
1775 | return (sip_proxy_require_t *)h; |
1776 | } |
1777 | #endif |
1778 | |
1779 | /** @} */ |
1780 | |
1781 | /**@addtogroup sip_from |
1782 | * @{ |
1783 | */ |
1784 | |
1785 | /** Parse a SIP @ref sip_from "From header". @internal */ |
1786 | SOFIAPUBFUN issize_t sip_from_d(su_home_t *, msg_header_t *, |
1787 | char *s, isize_t slen); |
1788 | |
1789 | /** Print a SIP @ref sip_from "From header". @internal */ |
1790 | SOFIAPUBFUN issize_t sip_from_e(char b[], isize_t bsiz, |
1791 | msg_header_t const *h, int flags); |
1792 | |
1793 | /**Access a SIP @ref sip_from "From header" |
1794 | * structure #sip_from_t from #sip_t. |
1795 | * |
1796 | */ |
1797 | #define sip_from(sip)((sip_from_t *)msg_header_access((msg_pub_t*)(sip), sip_from_class )) \ |
1798 | ((sip_from_t *)msg_header_access((msg_pub_t*)(sip), sip_from_class)) |
1799 | |
1800 | /**Initializer for structure #sip_from_t. |
1801 | * |
1802 | * A static #sip_from_t structure for |
1803 | * @ref sip_from "From header" must be initialized with |
1804 | * the SIP_FROM_INIT() macro. |
1805 | * For instance, |
1806 | * @code |
1807 | * |
1808 | * sip_from_t sip_from = SIP_FROM_INIT; |
1809 | * |
1810 | * @endcode |
1811 | * @HI |
1812 | * |
1813 | */ |
1814 | #define SIP_FROM_INIT(){{{ 0, 0, sip_from_class }}} SIP_HDR_INIT(from){{{ 0, 0, sip_from_class }}} |
1815 | |
1816 | /**Initialize a structure #sip_from_t. |
1817 | * |
1818 | * An #sip_from_t structure for |
1819 | * @ref sip_from "From header" can be initialized with the |
1820 | * sip_from_init() function/macro. For instance, |
1821 | * @code |
1822 | * |
1823 | * sip_from_t sip_from; |
1824 | * |
1825 | * sip_from_init(&sip_from); |
1826 | * |
1827 | * @endcode |
1828 | * @HI |
1829 | * |
1830 | */ |
1831 | #if SU_HAVE_INLINE1 |
1832 | su_inlinestatic inline sip_from_t *sip_from_init(sip_from_t x[1]) |
1833 | { |
1834 | return SIP_HEADER_INIT(x, sip_from_class, sizeof(sip_from_t))((void)memset((x), 0, (sizeof(sip_from_t))), (void)(((sip_common_t *)(x))->h_class = (sip_from_class)), (x)); |
1835 | } |
1836 | #else |
1837 | #define sip_from_init(x) \ |
1838 | SIP_HEADER_INIT(x, sip_from_class, sizeof(sip_from_t))((void)memset((x), 0, (sizeof(sip_from_t))), (void)(((sip_common_t *)(x))->h_class = (sip_from_class)), (x)) |
1839 | #endif |
1840 | |
1841 | /**Test if header object is instance of #sip_from_t. |
1842 | * |
1843 | * Check if the header class is an instance of |
1844 | * @ref sip_from "From header" object and return true (nonzero), |
1845 | * otherwise return false (zero). |
1846 | * |
1847 | * @param header pointer to the header structure to be tested |
1848 | * |
1849 | * @retval 1 (true) if the @a header is an instance of header from |
1850 | * @retval 0 (false) otherwise |
1851 | * |
1852 | */ |
1853 | #if SU_HAVE_INLINE1 |
1854 | su_inlinestatic inline int sip_is_from(sip_header_t const *header) |
1855 | { |
1856 | return header && header->sh_classsh_common->h_class->hc_hash == sip_from_hash; |
1857 | } |
1858 | #else |
1859 | int sip_is_from(sip_header_t const *header); |
1860 | #endif |
1861 | |
1862 | #define sip_from_p(h)sip_is_from((h)) sip_is_from((h)) |
1863 | |
1864 | |
1865 | /**Duplicate a list of @ref sip_from "From header" header structures #sip_from_t. |
1866 | * |
1867 | * Duplicate a header |
1868 | * structure @a hdr. If the header structure @a hdr |
1869 | * contains a reference (@c hdr->x_next) to a list of |
1870 | * headers, all the headers in the list are duplicated, too. |
1871 | * |
1872 | * @param home memory home used to allocate new structure |
1873 | * @param hdr header structure to be duplicated |
1874 | * |
1875 | * When duplicating, all parameter lists and non-constant |
1876 | * strings attached to the header are copied, too. The |
1877 | * function uses given memory @a home to allocate all the |
1878 | * memory areas used to copy the header. |
1879 | * |
1880 | * @par Example |
1881 | * @code |
1882 | * |
1883 | * from = sip_from_dup(home, sip->sip_from); |
1884 | * |
1885 | * @endcode |
1886 | * |
1887 | * @return |
1888 | * A pointer to the |
1889 | * newly duplicated #sip_from_t header structure, or NULL |
1890 | * upon an error. |
1891 | * |
1892 | */ |
1893 | #if SU_HAVE_INLINE1 |
1894 | su_inlinestatic inline |
1895 | #endif |
1896 | sip_from_t *sip_from_dup(su_home_t *home, sip_from_t const *hdr) |
1897 | __attribute__((__malloc__)); |
1898 | |
1899 | #if SU_HAVE_INLINE1 |
1900 | su_inlinestatic inline |
1901 | sip_from_t *sip_from_dup(su_home_t *home, sip_from_t const *hdr) |
1902 | { |
1903 | return (sip_from_t *) |
1904 | msg_header_dup_as(home, sip_from_class, (msg_header_t const *)hdr); |
1905 | } |
1906 | #endif |
1907 | |
1908 | /**Copy a list of @ref sip_from "From header" header structures #sip_from_t. |
1909 | * |
1910 | * The function sip_from_copy() copies a header structure @a |
1911 | * hdr. If the header structure @a hdr contains a reference (@c |
1912 | * hdr->h_next) to a list of headers, all the headers in that |
1913 | * list are copied, too. The function uses given memory @a home |
1914 | * to allocate all the memory areas used to copy the list of header |
1915 | * structure @a hdr. |
1916 | * |
1917 | * @param home memory home used to allocate new structure |
1918 | * @param hdr pointer to the header structure to be copied |
1919 | * |
1920 | * When copying, only the header structure and parameter lists attached to |
1921 | * it are duplicated. The new header structure retains all the references to |
1922 | * the strings within the old @a hdr header, including the encoding of the |
1923 | * old header, if present. |
1924 | * |
1925 | * @par Example |
1926 | * @code |
1927 | * |
1928 | * from = sip_from_copy(home, sip->sip_from); |
1929 | * |
1930 | * @endcode |
1931 | * |
1932 | * @return |
1933 | * A pointer to newly copied header structure, or NULL upon an error. |
1934 | * |
1935 | */ |
1936 | #if SU_HAVE_INLINE1 |
1937 | su_inlinestatic inline |
1938 | #endif |
1939 | sip_from_t *sip_from_copy(su_home_t *home, sip_from_t const *hdr) |
1940 | __attribute__((__malloc__)); |
1941 | |
1942 | #if SU_HAVE_INLINE1 |
1943 | su_inlinestatic inline |
1944 | sip_from_t *sip_from_copy(su_home_t *home, sip_from_t const *hdr) |
1945 | { |
1946 | return (sip_from_t *) |
1947 | msg_header_copy_as(home, sip_from_class, (msg_header_t const *)hdr); |
1948 | } |
1949 | #endif |
1950 | |
1951 | /**Make a @ref sip_from "From header" structure #sip_from_t. |
1952 | * |
1953 | * The function sip_from_make() makes a new |
1954 | * #sip_from_t header structure. It allocates a new |
1955 | * header structure, and decodes the string @a s as the |
1956 | * value of the structure. |
1957 | * |
1958 | * @param home memory home used to allocate new header structure. |
1959 | * @param s string to be decoded as value of the new header structure |
1960 | * |
1961 | * @return |
1962 | * A pointer to newly maked #sip_from_t header structure, or NULL upon an |
1963 | * error. |
1964 | * |
1965 | */ |
1966 | #if SU_HAVE_INLINE1 |
1967 | su_inlinestatic inline |
1968 | #endif |
1969 | sip_from_t *sip_from_make(su_home_t *home, char const *s) |
1970 | __attribute__((__malloc__)); |
1971 | |
1972 | #if SU_HAVE_INLINE1 |
1973 | su_inlinestatic inline sip_from_t *sip_from_make(su_home_t *home, char const *s) |
1974 | { |
1975 | return (sip_from_t *)sip_header_make(home, sip_from_class, s)((sip_header_t *)msg_header_make((home), (sip_from_class), (s ))); |
1976 | } |
1977 | #endif |
1978 | |
1979 | /**Make a @ref sip_from "From header" from formatting result. |
1980 | * |
1981 | * Make a new #sip_from_t object using formatting result as its value. |
1982 | * The function first prints the arguments according to the format @a fmt |
1983 | * specified. Then it allocates a new header structure, and parses the |
1984 | * formatting result to the structure #sip_from_t. |
1985 | * |
1986 | * @param home memory home used to allocate new header structure. |
1987 | * @param fmt string used as a printf()-style format |
1988 | * @param ... argument list for format |
1989 | * |
1990 | * @return |
1991 | * A pointer to newly |
1992 | * makes header structure, or NULL upon an error. |
1993 | * |
1994 | * @HIDE |
1995 | * |
1996 | */ |
1997 | #if SU_HAVE_INLINE1 |
1998 | su_inlinestatic inline |
1999 | #endif |
2000 | sip_from_t *sip_from_format(su_home_t *home, char const *fmt, ...) |
2001 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
2002 | |
2003 | #if SU_HAVE_INLINE1 |
2004 | su_inlinestatic inline sip_from_t *sip_from_format(su_home_t *home, char const *fmt, ...) |
2005 | { |
2006 | sip_header_t *h; |
2007 | va_list ap; |
2008 | |
2009 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
2010 | h = sip_header_vformat(home, sip_from_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_from_class), (fmt), (ap))); |
2011 | va_end(ap)__builtin_va_end(ap); |
2012 | |
2013 | return (sip_from_t *)h; |
2014 | } |
2015 | #endif |
2016 | |
2017 | /** @} */ |
2018 | |
2019 | /**@addtogroup sip_to |
2020 | * @{ |
2021 | */ |
2022 | |
2023 | /** Parse a SIP @ref sip_to "To header". @internal */ |
2024 | SOFIAPUBFUN issize_t sip_to_d(su_home_t *, msg_header_t *, |
2025 | char *s, isize_t slen); |
2026 | |
2027 | /** Print a SIP @ref sip_to "To header". @internal */ |
2028 | SOFIAPUBFUN issize_t sip_to_e(char b[], isize_t bsiz, |
2029 | msg_header_t const *h, int flags); |
2030 | |
2031 | /**Access a SIP @ref sip_to "To header" |
2032 | * structure #sip_to_t from #sip_t. |
2033 | * |
2034 | */ |
2035 | #define sip_to(sip)((sip_to_t *)msg_header_access((msg_pub_t*)(sip), sip_to_class )) \ |
2036 | ((sip_to_t *)msg_header_access((msg_pub_t*)(sip), sip_to_class)) |
2037 | |
2038 | /**Initializer for structure #sip_to_t. |
2039 | * |
2040 | * A static #sip_to_t structure for |
2041 | * @ref sip_to "To header" must be initialized with |
2042 | * the SIP_TO_INIT() macro. |
2043 | * For instance, |
2044 | * @code |
2045 | * |
2046 | * sip_to_t sip_to = SIP_TO_INIT; |
2047 | * |
2048 | * @endcode |
2049 | * @HI |
2050 | * |
2051 | */ |
2052 | #define SIP_TO_INIT(){{{ 0, 0, sip_to_class }}} SIP_HDR_INIT(to){{{ 0, 0, sip_to_class }}} |
2053 | |
2054 | /**Initialize a structure #sip_to_t. |
2055 | * |
2056 | * An #sip_to_t structure for |
2057 | * @ref sip_to "To header" can be initialized with the |
2058 | * sip_to_init() function/macro. For instance, |
2059 | * @code |
2060 | * |
2061 | * sip_to_t sip_to; |
2062 | * |
2063 | * sip_to_init(&sip_to); |
2064 | * |
2065 | * @endcode |
2066 | * @HI |
2067 | * |
2068 | */ |
2069 | #if SU_HAVE_INLINE1 |
2070 | su_inlinestatic inline sip_to_t *sip_to_init(sip_to_t x[1]) |
2071 | { |
2072 | return SIP_HEADER_INIT(x, sip_to_class, sizeof(sip_to_t))((void)memset((x), 0, (sizeof(sip_to_t))), (void)(((sip_common_t *)(x))->h_class = (sip_to_class)), (x)); |
2073 | } |
2074 | #else |
2075 | #define sip_to_init(x) \ |
2076 | SIP_HEADER_INIT(x, sip_to_class, sizeof(sip_to_t))((void)memset((x), 0, (sizeof(sip_to_t))), (void)(((sip_common_t *)(x))->h_class = (sip_to_class)), (x)) |
2077 | #endif |
2078 | |
2079 | /**Test if header object is instance of #sip_to_t. |
2080 | * |
2081 | * Check if the header class is an instance of |
2082 | * @ref sip_to "To header" object and return true (nonzero), |
2083 | * otherwise return false (zero). |
2084 | * |
2085 | * @param header pointer to the header structure to be tested |
2086 | * |
2087 | * @retval 1 (true) if the @a header is an instance of header to |
2088 | * @retval 0 (false) otherwise |
2089 | * |
2090 | */ |
2091 | #if SU_HAVE_INLINE1 |
2092 | su_inlinestatic inline int sip_is_to(sip_header_t const *header) |
2093 | { |
2094 | return header && header->sh_classsh_common->h_class->hc_hash == sip_to_hash; |
2095 | } |
2096 | #else |
2097 | int sip_is_to(sip_header_t const *header); |
2098 | #endif |
2099 | |
2100 | #define sip_to_p(h)sip_is_to((h)) sip_is_to((h)) |
2101 | |
2102 | |
2103 | /**Duplicate a list of @ref sip_to "To header" header structures #sip_to_t. |
2104 | * |
2105 | * Duplicate a header |
2106 | * structure @a hdr. If the header structure @a hdr |
2107 | * contains a reference (@c hdr->x_next) to a list of |
2108 | * headers, all the headers in the list are duplicated, too. |
2109 | * |
2110 | * @param home memory home used to allocate new structure |
2111 | * @param hdr header structure to be duplicated |
2112 | * |
2113 | * When duplicating, all parameter lists and non-constant |
2114 | * strings attached to the header are copied, too. The |
2115 | * function uses given memory @a home to allocate all the |
2116 | * memory areas used to copy the header. |
2117 | * |
2118 | * @par Example |
2119 | * @code |
2120 | * |
2121 | * to = sip_to_dup(home, sip->sip_to); |
2122 | * |
2123 | * @endcode |
2124 | * |
2125 | * @return |
2126 | * A pointer to the |
2127 | * newly duplicated #sip_to_t header structure, or NULL |
2128 | * upon an error. |
2129 | * |
2130 | */ |
2131 | #if SU_HAVE_INLINE1 |
2132 | su_inlinestatic inline |
2133 | #endif |
2134 | sip_to_t *sip_to_dup(su_home_t *home, sip_to_t const *hdr) |
2135 | __attribute__((__malloc__)); |
2136 | |
2137 | #if SU_HAVE_INLINE1 |
2138 | su_inlinestatic inline |
2139 | sip_to_t *sip_to_dup(su_home_t *home, sip_to_t const *hdr) |
2140 | { |
2141 | return (sip_to_t *) |
2142 | msg_header_dup_as(home, sip_to_class, (msg_header_t const *)hdr); |
2143 | } |
2144 | #endif |
2145 | |
2146 | /**Copy a list of @ref sip_to "To header" header structures #sip_to_t. |
2147 | * |
2148 | * The function sip_to_copy() copies a header structure @a |
2149 | * hdr. If the header structure @a hdr contains a reference (@c |
2150 | * hdr->h_next) to a list of headers, all the headers in that |
2151 | * list are copied, too. The function uses given memory @a home |
2152 | * to allocate all the memory areas used to copy the list of header |
2153 | * structure @a hdr. |
2154 | * |
2155 | * @param home memory home used to allocate new structure |
2156 | * @param hdr pointer to the header structure to be copied |
2157 | * |
2158 | * When copying, only the header structure and parameter lists attached to |
2159 | * it are duplicated. The new header structure retains all the references to |
2160 | * the strings within the old @a hdr header, including the encoding of the |
2161 | * old header, if present. |
2162 | * |
2163 | * @par Example |
2164 | * @code |
2165 | * |
2166 | * to = sip_to_copy(home, sip->sip_to); |
2167 | * |
2168 | * @endcode |
2169 | * |
2170 | * @return |
2171 | * A pointer to newly copied header structure, or NULL upon an error. |
2172 | * |
2173 | */ |
2174 | #if SU_HAVE_INLINE1 |
2175 | su_inlinestatic inline |
2176 | #endif |
2177 | sip_to_t *sip_to_copy(su_home_t *home, sip_to_t const *hdr) |
2178 | __attribute__((__malloc__)); |
2179 | |
2180 | #if SU_HAVE_INLINE1 |
2181 | su_inlinestatic inline |
2182 | sip_to_t *sip_to_copy(su_home_t *home, sip_to_t const *hdr) |
2183 | { |
2184 | return (sip_to_t *) |
2185 | msg_header_copy_as(home, sip_to_class, (msg_header_t const *)hdr); |
2186 | } |
2187 | #endif |
2188 | |
2189 | /**Make a @ref sip_to "To header" structure #sip_to_t. |
2190 | * |
2191 | * The function sip_to_make() makes a new |
2192 | * #sip_to_t header structure. It allocates a new |
2193 | * header structure, and decodes the string @a s as the |
2194 | * value of the structure. |
2195 | * |
2196 | * @param home memory home used to allocate new header structure. |
2197 | * @param s string to be decoded as value of the new header structure |
2198 | * |
2199 | * @return |
2200 | * A pointer to newly maked #sip_to_t header structure, or NULL upon an |
2201 | * error. |
2202 | * |
2203 | */ |
2204 | #if SU_HAVE_INLINE1 |
2205 | su_inlinestatic inline |
2206 | #endif |
2207 | sip_to_t *sip_to_make(su_home_t *home, char const *s) |
2208 | __attribute__((__malloc__)); |
2209 | |
2210 | #if SU_HAVE_INLINE1 |
2211 | su_inlinestatic inline sip_to_t *sip_to_make(su_home_t *home, char const *s) |
2212 | { |
2213 | return (sip_to_t *)sip_header_make(home, sip_to_class, s)((sip_header_t *)msg_header_make((home), (sip_to_class), (s)) ); |
2214 | } |
2215 | #endif |
2216 | |
2217 | /**Make a @ref sip_to "To header" from formatting result. |
2218 | * |
2219 | * Make a new #sip_to_t object using formatting result as its value. |
2220 | * The function first prints the arguments according to the format @a fmt |
2221 | * specified. Then it allocates a new header structure, and parses the |
2222 | * formatting result to the structure #sip_to_t. |
2223 | * |
2224 | * @param home memory home used to allocate new header structure. |
2225 | * @param fmt string used as a printf()-style format |
2226 | * @param ... argument list for format |
2227 | * |
2228 | * @return |
2229 | * A pointer to newly |
2230 | * makes header structure, or NULL upon an error. |
2231 | * |
2232 | * @HIDE |
2233 | * |
2234 | */ |
2235 | #if SU_HAVE_INLINE1 |
2236 | su_inlinestatic inline |
2237 | #endif |
2238 | sip_to_t *sip_to_format(su_home_t *home, char const *fmt, ...) |
2239 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
2240 | |
2241 | #if SU_HAVE_INLINE1 |
2242 | su_inlinestatic inline sip_to_t *sip_to_format(su_home_t *home, char const *fmt, ...) |
2243 | { |
2244 | sip_header_t *h; |
2245 | va_list ap; |
2246 | |
2247 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
2248 | h = sip_header_vformat(home, sip_to_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_to_class), ( fmt), (ap))); |
2249 | va_end(ap)__builtin_va_end(ap); |
2250 | |
2251 | return (sip_to_t *)h; |
2252 | } |
2253 | #endif |
2254 | |
2255 | /** @} */ |
2256 | |
2257 | /**@addtogroup sip_call_id |
2258 | * @{ |
2259 | */ |
2260 | |
2261 | /** Parse a SIP @ref sip_call_id "Call-ID header". @internal */ |
2262 | SOFIAPUBFUN issize_t sip_call_id_d(su_home_t *, msg_header_t *, |
2263 | char *s, isize_t slen); |
2264 | |
2265 | /** Print a SIP @ref sip_call_id "Call-ID header". @internal */ |
2266 | SOFIAPUBFUN issize_t sip_call_id_e(char b[], isize_t bsiz, |
2267 | msg_header_t const *h, int flags); |
2268 | |
2269 | /**Access a SIP @ref sip_call_id "Call-ID header" |
2270 | * structure #sip_call_id_t from #sip_t. |
2271 | * |
2272 | */ |
2273 | #define sip_call_id(sip)((sip_call_id_t *)msg_header_access((msg_pub_t*)(sip), sip_call_id_class )) \ |
2274 | ((sip_call_id_t *)msg_header_access((msg_pub_t*)(sip), sip_call_id_class)) |
2275 | |
2276 | /**Initializer for structure #sip_call_id_t. |
2277 | * |
2278 | * A static #sip_call_id_t structure for |
2279 | * @ref sip_call_id "Call-ID header" must be initialized with |
2280 | * the SIP_CALL_ID_INIT() macro. |
2281 | * For instance, |
2282 | * @code |
2283 | * |
2284 | * sip_call_id_t sip_call_id = SIP_CALL_ID_INIT; |
2285 | * |
2286 | * @endcode |
2287 | * @HI |
2288 | * |
2289 | */ |
2290 | #define SIP_CALL_ID_INIT(){{{ 0, 0, sip_call_id_class }}} SIP_HDR_INIT(call_id){{{ 0, 0, sip_call_id_class }}} |
2291 | |
2292 | /**Initialize a structure #sip_call_id_t. |
2293 | * |
2294 | * An #sip_call_id_t structure for |
2295 | * @ref sip_call_id "Call-ID header" can be initialized with the |
2296 | * sip_call_id_init() function/macro. For instance, |
2297 | * @code |
2298 | * |
2299 | * sip_call_id_t sip_call_id; |
2300 | * |
2301 | * sip_call_id_init(&sip_call_id); |
2302 | * |
2303 | * @endcode |
2304 | * @HI |
2305 | * |
2306 | */ |
2307 | #if SU_HAVE_INLINE1 |
2308 | su_inlinestatic inline sip_call_id_t *sip_call_id_init(sip_call_id_t x[1]) |
2309 | { |
2310 | return SIP_HEADER_INIT(x, sip_call_id_class, sizeof(sip_call_id_t))((void)memset((x), 0, (sizeof(sip_call_id_t))), (void)(((sip_common_t *)(x))->h_class = (sip_call_id_class)), (x)); |
2311 | } |
2312 | #else |
2313 | #define sip_call_id_init(x) \ |
2314 | SIP_HEADER_INIT(x, sip_call_id_class, sizeof(sip_call_id_t))((void)memset((x), 0, (sizeof(sip_call_id_t))), (void)(((sip_common_t *)(x))->h_class = (sip_call_id_class)), (x)) |
2315 | #endif |
2316 | |
2317 | /**Test if header object is instance of #sip_call_id_t. |
2318 | * |
2319 | * Check if the header class is an instance of |
2320 | * @ref sip_call_id "Call-ID header" object and return true (nonzero), |
2321 | * otherwise return false (zero). |
2322 | * |
2323 | * @param header pointer to the header structure to be tested |
2324 | * |
2325 | * @retval 1 (true) if the @a header is an instance of header call_id |
2326 | * @retval 0 (false) otherwise |
2327 | * |
2328 | */ |
2329 | #if SU_HAVE_INLINE1 |
2330 | su_inlinestatic inline int sip_is_call_id(sip_header_t const *header) |
2331 | { |
2332 | return header && header->sh_classsh_common->h_class->hc_hash == sip_call_id_hash; |
2333 | } |
2334 | #else |
2335 | int sip_is_call_id(sip_header_t const *header); |
2336 | #endif |
2337 | |
2338 | #define sip_call_id_p(h)sip_is_call_id((h)) sip_is_call_id((h)) |
2339 | |
2340 | |
2341 | /**Duplicate a list of @ref sip_call_id "Call-ID header" header structures #sip_call_id_t. |
2342 | * |
2343 | * Duplicate a header |
2344 | * structure @a hdr. If the header structure @a hdr |
2345 | * contains a reference (@c hdr->x_next) to a list of |
2346 | * headers, all the headers in the list are duplicated, too. |
2347 | * |
2348 | * @param home memory home used to allocate new structure |
2349 | * @param hdr header structure to be duplicated |
2350 | * |
2351 | * When duplicating, all parameter lists and non-constant |
2352 | * strings attached to the header are copied, too. The |
2353 | * function uses given memory @a home to allocate all the |
2354 | * memory areas used to copy the header. |
2355 | * |
2356 | * @par Example |
2357 | * @code |
2358 | * |
2359 | * call_id = sip_call_id_dup(home, sip->sip_call_id); |
2360 | * |
2361 | * @endcode |
2362 | * |
2363 | * @return |
2364 | * A pointer to the |
2365 | * newly duplicated #sip_call_id_t header structure, or NULL |
2366 | * upon an error. |
2367 | * |
2368 | */ |
2369 | #if SU_HAVE_INLINE1 |
2370 | su_inlinestatic inline |
2371 | #endif |
2372 | sip_call_id_t *sip_call_id_dup(su_home_t *home, sip_call_id_t const *hdr) |
2373 | __attribute__((__malloc__)); |
2374 | |
2375 | #if SU_HAVE_INLINE1 |
2376 | su_inlinestatic inline |
2377 | sip_call_id_t *sip_call_id_dup(su_home_t *home, sip_call_id_t const *hdr) |
2378 | { |
2379 | return (sip_call_id_t *) |
2380 | msg_header_dup_as(home, sip_call_id_class, (msg_header_t const *)hdr); |
2381 | } |
2382 | #endif |
2383 | |
2384 | /**Copy a list of @ref sip_call_id "Call-ID header" header structures #sip_call_id_t. |
2385 | * |
2386 | * The function sip_call_id_copy() copies a header structure @a |
2387 | * hdr. If the header structure @a hdr contains a reference (@c |
2388 | * hdr->h_next) to a list of headers, all the headers in that |
2389 | * list are copied, too. The function uses given memory @a home |
2390 | * to allocate all the memory areas used to copy the list of header |
2391 | * structure @a hdr. |
2392 | * |
2393 | * @param home memory home used to allocate new structure |
2394 | * @param hdr pointer to the header structure to be copied |
2395 | * |
2396 | * When copying, only the header structure and parameter lists attached to |
2397 | * it are duplicated. The new header structure retains all the references to |
2398 | * the strings within the old @a hdr header, including the encoding of the |
2399 | * old header, if present. |
2400 | * |
2401 | * @par Example |
2402 | * @code |
2403 | * |
2404 | * call_id = sip_call_id_copy(home, sip->sip_call_id); |
2405 | * |
2406 | * @endcode |
2407 | * |
2408 | * @return |
2409 | * A pointer to newly copied header structure, or NULL upon an error. |
2410 | * |
2411 | */ |
2412 | #if SU_HAVE_INLINE1 |
2413 | su_inlinestatic inline |
2414 | #endif |
2415 | sip_call_id_t *sip_call_id_copy(su_home_t *home, sip_call_id_t const *hdr) |
2416 | __attribute__((__malloc__)); |
2417 | |
2418 | #if SU_HAVE_INLINE1 |
2419 | su_inlinestatic inline |
2420 | sip_call_id_t *sip_call_id_copy(su_home_t *home, sip_call_id_t const *hdr) |
2421 | { |
2422 | return (sip_call_id_t *) |
2423 | msg_header_copy_as(home, sip_call_id_class, (msg_header_t const *)hdr); |
2424 | } |
2425 | #endif |
2426 | |
2427 | /**Make a @ref sip_call_id "Call-ID header" structure #sip_call_id_t. |
2428 | * |
2429 | * The function sip_call_id_make() makes a new |
2430 | * #sip_call_id_t header structure. It allocates a new |
2431 | * header structure, and decodes the string @a s as the |
2432 | * value of the structure. |
2433 | * |
2434 | * @param home memory home used to allocate new header structure. |
2435 | * @param s string to be decoded as value of the new header structure |
2436 | * |
2437 | * @return |
2438 | * A pointer to newly maked #sip_call_id_t header structure, or NULL upon an |
2439 | * error. |
2440 | * |
2441 | */ |
2442 | #if SU_HAVE_INLINE1 |
2443 | su_inlinestatic inline |
2444 | #endif |
2445 | sip_call_id_t *sip_call_id_make(su_home_t *home, char const *s) |
2446 | __attribute__((__malloc__)); |
2447 | |
2448 | #if SU_HAVE_INLINE1 |
2449 | su_inlinestatic inline sip_call_id_t *sip_call_id_make(su_home_t *home, char const *s) |
2450 | { |
2451 | return (sip_call_id_t *)sip_header_make(home, sip_call_id_class, s)((sip_header_t *)msg_header_make((home), (sip_call_id_class), (s))); |
2452 | } |
2453 | #endif |
2454 | |
2455 | /**Make a @ref sip_call_id "Call-ID header" from formatting result. |
2456 | * |
2457 | * Make a new #sip_call_id_t object using formatting result as its value. |
2458 | * The function first prints the arguments according to the format @a fmt |
2459 | * specified. Then it allocates a new header structure, and parses the |
2460 | * formatting result to the structure #sip_call_id_t. |
2461 | * |
2462 | * @param home memory home used to allocate new header structure. |
2463 | * @param fmt string used as a printf()-style format |
2464 | * @param ... argument list for format |
2465 | * |
2466 | * @return |
2467 | * A pointer to newly |
2468 | * makes header structure, or NULL upon an error. |
2469 | * |
2470 | * @HIDE |
2471 | * |
2472 | */ |
2473 | #if SU_HAVE_INLINE1 |
2474 | su_inlinestatic inline |
2475 | #endif |
2476 | sip_call_id_t *sip_call_id_format(su_home_t *home, char const *fmt, ...) |
2477 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
2478 | |
2479 | #if SU_HAVE_INLINE1 |
2480 | su_inlinestatic inline sip_call_id_t *sip_call_id_format(su_home_t *home, char const *fmt, ...) |
2481 | { |
2482 | sip_header_t *h; |
2483 | va_list ap; |
2484 | |
2485 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
2486 | h = sip_header_vformat(home, sip_call_id_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_call_id_class ), (fmt), (ap))); |
2487 | va_end(ap)__builtin_va_end(ap); |
2488 | |
2489 | return (sip_call_id_t *)h; |
2490 | } |
2491 | #endif |
2492 | |
2493 | /** @} */ |
2494 | |
2495 | /**@addtogroup sip_cseq |
2496 | * @{ |
2497 | */ |
2498 | |
2499 | /** Parse a SIP @ref sip_cseq "CSeq header". @internal */ |
2500 | SOFIAPUBFUN issize_t sip_cseq_d(su_home_t *, msg_header_t *, |
2501 | char *s, isize_t slen); |
2502 | |
2503 | /** Print a SIP @ref sip_cseq "CSeq header". @internal */ |
2504 | SOFIAPUBFUN issize_t sip_cseq_e(char b[], isize_t bsiz, |
2505 | msg_header_t const *h, int flags); |
2506 | |
2507 | /**Access a SIP @ref sip_cseq "CSeq header" |
2508 | * structure #sip_cseq_t from #sip_t. |
2509 | * |
2510 | */ |
2511 | #define sip_cseq(sip)((sip_cseq_t *)msg_header_access((msg_pub_t*)(sip), sip_cseq_class )) \ |
2512 | ((sip_cseq_t *)msg_header_access((msg_pub_t*)(sip), sip_cseq_class)) |
2513 | |
2514 | /**Initializer for structure #sip_cseq_t. |
2515 | * |
2516 | * A static #sip_cseq_t structure for |
2517 | * @ref sip_cseq "CSeq header" must be initialized with |
2518 | * the SIP_CSEQ_INIT() macro. |
2519 | * For instance, |
2520 | * @code |
2521 | * |
2522 | * sip_cseq_t sip_cseq = SIP_CSEQ_INIT; |
2523 | * |
2524 | * @endcode |
2525 | * @HI |
2526 | * |
2527 | */ |
2528 | #define SIP_CSEQ_INIT(){{{ 0, 0, sip_cseq_class }}} SIP_HDR_INIT(cseq){{{ 0, 0, sip_cseq_class }}} |
2529 | |
2530 | /**Initialize a structure #sip_cseq_t. |
2531 | * |
2532 | * An #sip_cseq_t structure for |
2533 | * @ref sip_cseq "CSeq header" can be initialized with the |
2534 | * sip_cseq_init() function/macro. For instance, |
2535 | * @code |
2536 | * |
2537 | * sip_cseq_t sip_cseq; |
2538 | * |
2539 | * sip_cseq_init(&sip_cseq); |
2540 | * |
2541 | * @endcode |
2542 | * @HI |
2543 | * |
2544 | */ |
2545 | #if SU_HAVE_INLINE1 |
2546 | su_inlinestatic inline sip_cseq_t *sip_cseq_init(sip_cseq_t x[1]) |
2547 | { |
2548 | return SIP_HEADER_INIT(x, sip_cseq_class, sizeof(sip_cseq_t))((void)memset((x), 0, (sizeof(sip_cseq_t))), (void)(((sip_common_t *)(x))->h_class = (sip_cseq_class)), (x)); |
2549 | } |
2550 | #else |
2551 | #define sip_cseq_init(x) \ |
2552 | SIP_HEADER_INIT(x, sip_cseq_class, sizeof(sip_cseq_t))((void)memset((x), 0, (sizeof(sip_cseq_t))), (void)(((sip_common_t *)(x))->h_class = (sip_cseq_class)), (x)) |
2553 | #endif |
2554 | |
2555 | /**Test if header object is instance of #sip_cseq_t. |
2556 | * |
2557 | * Check if the header class is an instance of |
2558 | * @ref sip_cseq "CSeq header" object and return true (nonzero), |
2559 | * otherwise return false (zero). |
2560 | * |
2561 | * @param header pointer to the header structure to be tested |
2562 | * |
2563 | * @retval 1 (true) if the @a header is an instance of header cseq |
2564 | * @retval 0 (false) otherwise |
2565 | * |
2566 | */ |
2567 | #if SU_HAVE_INLINE1 |
2568 | su_inlinestatic inline int sip_is_cseq(sip_header_t const *header) |
2569 | { |
2570 | return header && header->sh_classsh_common->h_class->hc_hash == sip_cseq_hash; |
2571 | } |
2572 | #else |
2573 | int sip_is_cseq(sip_header_t const *header); |
2574 | #endif |
2575 | |
2576 | #define sip_cseq_p(h)sip_is_cseq((h)) sip_is_cseq((h)) |
2577 | |
2578 | |
2579 | /**Duplicate a list of @ref sip_cseq "CSeq header" header structures #sip_cseq_t. |
2580 | * |
2581 | * Duplicate a header |
2582 | * structure @a hdr. If the header structure @a hdr |
2583 | * contains a reference (@c hdr->x_next) to a list of |
2584 | * headers, all the headers in the list are duplicated, too. |
2585 | * |
2586 | * @param home memory home used to allocate new structure |
2587 | * @param hdr header structure to be duplicated |
2588 | * |
2589 | * When duplicating, all parameter lists and non-constant |
2590 | * strings attached to the header are copied, too. The |
2591 | * function uses given memory @a home to allocate all the |
2592 | * memory areas used to copy the header. |
2593 | * |
2594 | * @par Example |
2595 | * @code |
2596 | * |
2597 | * cseq = sip_cseq_dup(home, sip->sip_cseq); |
2598 | * |
2599 | * @endcode |
2600 | * |
2601 | * @return |
2602 | * A pointer to the |
2603 | * newly duplicated #sip_cseq_t header structure, or NULL |
2604 | * upon an error. |
2605 | * |
2606 | */ |
2607 | #if SU_HAVE_INLINE1 |
2608 | su_inlinestatic inline |
2609 | #endif |
2610 | sip_cseq_t *sip_cseq_dup(su_home_t *home, sip_cseq_t const *hdr) |
2611 | __attribute__((__malloc__)); |
2612 | |
2613 | #if SU_HAVE_INLINE1 |
2614 | su_inlinestatic inline |
2615 | sip_cseq_t *sip_cseq_dup(su_home_t *home, sip_cseq_t const *hdr) |
2616 | { |
2617 | return (sip_cseq_t *) |
2618 | msg_header_dup_as(home, sip_cseq_class, (msg_header_t const *)hdr); |
2619 | } |
2620 | #endif |
2621 | |
2622 | /**Copy a list of @ref sip_cseq "CSeq header" header structures #sip_cseq_t. |
2623 | * |
2624 | * The function sip_cseq_copy() copies a header structure @a |
2625 | * hdr. If the header structure @a hdr contains a reference (@c |
2626 | * hdr->h_next) to a list of headers, all the headers in that |
2627 | * list are copied, too. The function uses given memory @a home |
2628 | * to allocate all the memory areas used to copy the list of header |
2629 | * structure @a hdr. |
2630 | * |
2631 | * @param home memory home used to allocate new structure |
2632 | * @param hdr pointer to the header structure to be copied |
2633 | * |
2634 | * When copying, only the header structure and parameter lists attached to |
2635 | * it are duplicated. The new header structure retains all the references to |
2636 | * the strings within the old @a hdr header, including the encoding of the |
2637 | * old header, if present. |
2638 | * |
2639 | * @par Example |
2640 | * @code |
2641 | * |
2642 | * cseq = sip_cseq_copy(home, sip->sip_cseq); |
2643 | * |
2644 | * @endcode |
2645 | * |
2646 | * @return |
2647 | * A pointer to newly copied header structure, or NULL upon an error. |
2648 | * |
2649 | */ |
2650 | #if SU_HAVE_INLINE1 |
2651 | su_inlinestatic inline |
2652 | #endif |
2653 | sip_cseq_t *sip_cseq_copy(su_home_t *home, sip_cseq_t const *hdr) |
2654 | __attribute__((__malloc__)); |
2655 | |
2656 | #if SU_HAVE_INLINE1 |
2657 | su_inlinestatic inline |
2658 | sip_cseq_t *sip_cseq_copy(su_home_t *home, sip_cseq_t const *hdr) |
2659 | { |
2660 | return (sip_cseq_t *) |
2661 | msg_header_copy_as(home, sip_cseq_class, (msg_header_t const *)hdr); |
2662 | } |
2663 | #endif |
2664 | |
2665 | /**Make a @ref sip_cseq "CSeq header" structure #sip_cseq_t. |
2666 | * |
2667 | * The function sip_cseq_make() makes a new |
2668 | * #sip_cseq_t header structure. It allocates a new |
2669 | * header structure, and decodes the string @a s as the |
2670 | * value of the structure. |
2671 | * |
2672 | * @param home memory home used to allocate new header structure. |
2673 | * @param s string to be decoded as value of the new header structure |
2674 | * |
2675 | * @return |
2676 | * A pointer to newly maked #sip_cseq_t header structure, or NULL upon an |
2677 | * error. |
2678 | * |
2679 | */ |
2680 | #if SU_HAVE_INLINE1 |
2681 | su_inlinestatic inline |
2682 | #endif |
2683 | sip_cseq_t *sip_cseq_make(su_home_t *home, char const *s) |
2684 | __attribute__((__malloc__)); |
2685 | |
2686 | #if SU_HAVE_INLINE1 |
2687 | su_inlinestatic inline sip_cseq_t *sip_cseq_make(su_home_t *home, char const *s) |
2688 | { |
2689 | return (sip_cseq_t *)sip_header_make(home, sip_cseq_class, s)((sip_header_t *)msg_header_make((home), (sip_cseq_class), (s ))); |
2690 | } |
2691 | #endif |
2692 | |
2693 | /**Make a @ref sip_cseq "CSeq header" from formatting result. |
2694 | * |
2695 | * Make a new #sip_cseq_t object using formatting result as its value. |
2696 | * The function first prints the arguments according to the format @a fmt |
2697 | * specified. Then it allocates a new header structure, and parses the |
2698 | * formatting result to the structure #sip_cseq_t. |
2699 | * |
2700 | * @param home memory home used to allocate new header structure. |
2701 | * @param fmt string used as a printf()-style format |
2702 | * @param ... argument list for format |
2703 | * |
2704 | * @return |
2705 | * A pointer to newly |
2706 | * makes header structure, or NULL upon an error. |
2707 | * |
2708 | * @HIDE |
2709 | * |
2710 | */ |
2711 | #if SU_HAVE_INLINE1 |
2712 | su_inlinestatic inline |
2713 | #endif |
2714 | sip_cseq_t *sip_cseq_format(su_home_t *home, char const *fmt, ...) |
2715 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
2716 | |
2717 | #if SU_HAVE_INLINE1 |
2718 | su_inlinestatic inline sip_cseq_t *sip_cseq_format(su_home_t *home, char const *fmt, ...) |
2719 | { |
2720 | sip_header_t *h; |
2721 | va_list ap; |
2722 | |
2723 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
2724 | h = sip_header_vformat(home, sip_cseq_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_cseq_class), (fmt), (ap))); |
2725 | va_end(ap)__builtin_va_end(ap); |
2726 | |
2727 | return (sip_cseq_t *)h; |
2728 | } |
2729 | #endif |
2730 | |
2731 | /** @} */ |
2732 | |
2733 | /**@addtogroup sip_identity |
2734 | * @{ |
2735 | */ |
2736 | |
2737 | /** Parse a SIP @ref sip_identity "Identity header". @internal */ |
2738 | SOFIAPUBFUN issize_t sip_identity_d(su_home_t *, msg_header_t *, |
2739 | char *s, isize_t slen); |
2740 | |
2741 | /** Print a SIP @ref sip_identity "Identity header". @internal */ |
2742 | SOFIAPUBFUN issize_t sip_identity_e(char b[], isize_t bsiz, |
2743 | msg_header_t const *h, int flags); |
2744 | |
2745 | /**Access a SIP @ref sip_identity "Identity header" |
2746 | * structure #sip_identity_t from #sip_t. |
2747 | * |
2748 | */ |
2749 | #define sip_identity(sip)((sip_identity_t *)msg_header_access((msg_pub_t*)(sip), sip_identity_class )) \ |
2750 | ((sip_identity_t *)msg_header_access((msg_pub_t*)(sip), sip_identity_class)) |
2751 | |
2752 | /**Initializer for structure #sip_identity_t. |
2753 | * |
2754 | * A static #sip_identity_t structure for |
2755 | * @ref sip_identity "Identity header" must be initialized with |
2756 | * the SIP_IDENTITY_INIT() macro. |
2757 | * For instance, |
2758 | * @code |
2759 | * |
2760 | * sip_identity_t sip_identity = SIP_IDENTITY_INIT; |
2761 | * |
2762 | * @endcode |
2763 | * @HI |
2764 | * |
2765 | */ |
2766 | #define SIP_IDENTITY_INIT(){{{ 0, 0, sip_identity_class }}} SIP_HDR_INIT(identity){{{ 0, 0, sip_identity_class }}} |
2767 | |
2768 | /**Initialize a structure #sip_identity_t. |
2769 | * |
2770 | * An #sip_identity_t structure for |
2771 | * @ref sip_identity "Identity header" can be initialized with the |
2772 | * sip_identity_init() function/macro. For instance, |
2773 | * @code |
2774 | * |
2775 | * sip_identity_t sip_identity; |
2776 | * |
2777 | * sip_identity_init(&sip_identity); |
2778 | * |
2779 | * @endcode |
2780 | * @HI |
2781 | * |
2782 | */ |
2783 | #if SU_HAVE_INLINE1 |
2784 | su_inlinestatic inline sip_identity_t *sip_identity_init(sip_identity_t x[1]) |
2785 | { |
2786 | return SIP_HEADER_INIT(x, sip_identity_class, sizeof(sip_identity_t))((void)memset((x), 0, (sizeof(sip_identity_t))), (void)(((sip_common_t *)(x))->h_class = (sip_identity_class)), (x)); |
2787 | } |
2788 | #else |
2789 | #define sip_identity_init(x) \ |
2790 | SIP_HEADER_INIT(x, sip_identity_class, sizeof(sip_identity_t))((void)memset((x), 0, (sizeof(sip_identity_t))), (void)(((sip_common_t *)(x))->h_class = (sip_identity_class)), (x)) |
2791 | #endif |
2792 | |
2793 | /**Test if header object is instance of #sip_identity_t. |
2794 | * |
2795 | * Check if the header class is an instance of |
2796 | * @ref sip_identity "Identity header" object and return true (nonzero), |
2797 | * otherwise return false (zero). |
2798 | * |
2799 | * @param header pointer to the header structure to be tested |
2800 | * |
2801 | * @retval 1 (true) if the @a header is an instance of header identity |
2802 | * @retval 0 (false) otherwise |
2803 | * |
2804 | */ |
2805 | #if SU_HAVE_INLINE1 |
2806 | su_inlinestatic inline int sip_is_identity(sip_header_t const *header) |
2807 | { |
2808 | return header && header->sh_classsh_common->h_class->hc_hash == sip_identity_hash; |
2809 | } |
2810 | #else |
2811 | int sip_is_identity(sip_header_t const *header); |
2812 | #endif |
2813 | |
2814 | #define sip_identity_p(h)sip_is_identity((h)) sip_is_identity((h)) |
2815 | |
2816 | |
2817 | /**Duplicate a list of @ref sip_identity "Identity header" header structures #sip_identity_t. |
2818 | * |
2819 | * Duplicate a header |
2820 | * structure @a hdr. If the header structure @a hdr |
2821 | * contains a reference (@c hdr->x_next) to a list of |
2822 | * headers, all the headers in the list are duplicated, too. |
2823 | * |
2824 | * @param home memory home used to allocate new structure |
2825 | * @param hdr header structure to be duplicated |
2826 | * |
2827 | * When duplicating, all parameter lists and non-constant |
2828 | * strings attached to the header are copied, too. The |
2829 | * function uses given memory @a home to allocate all the |
2830 | * memory areas used to copy the header. |
2831 | * |
2832 | * @par Example |
2833 | * @code |
2834 | * |
2835 | * identity = sip_identity_dup(home, sip->sip_identity); |
2836 | * |
2837 | * @endcode |
2838 | * |
2839 | * @return |
2840 | * A pointer to the |
2841 | * newly duplicated #sip_identity_t header structure, or NULL |
2842 | * upon an error. |
2843 | * |
2844 | */ |
2845 | #if SU_HAVE_INLINE1 |
2846 | su_inlinestatic inline |
2847 | #endif |
2848 | sip_identity_t *sip_identity_dup(su_home_t *home, sip_identity_t const *hdr) |
2849 | __attribute__((__malloc__)); |
2850 | |
2851 | #if SU_HAVE_INLINE1 |
2852 | su_inlinestatic inline |
2853 | sip_identity_t *sip_identity_dup(su_home_t *home, sip_identity_t const *hdr) |
2854 | { |
2855 | return (sip_identity_t *) |
2856 | msg_header_dup_as(home, sip_identity_class, (msg_header_t const *)hdr); |
2857 | } |
2858 | #endif |
2859 | |
2860 | /**Copy a list of @ref sip_identity "Identity header" header structures #sip_identity_t. |
2861 | * |
2862 | * The function sip_identity_copy() copies a header structure @a |
2863 | * hdr. If the header structure @a hdr contains a reference (@c |
2864 | * hdr->h_next) to a list of headers, all the headers in that |
2865 | * list are copied, too. The function uses given memory @a home |
2866 | * to allocate all the memory areas used to copy the list of header |
2867 | * structure @a hdr. |
2868 | * |
2869 | * @param home memory home used to allocate new structure |
2870 | * @param hdr pointer to the header structure to be copied |
2871 | * |
2872 | * When copying, only the header structure and parameter lists attached to |
2873 | * it are duplicated. The new header structure retains all the references to |
2874 | * the strings within the old @a hdr header, including the encoding of the |
2875 | * old header, if present. |
2876 | * |
2877 | * @par Example |
2878 | * @code |
2879 | * |
2880 | * identity = sip_identity_copy(home, sip->sip_identity); |
2881 | * |
2882 | * @endcode |
2883 | * |
2884 | * @return |
2885 | * A pointer to newly copied header structure, or NULL upon an error. |
2886 | * |
2887 | */ |
2888 | #if SU_HAVE_INLINE1 |
2889 | su_inlinestatic inline |
2890 | #endif |
2891 | sip_identity_t *sip_identity_copy(su_home_t *home, sip_identity_t const *hdr) |
2892 | __attribute__((__malloc__)); |
2893 | |
2894 | #if SU_HAVE_INLINE1 |
2895 | su_inlinestatic inline |
2896 | sip_identity_t *sip_identity_copy(su_home_t *home, sip_identity_t const *hdr) |
2897 | { |
2898 | return (sip_identity_t *) |
2899 | msg_header_copy_as(home, sip_identity_class, (msg_header_t const *)hdr); |
2900 | } |
2901 | #endif |
2902 | |
2903 | /**Make a @ref sip_identity "Identity header" structure #sip_identity_t. |
2904 | * |
2905 | * The function sip_identity_make() makes a new |
2906 | * #sip_identity_t header structure. It allocates a new |
2907 | * header structure, and decodes the string @a s as the |
2908 | * value of the structure. |
2909 | * |
2910 | * @param home memory home used to allocate new header structure. |
2911 | * @param s string to be decoded as value of the new header structure |
2912 | * |
2913 | * @return |
2914 | * A pointer to newly maked #sip_identity_t header structure, or NULL upon an |
2915 | * error. |
2916 | * |
2917 | */ |
2918 | #if SU_HAVE_INLINE1 |
2919 | su_inlinestatic inline |
2920 | #endif |
2921 | sip_identity_t *sip_identity_make(su_home_t *home, char const *s) |
2922 | __attribute__((__malloc__)); |
2923 | |
2924 | #if SU_HAVE_INLINE1 |
2925 | su_inlinestatic inline sip_identity_t *sip_identity_make(su_home_t *home, char const *s) |
2926 | { |
2927 | return (sip_identity_t *)sip_header_make(home, sip_identity_class, s)((sip_header_t *)msg_header_make((home), (sip_identity_class) , (s))); |
2928 | } |
2929 | #endif |
2930 | |
2931 | /**Make a @ref sip_identity "Identity header" from formatting result. |
2932 | * |
2933 | * Make a new #sip_identity_t object using formatting result as its value. |
2934 | * The function first prints the arguments according to the format @a fmt |
2935 | * specified. Then it allocates a new header structure, and parses the |
2936 | * formatting result to the structure #sip_identity_t. |
2937 | * |
2938 | * @param home memory home used to allocate new header structure. |
2939 | * @param fmt string used as a printf()-style format |
2940 | * @param ... argument list for format |
2941 | * |
2942 | * @return |
2943 | * A pointer to newly |
2944 | * makes header structure, or NULL upon an error. |
2945 | * |
2946 | * @HIDE |
2947 | * |
2948 | */ |
2949 | #if SU_HAVE_INLINE1 |
2950 | su_inlinestatic inline |
2951 | #endif |
2952 | sip_identity_t *sip_identity_format(su_home_t *home, char const *fmt, ...) |
2953 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
2954 | |
2955 | #if SU_HAVE_INLINE1 |
2956 | su_inlinestatic inline sip_identity_t *sip_identity_format(su_home_t *home, char const *fmt, ...) |
2957 | { |
2958 | sip_header_t *h; |
2959 | va_list ap; |
2960 | |
2961 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
2962 | h = sip_header_vformat(home, sip_identity_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_identity_class ), (fmt), (ap))); |
2963 | va_end(ap)__builtin_va_end(ap); |
2964 | |
2965 | return (sip_identity_t *)h; |
2966 | } |
2967 | #endif |
2968 | |
2969 | /** @} */ |
2970 | |
2971 | /**@addtogroup sip_contact |
2972 | * @{ |
2973 | */ |
2974 | |
2975 | /** Parse a SIP @ref sip_contact "Contact header". @internal */ |
2976 | SOFIAPUBFUN issize_t sip_contact_d(su_home_t *, msg_header_t *, |
2977 | char *s, isize_t slen); |
2978 | |
2979 | /** Print a SIP @ref sip_contact "Contact header". @internal */ |
2980 | SOFIAPUBFUN issize_t sip_contact_e(char b[], isize_t bsiz, |
2981 | msg_header_t const *h, int flags); |
2982 | |
2983 | /**Access a SIP @ref sip_contact "Contact header" |
2984 | * structure #sip_contact_t from #sip_t. |
2985 | * |
2986 | */ |
2987 | #define sip_contact(sip)((sip_contact_t *)msg_header_access((msg_pub_t*)(sip), sip_contact_class )) \ |
2988 | ((sip_contact_t *)msg_header_access((msg_pub_t*)(sip), sip_contact_class)) |
2989 | |
2990 | /**Initializer for structure #sip_contact_t. |
2991 | * |
2992 | * A static #sip_contact_t structure for |
2993 | * @ref sip_contact "Contact header" must be initialized with |
2994 | * the SIP_CONTACT_INIT() macro. |
2995 | * For instance, |
2996 | * @code |
2997 | * |
2998 | * sip_contact_t sip_contact = SIP_CONTACT_INIT; |
2999 | * |
3000 | * @endcode |
3001 | * @HI |
3002 | * |
3003 | */ |
3004 | #define SIP_CONTACT_INIT(){{{ 0, 0, sip_contact_class }}} SIP_HDR_INIT(contact){{{ 0, 0, sip_contact_class }}} |
3005 | |
3006 | /**Initialize a structure #sip_contact_t. |
3007 | * |
3008 | * An #sip_contact_t structure for |
3009 | * @ref sip_contact "Contact header" can be initialized with the |
3010 | * sip_contact_init() function/macro. For instance, |
3011 | * @code |
3012 | * |
3013 | * sip_contact_t sip_contact; |
3014 | * |
3015 | * sip_contact_init(&sip_contact); |
3016 | * |
3017 | * @endcode |
3018 | * @HI |
3019 | * |
3020 | */ |
3021 | #if SU_HAVE_INLINE1 |
3022 | su_inlinestatic inline sip_contact_t *sip_contact_init(sip_contact_t x[1]) |
3023 | { |
3024 | return SIP_HEADER_INIT(x, sip_contact_class, sizeof(sip_contact_t))((void)memset((x), 0, (sizeof(sip_contact_t))), (void)(((sip_common_t *)(x))->h_class = (sip_contact_class)), (x)); |
3025 | } |
3026 | #else |
3027 | #define sip_contact_init(x) \ |
3028 | SIP_HEADER_INIT(x, sip_contact_class, sizeof(sip_contact_t))((void)memset((x), 0, (sizeof(sip_contact_t))), (void)(((sip_common_t *)(x))->h_class = (sip_contact_class)), (x)) |
3029 | #endif |
3030 | |
3031 | /**Test if header object is instance of #sip_contact_t. |
3032 | * |
3033 | * Check if the header class is an instance of |
3034 | * @ref sip_contact "Contact header" object and return true (nonzero), |
3035 | * otherwise return false (zero). |
3036 | * |
3037 | * @param header pointer to the header structure to be tested |
3038 | * |
3039 | * @retval 1 (true) if the @a header is an instance of header contact |
3040 | * @retval 0 (false) otherwise |
3041 | * |
3042 | */ |
3043 | #if SU_HAVE_INLINE1 |
3044 | su_inlinestatic inline int sip_is_contact(sip_header_t const *header) |
3045 | { |
3046 | return header && header->sh_classsh_common->h_class->hc_hash == sip_contact_hash; |
3047 | } |
3048 | #else |
3049 | int sip_is_contact(sip_header_t const *header); |
3050 | #endif |
3051 | |
3052 | #define sip_contact_p(h)sip_is_contact((h)) sip_is_contact((h)) |
3053 | |
3054 | |
3055 | /**Duplicate a list of @ref sip_contact "Contact header" header structures #sip_contact_t. |
3056 | * |
3057 | * Duplicate a header |
3058 | * structure @a hdr. If the header structure @a hdr |
3059 | * contains a reference (@c hdr->x_next) to a list of |
3060 | * headers, all the headers in the list are duplicated, too. |
3061 | * |
3062 | * @param home memory home used to allocate new structure |
3063 | * @param hdr header structure to be duplicated |
3064 | * |
3065 | * When duplicating, all parameter lists and non-constant |
3066 | * strings attached to the header are copied, too. The |
3067 | * function uses given memory @a home to allocate all the |
3068 | * memory areas used to copy the header. |
3069 | * |
3070 | * @par Example |
3071 | * @code |
3072 | * |
3073 | * contact = sip_contact_dup(home, sip->sip_contact); |
3074 | * |
3075 | * @endcode |
3076 | * |
3077 | * @return |
3078 | * A pointer to the |
3079 | * newly duplicated #sip_contact_t header structure, or NULL |
3080 | * upon an error. |
3081 | * |
3082 | */ |
3083 | #if SU_HAVE_INLINE1 |
3084 | su_inlinestatic inline |
3085 | #endif |
3086 | sip_contact_t *sip_contact_dup(su_home_t *home, sip_contact_t const *hdr) |
3087 | __attribute__((__malloc__)); |
3088 | |
3089 | #if SU_HAVE_INLINE1 |
3090 | su_inlinestatic inline |
3091 | sip_contact_t *sip_contact_dup(su_home_t *home, sip_contact_t const *hdr) |
3092 | { |
3093 | return (sip_contact_t *) |
3094 | msg_header_dup_as(home, sip_contact_class, (msg_header_t const *)hdr); |
3095 | } |
3096 | #endif |
3097 | |
3098 | /**Copy a list of @ref sip_contact "Contact header" header structures #sip_contact_t. |
3099 | * |
3100 | * The function sip_contact_copy() copies a header structure @a |
3101 | * hdr. If the header structure @a hdr contains a reference (@c |
3102 | * hdr->h_next) to a list of headers, all the headers in that |
3103 | * list are copied, too. The function uses given memory @a home |
3104 | * to allocate all the memory areas used to copy the list of header |
3105 | * structure @a hdr. |
3106 | * |
3107 | * @param home memory home used to allocate new structure |
3108 | * @param hdr pointer to the header structure to be copied |
3109 | * |
3110 | * When copying, only the header structure and parameter lists attached to |
3111 | * it are duplicated. The new header structure retains all the references to |
3112 | * the strings within the old @a hdr header, including the encoding of the |
3113 | * old header, if present. |
3114 | * |
3115 | * @par Example |
3116 | * @code |
3117 | * |
3118 | * contact = sip_contact_copy(home, sip->sip_contact); |
3119 | * |
3120 | * @endcode |
3121 | * |
3122 | * @return |
3123 | * A pointer to newly copied header structure, or NULL upon an error. |
3124 | * |
3125 | */ |
3126 | #if SU_HAVE_INLINE1 |
3127 | su_inlinestatic inline |
3128 | #endif |
3129 | sip_contact_t *sip_contact_copy(su_home_t *home, sip_contact_t const *hdr) |
3130 | __attribute__((__malloc__)); |
3131 | |
3132 | #if SU_HAVE_INLINE1 |
3133 | su_inlinestatic inline |
3134 | sip_contact_t *sip_contact_copy(su_home_t *home, sip_contact_t const *hdr) |
3135 | { |
3136 | return (sip_contact_t *) |
3137 | msg_header_copy_as(home, sip_contact_class, (msg_header_t const *)hdr); |
3138 | } |
3139 | #endif |
3140 | |
3141 | /**Make a @ref sip_contact "Contact header" structure #sip_contact_t. |
3142 | * |
3143 | * The function sip_contact_make() makes a new |
3144 | * #sip_contact_t header structure. It allocates a new |
3145 | * header structure, and decodes the string @a s as the |
3146 | * value of the structure. |
3147 | * |
3148 | * @param home memory home used to allocate new header structure. |
3149 | * @param s string to be decoded as value of the new header structure |
3150 | * |
3151 | * @return |
3152 | * A pointer to newly maked #sip_contact_t header structure, or NULL upon an |
3153 | * error. |
3154 | * |
3155 | */ |
3156 | #if SU_HAVE_INLINE1 |
3157 | su_inlinestatic inline |
3158 | #endif |
3159 | sip_contact_t *sip_contact_make(su_home_t *home, char const *s) |
3160 | __attribute__((__malloc__)); |
3161 | |
3162 | #if SU_HAVE_INLINE1 |
3163 | su_inlinestatic inline sip_contact_t *sip_contact_make(su_home_t *home, char const *s) |
3164 | { |
3165 | return (sip_contact_t *)sip_header_make(home, sip_contact_class, s)((sip_header_t *)msg_header_make((home), (sip_contact_class), (s))); |
3166 | } |
3167 | #endif |
3168 | |
3169 | /**Make a @ref sip_contact "Contact header" from formatting result. |
3170 | * |
3171 | * Make a new #sip_contact_t object using formatting result as its value. |
3172 | * The function first prints the arguments according to the format @a fmt |
3173 | * specified. Then it allocates a new header structure, and parses the |
3174 | * formatting result to the structure #sip_contact_t. |
3175 | * |
3176 | * @param home memory home used to allocate new header structure. |
3177 | * @param fmt string used as a printf()-style format |
3178 | * @param ... argument list for format |
3179 | * |
3180 | * @return |
3181 | * A pointer to newly |
3182 | * makes header structure, or NULL upon an error. |
3183 | * |
3184 | * @HIDE |
3185 | * |
3186 | */ |
3187 | #if SU_HAVE_INLINE1 |
3188 | su_inlinestatic inline |
3189 | #endif |
3190 | sip_contact_t *sip_contact_format(su_home_t *home, char const *fmt, ...) |
3191 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
3192 | |
3193 | #if SU_HAVE_INLINE1 |
3194 | su_inlinestatic inline sip_contact_t *sip_contact_format(su_home_t *home, char const *fmt, ...) |
3195 | { |
3196 | sip_header_t *h; |
3197 | va_list ap; |
3198 | |
3199 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
3200 | h = sip_header_vformat(home, sip_contact_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_contact_class ), (fmt), (ap))); |
3201 | va_end(ap)__builtin_va_end(ap); |
3202 | |
3203 | return (sip_contact_t *)h; |
3204 | } |
3205 | #endif |
3206 | |
3207 | /** @} */ |
3208 | |
3209 | /**@addtogroup sip_rseq |
3210 | * @{ |
3211 | */ |
3212 | |
3213 | /** Parse a SIP @ref sip_rseq "RSeq header". @internal */ |
3214 | SOFIAPUBFUN issize_t sip_rseq_d(su_home_t *, msg_header_t *, |
3215 | char *s, isize_t slen); |
3216 | |
3217 | /** Print a SIP @ref sip_rseq "RSeq header". @internal */ |
3218 | SOFIAPUBFUN issize_t sip_rseq_e(char b[], isize_t bsiz, |
3219 | msg_header_t const *h, int flags); |
3220 | |
3221 | /**Access a SIP @ref sip_rseq "RSeq header" |
3222 | * structure #sip_rseq_t from #sip_t. |
3223 | * |
3224 | */ |
3225 | #define sip_rseq(sip)((sip_rseq_t *)msg_header_access((msg_pub_t*)(sip), sip_rseq_class )) \ |
3226 | ((sip_rseq_t *)msg_header_access((msg_pub_t*)(sip), sip_rseq_class)) |
3227 | |
3228 | /**Initializer for structure #sip_rseq_t. |
3229 | * |
3230 | * A static #sip_rseq_t structure for |
3231 | * @ref sip_rseq "RSeq header" must be initialized with |
3232 | * the SIP_RSEQ_INIT() macro. |
3233 | * For instance, |
3234 | * @code |
3235 | * |
3236 | * sip_rseq_t sip_rseq = SIP_RSEQ_INIT; |
3237 | * |
3238 | * @endcode |
3239 | * @HI |
3240 | * |
3241 | */ |
3242 | #define SIP_RSEQ_INIT(){{{ 0, 0, sip_rseq_class }}} SIP_HDR_INIT(rseq){{{ 0, 0, sip_rseq_class }}} |
3243 | |
3244 | /**Initialize a structure #sip_rseq_t. |
3245 | * |
3246 | * An #sip_rseq_t structure for |
3247 | * @ref sip_rseq "RSeq header" can be initialized with the |
3248 | * sip_rseq_init() function/macro. For instance, |
3249 | * @code |
3250 | * |
3251 | * sip_rseq_t sip_rseq; |
3252 | * |
3253 | * sip_rseq_init(&sip_rseq); |
3254 | * |
3255 | * @endcode |
3256 | * @HI |
3257 | * |
3258 | */ |
3259 | #if SU_HAVE_INLINE1 |
3260 | su_inlinestatic inline sip_rseq_t *sip_rseq_init(sip_rseq_t x[1]) |
3261 | { |
3262 | return SIP_HEADER_INIT(x, sip_rseq_class, sizeof(sip_rseq_t))((void)memset((x), 0, (sizeof(sip_rseq_t))), (void)(((sip_common_t *)(x))->h_class = (sip_rseq_class)), (x)); |
3263 | } |
3264 | #else |
3265 | #define sip_rseq_init(x) \ |
3266 | SIP_HEADER_INIT(x, sip_rseq_class, sizeof(sip_rseq_t))((void)memset((x), 0, (sizeof(sip_rseq_t))), (void)(((sip_common_t *)(x))->h_class = (sip_rseq_class)), (x)) |
3267 | #endif |
3268 | |
3269 | /**Test if header object is instance of #sip_rseq_t. |
3270 | * |
3271 | * Check if the header class is an instance of |
3272 | * @ref sip_rseq "RSeq header" object and return true (nonzero), |
3273 | * otherwise return false (zero). |
3274 | * |
3275 | * @param header pointer to the header structure to be tested |
3276 | * |
3277 | * @retval 1 (true) if the @a header is an instance of header rseq |
3278 | * @retval 0 (false) otherwise |
3279 | * |
3280 | */ |
3281 | #if SU_HAVE_INLINE1 |
3282 | su_inlinestatic inline int sip_is_rseq(sip_header_t const *header) |
3283 | { |
3284 | return header && header->sh_classsh_common->h_class->hc_hash == sip_rseq_hash; |
3285 | } |
3286 | #else |
3287 | int sip_is_rseq(sip_header_t const *header); |
3288 | #endif |
3289 | |
3290 | #define sip_rseq_p(h)sip_is_rseq((h)) sip_is_rseq((h)) |
3291 | |
3292 | |
3293 | /**Duplicate a list of @ref sip_rseq "RSeq header" header structures #sip_rseq_t. |
3294 | * |
3295 | * Duplicate a header |
3296 | * structure @a hdr. If the header structure @a hdr |
3297 | * contains a reference (@c hdr->x_next) to a list of |
3298 | * headers, all the headers in the list are duplicated, too. |
3299 | * |
3300 | * @param home memory home used to allocate new structure |
3301 | * @param hdr header structure to be duplicated |
3302 | * |
3303 | * When duplicating, all parameter lists and non-constant |
3304 | * strings attached to the header are copied, too. The |
3305 | * function uses given memory @a home to allocate all the |
3306 | * memory areas used to copy the header. |
3307 | * |
3308 | * @par Example |
3309 | * @code |
3310 | * |
3311 | * rseq = sip_rseq_dup(home, sip->sip_rseq); |
3312 | * |
3313 | * @endcode |
3314 | * |
3315 | * @return |
3316 | * A pointer to the |
3317 | * newly duplicated #sip_rseq_t header structure, or NULL |
3318 | * upon an error. |
3319 | * |
3320 | */ |
3321 | #if SU_HAVE_INLINE1 |
3322 | su_inlinestatic inline |
3323 | #endif |
3324 | sip_rseq_t *sip_rseq_dup(su_home_t *home, sip_rseq_t const *hdr) |
3325 | __attribute__((__malloc__)); |
3326 | |
3327 | #if SU_HAVE_INLINE1 |
3328 | su_inlinestatic inline |
3329 | sip_rseq_t *sip_rseq_dup(su_home_t *home, sip_rseq_t const *hdr) |
3330 | { |
3331 | return (sip_rseq_t *) |
3332 | msg_header_dup_as(home, sip_rseq_class, (msg_header_t const *)hdr); |
3333 | } |
3334 | #endif |
3335 | |
3336 | /**Copy a list of @ref sip_rseq "RSeq header" header structures #sip_rseq_t. |
3337 | * |
3338 | * The function sip_rseq_copy() copies a header structure @a |
3339 | * hdr. If the header structure @a hdr contains a reference (@c |
3340 | * hdr->h_next) to a list of headers, all the headers in that |
3341 | * list are copied, too. The function uses given memory @a home |
3342 | * to allocate all the memory areas used to copy the list of header |
3343 | * structure @a hdr. |
3344 | * |
3345 | * @param home memory home used to allocate new structure |
3346 | * @param hdr pointer to the header structure to be copied |
3347 | * |
3348 | * When copying, only the header structure and parameter lists attached to |
3349 | * it are duplicated. The new header structure retains all the references to |
3350 | * the strings within the old @a hdr header, including the encoding of the |
3351 | * old header, if present. |
3352 | * |
3353 | * @par Example |
3354 | * @code |
3355 | * |
3356 | * rseq = sip_rseq_copy(home, sip->sip_rseq); |
3357 | * |
3358 | * @endcode |
3359 | * |
3360 | * @return |
3361 | * A pointer to newly copied header structure, or NULL upon an error. |
3362 | * |
3363 | */ |
3364 | #if SU_HAVE_INLINE1 |
3365 | su_inlinestatic inline |
3366 | #endif |
3367 | sip_rseq_t *sip_rseq_copy(su_home_t *home, sip_rseq_t const *hdr) |
3368 | __attribute__((__malloc__)); |
3369 | |
3370 | #if SU_HAVE_INLINE1 |
3371 | su_inlinestatic inline |
3372 | sip_rseq_t *sip_rseq_copy(su_home_t *home, sip_rseq_t const *hdr) |
3373 | { |
3374 | return (sip_rseq_t *) |
3375 | msg_header_copy_as(home, sip_rseq_class, (msg_header_t const *)hdr); |
3376 | } |
3377 | #endif |
3378 | |
3379 | /**Make a @ref sip_rseq "RSeq header" structure #sip_rseq_t. |
3380 | * |
3381 | * The function sip_rseq_make() makes a new |
3382 | * #sip_rseq_t header structure. It allocates a new |
3383 | * header structure, and decodes the string @a s as the |
3384 | * value of the structure. |
3385 | * |
3386 | * @param home memory home used to allocate new header structure. |
3387 | * @param s string to be decoded as value of the new header structure |
3388 | * |
3389 | * @return |
3390 | * A pointer to newly maked #sip_rseq_t header structure, or NULL upon an |
3391 | * error. |
3392 | * |
3393 | */ |
3394 | #if SU_HAVE_INLINE1 |
3395 | su_inlinestatic inline |
3396 | #endif |
3397 | sip_rseq_t *sip_rseq_make(su_home_t *home, char const *s) |
3398 | __attribute__((__malloc__)); |
3399 | |
3400 | #if SU_HAVE_INLINE1 |
3401 | su_inlinestatic inline sip_rseq_t *sip_rseq_make(su_home_t *home, char const *s) |
3402 | { |
3403 | return (sip_rseq_t *)sip_header_make(home, sip_rseq_class, s)((sip_header_t *)msg_header_make((home), (sip_rseq_class), (s ))); |
3404 | } |
3405 | #endif |
3406 | |
3407 | /**Make a @ref sip_rseq "RSeq header" from formatting result. |
3408 | * |
3409 | * Make a new #sip_rseq_t object using formatting result as its value. |
3410 | * The function first prints the arguments according to the format @a fmt |
3411 | * specified. Then it allocates a new header structure, and parses the |
3412 | * formatting result to the structure #sip_rseq_t. |
3413 | * |
3414 | * @param home memory home used to allocate new header structure. |
3415 | * @param fmt string used as a printf()-style format |
3416 | * @param ... argument list for format |
3417 | * |
3418 | * @return |
3419 | * A pointer to newly |
3420 | * makes header structure, or NULL upon an error. |
3421 | * |
3422 | * @HIDE |
3423 | * |
3424 | */ |
3425 | #if SU_HAVE_INLINE1 |
3426 | su_inlinestatic inline |
3427 | #endif |
3428 | sip_rseq_t *sip_rseq_format(su_home_t *home, char const *fmt, ...) |
3429 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
3430 | |
3431 | #if SU_HAVE_INLINE1 |
3432 | su_inlinestatic inline sip_rseq_t *sip_rseq_format(su_home_t *home, char const *fmt, ...) |
3433 | { |
3434 | sip_header_t *h; |
3435 | va_list ap; |
3436 | |
3437 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
3438 | h = sip_header_vformat(home, sip_rseq_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_rseq_class), (fmt), (ap))); |
3439 | va_end(ap)__builtin_va_end(ap); |
3440 | |
3441 | return (sip_rseq_t *)h; |
3442 | } |
3443 | #endif |
3444 | |
3445 | /** @} */ |
3446 | |
3447 | /**@addtogroup sip_rack |
3448 | * @{ |
3449 | */ |
3450 | |
3451 | /** Parse a SIP @ref sip_rack "RAck header". @internal */ |
3452 | SOFIAPUBFUN issize_t sip_rack_d(su_home_t *, msg_header_t *, |
3453 | char *s, isize_t slen); |
3454 | |
3455 | /** Print a SIP @ref sip_rack "RAck header". @internal */ |
3456 | SOFIAPUBFUN issize_t sip_rack_e(char b[], isize_t bsiz, |
3457 | msg_header_t const *h, int flags); |
3458 | |
3459 | /**Access a SIP @ref sip_rack "RAck header" |
3460 | * structure #sip_rack_t from #sip_t. |
3461 | * |
3462 | */ |
3463 | #define sip_rack(sip)((sip_rack_t *)msg_header_access((msg_pub_t*)(sip), sip_rack_class )) \ |
3464 | ((sip_rack_t *)msg_header_access((msg_pub_t*)(sip), sip_rack_class)) |
3465 | |
3466 | /**Initializer for structure #sip_rack_t. |
3467 | * |
3468 | * A static #sip_rack_t structure for |
3469 | * @ref sip_rack "RAck header" must be initialized with |
3470 | * the SIP_RACK_INIT() macro. |
3471 | * For instance, |
3472 | * @code |
3473 | * |
3474 | * sip_rack_t sip_rack = SIP_RACK_INIT; |
3475 | * |
3476 | * @endcode |
3477 | * @HI |
3478 | * |
3479 | */ |
3480 | #define SIP_RACK_INIT(){{{ 0, 0, sip_rack_class }}} SIP_HDR_INIT(rack){{{ 0, 0, sip_rack_class }}} |
3481 | |
3482 | /**Initialize a structure #sip_rack_t. |
3483 | * |
3484 | * An #sip_rack_t structure for |
3485 | * @ref sip_rack "RAck header" can be initialized with the |
3486 | * sip_rack_init() function/macro. For instance, |
3487 | * @code |
3488 | * |
3489 | * sip_rack_t sip_rack; |
3490 | * |
3491 | * sip_rack_init(&sip_rack); |
3492 | * |
3493 | * @endcode |
3494 | * @HI |
3495 | * |
3496 | */ |
3497 | #if SU_HAVE_INLINE1 |
3498 | su_inlinestatic inline sip_rack_t *sip_rack_init(sip_rack_t x[1]) |
3499 | { |
3500 | return SIP_HEADER_INIT(x, sip_rack_class, sizeof(sip_rack_t))((void)memset((x), 0, (sizeof(sip_rack_t))), (void)(((sip_common_t *)(x))->h_class = (sip_rack_class)), (x)); |
3501 | } |
3502 | #else |
3503 | #define sip_rack_init(x) \ |
3504 | SIP_HEADER_INIT(x, sip_rack_class, sizeof(sip_rack_t))((void)memset((x), 0, (sizeof(sip_rack_t))), (void)(((sip_common_t *)(x))->h_class = (sip_rack_class)), (x)) |
3505 | #endif |
3506 | |
3507 | /**Test if header object is instance of #sip_rack_t. |
3508 | * |
3509 | * Check if the header class is an instance of |
3510 | * @ref sip_rack "RAck header" object and return true (nonzero), |
3511 | * otherwise return false (zero). |
3512 | * |
3513 | * @param header pointer to the header structure to be tested |
3514 | * |
3515 | * @retval 1 (true) if the @a header is an instance of header rack |
3516 | * @retval 0 (false) otherwise |
3517 | * |
3518 | */ |
3519 | #if SU_HAVE_INLINE1 |
3520 | su_inlinestatic inline int sip_is_rack(sip_header_t const *header) |
3521 | { |
3522 | return header && header->sh_classsh_common->h_class->hc_hash == sip_rack_hash; |
3523 | } |
3524 | #else |
3525 | int sip_is_rack(sip_header_t const *header); |
3526 | #endif |
3527 | |
3528 | #define sip_rack_p(h)sip_is_rack((h)) sip_is_rack((h)) |
3529 | |
3530 | |
3531 | /**Duplicate a list of @ref sip_rack "RAck header" header structures #sip_rack_t. |
3532 | * |
3533 | * Duplicate a header |
3534 | * structure @a hdr. If the header structure @a hdr |
3535 | * contains a reference (@c hdr->x_next) to a list of |
3536 | * headers, all the headers in the list are duplicated, too. |
3537 | * |
3538 | * @param home memory home used to allocate new structure |
3539 | * @param hdr header structure to be duplicated |
3540 | * |
3541 | * When duplicating, all parameter lists and non-constant |
3542 | * strings attached to the header are copied, too. The |
3543 | * function uses given memory @a home to allocate all the |
3544 | * memory areas used to copy the header. |
3545 | * |
3546 | * @par Example |
3547 | * @code |
3548 | * |
3549 | * rack = sip_rack_dup(home, sip->sip_rack); |
3550 | * |
3551 | * @endcode |
3552 | * |
3553 | * @return |
3554 | * A pointer to the |
3555 | * newly duplicated #sip_rack_t header structure, or NULL |
3556 | * upon an error. |
3557 | * |
3558 | */ |
3559 | #if SU_HAVE_INLINE1 |
3560 | su_inlinestatic inline |
3561 | #endif |
3562 | sip_rack_t *sip_rack_dup(su_home_t *home, sip_rack_t const *hdr) |
3563 | __attribute__((__malloc__)); |
3564 | |
3565 | #if SU_HAVE_INLINE1 |
3566 | su_inlinestatic inline |
3567 | sip_rack_t *sip_rack_dup(su_home_t *home, sip_rack_t const *hdr) |
3568 | { |
3569 | return (sip_rack_t *) |
3570 | msg_header_dup_as(home, sip_rack_class, (msg_header_t const *)hdr); |
3571 | } |
3572 | #endif |
3573 | |
3574 | /**Copy a list of @ref sip_rack "RAck header" header structures #sip_rack_t. |
3575 | * |
3576 | * The function sip_rack_copy() copies a header structure @a |
3577 | * hdr. If the header structure @a hdr contains a reference (@c |
3578 | * hdr->h_next) to a list of headers, all the headers in that |
3579 | * list are copied, too. The function uses given memory @a home |
3580 | * to allocate all the memory areas used to copy the list of header |
3581 | * structure @a hdr. |
3582 | * |
3583 | * @param home memory home used to allocate new structure |
3584 | * @param hdr pointer to the header structure to be copied |
3585 | * |
3586 | * When copying, only the header structure and parameter lists attached to |
3587 | * it are duplicated. The new header structure retains all the references to |
3588 | * the strings within the old @a hdr header, including the encoding of the |
3589 | * old header, if present. |
3590 | * |
3591 | * @par Example |
3592 | * @code |
3593 | * |
3594 | * rack = sip_rack_copy(home, sip->sip_rack); |
3595 | * |
3596 | * @endcode |
3597 | * |
3598 | * @return |
3599 | * A pointer to newly copied header structure, or NULL upon an error. |
3600 | * |
3601 | */ |
3602 | #if SU_HAVE_INLINE1 |
3603 | su_inlinestatic inline |
3604 | #endif |
3605 | sip_rack_t *sip_rack_copy(su_home_t *home, sip_rack_t const *hdr) |
3606 | __attribute__((__malloc__)); |
3607 | |
3608 | #if SU_HAVE_INLINE1 |
3609 | su_inlinestatic inline |
3610 | sip_rack_t *sip_rack_copy(su_home_t *home, sip_rack_t const *hdr) |
3611 | { |
3612 | return (sip_rack_t *) |
3613 | msg_header_copy_as(home, sip_rack_class, (msg_header_t const *)hdr); |
3614 | } |
3615 | #endif |
3616 | |
3617 | /**Make a @ref sip_rack "RAck header" structure #sip_rack_t. |
3618 | * |
3619 | * The function sip_rack_make() makes a new |
3620 | * #sip_rack_t header structure. It allocates a new |
3621 | * header structure, and decodes the string @a s as the |
3622 | * value of the structure. |
3623 | * |
3624 | * @param home memory home used to allocate new header structure. |
3625 | * @param s string to be decoded as value of the new header structure |
3626 | * |
3627 | * @return |
3628 | * A pointer to newly maked #sip_rack_t header structure, or NULL upon an |
3629 | * error. |
3630 | * |
3631 | */ |
3632 | #if SU_HAVE_INLINE1 |
3633 | su_inlinestatic inline |
3634 | #endif |
3635 | sip_rack_t *sip_rack_make(su_home_t *home, char const *s) |
3636 | __attribute__((__malloc__)); |
3637 | |
3638 | #if SU_HAVE_INLINE1 |
3639 | su_inlinestatic inline sip_rack_t *sip_rack_make(su_home_t *home, char const *s) |
3640 | { |
3641 | return (sip_rack_t *)sip_header_make(home, sip_rack_class, s)((sip_header_t *)msg_header_make((home), (sip_rack_class), (s ))); |
3642 | } |
3643 | #endif |
3644 | |
3645 | /**Make a @ref sip_rack "RAck header" from formatting result. |
3646 | * |
3647 | * Make a new #sip_rack_t object using formatting result as its value. |
3648 | * The function first prints the arguments according to the format @a fmt |
3649 | * specified. Then it allocates a new header structure, and parses the |
3650 | * formatting result to the structure #sip_rack_t. |
3651 | * |
3652 | * @param home memory home used to allocate new header structure. |
3653 | * @param fmt string used as a printf()-style format |
3654 | * @param ... argument list for format |
3655 | * |
3656 | * @return |
3657 | * A pointer to newly |
3658 | * makes header structure, or NULL upon an error. |
3659 | * |
3660 | * @HIDE |
3661 | * |
3662 | */ |
3663 | #if SU_HAVE_INLINE1 |
3664 | su_inlinestatic inline |
3665 | #endif |
3666 | sip_rack_t *sip_rack_format(su_home_t *home, char const *fmt, ...) |
3667 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
3668 | |
3669 | #if SU_HAVE_INLINE1 |
3670 | su_inlinestatic inline sip_rack_t *sip_rack_format(su_home_t *home, char const *fmt, ...) |
3671 | { |
3672 | sip_header_t *h; |
3673 | va_list ap; |
3674 | |
3675 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
3676 | h = sip_header_vformat(home, sip_rack_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_rack_class), (fmt), (ap))); |
3677 | va_end(ap)__builtin_va_end(ap); |
3678 | |
3679 | return (sip_rack_t *)h; |
3680 | } |
3681 | #endif |
3682 | |
3683 | /** @} */ |
3684 | |
3685 | /**@addtogroup sip_request_disposition |
3686 | * @{ |
3687 | */ |
3688 | |
3689 | /** Parse a SIP @ref sip_request_disposition "Request-Disposition header". @internal */ |
3690 | SOFIAPUBFUN issize_t sip_request_disposition_d(su_home_t *, msg_header_t *, |
3691 | char *s, isize_t slen); |
3692 | |
3693 | /** Print a SIP @ref sip_request_disposition "Request-Disposition header". @internal */ |
3694 | SOFIAPUBFUN issize_t sip_request_disposition_e(char b[], isize_t bsiz, |
3695 | msg_header_t const *h, int flags); |
3696 | |
3697 | /**Access a SIP @ref sip_request_disposition "Request-Disposition header" |
3698 | * structure #sip_request_disposition_t from #sip_t. |
3699 | * |
3700 | */ |
3701 | #define sip_request_disposition(sip)((sip_request_disposition_t *)msg_header_access((msg_pub_t*)( sip), sip_request_disposition_class)) \ |
3702 | ((sip_request_disposition_t *)msg_header_access((msg_pub_t*)(sip), sip_request_disposition_class)) |
3703 | |
3704 | /**Initializer for structure #sip_request_disposition_t. |
3705 | * |
3706 | * A static #sip_request_disposition_t structure for |
3707 | * @ref sip_request_disposition "Request-Disposition header" must be initialized with |
3708 | * the SIP_REQUEST_DISPOSITION_INIT() macro. |
3709 | * For instance, |
3710 | * @code |
3711 | * |
3712 | * sip_request_disposition_t sip_request_disposition = SIP_REQUEST_DISPOSITION_INIT; |
3713 | * |
3714 | * @endcode |
3715 | * @HI |
3716 | * |
3717 | */ |
3718 | #define SIP_REQUEST_DISPOSITION_INIT(){{{ 0, 0, sip_request_disposition_class }}} SIP_HDR_INIT(request_disposition){{{ 0, 0, sip_request_disposition_class }}} |
3719 | |
3720 | /**Initialize a structure #sip_request_disposition_t. |
3721 | * |
3722 | * An #sip_request_disposition_t structure for |
3723 | * @ref sip_request_disposition "Request-Disposition header" can be initialized with the |
3724 | * sip_request_disposition_init() function/macro. For instance, |
3725 | * @code |
3726 | * |
3727 | * sip_request_disposition_t sip_request_disposition; |
3728 | * |
3729 | * sip_request_disposition_init(&sip_request_disposition); |
3730 | * |
3731 | * @endcode |
3732 | * @HI |
3733 | * |
3734 | */ |
3735 | #if SU_HAVE_INLINE1 |
3736 | su_inlinestatic inline sip_request_disposition_t *sip_request_disposition_init(sip_request_disposition_t x[1]) |
3737 | { |
3738 | return SIP_HEADER_INIT(x, sip_request_disposition_class, sizeof(sip_request_disposition_t))((void)memset((x), 0, (sizeof(sip_request_disposition_t))), ( void)(((sip_common_t *)(x))->h_class = (sip_request_disposition_class )), (x)); |
3739 | } |
3740 | #else |
3741 | #define sip_request_disposition_init(x) \ |
3742 | SIP_HEADER_INIT(x, sip_request_disposition_class, sizeof(sip_request_disposition_t))((void)memset((x), 0, (sizeof(sip_request_disposition_t))), ( void)(((sip_common_t *)(x))->h_class = (sip_request_disposition_class )), (x)) |
3743 | #endif |
3744 | |
3745 | /**Test if header object is instance of #sip_request_disposition_t. |
3746 | * |
3747 | * Check if the header class is an instance of |
3748 | * @ref sip_request_disposition "Request-Disposition header" object and return true (nonzero), |
3749 | * otherwise return false (zero). |
3750 | * |
3751 | * @param header pointer to the header structure to be tested |
3752 | * |
3753 | * @retval 1 (true) if the @a header is an instance of header request_disposition |
3754 | * @retval 0 (false) otherwise |
3755 | * |
3756 | */ |
3757 | #if SU_HAVE_INLINE1 |
3758 | su_inlinestatic inline int sip_is_request_disposition(sip_header_t const *header) |
3759 | { |
3760 | return header && header->sh_classsh_common->h_class->hc_hash == sip_request_disposition_hash; |
3761 | } |
3762 | #else |
3763 | int sip_is_request_disposition(sip_header_t const *header); |
3764 | #endif |
3765 | |
3766 | #define sip_request_disposition_p(h)sip_is_request_disposition((h)) sip_is_request_disposition((h)) |
3767 | |
3768 | |
3769 | /**Duplicate a list of @ref sip_request_disposition "Request-Disposition header" header structures #sip_request_disposition_t. |
3770 | * |
3771 | * Duplicate a header |
3772 | * structure @a hdr. If the header structure @a hdr |
3773 | * contains a reference (@c hdr->x_next) to a list of |
3774 | * headers, all the headers in the list are duplicated, too. |
3775 | * |
3776 | * @param home memory home used to allocate new structure |
3777 | * @param hdr header structure to be duplicated |
3778 | * |
3779 | * When duplicating, all parameter lists and non-constant |
3780 | * strings attached to the header are copied, too. The |
3781 | * function uses given memory @a home to allocate all the |
3782 | * memory areas used to copy the header. |
3783 | * |
3784 | * @par Example |
3785 | * @code |
3786 | * |
3787 | * request_disposition = sip_request_disposition_dup(home, sip->sip_request_disposition); |
3788 | * |
3789 | * @endcode |
3790 | * |
3791 | * @return |
3792 | * A pointer to the |
3793 | * newly duplicated #sip_request_disposition_t header structure, or NULL |
3794 | * upon an error. |
3795 | * |
3796 | */ |
3797 | #if SU_HAVE_INLINE1 |
3798 | su_inlinestatic inline |
3799 | #endif |
3800 | sip_request_disposition_t *sip_request_disposition_dup(su_home_t *home, sip_request_disposition_t const *hdr) |
3801 | __attribute__((__malloc__)); |
3802 | |
3803 | #if SU_HAVE_INLINE1 |
3804 | su_inlinestatic inline |
3805 | sip_request_disposition_t *sip_request_disposition_dup(su_home_t *home, sip_request_disposition_t const *hdr) |
3806 | { |
3807 | return (sip_request_disposition_t *) |
3808 | msg_header_dup_as(home, sip_request_disposition_class, (msg_header_t const *)hdr); |
3809 | } |
3810 | #endif |
3811 | |
3812 | /**Copy a list of @ref sip_request_disposition "Request-Disposition header" header structures #sip_request_disposition_t. |
3813 | * |
3814 | * The function sip_request_disposition_copy() copies a header structure @a |
3815 | * hdr. If the header structure @a hdr contains a reference (@c |
3816 | * hdr->h_next) to a list of headers, all the headers in that |
3817 | * list are copied, too. The function uses given memory @a home |
3818 | * to allocate all the memory areas used to copy the list of header |
3819 | * structure @a hdr. |
3820 | * |
3821 | * @param home memory home used to allocate new structure |
3822 | * @param hdr pointer to the header structure to be copied |
3823 | * |
3824 | * When copying, only the header structure and parameter lists attached to |
3825 | * it are duplicated. The new header structure retains all the references to |
3826 | * the strings within the old @a hdr header, including the encoding of the |
3827 | * old header, if present. |
3828 | * |
3829 | * @par Example |
3830 | * @code |
3831 | * |
3832 | * request_disposition = sip_request_disposition_copy(home, sip->sip_request_disposition); |
3833 | * |
3834 | * @endcode |
3835 | * |
3836 | * @return |
3837 | * A pointer to newly copied header structure, or NULL upon an error. |
3838 | * |
3839 | */ |
3840 | #if SU_HAVE_INLINE1 |
3841 | su_inlinestatic inline |
3842 | #endif |
3843 | sip_request_disposition_t *sip_request_disposition_copy(su_home_t *home, sip_request_disposition_t const *hdr) |
3844 | __attribute__((__malloc__)); |
3845 | |
3846 | #if SU_HAVE_INLINE1 |
3847 | su_inlinestatic inline |
3848 | sip_request_disposition_t *sip_request_disposition_copy(su_home_t *home, sip_request_disposition_t const *hdr) |
3849 | { |
3850 | return (sip_request_disposition_t *) |
3851 | msg_header_copy_as(home, sip_request_disposition_class, (msg_header_t const *)hdr); |
3852 | } |
3853 | #endif |
3854 | |
3855 | /**Make a @ref sip_request_disposition "Request-Disposition header" structure #sip_request_disposition_t. |
3856 | * |
3857 | * The function sip_request_disposition_make() makes a new |
3858 | * #sip_request_disposition_t header structure. It allocates a new |
3859 | * header structure, and decodes the string @a s as the |
3860 | * value of the structure. |
3861 | * |
3862 | * @param home memory home used to allocate new header structure. |
3863 | * @param s string to be decoded as value of the new header structure |
3864 | * |
3865 | * @return |
3866 | * A pointer to newly maked #sip_request_disposition_t header structure, or NULL upon an |
3867 | * error. |
3868 | * |
3869 | */ |
3870 | #if SU_HAVE_INLINE1 |
3871 | su_inlinestatic inline |
3872 | #endif |
3873 | sip_request_disposition_t *sip_request_disposition_make(su_home_t *home, char const *s) |
3874 | __attribute__((__malloc__)); |
3875 | |
3876 | #if SU_HAVE_INLINE1 |
3877 | su_inlinestatic inline sip_request_disposition_t *sip_request_disposition_make(su_home_t *home, char const *s) |
3878 | { |
3879 | return (sip_request_disposition_t *)sip_header_make(home, sip_request_disposition_class, s)((sip_header_t *)msg_header_make((home), (sip_request_disposition_class ), (s))); |
3880 | } |
3881 | #endif |
3882 | |
3883 | /**Make a @ref sip_request_disposition "Request-Disposition header" from formatting result. |
3884 | * |
3885 | * Make a new #sip_request_disposition_t object using formatting result as its value. |
3886 | * The function first prints the arguments according to the format @a fmt |
3887 | * specified. Then it allocates a new header structure, and parses the |
3888 | * formatting result to the structure #sip_request_disposition_t. |
3889 | * |
3890 | * @param home memory home used to allocate new header structure. |
3891 | * @param fmt string used as a printf()-style format |
3892 | * @param ... argument list for format |
3893 | * |
3894 | * @return |
3895 | * A pointer to newly |
3896 | * makes header structure, or NULL upon an error. |
3897 | * |
3898 | * @HIDE |
3899 | * |
3900 | */ |
3901 | #if SU_HAVE_INLINE1 |
3902 | su_inlinestatic inline |
3903 | #endif |
3904 | sip_request_disposition_t *sip_request_disposition_format(su_home_t *home, char const *fmt, ...) |
3905 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
3906 | |
3907 | #if SU_HAVE_INLINE1 |
3908 | su_inlinestatic inline sip_request_disposition_t *sip_request_disposition_format(su_home_t *home, char const *fmt, ...) |
3909 | { |
3910 | sip_header_t *h; |
3911 | va_list ap; |
3912 | |
3913 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
3914 | h = sip_header_vformat(home, sip_request_disposition_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_request_disposition_class ), (fmt), (ap))); |
3915 | va_end(ap)__builtin_va_end(ap); |
3916 | |
3917 | return (sip_request_disposition_t *)h; |
3918 | } |
3919 | #endif |
3920 | |
3921 | /** @} */ |
3922 | |
3923 | /**@addtogroup sip_accept_contact |
3924 | * @{ |
3925 | */ |
3926 | |
3927 | /** Parse a SIP @ref sip_accept_contact "Accept-Contact header". @internal */ |
3928 | SOFIAPUBFUN issize_t sip_accept_contact_d(su_home_t *, msg_header_t *, |
3929 | char *s, isize_t slen); |
3930 | |
3931 | /** Print a SIP @ref sip_accept_contact "Accept-Contact header". @internal */ |
3932 | SOFIAPUBFUN issize_t sip_accept_contact_e(char b[], isize_t bsiz, |
3933 | msg_header_t const *h, int flags); |
3934 | |
3935 | /**Access a SIP @ref sip_accept_contact "Accept-Contact header" |
3936 | * structure #sip_accept_contact_t from #sip_t. |
3937 | * |
3938 | */ |
3939 | #define sip_accept_contact(sip)((sip_accept_contact_t *)msg_header_access((msg_pub_t*)(sip), sip_accept_contact_class)) \ |
3940 | ((sip_accept_contact_t *)msg_header_access((msg_pub_t*)(sip), sip_accept_contact_class)) |
3941 | |
3942 | /**Initializer for structure #sip_accept_contact_t. |
3943 | * |
3944 | * A static #sip_accept_contact_t structure for |
3945 | * @ref sip_accept_contact "Accept-Contact header" must be initialized with |
3946 | * the SIP_ACCEPT_CONTACT_INIT() macro. |
3947 | * For instance, |
3948 | * @code |
3949 | * |
3950 | * sip_accept_contact_t sip_accept_contact = SIP_ACCEPT_CONTACT_INIT; |
3951 | * |
3952 | * @endcode |
3953 | * @HI |
3954 | * |
3955 | */ |
3956 | #define SIP_ACCEPT_CONTACT_INIT(){{{ 0, 0, sip_accept_contact_class }}} SIP_HDR_INIT(accept_contact){{{ 0, 0, sip_accept_contact_class }}} |
3957 | |
3958 | /**Initialize a structure #sip_accept_contact_t. |
3959 | * |
3960 | * An #sip_accept_contact_t structure for |
3961 | * @ref sip_accept_contact "Accept-Contact header" can be initialized with the |
3962 | * sip_accept_contact_init() function/macro. For instance, |
3963 | * @code |
3964 | * |
3965 | * sip_accept_contact_t sip_accept_contact; |
3966 | * |
3967 | * sip_accept_contact_init(&sip_accept_contact); |
3968 | * |
3969 | * @endcode |
3970 | * @HI |
3971 | * |
3972 | */ |
3973 | #if SU_HAVE_INLINE1 |
3974 | su_inlinestatic inline sip_accept_contact_t *sip_accept_contact_init(sip_accept_contact_t x[1]) |
3975 | { |
3976 | return SIP_HEADER_INIT(x, sip_accept_contact_class, sizeof(sip_accept_contact_t))((void)memset((x), 0, (sizeof(sip_accept_contact_t))), (void) (((sip_common_t *)(x))->h_class = (sip_accept_contact_class )), (x)); |
3977 | } |
3978 | #else |
3979 | #define sip_accept_contact_init(x) \ |
3980 | SIP_HEADER_INIT(x, sip_accept_contact_class, sizeof(sip_accept_contact_t))((void)memset((x), 0, (sizeof(sip_accept_contact_t))), (void) (((sip_common_t *)(x))->h_class = (sip_accept_contact_class )), (x)) |
3981 | #endif |
3982 | |
3983 | /**Test if header object is instance of #sip_accept_contact_t. |
3984 | * |
3985 | * Check if the header class is an instance of |
3986 | * @ref sip_accept_contact "Accept-Contact header" object and return true (nonzero), |
3987 | * otherwise return false (zero). |
3988 | * |
3989 | * @param header pointer to the header structure to be tested |
3990 | * |
3991 | * @retval 1 (true) if the @a header is an instance of header accept_contact |
3992 | * @retval 0 (false) otherwise |
3993 | * |
3994 | */ |
3995 | #if SU_HAVE_INLINE1 |
3996 | su_inlinestatic inline int sip_is_accept_contact(sip_header_t const *header) |
3997 | { |
3998 | return header && header->sh_classsh_common->h_class->hc_hash == sip_accept_contact_hash; |
3999 | } |
4000 | #else |
4001 | int sip_is_accept_contact(sip_header_t const *header); |
4002 | #endif |
4003 | |
4004 | #define sip_accept_contact_p(h)sip_is_accept_contact((h)) sip_is_accept_contact((h)) |
4005 | |
4006 | |
4007 | /**Duplicate a list of @ref sip_accept_contact "Accept-Contact header" header structures #sip_accept_contact_t. |
4008 | * |
4009 | * Duplicate a header |
4010 | * structure @a hdr. If the header structure @a hdr |
4011 | * contains a reference (@c hdr->x_next) to a list of |
4012 | * headers, all the headers in the list are duplicated, too. |
4013 | * |
4014 | * @param home memory home used to allocate new structure |
4015 | * @param hdr header structure to be duplicated |
4016 | * |
4017 | * When duplicating, all parameter lists and non-constant |
4018 | * strings attached to the header are copied, too. The |
4019 | * function uses given memory @a home to allocate all the |
4020 | * memory areas used to copy the header. |
4021 | * |
4022 | * @par Example |
4023 | * @code |
4024 | * |
4025 | * accept_contact = sip_accept_contact_dup(home, sip->sip_accept_contact); |
4026 | * |
4027 | * @endcode |
4028 | * |
4029 | * @return |
4030 | * A pointer to the |
4031 | * newly duplicated #sip_accept_contact_t header structure, or NULL |
4032 | * upon an error. |
4033 | * |
4034 | */ |
4035 | #if SU_HAVE_INLINE1 |
4036 | su_inlinestatic inline |
4037 | #endif |
4038 | sip_accept_contact_t *sip_accept_contact_dup(su_home_t *home, sip_accept_contact_t const *hdr) |
4039 | __attribute__((__malloc__)); |
4040 | |
4041 | #if SU_HAVE_INLINE1 |
4042 | su_inlinestatic inline |
4043 | sip_accept_contact_t *sip_accept_contact_dup(su_home_t *home, sip_accept_contact_t const *hdr) |
4044 | { |
4045 | return (sip_accept_contact_t *) |
4046 | msg_header_dup_as(home, sip_accept_contact_class, (msg_header_t const *)hdr); |
4047 | } |
4048 | #endif |
4049 | |
4050 | /**Copy a list of @ref sip_accept_contact "Accept-Contact header" header structures #sip_accept_contact_t. |
4051 | * |
4052 | * The function sip_accept_contact_copy() copies a header structure @a |
4053 | * hdr. If the header structure @a hdr contains a reference (@c |
4054 | * hdr->h_next) to a list of headers, all the headers in that |
4055 | * list are copied, too. The function uses given memory @a home |
4056 | * to allocate all the memory areas used to copy the list of header |
4057 | * structure @a hdr. |
4058 | * |
4059 | * @param home memory home used to allocate new structure |
4060 | * @param hdr pointer to the header structure to be copied |
4061 | * |
4062 | * When copying, only the header structure and parameter lists attached to |
4063 | * it are duplicated. The new header structure retains all the references to |
4064 | * the strings within the old @a hdr header, including the encoding of the |
4065 | * old header, if present. |
4066 | * |
4067 | * @par Example |
4068 | * @code |
4069 | * |
4070 | * accept_contact = sip_accept_contact_copy(home, sip->sip_accept_contact); |
4071 | * |
4072 | * @endcode |
4073 | * |
4074 | * @return |
4075 | * A pointer to newly copied header structure, or NULL upon an error. |
4076 | * |
4077 | */ |
4078 | #if SU_HAVE_INLINE1 |
4079 | su_inlinestatic inline |
4080 | #endif |
4081 | sip_accept_contact_t *sip_accept_contact_copy(su_home_t *home, sip_accept_contact_t const *hdr) |
4082 | __attribute__((__malloc__)); |
4083 | |
4084 | #if SU_HAVE_INLINE1 |
4085 | su_inlinestatic inline |
4086 | sip_accept_contact_t *sip_accept_contact_copy(su_home_t *home, sip_accept_contact_t const *hdr) |
4087 | { |
4088 | return (sip_accept_contact_t *) |
4089 | msg_header_copy_as(home, sip_accept_contact_class, (msg_header_t const *)hdr); |
4090 | } |
4091 | #endif |
4092 | |
4093 | /**Make a @ref sip_accept_contact "Accept-Contact header" structure #sip_accept_contact_t. |
4094 | * |
4095 | * The function sip_accept_contact_make() makes a new |
4096 | * #sip_accept_contact_t header structure. It allocates a new |
4097 | * header structure, and decodes the string @a s as the |
4098 | * value of the structure. |
4099 | * |
4100 | * @param home memory home used to allocate new header structure. |
4101 | * @param s string to be decoded as value of the new header structure |
4102 | * |
4103 | * @return |
4104 | * A pointer to newly maked #sip_accept_contact_t header structure, or NULL upon an |
4105 | * error. |
4106 | * |
4107 | */ |
4108 | #if SU_HAVE_INLINE1 |
4109 | su_inlinestatic inline |
4110 | #endif |
4111 | sip_accept_contact_t *sip_accept_contact_make(su_home_t *home, char const *s) |
4112 | __attribute__((__malloc__)); |
4113 | |
4114 | #if SU_HAVE_INLINE1 |
4115 | su_inlinestatic inline sip_accept_contact_t *sip_accept_contact_make(su_home_t *home, char const *s) |
4116 | { |
4117 | return (sip_accept_contact_t *)sip_header_make(home, sip_accept_contact_class, s)((sip_header_t *)msg_header_make((home), (sip_accept_contact_class ), (s))); |
4118 | } |
4119 | #endif |
4120 | |
4121 | /**Make a @ref sip_accept_contact "Accept-Contact header" from formatting result. |
4122 | * |
4123 | * Make a new #sip_accept_contact_t object using formatting result as its value. |
4124 | * The function first prints the arguments according to the format @a fmt |
4125 | * specified. Then it allocates a new header structure, and parses the |
4126 | * formatting result to the structure #sip_accept_contact_t. |
4127 | * |
4128 | * @param home memory home used to allocate new header structure. |
4129 | * @param fmt string used as a printf()-style format |
4130 | * @param ... argument list for format |
4131 | * |
4132 | * @return |
4133 | * A pointer to newly |
4134 | * makes header structure, or NULL upon an error. |
4135 | * |
4136 | * @HIDE |
4137 | * |
4138 | */ |
4139 | #if SU_HAVE_INLINE1 |
4140 | su_inlinestatic inline |
4141 | #endif |
4142 | sip_accept_contact_t *sip_accept_contact_format(su_home_t *home, char const *fmt, ...) |
4143 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
4144 | |
4145 | #if SU_HAVE_INLINE1 |
4146 | su_inlinestatic inline sip_accept_contact_t *sip_accept_contact_format(su_home_t *home, char const *fmt, ...) |
4147 | { |
4148 | sip_header_t *h; |
4149 | va_list ap; |
4150 | |
4151 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
4152 | h = sip_header_vformat(home, sip_accept_contact_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_accept_contact_class ), (fmt), (ap))); |
4153 | va_end(ap)__builtin_va_end(ap); |
4154 | |
4155 | return (sip_accept_contact_t *)h; |
4156 | } |
4157 | #endif |
4158 | |
4159 | /** @} */ |
4160 | |
4161 | /**@addtogroup sip_reject_contact |
4162 | * @{ |
4163 | */ |
4164 | |
4165 | /** Parse a SIP @ref sip_reject_contact "Reject-Contact header". @internal */ |
4166 | SOFIAPUBFUN issize_t sip_reject_contact_d(su_home_t *, msg_header_t *, |
4167 | char *s, isize_t slen); |
4168 | |
4169 | /** Print a SIP @ref sip_reject_contact "Reject-Contact header". @internal */ |
4170 | SOFIAPUBFUN issize_t sip_reject_contact_e(char b[], isize_t bsiz, |
4171 | msg_header_t const *h, int flags); |
4172 | |
4173 | /**Access a SIP @ref sip_reject_contact "Reject-Contact header" |
4174 | * structure #sip_reject_contact_t from #sip_t. |
4175 | * |
4176 | */ |
4177 | #define sip_reject_contact(sip)((sip_reject_contact_t *)msg_header_access((msg_pub_t*)(sip), sip_reject_contact_class)) \ |
4178 | ((sip_reject_contact_t *)msg_header_access((msg_pub_t*)(sip), sip_reject_contact_class)) |
4179 | |
4180 | /**Initializer for structure #sip_reject_contact_t. |
4181 | * |
4182 | * A static #sip_reject_contact_t structure for |
4183 | * @ref sip_reject_contact "Reject-Contact header" must be initialized with |
4184 | * the SIP_REJECT_CONTACT_INIT() macro. |
4185 | * For instance, |
4186 | * @code |
4187 | * |
4188 | * sip_reject_contact_t sip_reject_contact = SIP_REJECT_CONTACT_INIT; |
4189 | * |
4190 | * @endcode |
4191 | * @HI |
4192 | * |
4193 | */ |
4194 | #define SIP_REJECT_CONTACT_INIT(){{{ 0, 0, sip_reject_contact_class }}} SIP_HDR_INIT(reject_contact){{{ 0, 0, sip_reject_contact_class }}} |
4195 | |
4196 | /**Initialize a structure #sip_reject_contact_t. |
4197 | * |
4198 | * An #sip_reject_contact_t structure for |
4199 | * @ref sip_reject_contact "Reject-Contact header" can be initialized with the |
4200 | * sip_reject_contact_init() function/macro. For instance, |
4201 | * @code |
4202 | * |
4203 | * sip_reject_contact_t sip_reject_contact; |
4204 | * |
4205 | * sip_reject_contact_init(&sip_reject_contact); |
4206 | * |
4207 | * @endcode |
4208 | * @HI |
4209 | * |
4210 | */ |
4211 | #if SU_HAVE_INLINE1 |
4212 | su_inlinestatic inline sip_reject_contact_t *sip_reject_contact_init(sip_reject_contact_t x[1]) |
4213 | { |
4214 | return SIP_HEADER_INIT(x, sip_reject_contact_class, sizeof(sip_reject_contact_t))((void)memset((x), 0, (sizeof(sip_reject_contact_t))), (void) (((sip_common_t *)(x))->h_class = (sip_reject_contact_class )), (x)); |
4215 | } |
4216 | #else |
4217 | #define sip_reject_contact_init(x) \ |
4218 | SIP_HEADER_INIT(x, sip_reject_contact_class, sizeof(sip_reject_contact_t))((void)memset((x), 0, (sizeof(sip_reject_contact_t))), (void) (((sip_common_t *)(x))->h_class = (sip_reject_contact_class )), (x)) |
4219 | #endif |
4220 | |
4221 | /**Test if header object is instance of #sip_reject_contact_t. |
4222 | * |
4223 | * Check if the header class is an instance of |
4224 | * @ref sip_reject_contact "Reject-Contact header" object and return true (nonzero), |
4225 | * otherwise return false (zero). |
4226 | * |
4227 | * @param header pointer to the header structure to be tested |
4228 | * |
4229 | * @retval 1 (true) if the @a header is an instance of header reject_contact |
4230 | * @retval 0 (false) otherwise |
4231 | * |
4232 | */ |
4233 | #if SU_HAVE_INLINE1 |
4234 | su_inlinestatic inline int sip_is_reject_contact(sip_header_t const *header) |
4235 | { |
4236 | return header && header->sh_classsh_common->h_class->hc_hash == sip_reject_contact_hash; |
4237 | } |
4238 | #else |
4239 | int sip_is_reject_contact(sip_header_t const *header); |
4240 | #endif |
4241 | |
4242 | #define sip_reject_contact_p(h)sip_is_reject_contact((h)) sip_is_reject_contact((h)) |
4243 | |
4244 | |
4245 | /**Duplicate a list of @ref sip_reject_contact "Reject-Contact header" header structures #sip_reject_contact_t. |
4246 | * |
4247 | * Duplicate a header |
4248 | * structure @a hdr. If the header structure @a hdr |
4249 | * contains a reference (@c hdr->x_next) to a list of |
4250 | * headers, all the headers in the list are duplicated, too. |
4251 | * |
4252 | * @param home memory home used to allocate new structure |
4253 | * @param hdr header structure to be duplicated |
4254 | * |
4255 | * When duplicating, all parameter lists and non-constant |
4256 | * strings attached to the header are copied, too. The |
4257 | * function uses given memory @a home to allocate all the |
4258 | * memory areas used to copy the header. |
4259 | * |
4260 | * @par Example |
4261 | * @code |
4262 | * |
4263 | * reject_contact = sip_reject_contact_dup(home, sip->sip_reject_contact); |
4264 | * |
4265 | * @endcode |
4266 | * |
4267 | * @return |
4268 | * A pointer to the |
4269 | * newly duplicated #sip_reject_contact_t header structure, or NULL |
4270 | * upon an error. |
4271 | * |
4272 | */ |
4273 | #if SU_HAVE_INLINE1 |
4274 | su_inlinestatic inline |
4275 | #endif |
4276 | sip_reject_contact_t *sip_reject_contact_dup(su_home_t *home, sip_reject_contact_t const *hdr) |
4277 | __attribute__((__malloc__)); |
4278 | |
4279 | #if SU_HAVE_INLINE1 |
4280 | su_inlinestatic inline |
4281 | sip_reject_contact_t *sip_reject_contact_dup(su_home_t *home, sip_reject_contact_t const *hdr) |
4282 | { |
4283 | return (sip_reject_contact_t *) |
4284 | msg_header_dup_as(home, sip_reject_contact_class, (msg_header_t const *)hdr); |
4285 | } |
4286 | #endif |
4287 | |
4288 | /**Copy a list of @ref sip_reject_contact "Reject-Contact header" header structures #sip_reject_contact_t. |
4289 | * |
4290 | * The function sip_reject_contact_copy() copies a header structure @a |
4291 | * hdr. If the header structure @a hdr contains a reference (@c |
4292 | * hdr->h_next) to a list of headers, all the headers in that |
4293 | * list are copied, too. The function uses given memory @a home |
4294 | * to allocate all the memory areas used to copy the list of header |
4295 | * structure @a hdr. |
4296 | * |
4297 | * @param home memory home used to allocate new structure |
4298 | * @param hdr pointer to the header structure to be copied |
4299 | * |
4300 | * When copying, only the header structure and parameter lists attached to |
4301 | * it are duplicated. The new header structure retains all the references to |
4302 | * the strings within the old @a hdr header, including the encoding of the |
4303 | * old header, if present. |
4304 | * |
4305 | * @par Example |
4306 | * @code |
4307 | * |
4308 | * reject_contact = sip_reject_contact_copy(home, sip->sip_reject_contact); |
4309 | * |
4310 | * @endcode |
4311 | * |
4312 | * @return |
4313 | * A pointer to newly copied header structure, or NULL upon an error. |
4314 | * |
4315 | */ |
4316 | #if SU_HAVE_INLINE1 |
4317 | su_inlinestatic inline |
4318 | #endif |
4319 | sip_reject_contact_t *sip_reject_contact_copy(su_home_t *home, sip_reject_contact_t const *hdr) |
4320 | __attribute__((__malloc__)); |
4321 | |
4322 | #if SU_HAVE_INLINE1 |
4323 | su_inlinestatic inline |
4324 | sip_reject_contact_t *sip_reject_contact_copy(su_home_t *home, sip_reject_contact_t const *hdr) |
4325 | { |
4326 | return (sip_reject_contact_t *) |
4327 | msg_header_copy_as(home, sip_reject_contact_class, (msg_header_t const *)hdr); |
4328 | } |
4329 | #endif |
4330 | |
4331 | /**Make a @ref sip_reject_contact "Reject-Contact header" structure #sip_reject_contact_t. |
4332 | * |
4333 | * The function sip_reject_contact_make() makes a new |
4334 | * #sip_reject_contact_t header structure. It allocates a new |
4335 | * header structure, and decodes the string @a s as the |
4336 | * value of the structure. |
4337 | * |
4338 | * @param home memory home used to allocate new header structure. |
4339 | * @param s string to be decoded as value of the new header structure |
4340 | * |
4341 | * @return |
4342 | * A pointer to newly maked #sip_reject_contact_t header structure, or NULL upon an |
4343 | * error. |
4344 | * |
4345 | */ |
4346 | #if SU_HAVE_INLINE1 |
4347 | su_inlinestatic inline |
4348 | #endif |
4349 | sip_reject_contact_t *sip_reject_contact_make(su_home_t *home, char const *s) |
4350 | __attribute__((__malloc__)); |
4351 | |
4352 | #if SU_HAVE_INLINE1 |
4353 | su_inlinestatic inline sip_reject_contact_t *sip_reject_contact_make(su_home_t *home, char const *s) |
4354 | { |
4355 | return (sip_reject_contact_t *)sip_header_make(home, sip_reject_contact_class, s)((sip_header_t *)msg_header_make((home), (sip_reject_contact_class ), (s))); |
4356 | } |
4357 | #endif |
4358 | |
4359 | /**Make a @ref sip_reject_contact "Reject-Contact header" from formatting result. |
4360 | * |
4361 | * Make a new #sip_reject_contact_t object using formatting result as its value. |
4362 | * The function first prints the arguments according to the format @a fmt |
4363 | * specified. Then it allocates a new header structure, and parses the |
4364 | * formatting result to the structure #sip_reject_contact_t. |
4365 | * |
4366 | * @param home memory home used to allocate new header structure. |
4367 | * @param fmt string used as a printf()-style format |
4368 | * @param ... argument list for format |
4369 | * |
4370 | * @return |
4371 | * A pointer to newly |
4372 | * makes header structure, or NULL upon an error. |
4373 | * |
4374 | * @HIDE |
4375 | * |
4376 | */ |
4377 | #if SU_HAVE_INLINE1 |
4378 | su_inlinestatic inline |
4379 | #endif |
4380 | sip_reject_contact_t *sip_reject_contact_format(su_home_t *home, char const *fmt, ...) |
4381 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
4382 | |
4383 | #if SU_HAVE_INLINE1 |
4384 | su_inlinestatic inline sip_reject_contact_t *sip_reject_contact_format(su_home_t *home, char const *fmt, ...) |
4385 | { |
4386 | sip_header_t *h; |
4387 | va_list ap; |
4388 | |
4389 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
4390 | h = sip_header_vformat(home, sip_reject_contact_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_reject_contact_class ), (fmt), (ap))); |
4391 | va_end(ap)__builtin_va_end(ap); |
4392 | |
4393 | return (sip_reject_contact_t *)h; |
4394 | } |
4395 | #endif |
4396 | |
4397 | /** @} */ |
4398 | |
4399 | /**@addtogroup sip_expires |
4400 | * @{ |
4401 | */ |
4402 | |
4403 | /** Parse a SIP @ref sip_expires "Expires header". @internal */ |
4404 | SOFIAPUBFUN issize_t sip_expires_d(su_home_t *, msg_header_t *, |
4405 | char *s, isize_t slen); |
4406 | |
4407 | /** Print a SIP @ref sip_expires "Expires header". @internal */ |
4408 | SOFIAPUBFUN issize_t sip_expires_e(char b[], isize_t bsiz, |
4409 | msg_header_t const *h, int flags); |
4410 | |
4411 | /**Access a SIP @ref sip_expires "Expires header" |
4412 | * structure #sip_expires_t from #sip_t. |
4413 | * |
4414 | */ |
4415 | #define sip_expires(sip)((sip_expires_t *)msg_header_access((msg_pub_t*)(sip), sip_expires_class )) \ |
4416 | ((sip_expires_t *)msg_header_access((msg_pub_t*)(sip), sip_expires_class)) |
4417 | |
4418 | /**Initializer for structure #sip_expires_t. |
4419 | * |
4420 | * A static #sip_expires_t structure for |
4421 | * @ref sip_expires "Expires header" must be initialized with |
4422 | * the SIP_EXPIRES_INIT() macro. |
4423 | * For instance, |
4424 | * @code |
4425 | * |
4426 | * sip_expires_t sip_expires = SIP_EXPIRES_INIT; |
4427 | * |
4428 | * @endcode |
4429 | * @HI |
4430 | * |
4431 | */ |
4432 | #define SIP_EXPIRES_INIT(){{{ 0, 0, sip_expires_class }}} SIP_HDR_INIT(expires){{{ 0, 0, sip_expires_class }}} |
4433 | |
4434 | /**Initialize a structure #sip_expires_t. |
4435 | * |
4436 | * An #sip_expires_t structure for |
4437 | * @ref sip_expires "Expires header" can be initialized with the |
4438 | * sip_expires_init() function/macro. For instance, |
4439 | * @code |
4440 | * |
4441 | * sip_expires_t sip_expires; |
4442 | * |
4443 | * sip_expires_init(&sip_expires); |
4444 | * |
4445 | * @endcode |
4446 | * @HI |
4447 | * |
4448 | */ |
4449 | #if SU_HAVE_INLINE1 |
4450 | su_inlinestatic inline sip_expires_t *sip_expires_init(sip_expires_t x[1]) |
4451 | { |
4452 | return SIP_HEADER_INIT(x, sip_expires_class, sizeof(sip_expires_t))((void)memset((x), 0, (sizeof(sip_expires_t))), (void)(((sip_common_t *)(x))->h_class = (sip_expires_class)), (x)); |
4453 | } |
4454 | #else |
4455 | #define sip_expires_init(x) \ |
4456 | SIP_HEADER_INIT(x, sip_expires_class, sizeof(sip_expires_t))((void)memset((x), 0, (sizeof(sip_expires_t))), (void)(((sip_common_t *)(x))->h_class = (sip_expires_class)), (x)) |
4457 | #endif |
4458 | |
4459 | /**Test if header object is instance of #sip_expires_t. |
4460 | * |
4461 | * Check if the header class is an instance of |
4462 | * @ref sip_expires "Expires header" object and return true (nonzero), |
4463 | * otherwise return false (zero). |
4464 | * |
4465 | * @param header pointer to the header structure to be tested |
4466 | * |
4467 | * @retval 1 (true) if the @a header is an instance of header expires |
4468 | * @retval 0 (false) otherwise |
4469 | * |
4470 | */ |
4471 | #if SU_HAVE_INLINE1 |
4472 | su_inlinestatic inline int sip_is_expires(sip_header_t const *header) |
4473 | { |
4474 | return header && header->sh_classsh_common->h_class->hc_hash == sip_expires_hash; |
4475 | } |
4476 | #else |
4477 | int sip_is_expires(sip_header_t const *header); |
4478 | #endif |
4479 | |
4480 | #define sip_expires_p(h)sip_is_expires((h)) sip_is_expires((h)) |
4481 | |
4482 | |
4483 | /**Duplicate a list of @ref sip_expires "Expires header" header structures #sip_expires_t. |
4484 | * |
4485 | * Duplicate a header |
4486 | * structure @a hdr. If the header structure @a hdr |
4487 | * contains a reference (@c hdr->x_next) to a list of |
4488 | * headers, all the headers in the list are duplicated, too. |
4489 | * |
4490 | * @param home memory home used to allocate new structure |
4491 | * @param hdr header structure to be duplicated |
4492 | * |
4493 | * When duplicating, all parameter lists and non-constant |
4494 | * strings attached to the header are copied, too. The |
4495 | * function uses given memory @a home to allocate all the |
4496 | * memory areas used to copy the header. |
4497 | * |
4498 | * @par Example |
4499 | * @code |
4500 | * |
4501 | * expires = sip_expires_dup(home, sip->sip_expires); |
4502 | * |
4503 | * @endcode |
4504 | * |
4505 | * @return |
4506 | * A pointer to the |
4507 | * newly duplicated #sip_expires_t header structure, or NULL |
4508 | * upon an error. |
4509 | * |
4510 | */ |
4511 | #if SU_HAVE_INLINE1 |
4512 | su_inlinestatic inline |
4513 | #endif |
4514 | sip_expires_t *sip_expires_dup(su_home_t *home, sip_expires_t const *hdr) |
4515 | __attribute__((__malloc__)); |
4516 | |
4517 | #if SU_HAVE_INLINE1 |
4518 | su_inlinestatic inline |
4519 | sip_expires_t *sip_expires_dup(su_home_t *home, sip_expires_t const *hdr) |
4520 | { |
4521 | return (sip_expires_t *) |
4522 | msg_header_dup_as(home, sip_expires_class, (msg_header_t const *)hdr); |
4523 | } |
4524 | #endif |
4525 | |
4526 | /**Copy a list of @ref sip_expires "Expires header" header structures #sip_expires_t. |
4527 | * |
4528 | * The function sip_expires_copy() copies a header structure @a |
4529 | * hdr. If the header structure @a hdr contains a reference (@c |
4530 | * hdr->h_next) to a list of headers, all the headers in that |
4531 | * list are copied, too. The function uses given memory @a home |
4532 | * to allocate all the memory areas used to copy the list of header |
4533 | * structure @a hdr. |
4534 | * |
4535 | * @param home memory home used to allocate new structure |
4536 | * @param hdr pointer to the header structure to be copied |
4537 | * |
4538 | * When copying, only the header structure and parameter lists attached to |
4539 | * it are duplicated. The new header structure retains all the references to |
4540 | * the strings within the old @a hdr header, including the encoding of the |
4541 | * old header, if present. |
4542 | * |
4543 | * @par Example |
4544 | * @code |
4545 | * |
4546 | * expires = sip_expires_copy(home, sip->sip_expires); |
4547 | * |
4548 | * @endcode |
4549 | * |
4550 | * @return |
4551 | * A pointer to newly copied header structure, or NULL upon an error. |
4552 | * |
4553 | */ |
4554 | #if SU_HAVE_INLINE1 |
4555 | su_inlinestatic inline |
4556 | #endif |
4557 | sip_expires_t *sip_expires_copy(su_home_t *home, sip_expires_t const *hdr) |
4558 | __attribute__((__malloc__)); |
4559 | |
4560 | #if SU_HAVE_INLINE1 |
4561 | su_inlinestatic inline |
4562 | sip_expires_t *sip_expires_copy(su_home_t *home, sip_expires_t const *hdr) |
4563 | { |
4564 | return (sip_expires_t *) |
4565 | msg_header_copy_as(home, sip_expires_class, (msg_header_t const *)hdr); |
4566 | } |
4567 | #endif |
4568 | |
4569 | /**Make a @ref sip_expires "Expires header" structure #sip_expires_t. |
4570 | * |
4571 | * The function sip_expires_make() makes a new |
4572 | * #sip_expires_t header structure. It allocates a new |
4573 | * header structure, and decodes the string @a s as the |
4574 | * value of the structure. |
4575 | * |
4576 | * @param home memory home used to allocate new header structure. |
4577 | * @param s string to be decoded as value of the new header structure |
4578 | * |
4579 | * @return |
4580 | * A pointer to newly maked #sip_expires_t header structure, or NULL upon an |
4581 | * error. |
4582 | * |
4583 | */ |
4584 | #if SU_HAVE_INLINE1 |
4585 | su_inlinestatic inline |
4586 | #endif |
4587 | sip_expires_t *sip_expires_make(su_home_t *home, char const *s) |
4588 | __attribute__((__malloc__)); |
4589 | |
4590 | #if SU_HAVE_INLINE1 |
4591 | su_inlinestatic inline sip_expires_t *sip_expires_make(su_home_t *home, char const *s) |
4592 | { |
4593 | return (sip_expires_t *)sip_header_make(home, sip_expires_class, s)((sip_header_t *)msg_header_make((home), (sip_expires_class), (s))); |
4594 | } |
4595 | #endif |
4596 | |
4597 | /**Make a @ref sip_expires "Expires header" from formatting result. |
4598 | * |
4599 | * Make a new #sip_expires_t object using formatting result as its value. |
4600 | * The function first prints the arguments according to the format @a fmt |
4601 | * specified. Then it allocates a new header structure, and parses the |
4602 | * formatting result to the structure #sip_expires_t. |
4603 | * |
4604 | * @param home memory home used to allocate new header structure. |
4605 | * @param fmt string used as a printf()-style format |
4606 | * @param ... argument list for format |
4607 | * |
4608 | * @return |
4609 | * A pointer to newly |
4610 | * makes header structure, or NULL upon an error. |
4611 | * |
4612 | * @HIDE |
4613 | * |
4614 | */ |
4615 | #if SU_HAVE_INLINE1 |
4616 | su_inlinestatic inline |
4617 | #endif |
4618 | sip_expires_t *sip_expires_format(su_home_t *home, char const *fmt, ...) |
4619 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
4620 | |
4621 | #if SU_HAVE_INLINE1 |
4622 | su_inlinestatic inline sip_expires_t *sip_expires_format(su_home_t *home, char const *fmt, ...) |
4623 | { |
4624 | sip_header_t *h; |
4625 | va_list ap; |
4626 | |
4627 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
4628 | h = sip_header_vformat(home, sip_expires_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_expires_class ), (fmt), (ap))); |
4629 | va_end(ap)__builtin_va_end(ap); |
4630 | |
4631 | return (sip_expires_t *)h; |
4632 | } |
4633 | #endif |
4634 | |
4635 | /** @} */ |
4636 | |
4637 | /**@addtogroup sip_date |
4638 | * @{ |
4639 | */ |
4640 | |
4641 | /** Parse a SIP @ref sip_date "Date header". @internal */ |
4642 | SOFIAPUBFUN issize_t sip_date_d(su_home_t *, msg_header_t *, |
4643 | char *s, isize_t slen); |
4644 | |
4645 | /** Print a SIP @ref sip_date "Date header". @internal */ |
4646 | SOFIAPUBFUN issize_t sip_date_e(char b[], isize_t bsiz, |
4647 | msg_header_t const *h, int flags); |
4648 | |
4649 | /**Access a SIP @ref sip_date "Date header" |
4650 | * structure #sip_date_t from #sip_t. |
4651 | * |
4652 | */ |
4653 | #define sip_date(sip)((sip_date_t *)msg_header_access((msg_pub_t*)(sip), sip_date_class )) \ |
4654 | ((sip_date_t *)msg_header_access((msg_pub_t*)(sip), sip_date_class)) |
4655 | |
4656 | /**Initializer for structure #sip_date_t. |
4657 | * |
4658 | * A static #sip_date_t structure for |
4659 | * @ref sip_date "Date header" must be initialized with |
4660 | * the SIP_DATE_INIT() macro. |
4661 | * For instance, |
4662 | * @code |
4663 | * |
4664 | * sip_date_t sip_date = SIP_DATE_INIT; |
4665 | * |
4666 | * @endcode |
4667 | * @HI |
4668 | * |
4669 | */ |
4670 | #define SIP_DATE_INIT(){{{ 0, 0, sip_date_class }}} SIP_HDR_INIT(date){{{ 0, 0, sip_date_class }}} |
4671 | |
4672 | /**Initialize a structure #sip_date_t. |
4673 | * |
4674 | * An #sip_date_t structure for |
4675 | * @ref sip_date "Date header" can be initialized with the |
4676 | * sip_date_init() function/macro. For instance, |
4677 | * @code |
4678 | * |
4679 | * sip_date_t sip_date; |
4680 | * |
4681 | * sip_date_init(&sip_date); |
4682 | * |
4683 | * @endcode |
4684 | * @HI |
4685 | * |
4686 | */ |
4687 | #if SU_HAVE_INLINE1 |
4688 | su_inlinestatic inline sip_date_t *sip_date_init(sip_date_t x[1]) |
4689 | { |
4690 | return SIP_HEADER_INIT(x, sip_date_class, sizeof(sip_date_t))((void)memset((x), 0, (sizeof(sip_date_t))), (void)(((sip_common_t *)(x))->h_class = (sip_date_class)), (x)); |
4691 | } |
4692 | #else |
4693 | #define sip_date_init(x) \ |
4694 | SIP_HEADER_INIT(x, sip_date_class, sizeof(sip_date_t))((void)memset((x), 0, (sizeof(sip_date_t))), (void)(((sip_common_t *)(x))->h_class = (sip_date_class)), (x)) |
4695 | #endif |
4696 | |
4697 | /**Test if header object is instance of #sip_date_t. |
4698 | * |
4699 | * Check if the header class is an instance of |
4700 | * @ref sip_date "Date header" object and return true (nonzero), |
4701 | * otherwise return false (zero). |
4702 | * |
4703 | * @param header pointer to the header structure to be tested |
4704 | * |
4705 | * @retval 1 (true) if the @a header is an instance of header date |
4706 | * @retval 0 (false) otherwise |
4707 | * |
4708 | */ |
4709 | #if SU_HAVE_INLINE1 |
4710 | su_inlinestatic inline int sip_is_date(sip_header_t const *header) |
4711 | { |
4712 | return header && header->sh_classsh_common->h_class->hc_hash == sip_date_hash; |
4713 | } |
4714 | #else |
4715 | int sip_is_date(sip_header_t const *header); |
4716 | #endif |
4717 | |
4718 | #define sip_date_p(h)sip_is_date((h)) sip_is_date((h)) |
4719 | |
4720 | |
4721 | /**Duplicate a list of @ref sip_date "Date header" header structures #sip_date_t. |
4722 | * |
4723 | * Duplicate a header |
4724 | * structure @a hdr. If the header structure @a hdr |
4725 | * contains a reference (@c hdr->x_next) to a list of |
4726 | * headers, all the headers in the list are duplicated, too. |
4727 | * |
4728 | * @param home memory home used to allocate new structure |
4729 | * @param hdr header structure to be duplicated |
4730 | * |
4731 | * When duplicating, all parameter lists and non-constant |
4732 | * strings attached to the header are copied, too. The |
4733 | * function uses given memory @a home to allocate all the |
4734 | * memory areas used to copy the header. |
4735 | * |
4736 | * @par Example |
4737 | * @code |
4738 | * |
4739 | * date = sip_date_dup(home, sip->sip_date); |
4740 | * |
4741 | * @endcode |
4742 | * |
4743 | * @return |
4744 | * A pointer to the |
4745 | * newly duplicated #sip_date_t header structure, or NULL |
4746 | * upon an error. |
4747 | * |
4748 | */ |
4749 | #if SU_HAVE_INLINE1 |
4750 | su_inlinestatic inline |
4751 | #endif |
4752 | sip_date_t *sip_date_dup(su_home_t *home, sip_date_t const *hdr) |
4753 | __attribute__((__malloc__)); |
4754 | |
4755 | #if SU_HAVE_INLINE1 |
4756 | su_inlinestatic inline |
4757 | sip_date_t *sip_date_dup(su_home_t *home, sip_date_t const *hdr) |
4758 | { |
4759 | return (sip_date_t *) |
4760 | msg_header_dup_as(home, sip_date_class, (msg_header_t const *)hdr); |
4761 | } |
4762 | #endif |
4763 | |
4764 | /**Copy a list of @ref sip_date "Date header" header structures #sip_date_t. |
4765 | * |
4766 | * The function sip_date_copy() copies a header structure @a |
4767 | * hdr. If the header structure @a hdr contains a reference (@c |
4768 | * hdr->h_next) to a list of headers, all the headers in that |
4769 | * list are copied, too. The function uses given memory @a home |
4770 | * to allocate all the memory areas used to copy the list of header |
4771 | * structure @a hdr. |
4772 | * |
4773 | * @param home memory home used to allocate new structure |
4774 | * @param hdr pointer to the header structure to be copied |
4775 | * |
4776 | * When copying, only the header structure and parameter lists attached to |
4777 | * it are duplicated. The new header structure retains all the references to |
4778 | * the strings within the old @a hdr header, including the encoding of the |
4779 | * old header, if present. |
4780 | * |
4781 | * @par Example |
4782 | * @code |
4783 | * |
4784 | * date = sip_date_copy(home, sip->sip_date); |
4785 | * |
4786 | * @endcode |
4787 | * |
4788 | * @return |
4789 | * A pointer to newly copied header structure, or NULL upon an error. |
4790 | * |
4791 | */ |
4792 | #if SU_HAVE_INLINE1 |
4793 | su_inlinestatic inline |
4794 | #endif |
4795 | sip_date_t *sip_date_copy(su_home_t *home, sip_date_t const *hdr) |
4796 | __attribute__((__malloc__)); |
4797 | |
4798 | #if SU_HAVE_INLINE1 |
4799 | su_inlinestatic inline |
4800 | sip_date_t *sip_date_copy(su_home_t *home, sip_date_t const *hdr) |
4801 | { |
4802 | return (sip_date_t *) |
4803 | msg_header_copy_as(home, sip_date_class, (msg_header_t const *)hdr); |
4804 | } |
4805 | #endif |
4806 | |
4807 | /**Make a @ref sip_date "Date header" structure #sip_date_t. |
4808 | * |
4809 | * The function sip_date_make() makes a new |
4810 | * #sip_date_t header structure. It allocates a new |
4811 | * header structure, and decodes the string @a s as the |
4812 | * value of the structure. |
4813 | * |
4814 | * @param home memory home used to allocate new header structure. |
4815 | * @param s string to be decoded as value of the new header structure |
4816 | * |
4817 | * @return |
4818 | * A pointer to newly maked #sip_date_t header structure, or NULL upon an |
4819 | * error. |
4820 | * |
4821 | */ |
4822 | #if SU_HAVE_INLINE1 |
4823 | su_inlinestatic inline |
4824 | #endif |
4825 | sip_date_t *sip_date_make(su_home_t *home, char const *s) |
4826 | __attribute__((__malloc__)); |
4827 | |
4828 | #if SU_HAVE_INLINE1 |
4829 | su_inlinestatic inline sip_date_t *sip_date_make(su_home_t *home, char const *s) |
4830 | { |
4831 | return (sip_date_t *)sip_header_make(home, sip_date_class, s)((sip_header_t *)msg_header_make((home), (sip_date_class), (s ))); |
4832 | } |
4833 | #endif |
4834 | |
4835 | /**Make a @ref sip_date "Date header" from formatting result. |
4836 | * |
4837 | * Make a new #sip_date_t object using formatting result as its value. |
4838 | * The function first prints the arguments according to the format @a fmt |
4839 | * specified. Then it allocates a new header structure, and parses the |
4840 | * formatting result to the structure #sip_date_t. |
4841 | * |
4842 | * @param home memory home used to allocate new header structure. |
4843 | * @param fmt string used as a printf()-style format |
4844 | * @param ... argument list for format |
4845 | * |
4846 | * @return |
4847 | * A pointer to newly |
4848 | * makes header structure, or NULL upon an error. |
4849 | * |
4850 | * @HIDE |
4851 | * |
4852 | */ |
4853 | #if SU_HAVE_INLINE1 |
4854 | su_inlinestatic inline |
4855 | #endif |
4856 | sip_date_t *sip_date_format(su_home_t *home, char const *fmt, ...) |
4857 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
4858 | |
4859 | #if SU_HAVE_INLINE1 |
4860 | su_inlinestatic inline sip_date_t *sip_date_format(su_home_t *home, char const *fmt, ...) |
4861 | { |
4862 | sip_header_t *h; |
4863 | va_list ap; |
4864 | |
4865 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
4866 | h = sip_header_vformat(home, sip_date_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_date_class), (fmt), (ap))); |
4867 | va_end(ap)__builtin_va_end(ap); |
4868 | |
4869 | return (sip_date_t *)h; |
4870 | } |
4871 | #endif |
4872 | |
4873 | /** @} */ |
4874 | |
4875 | /**@addtogroup sip_retry_after |
4876 | * @{ |
4877 | */ |
4878 | |
4879 | /** Parse a SIP @ref sip_retry_after "Retry-After header". @internal */ |
4880 | SOFIAPUBFUN issize_t sip_retry_after_d(su_home_t *, msg_header_t *, |
4881 | char *s, isize_t slen); |
4882 | |
4883 | /** Print a SIP @ref sip_retry_after "Retry-After header". @internal */ |
4884 | SOFIAPUBFUN issize_t sip_retry_after_e(char b[], isize_t bsiz, |
4885 | msg_header_t const *h, int flags); |
4886 | |
4887 | /**Access a SIP @ref sip_retry_after "Retry-After header" |
4888 | * structure #sip_retry_after_t from #sip_t. |
4889 | * |
4890 | */ |
4891 | #define sip_retry_after(sip)((sip_retry_after_t *)msg_header_access((msg_pub_t*)(sip), sip_retry_after_class )) \ |
4892 | ((sip_retry_after_t *)msg_header_access((msg_pub_t*)(sip), sip_retry_after_class)) |
4893 | |
4894 | /**Initializer for structure #sip_retry_after_t. |
4895 | * |
4896 | * A static #sip_retry_after_t structure for |
4897 | * @ref sip_retry_after "Retry-After header" must be initialized with |
4898 | * the SIP_RETRY_AFTER_INIT() macro. |
4899 | * For instance, |
4900 | * @code |
4901 | * |
4902 | * sip_retry_after_t sip_retry_after = SIP_RETRY_AFTER_INIT; |
4903 | * |
4904 | * @endcode |
4905 | * @HI |
4906 | * |
4907 | */ |
4908 | #define SIP_RETRY_AFTER_INIT(){{{ 0, 0, sip_retry_after_class }}} SIP_HDR_INIT(retry_after){{{ 0, 0, sip_retry_after_class }}} |
4909 | |
4910 | /**Initialize a structure #sip_retry_after_t. |
4911 | * |
4912 | * An #sip_retry_after_t structure for |
4913 | * @ref sip_retry_after "Retry-After header" can be initialized with the |
4914 | * sip_retry_after_init() function/macro. For instance, |
4915 | * @code |
4916 | * |
4917 | * sip_retry_after_t sip_retry_after; |
4918 | * |
4919 | * sip_retry_after_init(&sip_retry_after); |
4920 | * |
4921 | * @endcode |
4922 | * @HI |
4923 | * |
4924 | */ |
4925 | #if SU_HAVE_INLINE1 |
4926 | su_inlinestatic inline sip_retry_after_t *sip_retry_after_init(sip_retry_after_t x[1]) |
4927 | { |
4928 | return SIP_HEADER_INIT(x, sip_retry_after_class, sizeof(sip_retry_after_t))((void)memset((x), 0, (sizeof(sip_retry_after_t))), (void)((( sip_common_t *)(x))->h_class = (sip_retry_after_class)), ( x)); |
4929 | } |
4930 | #else |
4931 | #define sip_retry_after_init(x) \ |
4932 | SIP_HEADER_INIT(x, sip_retry_after_class, sizeof(sip_retry_after_t))((void)memset((x), 0, (sizeof(sip_retry_after_t))), (void)((( sip_common_t *)(x))->h_class = (sip_retry_after_class)), ( x)) |
4933 | #endif |
4934 | |
4935 | /**Test if header object is instance of #sip_retry_after_t. |
4936 | * |
4937 | * Check if the header class is an instance of |
4938 | * @ref sip_retry_after "Retry-After header" object and return true (nonzero), |
4939 | * otherwise return false (zero). |
4940 | * |
4941 | * @param header pointer to the header structure to be tested |
4942 | * |
4943 | * @retval 1 (true) if the @a header is an instance of header retry_after |
4944 | * @retval 0 (false) otherwise |
4945 | * |
4946 | */ |
4947 | #if SU_HAVE_INLINE1 |
4948 | su_inlinestatic inline int sip_is_retry_after(sip_header_t const *header) |
4949 | { |
4950 | return header && header->sh_classsh_common->h_class->hc_hash == sip_retry_after_hash; |
4951 | } |
4952 | #else |
4953 | int sip_is_retry_after(sip_header_t const *header); |
4954 | #endif |
4955 | |
4956 | #define sip_retry_after_p(h)sip_is_retry_after((h)) sip_is_retry_after((h)) |
4957 | |
4958 | |
4959 | /**Duplicate a list of @ref sip_retry_after "Retry-After header" header structures #sip_retry_after_t. |
4960 | * |
4961 | * Duplicate a header |
4962 | * structure @a hdr. If the header structure @a hdr |
4963 | * contains a reference (@c hdr->x_next) to a list of |
4964 | * headers, all the headers in the list are duplicated, too. |
4965 | * |
4966 | * @param home memory home used to allocate new structure |
4967 | * @param hdr header structure to be duplicated |
4968 | * |
4969 | * When duplicating, all parameter lists and non-constant |
4970 | * strings attached to the header are copied, too. The |
4971 | * function uses given memory @a home to allocate all the |
4972 | * memory areas used to copy the header. |
4973 | * |
4974 | * @par Example |
4975 | * @code |
4976 | * |
4977 | * retry_after = sip_retry_after_dup(home, sip->sip_retry_after); |
4978 | * |
4979 | * @endcode |
4980 | * |
4981 | * @return |
4982 | * A pointer to the |
4983 | * newly duplicated #sip_retry_after_t header structure, or NULL |
4984 | * upon an error. |
4985 | * |
4986 | */ |
4987 | #if SU_HAVE_INLINE1 |
4988 | su_inlinestatic inline |
4989 | #endif |
4990 | sip_retry_after_t *sip_retry_after_dup(su_home_t *home, sip_retry_after_t const *hdr) |
4991 | __attribute__((__malloc__)); |
4992 | |
4993 | #if SU_HAVE_INLINE1 |
4994 | su_inlinestatic inline |
4995 | sip_retry_after_t *sip_retry_after_dup(su_home_t *home, sip_retry_after_t const *hdr) |
4996 | { |
4997 | return (sip_retry_after_t *) |
4998 | msg_header_dup_as(home, sip_retry_after_class, (msg_header_t const *)hdr); |
4999 | } |
5000 | #endif |
5001 | |
5002 | /**Copy a list of @ref sip_retry_after "Retry-After header" header structures #sip_retry_after_t. |
5003 | * |
5004 | * The function sip_retry_after_copy() copies a header structure @a |
5005 | * hdr. If the header structure @a hdr contains a reference (@c |
5006 | * hdr->h_next) to a list of headers, all the headers in that |
5007 | * list are copied, too. The function uses given memory @a home |
5008 | * to allocate all the memory areas used to copy the list of header |
5009 | * structure @a hdr. |
5010 | * |
5011 | * @param home memory home used to allocate new structure |
5012 | * @param hdr pointer to the header structure to be copied |
5013 | * |
5014 | * When copying, only the header structure and parameter lists attached to |
5015 | * it are duplicated. The new header structure retains all the references to |
5016 | * the strings within the old @a hdr header, including the encoding of the |
5017 | * old header, if present. |
5018 | * |
5019 | * @par Example |
5020 | * @code |
5021 | * |
5022 | * retry_after = sip_retry_after_copy(home, sip->sip_retry_after); |
5023 | * |
5024 | * @endcode |
5025 | * |
5026 | * @return |
5027 | * A pointer to newly copied header structure, or NULL upon an error. |
5028 | * |
5029 | */ |
5030 | #if SU_HAVE_INLINE1 |
5031 | su_inlinestatic inline |
5032 | #endif |
5033 | sip_retry_after_t *sip_retry_after_copy(su_home_t *home, sip_retry_after_t const *hdr) |
5034 | __attribute__((__malloc__)); |
5035 | |
5036 | #if SU_HAVE_INLINE1 |
5037 | su_inlinestatic inline |
5038 | sip_retry_after_t *sip_retry_after_copy(su_home_t *home, sip_retry_after_t const *hdr) |
5039 | { |
5040 | return (sip_retry_after_t *) |
5041 | msg_header_copy_as(home, sip_retry_after_class, (msg_header_t const *)hdr); |
5042 | } |
5043 | #endif |
5044 | |
5045 | /**Make a @ref sip_retry_after "Retry-After header" structure #sip_retry_after_t. |
5046 | * |
5047 | * The function sip_retry_after_make() makes a new |
5048 | * #sip_retry_after_t header structure. It allocates a new |
5049 | * header structure, and decodes the string @a s as the |
5050 | * value of the structure. |
5051 | * |
5052 | * @param home memory home used to allocate new header structure. |
5053 | * @param s string to be decoded as value of the new header structure |
5054 | * |
5055 | * @return |
5056 | * A pointer to newly maked #sip_retry_after_t header structure, or NULL upon an |
5057 | * error. |
5058 | * |
5059 | */ |
5060 | #if SU_HAVE_INLINE1 |
5061 | su_inlinestatic inline |
5062 | #endif |
5063 | sip_retry_after_t *sip_retry_after_make(su_home_t *home, char const *s) |
5064 | __attribute__((__malloc__)); |
5065 | |
5066 | #if SU_HAVE_INLINE1 |
5067 | su_inlinestatic inline sip_retry_after_t *sip_retry_after_make(su_home_t *home, char const *s) |
5068 | { |
5069 | return (sip_retry_after_t *)sip_header_make(home, sip_retry_after_class, s)((sip_header_t *)msg_header_make((home), (sip_retry_after_class ), (s))); |
5070 | } |
5071 | #endif |
5072 | |
5073 | /**Make a @ref sip_retry_after "Retry-After header" from formatting result. |
5074 | * |
5075 | * Make a new #sip_retry_after_t object using formatting result as its value. |
5076 | * The function first prints the arguments according to the format @a fmt |
5077 | * specified. Then it allocates a new header structure, and parses the |
5078 | * formatting result to the structure #sip_retry_after_t. |
5079 | * |
5080 | * @param home memory home used to allocate new header structure. |
5081 | * @param fmt string used as a printf()-style format |
5082 | * @param ... argument list for format |
5083 | * |
5084 | * @return |
5085 | * A pointer to newly |
5086 | * makes header structure, or NULL upon an error. |
5087 | * |
5088 | * @HIDE |
5089 | * |
5090 | */ |
5091 | #if SU_HAVE_INLINE1 |
5092 | su_inlinestatic inline |
5093 | #endif |
5094 | sip_retry_after_t *sip_retry_after_format(su_home_t *home, char const *fmt, ...) |
5095 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
5096 | |
5097 | #if SU_HAVE_INLINE1 |
5098 | su_inlinestatic inline sip_retry_after_t *sip_retry_after_format(su_home_t *home, char const *fmt, ...) |
5099 | { |
5100 | sip_header_t *h; |
5101 | va_list ap; |
5102 | |
5103 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
5104 | h = sip_header_vformat(home, sip_retry_after_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_retry_after_class ), (fmt), (ap))); |
5105 | va_end(ap)__builtin_va_end(ap); |
5106 | |
5107 | return (sip_retry_after_t *)h; |
5108 | } |
5109 | #endif |
5110 | |
5111 | /** @} */ |
5112 | |
5113 | /**@addtogroup sip_timestamp |
5114 | * @{ |
5115 | */ |
5116 | |
5117 | /** Parse a SIP @ref sip_timestamp "Timestamp header". @internal */ |
5118 | SOFIAPUBFUN issize_t sip_timestamp_d(su_home_t *, msg_header_t *, |
5119 | char *s, isize_t slen); |
5120 | |
5121 | /** Print a SIP @ref sip_timestamp "Timestamp header". @internal */ |
5122 | SOFIAPUBFUN issize_t sip_timestamp_e(char b[], isize_t bsiz, |
5123 | msg_header_t const *h, int flags); |
5124 | |
5125 | /**Access a SIP @ref sip_timestamp "Timestamp header" |
5126 | * structure #sip_timestamp_t from #sip_t. |
5127 | * |
5128 | */ |
5129 | #define sip_timestamp(sip)((sip_timestamp_t *)msg_header_access((msg_pub_t*)(sip), sip_timestamp_class )) \ |
5130 | ((sip_timestamp_t *)msg_header_access((msg_pub_t*)(sip), sip_timestamp_class)) |
5131 | |
5132 | /**Initializer for structure #sip_timestamp_t. |
5133 | * |
5134 | * A static #sip_timestamp_t structure for |
5135 | * @ref sip_timestamp "Timestamp header" must be initialized with |
5136 | * the SIP_TIMESTAMP_INIT() macro. |
5137 | * For instance, |
5138 | * @code |
5139 | * |
5140 | * sip_timestamp_t sip_timestamp = SIP_TIMESTAMP_INIT; |
5141 | * |
5142 | * @endcode |
5143 | * @HI |
5144 | * |
5145 | */ |
5146 | #define SIP_TIMESTAMP_INIT(){{{ 0, 0, sip_timestamp_class }}} SIP_HDR_INIT(timestamp){{{ 0, 0, sip_timestamp_class }}} |
5147 | |
5148 | /**Initialize a structure #sip_timestamp_t. |
5149 | * |
5150 | * An #sip_timestamp_t structure for |
5151 | * @ref sip_timestamp "Timestamp header" can be initialized with the |
5152 | * sip_timestamp_init() function/macro. For instance, |
5153 | * @code |
5154 | * |
5155 | * sip_timestamp_t sip_timestamp; |
5156 | * |
5157 | * sip_timestamp_init(&sip_timestamp); |
5158 | * |
5159 | * @endcode |
5160 | * @HI |
5161 | * |
5162 | */ |
5163 | #if SU_HAVE_INLINE1 |
5164 | su_inlinestatic inline sip_timestamp_t *sip_timestamp_init(sip_timestamp_t x[1]) |
5165 | { |
5166 | return SIP_HEADER_INIT(x, sip_timestamp_class, sizeof(sip_timestamp_t))((void)memset((x), 0, (sizeof(sip_timestamp_t))), (void)(((sip_common_t *)(x))->h_class = (sip_timestamp_class)), (x)); |
5167 | } |
5168 | #else |
5169 | #define sip_timestamp_init(x) \ |
5170 | SIP_HEADER_INIT(x, sip_timestamp_class, sizeof(sip_timestamp_t))((void)memset((x), 0, (sizeof(sip_timestamp_t))), (void)(((sip_common_t *)(x))->h_class = (sip_timestamp_class)), (x)) |
5171 | #endif |
5172 | |
5173 | /**Test if header object is instance of #sip_timestamp_t. |
5174 | * |
5175 | * Check if the header class is an instance of |
5176 | * @ref sip_timestamp "Timestamp header" object and return true (nonzero), |
5177 | * otherwise return false (zero). |
5178 | * |
5179 | * @param header pointer to the header structure to be tested |
5180 | * |
5181 | * @retval 1 (true) if the @a header is an instance of header timestamp |
5182 | * @retval 0 (false) otherwise |
5183 | * |
5184 | */ |
5185 | #if SU_HAVE_INLINE1 |
5186 | su_inlinestatic inline int sip_is_timestamp(sip_header_t const *header) |
5187 | { |
5188 | return header && header->sh_classsh_common->h_class->hc_hash == sip_timestamp_hash; |
5189 | } |
5190 | #else |
5191 | int sip_is_timestamp(sip_header_t const *header); |
5192 | #endif |
5193 | |
5194 | #define sip_timestamp_p(h)sip_is_timestamp((h)) sip_is_timestamp((h)) |
5195 | |
5196 | |
5197 | /**Duplicate a list of @ref sip_timestamp "Timestamp header" header structures #sip_timestamp_t. |
5198 | * |
5199 | * Duplicate a header |
5200 | * structure @a hdr. If the header structure @a hdr |
5201 | * contains a reference (@c hdr->x_next) to a list of |
5202 | * headers, all the headers in the list are duplicated, too. |
5203 | * |
5204 | * @param home memory home used to allocate new structure |
5205 | * @param hdr header structure to be duplicated |
5206 | * |
5207 | * When duplicating, all parameter lists and non-constant |
5208 | * strings attached to the header are copied, too. The |
5209 | * function uses given memory @a home to allocate all the |
5210 | * memory areas used to copy the header. |
5211 | * |
5212 | * @par Example |
5213 | * @code |
5214 | * |
5215 | * timestamp = sip_timestamp_dup(home, sip->sip_timestamp); |
5216 | * |
5217 | * @endcode |
5218 | * |
5219 | * @return |
5220 | * A pointer to the |
5221 | * newly duplicated #sip_timestamp_t header structure, or NULL |
5222 | * upon an error. |
5223 | * |
5224 | */ |
5225 | #if SU_HAVE_INLINE1 |
5226 | su_inlinestatic inline |
5227 | #endif |
5228 | sip_timestamp_t *sip_timestamp_dup(su_home_t *home, sip_timestamp_t const *hdr) |
5229 | __attribute__((__malloc__)); |
5230 | |
5231 | #if SU_HAVE_INLINE1 |
5232 | su_inlinestatic inline |
5233 | sip_timestamp_t *sip_timestamp_dup(su_home_t *home, sip_timestamp_t const *hdr) |
5234 | { |
5235 | return (sip_timestamp_t *) |
5236 | msg_header_dup_as(home, sip_timestamp_class, (msg_header_t const *)hdr); |
5237 | } |
5238 | #endif |
5239 | |
5240 | /**Copy a list of @ref sip_timestamp "Timestamp header" header structures #sip_timestamp_t. |
5241 | * |
5242 | * The function sip_timestamp_copy() copies a header structure @a |
5243 | * hdr. If the header structure @a hdr contains a reference (@c |
5244 | * hdr->h_next) to a list of headers, all the headers in that |
5245 | * list are copied, too. The function uses given memory @a home |
5246 | * to allocate all the memory areas used to copy the list of header |
5247 | * structure @a hdr. |
5248 | * |
5249 | * @param home memory home used to allocate new structure |
5250 | * @param hdr pointer to the header structure to be copied |
5251 | * |
5252 | * When copying, only the header structure and parameter lists attached to |
5253 | * it are duplicated. The new header structure retains all the references to |
5254 | * the strings within the old @a hdr header, including the encoding of the |
5255 | * old header, if present. |
5256 | * |
5257 | * @par Example |
5258 | * @code |
5259 | * |
5260 | * timestamp = sip_timestamp_copy(home, sip->sip_timestamp); |
5261 | * |
5262 | * @endcode |
5263 | * |
5264 | * @return |
5265 | * A pointer to newly copied header structure, or NULL upon an error. |
5266 | * |
5267 | */ |
5268 | #if SU_HAVE_INLINE1 |
5269 | su_inlinestatic inline |
5270 | #endif |
5271 | sip_timestamp_t *sip_timestamp_copy(su_home_t *home, sip_timestamp_t const *hdr) |
5272 | __attribute__((__malloc__)); |
5273 | |
5274 | #if SU_HAVE_INLINE1 |
5275 | su_inlinestatic inline |
5276 | sip_timestamp_t *sip_timestamp_copy(su_home_t *home, sip_timestamp_t const *hdr) |
5277 | { |
5278 | return (sip_timestamp_t *) |
5279 | msg_header_copy_as(home, sip_timestamp_class, (msg_header_t const *)hdr); |
5280 | } |
5281 | #endif |
5282 | |
5283 | /**Make a @ref sip_timestamp "Timestamp header" structure #sip_timestamp_t. |
5284 | * |
5285 | * The function sip_timestamp_make() makes a new |
5286 | * #sip_timestamp_t header structure. It allocates a new |
5287 | * header structure, and decodes the string @a s as the |
5288 | * value of the structure. |
5289 | * |
5290 | * @param home memory home used to allocate new header structure. |
5291 | * @param s string to be decoded as value of the new header structure |
5292 | * |
5293 | * @return |
5294 | * A pointer to newly maked #sip_timestamp_t header structure, or NULL upon an |
5295 | * error. |
5296 | * |
5297 | */ |
5298 | #if SU_HAVE_INLINE1 |
5299 | su_inlinestatic inline |
5300 | #endif |
5301 | sip_timestamp_t *sip_timestamp_make(su_home_t *home, char const *s) |
5302 | __attribute__((__malloc__)); |
5303 | |
5304 | #if SU_HAVE_INLINE1 |
5305 | su_inlinestatic inline sip_timestamp_t *sip_timestamp_make(su_home_t *home, char const *s) |
5306 | { |
5307 | return (sip_timestamp_t *)sip_header_make(home, sip_timestamp_class, s)((sip_header_t *)msg_header_make((home), (sip_timestamp_class ), (s))); |
5308 | } |
5309 | #endif |
5310 | |
5311 | /**Make a @ref sip_timestamp "Timestamp header" from formatting result. |
5312 | * |
5313 | * Make a new #sip_timestamp_t object using formatting result as its value. |
5314 | * The function first prints the arguments according to the format @a fmt |
5315 | * specified. Then it allocates a new header structure, and parses the |
5316 | * formatting result to the structure #sip_timestamp_t. |
5317 | * |
5318 | * @param home memory home used to allocate new header structure. |
5319 | * @param fmt string used as a printf()-style format |
5320 | * @param ... argument list for format |
5321 | * |
5322 | * @return |
5323 | * A pointer to newly |
5324 | * makes header structure, or NULL upon an error. |
5325 | * |
5326 | * @HIDE |
5327 | * |
5328 | */ |
5329 | #if SU_HAVE_INLINE1 |
5330 | su_inlinestatic inline |
5331 | #endif |
5332 | sip_timestamp_t *sip_timestamp_format(su_home_t *home, char const *fmt, ...) |
5333 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
5334 | |
5335 | #if SU_HAVE_INLINE1 |
5336 | su_inlinestatic inline sip_timestamp_t *sip_timestamp_format(su_home_t *home, char const *fmt, ...) |
5337 | { |
5338 | sip_header_t *h; |
5339 | va_list ap; |
5340 | |
5341 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
5342 | h = sip_header_vformat(home, sip_timestamp_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_timestamp_class ), (fmt), (ap))); |
5343 | va_end(ap)__builtin_va_end(ap); |
5344 | |
5345 | return (sip_timestamp_t *)h; |
5346 | } |
5347 | #endif |
5348 | |
5349 | /** @} */ |
5350 | |
5351 | /**@addtogroup sip_min_expires |
5352 | * @{ |
5353 | */ |
5354 | |
5355 | /** Parse a SIP @ref sip_min_expires "Min-Expires header". @internal */ |
5356 | SOFIAPUBFUN issize_t sip_min_expires_d(su_home_t *, msg_header_t *, |
5357 | char *s, isize_t slen); |
5358 | |
5359 | /** Print a SIP @ref sip_min_expires "Min-Expires header". @internal */ |
5360 | SOFIAPUBFUN issize_t sip_min_expires_e(char b[], isize_t bsiz, |
5361 | msg_header_t const *h, int flags); |
5362 | |
5363 | /**Access a SIP @ref sip_min_expires "Min-Expires header" |
5364 | * structure #sip_min_expires_t from #sip_t. |
5365 | * |
5366 | */ |
5367 | #define sip_min_expires(sip)((sip_min_expires_t *)msg_header_access((msg_pub_t*)(sip), sip_min_expires_class )) \ |
5368 | ((sip_min_expires_t *)msg_header_access((msg_pub_t*)(sip), sip_min_expires_class)) |
5369 | |
5370 | /**Initializer for structure #sip_min_expires_t. |
5371 | * |
5372 | * A static #sip_min_expires_t structure for |
5373 | * @ref sip_min_expires "Min-Expires header" must be initialized with |
5374 | * the SIP_MIN_EXPIRES_INIT() macro. |
5375 | * For instance, |
5376 | * @code |
5377 | * |
5378 | * sip_min_expires_t sip_min_expires = SIP_MIN_EXPIRES_INIT; |
5379 | * |
5380 | * @endcode |
5381 | * @HI |
5382 | * |
5383 | */ |
5384 | #define SIP_MIN_EXPIRES_INIT(){{{ 0, 0, sip_min_expires_class }}} SIP_HDR_INIT(min_expires){{{ 0, 0, sip_min_expires_class }}} |
5385 | |
5386 | /**Initialize a structure #sip_min_expires_t. |
5387 | * |
5388 | * An #sip_min_expires_t structure for |
5389 | * @ref sip_min_expires "Min-Expires header" can be initialized with the |
5390 | * sip_min_expires_init() function/macro. For instance, |
5391 | * @code |
5392 | * |
5393 | * sip_min_expires_t sip_min_expires; |
5394 | * |
5395 | * sip_min_expires_init(&sip_min_expires); |
5396 | * |
5397 | * @endcode |
5398 | * @HI |
5399 | * |
5400 | */ |
5401 | #if SU_HAVE_INLINE1 |
5402 | su_inlinestatic inline sip_min_expires_t *sip_min_expires_init(sip_min_expires_t x[1]) |
5403 | { |
5404 | return SIP_HEADER_INIT(x, sip_min_expires_class, sizeof(sip_min_expires_t))((void)memset((x), 0, (sizeof(sip_min_expires_t))), (void)((( sip_common_t *)(x))->h_class = (sip_min_expires_class)), ( x)); |
5405 | } |
5406 | #else |
5407 | #define sip_min_expires_init(x) \ |
5408 | SIP_HEADER_INIT(x, sip_min_expires_class, sizeof(sip_min_expires_t))((void)memset((x), 0, (sizeof(sip_min_expires_t))), (void)((( sip_common_t *)(x))->h_class = (sip_min_expires_class)), ( x)) |
5409 | #endif |
5410 | |
5411 | /**Test if header object is instance of #sip_min_expires_t. |
5412 | * |
5413 | * Check if the header class is an instance of |
5414 | * @ref sip_min_expires "Min-Expires header" object and return true (nonzero), |
5415 | * otherwise return false (zero). |
5416 | * |
5417 | * @param header pointer to the header structure to be tested |
5418 | * |
5419 | * @retval 1 (true) if the @a header is an instance of header min_expires |
5420 | * @retval 0 (false) otherwise |
5421 | * |
5422 | */ |
5423 | #if SU_HAVE_INLINE1 |
5424 | su_inlinestatic inline int sip_is_min_expires(sip_header_t const *header) |
5425 | { |
5426 | return header && header->sh_classsh_common->h_class->hc_hash == sip_min_expires_hash; |
5427 | } |
5428 | #else |
5429 | int sip_is_min_expires(sip_header_t const *header); |
5430 | #endif |
5431 | |
5432 | #define sip_min_expires_p(h)sip_is_min_expires((h)) sip_is_min_expires((h)) |
5433 | |
5434 | |
5435 | /**Duplicate a list of @ref sip_min_expires "Min-Expires header" header structures #sip_min_expires_t. |
5436 | * |
5437 | * Duplicate a header |
5438 | * structure @a hdr. If the header structure @a hdr |
5439 | * contains a reference (@c hdr->x_next) to a list of |
5440 | * headers, all the headers in the list are duplicated, too. |
5441 | * |
5442 | * @param home memory home used to allocate new structure |
5443 | * @param hdr header structure to be duplicated |
5444 | * |
5445 | * When duplicating, all parameter lists and non-constant |
5446 | * strings attached to the header are copied, too. The |
5447 | * function uses given memory @a home to allocate all the |
5448 | * memory areas used to copy the header. |
5449 | * |
5450 | * @par Example |
5451 | * @code |
5452 | * |
5453 | * min_expires = sip_min_expires_dup(home, sip->sip_min_expires); |
5454 | * |
5455 | * @endcode |
5456 | * |
5457 | * @return |
5458 | * A pointer to the |
5459 | * newly duplicated #sip_min_expires_t header structure, or NULL |
5460 | * upon an error. |
5461 | * |
5462 | */ |
5463 | #if SU_HAVE_INLINE1 |
5464 | su_inlinestatic inline |
5465 | #endif |
5466 | sip_min_expires_t *sip_min_expires_dup(su_home_t *home, sip_min_expires_t const *hdr) |
5467 | __attribute__((__malloc__)); |
5468 | |
5469 | #if SU_HAVE_INLINE1 |
5470 | su_inlinestatic inline |
5471 | sip_min_expires_t *sip_min_expires_dup(su_home_t *home, sip_min_expires_t const *hdr) |
5472 | { |
5473 | return (sip_min_expires_t *) |
5474 | msg_header_dup_as(home, sip_min_expires_class, (msg_header_t const *)hdr); |
5475 | } |
5476 | #endif |
5477 | |
5478 | /**Copy a list of @ref sip_min_expires "Min-Expires header" header structures #sip_min_expires_t. |
5479 | * |
5480 | * The function sip_min_expires_copy() copies a header structure @a |
5481 | * hdr. If the header structure @a hdr contains a reference (@c |
5482 | * hdr->h_next) to a list of headers, all the headers in that |
5483 | * list are copied, too. The function uses given memory @a home |
5484 | * to allocate all the memory areas used to copy the list of header |
5485 | * structure @a hdr. |
5486 | * |
5487 | * @param home memory home used to allocate new structure |
5488 | * @param hdr pointer to the header structure to be copied |
5489 | * |
5490 | * When copying, only the header structure and parameter lists attached to |
5491 | * it are duplicated. The new header structure retains all the references to |
5492 | * the strings within the old @a hdr header, including the encoding of the |
5493 | * old header, if present. |
5494 | * |
5495 | * @par Example |
5496 | * @code |
5497 | * |
5498 | * min_expires = sip_min_expires_copy(home, sip->sip_min_expires); |
5499 | * |
5500 | * @endcode |
5501 | * |
5502 | * @return |
5503 | * A pointer to newly copied header structure, or NULL upon an error. |
5504 | * |
5505 | */ |
5506 | #if SU_HAVE_INLINE1 |
5507 | su_inlinestatic inline |
5508 | #endif |
5509 | sip_min_expires_t *sip_min_expires_copy(su_home_t *home, sip_min_expires_t const *hdr) |
5510 | __attribute__((__malloc__)); |
5511 | |
5512 | #if SU_HAVE_INLINE1 |
5513 | su_inlinestatic inline |
5514 | sip_min_expires_t *sip_min_expires_copy(su_home_t *home, sip_min_expires_t const *hdr) |
5515 | { |
5516 | return (sip_min_expires_t *) |
5517 | msg_header_copy_as(home, sip_min_expires_class, (msg_header_t const *)hdr); |
5518 | } |
5519 | #endif |
5520 | |
5521 | /**Make a @ref sip_min_expires "Min-Expires header" structure #sip_min_expires_t. |
5522 | * |
5523 | * The function sip_min_expires_make() makes a new |
5524 | * #sip_min_expires_t header structure. It allocates a new |
5525 | * header structure, and decodes the string @a s as the |
5526 | * value of the structure. |
5527 | * |
5528 | * @param home memory home used to allocate new header structure. |
5529 | * @param s string to be decoded as value of the new header structure |
5530 | * |
5531 | * @return |
5532 | * A pointer to newly maked #sip_min_expires_t header structure, or NULL upon an |
5533 | * error. |
5534 | * |
5535 | */ |
5536 | #if SU_HAVE_INLINE1 |
5537 | su_inlinestatic inline |
5538 | #endif |
5539 | sip_min_expires_t *sip_min_expires_make(su_home_t *home, char const *s) |
5540 | __attribute__((__malloc__)); |
5541 | |
5542 | #if SU_HAVE_INLINE1 |
5543 | su_inlinestatic inline sip_min_expires_t *sip_min_expires_make(su_home_t *home, char const *s) |
5544 | { |
5545 | return (sip_min_expires_t *)sip_header_make(home, sip_min_expires_class, s)((sip_header_t *)msg_header_make((home), (sip_min_expires_class ), (s))); |
5546 | } |
5547 | #endif |
5548 | |
5549 | /**Make a @ref sip_min_expires "Min-Expires header" from formatting result. |
5550 | * |
5551 | * Make a new #sip_min_expires_t object using formatting result as its value. |
5552 | * The function first prints the arguments according to the format @a fmt |
5553 | * specified. Then it allocates a new header structure, and parses the |
5554 | * formatting result to the structure #sip_min_expires_t. |
5555 | * |
5556 | * @param home memory home used to allocate new header structure. |
5557 | * @param fmt string used as a printf()-style format |
5558 | * @param ... argument list for format |
5559 | * |
5560 | * @return |
5561 | * A pointer to newly |
5562 | * makes header structure, or NULL upon an error. |
5563 | * |
5564 | * @HIDE |
5565 | * |
5566 | */ |
5567 | #if SU_HAVE_INLINE1 |
5568 | su_inlinestatic inline |
5569 | #endif |
5570 | sip_min_expires_t *sip_min_expires_format(su_home_t *home, char const *fmt, ...) |
5571 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
5572 | |
5573 | #if SU_HAVE_INLINE1 |
5574 | su_inlinestatic inline sip_min_expires_t *sip_min_expires_format(su_home_t *home, char const *fmt, ...) |
5575 | { |
5576 | sip_header_t *h; |
5577 | va_list ap; |
5578 | |
5579 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
5580 | h = sip_header_vformat(home, sip_min_expires_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_min_expires_class ), (fmt), (ap))); |
5581 | va_end(ap)__builtin_va_end(ap); |
5582 | |
5583 | return (sip_min_expires_t *)h; |
5584 | } |
5585 | #endif |
5586 | |
5587 | /** @} */ |
5588 | |
5589 | /**@addtogroup sip_subject |
5590 | * @{ |
5591 | */ |
5592 | |
5593 | /** Parse a SIP @ref sip_subject "Subject header". @internal */ |
5594 | SOFIAPUBFUN issize_t sip_subject_d(su_home_t *, msg_header_t *, |
5595 | char *s, isize_t slen); |
5596 | |
5597 | /** Print a SIP @ref sip_subject "Subject header". @internal */ |
5598 | SOFIAPUBFUN issize_t sip_subject_e(char b[], isize_t bsiz, |
5599 | msg_header_t const *h, int flags); |
5600 | |
5601 | /**Access a SIP @ref sip_subject "Subject header" |
5602 | * structure #sip_subject_t from #sip_t. |
5603 | * |
5604 | */ |
5605 | #define sip_subject(sip)((sip_subject_t *)msg_header_access((msg_pub_t*)(sip), sip_subject_class )) \ |
5606 | ((sip_subject_t *)msg_header_access((msg_pub_t*)(sip), sip_subject_class)) |
5607 | |
5608 | /**Initializer for structure #sip_subject_t. |
5609 | * |
5610 | * A static #sip_subject_t structure for |
5611 | * @ref sip_subject "Subject header" must be initialized with |
5612 | * the SIP_SUBJECT_INIT() macro. |
5613 | * For instance, |
5614 | * @code |
5615 | * |
5616 | * sip_subject_t sip_subject = SIP_SUBJECT_INIT; |
5617 | * |
5618 | * @endcode |
5619 | * @HI |
5620 | * |
5621 | */ |
5622 | #define SIP_SUBJECT_INIT(){{{ 0, 0, sip_subject_class }}} SIP_HDR_INIT(subject){{{ 0, 0, sip_subject_class }}} |
5623 | |
5624 | /**Initialize a structure #sip_subject_t. |
5625 | * |
5626 | * An #sip_subject_t structure for |
5627 | * @ref sip_subject "Subject header" can be initialized with the |
5628 | * sip_subject_init() function/macro. For instance, |
5629 | * @code |
5630 | * |
5631 | * sip_subject_t sip_subject; |
5632 | * |
5633 | * sip_subject_init(&sip_subject); |
5634 | * |
5635 | * @endcode |
5636 | * @HI |
5637 | * |
5638 | */ |
5639 | #if SU_HAVE_INLINE1 |
5640 | su_inlinestatic inline sip_subject_t *sip_subject_init(sip_subject_t x[1]) |
5641 | { |
5642 | return SIP_HEADER_INIT(x, sip_subject_class, sizeof(sip_subject_t))((void)memset((x), 0, (sizeof(sip_subject_t))), (void)(((sip_common_t *)(x))->h_class = (sip_subject_class)), (x)); |
5643 | } |
5644 | #else |
5645 | #define sip_subject_init(x) \ |
5646 | SIP_HEADER_INIT(x, sip_subject_class, sizeof(sip_subject_t))((void)memset((x), 0, (sizeof(sip_subject_t))), (void)(((sip_common_t *)(x))->h_class = (sip_subject_class)), (x)) |
5647 | #endif |
5648 | |
5649 | /**Test if header object is instance of #sip_subject_t. |
5650 | * |
5651 | * Check if the header class is an instance of |
5652 | * @ref sip_subject "Subject header" object and return true (nonzero), |
5653 | * otherwise return false (zero). |
5654 | * |
5655 | * @param header pointer to the header structure to be tested |
5656 | * |
5657 | * @retval 1 (true) if the @a header is an instance of header subject |
5658 | * @retval 0 (false) otherwise |
5659 | * |
5660 | */ |
5661 | #if SU_HAVE_INLINE1 |
5662 | su_inlinestatic inline int sip_is_subject(sip_header_t const *header) |
5663 | { |
5664 | return header && header->sh_classsh_common->h_class->hc_hash == sip_subject_hash; |
5665 | } |
5666 | #else |
5667 | int sip_is_subject(sip_header_t const *header); |
5668 | #endif |
5669 | |
5670 | #define sip_subject_p(h)sip_is_subject((h)) sip_is_subject((h)) |
5671 | |
5672 | |
5673 | /**Duplicate a list of @ref sip_subject "Subject header" header structures #sip_subject_t. |
5674 | * |
5675 | * Duplicate a header |
5676 | * structure @a hdr. If the header structure @a hdr |
5677 | * contains a reference (@c hdr->x_next) to a list of |
5678 | * headers, all the headers in the list are duplicated, too. |
5679 | * |
5680 | * @param home memory home used to allocate new structure |
5681 | * @param hdr header structure to be duplicated |
5682 | * |
5683 | * When duplicating, all parameter lists and non-constant |
5684 | * strings attached to the header are copied, too. The |
5685 | * function uses given memory @a home to allocate all the |
5686 | * memory areas used to copy the header. |
5687 | * |
5688 | * @par Example |
5689 | * @code |
5690 | * |
5691 | * subject = sip_subject_dup(home, sip->sip_subject); |
5692 | * |
5693 | * @endcode |
5694 | * |
5695 | * @return |
5696 | * A pointer to the |
5697 | * newly duplicated #sip_subject_t header structure, or NULL |
5698 | * upon an error. |
5699 | * |
5700 | */ |
5701 | #if SU_HAVE_INLINE1 |
5702 | su_inlinestatic inline |
5703 | #endif |
5704 | sip_subject_t *sip_subject_dup(su_home_t *home, sip_subject_t const *hdr) |
5705 | __attribute__((__malloc__)); |
5706 | |
5707 | #if SU_HAVE_INLINE1 |
5708 | su_inlinestatic inline |
5709 | sip_subject_t *sip_subject_dup(su_home_t *home, sip_subject_t const *hdr) |
5710 | { |
5711 | return (sip_subject_t *) |
5712 | msg_header_dup_as(home, sip_subject_class, (msg_header_t const *)hdr); |
5713 | } |
5714 | #endif |
5715 | |
5716 | /**Copy a list of @ref sip_subject "Subject header" header structures #sip_subject_t. |
5717 | * |
5718 | * The function sip_subject_copy() copies a header structure @a |
5719 | * hdr. If the header structure @a hdr contains a reference (@c |
5720 | * hdr->h_next) to a list of headers, all the headers in that |
5721 | * list are copied, too. The function uses given memory @a home |
5722 | * to allocate all the memory areas used to copy the list of header |
5723 | * structure @a hdr. |
5724 | * |
5725 | * @param home memory home used to allocate new structure |
5726 | * @param hdr pointer to the header structure to be copied |
5727 | * |
5728 | * When copying, only the header structure and parameter lists attached to |
5729 | * it are duplicated. The new header structure retains all the references to |
5730 | * the strings within the old @a hdr header, including the encoding of the |
5731 | * old header, if present. |
5732 | * |
5733 | * @par Example |
5734 | * @code |
5735 | * |
5736 | * subject = sip_subject_copy(home, sip->sip_subject); |
5737 | * |
5738 | * @endcode |
5739 | * |
5740 | * @return |
5741 | * A pointer to newly copied header structure, or NULL upon an error. |
5742 | * |
5743 | */ |
5744 | #if SU_HAVE_INLINE1 |
5745 | su_inlinestatic inline |
5746 | #endif |
5747 | sip_subject_t *sip_subject_copy(su_home_t *home, sip_subject_t const *hdr) |
5748 | __attribute__((__malloc__)); |
5749 | |
5750 | #if SU_HAVE_INLINE1 |
5751 | su_inlinestatic inline |
5752 | sip_subject_t *sip_subject_copy(su_home_t *home, sip_subject_t const *hdr) |
5753 | { |
5754 | return (sip_subject_t *) |
5755 | msg_header_copy_as(home, sip_subject_class, (msg_header_t const *)hdr); |
5756 | } |
5757 | #endif |
5758 | |
5759 | /**Make a @ref sip_subject "Subject header" structure #sip_subject_t. |
5760 | * |
5761 | * The function sip_subject_make() makes a new |
5762 | * #sip_subject_t header structure. It allocates a new |
5763 | * header structure, and decodes the string @a s as the |
5764 | * value of the structure. |
5765 | * |
5766 | * @param home memory home used to allocate new header structure. |
5767 | * @param s string to be decoded as value of the new header structure |
5768 | * |
5769 | * @return |
5770 | * A pointer to newly maked #sip_subject_t header structure, or NULL upon an |
5771 | * error. |
5772 | * |
5773 | */ |
5774 | #if SU_HAVE_INLINE1 |
5775 | su_inlinestatic inline |
5776 | #endif |
5777 | sip_subject_t *sip_subject_make(su_home_t *home, char const *s) |
5778 | __attribute__((__malloc__)); |
5779 | |
5780 | #if SU_HAVE_INLINE1 |
5781 | su_inlinestatic inline sip_subject_t *sip_subject_make(su_home_t *home, char const *s) |
5782 | { |
5783 | return (sip_subject_t *)sip_header_make(home, sip_subject_class, s)((sip_header_t *)msg_header_make((home), (sip_subject_class), (s))); |
5784 | } |
5785 | #endif |
5786 | |
5787 | /**Make a @ref sip_subject "Subject header" from formatting result. |
5788 | * |
5789 | * Make a new #sip_subject_t object using formatting result as its value. |
5790 | * The function first prints the arguments according to the format @a fmt |
5791 | * specified. Then it allocates a new header structure, and parses the |
5792 | * formatting result to the structure #sip_subject_t. |
5793 | * |
5794 | * @param home memory home used to allocate new header structure. |
5795 | * @param fmt string used as a printf()-style format |
5796 | * @param ... argument list for format |
5797 | * |
5798 | * @return |
5799 | * A pointer to newly |
5800 | * makes header structure, or NULL upon an error. |
5801 | * |
5802 | * @HIDE |
5803 | * |
5804 | */ |
5805 | #if SU_HAVE_INLINE1 |
5806 | su_inlinestatic inline |
5807 | #endif |
5808 | sip_subject_t *sip_subject_format(su_home_t *home, char const *fmt, ...) |
5809 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
5810 | |
5811 | #if SU_HAVE_INLINE1 |
5812 | su_inlinestatic inline sip_subject_t *sip_subject_format(su_home_t *home, char const *fmt, ...) |
5813 | { |
5814 | sip_header_t *h; |
5815 | va_list ap; |
5816 | |
5817 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
5818 | h = sip_header_vformat(home, sip_subject_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_subject_class ), (fmt), (ap))); |
5819 | va_end(ap)__builtin_va_end(ap); |
5820 | |
5821 | return (sip_subject_t *)h; |
5822 | } |
5823 | #endif |
5824 | |
5825 | /** @} */ |
5826 | |
5827 | /**@addtogroup sip_priority |
5828 | * @{ |
5829 | */ |
5830 | |
5831 | /** Parse a SIP @ref sip_priority "Priority header". @internal */ |
5832 | SOFIAPUBFUN issize_t sip_priority_d(su_home_t *, msg_header_t *, |
5833 | char *s, isize_t slen); |
5834 | |
5835 | /** Print a SIP @ref sip_priority "Priority header". @internal */ |
5836 | SOFIAPUBFUN issize_t sip_priority_e(char b[], isize_t bsiz, |
5837 | msg_header_t const *h, int flags); |
5838 | |
5839 | /**Access a SIP @ref sip_priority "Priority header" |
5840 | * structure #sip_priority_t from #sip_t. |
5841 | * |
5842 | */ |
5843 | #define sip_priority(sip)((sip_priority_t *)msg_header_access((msg_pub_t*)(sip), sip_priority_class )) \ |
5844 | ((sip_priority_t *)msg_header_access((msg_pub_t*)(sip), sip_priority_class)) |
5845 | |
5846 | /**Initializer for structure #sip_priority_t. |
5847 | * |
5848 | * A static #sip_priority_t structure for |
5849 | * @ref sip_priority "Priority header" must be initialized with |
5850 | * the SIP_PRIORITY_INIT() macro. |
5851 | * For instance, |
5852 | * @code |
5853 | * |
5854 | * sip_priority_t sip_priority = SIP_PRIORITY_INIT; |
5855 | * |
5856 | * @endcode |
5857 | * @HI |
5858 | * |
5859 | */ |
5860 | #define SIP_PRIORITY_INIT(){{{ 0, 0, sip_priority_class }}} SIP_HDR_INIT(priority){{{ 0, 0, sip_priority_class }}} |
5861 | |
5862 | /**Initialize a structure #sip_priority_t. |
5863 | * |
5864 | * An #sip_priority_t structure for |
5865 | * @ref sip_priority "Priority header" can be initialized with the |
5866 | * sip_priority_init() function/macro. For instance, |
5867 | * @code |
5868 | * |
5869 | * sip_priority_t sip_priority; |
5870 | * |
5871 | * sip_priority_init(&sip_priority); |
5872 | * |
5873 | * @endcode |
5874 | * @HI |
5875 | * |
5876 | */ |
5877 | #if SU_HAVE_INLINE1 |
5878 | su_inlinestatic inline sip_priority_t *sip_priority_init(sip_priority_t x[1]) |
5879 | { |
5880 | return SIP_HEADER_INIT(x, sip_priority_class, sizeof(sip_priority_t))((void)memset((x), 0, (sizeof(sip_priority_t))), (void)(((sip_common_t *)(x))->h_class = (sip_priority_class)), (x)); |
5881 | } |
5882 | #else |
5883 | #define sip_priority_init(x) \ |
5884 | SIP_HEADER_INIT(x, sip_priority_class, sizeof(sip_priority_t))((void)memset((x), 0, (sizeof(sip_priority_t))), (void)(((sip_common_t *)(x))->h_class = (sip_priority_class)), (x)) |
5885 | #endif |
5886 | |
5887 | /**Test if header object is instance of #sip_priority_t. |
5888 | * |
5889 | * Check if the header class is an instance of |
5890 | * @ref sip_priority "Priority header" object and return true (nonzero), |
5891 | * otherwise return false (zero). |
5892 | * |
5893 | * @param header pointer to the header structure to be tested |
5894 | * |
5895 | * @retval 1 (true) if the @a header is an instance of header priority |
5896 | * @retval 0 (false) otherwise |
5897 | * |
5898 | */ |
5899 | #if SU_HAVE_INLINE1 |
5900 | su_inlinestatic inline int sip_is_priority(sip_header_t const *header) |
5901 | { |
5902 | return header && header->sh_classsh_common->h_class->hc_hash == sip_priority_hash; |
5903 | } |
5904 | #else |
5905 | int sip_is_priority(sip_header_t const *header); |
5906 | #endif |
5907 | |
5908 | #define sip_priority_p(h)sip_is_priority((h)) sip_is_priority((h)) |
5909 | |
5910 | |
5911 | /**Duplicate a list of @ref sip_priority "Priority header" header structures #sip_priority_t. |
5912 | * |
5913 | * Duplicate a header |
5914 | * structure @a hdr. If the header structure @a hdr |
5915 | * contains a reference (@c hdr->x_next) to a list of |
5916 | * headers, all the headers in the list are duplicated, too. |
5917 | * |
5918 | * @param home memory home used to allocate new structure |
5919 | * @param hdr header structure to be duplicated |
5920 | * |
5921 | * When duplicating, all parameter lists and non-constant |
5922 | * strings attached to the header are copied, too. The |
5923 | * function uses given memory @a home to allocate all the |
5924 | * memory areas used to copy the header. |
5925 | * |
5926 | * @par Example |
5927 | * @code |
5928 | * |
5929 | * priority = sip_priority_dup(home, sip->sip_priority); |
5930 | * |
5931 | * @endcode |
5932 | * |
5933 | * @return |
5934 | * A pointer to the |
5935 | * newly duplicated #sip_priority_t header structure, or NULL |
5936 | * upon an error. |
5937 | * |
5938 | */ |
5939 | #if SU_HAVE_INLINE1 |
5940 | su_inlinestatic inline |
5941 | #endif |
5942 | sip_priority_t *sip_priority_dup(su_home_t *home, sip_priority_t const *hdr) |
5943 | __attribute__((__malloc__)); |
5944 | |
5945 | #if SU_HAVE_INLINE1 |
5946 | su_inlinestatic inline |
5947 | sip_priority_t *sip_priority_dup(su_home_t *home, sip_priority_t const *hdr) |
5948 | { |
5949 | return (sip_priority_t *) |
5950 | msg_header_dup_as(home, sip_priority_class, (msg_header_t const *)hdr); |
5951 | } |
5952 | #endif |
5953 | |
5954 | /**Copy a list of @ref sip_priority "Priority header" header structures #sip_priority_t. |
5955 | * |
5956 | * The function sip_priority_copy() copies a header structure @a |
5957 | * hdr. If the header structure @a hdr contains a reference (@c |
5958 | * hdr->h_next) to a list of headers, all the headers in that |
5959 | * list are copied, too. The function uses given memory @a home |
5960 | * to allocate all the memory areas used to copy the list of header |
5961 | * structure @a hdr. |
5962 | * |
5963 | * @param home memory home used to allocate new structure |
5964 | * @param hdr pointer to the header structure to be copied |
5965 | * |
5966 | * When copying, only the header structure and parameter lists attached to |
5967 | * it are duplicated. The new header structure retains all the references to |
5968 | * the strings within the old @a hdr header, including the encoding of the |
5969 | * old header, if present. |
5970 | * |
5971 | * @par Example |
5972 | * @code |
5973 | * |
5974 | * priority = sip_priority_copy(home, sip->sip_priority); |
5975 | * |
5976 | * @endcode |
5977 | * |
5978 | * @return |
5979 | * A pointer to newly copied header structure, or NULL upon an error. |
5980 | * |
5981 | */ |
5982 | #if SU_HAVE_INLINE1 |
5983 | su_inlinestatic inline |
5984 | #endif |
5985 | sip_priority_t *sip_priority_copy(su_home_t *home, sip_priority_t const *hdr) |
5986 | __attribute__((__malloc__)); |
5987 | |
5988 | #if SU_HAVE_INLINE1 |
5989 | su_inlinestatic inline |
5990 | sip_priority_t *sip_priority_copy(su_home_t *home, sip_priority_t const *hdr) |
5991 | { |
5992 | return (sip_priority_t *) |
5993 | msg_header_copy_as(home, sip_priority_class, (msg_header_t const *)hdr); |
5994 | } |
5995 | #endif |
5996 | |
5997 | /**Make a @ref sip_priority "Priority header" structure #sip_priority_t. |
5998 | * |
5999 | * The function sip_priority_make() makes a new |
6000 | * #sip_priority_t header structure. It allocates a new |
6001 | * header structure, and decodes the string @a s as the |
6002 | * value of the structure. |
6003 | * |
6004 | * @param home memory home used to allocate new header structure. |
6005 | * @param s string to be decoded as value of the new header structure |
6006 | * |
6007 | * @return |
6008 | * A pointer to newly maked #sip_priority_t header structure, or NULL upon an |
6009 | * error. |
6010 | * |
6011 | */ |
6012 | #if SU_HAVE_INLINE1 |
6013 | su_inlinestatic inline |
6014 | #endif |
6015 | sip_priority_t *sip_priority_make(su_home_t *home, char const *s) |
6016 | __attribute__((__malloc__)); |
6017 | |
6018 | #if SU_HAVE_INLINE1 |
6019 | su_inlinestatic inline sip_priority_t *sip_priority_make(su_home_t *home, char const *s) |
6020 | { |
6021 | return (sip_priority_t *)sip_header_make(home, sip_priority_class, s)((sip_header_t *)msg_header_make((home), (sip_priority_class) , (s))); |
6022 | } |
6023 | #endif |
6024 | |
6025 | /**Make a @ref sip_priority "Priority header" from formatting result. |
6026 | * |
6027 | * Make a new #sip_priority_t object using formatting result as its value. |
6028 | * The function first prints the arguments according to the format @a fmt |
6029 | * specified. Then it allocates a new header structure, and parses the |
6030 | * formatting result to the structure #sip_priority_t. |
6031 | * |
6032 | * @param home memory home used to allocate new header structure. |
6033 | * @param fmt string used as a printf()-style format |
6034 | * @param ... argument list for format |
6035 | * |
6036 | * @return |
6037 | * A pointer to newly |
6038 | * makes header structure, or NULL upon an error. |
6039 | * |
6040 | * @HIDE |
6041 | * |
6042 | */ |
6043 | #if SU_HAVE_INLINE1 |
6044 | su_inlinestatic inline |
6045 | #endif |
6046 | sip_priority_t *sip_priority_format(su_home_t *home, char const *fmt, ...) |
6047 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
6048 | |
6049 | #if SU_HAVE_INLINE1 |
6050 | su_inlinestatic inline sip_priority_t *sip_priority_format(su_home_t *home, char const *fmt, ...) |
6051 | { |
6052 | sip_header_t *h; |
6053 | va_list ap; |
6054 | |
6055 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
6056 | h = sip_header_vformat(home, sip_priority_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_priority_class ), (fmt), (ap))); |
6057 | va_end(ap)__builtin_va_end(ap); |
6058 | |
6059 | return (sip_priority_t *)h; |
6060 | } |
6061 | #endif |
6062 | |
6063 | /** @} */ |
6064 | |
6065 | /**@addtogroup sip_call_info |
6066 | * @{ |
6067 | */ |
6068 | |
6069 | /** Parse a SIP @ref sip_call_info "Call-Info header". @internal */ |
6070 | SOFIAPUBFUN issize_t sip_call_info_d(su_home_t *, msg_header_t *, |
6071 | char *s, isize_t slen); |
6072 | |
6073 | /** Print a SIP @ref sip_call_info "Call-Info header". @internal */ |
6074 | SOFIAPUBFUN issize_t sip_call_info_e(char b[], isize_t bsiz, |
6075 | msg_header_t const *h, int flags); |
6076 | |
6077 | /**Access a SIP @ref sip_call_info "Call-Info header" |
6078 | * structure #sip_call_info_t from #sip_t. |
6079 | * |
6080 | */ |
6081 | #define sip_call_info(sip)((sip_call_info_t *)msg_header_access((msg_pub_t*)(sip), sip_call_info_class )) \ |
6082 | ((sip_call_info_t *)msg_header_access((msg_pub_t*)(sip), sip_call_info_class)) |
6083 | |
6084 | /**Initializer for structure #sip_call_info_t. |
6085 | * |
6086 | * A static #sip_call_info_t structure for |
6087 | * @ref sip_call_info "Call-Info header" must be initialized with |
6088 | * the SIP_CALL_INFO_INIT() macro. |
6089 | * For instance, |
6090 | * @code |
6091 | * |
6092 | * sip_call_info_t sip_call_info = SIP_CALL_INFO_INIT; |
6093 | * |
6094 | * @endcode |
6095 | * @HI |
6096 | * |
6097 | */ |
6098 | #define SIP_CALL_INFO_INIT(){{{ 0, 0, sip_call_info_class }}} SIP_HDR_INIT(call_info){{{ 0, 0, sip_call_info_class }}} |
6099 | |
6100 | /**Initialize a structure #sip_call_info_t. |
6101 | * |
6102 | * An #sip_call_info_t structure for |
6103 | * @ref sip_call_info "Call-Info header" can be initialized with the |
6104 | * sip_call_info_init() function/macro. For instance, |
6105 | * @code |
6106 | * |
6107 | * sip_call_info_t sip_call_info; |
6108 | * |
6109 | * sip_call_info_init(&sip_call_info); |
6110 | * |
6111 | * @endcode |
6112 | * @HI |
6113 | * |
6114 | */ |
6115 | #if SU_HAVE_INLINE1 |
6116 | su_inlinestatic inline sip_call_info_t *sip_call_info_init(sip_call_info_t x[1]) |
6117 | { |
6118 | return SIP_HEADER_INIT(x, sip_call_info_class, sizeof(sip_call_info_t))((void)memset((x), 0, (sizeof(sip_call_info_t))), (void)(((sip_common_t *)(x))->h_class = (sip_call_info_class)), (x)); |
6119 | } |
6120 | #else |
6121 | #define sip_call_info_init(x) \ |
6122 | SIP_HEADER_INIT(x, sip_call_info_class, sizeof(sip_call_info_t))((void)memset((x), 0, (sizeof(sip_call_info_t))), (void)(((sip_common_t *)(x))->h_class = (sip_call_info_class)), (x)) |
6123 | #endif |
6124 | |
6125 | /**Test if header object is instance of #sip_call_info_t. |
6126 | * |
6127 | * Check if the header class is an instance of |
6128 | * @ref sip_call_info "Call-Info header" object and return true (nonzero), |
6129 | * otherwise return false (zero). |
6130 | * |
6131 | * @param header pointer to the header structure to be tested |
6132 | * |
6133 | * @retval 1 (true) if the @a header is an instance of header call_info |
6134 | * @retval 0 (false) otherwise |
6135 | * |
6136 | */ |
6137 | #if SU_HAVE_INLINE1 |
6138 | su_inlinestatic inline int sip_is_call_info(sip_header_t const *header) |
6139 | { |
6140 | return header && header->sh_classsh_common->h_class->hc_hash == sip_call_info_hash; |
6141 | } |
6142 | #else |
6143 | int sip_is_call_info(sip_header_t const *header); |
6144 | #endif |
6145 | |
6146 | #define sip_call_info_p(h)sip_is_call_info((h)) sip_is_call_info((h)) |
6147 | |
6148 | |
6149 | /**Duplicate a list of @ref sip_call_info "Call-Info header" header structures #sip_call_info_t. |
6150 | * |
6151 | * Duplicate a header |
6152 | * structure @a hdr. If the header structure @a hdr |
6153 | * contains a reference (@c hdr->x_next) to a list of |
6154 | * headers, all the headers in the list are duplicated, too. |
6155 | * |
6156 | * @param home memory home used to allocate new structure |
6157 | * @param hdr header structure to be duplicated |
6158 | * |
6159 | * When duplicating, all parameter lists and non-constant |
6160 | * strings attached to the header are copied, too. The |
6161 | * function uses given memory @a home to allocate all the |
6162 | * memory areas used to copy the header. |
6163 | * |
6164 | * @par Example |
6165 | * @code |
6166 | * |
6167 | * call_info = sip_call_info_dup(home, sip->sip_call_info); |
6168 | * |
6169 | * @endcode |
6170 | * |
6171 | * @return |
6172 | * A pointer to the |
6173 | * newly duplicated #sip_call_info_t header structure, or NULL |
6174 | * upon an error. |
6175 | * |
6176 | */ |
6177 | #if SU_HAVE_INLINE1 |
6178 | su_inlinestatic inline |
6179 | #endif |
6180 | sip_call_info_t *sip_call_info_dup(su_home_t *home, sip_call_info_t const *hdr) |
6181 | __attribute__((__malloc__)); |
6182 | |
6183 | #if SU_HAVE_INLINE1 |
6184 | su_inlinestatic inline |
6185 | sip_call_info_t *sip_call_info_dup(su_home_t *home, sip_call_info_t const *hdr) |
6186 | { |
6187 | return (sip_call_info_t *) |
6188 | msg_header_dup_as(home, sip_call_info_class, (msg_header_t const *)hdr); |
6189 | } |
6190 | #endif |
6191 | |
6192 | /**Copy a list of @ref sip_call_info "Call-Info header" header structures #sip_call_info_t. |
6193 | * |
6194 | * The function sip_call_info_copy() copies a header structure @a |
6195 | * hdr. If the header structure @a hdr contains a reference (@c |
6196 | * hdr->h_next) to a list of headers, all the headers in that |
6197 | * list are copied, too. The function uses given memory @a home |
6198 | * to allocate all the memory areas used to copy the list of header |
6199 | * structure @a hdr. |
6200 | * |
6201 | * @param home memory home used to allocate new structure |
6202 | * @param hdr pointer to the header structure to be copied |
6203 | * |
6204 | * When copying, only the header structure and parameter lists attached to |
6205 | * it are duplicated. The new header structure retains all the references to |
6206 | * the strings within the old @a hdr header, including the encoding of the |
6207 | * old header, if present. |
6208 | * |
6209 | * @par Example |
6210 | * @code |
6211 | * |
6212 | * call_info = sip_call_info_copy(home, sip->sip_call_info); |
6213 | * |
6214 | * @endcode |
6215 | * |
6216 | * @return |
6217 | * A pointer to newly copied header structure, or NULL upon an error. |
6218 | * |
6219 | */ |
6220 | #if SU_HAVE_INLINE1 |
6221 | su_inlinestatic inline |
6222 | #endif |
6223 | sip_call_info_t *sip_call_info_copy(su_home_t *home, sip_call_info_t const *hdr) |
6224 | __attribute__((__malloc__)); |
6225 | |
6226 | #if SU_HAVE_INLINE1 |
6227 | su_inlinestatic inline |
6228 | sip_call_info_t *sip_call_info_copy(su_home_t *home, sip_call_info_t const *hdr) |
6229 | { |
6230 | return (sip_call_info_t *) |
6231 | msg_header_copy_as(home, sip_call_info_class, (msg_header_t const *)hdr); |
6232 | } |
6233 | #endif |
6234 | |
6235 | /**Make a @ref sip_call_info "Call-Info header" structure #sip_call_info_t. |
6236 | * |
6237 | * The function sip_call_info_make() makes a new |
6238 | * #sip_call_info_t header structure. It allocates a new |
6239 | * header structure, and decodes the string @a s as the |
6240 | * value of the structure. |
6241 | * |
6242 | * @param home memory home used to allocate new header structure. |
6243 | * @param s string to be decoded as value of the new header structure |
6244 | * |
6245 | * @return |
6246 | * A pointer to newly maked #sip_call_info_t header structure, or NULL upon an |
6247 | * error. |
6248 | * |
6249 | */ |
6250 | #if SU_HAVE_INLINE1 |
6251 | su_inlinestatic inline |
6252 | #endif |
6253 | sip_call_info_t *sip_call_info_make(su_home_t *home, char const *s) |
6254 | __attribute__((__malloc__)); |
6255 | |
6256 | #if SU_HAVE_INLINE1 |
6257 | su_inlinestatic inline sip_call_info_t *sip_call_info_make(su_home_t *home, char const *s) |
6258 | { |
6259 | return (sip_call_info_t *)sip_header_make(home, sip_call_info_class, s)((sip_header_t *)msg_header_make((home), (sip_call_info_class ), (s))); |
6260 | } |
6261 | #endif |
6262 | |
6263 | /**Make a @ref sip_call_info "Call-Info header" from formatting result. |
6264 | * |
6265 | * Make a new #sip_call_info_t object using formatting result as its value. |
6266 | * The function first prints the arguments according to the format @a fmt |
6267 | * specified. Then it allocates a new header structure, and parses the |
6268 | * formatting result to the structure #sip_call_info_t. |
6269 | * |
6270 | * @param home memory home used to allocate new header structure. |
6271 | * @param fmt string used as a printf()-style format |
6272 | * @param ... argument list for format |
6273 | * |
6274 | * @return |
6275 | * A pointer to newly |
6276 | * makes header structure, or NULL upon an error. |
6277 | * |
6278 | * @HIDE |
6279 | * |
6280 | */ |
6281 | #if SU_HAVE_INLINE1 |
6282 | su_inlinestatic inline |
6283 | #endif |
6284 | sip_call_info_t *sip_call_info_format(su_home_t *home, char const *fmt, ...) |
6285 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
6286 | |
6287 | #if SU_HAVE_INLINE1 |
6288 | su_inlinestatic inline sip_call_info_t *sip_call_info_format(su_home_t *home, char const *fmt, ...) |
6289 | { |
6290 | sip_header_t *h; |
6291 | va_list ap; |
6292 | |
6293 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
6294 | h = sip_header_vformat(home, sip_call_info_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_call_info_class ), (fmt), (ap))); |
6295 | va_end(ap)__builtin_va_end(ap); |
6296 | |
6297 | return (sip_call_info_t *)h; |
6298 | } |
6299 | #endif |
6300 | |
6301 | /** @} */ |
6302 | |
6303 | /**@addtogroup sip_organization |
6304 | * @{ |
6305 | */ |
6306 | |
6307 | /** Parse a SIP @ref sip_organization "Organization header". @internal */ |
6308 | SOFIAPUBFUN issize_t sip_organization_d(su_home_t *, msg_header_t *, |
6309 | char *s, isize_t slen); |
6310 | |
6311 | /** Print a SIP @ref sip_organization "Organization header". @internal */ |
6312 | SOFIAPUBFUN issize_t sip_organization_e(char b[], isize_t bsiz, |
6313 | msg_header_t const *h, int flags); |
6314 | |
6315 | /**Access a SIP @ref sip_organization "Organization header" |
6316 | * structure #sip_organization_t from #sip_t. |
6317 | * |
6318 | */ |
6319 | #define sip_organization(sip)((sip_organization_t *)msg_header_access((msg_pub_t*)(sip), sip_organization_class )) \ |
6320 | ((sip_organization_t *)msg_header_access((msg_pub_t*)(sip), sip_organization_class)) |
6321 | |
6322 | /**Initializer for structure #sip_organization_t. |
6323 | * |
6324 | * A static #sip_organization_t structure for |
6325 | * @ref sip_organization "Organization header" must be initialized with |
6326 | * the SIP_ORGANIZATION_INIT() macro. |
6327 | * For instance, |
6328 | * @code |
6329 | * |
6330 | * sip_organization_t sip_organization = SIP_ORGANIZATION_INIT; |
6331 | * |
6332 | * @endcode |
6333 | * @HI |
6334 | * |
6335 | */ |
6336 | #define SIP_ORGANIZATION_INIT(){{{ 0, 0, sip_organization_class }}} SIP_HDR_INIT(organization){{{ 0, 0, sip_organization_class }}} |
6337 | |
6338 | /**Initialize a structure #sip_organization_t. |
6339 | * |
6340 | * An #sip_organization_t structure for |
6341 | * @ref sip_organization "Organization header" can be initialized with the |
6342 | * sip_organization_init() function/macro. For instance, |
6343 | * @code |
6344 | * |
6345 | * sip_organization_t sip_organization; |
6346 | * |
6347 | * sip_organization_init(&sip_organization); |
6348 | * |
6349 | * @endcode |
6350 | * @HI |
6351 | * |
6352 | */ |
6353 | #if SU_HAVE_INLINE1 |
6354 | su_inlinestatic inline sip_organization_t *sip_organization_init(sip_organization_t x[1]) |
6355 | { |
6356 | return SIP_HEADER_INIT(x, sip_organization_class, sizeof(sip_organization_t))((void)memset((x), 0, (sizeof(sip_organization_t))), (void)(( (sip_common_t *)(x))->h_class = (sip_organization_class)), (x)); |
6357 | } |
6358 | #else |
6359 | #define sip_organization_init(x) \ |
6360 | SIP_HEADER_INIT(x, sip_organization_class, sizeof(sip_organization_t))((void)memset((x), 0, (sizeof(sip_organization_t))), (void)(( (sip_common_t *)(x))->h_class = (sip_organization_class)), (x)) |
6361 | #endif |
6362 | |
6363 | /**Test if header object is instance of #sip_organization_t. |
6364 | * |
6365 | * Check if the header class is an instance of |
6366 | * @ref sip_organization "Organization header" object and return true (nonzero), |
6367 | * otherwise return false (zero). |
6368 | * |
6369 | * @param header pointer to the header structure to be tested |
6370 | * |
6371 | * @retval 1 (true) if the @a header is an instance of header organization |
6372 | * @retval 0 (false) otherwise |
6373 | * |
6374 | */ |
6375 | #if SU_HAVE_INLINE1 |
6376 | su_inlinestatic inline int sip_is_organization(sip_header_t const *header) |
6377 | { |
6378 | return header && header->sh_classsh_common->h_class->hc_hash == sip_organization_hash; |
6379 | } |
6380 | #else |
6381 | int sip_is_organization(sip_header_t const *header); |
6382 | #endif |
6383 | |
6384 | #define sip_organization_p(h)sip_is_organization((h)) sip_is_organization((h)) |
6385 | |
6386 | |
6387 | /**Duplicate a list of @ref sip_organization "Organization header" header structures #sip_organization_t. |
6388 | * |
6389 | * Duplicate a header |
6390 | * structure @a hdr. If the header structure @a hdr |
6391 | * contains a reference (@c hdr->x_next) to a list of |
6392 | * headers, all the headers in the list are duplicated, too. |
6393 | * |
6394 | * @param home memory home used to allocate new structure |
6395 | * @param hdr header structure to be duplicated |
6396 | * |
6397 | * When duplicating, all parameter lists and non-constant |
6398 | * strings attached to the header are copied, too. The |
6399 | * function uses given memory @a home to allocate all the |
6400 | * memory areas used to copy the header. |
6401 | * |
6402 | * @par Example |
6403 | * @code |
6404 | * |
6405 | * organization = sip_organization_dup(home, sip->sip_organization); |
6406 | * |
6407 | * @endcode |
6408 | * |
6409 | * @return |
6410 | * A pointer to the |
6411 | * newly duplicated #sip_organization_t header structure, or NULL |
6412 | * upon an error. |
6413 | * |
6414 | */ |
6415 | #if SU_HAVE_INLINE1 |
6416 | su_inlinestatic inline |
6417 | #endif |
6418 | sip_organization_t *sip_organization_dup(su_home_t *home, sip_organization_t const *hdr) |
6419 | __attribute__((__malloc__)); |
6420 | |
6421 | #if SU_HAVE_INLINE1 |
6422 | su_inlinestatic inline |
6423 | sip_organization_t *sip_organization_dup(su_home_t *home, sip_organization_t const *hdr) |
6424 | { |
6425 | return (sip_organization_t *) |
6426 | msg_header_dup_as(home, sip_organization_class, (msg_header_t const *)hdr); |
6427 | } |
6428 | #endif |
6429 | |
6430 | /**Copy a list of @ref sip_organization "Organization header" header structures #sip_organization_t. |
6431 | * |
6432 | * The function sip_organization_copy() copies a header structure @a |
6433 | * hdr. If the header structure @a hdr contains a reference (@c |
6434 | * hdr->h_next) to a list of headers, all the headers in that |
6435 | * list are copied, too. The function uses given memory @a home |
6436 | * to allocate all the memory areas used to copy the list of header |
6437 | * structure @a hdr. |
6438 | * |
6439 | * @param home memory home used to allocate new structure |
6440 | * @param hdr pointer to the header structure to be copied |
6441 | * |
6442 | * When copying, only the header structure and parameter lists attached to |
6443 | * it are duplicated. The new header structure retains all the references to |
6444 | * the strings within the old @a hdr header, including the encoding of the |
6445 | * old header, if present. |
6446 | * |
6447 | * @par Example |
6448 | * @code |
6449 | * |
6450 | * organization = sip_organization_copy(home, sip->sip_organization); |
6451 | * |
6452 | * @endcode |
6453 | * |
6454 | * @return |
6455 | * A pointer to newly copied header structure, or NULL upon an error. |
6456 | * |
6457 | */ |
6458 | #if SU_HAVE_INLINE1 |
6459 | su_inlinestatic inline |
6460 | #endif |
6461 | sip_organization_t *sip_organization_copy(su_home_t *home, sip_organization_t const *hdr) |
6462 | __attribute__((__malloc__)); |
6463 | |
6464 | #if SU_HAVE_INLINE1 |
6465 | su_inlinestatic inline |
6466 | sip_organization_t *sip_organization_copy(su_home_t *home, sip_organization_t const *hdr) |
6467 | { |
6468 | return (sip_organization_t *) |
6469 | msg_header_copy_as(home, sip_organization_class, (msg_header_t const *)hdr); |
6470 | } |
6471 | #endif |
6472 | |
6473 | /**Make a @ref sip_organization "Organization header" structure #sip_organization_t. |
6474 | * |
6475 | * The function sip_organization_make() makes a new |
6476 | * #sip_organization_t header structure. It allocates a new |
6477 | * header structure, and decodes the string @a s as the |
6478 | * value of the structure. |
6479 | * |
6480 | * @param home memory home used to allocate new header structure. |
6481 | * @param s string to be decoded as value of the new header structure |
6482 | * |
6483 | * @return |
6484 | * A pointer to newly maked #sip_organization_t header structure, or NULL upon an |
6485 | * error. |
6486 | * |
6487 | */ |
6488 | #if SU_HAVE_INLINE1 |
6489 | su_inlinestatic inline |
6490 | #endif |
6491 | sip_organization_t *sip_organization_make(su_home_t *home, char const *s) |
6492 | __attribute__((__malloc__)); |
6493 | |
6494 | #if SU_HAVE_INLINE1 |
6495 | su_inlinestatic inline sip_organization_t *sip_organization_make(su_home_t *home, char const *s) |
6496 | { |
6497 | return (sip_organization_t *)sip_header_make(home, sip_organization_class, s)((sip_header_t *)msg_header_make((home), (sip_organization_class ), (s))); |
6498 | } |
6499 | #endif |
6500 | |
6501 | /**Make a @ref sip_organization "Organization header" from formatting result. |
6502 | * |
6503 | * Make a new #sip_organization_t object using formatting result as its value. |
6504 | * The function first prints the arguments according to the format @a fmt |
6505 | * specified. Then it allocates a new header structure, and parses the |
6506 | * formatting result to the structure #sip_organization_t. |
6507 | * |
6508 | * @param home memory home used to allocate new header structure. |
6509 | * @param fmt string used as a printf()-style format |
6510 | * @param ... argument list for format |
6511 | * |
6512 | * @return |
6513 | * A pointer to newly |
6514 | * makes header structure, or NULL upon an error. |
6515 | * |
6516 | * @HIDE |
6517 | * |
6518 | */ |
6519 | #if SU_HAVE_INLINE1 |
6520 | su_inlinestatic inline |
6521 | #endif |
6522 | sip_organization_t *sip_organization_format(su_home_t *home, char const *fmt, ...) |
6523 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
6524 | |
6525 | #if SU_HAVE_INLINE1 |
6526 | su_inlinestatic inline sip_organization_t *sip_organization_format(su_home_t *home, char const *fmt, ...) |
6527 | { |
6528 | sip_header_t *h; |
6529 | va_list ap; |
6530 | |
6531 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
6532 | h = sip_header_vformat(home, sip_organization_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_organization_class ), (fmt), (ap))); |
6533 | va_end(ap)__builtin_va_end(ap); |
6534 | |
6535 | return (sip_organization_t *)h; |
6536 | } |
6537 | #endif |
6538 | |
6539 | /** @} */ |
6540 | |
6541 | /**@addtogroup sip_server |
6542 | * @{ |
6543 | */ |
6544 | |
6545 | /** Parse a SIP @ref sip_server "Server header". @internal */ |
6546 | SOFIAPUBFUN issize_t sip_server_d(su_home_t *, msg_header_t *, |
6547 | char *s, isize_t slen); |
6548 | |
6549 | /** Print a SIP @ref sip_server "Server header". @internal */ |
6550 | SOFIAPUBFUN issize_t sip_server_e(char b[], isize_t bsiz, |
6551 | msg_header_t const *h, int flags); |
6552 | |
6553 | /**Access a SIP @ref sip_server "Server header" |
6554 | * structure #sip_server_t from #sip_t. |
6555 | * |
6556 | */ |
6557 | #define sip_server(sip)((sip_server_t *)msg_header_access((msg_pub_t*)(sip), sip_server_class )) \ |
6558 | ((sip_server_t *)msg_header_access((msg_pub_t*)(sip), sip_server_class)) |
6559 | |
6560 | /**Initializer for structure #sip_server_t. |
6561 | * |
6562 | * A static #sip_server_t structure for |
6563 | * @ref sip_server "Server header" must be initialized with |
6564 | * the SIP_SERVER_INIT() macro. |
6565 | * For instance, |
6566 | * @code |
6567 | * |
6568 | * sip_server_t sip_server = SIP_SERVER_INIT; |
6569 | * |
6570 | * @endcode |
6571 | * @HI |
6572 | * |
6573 | */ |
6574 | #define SIP_SERVER_INIT(){{{ 0, 0, sip_server_class }}} SIP_HDR_INIT(server){{{ 0, 0, sip_server_class }}} |
6575 | |
6576 | /**Initialize a structure #sip_server_t. |
6577 | * |
6578 | * An #sip_server_t structure for |
6579 | * @ref sip_server "Server header" can be initialized with the |
6580 | * sip_server_init() function/macro. For instance, |
6581 | * @code |
6582 | * |
6583 | * sip_server_t sip_server; |
6584 | * |
6585 | * sip_server_init(&sip_server); |
6586 | * |
6587 | * @endcode |
6588 | * @HI |
6589 | * |
6590 | */ |
6591 | #if SU_HAVE_INLINE1 |
6592 | su_inlinestatic inline sip_server_t *sip_server_init(sip_server_t x[1]) |
6593 | { |
6594 | return SIP_HEADER_INIT(x, sip_server_class, sizeof(sip_server_t))((void)memset((x), 0, (sizeof(sip_server_t))), (void)(((sip_common_t *)(x))->h_class = (sip_server_class)), (x)); |
6595 | } |
6596 | #else |
6597 | #define sip_server_init(x) \ |
6598 | SIP_HEADER_INIT(x, sip_server_class, sizeof(sip_server_t))((void)memset((x), 0, (sizeof(sip_server_t))), (void)(((sip_common_t *)(x))->h_class = (sip_server_class)), (x)) |
6599 | #endif |
6600 | |
6601 | /**Test if header object is instance of #sip_server_t. |
6602 | * |
6603 | * Check if the header class is an instance of |
6604 | * @ref sip_server "Server header" object and return true (nonzero), |
6605 | * otherwise return false (zero). |
6606 | * |
6607 | * @param header pointer to the header structure to be tested |
6608 | * |
6609 | * @retval 1 (true) if the @a header is an instance of header server |
6610 | * @retval 0 (false) otherwise |
6611 | * |
6612 | */ |
6613 | #if SU_HAVE_INLINE1 |
6614 | su_inlinestatic inline int sip_is_server(sip_header_t const *header) |
6615 | { |
6616 | return header && header->sh_classsh_common->h_class->hc_hash == sip_server_hash; |
6617 | } |
6618 | #else |
6619 | int sip_is_server(sip_header_t const *header); |
6620 | #endif |
6621 | |
6622 | #define sip_server_p(h)sip_is_server((h)) sip_is_server((h)) |
6623 | |
6624 | |
6625 | /**Duplicate a list of @ref sip_server "Server header" header structures #sip_server_t. |
6626 | * |
6627 | * Duplicate a header |
6628 | * structure @a hdr. If the header structure @a hdr |
6629 | * contains a reference (@c hdr->x_next) to a list of |
6630 | * headers, all the headers in the list are duplicated, too. |
6631 | * |
6632 | * @param home memory home used to allocate new structure |
6633 | * @param hdr header structure to be duplicated |
6634 | * |
6635 | * When duplicating, all parameter lists and non-constant |
6636 | * strings attached to the header are copied, too. The |
6637 | * function uses given memory @a home to allocate all the |
6638 | * memory areas used to copy the header. |
6639 | * |
6640 | * @par Example |
6641 | * @code |
6642 | * |
6643 | * server = sip_server_dup(home, sip->sip_server); |
6644 | * |
6645 | * @endcode |
6646 | * |
6647 | * @return |
6648 | * A pointer to the |
6649 | * newly duplicated #sip_server_t header structure, or NULL |
6650 | * upon an error. |
6651 | * |
6652 | */ |
6653 | #if SU_HAVE_INLINE1 |
6654 | su_inlinestatic inline |
6655 | #endif |
6656 | sip_server_t *sip_server_dup(su_home_t *home, sip_server_t const *hdr) |
6657 | __attribute__((__malloc__)); |
6658 | |
6659 | #if SU_HAVE_INLINE1 |
6660 | su_inlinestatic inline |
6661 | sip_server_t *sip_server_dup(su_home_t *home, sip_server_t const *hdr) |
6662 | { |
6663 | return (sip_server_t *) |
6664 | msg_header_dup_as(home, sip_server_class, (msg_header_t const *)hdr); |
6665 | } |
6666 | #endif |
6667 | |
6668 | /**Copy a list of @ref sip_server "Server header" header structures #sip_server_t. |
6669 | * |
6670 | * The function sip_server_copy() copies a header structure @a |
6671 | * hdr. If the header structure @a hdr contains a reference (@c |
6672 | * hdr->h_next) to a list of headers, all the headers in that |
6673 | * list are copied, too. The function uses given memory @a home |
6674 | * to allocate all the memory areas used to copy the list of header |
6675 | * structure @a hdr. |
6676 | * |
6677 | * @param home memory home used to allocate new structure |
6678 | * @param hdr pointer to the header structure to be copied |
6679 | * |
6680 | * When copying, only the header structure and parameter lists attached to |
6681 | * it are duplicated. The new header structure retains all the references to |
6682 | * the strings within the old @a hdr header, including the encoding of the |
6683 | * old header, if present. |
6684 | * |
6685 | * @par Example |
6686 | * @code |
6687 | * |
6688 | * server = sip_server_copy(home, sip->sip_server); |
6689 | * |
6690 | * @endcode |
6691 | * |
6692 | * @return |
6693 | * A pointer to newly copied header structure, or NULL upon an error. |
6694 | * |
6695 | */ |
6696 | #if SU_HAVE_INLINE1 |
6697 | su_inlinestatic inline |
6698 | #endif |
6699 | sip_server_t *sip_server_copy(su_home_t *home, sip_server_t const *hdr) |
6700 | __attribute__((__malloc__)); |
6701 | |
6702 | #if SU_HAVE_INLINE1 |
6703 | su_inlinestatic inline |
6704 | sip_server_t *sip_server_copy(su_home_t *home, sip_server_t const *hdr) |
6705 | { |
6706 | return (sip_server_t *) |
6707 | msg_header_copy_as(home, sip_server_class, (msg_header_t const *)hdr); |
6708 | } |
6709 | #endif |
6710 | |
6711 | /**Make a @ref sip_server "Server header" structure #sip_server_t. |
6712 | * |
6713 | * The function sip_server_make() makes a new |
6714 | * #sip_server_t header structure. It allocates a new |
6715 | * header structure, and decodes the string @a s as the |
6716 | * value of the structure. |
6717 | * |
6718 | * @param home memory home used to allocate new header structure. |
6719 | * @param s string to be decoded as value of the new header structure |
6720 | * |
6721 | * @return |
6722 | * A pointer to newly maked #sip_server_t header structure, or NULL upon an |
6723 | * error. |
6724 | * |
6725 | */ |
6726 | #if SU_HAVE_INLINE1 |
6727 | su_inlinestatic inline |
6728 | #endif |
6729 | sip_server_t *sip_server_make(su_home_t *home, char const *s) |
6730 | __attribute__((__malloc__)); |
6731 | |
6732 | #if SU_HAVE_INLINE1 |
6733 | su_inlinestatic inline sip_server_t *sip_server_make(su_home_t *home, char const *s) |
6734 | { |
6735 | return (sip_server_t *)sip_header_make(home, sip_server_class, s)((sip_header_t *)msg_header_make((home), (sip_server_class), ( s))); |
6736 | } |
6737 | #endif |
6738 | |
6739 | /**Make a @ref sip_server "Server header" from formatting result. |
6740 | * |
6741 | * Make a new #sip_server_t object using formatting result as its value. |
6742 | * The function first prints the arguments according to the format @a fmt |
6743 | * specified. Then it allocates a new header structure, and parses the |
6744 | * formatting result to the structure #sip_server_t. |
6745 | * |
6746 | * @param home memory home used to allocate new header structure. |
6747 | * @param fmt string used as a printf()-style format |
6748 | * @param ... argument list for format |
6749 | * |
6750 | * @return |
6751 | * A pointer to newly |
6752 | * makes header structure, or NULL upon an error. |
6753 | * |
6754 | * @HIDE |
6755 | * |
6756 | */ |
6757 | #if SU_HAVE_INLINE1 |
6758 | su_inlinestatic inline |
6759 | #endif |
6760 | sip_server_t *sip_server_format(su_home_t *home, char const *fmt, ...) |
6761 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
6762 | |
6763 | #if SU_HAVE_INLINE1 |
6764 | su_inlinestatic inline sip_server_t *sip_server_format(su_home_t *home, char const *fmt, ...) |
6765 | { |
6766 | sip_header_t *h; |
6767 | va_list ap; |
6768 | |
6769 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
6770 | h = sip_header_vformat(home, sip_server_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_server_class ), (fmt), (ap))); |
6771 | va_end(ap)__builtin_va_end(ap); |
6772 | |
6773 | return (sip_server_t *)h; |
6774 | } |
6775 | #endif |
6776 | |
6777 | /** @} */ |
6778 | |
6779 | /**@addtogroup sip_user_agent |
6780 | * @{ |
6781 | */ |
6782 | |
6783 | /** Parse a SIP @ref sip_user_agent "User-Agent header". @internal */ |
6784 | SOFIAPUBFUN issize_t sip_user_agent_d(su_home_t *, msg_header_t *, |
6785 | char *s, isize_t slen); |
6786 | |
6787 | /** Print a SIP @ref sip_user_agent "User-Agent header". @internal */ |
6788 | SOFIAPUBFUN issize_t sip_user_agent_e(char b[], isize_t bsiz, |
6789 | msg_header_t const *h, int flags); |
6790 | |
6791 | /**Access a SIP @ref sip_user_agent "User-Agent header" |
6792 | * structure #sip_user_agent_t from #sip_t. |
6793 | * |
6794 | */ |
6795 | #define sip_user_agent(sip)((sip_user_agent_t *)msg_header_access((msg_pub_t*)(sip), sip_user_agent_class )) \ |
6796 | ((sip_user_agent_t *)msg_header_access((msg_pub_t*)(sip), sip_user_agent_class)) |
6797 | |
6798 | /**Initializer for structure #sip_user_agent_t. |
6799 | * |
6800 | * A static #sip_user_agent_t structure for |
6801 | * @ref sip_user_agent "User-Agent header" must be initialized with |
6802 | * the SIP_USER_AGENT_INIT() macro. |
6803 | * For instance, |
6804 | * @code |
6805 | * |
6806 | * sip_user_agent_t sip_user_agent = SIP_USER_AGENT_INIT; |
6807 | * |
6808 | * @endcode |
6809 | * @HI |
6810 | * |
6811 | */ |
6812 | #define SIP_USER_AGENT_INIT(){{{ 0, 0, sip_user_agent_class }}} SIP_HDR_INIT(user_agent){{{ 0, 0, sip_user_agent_class }}} |
6813 | |
6814 | /**Initialize a structure #sip_user_agent_t. |
6815 | * |
6816 | * An #sip_user_agent_t structure for |
6817 | * @ref sip_user_agent "User-Agent header" can be initialized with the |
6818 | * sip_user_agent_init() function/macro. For instance, |
6819 | * @code |
6820 | * |
6821 | * sip_user_agent_t sip_user_agent; |
6822 | * |
6823 | * sip_user_agent_init(&sip_user_agent); |
6824 | * |
6825 | * @endcode |
6826 | * @HI |
6827 | * |
6828 | */ |
6829 | #if SU_HAVE_INLINE1 |
6830 | su_inlinestatic inline sip_user_agent_t *sip_user_agent_init(sip_user_agent_t x[1]) |
6831 | { |
6832 | return SIP_HEADER_INIT(x, sip_user_agent_class, sizeof(sip_user_agent_t))((void)memset((x), 0, (sizeof(sip_user_agent_t))), (void)(((sip_common_t *)(x))->h_class = (sip_user_agent_class)), (x)); |
6833 | } |
6834 | #else |
6835 | #define sip_user_agent_init(x) \ |
6836 | SIP_HEADER_INIT(x, sip_user_agent_class, sizeof(sip_user_agent_t))((void)memset((x), 0, (sizeof(sip_user_agent_t))), (void)(((sip_common_t *)(x))->h_class = (sip_user_agent_class)), (x)) |
6837 | #endif |
6838 | |
6839 | /**Test if header object is instance of #sip_user_agent_t. |
6840 | * |
6841 | * Check if the header class is an instance of |
6842 | * @ref sip_user_agent "User-Agent header" object and return true (nonzero), |
6843 | * otherwise return false (zero). |
6844 | * |
6845 | * @param header pointer to the header structure to be tested |
6846 | * |
6847 | * @retval 1 (true) if the @a header is an instance of header user_agent |
6848 | * @retval 0 (false) otherwise |
6849 | * |
6850 | */ |
6851 | #if SU_HAVE_INLINE1 |
6852 | su_inlinestatic inline int sip_is_user_agent(sip_header_t const *header) |
6853 | { |
6854 | return header && header->sh_classsh_common->h_class->hc_hash == sip_user_agent_hash; |
6855 | } |
6856 | #else |
6857 | int sip_is_user_agent(sip_header_t const *header); |
6858 | #endif |
6859 | |
6860 | #define sip_user_agent_p(h)sip_is_user_agent((h)) sip_is_user_agent((h)) |
6861 | |
6862 | |
6863 | /**Duplicate a list of @ref sip_user_agent "User-Agent header" header structures #sip_user_agent_t. |
6864 | * |
6865 | * Duplicate a header |
6866 | * structure @a hdr. If the header structure @a hdr |
6867 | * contains a reference (@c hdr->x_next) to a list of |
6868 | * headers, all the headers in the list are duplicated, too. |
6869 | * |
6870 | * @param home memory home used to allocate new structure |
6871 | * @param hdr header structure to be duplicated |
6872 | * |
6873 | * When duplicating, all parameter lists and non-constant |
6874 | * strings attached to the header are copied, too. The |
6875 | * function uses given memory @a home to allocate all the |
6876 | * memory areas used to copy the header. |
6877 | * |
6878 | * @par Example |
6879 | * @code |
6880 | * |
6881 | * user_agent = sip_user_agent_dup(home, sip->sip_user_agent); |
6882 | * |
6883 | * @endcode |
6884 | * |
6885 | * @return |
6886 | * A pointer to the |
6887 | * newly duplicated #sip_user_agent_t header structure, or NULL |
6888 | * upon an error. |
6889 | * |
6890 | */ |
6891 | #if SU_HAVE_INLINE1 |
6892 | su_inlinestatic inline |
6893 | #endif |
6894 | sip_user_agent_t *sip_user_agent_dup(su_home_t *home, sip_user_agent_t const *hdr) |
6895 | __attribute__((__malloc__)); |
6896 | |
6897 | #if SU_HAVE_INLINE1 |
6898 | su_inlinestatic inline |
6899 | sip_user_agent_t *sip_user_agent_dup(su_home_t *home, sip_user_agent_t const *hdr) |
6900 | { |
6901 | return (sip_user_agent_t *) |
6902 | msg_header_dup_as(home, sip_user_agent_class, (msg_header_t const *)hdr); |
6903 | } |
6904 | #endif |
6905 | |
6906 | /**Copy a list of @ref sip_user_agent "User-Agent header" header structures #sip_user_agent_t. |
6907 | * |
6908 | * The function sip_user_agent_copy() copies a header structure @a |
6909 | * hdr. If the header structure @a hdr contains a reference (@c |
6910 | * hdr->h_next) to a list of headers, all the headers in that |
6911 | * list are copied, too. The function uses given memory @a home |
6912 | * to allocate all the memory areas used to copy the list of header |
6913 | * structure @a hdr. |
6914 | * |
6915 | * @param home memory home used to allocate new structure |
6916 | * @param hdr pointer to the header structure to be copied |
6917 | * |
6918 | * When copying, only the header structure and parameter lists attached to |
6919 | * it are duplicated. The new header structure retains all the references to |
6920 | * the strings within the old @a hdr header, including the encoding of the |
6921 | * old header, if present. |
6922 | * |
6923 | * @par Example |
6924 | * @code |
6925 | * |
6926 | * user_agent = sip_user_agent_copy(home, sip->sip_user_agent); |
6927 | * |
6928 | * @endcode |
6929 | * |
6930 | * @return |
6931 | * A pointer to newly copied header structure, or NULL upon an error. |
6932 | * |
6933 | */ |
6934 | #if SU_HAVE_INLINE1 |
6935 | su_inlinestatic inline |
6936 | #endif |
6937 | sip_user_agent_t *sip_user_agent_copy(su_home_t *home, sip_user_agent_t const *hdr) |
6938 | __attribute__((__malloc__)); |
6939 | |
6940 | #if SU_HAVE_INLINE1 |
6941 | su_inlinestatic inline |
6942 | sip_user_agent_t *sip_user_agent_copy(su_home_t *home, sip_user_agent_t const *hdr) |
6943 | { |
6944 | return (sip_user_agent_t *) |
6945 | msg_header_copy_as(home, sip_user_agent_class, (msg_header_t const *)hdr); |
6946 | } |
6947 | #endif |
6948 | |
6949 | /**Make a @ref sip_user_agent "User-Agent header" structure #sip_user_agent_t. |
6950 | * |
6951 | * The function sip_user_agent_make() makes a new |
6952 | * #sip_user_agent_t header structure. It allocates a new |
6953 | * header structure, and decodes the string @a s as the |
6954 | * value of the structure. |
6955 | * |
6956 | * @param home memory home used to allocate new header structure. |
6957 | * @param s string to be decoded as value of the new header structure |
6958 | * |
6959 | * @return |
6960 | * A pointer to newly maked #sip_user_agent_t header structure, or NULL upon an |
6961 | * error. |
6962 | * |
6963 | */ |
6964 | #if SU_HAVE_INLINE1 |
6965 | su_inlinestatic inline |
6966 | #endif |
6967 | sip_user_agent_t *sip_user_agent_make(su_home_t *home, char const *s) |
6968 | __attribute__((__malloc__)); |
6969 | |
6970 | #if SU_HAVE_INLINE1 |
6971 | su_inlinestatic inline sip_user_agent_t *sip_user_agent_make(su_home_t *home, char const *s) |
6972 | { |
6973 | return (sip_user_agent_t *)sip_header_make(home, sip_user_agent_class, s)((sip_header_t *)msg_header_make((home), (sip_user_agent_class ), (s))); |
6974 | } |
6975 | #endif |
6976 | |
6977 | /**Make a @ref sip_user_agent "User-Agent header" from formatting result. |
6978 | * |
6979 | * Make a new #sip_user_agent_t object using formatting result as its value. |
6980 | * The function first prints the arguments according to the format @a fmt |
6981 | * specified. Then it allocates a new header structure, and parses the |
6982 | * formatting result to the structure #sip_user_agent_t. |
6983 | * |
6984 | * @param home memory home used to allocate new header structure. |
6985 | * @param fmt string used as a printf()-style format |
6986 | * @param ... argument list for format |
6987 | * |
6988 | * @return |
6989 | * A pointer to newly |
6990 | * makes header structure, or NULL upon an error. |
6991 | * |
6992 | * @HIDE |
6993 | * |
6994 | */ |
6995 | #if SU_HAVE_INLINE1 |
6996 | su_inlinestatic inline |
6997 | #endif |
6998 | sip_user_agent_t *sip_user_agent_format(su_home_t *home, char const *fmt, ...) |
6999 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
7000 | |
7001 | #if SU_HAVE_INLINE1 |
7002 | su_inlinestatic inline sip_user_agent_t *sip_user_agent_format(su_home_t *home, char const *fmt, ...) |
7003 | { |
7004 | sip_header_t *h; |
7005 | va_list ap; |
7006 | |
7007 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
7008 | h = sip_header_vformat(home, sip_user_agent_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_user_agent_class ), (fmt), (ap))); |
7009 | va_end(ap)__builtin_va_end(ap); |
7010 | |
7011 | return (sip_user_agent_t *)h; |
7012 | } |
7013 | #endif |
7014 | |
7015 | /** @} */ |
7016 | |
7017 | /**@addtogroup sip_in_reply_to |
7018 | * @{ |
7019 | */ |
7020 | |
7021 | /** Parse a SIP @ref sip_in_reply_to "In-Reply-To header". @internal */ |
7022 | SOFIAPUBFUN issize_t sip_in_reply_to_d(su_home_t *, msg_header_t *, |
7023 | char *s, isize_t slen); |
7024 | |
7025 | /** Print a SIP @ref sip_in_reply_to "In-Reply-To header". @internal */ |
7026 | SOFIAPUBFUN issize_t sip_in_reply_to_e(char b[], isize_t bsiz, |
7027 | msg_header_t const *h, int flags); |
7028 | |
7029 | /**Access a SIP @ref sip_in_reply_to "In-Reply-To header" |
7030 | * structure #sip_in_reply_to_t from #sip_t. |
7031 | * |
7032 | */ |
7033 | #define sip_in_reply_to(sip)((sip_in_reply_to_t *)msg_header_access((msg_pub_t*)(sip), sip_in_reply_to_class )) \ |
7034 | ((sip_in_reply_to_t *)msg_header_access((msg_pub_t*)(sip), sip_in_reply_to_class)) |
7035 | |
7036 | /**Initializer for structure #sip_in_reply_to_t. |
7037 | * |
7038 | * A static #sip_in_reply_to_t structure for |
7039 | * @ref sip_in_reply_to "In-Reply-To header" must be initialized with |
7040 | * the SIP_IN_REPLY_TO_INIT() macro. |
7041 | * For instance, |
7042 | * @code |
7043 | * |
7044 | * sip_in_reply_to_t sip_in_reply_to = SIP_IN_REPLY_TO_INIT; |
7045 | * |
7046 | * @endcode |
7047 | * @HI |
7048 | * |
7049 | */ |
7050 | #define SIP_IN_REPLY_TO_INIT(){{{ 0, 0, sip_in_reply_to_class }}} SIP_HDR_INIT(in_reply_to){{{ 0, 0, sip_in_reply_to_class }}} |
7051 | |
7052 | /**Initialize a structure #sip_in_reply_to_t. |
7053 | * |
7054 | * An #sip_in_reply_to_t structure for |
7055 | * @ref sip_in_reply_to "In-Reply-To header" can be initialized with the |
7056 | * sip_in_reply_to_init() function/macro. For instance, |
7057 | * @code |
7058 | * |
7059 | * sip_in_reply_to_t sip_in_reply_to; |
7060 | * |
7061 | * sip_in_reply_to_init(&sip_in_reply_to); |
7062 | * |
7063 | * @endcode |
7064 | * @HI |
7065 | * |
7066 | */ |
7067 | #if SU_HAVE_INLINE1 |
7068 | su_inlinestatic inline sip_in_reply_to_t *sip_in_reply_to_init(sip_in_reply_to_t x[1]) |
7069 | { |
7070 | return SIP_HEADER_INIT(x, sip_in_reply_to_class, sizeof(sip_in_reply_to_t))((void)memset((x), 0, (sizeof(sip_in_reply_to_t))), (void)((( sip_common_t *)(x))->h_class = (sip_in_reply_to_class)), ( x)); |
7071 | } |
7072 | #else |
7073 | #define sip_in_reply_to_init(x) \ |
7074 | SIP_HEADER_INIT(x, sip_in_reply_to_class, sizeof(sip_in_reply_to_t))((void)memset((x), 0, (sizeof(sip_in_reply_to_t))), (void)((( sip_common_t *)(x))->h_class = (sip_in_reply_to_class)), ( x)) |
7075 | #endif |
7076 | |
7077 | /**Test if header object is instance of #sip_in_reply_to_t. |
7078 | * |
7079 | * Check if the header class is an instance of |
7080 | * @ref sip_in_reply_to "In-Reply-To header" object and return true (nonzero), |
7081 | * otherwise return false (zero). |
7082 | * |
7083 | * @param header pointer to the header structure to be tested |
7084 | * |
7085 | * @retval 1 (true) if the @a header is an instance of header in_reply_to |
7086 | * @retval 0 (false) otherwise |
7087 | * |
7088 | */ |
7089 | #if SU_HAVE_INLINE1 |
7090 | su_inlinestatic inline int sip_is_in_reply_to(sip_header_t const *header) |
7091 | { |
7092 | return header && header->sh_classsh_common->h_class->hc_hash == sip_in_reply_to_hash; |
7093 | } |
7094 | #else |
7095 | int sip_is_in_reply_to(sip_header_t const *header); |
7096 | #endif |
7097 | |
7098 | #define sip_in_reply_to_p(h)sip_is_in_reply_to((h)) sip_is_in_reply_to((h)) |
7099 | |
7100 | |
7101 | /**Duplicate a list of @ref sip_in_reply_to "In-Reply-To header" header structures #sip_in_reply_to_t. |
7102 | * |
7103 | * Duplicate a header |
7104 | * structure @a hdr. If the header structure @a hdr |
7105 | * contains a reference (@c hdr->x_next) to a list of |
7106 | * headers, all the headers in the list are duplicated, too. |
7107 | * |
7108 | * @param home memory home used to allocate new structure |
7109 | * @param hdr header structure to be duplicated |
7110 | * |
7111 | * When duplicating, all parameter lists and non-constant |
7112 | * strings attached to the header are copied, too. The |
7113 | * function uses given memory @a home to allocate all the |
7114 | * memory areas used to copy the header. |
7115 | * |
7116 | * @par Example |
7117 | * @code |
7118 | * |
7119 | * in_reply_to = sip_in_reply_to_dup(home, sip->sip_in_reply_to); |
7120 | * |
7121 | * @endcode |
7122 | * |
7123 | * @return |
7124 | * A pointer to the |
7125 | * newly duplicated #sip_in_reply_to_t header structure, or NULL |
7126 | * upon an error. |
7127 | * |
7128 | */ |
7129 | #if SU_HAVE_INLINE1 |
7130 | su_inlinestatic inline |
7131 | #endif |
7132 | sip_in_reply_to_t *sip_in_reply_to_dup(su_home_t *home, sip_in_reply_to_t const *hdr) |
7133 | __attribute__((__malloc__)); |
7134 | |
7135 | #if SU_HAVE_INLINE1 |
7136 | su_inlinestatic inline |
7137 | sip_in_reply_to_t *sip_in_reply_to_dup(su_home_t *home, sip_in_reply_to_t const *hdr) |
7138 | { |
7139 | return (sip_in_reply_to_t *) |
7140 | msg_header_dup_as(home, sip_in_reply_to_class, (msg_header_t const *)hdr); |
7141 | } |
7142 | #endif |
7143 | |
7144 | /**Copy a list of @ref sip_in_reply_to "In-Reply-To header" header structures #sip_in_reply_to_t. |
7145 | * |
7146 | * The function sip_in_reply_to_copy() copies a header structure @a |
7147 | * hdr. If the header structure @a hdr contains a reference (@c |
7148 | * hdr->h_next) to a list of headers, all the headers in that |
7149 | * list are copied, too. The function uses given memory @a home |
7150 | * to allocate all the memory areas used to copy the list of header |
7151 | * structure @a hdr. |
7152 | * |
7153 | * @param home memory home used to allocate new structure |
7154 | * @param hdr pointer to the header structure to be copied |
7155 | * |
7156 | * When copying, only the header structure and parameter lists attached to |
7157 | * it are duplicated. The new header structure retains all the references to |
7158 | * the strings within the old @a hdr header, including the encoding of the |
7159 | * old header, if present. |
7160 | * |
7161 | * @par Example |
7162 | * @code |
7163 | * |
7164 | * in_reply_to = sip_in_reply_to_copy(home, sip->sip_in_reply_to); |
7165 | * |
7166 | * @endcode |
7167 | * |
7168 | * @return |
7169 | * A pointer to newly copied header structure, or NULL upon an error. |
7170 | * |
7171 | */ |
7172 | #if SU_HAVE_INLINE1 |
7173 | su_inlinestatic inline |
7174 | #endif |
7175 | sip_in_reply_to_t *sip_in_reply_to_copy(su_home_t *home, sip_in_reply_to_t const *hdr) |
7176 | __attribute__((__malloc__)); |
7177 | |
7178 | #if SU_HAVE_INLINE1 |
7179 | su_inlinestatic inline |
7180 | sip_in_reply_to_t *sip_in_reply_to_copy(su_home_t *home, sip_in_reply_to_t const *hdr) |
7181 | { |
7182 | return (sip_in_reply_to_t *) |
7183 | msg_header_copy_as(home, sip_in_reply_to_class, (msg_header_t const *)hdr); |
7184 | } |
7185 | #endif |
7186 | |
7187 | /**Make a @ref sip_in_reply_to "In-Reply-To header" structure #sip_in_reply_to_t. |
7188 | * |
7189 | * The function sip_in_reply_to_make() makes a new |
7190 | * #sip_in_reply_to_t header structure. It allocates a new |
7191 | * header structure, and decodes the string @a s as the |
7192 | * value of the structure. |
7193 | * |
7194 | * @param home memory home used to allocate new header structure. |
7195 | * @param s string to be decoded as value of the new header structure |
7196 | * |
7197 | * @return |
7198 | * A pointer to newly maked #sip_in_reply_to_t header structure, or NULL upon an |
7199 | * error. |
7200 | * |
7201 | */ |
7202 | #if SU_HAVE_INLINE1 |
7203 | su_inlinestatic inline |
7204 | #endif |
7205 | sip_in_reply_to_t *sip_in_reply_to_make(su_home_t *home, char const *s) |
7206 | __attribute__((__malloc__)); |
7207 | |
7208 | #if SU_HAVE_INLINE1 |
7209 | su_inlinestatic inline sip_in_reply_to_t *sip_in_reply_to_make(su_home_t *home, char const *s) |
7210 | { |
7211 | return (sip_in_reply_to_t *)sip_header_make(home, sip_in_reply_to_class, s)((sip_header_t *)msg_header_make((home), (sip_in_reply_to_class ), (s))); |
7212 | } |
7213 | #endif |
7214 | |
7215 | /**Make a @ref sip_in_reply_to "In-Reply-To header" from formatting result. |
7216 | * |
7217 | * Make a new #sip_in_reply_to_t object using formatting result as its value. |
7218 | * The function first prints the arguments according to the format @a fmt |
7219 | * specified. Then it allocates a new header structure, and parses the |
7220 | * formatting result to the structure #sip_in_reply_to_t. |
7221 | * |
7222 | * @param home memory home used to allocate new header structure. |
7223 | * @param fmt string used as a printf()-style format |
7224 | * @param ... argument list for format |
7225 | * |
7226 | * @return |
7227 | * A pointer to newly |
7228 | * makes header structure, or NULL upon an error. |
7229 | * |
7230 | * @HIDE |
7231 | * |
7232 | */ |
7233 | #if SU_HAVE_INLINE1 |
7234 | su_inlinestatic inline |
7235 | #endif |
7236 | sip_in_reply_to_t *sip_in_reply_to_format(su_home_t *home, char const *fmt, ...) |
7237 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
7238 | |
7239 | #if SU_HAVE_INLINE1 |
7240 | su_inlinestatic inline sip_in_reply_to_t *sip_in_reply_to_format(su_home_t *home, char const *fmt, ...) |
7241 | { |
7242 | sip_header_t *h; |
7243 | va_list ap; |
7244 | |
7245 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
7246 | h = sip_header_vformat(home, sip_in_reply_to_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_in_reply_to_class ), (fmt), (ap))); |
7247 | va_end(ap)__builtin_va_end(ap); |
7248 | |
7249 | return (sip_in_reply_to_t *)h; |
7250 | } |
7251 | #endif |
7252 | |
7253 | /** @} */ |
7254 | |
7255 | /**@addtogroup sip_accept |
7256 | * @{ |
7257 | */ |
7258 | |
7259 | /** Parse a SIP @ref sip_accept "Accept header". @internal */ |
7260 | SOFIAPUBFUN issize_t sip_accept_d(su_home_t *, msg_header_t *, |
7261 | char *s, isize_t slen); |
7262 | |
7263 | /** Print a SIP @ref sip_accept "Accept header". @internal */ |
7264 | SOFIAPUBFUN issize_t sip_accept_e(char b[], isize_t bsiz, |
7265 | msg_header_t const *h, int flags); |
7266 | |
7267 | /**Access a SIP @ref sip_accept "Accept header" |
7268 | * structure #sip_accept_t from #sip_t. |
7269 | * |
7270 | */ |
7271 | #define sip_accept(sip)((sip_accept_t *)msg_header_access((msg_pub_t*)(sip), sip_accept_class )) \ |
7272 | ((sip_accept_t *)msg_header_access((msg_pub_t*)(sip), sip_accept_class)) |
7273 | |
7274 | /**Initializer for structure #sip_accept_t. |
7275 | * |
7276 | * A static #sip_accept_t structure for |
7277 | * @ref sip_accept "Accept header" must be initialized with |
7278 | * the SIP_ACCEPT_INIT() macro. |
7279 | * For instance, |
7280 | * @code |
7281 | * |
7282 | * sip_accept_t sip_accept = SIP_ACCEPT_INIT; |
7283 | * |
7284 | * @endcode |
7285 | * @HI |
7286 | * |
7287 | */ |
7288 | #define SIP_ACCEPT_INIT(){{{ 0, 0, sip_accept_class }}} SIP_HDR_INIT(accept){{{ 0, 0, sip_accept_class }}} |
7289 | |
7290 | /**Initialize a structure #sip_accept_t. |
7291 | * |
7292 | * An #sip_accept_t structure for |
7293 | * @ref sip_accept "Accept header" can be initialized with the |
7294 | * sip_accept_init() function/macro. For instance, |
7295 | * @code |
7296 | * |
7297 | * sip_accept_t sip_accept; |
7298 | * |
7299 | * sip_accept_init(&sip_accept); |
7300 | * |
7301 | * @endcode |
7302 | * @HI |
7303 | * |
7304 | */ |
7305 | #if SU_HAVE_INLINE1 |
7306 | su_inlinestatic inline sip_accept_t *sip_accept_init(sip_accept_t x[1]) |
7307 | { |
7308 | return SIP_HEADER_INIT(x, sip_accept_class, sizeof(sip_accept_t))((void)memset((x), 0, (sizeof(sip_accept_t))), (void)(((sip_common_t *)(x))->h_class = (sip_accept_class)), (x)); |
7309 | } |
7310 | #else |
7311 | #define sip_accept_init(x) \ |
7312 | SIP_HEADER_INIT(x, sip_accept_class, sizeof(sip_accept_t))((void)memset((x), 0, (sizeof(sip_accept_t))), (void)(((sip_common_t *)(x))->h_class = (sip_accept_class)), (x)) |
7313 | #endif |
7314 | |
7315 | /**Test if header object is instance of #sip_accept_t. |
7316 | * |
7317 | * Check if the header class is an instance of |
7318 | * @ref sip_accept "Accept header" object and return true (nonzero), |
7319 | * otherwise return false (zero). |
7320 | * |
7321 | * @param header pointer to the header structure to be tested |
7322 | * |
7323 | * @retval 1 (true) if the @a header is an instance of header accept |
7324 | * @retval 0 (false) otherwise |
7325 | * |
7326 | */ |
7327 | #if SU_HAVE_INLINE1 |
7328 | su_inlinestatic inline int sip_is_accept(sip_header_t const *header) |
7329 | { |
7330 | return header && header->sh_classsh_common->h_class->hc_hash == sip_accept_hash; |
7331 | } |
7332 | #else |
7333 | int sip_is_accept(sip_header_t const *header); |
7334 | #endif |
7335 | |
7336 | #define sip_accept_p(h)sip_is_accept((h)) sip_is_accept((h)) |
7337 | |
7338 | |
7339 | /**Duplicate a list of @ref sip_accept "Accept header" header structures #sip_accept_t. |
7340 | * |
7341 | * Duplicate a header |
7342 | * structure @a hdr. If the header structure @a hdr |
7343 | * contains a reference (@c hdr->x_next) to a list of |
7344 | * headers, all the headers in the list are duplicated, too. |
7345 | * |
7346 | * @param home memory home used to allocate new structure |
7347 | * @param hdr header structure to be duplicated |
7348 | * |
7349 | * When duplicating, all parameter lists and non-constant |
7350 | * strings attached to the header are copied, too. The |
7351 | * function uses given memory @a home to allocate all the |
7352 | * memory areas used to copy the header. |
7353 | * |
7354 | * @par Example |
7355 | * @code |
7356 | * |
7357 | * accept = sip_accept_dup(home, sip->sip_accept); |
7358 | * |
7359 | * @endcode |
7360 | * |
7361 | * @return |
7362 | * A pointer to the |
7363 | * newly duplicated #sip_accept_t header structure, or NULL |
7364 | * upon an error. |
7365 | * |
7366 | */ |
7367 | #if SU_HAVE_INLINE1 |
7368 | su_inlinestatic inline |
7369 | #endif |
7370 | sip_accept_t *sip_accept_dup(su_home_t *home, sip_accept_t const *hdr) |
7371 | __attribute__((__malloc__)); |
7372 | |
7373 | #if SU_HAVE_INLINE1 |
7374 | su_inlinestatic inline |
7375 | sip_accept_t *sip_accept_dup(su_home_t *home, sip_accept_t const *hdr) |
7376 | { |
7377 | return (sip_accept_t *) |
7378 | msg_header_dup_as(home, sip_accept_class, (msg_header_t const *)hdr); |
7379 | } |
7380 | #endif |
7381 | |
7382 | /**Copy a list of @ref sip_accept "Accept header" header structures #sip_accept_t. |
7383 | * |
7384 | * The function sip_accept_copy() copies a header structure @a |
7385 | * hdr. If the header structure @a hdr contains a reference (@c |
7386 | * hdr->h_next) to a list of headers, all the headers in that |
7387 | * list are copied, too. The function uses given memory @a home |
7388 | * to allocate all the memory areas used to copy the list of header |
7389 | * structure @a hdr. |
7390 | * |
7391 | * @param home memory home used to allocate new structure |
7392 | * @param hdr pointer to the header structure to be copied |
7393 | * |
7394 | * When copying, only the header structure and parameter lists attached to |
7395 | * it are duplicated. The new header structure retains all the references to |
7396 | * the strings within the old @a hdr header, including the encoding of the |
7397 | * old header, if present. |
7398 | * |
7399 | * @par Example |
7400 | * @code |
7401 | * |
7402 | * accept = sip_accept_copy(home, sip->sip_accept); |
7403 | * |
7404 | * @endcode |
7405 | * |
7406 | * @return |
7407 | * A pointer to newly copied header structure, or NULL upon an error. |
7408 | * |
7409 | */ |
7410 | #if SU_HAVE_INLINE1 |
7411 | su_inlinestatic inline |
7412 | #endif |
7413 | sip_accept_t *sip_accept_copy(su_home_t *home, sip_accept_t const *hdr) |
7414 | __attribute__((__malloc__)); |
7415 | |
7416 | #if SU_HAVE_INLINE1 |
7417 | su_inlinestatic inline |
7418 | sip_accept_t *sip_accept_copy(su_home_t *home, sip_accept_t const *hdr) |
7419 | { |
7420 | return (sip_accept_t *) |
7421 | msg_header_copy_as(home, sip_accept_class, (msg_header_t const *)hdr); |
7422 | } |
7423 | #endif |
7424 | |
7425 | /**Make a @ref sip_accept "Accept header" structure #sip_accept_t. |
7426 | * |
7427 | * The function sip_accept_make() makes a new |
7428 | * #sip_accept_t header structure. It allocates a new |
7429 | * header structure, and decodes the string @a s as the |
7430 | * value of the structure. |
7431 | * |
7432 | * @param home memory home used to allocate new header structure. |
7433 | * @param s string to be decoded as value of the new header structure |
7434 | * |
7435 | * @return |
7436 | * A pointer to newly maked #sip_accept_t header structure, or NULL upon an |
7437 | * error. |
7438 | * |
7439 | */ |
7440 | #if SU_HAVE_INLINE1 |
7441 | su_inlinestatic inline |
7442 | #endif |
7443 | sip_accept_t *sip_accept_make(su_home_t *home, char const *s) |
7444 | __attribute__((__malloc__)); |
7445 | |
7446 | #if SU_HAVE_INLINE1 |
7447 | su_inlinestatic inline sip_accept_t *sip_accept_make(su_home_t *home, char const *s) |
7448 | { |
7449 | return (sip_accept_t *)sip_header_make(home, sip_accept_class, s)((sip_header_t *)msg_header_make((home), (sip_accept_class), ( s))); |
7450 | } |
7451 | #endif |
7452 | |
7453 | /**Make a @ref sip_accept "Accept header" from formatting result. |
7454 | * |
7455 | * Make a new #sip_accept_t object using formatting result as its value. |
7456 | * The function first prints the arguments according to the format @a fmt |
7457 | * specified. Then it allocates a new header structure, and parses the |
7458 | * formatting result to the structure #sip_accept_t. |
7459 | * |
7460 | * @param home memory home used to allocate new header structure. |
7461 | * @param fmt string used as a printf()-style format |
7462 | * @param ... argument list for format |
7463 | * |
7464 | * @return |
7465 | * A pointer to newly |
7466 | * makes header structure, or NULL upon an error. |
7467 | * |
7468 | * @HIDE |
7469 | * |
7470 | */ |
7471 | #if SU_HAVE_INLINE1 |
7472 | su_inlinestatic inline |
7473 | #endif |
7474 | sip_accept_t *sip_accept_format(su_home_t *home, char const *fmt, ...) |
7475 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
7476 | |
7477 | #if SU_HAVE_INLINE1 |
7478 | su_inlinestatic inline sip_accept_t *sip_accept_format(su_home_t *home, char const *fmt, ...) |
7479 | { |
7480 | sip_header_t *h; |
7481 | va_list ap; |
7482 | |
7483 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
7484 | h = sip_header_vformat(home, sip_accept_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_accept_class ), (fmt), (ap))); |
7485 | va_end(ap)__builtin_va_end(ap); |
7486 | |
7487 | return (sip_accept_t *)h; |
7488 | } |
7489 | #endif |
7490 | |
7491 | /** @} */ |
7492 | |
7493 | /**@addtogroup sip_accept_encoding |
7494 | * @{ |
7495 | */ |
7496 | |
7497 | /** Parse a SIP @ref sip_accept_encoding "Accept-Encoding header". @internal */ |
7498 | SOFIAPUBFUN issize_t sip_accept_encoding_d(su_home_t *, msg_header_t *, |
7499 | char *s, isize_t slen); |
7500 | |
7501 | /** Print a SIP @ref sip_accept_encoding "Accept-Encoding header". @internal */ |
7502 | SOFIAPUBFUN issize_t sip_accept_encoding_e(char b[], isize_t bsiz, |
7503 | msg_header_t const *h, int flags); |
7504 | |
7505 | /**Access a SIP @ref sip_accept_encoding "Accept-Encoding header" |
7506 | * structure #sip_accept_encoding_t from #sip_t. |
7507 | * |
7508 | */ |
7509 | #define sip_accept_encoding(sip)((sip_accept_encoding_t *)msg_header_access((msg_pub_t*)(sip) , sip_accept_encoding_class)) \ |
7510 | ((sip_accept_encoding_t *)msg_header_access((msg_pub_t*)(sip), sip_accept_encoding_class)) |
7511 | |
7512 | /**Initializer for structure #sip_accept_encoding_t. |
7513 | * |
7514 | * A static #sip_accept_encoding_t structure for |
7515 | * @ref sip_accept_encoding "Accept-Encoding header" must be initialized with |
7516 | * the SIP_ACCEPT_ENCODING_INIT() macro. |
7517 | * For instance, |
7518 | * @code |
7519 | * |
7520 | * sip_accept_encoding_t sip_accept_encoding = SIP_ACCEPT_ENCODING_INIT; |
7521 | * |
7522 | * @endcode |
7523 | * @HI |
7524 | * |
7525 | */ |
7526 | #define SIP_ACCEPT_ENCODING_INIT(){{{ 0, 0, sip_accept_encoding_class }}} SIP_HDR_INIT(accept_encoding){{{ 0, 0, sip_accept_encoding_class }}} |
7527 | |
7528 | /**Initialize a structure #sip_accept_encoding_t. |
7529 | * |
7530 | * An #sip_accept_encoding_t structure for |
7531 | * @ref sip_accept_encoding "Accept-Encoding header" can be initialized with the |
7532 | * sip_accept_encoding_init() function/macro. For instance, |
7533 | * @code |
7534 | * |
7535 | * sip_accept_encoding_t sip_accept_encoding; |
7536 | * |
7537 | * sip_accept_encoding_init(&sip_accept_encoding); |
7538 | * |
7539 | * @endcode |
7540 | * @HI |
7541 | * |
7542 | */ |
7543 | #if SU_HAVE_INLINE1 |
7544 | su_inlinestatic inline sip_accept_encoding_t *sip_accept_encoding_init(sip_accept_encoding_t x[1]) |
7545 | { |
7546 | return SIP_HEADER_INIT(x, sip_accept_encoding_class, sizeof(sip_accept_encoding_t))((void)memset((x), 0, (sizeof(sip_accept_encoding_t))), (void )(((sip_common_t *)(x))->h_class = (sip_accept_encoding_class )), (x)); |
7547 | } |
7548 | #else |
7549 | #define sip_accept_encoding_init(x) \ |
7550 | SIP_HEADER_INIT(x, sip_accept_encoding_class, sizeof(sip_accept_encoding_t))((void)memset((x), 0, (sizeof(sip_accept_encoding_t))), (void )(((sip_common_t *)(x))->h_class = (sip_accept_encoding_class )), (x)) |
7551 | #endif |
7552 | |
7553 | /**Test if header object is instance of #sip_accept_encoding_t. |
7554 | * |
7555 | * Check if the header class is an instance of |
7556 | * @ref sip_accept_encoding "Accept-Encoding header" object and return true (nonzero), |
7557 | * otherwise return false (zero). |
7558 | * |
7559 | * @param header pointer to the header structure to be tested |
7560 | * |
7561 | * @retval 1 (true) if the @a header is an instance of header accept_encoding |
7562 | * @retval 0 (false) otherwise |
7563 | * |
7564 | */ |
7565 | #if SU_HAVE_INLINE1 |
7566 | su_inlinestatic inline int sip_is_accept_encoding(sip_header_t const *header) |
7567 | { |
7568 | return header && header->sh_classsh_common->h_class->hc_hash == sip_accept_encoding_hash; |
7569 | } |
7570 | #else |
7571 | int sip_is_accept_encoding(sip_header_t const *header); |
7572 | #endif |
7573 | |
7574 | #define sip_accept_encoding_p(h)sip_is_accept_encoding((h)) sip_is_accept_encoding((h)) |
7575 | |
7576 | |
7577 | /**Duplicate a list of @ref sip_accept_encoding "Accept-Encoding header" header structures #sip_accept_encoding_t. |
7578 | * |
7579 | * Duplicate a header |
7580 | * structure @a hdr. If the header structure @a hdr |
7581 | * contains a reference (@c hdr->x_next) to a list of |
7582 | * headers, all the headers in the list are duplicated, too. |
7583 | * |
7584 | * @param home memory home used to allocate new structure |
7585 | * @param hdr header structure to be duplicated |
7586 | * |
7587 | * When duplicating, all parameter lists and non-constant |
7588 | * strings attached to the header are copied, too. The |
7589 | * function uses given memory @a home to allocate all the |
7590 | * memory areas used to copy the header. |
7591 | * |
7592 | * @par Example |
7593 | * @code |
7594 | * |
7595 | * accept_encoding = sip_accept_encoding_dup(home, sip->sip_accept_encoding); |
7596 | * |
7597 | * @endcode |
7598 | * |
7599 | * @return |
7600 | * A pointer to the |
7601 | * newly duplicated #sip_accept_encoding_t header structure, or NULL |
7602 | * upon an error. |
7603 | * |
7604 | */ |
7605 | #if SU_HAVE_INLINE1 |
7606 | su_inlinestatic inline |
7607 | #endif |
7608 | sip_accept_encoding_t *sip_accept_encoding_dup(su_home_t *home, sip_accept_encoding_t const *hdr) |
7609 | __attribute__((__malloc__)); |
7610 | |
7611 | #if SU_HAVE_INLINE1 |
7612 | su_inlinestatic inline |
7613 | sip_accept_encoding_t *sip_accept_encoding_dup(su_home_t *home, sip_accept_encoding_t const *hdr) |
7614 | { |
7615 | return (sip_accept_encoding_t *) |
7616 | msg_header_dup_as(home, sip_accept_encoding_class, (msg_header_t const *)hdr); |
7617 | } |
7618 | #endif |
7619 | |
7620 | /**Copy a list of @ref sip_accept_encoding "Accept-Encoding header" header structures #sip_accept_encoding_t. |
7621 | * |
7622 | * The function sip_accept_encoding_copy() copies a header structure @a |
7623 | * hdr. If the header structure @a hdr contains a reference (@c |
7624 | * hdr->h_next) to a list of headers, all the headers in that |
7625 | * list are copied, too. The function uses given memory @a home |
7626 | * to allocate all the memory areas used to copy the list of header |
7627 | * structure @a hdr. |
7628 | * |
7629 | * @param home memory home used to allocate new structure |
7630 | * @param hdr pointer to the header structure to be copied |
7631 | * |
7632 | * When copying, only the header structure and parameter lists attached to |
7633 | * it are duplicated. The new header structure retains all the references to |
7634 | * the strings within the old @a hdr header, including the encoding of the |
7635 | * old header, if present. |
7636 | * |
7637 | * @par Example |
7638 | * @code |
7639 | * |
7640 | * accept_encoding = sip_accept_encoding_copy(home, sip->sip_accept_encoding); |
7641 | * |
7642 | * @endcode |
7643 | * |
7644 | * @return |
7645 | * A pointer to newly copied header structure, or NULL upon an error. |
7646 | * |
7647 | */ |
7648 | #if SU_HAVE_INLINE1 |
7649 | su_inlinestatic inline |
7650 | #endif |
7651 | sip_accept_encoding_t *sip_accept_encoding_copy(su_home_t *home, sip_accept_encoding_t const *hdr) |
7652 | __attribute__((__malloc__)); |
7653 | |
7654 | #if SU_HAVE_INLINE1 |
7655 | su_inlinestatic inline |
7656 | sip_accept_encoding_t *sip_accept_encoding_copy(su_home_t *home, sip_accept_encoding_t const *hdr) |
7657 | { |
7658 | return (sip_accept_encoding_t *) |
7659 | msg_header_copy_as(home, sip_accept_encoding_class, (msg_header_t const *)hdr); |
7660 | } |
7661 | #endif |
7662 | |
7663 | /**Make a @ref sip_accept_encoding "Accept-Encoding header" structure #sip_accept_encoding_t. |
7664 | * |
7665 | * The function sip_accept_encoding_make() makes a new |
7666 | * #sip_accept_encoding_t header structure. It allocates a new |
7667 | * header structure, and decodes the string @a s as the |
7668 | * value of the structure. |
7669 | * |
7670 | * @param home memory home used to allocate new header structure. |
7671 | * @param s string to be decoded as value of the new header structure |
7672 | * |
7673 | * @return |
7674 | * A pointer to newly maked #sip_accept_encoding_t header structure, or NULL upon an |
7675 | * error. |
7676 | * |
7677 | */ |
7678 | #if SU_HAVE_INLINE1 |
7679 | su_inlinestatic inline |
7680 | #endif |
7681 | sip_accept_encoding_t *sip_accept_encoding_make(su_home_t *home, char const *s) |
7682 | __attribute__((__malloc__)); |
7683 | |
7684 | #if SU_HAVE_INLINE1 |
7685 | su_inlinestatic inline sip_accept_encoding_t *sip_accept_encoding_make(su_home_t *home, char const *s) |
7686 | { |
7687 | return (sip_accept_encoding_t *)sip_header_make(home, sip_accept_encoding_class, s)((sip_header_t *)msg_header_make((home), (sip_accept_encoding_class ), (s))); |
7688 | } |
7689 | #endif |
7690 | |
7691 | /**Make a @ref sip_accept_encoding "Accept-Encoding header" from formatting result. |
7692 | * |
7693 | * Make a new #sip_accept_encoding_t object using formatting result as its value. |
7694 | * The function first prints the arguments according to the format @a fmt |
7695 | * specified. Then it allocates a new header structure, and parses the |
7696 | * formatting result to the structure #sip_accept_encoding_t. |
7697 | * |
7698 | * @param home memory home used to allocate new header structure. |
7699 | * @param fmt string used as a printf()-style format |
7700 | * @param ... argument list for format |
7701 | * |
7702 | * @return |
7703 | * A pointer to newly |
7704 | * makes header structure, or NULL upon an error. |
7705 | * |
7706 | * @HIDE |
7707 | * |
7708 | */ |
7709 | #if SU_HAVE_INLINE1 |
7710 | su_inlinestatic inline |
7711 | #endif |
7712 | sip_accept_encoding_t *sip_accept_encoding_format(su_home_t *home, char const *fmt, ...) |
7713 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
7714 | |
7715 | #if SU_HAVE_INLINE1 |
7716 | su_inlinestatic inline sip_accept_encoding_t *sip_accept_encoding_format(su_home_t *home, char const *fmt, ...) |
7717 | { |
7718 | sip_header_t *h; |
7719 | va_list ap; |
7720 | |
7721 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
7722 | h = sip_header_vformat(home, sip_accept_encoding_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_accept_encoding_class ), (fmt), (ap))); |
7723 | va_end(ap)__builtin_va_end(ap); |
7724 | |
7725 | return (sip_accept_encoding_t *)h; |
7726 | } |
7727 | #endif |
7728 | |
7729 | /** @} */ |
7730 | |
7731 | /**@addtogroup sip_accept_language |
7732 | * @{ |
7733 | */ |
7734 | |
7735 | /** Parse a SIP @ref sip_accept_language "Accept-Language header". @internal */ |
7736 | SOFIAPUBFUN issize_t sip_accept_language_d(su_home_t *, msg_header_t *, |
7737 | char *s, isize_t slen); |
7738 | |
7739 | /** Print a SIP @ref sip_accept_language "Accept-Language header". @internal */ |
7740 | SOFIAPUBFUN issize_t sip_accept_language_e(char b[], isize_t bsiz, |
7741 | msg_header_t const *h, int flags); |
7742 | |
7743 | /**Access a SIP @ref sip_accept_language "Accept-Language header" |
7744 | * structure #sip_accept_language_t from #sip_t. |
7745 | * |
7746 | */ |
7747 | #define sip_accept_language(sip)((sip_accept_language_t *)msg_header_access((msg_pub_t*)(sip) , sip_accept_language_class)) \ |
7748 | ((sip_accept_language_t *)msg_header_access((msg_pub_t*)(sip), sip_accept_language_class)) |
7749 | |
7750 | /**Initializer for structure #sip_accept_language_t. |
7751 | * |
7752 | * A static #sip_accept_language_t structure for |
7753 | * @ref sip_accept_language "Accept-Language header" must be initialized with |
7754 | * the SIP_ACCEPT_LANGUAGE_INIT() macro. |
7755 | * For instance, |
7756 | * @code |
7757 | * |
7758 | * sip_accept_language_t sip_accept_language = SIP_ACCEPT_LANGUAGE_INIT; |
7759 | * |
7760 | * @endcode |
7761 | * @HI |
7762 | * |
7763 | */ |
7764 | #define SIP_ACCEPT_LANGUAGE_INIT(){{{ 0, 0, sip_accept_language_class }}} SIP_HDR_INIT(accept_language){{{ 0, 0, sip_accept_language_class }}} |
7765 | |
7766 | /**Initialize a structure #sip_accept_language_t. |
7767 | * |
7768 | * An #sip_accept_language_t structure for |
7769 | * @ref sip_accept_language "Accept-Language header" can be initialized with the |
7770 | * sip_accept_language_init() function/macro. For instance, |
7771 | * @code |
7772 | * |
7773 | * sip_accept_language_t sip_accept_language; |
7774 | * |
7775 | * sip_accept_language_init(&sip_accept_language); |
7776 | * |
7777 | * @endcode |
7778 | * @HI |
7779 | * |
7780 | */ |
7781 | #if SU_HAVE_INLINE1 |
7782 | su_inlinestatic inline sip_accept_language_t *sip_accept_language_init(sip_accept_language_t x[1]) |
7783 | { |
7784 | return SIP_HEADER_INIT(x, sip_accept_language_class, sizeof(sip_accept_language_t))((void)memset((x), 0, (sizeof(sip_accept_language_t))), (void )(((sip_common_t *)(x))->h_class = (sip_accept_language_class )), (x)); |
7785 | } |
7786 | #else |
7787 | #define sip_accept_language_init(x) \ |
7788 | SIP_HEADER_INIT(x, sip_accept_language_class, sizeof(sip_accept_language_t))((void)memset((x), 0, (sizeof(sip_accept_language_t))), (void )(((sip_common_t *)(x))->h_class = (sip_accept_language_class )), (x)) |
7789 | #endif |
7790 | |
7791 | /**Test if header object is instance of #sip_accept_language_t. |
7792 | * |
7793 | * Check if the header class is an instance of |
7794 | * @ref sip_accept_language "Accept-Language header" object and return true (nonzero), |
7795 | * otherwise return false (zero). |
7796 | * |
7797 | * @param header pointer to the header structure to be tested |
7798 | * |
7799 | * @retval 1 (true) if the @a header is an instance of header accept_language |
7800 | * @retval 0 (false) otherwise |
7801 | * |
7802 | */ |
7803 | #if SU_HAVE_INLINE1 |
7804 | su_inlinestatic inline int sip_is_accept_language(sip_header_t const *header) |
7805 | { |
7806 | return header && header->sh_classsh_common->h_class->hc_hash == sip_accept_language_hash; |
7807 | } |
7808 | #else |
7809 | int sip_is_accept_language(sip_header_t const *header); |
7810 | #endif |
7811 | |
7812 | #define sip_accept_language_p(h)sip_is_accept_language((h)) sip_is_accept_language((h)) |
7813 | |
7814 | |
7815 | /**Duplicate a list of @ref sip_accept_language "Accept-Language header" header structures #sip_accept_language_t. |
7816 | * |
7817 | * Duplicate a header |
7818 | * structure @a hdr. If the header structure @a hdr |
7819 | * contains a reference (@c hdr->x_next) to a list of |
7820 | * headers, all the headers in the list are duplicated, too. |
7821 | * |
7822 | * @param home memory home used to allocate new structure |
7823 | * @param hdr header structure to be duplicated |
7824 | * |
7825 | * When duplicating, all parameter lists and non-constant |
7826 | * strings attached to the header are copied, too. The |
7827 | * function uses given memory @a home to allocate all the |
7828 | * memory areas used to copy the header. |
7829 | * |
7830 | * @par Example |
7831 | * @code |
7832 | * |
7833 | * accept_language = sip_accept_language_dup(home, sip->sip_accept_language); |
7834 | * |
7835 | * @endcode |
7836 | * |
7837 | * @return |
7838 | * A pointer to the |
7839 | * newly duplicated #sip_accept_language_t header structure, or NULL |
7840 | * upon an error. |
7841 | * |
7842 | */ |
7843 | #if SU_HAVE_INLINE1 |
7844 | su_inlinestatic inline |
7845 | #endif |
7846 | sip_accept_language_t *sip_accept_language_dup(su_home_t *home, sip_accept_language_t const *hdr) |
7847 | __attribute__((__malloc__)); |
7848 | |
7849 | #if SU_HAVE_INLINE1 |
7850 | su_inlinestatic inline |
7851 | sip_accept_language_t *sip_accept_language_dup(su_home_t *home, sip_accept_language_t const *hdr) |
7852 | { |
7853 | return (sip_accept_language_t *) |
7854 | msg_header_dup_as(home, sip_accept_language_class, (msg_header_t const *)hdr); |
7855 | } |
7856 | #endif |
7857 | |
7858 | /**Copy a list of @ref sip_accept_language "Accept-Language header" header structures #sip_accept_language_t. |
7859 | * |
7860 | * The function sip_accept_language_copy() copies a header structure @a |
7861 | * hdr. If the header structure @a hdr contains a reference (@c |
7862 | * hdr->h_next) to a list of headers, all the headers in that |
7863 | * list are copied, too. The function uses given memory @a home |
7864 | * to allocate all the memory areas used to copy the list of header |
7865 | * structure @a hdr. |
7866 | * |
7867 | * @param home memory home used to allocate new structure |
7868 | * @param hdr pointer to the header structure to be copied |
7869 | * |
7870 | * When copying, only the header structure and parameter lists attached to |
7871 | * it are duplicated. The new header structure retains all the references to |
7872 | * the strings within the old @a hdr header, including the encoding of the |
7873 | * old header, if present. |
7874 | * |
7875 | * @par Example |
7876 | * @code |
7877 | * |
7878 | * accept_language = sip_accept_language_copy(home, sip->sip_accept_language); |
7879 | * |
7880 | * @endcode |
7881 | * |
7882 | * @return |
7883 | * A pointer to newly copied header structure, or NULL upon an error. |
7884 | * |
7885 | */ |
7886 | #if SU_HAVE_INLINE1 |
7887 | su_inlinestatic inline |
7888 | #endif |
7889 | sip_accept_language_t *sip_accept_language_copy(su_home_t *home, sip_accept_language_t const *hdr) |
7890 | __attribute__((__malloc__)); |
7891 | |
7892 | #if SU_HAVE_INLINE1 |
7893 | su_inlinestatic inline |
7894 | sip_accept_language_t *sip_accept_language_copy(su_home_t *home, sip_accept_language_t const *hdr) |
7895 | { |
7896 | return (sip_accept_language_t *) |
7897 | msg_header_copy_as(home, sip_accept_language_class, (msg_header_t const *)hdr); |
7898 | } |
7899 | #endif |
7900 | |
7901 | /**Make a @ref sip_accept_language "Accept-Language header" structure #sip_accept_language_t. |
7902 | * |
7903 | * The function sip_accept_language_make() makes a new |
7904 | * #sip_accept_language_t header structure. It allocates a new |
7905 | * header structure, and decodes the string @a s as the |
7906 | * value of the structure. |
7907 | * |
7908 | * @param home memory home used to allocate new header structure. |
7909 | * @param s string to be decoded as value of the new header structure |
7910 | * |
7911 | * @return |
7912 | * A pointer to newly maked #sip_accept_language_t header structure, or NULL upon an |
7913 | * error. |
7914 | * |
7915 | */ |
7916 | #if SU_HAVE_INLINE1 |
7917 | su_inlinestatic inline |
7918 | #endif |
7919 | sip_accept_language_t *sip_accept_language_make(su_home_t *home, char const *s) |
7920 | __attribute__((__malloc__)); |
7921 | |
7922 | #if SU_HAVE_INLINE1 |
7923 | su_inlinestatic inline sip_accept_language_t *sip_accept_language_make(su_home_t *home, char const *s) |
7924 | { |
7925 | return (sip_accept_language_t *)sip_header_make(home, sip_accept_language_class, s)((sip_header_t *)msg_header_make((home), (sip_accept_language_class ), (s))); |
7926 | } |
7927 | #endif |
7928 | |
7929 | /**Make a @ref sip_accept_language "Accept-Language header" from formatting result. |
7930 | * |
7931 | * Make a new #sip_accept_language_t object using formatting result as its value. |
7932 | * The function first prints the arguments according to the format @a fmt |
7933 | * specified. Then it allocates a new header structure, and parses the |
7934 | * formatting result to the structure #sip_accept_language_t. |
7935 | * |
7936 | * @param home memory home used to allocate new header structure. |
7937 | * @param fmt string used as a printf()-style format |
7938 | * @param ... argument list for format |
7939 | * |
7940 | * @return |
7941 | * A pointer to newly |
7942 | * makes header structure, or NULL upon an error. |
7943 | * |
7944 | * @HIDE |
7945 | * |
7946 | */ |
7947 | #if SU_HAVE_INLINE1 |
7948 | su_inlinestatic inline |
7949 | #endif |
7950 | sip_accept_language_t *sip_accept_language_format(su_home_t *home, char const *fmt, ...) |
7951 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
7952 | |
7953 | #if SU_HAVE_INLINE1 |
7954 | su_inlinestatic inline sip_accept_language_t *sip_accept_language_format(su_home_t *home, char const *fmt, ...) |
7955 | { |
7956 | sip_header_t *h; |
7957 | va_list ap; |
7958 | |
7959 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
7960 | h = sip_header_vformat(home, sip_accept_language_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_accept_language_class ), (fmt), (ap))); |
7961 | va_end(ap)__builtin_va_end(ap); |
7962 | |
7963 | return (sip_accept_language_t *)h; |
7964 | } |
7965 | #endif |
7966 | |
7967 | /** @} */ |
7968 | |
7969 | /**@addtogroup sip_allow |
7970 | * @{ |
7971 | */ |
7972 | |
7973 | /** Parse a SIP @ref sip_allow "Allow header". @internal */ |
7974 | SOFIAPUBFUN issize_t sip_allow_d(su_home_t *, msg_header_t *, |
7975 | char *s, isize_t slen); |
7976 | |
7977 | /** Print a SIP @ref sip_allow "Allow header". @internal */ |
7978 | SOFIAPUBFUN issize_t sip_allow_e(char b[], isize_t bsiz, |
7979 | msg_header_t const *h, int flags); |
7980 | |
7981 | /**Access a SIP @ref sip_allow "Allow header" |
7982 | * structure #sip_allow_t from #sip_t. |
7983 | * |
7984 | */ |
7985 | #define sip_allow(sip)((sip_allow_t *)msg_header_access((msg_pub_t*)(sip), sip_allow_class )) \ |
7986 | ((sip_allow_t *)msg_header_access((msg_pub_t*)(sip), sip_allow_class)) |
7987 | |
7988 | /**Initializer for structure #sip_allow_t. |
7989 | * |
7990 | * A static #sip_allow_t structure for |
7991 | * @ref sip_allow "Allow header" must be initialized with |
7992 | * the SIP_ALLOW_INIT() macro. |
7993 | * For instance, |
7994 | * @code |
7995 | * |
7996 | * sip_allow_t sip_allow = SIP_ALLOW_INIT; |
7997 | * |
7998 | * @endcode |
7999 | * @HI |
8000 | * |
8001 | */ |
8002 | #define SIP_ALLOW_INIT(){{{ 0, 0, sip_allow_class }}} SIP_HDR_INIT(allow){{{ 0, 0, sip_allow_class }}} |
8003 | |
8004 | /**Initialize a structure #sip_allow_t. |
8005 | * |
8006 | * An #sip_allow_t structure for |
8007 | * @ref sip_allow "Allow header" can be initialized with the |
8008 | * sip_allow_init() function/macro. For instance, |
8009 | * @code |
8010 | * |
8011 | * sip_allow_t sip_allow; |
8012 | * |
8013 | * sip_allow_init(&sip_allow); |
8014 | * |
8015 | * @endcode |
8016 | * @HI |
8017 | * |
8018 | */ |
8019 | #if SU_HAVE_INLINE1 |
8020 | su_inlinestatic inline sip_allow_t *sip_allow_init(sip_allow_t x[1]) |
8021 | { |
8022 | return SIP_HEADER_INIT(x, sip_allow_class, sizeof(sip_allow_t))((void)memset((x), 0, (sizeof(sip_allow_t))), (void)(((sip_common_t *)(x))->h_class = (sip_allow_class)), (x)); |
8023 | } |
8024 | #else |
8025 | #define sip_allow_init(x) \ |
8026 | SIP_HEADER_INIT(x, sip_allow_class, sizeof(sip_allow_t))((void)memset((x), 0, (sizeof(sip_allow_t))), (void)(((sip_common_t *)(x))->h_class = (sip_allow_class)), (x)) |
8027 | #endif |
8028 | |
8029 | /**Test if header object is instance of #sip_allow_t. |
8030 | * |
8031 | * Check if the header class is an instance of |
8032 | * @ref sip_allow "Allow header" object and return true (nonzero), |
8033 | * otherwise return false (zero). |
8034 | * |
8035 | * @param header pointer to the header structure to be tested |
8036 | * |
8037 | * @retval 1 (true) if the @a header is an instance of header allow |
8038 | * @retval 0 (false) otherwise |
8039 | * |
8040 | */ |
8041 | #if SU_HAVE_INLINE1 |
8042 | su_inlinestatic inline int sip_is_allow(sip_header_t const *header) |
8043 | { |
8044 | return header && header->sh_classsh_common->h_class->hc_hash == sip_allow_hash; |
8045 | } |
8046 | #else |
8047 | int sip_is_allow(sip_header_t const *header); |
8048 | #endif |
8049 | |
8050 | #define sip_allow_p(h)sip_is_allow((h)) sip_is_allow((h)) |
8051 | |
8052 | |
8053 | /**Duplicate a list of @ref sip_allow "Allow header" header structures #sip_allow_t. |
8054 | * |
8055 | * Duplicate a header |
8056 | * structure @a hdr. If the header structure @a hdr |
8057 | * contains a reference (@c hdr->x_next) to a list of |
8058 | * headers, all the headers in the list are duplicated, too. |
8059 | * |
8060 | * @param home memory home used to allocate new structure |
8061 | * @param hdr header structure to be duplicated |
8062 | * |
8063 | * When duplicating, all parameter lists and non-constant |
8064 | * strings attached to the header are copied, too. The |
8065 | * function uses given memory @a home to allocate all the |
8066 | * memory areas used to copy the header. |
8067 | * |
8068 | * @par Example |
8069 | * @code |
8070 | * |
8071 | * allow = sip_allow_dup(home, sip->sip_allow); |
8072 | * |
8073 | * @endcode |
8074 | * |
8075 | * @return |
8076 | * A pointer to the |
8077 | * newly duplicated #sip_allow_t header structure, or NULL |
8078 | * upon an error. |
8079 | * |
8080 | */ |
8081 | #if SU_HAVE_INLINE1 |
8082 | su_inlinestatic inline |
8083 | #endif |
8084 | sip_allow_t *sip_allow_dup(su_home_t *home, sip_allow_t const *hdr) |
8085 | __attribute__((__malloc__)); |
8086 | |
8087 | #if SU_HAVE_INLINE1 |
8088 | su_inlinestatic inline |
8089 | sip_allow_t *sip_allow_dup(su_home_t *home, sip_allow_t const *hdr) |
8090 | { |
8091 | return (sip_allow_t *) |
8092 | msg_header_dup_as(home, sip_allow_class, (msg_header_t const *)hdr); |
8093 | } |
8094 | #endif |
8095 | |
8096 | /**Copy a list of @ref sip_allow "Allow header" header structures #sip_allow_t. |
8097 | * |
8098 | * The function sip_allow_copy() copies a header structure @a |
8099 | * hdr. If the header structure @a hdr contains a reference (@c |
8100 | * hdr->h_next) to a list of headers, all the headers in that |
8101 | * list are copied, too. The function uses given memory @a home |
8102 | * to allocate all the memory areas used to copy the list of header |
8103 | * structure @a hdr. |
8104 | * |
8105 | * @param home memory home used to allocate new structure |
8106 | * @param hdr pointer to the header structure to be copied |
8107 | * |
8108 | * When copying, only the header structure and parameter lists attached to |
8109 | * it are duplicated. The new header structure retains all the references to |
8110 | * the strings within the old @a hdr header, including the encoding of the |
8111 | * old header, if present. |
8112 | * |
8113 | * @par Example |
8114 | * @code |
8115 | * |
8116 | * allow = sip_allow_copy(home, sip->sip_allow); |
8117 | * |
8118 | * @endcode |
8119 | * |
8120 | * @return |
8121 | * A pointer to newly copied header structure, or NULL upon an error. |
8122 | * |
8123 | */ |
8124 | #if SU_HAVE_INLINE1 |
8125 | su_inlinestatic inline |
8126 | #endif |
8127 | sip_allow_t *sip_allow_copy(su_home_t *home, sip_allow_t const *hdr) |
8128 | __attribute__((__malloc__)); |
8129 | |
8130 | #if SU_HAVE_INLINE1 |
8131 | su_inlinestatic inline |
8132 | sip_allow_t *sip_allow_copy(su_home_t *home, sip_allow_t const *hdr) |
8133 | { |
8134 | return (sip_allow_t *) |
8135 | msg_header_copy_as(home, sip_allow_class, (msg_header_t const *)hdr); |
8136 | } |
8137 | #endif |
8138 | |
8139 | /**Make a @ref sip_allow "Allow header" structure #sip_allow_t. |
8140 | * |
8141 | * The function sip_allow_make() makes a new |
8142 | * #sip_allow_t header structure. It allocates a new |
8143 | * header structure, and decodes the string @a s as the |
8144 | * value of the structure. |
8145 | * |
8146 | * @param home memory home used to allocate new header structure. |
8147 | * @param s string to be decoded as value of the new header structure |
8148 | * |
8149 | * @return |
8150 | * A pointer to newly maked #sip_allow_t header structure, or NULL upon an |
8151 | * error. |
8152 | * |
8153 | */ |
8154 | #if SU_HAVE_INLINE1 |
8155 | su_inlinestatic inline |
8156 | #endif |
8157 | sip_allow_t *sip_allow_make(su_home_t *home, char const *s) |
8158 | __attribute__((__malloc__)); |
8159 | |
8160 | #if SU_HAVE_INLINE1 |
8161 | su_inlinestatic inline sip_allow_t *sip_allow_make(su_home_t *home, char const *s) |
8162 | { |
8163 | return (sip_allow_t *)sip_header_make(home, sip_allow_class, s)((sip_header_t *)msg_header_make((home), (sip_allow_class), ( s))); |
8164 | } |
8165 | #endif |
8166 | |
8167 | /**Make a @ref sip_allow "Allow header" from formatting result. |
8168 | * |
8169 | * Make a new #sip_allow_t object using formatting result as its value. |
8170 | * The function first prints the arguments according to the format @a fmt |
8171 | * specified. Then it allocates a new header structure, and parses the |
8172 | * formatting result to the structure #sip_allow_t. |
8173 | * |
8174 | * @param home memory home used to allocate new header structure. |
8175 | * @param fmt string used as a printf()-style format |
8176 | * @param ... argument list for format |
8177 | * |
8178 | * @return |
8179 | * A pointer to newly |
8180 | * makes header structure, or NULL upon an error. |
8181 | * |
8182 | * @HIDE |
8183 | * |
8184 | */ |
8185 | #if SU_HAVE_INLINE1 |
8186 | su_inlinestatic inline |
8187 | #endif |
8188 | sip_allow_t *sip_allow_format(su_home_t *home, char const *fmt, ...) |
8189 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
8190 | |
8191 | #if SU_HAVE_INLINE1 |
8192 | su_inlinestatic inline sip_allow_t *sip_allow_format(su_home_t *home, char const *fmt, ...) |
8193 | { |
8194 | sip_header_t *h; |
8195 | va_list ap; |
8196 | |
8197 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
8198 | h = sip_header_vformat(home, sip_allow_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_allow_class) , (fmt), (ap))); |
8199 | va_end(ap)__builtin_va_end(ap); |
8200 | |
8201 | return (sip_allow_t *)h; |
8202 | } |
8203 | #endif |
8204 | |
8205 | /** @} */ |
8206 | |
8207 | /**@addtogroup sip_require |
8208 | * @{ |
8209 | */ |
8210 | |
8211 | /** Parse a SIP @ref sip_require "Require header". @internal */ |
8212 | SOFIAPUBFUN issize_t sip_require_d(su_home_t *, msg_header_t *, |
8213 | char *s, isize_t slen); |
8214 | |
8215 | /** Print a SIP @ref sip_require "Require header". @internal */ |
8216 | SOFIAPUBFUN issize_t sip_require_e(char b[], isize_t bsiz, |
8217 | msg_header_t const *h, int flags); |
8218 | |
8219 | /**Access a SIP @ref sip_require "Require header" |
8220 | * structure #sip_require_t from #sip_t. |
8221 | * |
8222 | */ |
8223 | #define sip_require(sip)((sip_require_t *)msg_header_access((msg_pub_t*)(sip), sip_require_class )) \ |
8224 | ((sip_require_t *)msg_header_access((msg_pub_t*)(sip), sip_require_class)) |
8225 | |
8226 | /**Initializer for structure #sip_require_t. |
8227 | * |
8228 | * A static #sip_require_t structure for |
8229 | * @ref sip_require "Require header" must be initialized with |
8230 | * the SIP_REQUIRE_INIT() macro. |
8231 | * For instance, |
8232 | * @code |
8233 | * |
8234 | * sip_require_t sip_require = SIP_REQUIRE_INIT; |
8235 | * |
8236 | * @endcode |
8237 | * @HI |
8238 | * |
8239 | */ |
8240 | #define SIP_REQUIRE_INIT(){{{ 0, 0, sip_require_class }}} SIP_HDR_INIT(require){{{ 0, 0, sip_require_class }}} |
8241 | |
8242 | /**Initialize a structure #sip_require_t. |
8243 | * |
8244 | * An #sip_require_t structure for |
8245 | * @ref sip_require "Require header" can be initialized with the |
8246 | * sip_require_init() function/macro. For instance, |
8247 | * @code |
8248 | * |
8249 | * sip_require_t sip_require; |
8250 | * |
8251 | * sip_require_init(&sip_require); |
8252 | * |
8253 | * @endcode |
8254 | * @HI |
8255 | * |
8256 | */ |
8257 | #if SU_HAVE_INLINE1 |
8258 | su_inlinestatic inline sip_require_t *sip_require_init(sip_require_t x[1]) |
8259 | { |
8260 | return SIP_HEADER_INIT(x, sip_require_class, sizeof(sip_require_t))((void)memset((x), 0, (sizeof(sip_require_t))), (void)(((sip_common_t *)(x))->h_class = (sip_require_class)), (x)); |
8261 | } |
8262 | #else |
8263 | #define sip_require_init(x) \ |
8264 | SIP_HEADER_INIT(x, sip_require_class, sizeof(sip_require_t))((void)memset((x), 0, (sizeof(sip_require_t))), (void)(((sip_common_t *)(x))->h_class = (sip_require_class)), (x)) |
8265 | #endif |
8266 | |
8267 | /**Test if header object is instance of #sip_require_t. |
8268 | * |
8269 | * Check if the header class is an instance of |
8270 | * @ref sip_require "Require header" object and return true (nonzero), |
8271 | * otherwise return false (zero). |
8272 | * |
8273 | * @param header pointer to the header structure to be tested |
8274 | * |
8275 | * @retval 1 (true) if the @a header is an instance of header require |
8276 | * @retval 0 (false) otherwise |
8277 | * |
8278 | */ |
8279 | #if SU_HAVE_INLINE1 |
8280 | su_inlinestatic inline int sip_is_require(sip_header_t const *header) |
8281 | { |
8282 | return header && header->sh_classsh_common->h_class->hc_hash == sip_require_hash; |
8283 | } |
8284 | #else |
8285 | int sip_is_require(sip_header_t const *header); |
8286 | #endif |
8287 | |
8288 | #define sip_require_p(h)sip_is_require((h)) sip_is_require((h)) |
8289 | |
8290 | |
8291 | /**Duplicate a list of @ref sip_require "Require header" header structures #sip_require_t. |
8292 | * |
8293 | * Duplicate a header |
8294 | * structure @a hdr. If the header structure @a hdr |
8295 | * contains a reference (@c hdr->x_next) to a list of |
8296 | * headers, all the headers in the list are duplicated, too. |
8297 | * |
8298 | * @param home memory home used to allocate new structure |
8299 | * @param hdr header structure to be duplicated |
8300 | * |
8301 | * When duplicating, all parameter lists and non-constant |
8302 | * strings attached to the header are copied, too. The |
8303 | * function uses given memory @a home to allocate all the |
8304 | * memory areas used to copy the header. |
8305 | * |
8306 | * @par Example |
8307 | * @code |
8308 | * |
8309 | * require = sip_require_dup(home, sip->sip_require); |
8310 | * |
8311 | * @endcode |
8312 | * |
8313 | * @return |
8314 | * A pointer to the |
8315 | * newly duplicated #sip_require_t header structure, or NULL |
8316 | * upon an error. |
8317 | * |
8318 | */ |
8319 | #if SU_HAVE_INLINE1 |
8320 | su_inlinestatic inline |
8321 | #endif |
8322 | sip_require_t *sip_require_dup(su_home_t *home, sip_require_t const *hdr) |
8323 | __attribute__((__malloc__)); |
8324 | |
8325 | #if SU_HAVE_INLINE1 |
8326 | su_inlinestatic inline |
8327 | sip_require_t *sip_require_dup(su_home_t *home, sip_require_t const *hdr) |
8328 | { |
8329 | return (sip_require_t *) |
8330 | msg_header_dup_as(home, sip_require_class, (msg_header_t const *)hdr); |
8331 | } |
8332 | #endif |
8333 | |
8334 | /**Copy a list of @ref sip_require "Require header" header structures #sip_require_t. |
8335 | * |
8336 | * The function sip_require_copy() copies a header structure @a |
8337 | * hdr. If the header structure @a hdr contains a reference (@c |
8338 | * hdr->h_next) to a list of headers, all the headers in that |
8339 | * list are copied, too. The function uses given memory @a home |
8340 | * to allocate all the memory areas used to copy the list of header |
8341 | * structure @a hdr. |
8342 | * |
8343 | * @param home memory home used to allocate new structure |
8344 | * @param hdr pointer to the header structure to be copied |
8345 | * |
8346 | * When copying, only the header structure and parameter lists attached to |
8347 | * it are duplicated. The new header structure retains all the references to |
8348 | * the strings within the old @a hdr header, including the encoding of the |
8349 | * old header, if present. |
8350 | * |
8351 | * @par Example |
8352 | * @code |
8353 | * |
8354 | * require = sip_require_copy(home, sip->sip_require); |
8355 | * |
8356 | * @endcode |
8357 | * |
8358 | * @return |
8359 | * A pointer to newly copied header structure, or NULL upon an error. |
8360 | * |
8361 | */ |
8362 | #if SU_HAVE_INLINE1 |
8363 | su_inlinestatic inline |
8364 | #endif |
8365 | sip_require_t *sip_require_copy(su_home_t *home, sip_require_t const *hdr) |
8366 | __attribute__((__malloc__)); |
8367 | |
8368 | #if SU_HAVE_INLINE1 |
8369 | su_inlinestatic inline |
8370 | sip_require_t *sip_require_copy(su_home_t *home, sip_require_t const *hdr) |
8371 | { |
8372 | return (sip_require_t *) |
8373 | msg_header_copy_as(home, sip_require_class, (msg_header_t const *)hdr); |
8374 | } |
8375 | #endif |
8376 | |
8377 | /**Make a @ref sip_require "Require header" structure #sip_require_t. |
8378 | * |
8379 | * The function sip_require_make() makes a new |
8380 | * #sip_require_t header structure. It allocates a new |
8381 | * header structure, and decodes the string @a s as the |
8382 | * value of the structure. |
8383 | * |
8384 | * @param home memory home used to allocate new header structure. |
8385 | * @param s string to be decoded as value of the new header structure |
8386 | * |
8387 | * @return |
8388 | * A pointer to newly maked #sip_require_t header structure, or NULL upon an |
8389 | * error. |
8390 | * |
8391 | */ |
8392 | #if SU_HAVE_INLINE1 |
8393 | su_inlinestatic inline |
8394 | #endif |
8395 | sip_require_t *sip_require_make(su_home_t *home, char const *s) |
8396 | __attribute__((__malloc__)); |
8397 | |
8398 | #if SU_HAVE_INLINE1 |
8399 | su_inlinestatic inline sip_require_t *sip_require_make(su_home_t *home, char const *s) |
8400 | { |
8401 | return (sip_require_t *)sip_header_make(home, sip_require_class, s)((sip_header_t *)msg_header_make((home), (sip_require_class), (s))); |
8402 | } |
8403 | #endif |
8404 | |
8405 | /**Make a @ref sip_require "Require header" from formatting result. |
8406 | * |
8407 | * Make a new #sip_require_t object using formatting result as its value. |
8408 | * The function first prints the arguments according to the format @a fmt |
8409 | * specified. Then it allocates a new header structure, and parses the |
8410 | * formatting result to the structure #sip_require_t. |
8411 | * |
8412 | * @param home memory home used to allocate new header structure. |
8413 | * @param fmt string used as a printf()-style format |
8414 | * @param ... argument list for format |
8415 | * |
8416 | * @return |
8417 | * A pointer to newly |
8418 | * makes header structure, or NULL upon an error. |
8419 | * |
8420 | * @HIDE |
8421 | * |
8422 | */ |
8423 | #if SU_HAVE_INLINE1 |
8424 | su_inlinestatic inline |
8425 | #endif |
8426 | sip_require_t *sip_require_format(su_home_t *home, char const *fmt, ...) |
8427 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
8428 | |
8429 | #if SU_HAVE_INLINE1 |
8430 | su_inlinestatic inline sip_require_t *sip_require_format(su_home_t *home, char const *fmt, ...) |
8431 | { |
8432 | sip_header_t *h; |
8433 | va_list ap; |
8434 | |
8435 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
8436 | h = sip_header_vformat(home, sip_require_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_require_class ), (fmt), (ap))); |
8437 | va_end(ap)__builtin_va_end(ap); |
8438 | |
8439 | return (sip_require_t *)h; |
8440 | } |
8441 | #endif |
8442 | |
8443 | /** @} */ |
8444 | |
8445 | /**@addtogroup sip_supported |
8446 | * @{ |
8447 | */ |
8448 | |
8449 | /** Parse a SIP @ref sip_supported "Supported header". @internal */ |
8450 | SOFIAPUBFUN issize_t sip_supported_d(su_home_t *, msg_header_t *, |
8451 | char *s, isize_t slen); |
8452 | |
8453 | /** Print a SIP @ref sip_supported "Supported header". @internal */ |
8454 | SOFIAPUBFUN issize_t sip_supported_e(char b[], isize_t bsiz, |
8455 | msg_header_t const *h, int flags); |
8456 | |
8457 | /**Access a SIP @ref sip_supported "Supported header" |
8458 | * structure #sip_supported_t from #sip_t. |
8459 | * |
8460 | */ |
8461 | #define sip_supported(sip)((sip_supported_t *)msg_header_access((msg_pub_t*)(sip), sip_supported_class )) \ |
8462 | ((sip_supported_t *)msg_header_access((msg_pub_t*)(sip), sip_supported_class)) |
8463 | |
8464 | /**Initializer for structure #sip_supported_t. |
8465 | * |
8466 | * A static #sip_supported_t structure for |
8467 | * @ref sip_supported "Supported header" must be initialized with |
8468 | * the SIP_SUPPORTED_INIT() macro. |
8469 | * For instance, |
8470 | * @code |
8471 | * |
8472 | * sip_supported_t sip_supported = SIP_SUPPORTED_INIT; |
8473 | * |
8474 | * @endcode |
8475 | * @HI |
8476 | * |
8477 | */ |
8478 | #define SIP_SUPPORTED_INIT(){{{ 0, 0, sip_supported_class }}} SIP_HDR_INIT(supported){{{ 0, 0, sip_supported_class }}} |
8479 | |
8480 | /**Initialize a structure #sip_supported_t. |
8481 | * |
8482 | * An #sip_supported_t structure for |
8483 | * @ref sip_supported "Supported header" can be initialized with the |
8484 | * sip_supported_init() function/macro. For instance, |
8485 | * @code |
8486 | * |
8487 | * sip_supported_t sip_supported; |
8488 | * |
8489 | * sip_supported_init(&sip_supported); |
8490 | * |
8491 | * @endcode |
8492 | * @HI |
8493 | * |
8494 | */ |
8495 | #if SU_HAVE_INLINE1 |
8496 | su_inlinestatic inline sip_supported_t *sip_supported_init(sip_supported_t x[1]) |
8497 | { |
8498 | return SIP_HEADER_INIT(x, sip_supported_class, sizeof(sip_supported_t))((void)memset((x), 0, (sizeof(sip_supported_t))), (void)(((sip_common_t *)(x))->h_class = (sip_supported_class)), (x)); |
8499 | } |
8500 | #else |
8501 | #define sip_supported_init(x) \ |
8502 | SIP_HEADER_INIT(x, sip_supported_class, sizeof(sip_supported_t))((void)memset((x), 0, (sizeof(sip_supported_t))), (void)(((sip_common_t *)(x))->h_class = (sip_supported_class)), (x)) |
8503 | #endif |
8504 | |
8505 | /**Test if header object is instance of #sip_supported_t. |
8506 | * |
8507 | * Check if the header class is an instance of |
8508 | * @ref sip_supported "Supported header" object and return true (nonzero), |
8509 | * otherwise return false (zero). |
8510 | * |
8511 | * @param header pointer to the header structure to be tested |
8512 | * |
8513 | * @retval 1 (true) if the @a header is an instance of header supported |
8514 | * @retval 0 (false) otherwise |
8515 | * |
8516 | */ |
8517 | #if SU_HAVE_INLINE1 |
8518 | su_inlinestatic inline int sip_is_supported(sip_header_t const *header) |
8519 | { |
8520 | return header && header->sh_classsh_common->h_class->hc_hash == sip_supported_hash; |
8521 | } |
8522 | #else |
8523 | int sip_is_supported(sip_header_t const *header); |
8524 | #endif |
8525 | |
8526 | #define sip_supported_p(h)sip_is_supported((h)) sip_is_supported((h)) |
8527 | |
8528 | |
8529 | /**Duplicate a list of @ref sip_supported "Supported header" header structures #sip_supported_t. |
8530 | * |
8531 | * Duplicate a header |
8532 | * structure @a hdr. If the header structure @a hdr |
8533 | * contains a reference (@c hdr->x_next) to a list of |
8534 | * headers, all the headers in the list are duplicated, too. |
8535 | * |
8536 | * @param home memory home used to allocate new structure |
8537 | * @param hdr header structure to be duplicated |
8538 | * |
8539 | * When duplicating, all parameter lists and non-constant |
8540 | * strings attached to the header are copied, too. The |
8541 | * function uses given memory @a home to allocate all the |
8542 | * memory areas used to copy the header. |
8543 | * |
8544 | * @par Example |
8545 | * @code |
8546 | * |
8547 | * supported = sip_supported_dup(home, sip->sip_supported); |
8548 | * |
8549 | * @endcode |
8550 | * |
8551 | * @return |
8552 | * A pointer to the |
8553 | * newly duplicated #sip_supported_t header structure, or NULL |
8554 | * upon an error. |
8555 | * |
8556 | */ |
8557 | #if SU_HAVE_INLINE1 |
8558 | su_inlinestatic inline |
8559 | #endif |
8560 | sip_supported_t *sip_supported_dup(su_home_t *home, sip_supported_t const *hdr) |
8561 | __attribute__((__malloc__)); |
8562 | |
8563 | #if SU_HAVE_INLINE1 |
8564 | su_inlinestatic inline |
8565 | sip_supported_t *sip_supported_dup(su_home_t *home, sip_supported_t const *hdr) |
8566 | { |
8567 | return (sip_supported_t *) |
8568 | msg_header_dup_as(home, sip_supported_class, (msg_header_t const *)hdr); |
8569 | } |
8570 | #endif |
8571 | |
8572 | /**Copy a list of @ref sip_supported "Supported header" header structures #sip_supported_t. |
8573 | * |
8574 | * The function sip_supported_copy() copies a header structure @a |
8575 | * hdr. If the header structure @a hdr contains a reference (@c |
8576 | * hdr->h_next) to a list of headers, all the headers in that |
8577 | * list are copied, too. The function uses given memory @a home |
8578 | * to allocate all the memory areas used to copy the list of header |
8579 | * structure @a hdr. |
8580 | * |
8581 | * @param home memory home used to allocate new structure |
8582 | * @param hdr pointer to the header structure to be copied |
8583 | * |
8584 | * When copying, only the header structure and parameter lists attached to |
8585 | * it are duplicated. The new header structure retains all the references to |
8586 | * the strings within the old @a hdr header, including the encoding of the |
8587 | * old header, if present. |
8588 | * |
8589 | * @par Example |
8590 | * @code |
8591 | * |
8592 | * supported = sip_supported_copy(home, sip->sip_supported); |
8593 | * |
8594 | * @endcode |
8595 | * |
8596 | * @return |
8597 | * A pointer to newly copied header structure, or NULL upon an error. |
8598 | * |
8599 | */ |
8600 | #if SU_HAVE_INLINE1 |
8601 | su_inlinestatic inline |
8602 | #endif |
8603 | sip_supported_t *sip_supported_copy(su_home_t *home, sip_supported_t const *hdr) |
8604 | __attribute__((__malloc__)); |
8605 | |
8606 | #if SU_HAVE_INLINE1 |
8607 | su_inlinestatic inline |
8608 | sip_supported_t *sip_supported_copy(su_home_t *home, sip_supported_t const *hdr) |
8609 | { |
8610 | return (sip_supported_t *) |
8611 | msg_header_copy_as(home, sip_supported_class, (msg_header_t const *)hdr); |
8612 | } |
8613 | #endif |
8614 | |
8615 | /**Make a @ref sip_supported "Supported header" structure #sip_supported_t. |
8616 | * |
8617 | * The function sip_supported_make() makes a new |
8618 | * #sip_supported_t header structure. It allocates a new |
8619 | * header structure, and decodes the string @a s as the |
8620 | * value of the structure. |
8621 | * |
8622 | * @param home memory home used to allocate new header structure. |
8623 | * @param s string to be decoded as value of the new header structure |
8624 | * |
8625 | * @return |
8626 | * A pointer to newly maked #sip_supported_t header structure, or NULL upon an |
8627 | * error. |
8628 | * |
8629 | */ |
8630 | #if SU_HAVE_INLINE1 |
8631 | su_inlinestatic inline |
8632 | #endif |
8633 | sip_supported_t *sip_supported_make(su_home_t *home, char const *s) |
8634 | __attribute__((__malloc__)); |
8635 | |
8636 | #if SU_HAVE_INLINE1 |
8637 | su_inlinestatic inline sip_supported_t *sip_supported_make(su_home_t *home, char const *s) |
8638 | { |
8639 | return (sip_supported_t *)sip_header_make(home, sip_supported_class, s)((sip_header_t *)msg_header_make((home), (sip_supported_class ), (s))); |
8640 | } |
8641 | #endif |
8642 | |
8643 | /**Make a @ref sip_supported "Supported header" from formatting result. |
8644 | * |
8645 | * Make a new #sip_supported_t object using formatting result as its value. |
8646 | * The function first prints the arguments according to the format @a fmt |
8647 | * specified. Then it allocates a new header structure, and parses the |
8648 | * formatting result to the structure #sip_supported_t. |
8649 | * |
8650 | * @param home memory home used to allocate new header structure. |
8651 | * @param fmt string used as a printf()-style format |
8652 | * @param ... argument list for format |
8653 | * |
8654 | * @return |
8655 | * A pointer to newly |
8656 | * makes header structure, or NULL upon an error. |
8657 | * |
8658 | * @HIDE |
8659 | * |
8660 | */ |
8661 | #if SU_HAVE_INLINE1 |
8662 | su_inlinestatic inline |
8663 | #endif |
8664 | sip_supported_t *sip_supported_format(su_home_t *home, char const *fmt, ...) |
8665 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
8666 | |
8667 | #if SU_HAVE_INLINE1 |
8668 | su_inlinestatic inline sip_supported_t *sip_supported_format(su_home_t *home, char const *fmt, ...) |
8669 | { |
8670 | sip_header_t *h; |
8671 | va_list ap; |
8672 | |
8673 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
8674 | h = sip_header_vformat(home, sip_supported_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_supported_class ), (fmt), (ap))); |
8675 | va_end(ap)__builtin_va_end(ap); |
8676 | |
8677 | return (sip_supported_t *)h; |
8678 | } |
8679 | #endif |
8680 | |
8681 | /** @} */ |
8682 | |
8683 | /**@addtogroup sip_unsupported |
8684 | * @{ |
8685 | */ |
8686 | |
8687 | /** Parse a SIP @ref sip_unsupported "Unsupported header". @internal */ |
8688 | SOFIAPUBFUN issize_t sip_unsupported_d(su_home_t *, msg_header_t *, |
8689 | char *s, isize_t slen); |
8690 | |
8691 | /** Print a SIP @ref sip_unsupported "Unsupported header". @internal */ |
8692 | SOFIAPUBFUN issize_t sip_unsupported_e(char b[], isize_t bsiz, |
8693 | msg_header_t const *h, int flags); |
8694 | |
8695 | /**Access a SIP @ref sip_unsupported "Unsupported header" |
8696 | * structure #sip_unsupported_t from #sip_t. |
8697 | * |
8698 | */ |
8699 | #define sip_unsupported(sip)((sip_unsupported_t *)msg_header_access((msg_pub_t*)(sip), sip_unsupported_class )) \ |
8700 | ((sip_unsupported_t *)msg_header_access((msg_pub_t*)(sip), sip_unsupported_class)) |
8701 | |
8702 | /**Initializer for structure #sip_unsupported_t. |
8703 | * |
8704 | * A static #sip_unsupported_t structure for |
8705 | * @ref sip_unsupported "Unsupported header" must be initialized with |
8706 | * the SIP_UNSUPPORTED_INIT() macro. |
8707 | * For instance, |
8708 | * @code |
8709 | * |
8710 | * sip_unsupported_t sip_unsupported = SIP_UNSUPPORTED_INIT; |
8711 | * |
8712 | * @endcode |
8713 | * @HI |
8714 | * |
8715 | */ |
8716 | #define SIP_UNSUPPORTED_INIT(){{{ 0, 0, sip_unsupported_class }}} SIP_HDR_INIT(unsupported){{{ 0, 0, sip_unsupported_class }}} |
8717 | |
8718 | /**Initialize a structure #sip_unsupported_t. |
8719 | * |
8720 | * An #sip_unsupported_t structure for |
8721 | * @ref sip_unsupported "Unsupported header" can be initialized with the |
8722 | * sip_unsupported_init() function/macro. For instance, |
8723 | * @code |
8724 | * |
8725 | * sip_unsupported_t sip_unsupported; |
8726 | * |
8727 | * sip_unsupported_init(&sip_unsupported); |
8728 | * |
8729 | * @endcode |
8730 | * @HI |
8731 | * |
8732 | */ |
8733 | #if SU_HAVE_INLINE1 |
8734 | su_inlinestatic inline sip_unsupported_t *sip_unsupported_init(sip_unsupported_t x[1]) |
8735 | { |
8736 | return SIP_HEADER_INIT(x, sip_unsupported_class, sizeof(sip_unsupported_t))((void)memset((x), 0, (sizeof(sip_unsupported_t))), (void)((( sip_common_t *)(x))->h_class = (sip_unsupported_class)), ( x)); |
8737 | } |
8738 | #else |
8739 | #define sip_unsupported_init(x) \ |
8740 | SIP_HEADER_INIT(x, sip_unsupported_class, sizeof(sip_unsupported_t))((void)memset((x), 0, (sizeof(sip_unsupported_t))), (void)((( sip_common_t *)(x))->h_class = (sip_unsupported_class)), ( x)) |
8741 | #endif |
8742 | |
8743 | /**Test if header object is instance of #sip_unsupported_t. |
8744 | * |
8745 | * Check if the header class is an instance of |
8746 | * @ref sip_unsupported "Unsupported header" object and return true (nonzero), |
8747 | * otherwise return false (zero). |
8748 | * |
8749 | * @param header pointer to the header structure to be tested |
8750 | * |
8751 | * @retval 1 (true) if the @a header is an instance of header unsupported |
8752 | * @retval 0 (false) otherwise |
8753 | * |
8754 | */ |
8755 | #if SU_HAVE_INLINE1 |
8756 | su_inlinestatic inline int sip_is_unsupported(sip_header_t const *header) |
8757 | { |
8758 | return header && header->sh_classsh_common->h_class->hc_hash == sip_unsupported_hash; |
8759 | } |
8760 | #else |
8761 | int sip_is_unsupported(sip_header_t const *header); |
8762 | #endif |
8763 | |
8764 | #define sip_unsupported_p(h)sip_is_unsupported((h)) sip_is_unsupported((h)) |
8765 | |
8766 | |
8767 | /**Duplicate a list of @ref sip_unsupported "Unsupported header" header structures #sip_unsupported_t. |
8768 | * |
8769 | * Duplicate a header |
8770 | * structure @a hdr. If the header structure @a hdr |
8771 | * contains a reference (@c hdr->x_next) to a list of |
8772 | * headers, all the headers in the list are duplicated, too. |
8773 | * |
8774 | * @param home memory home used to allocate new structure |
8775 | * @param hdr header structure to be duplicated |
8776 | * |
8777 | * When duplicating, all parameter lists and non-constant |
8778 | * strings attached to the header are copied, too. The |
8779 | * function uses given memory @a home to allocate all the |
8780 | * memory areas used to copy the header. |
8781 | * |
8782 | * @par Example |
8783 | * @code |
8784 | * |
8785 | * unsupported = sip_unsupported_dup(home, sip->sip_unsupported); |
8786 | * |
8787 | * @endcode |
8788 | * |
8789 | * @return |
8790 | * A pointer to the |
8791 | * newly duplicated #sip_unsupported_t header structure, or NULL |
8792 | * upon an error. |
8793 | * |
8794 | */ |
8795 | #if SU_HAVE_INLINE1 |
8796 | su_inlinestatic inline |
8797 | #endif |
8798 | sip_unsupported_t *sip_unsupported_dup(su_home_t *home, sip_unsupported_t const *hdr) |
8799 | __attribute__((__malloc__)); |
8800 | |
8801 | #if SU_HAVE_INLINE1 |
8802 | su_inlinestatic inline |
8803 | sip_unsupported_t *sip_unsupported_dup(su_home_t *home, sip_unsupported_t const *hdr) |
8804 | { |
8805 | return (sip_unsupported_t *) |
8806 | msg_header_dup_as(home, sip_unsupported_class, (msg_header_t const *)hdr); |
8807 | } |
8808 | #endif |
8809 | |
8810 | /**Copy a list of @ref sip_unsupported "Unsupported header" header structures #sip_unsupported_t. |
8811 | * |
8812 | * The function sip_unsupported_copy() copies a header structure @a |
8813 | * hdr. If the header structure @a hdr contains a reference (@c |
8814 | * hdr->h_next) to a list of headers, all the headers in that |
8815 | * list are copied, too. The function uses given memory @a home |
8816 | * to allocate all the memory areas used to copy the list of header |
8817 | * structure @a hdr. |
8818 | * |
8819 | * @param home memory home used to allocate new structure |
8820 | * @param hdr pointer to the header structure to be copied |
8821 | * |
8822 | * When copying, only the header structure and parameter lists attached to |
8823 | * it are duplicated. The new header structure retains all the references to |
8824 | * the strings within the old @a hdr header, including the encoding of the |
8825 | * old header, if present. |
8826 | * |
8827 | * @par Example |
8828 | * @code |
8829 | * |
8830 | * unsupported = sip_unsupported_copy(home, sip->sip_unsupported); |
8831 | * |
8832 | * @endcode |
8833 | * |
8834 | * @return |
8835 | * A pointer to newly copied header structure, or NULL upon an error. |
8836 | * |
8837 | */ |
8838 | #if SU_HAVE_INLINE1 |
8839 | su_inlinestatic inline |
8840 | #endif |
8841 | sip_unsupported_t *sip_unsupported_copy(su_home_t *home, sip_unsupported_t const *hdr) |
8842 | __attribute__((__malloc__)); |
8843 | |
8844 | #if SU_HAVE_INLINE1 |
8845 | su_inlinestatic inline |
8846 | sip_unsupported_t *sip_unsupported_copy(su_home_t *home, sip_unsupported_t const *hdr) |
8847 | { |
8848 | return (sip_unsupported_t *) |
8849 | msg_header_copy_as(home, sip_unsupported_class, (msg_header_t const *)hdr); |
8850 | } |
8851 | #endif |
8852 | |
8853 | /**Make a @ref sip_unsupported "Unsupported header" structure #sip_unsupported_t. |
8854 | * |
8855 | * The function sip_unsupported_make() makes a new |
8856 | * #sip_unsupported_t header structure. It allocates a new |
8857 | * header structure, and decodes the string @a s as the |
8858 | * value of the structure. |
8859 | * |
8860 | * @param home memory home used to allocate new header structure. |
8861 | * @param s string to be decoded as value of the new header structure |
8862 | * |
8863 | * @return |
8864 | * A pointer to newly maked #sip_unsupported_t header structure, or NULL upon an |
8865 | * error. |
8866 | * |
8867 | */ |
8868 | #if SU_HAVE_INLINE1 |
8869 | su_inlinestatic inline |
8870 | #endif |
8871 | sip_unsupported_t *sip_unsupported_make(su_home_t *home, char const *s) |
8872 | __attribute__((__malloc__)); |
8873 | |
8874 | #if SU_HAVE_INLINE1 |
8875 | su_inlinestatic inline sip_unsupported_t *sip_unsupported_make(su_home_t *home, char const *s) |
8876 | { |
8877 | return (sip_unsupported_t *)sip_header_make(home, sip_unsupported_class, s)((sip_header_t *)msg_header_make((home), (sip_unsupported_class ), (s))); |
8878 | } |
8879 | #endif |
8880 | |
8881 | /**Make a @ref sip_unsupported "Unsupported header" from formatting result. |
8882 | * |
8883 | * Make a new #sip_unsupported_t object using formatting result as its value. |
8884 | * The function first prints the arguments according to the format @a fmt |
8885 | * specified. Then it allocates a new header structure, and parses the |
8886 | * formatting result to the structure #sip_unsupported_t. |
8887 | * |
8888 | * @param home memory home used to allocate new header structure. |
8889 | * @param fmt string used as a printf()-style format |
8890 | * @param ... argument list for format |
8891 | * |
8892 | * @return |
8893 | * A pointer to newly |
8894 | * makes header structure, or NULL upon an error. |
8895 | * |
8896 | * @HIDE |
8897 | * |
8898 | */ |
8899 | #if SU_HAVE_INLINE1 |
8900 | su_inlinestatic inline |
8901 | #endif |
8902 | sip_unsupported_t *sip_unsupported_format(su_home_t *home, char const *fmt, ...) |
8903 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
8904 | |
8905 | #if SU_HAVE_INLINE1 |
8906 | su_inlinestatic inline sip_unsupported_t *sip_unsupported_format(su_home_t *home, char const *fmt, ...) |
8907 | { |
8908 | sip_header_t *h; |
8909 | va_list ap; |
8910 | |
8911 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
8912 | h = sip_header_vformat(home, sip_unsupported_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_unsupported_class ), (fmt), (ap))); |
8913 | va_end(ap)__builtin_va_end(ap); |
8914 | |
8915 | return (sip_unsupported_t *)h; |
8916 | } |
8917 | #endif |
8918 | |
8919 | /** @} */ |
8920 | |
8921 | /**@addtogroup sip_event |
8922 | * @{ |
8923 | */ |
8924 | |
8925 | /** Parse a SIP @ref sip_event "Event header". @internal */ |
8926 | SOFIAPUBFUN issize_t sip_event_d(su_home_t *, msg_header_t *, |
8927 | char *s, isize_t slen); |
8928 | |
8929 | /** Print a SIP @ref sip_event "Event header". @internal */ |
8930 | SOFIAPUBFUN issize_t sip_event_e(char b[], isize_t bsiz, |
8931 | msg_header_t const *h, int flags); |
8932 | |
8933 | /**Access a SIP @ref sip_event "Event header" |
8934 | * structure #sip_event_t from #sip_t. |
8935 | * |
8936 | */ |
8937 | #define sip_event(sip)((sip_event_t *)msg_header_access((msg_pub_t*)(sip), sip_event_class )) \ |
8938 | ((sip_event_t *)msg_header_access((msg_pub_t*)(sip), sip_event_class)) |
8939 | |
8940 | /**Initializer for structure #sip_event_t. |
8941 | * |
8942 | * A static #sip_event_t structure for |
8943 | * @ref sip_event "Event header" must be initialized with |
8944 | * the SIP_EVENT_INIT() macro. |
8945 | * For instance, |
8946 | * @code |
8947 | * |
8948 | * sip_event_t sip_event = SIP_EVENT_INIT; |
8949 | * |
8950 | * @endcode |
8951 | * @HI |
8952 | * |
8953 | */ |
8954 | #define SIP_EVENT_INIT(){{{ 0, 0, sip_event_class }}} SIP_HDR_INIT(event){{{ 0, 0, sip_event_class }}} |
8955 | |
8956 | /**Initialize a structure #sip_event_t. |
8957 | * |
8958 | * An #sip_event_t structure for |
8959 | * @ref sip_event "Event header" can be initialized with the |
8960 | * sip_event_init() function/macro. For instance, |
8961 | * @code |
8962 | * |
8963 | * sip_event_t sip_event; |
8964 | * |
8965 | * sip_event_init(&sip_event); |
8966 | * |
8967 | * @endcode |
8968 | * @HI |
8969 | * |
8970 | */ |
8971 | #if SU_HAVE_INLINE1 |
8972 | su_inlinestatic inline sip_event_t *sip_event_init(sip_event_t x[1]) |
8973 | { |
8974 | return SIP_HEADER_INIT(x, sip_event_class, sizeof(sip_event_t))((void)memset((x), 0, (sizeof(sip_event_t))), (void)(((sip_common_t *)(x))->h_class = (sip_event_class)), (x)); |
8975 | } |
8976 | #else |
8977 | #define sip_event_init(x) \ |
8978 | SIP_HEADER_INIT(x, sip_event_class, sizeof(sip_event_t))((void)memset((x), 0, (sizeof(sip_event_t))), (void)(((sip_common_t *)(x))->h_class = (sip_event_class)), (x)) |
8979 | #endif |
8980 | |
8981 | /**Test if header object is instance of #sip_event_t. |
8982 | * |
8983 | * Check if the header class is an instance of |
8984 | * @ref sip_event "Event header" object and return true (nonzero), |
8985 | * otherwise return false (zero). |
8986 | * |
8987 | * @param header pointer to the header structure to be tested |
8988 | * |
8989 | * @retval 1 (true) if the @a header is an instance of header event |
8990 | * @retval 0 (false) otherwise |
8991 | * |
8992 | */ |
8993 | #if SU_HAVE_INLINE1 |
8994 | su_inlinestatic inline int sip_is_event(sip_header_t const *header) |
8995 | { |
8996 | return header && header->sh_classsh_common->h_class->hc_hash == sip_event_hash; |
8997 | } |
8998 | #else |
8999 | int sip_is_event(sip_header_t const *header); |
9000 | #endif |
9001 | |
9002 | #define sip_event_p(h)sip_is_event((h)) sip_is_event((h)) |
9003 | |
9004 | |
9005 | /**Duplicate a list of @ref sip_event "Event header" header structures #sip_event_t. |
9006 | * |
9007 | * Duplicate a header |
9008 | * structure @a hdr. If the header structure @a hdr |
9009 | * contains a reference (@c hdr->x_next) to a list of |
9010 | * headers, all the headers in the list are duplicated, too. |
9011 | * |
9012 | * @param home memory home used to allocate new structure |
9013 | * @param hdr header structure to be duplicated |
9014 | * |
9015 | * When duplicating, all parameter lists and non-constant |
9016 | * strings attached to the header are copied, too. The |
9017 | * function uses given memory @a home to allocate all the |
9018 | * memory areas used to copy the header. |
9019 | * |
9020 | * @par Example |
9021 | * @code |
9022 | * |
9023 | * event = sip_event_dup(home, sip->sip_event); |
9024 | * |
9025 | * @endcode |
9026 | * |
9027 | * @return |
9028 | * A pointer to the |
9029 | * newly duplicated #sip_event_t header structure, or NULL |
9030 | * upon an error. |
9031 | * |
9032 | */ |
9033 | #if SU_HAVE_INLINE1 |
9034 | su_inlinestatic inline |
9035 | #endif |
9036 | sip_event_t *sip_event_dup(su_home_t *home, sip_event_t const *hdr) |
9037 | __attribute__((__malloc__)); |
9038 | |
9039 | #if SU_HAVE_INLINE1 |
9040 | su_inlinestatic inline |
9041 | sip_event_t *sip_event_dup(su_home_t *home, sip_event_t const *hdr) |
9042 | { |
9043 | return (sip_event_t *) |
9044 | msg_header_dup_as(home, sip_event_class, (msg_header_t const *)hdr); |
9045 | } |
9046 | #endif |
9047 | |
9048 | /**Copy a list of @ref sip_event "Event header" header structures #sip_event_t. |
9049 | * |
9050 | * The function sip_event_copy() copies a header structure @a |
9051 | * hdr. If the header structure @a hdr contains a reference (@c |
9052 | * hdr->h_next) to a list of headers, all the headers in that |
9053 | * list are copied, too. The function uses given memory @a home |
9054 | * to allocate all the memory areas used to copy the list of header |
9055 | * structure @a hdr. |
9056 | * |
9057 | * @param home memory home used to allocate new structure |
9058 | * @param hdr pointer to the header structure to be copied |
9059 | * |
9060 | * When copying, only the header structure and parameter lists attached to |
9061 | * it are duplicated. The new header structure retains all the references to |
9062 | * the strings within the old @a hdr header, including the encoding of the |
9063 | * old header, if present. |
9064 | * |
9065 | * @par Example |
9066 | * @code |
9067 | * |
9068 | * event = sip_event_copy(home, sip->sip_event); |
9069 | * |
9070 | * @endcode |
9071 | * |
9072 | * @return |
9073 | * A pointer to newly copied header structure, or NULL upon an error. |
9074 | * |
9075 | */ |
9076 | #if SU_HAVE_INLINE1 |
9077 | su_inlinestatic inline |
9078 | #endif |
9079 | sip_event_t *sip_event_copy(su_home_t *home, sip_event_t const *hdr) |
9080 | __attribute__((__malloc__)); |
9081 | |
9082 | #if SU_HAVE_INLINE1 |
9083 | su_inlinestatic inline |
9084 | sip_event_t *sip_event_copy(su_home_t *home, sip_event_t const *hdr) |
9085 | { |
9086 | return (sip_event_t *) |
9087 | msg_header_copy_as(home, sip_event_class, (msg_header_t const *)hdr); |
9088 | } |
9089 | #endif |
9090 | |
9091 | /**Make a @ref sip_event "Event header" structure #sip_event_t. |
9092 | * |
9093 | * The function sip_event_make() makes a new |
9094 | * #sip_event_t header structure. It allocates a new |
9095 | * header structure, and decodes the string @a s as the |
9096 | * value of the structure. |
9097 | * |
9098 | * @param home memory home used to allocate new header structure. |
9099 | * @param s string to be decoded as value of the new header structure |
9100 | * |
9101 | * @return |
9102 | * A pointer to newly maked #sip_event_t header structure, or NULL upon an |
9103 | * error. |
9104 | * |
9105 | */ |
9106 | #if SU_HAVE_INLINE1 |
9107 | su_inlinestatic inline |
9108 | #endif |
9109 | sip_event_t *sip_event_make(su_home_t *home, char const *s) |
9110 | __attribute__((__malloc__)); |
9111 | |
9112 | #if SU_HAVE_INLINE1 |
9113 | su_inlinestatic inline sip_event_t *sip_event_make(su_home_t *home, char const *s) |
9114 | { |
9115 | return (sip_event_t *)sip_header_make(home, sip_event_class, s)((sip_header_t *)msg_header_make((home), (sip_event_class), ( s))); |
9116 | } |
9117 | #endif |
9118 | |
9119 | /**Make a @ref sip_event "Event header" from formatting result. |
9120 | * |
9121 | * Make a new #sip_event_t object using formatting result as its value. |
9122 | * The function first prints the arguments according to the format @a fmt |
9123 | * specified. Then it allocates a new header structure, and parses the |
9124 | * formatting result to the structure #sip_event_t. |
9125 | * |
9126 | * @param home memory home used to allocate new header structure. |
9127 | * @param fmt string used as a printf()-style format |
9128 | * @param ... argument list for format |
9129 | * |
9130 | * @return |
9131 | * A pointer to newly |
9132 | * makes header structure, or NULL upon an error. |
9133 | * |
9134 | * @HIDE |
9135 | * |
9136 | */ |
9137 | #if SU_HAVE_INLINE1 |
9138 | su_inlinestatic inline |
9139 | #endif |
9140 | sip_event_t *sip_event_format(su_home_t *home, char const *fmt, ...) |
9141 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
9142 | |
9143 | #if SU_HAVE_INLINE1 |
9144 | su_inlinestatic inline sip_event_t *sip_event_format(su_home_t *home, char const *fmt, ...) |
9145 | { |
9146 | sip_header_t *h; |
9147 | va_list ap; |
9148 | |
9149 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
9150 | h = sip_header_vformat(home, sip_event_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_event_class) , (fmt), (ap))); |
9151 | va_end(ap)__builtin_va_end(ap); |
9152 | |
9153 | return (sip_event_t *)h; |
9154 | } |
9155 | #endif |
9156 | |
9157 | /** @} */ |
9158 | |
9159 | /**@addtogroup sip_allow_events |
9160 | * @{ |
9161 | */ |
9162 | |
9163 | /** Parse a SIP @ref sip_allow_events "Allow-Events header". @internal */ |
9164 | SOFIAPUBFUN issize_t sip_allow_events_d(su_home_t *, msg_header_t *, |
9165 | char *s, isize_t slen); |
9166 | |
9167 | /** Print a SIP @ref sip_allow_events "Allow-Events header". @internal */ |
9168 | SOFIAPUBFUN issize_t sip_allow_events_e(char b[], isize_t bsiz, |
9169 | msg_header_t const *h, int flags); |
9170 | |
9171 | /**Access a SIP @ref sip_allow_events "Allow-Events header" |
9172 | * structure #sip_allow_events_t from #sip_t. |
9173 | * |
9174 | */ |
9175 | #define sip_allow_events(sip)((sip_allow_events_t *)msg_header_access((msg_pub_t*)(sip), sip_allow_events_class )) \ |
9176 | ((sip_allow_events_t *)msg_header_access((msg_pub_t*)(sip), sip_allow_events_class)) |
9177 | |
9178 | /**Initializer for structure #sip_allow_events_t. |
9179 | * |
9180 | * A static #sip_allow_events_t structure for |
9181 | * @ref sip_allow_events "Allow-Events header" must be initialized with |
9182 | * the SIP_ALLOW_EVENTS_INIT() macro. |
9183 | * For instance, |
9184 | * @code |
9185 | * |
9186 | * sip_allow_events_t sip_allow_events = SIP_ALLOW_EVENTS_INIT; |
9187 | * |
9188 | * @endcode |
9189 | * @HI |
9190 | * |
9191 | */ |
9192 | #define SIP_ALLOW_EVENTS_INIT(){{{ 0, 0, sip_allow_events_class }}} SIP_HDR_INIT(allow_events){{{ 0, 0, sip_allow_events_class }}} |
9193 | |
9194 | /**Initialize a structure #sip_allow_events_t. |
9195 | * |
9196 | * An #sip_allow_events_t structure for |
9197 | * @ref sip_allow_events "Allow-Events header" can be initialized with the |
9198 | * sip_allow_events_init() function/macro. For instance, |
9199 | * @code |
9200 | * |
9201 | * sip_allow_events_t sip_allow_events; |
9202 | * |
9203 | * sip_allow_events_init(&sip_allow_events); |
9204 | * |
9205 | * @endcode |
9206 | * @HI |
9207 | * |
9208 | */ |
9209 | #if SU_HAVE_INLINE1 |
9210 | su_inlinestatic inline sip_allow_events_t *sip_allow_events_init(sip_allow_events_t x[1]) |
9211 | { |
9212 | return SIP_HEADER_INIT(x, sip_allow_events_class, sizeof(sip_allow_events_t))((void)memset((x), 0, (sizeof(sip_allow_events_t))), (void)(( (sip_common_t *)(x))->h_class = (sip_allow_events_class)), (x)); |
9213 | } |
9214 | #else |
9215 | #define sip_allow_events_init(x) \ |
9216 | SIP_HEADER_INIT(x, sip_allow_events_class, sizeof(sip_allow_events_t))((void)memset((x), 0, (sizeof(sip_allow_events_t))), (void)(( (sip_common_t *)(x))->h_class = (sip_allow_events_class)), (x)) |
9217 | #endif |
9218 | |
9219 | /**Test if header object is instance of #sip_allow_events_t. |
9220 | * |
9221 | * Check if the header class is an instance of |
9222 | * @ref sip_allow_events "Allow-Events header" object and return true (nonzero), |
9223 | * otherwise return false (zero). |
9224 | * |
9225 | * @param header pointer to the header structure to be tested |
9226 | * |
9227 | * @retval 1 (true) if the @a header is an instance of header allow_events |
9228 | * @retval 0 (false) otherwise |
9229 | * |
9230 | */ |
9231 | #if SU_HAVE_INLINE1 |
9232 | su_inlinestatic inline int sip_is_allow_events(sip_header_t const *header) |
9233 | { |
9234 | return header && header->sh_classsh_common->h_class->hc_hash == sip_allow_events_hash; |
9235 | } |
9236 | #else |
9237 | int sip_is_allow_events(sip_header_t const *header); |
9238 | #endif |
9239 | |
9240 | #define sip_allow_events_p(h)sip_is_allow_events((h)) sip_is_allow_events((h)) |
9241 | |
9242 | |
9243 | /**Duplicate a list of @ref sip_allow_events "Allow-Events header" header structures #sip_allow_events_t. |
9244 | * |
9245 | * Duplicate a header |
9246 | * structure @a hdr. If the header structure @a hdr |
9247 | * contains a reference (@c hdr->x_next) to a list of |
9248 | * headers, all the headers in the list are duplicated, too. |
9249 | * |
9250 | * @param home memory home used to allocate new structure |
9251 | * @param hdr header structure to be duplicated |
9252 | * |
9253 | * When duplicating, all parameter lists and non-constant |
9254 | * strings attached to the header are copied, too. The |
9255 | * function uses given memory @a home to allocate all the |
9256 | * memory areas used to copy the header. |
9257 | * |
9258 | * @par Example |
9259 | * @code |
9260 | * |
9261 | * allow_events = sip_allow_events_dup(home, sip->sip_allow_events); |
9262 | * |
9263 | * @endcode |
9264 | * |
9265 | * @return |
9266 | * A pointer to the |
9267 | * newly duplicated #sip_allow_events_t header structure, or NULL |
9268 | * upon an error. |
9269 | * |
9270 | */ |
9271 | #if SU_HAVE_INLINE1 |
9272 | su_inlinestatic inline |
9273 | #endif |
9274 | sip_allow_events_t *sip_allow_events_dup(su_home_t *home, sip_allow_events_t const *hdr) |
9275 | __attribute__((__malloc__)); |
9276 | |
9277 | #if SU_HAVE_INLINE1 |
9278 | su_inlinestatic inline |
9279 | sip_allow_events_t *sip_allow_events_dup(su_home_t *home, sip_allow_events_t const *hdr) |
9280 | { |
9281 | return (sip_allow_events_t *) |
9282 | msg_header_dup_as(home, sip_allow_events_class, (msg_header_t const *)hdr); |
9283 | } |
9284 | #endif |
9285 | |
9286 | /**Copy a list of @ref sip_allow_events "Allow-Events header" header structures #sip_allow_events_t. |
9287 | * |
9288 | * The function sip_allow_events_copy() copies a header structure @a |
9289 | * hdr. If the header structure @a hdr contains a reference (@c |
9290 | * hdr->h_next) to a list of headers, all the headers in that |
9291 | * list are copied, too. The function uses given memory @a home |
9292 | * to allocate all the memory areas used to copy the list of header |
9293 | * structure @a hdr. |
9294 | * |
9295 | * @param home memory home used to allocate new structure |
9296 | * @param hdr pointer to the header structure to be copied |
9297 | * |
9298 | * When copying, only the header structure and parameter lists attached to |
9299 | * it are duplicated. The new header structure retains all the references to |
9300 | * the strings within the old @a hdr header, including the encoding of the |
9301 | * old header, if present. |
9302 | * |
9303 | * @par Example |
9304 | * @code |
9305 | * |
9306 | * allow_events = sip_allow_events_copy(home, sip->sip_allow_events); |
9307 | * |
9308 | * @endcode |
9309 | * |
9310 | * @return |
9311 | * A pointer to newly copied header structure, or NULL upon an error. |
9312 | * |
9313 | */ |
9314 | #if SU_HAVE_INLINE1 |
9315 | su_inlinestatic inline |
9316 | #endif |
9317 | sip_allow_events_t *sip_allow_events_copy(su_home_t *home, sip_allow_events_t const *hdr) |
9318 | __attribute__((__malloc__)); |
9319 | |
9320 | #if SU_HAVE_INLINE1 |
9321 | su_inlinestatic inline |
9322 | sip_allow_events_t *sip_allow_events_copy(su_home_t *home, sip_allow_events_t const *hdr) |
9323 | { |
9324 | return (sip_allow_events_t *) |
9325 | msg_header_copy_as(home, sip_allow_events_class, (msg_header_t const *)hdr); |
9326 | } |
9327 | #endif |
9328 | |
9329 | /**Make a @ref sip_allow_events "Allow-Events header" structure #sip_allow_events_t. |
9330 | * |
9331 | * The function sip_allow_events_make() makes a new |
9332 | * #sip_allow_events_t header structure. It allocates a new |
9333 | * header structure, and decodes the string @a s as the |
9334 | * value of the structure. |
9335 | * |
9336 | * @param home memory home used to allocate new header structure. |
9337 | * @param s string to be decoded as value of the new header structure |
9338 | * |
9339 | * @return |
9340 | * A pointer to newly maked #sip_allow_events_t header structure, or NULL upon an |
9341 | * error. |
9342 | * |
9343 | */ |
9344 | #if SU_HAVE_INLINE1 |
9345 | su_inlinestatic inline |
9346 | #endif |
9347 | sip_allow_events_t *sip_allow_events_make(su_home_t *home, char const *s) |
9348 | __attribute__((__malloc__)); |
9349 | |
9350 | #if SU_HAVE_INLINE1 |
9351 | su_inlinestatic inline sip_allow_events_t *sip_allow_events_make(su_home_t *home, char const *s) |
9352 | { |
9353 | return (sip_allow_events_t *)sip_header_make(home, sip_allow_events_class, s)((sip_header_t *)msg_header_make((home), (sip_allow_events_class ), (s))); |
9354 | } |
9355 | #endif |
9356 | |
9357 | /**Make a @ref sip_allow_events "Allow-Events header" from formatting result. |
9358 | * |
9359 | * Make a new #sip_allow_events_t object using formatting result as its value. |
9360 | * The function first prints the arguments according to the format @a fmt |
9361 | * specified. Then it allocates a new header structure, and parses the |
9362 | * formatting result to the structure #sip_allow_events_t. |
9363 | * |
9364 | * @param home memory home used to allocate new header structure. |
9365 | * @param fmt string used as a printf()-style format |
9366 | * @param ... argument list for format |
9367 | * |
9368 | * @return |
9369 | * A pointer to newly |
9370 | * makes header structure, or NULL upon an error. |
9371 | * |
9372 | * @HIDE |
9373 | * |
9374 | */ |
9375 | #if SU_HAVE_INLINE1 |
9376 | su_inlinestatic inline |
9377 | #endif |
9378 | sip_allow_events_t *sip_allow_events_format(su_home_t *home, char const *fmt, ...) |
9379 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
9380 | |
9381 | #if SU_HAVE_INLINE1 |
9382 | su_inlinestatic inline sip_allow_events_t *sip_allow_events_format(su_home_t *home, char const *fmt, ...) |
9383 | { |
9384 | sip_header_t *h; |
9385 | va_list ap; |
9386 | |
9387 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
9388 | h = sip_header_vformat(home, sip_allow_events_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_allow_events_class ), (fmt), (ap))); |
9389 | va_end(ap)__builtin_va_end(ap); |
9390 | |
9391 | return (sip_allow_events_t *)h; |
9392 | } |
9393 | #endif |
9394 | |
9395 | /** @} */ |
9396 | |
9397 | /**@addtogroup sip_subscription_state |
9398 | * @{ |
9399 | */ |
9400 | |
9401 | /** Parse a SIP @ref sip_subscription_state "Subscription-State header". @internal */ |
9402 | SOFIAPUBFUN issize_t sip_subscription_state_d(su_home_t *, msg_header_t *, |
9403 | char *s, isize_t slen); |
9404 | |
9405 | /** Print a SIP @ref sip_subscription_state "Subscription-State header". @internal */ |
9406 | SOFIAPUBFUN issize_t sip_subscription_state_e(char b[], isize_t bsiz, |
9407 | msg_header_t const *h, int flags); |
9408 | |
9409 | /**Access a SIP @ref sip_subscription_state "Subscription-State header" |
9410 | * structure #sip_subscription_state_t from #sip_t. |
9411 | * |
9412 | */ |
9413 | #define sip_subscription_state(sip)((sip_subscription_state_t *)msg_header_access((msg_pub_t*)(sip ), sip_subscription_state_class)) \ |
9414 | ((sip_subscription_state_t *)msg_header_access((msg_pub_t*)(sip), sip_subscription_state_class)) |
9415 | |
9416 | /**Initializer for structure #sip_subscription_state_t. |
9417 | * |
9418 | * A static #sip_subscription_state_t structure for |
9419 | * @ref sip_subscription_state "Subscription-State header" must be initialized with |
9420 | * the SIP_SUBSCRIPTION_STATE_INIT() macro. |
9421 | * For instance, |
9422 | * @code |
9423 | * |
9424 | * sip_subscription_state_t sip_subscription_state = SIP_SUBSCRIPTION_STATE_INIT; |
9425 | * |
9426 | * @endcode |
9427 | * @HI |
9428 | * |
9429 | */ |
9430 | #define SIP_SUBSCRIPTION_STATE_INIT(){{{ 0, 0, sip_subscription_state_class }}} SIP_HDR_INIT(subscription_state){{{ 0, 0, sip_subscription_state_class }}} |
9431 | |
9432 | /**Initialize a structure #sip_subscription_state_t. |
9433 | * |
9434 | * An #sip_subscription_state_t structure for |
9435 | * @ref sip_subscription_state "Subscription-State header" can be initialized with the |
9436 | * sip_subscription_state_init() function/macro. For instance, |
9437 | * @code |
9438 | * |
9439 | * sip_subscription_state_t sip_subscription_state; |
9440 | * |
9441 | * sip_subscription_state_init(&sip_subscription_state); |
9442 | * |
9443 | * @endcode |
9444 | * @HI |
9445 | * |
9446 | */ |
9447 | #if SU_HAVE_INLINE1 |
9448 | su_inlinestatic inline sip_subscription_state_t *sip_subscription_state_init(sip_subscription_state_t x[1]) |
9449 | { |
9450 | return SIP_HEADER_INIT(x, sip_subscription_state_class, sizeof(sip_subscription_state_t))((void)memset((x), 0, (sizeof(sip_subscription_state_t))), (void )(((sip_common_t *)(x))->h_class = (sip_subscription_state_class )), (x)); |
9451 | } |
9452 | #else |
9453 | #define sip_subscription_state_init(x) \ |
9454 | SIP_HEADER_INIT(x, sip_subscription_state_class, sizeof(sip_subscription_state_t))((void)memset((x), 0, (sizeof(sip_subscription_state_t))), (void )(((sip_common_t *)(x))->h_class = (sip_subscription_state_class )), (x)) |
9455 | #endif |
9456 | |
9457 | /**Test if header object is instance of #sip_subscription_state_t. |
9458 | * |
9459 | * Check if the header class is an instance of |
9460 | * @ref sip_subscription_state "Subscription-State header" object and return true (nonzero), |
9461 | * otherwise return false (zero). |
9462 | * |
9463 | * @param header pointer to the header structure to be tested |
9464 | * |
9465 | * @retval 1 (true) if the @a header is an instance of header subscription_state |
9466 | * @retval 0 (false) otherwise |
9467 | * |
9468 | */ |
9469 | #if SU_HAVE_INLINE1 |
9470 | su_inlinestatic inline int sip_is_subscription_state(sip_header_t const *header) |
9471 | { |
9472 | return header && header->sh_classsh_common->h_class->hc_hash == sip_subscription_state_hash; |
9473 | } |
9474 | #else |
9475 | int sip_is_subscription_state(sip_header_t const *header); |
9476 | #endif |
9477 | |
9478 | #define sip_subscription_state_p(h)sip_is_subscription_state((h)) sip_is_subscription_state((h)) |
9479 | |
9480 | |
9481 | /**Duplicate a list of @ref sip_subscription_state "Subscription-State header" header structures #sip_subscription_state_t. |
9482 | * |
9483 | * Duplicate a header |
9484 | * structure @a hdr. If the header structure @a hdr |
9485 | * contains a reference (@c hdr->x_next) to a list of |
9486 | * headers, all the headers in the list are duplicated, too. |
9487 | * |
9488 | * @param home memory home used to allocate new structure |
9489 | * @param hdr header structure to be duplicated |
9490 | * |
9491 | * When duplicating, all parameter lists and non-constant |
9492 | * strings attached to the header are copied, too. The |
9493 | * function uses given memory @a home to allocate all the |
9494 | * memory areas used to copy the header. |
9495 | * |
9496 | * @par Example |
9497 | * @code |
9498 | * |
9499 | * subscription_state = sip_subscription_state_dup(home, sip->sip_subscription_state); |
9500 | * |
9501 | * @endcode |
9502 | * |
9503 | * @return |
9504 | * A pointer to the |
9505 | * newly duplicated #sip_subscription_state_t header structure, or NULL |
9506 | * upon an error. |
9507 | * |
9508 | */ |
9509 | #if SU_HAVE_INLINE1 |
9510 | su_inlinestatic inline |
9511 | #endif |
9512 | sip_subscription_state_t *sip_subscription_state_dup(su_home_t *home, sip_subscription_state_t const *hdr) |
9513 | __attribute__((__malloc__)); |
9514 | |
9515 | #if SU_HAVE_INLINE1 |
9516 | su_inlinestatic inline |
9517 | sip_subscription_state_t *sip_subscription_state_dup(su_home_t *home, sip_subscription_state_t const *hdr) |
9518 | { |
9519 | return (sip_subscription_state_t *) |
9520 | msg_header_dup_as(home, sip_subscription_state_class, (msg_header_t const *)hdr); |
9521 | } |
9522 | #endif |
9523 | |
9524 | /**Copy a list of @ref sip_subscription_state "Subscription-State header" header structures #sip_subscription_state_t. |
9525 | * |
9526 | * The function sip_subscription_state_copy() copies a header structure @a |
9527 | * hdr. If the header structure @a hdr contains a reference (@c |
9528 | * hdr->h_next) to a list of headers, all the headers in that |
9529 | * list are copied, too. The function uses given memory @a home |
9530 | * to allocate all the memory areas used to copy the list of header |
9531 | * structure @a hdr. |
9532 | * |
9533 | * @param home memory home used to allocate new structure |
9534 | * @param hdr pointer to the header structure to be copied |
9535 | * |
9536 | * When copying, only the header structure and parameter lists attached to |
9537 | * it are duplicated. The new header structure retains all the references to |
9538 | * the strings within the old @a hdr header, including the encoding of the |
9539 | * old header, if present. |
9540 | * |
9541 | * @par Example |
9542 | * @code |
9543 | * |
9544 | * subscription_state = sip_subscription_state_copy(home, sip->sip_subscription_state); |
9545 | * |
9546 | * @endcode |
9547 | * |
9548 | * @return |
9549 | * A pointer to newly copied header structure, or NULL upon an error. |
9550 | * |
9551 | */ |
9552 | #if SU_HAVE_INLINE1 |
9553 | su_inlinestatic inline |
9554 | #endif |
9555 | sip_subscription_state_t *sip_subscription_state_copy(su_home_t *home, sip_subscription_state_t const *hdr) |
9556 | __attribute__((__malloc__)); |
9557 | |
9558 | #if SU_HAVE_INLINE1 |
9559 | su_inlinestatic inline |
9560 | sip_subscription_state_t *sip_subscription_state_copy(su_home_t *home, sip_subscription_state_t const *hdr) |
9561 | { |
9562 | return (sip_subscription_state_t *) |
9563 | msg_header_copy_as(home, sip_subscription_state_class, (msg_header_t const *)hdr); |
9564 | } |
9565 | #endif |
9566 | |
9567 | /**Make a @ref sip_subscription_state "Subscription-State header" structure #sip_subscription_state_t. |
9568 | * |
9569 | * The function sip_subscription_state_make() makes a new |
9570 | * #sip_subscription_state_t header structure. It allocates a new |
9571 | * header structure, and decodes the string @a s as the |
9572 | * value of the structure. |
9573 | * |
9574 | * @param home memory home used to allocate new header structure. |
9575 | * @param s string to be decoded as value of the new header structure |
9576 | * |
9577 | * @return |
9578 | * A pointer to newly maked #sip_subscription_state_t header structure, or NULL upon an |
9579 | * error. |
9580 | * |
9581 | */ |
9582 | #if SU_HAVE_INLINE1 |
9583 | su_inlinestatic inline |
9584 | #endif |
9585 | sip_subscription_state_t *sip_subscription_state_make(su_home_t *home, char const *s) |
9586 | __attribute__((__malloc__)); |
9587 | |
9588 | #if SU_HAVE_INLINE1 |
9589 | su_inlinestatic inline sip_subscription_state_t *sip_subscription_state_make(su_home_t *home, char const *s) |
9590 | { |
9591 | return (sip_subscription_state_t *)sip_header_make(home, sip_subscription_state_class, s)((sip_header_t *)msg_header_make((home), (sip_subscription_state_class ), (s))); |
9592 | } |
9593 | #endif |
9594 | |
9595 | /**Make a @ref sip_subscription_state "Subscription-State header" from formatting result. |
9596 | * |
9597 | * Make a new #sip_subscription_state_t object using formatting result as its value. |
9598 | * The function first prints the arguments according to the format @a fmt |
9599 | * specified. Then it allocates a new header structure, and parses the |
9600 | * formatting result to the structure #sip_subscription_state_t. |
9601 | * |
9602 | * @param home memory home used to allocate new header structure. |
9603 | * @param fmt string used as a printf()-style format |
9604 | * @param ... argument list for format |
9605 | * |
9606 | * @return |
9607 | * A pointer to newly |
9608 | * makes header structure, or NULL upon an error. |
9609 | * |
9610 | * @HIDE |
9611 | * |
9612 | */ |
9613 | #if SU_HAVE_INLINE1 |
9614 | su_inlinestatic inline |
9615 | #endif |
9616 | sip_subscription_state_t *sip_subscription_state_format(su_home_t *home, char const *fmt, ...) |
9617 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
9618 | |
9619 | #if SU_HAVE_INLINE1 |
9620 | su_inlinestatic inline sip_subscription_state_t *sip_subscription_state_format(su_home_t *home, char const *fmt, ...) |
9621 | { |
9622 | sip_header_t *h; |
9623 | va_list ap; |
9624 | |
9625 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
9626 | h = sip_header_vformat(home, sip_subscription_state_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_subscription_state_class ), (fmt), (ap))); |
9627 | va_end(ap)__builtin_va_end(ap); |
9628 | |
9629 | return (sip_subscription_state_t *)h; |
9630 | } |
9631 | #endif |
9632 | |
9633 | /** @} */ |
9634 | |
9635 | /**@addtogroup sip_proxy_authenticate |
9636 | * @{ |
9637 | */ |
9638 | |
9639 | /** Parse a SIP @ref sip_proxy_authenticate "Proxy-Authenticate header". @internal */ |
9640 | SOFIAPUBFUN issize_t sip_proxy_authenticate_d(su_home_t *, msg_header_t *, |
9641 | char *s, isize_t slen); |
9642 | |
9643 | /** Print a SIP @ref sip_proxy_authenticate "Proxy-Authenticate header". @internal */ |
9644 | SOFIAPUBFUN issize_t sip_proxy_authenticate_e(char b[], isize_t bsiz, |
9645 | msg_header_t const *h, int flags); |
9646 | |
9647 | /**Access a SIP @ref sip_proxy_authenticate "Proxy-Authenticate header" |
9648 | * structure #sip_proxy_authenticate_t from #sip_t. |
9649 | * |
9650 | */ |
9651 | #define sip_proxy_authenticate(sip)((sip_proxy_authenticate_t *)msg_header_access((msg_pub_t*)(sip ), sip_proxy_authenticate_class)) \ |
9652 | ((sip_proxy_authenticate_t *)msg_header_access((msg_pub_t*)(sip), sip_proxy_authenticate_class)) |
9653 | |
9654 | /**Initializer for structure #sip_proxy_authenticate_t. |
9655 | * |
9656 | * A static #sip_proxy_authenticate_t structure for |
9657 | * @ref sip_proxy_authenticate "Proxy-Authenticate header" must be initialized with |
9658 | * the SIP_PROXY_AUTHENTICATE_INIT() macro. |
9659 | * For instance, |
9660 | * @code |
9661 | * |
9662 | * sip_proxy_authenticate_t sip_proxy_authenticate = SIP_PROXY_AUTHENTICATE_INIT; |
9663 | * |
9664 | * @endcode |
9665 | * @HI |
9666 | * |
9667 | */ |
9668 | #define SIP_PROXY_AUTHENTICATE_INIT(){{{ 0, 0, sip_proxy_authenticate_class }}} SIP_HDR_INIT(proxy_authenticate){{{ 0, 0, sip_proxy_authenticate_class }}} |
9669 | |
9670 | /**Initialize a structure #sip_proxy_authenticate_t. |
9671 | * |
9672 | * An #sip_proxy_authenticate_t structure for |
9673 | * @ref sip_proxy_authenticate "Proxy-Authenticate header" can be initialized with the |
9674 | * sip_proxy_authenticate_init() function/macro. For instance, |
9675 | * @code |
9676 | * |
9677 | * sip_proxy_authenticate_t sip_proxy_authenticate; |
9678 | * |
9679 | * sip_proxy_authenticate_init(&sip_proxy_authenticate); |
9680 | * |
9681 | * @endcode |
9682 | * @HI |
9683 | * |
9684 | */ |
9685 | #if SU_HAVE_INLINE1 |
9686 | su_inlinestatic inline sip_proxy_authenticate_t *sip_proxy_authenticate_init(sip_proxy_authenticate_t x[1]) |
9687 | { |
9688 | return SIP_HEADER_INIT(x, sip_proxy_authenticate_class, sizeof(sip_proxy_authenticate_t))((void)memset((x), 0, (sizeof(sip_proxy_authenticate_t))), (void )(((sip_common_t *)(x))->h_class = (sip_proxy_authenticate_class )), (x)); |
9689 | } |
9690 | #else |
9691 | #define sip_proxy_authenticate_init(x) \ |
9692 | SIP_HEADER_INIT(x, sip_proxy_authenticate_class, sizeof(sip_proxy_authenticate_t))((void)memset((x), 0, (sizeof(sip_proxy_authenticate_t))), (void )(((sip_common_t *)(x))->h_class = (sip_proxy_authenticate_class )), (x)) |
9693 | #endif |
9694 | |
9695 | /**Test if header object is instance of #sip_proxy_authenticate_t. |
9696 | * |
9697 | * Check if the header class is an instance of |
9698 | * @ref sip_proxy_authenticate "Proxy-Authenticate header" object and return true (nonzero), |
9699 | * otherwise return false (zero). |
9700 | * |
9701 | * @param header pointer to the header structure to be tested |
9702 | * |
9703 | * @retval 1 (true) if the @a header is an instance of header proxy_authenticate |
9704 | * @retval 0 (false) otherwise |
9705 | * |
9706 | */ |
9707 | #if SU_HAVE_INLINE1 |
9708 | su_inlinestatic inline int sip_is_proxy_authenticate(sip_header_t const *header) |
9709 | { |
9710 | return header && header->sh_classsh_common->h_class->hc_hash == sip_proxy_authenticate_hash; |
9711 | } |
9712 | #else |
9713 | int sip_is_proxy_authenticate(sip_header_t const *header); |
9714 | #endif |
9715 | |
9716 | #define sip_proxy_authenticate_p(h)sip_is_proxy_authenticate((h)) sip_is_proxy_authenticate((h)) |
9717 | |
9718 | |
9719 | /**Duplicate a list of @ref sip_proxy_authenticate "Proxy-Authenticate header" header structures #sip_proxy_authenticate_t. |
9720 | * |
9721 | * Duplicate a header |
9722 | * structure @a hdr. If the header structure @a hdr |
9723 | * contains a reference (@c hdr->x_next) to a list of |
9724 | * headers, all the headers in the list are duplicated, too. |
9725 | * |
9726 | * @param home memory home used to allocate new structure |
9727 | * @param hdr header structure to be duplicated |
9728 | * |
9729 | * When duplicating, all parameter lists and non-constant |
9730 | * strings attached to the header are copied, too. The |
9731 | * function uses given memory @a home to allocate all the |
9732 | * memory areas used to copy the header. |
9733 | * |
9734 | * @par Example |
9735 | * @code |
9736 | * |
9737 | * proxy_authenticate = sip_proxy_authenticate_dup(home, sip->sip_proxy_authenticate); |
9738 | * |
9739 | * @endcode |
9740 | * |
9741 | * @return |
9742 | * A pointer to the |
9743 | * newly duplicated #sip_proxy_authenticate_t header structure, or NULL |
9744 | * upon an error. |
9745 | * |
9746 | */ |
9747 | #if SU_HAVE_INLINE1 |
9748 | su_inlinestatic inline |
9749 | #endif |
9750 | sip_proxy_authenticate_t *sip_proxy_authenticate_dup(su_home_t *home, sip_proxy_authenticate_t const *hdr) |
9751 | __attribute__((__malloc__)); |
9752 | |
9753 | #if SU_HAVE_INLINE1 |
9754 | su_inlinestatic inline |
9755 | sip_proxy_authenticate_t *sip_proxy_authenticate_dup(su_home_t *home, sip_proxy_authenticate_t const *hdr) |
9756 | { |
9757 | return (sip_proxy_authenticate_t *) |
9758 | msg_header_dup_as(home, sip_proxy_authenticate_class, (msg_header_t const *)hdr); |
9759 | } |
9760 | #endif |
9761 | |
9762 | /**Copy a list of @ref sip_proxy_authenticate "Proxy-Authenticate header" header structures #sip_proxy_authenticate_t. |
9763 | * |
9764 | * The function sip_proxy_authenticate_copy() copies a header structure @a |
9765 | * hdr. If the header structure @a hdr contains a reference (@c |
9766 | * hdr->h_next) to a list of headers, all the headers in that |
9767 | * list are copied, too. The function uses given memory @a home |
9768 | * to allocate all the memory areas used to copy the list of header |
9769 | * structure @a hdr. |
9770 | * |
9771 | * @param home memory home used to allocate new structure |
9772 | * @param hdr pointer to the header structure to be copied |
9773 | * |
9774 | * When copying, only the header structure and parameter lists attached to |
9775 | * it are duplicated. The new header structure retains all the references to |
9776 | * the strings within the old @a hdr header, including the encoding of the |
9777 | * old header, if present. |
9778 | * |
9779 | * @par Example |
9780 | * @code |
9781 | * |
9782 | * proxy_authenticate = sip_proxy_authenticate_copy(home, sip->sip_proxy_authenticate); |
9783 | * |
9784 | * @endcode |
9785 | * |
9786 | * @return |
9787 | * A pointer to newly copied header structure, or NULL upon an error. |
9788 | * |
9789 | */ |
9790 | #if SU_HAVE_INLINE1 |
9791 | su_inlinestatic inline |
9792 | #endif |
9793 | sip_proxy_authenticate_t *sip_proxy_authenticate_copy(su_home_t *home, sip_proxy_authenticate_t const *hdr) |
9794 | __attribute__((__malloc__)); |
9795 | |
9796 | #if SU_HAVE_INLINE1 |
9797 | su_inlinestatic inline |
9798 | sip_proxy_authenticate_t *sip_proxy_authenticate_copy(su_home_t *home, sip_proxy_authenticate_t const *hdr) |
9799 | { |
9800 | return (sip_proxy_authenticate_t *) |
9801 | msg_header_copy_as(home, sip_proxy_authenticate_class, (msg_header_t const *)hdr); |
9802 | } |
9803 | #endif |
9804 | |
9805 | /**Make a @ref sip_proxy_authenticate "Proxy-Authenticate header" structure #sip_proxy_authenticate_t. |
9806 | * |
9807 | * The function sip_proxy_authenticate_make() makes a new |
9808 | * #sip_proxy_authenticate_t header structure. It allocates a new |
9809 | * header structure, and decodes the string @a s as the |
9810 | * value of the structure. |
9811 | * |
9812 | * @param home memory home used to allocate new header structure. |
9813 | * @param s string to be decoded as value of the new header structure |
9814 | * |
9815 | * @return |
9816 | * A pointer to newly maked #sip_proxy_authenticate_t header structure, or NULL upon an |
9817 | * error. |
9818 | * |
9819 | */ |
9820 | #if SU_HAVE_INLINE1 |
9821 | su_inlinestatic inline |
9822 | #endif |
9823 | sip_proxy_authenticate_t *sip_proxy_authenticate_make(su_home_t *home, char const *s) |
9824 | __attribute__((__malloc__)); |
9825 | |
9826 | #if SU_HAVE_INLINE1 |
9827 | su_inlinestatic inline sip_proxy_authenticate_t *sip_proxy_authenticate_make(su_home_t *home, char const *s) |
9828 | { |
9829 | return (sip_proxy_authenticate_t *)sip_header_make(home, sip_proxy_authenticate_class, s)((sip_header_t *)msg_header_make((home), (sip_proxy_authenticate_class ), (s))); |
9830 | } |
9831 | #endif |
9832 | |
9833 | /**Make a @ref sip_proxy_authenticate "Proxy-Authenticate header" from formatting result. |
9834 | * |
9835 | * Make a new #sip_proxy_authenticate_t object using formatting result as its value. |
9836 | * The function first prints the arguments according to the format @a fmt |
9837 | * specified. Then it allocates a new header structure, and parses the |
9838 | * formatting result to the structure #sip_proxy_authenticate_t. |
9839 | * |
9840 | * @param home memory home used to allocate new header structure. |
9841 | * @param fmt string used as a printf()-style format |
9842 | * @param ... argument list for format |
9843 | * |
9844 | * @return |
9845 | * A pointer to newly |
9846 | * makes header structure, or NULL upon an error. |
9847 | * |
9848 | * @HIDE |
9849 | * |
9850 | */ |
9851 | #if SU_HAVE_INLINE1 |
9852 | su_inlinestatic inline |
9853 | #endif |
9854 | sip_proxy_authenticate_t *sip_proxy_authenticate_format(su_home_t *home, char const *fmt, ...) |
9855 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
9856 | |
9857 | #if SU_HAVE_INLINE1 |
9858 | su_inlinestatic inline sip_proxy_authenticate_t *sip_proxy_authenticate_format(su_home_t *home, char const *fmt, ...) |
9859 | { |
9860 | sip_header_t *h; |
9861 | va_list ap; |
9862 | |
9863 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
9864 | h = sip_header_vformat(home, sip_proxy_authenticate_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_proxy_authenticate_class ), (fmt), (ap))); |
9865 | va_end(ap)__builtin_va_end(ap); |
9866 | |
9867 | return (sip_proxy_authenticate_t *)h; |
9868 | } |
9869 | #endif |
9870 | |
9871 | /** @} */ |
9872 | |
9873 | /**@addtogroup sip_proxy_authentication_info |
9874 | * @{ |
9875 | */ |
9876 | |
9877 | /** Parse a SIP @ref sip_proxy_authentication_info "Proxy-Authentication-Info header". @internal */ |
9878 | SOFIAPUBFUN issize_t sip_proxy_authentication_info_d(su_home_t *, msg_header_t *, |
9879 | char *s, isize_t slen); |
9880 | |
9881 | /** Print a SIP @ref sip_proxy_authentication_info "Proxy-Authentication-Info header". @internal */ |
9882 | SOFIAPUBFUN issize_t sip_proxy_authentication_info_e(char b[], isize_t bsiz, |
9883 | msg_header_t const *h, int flags); |
9884 | |
9885 | /**Access a SIP @ref sip_proxy_authentication_info "Proxy-Authentication-Info header" |
9886 | * structure #sip_proxy_authentication_info_t from #sip_t. |
9887 | * |
9888 | */ |
9889 | #define sip_proxy_authentication_info(sip)((sip_proxy_authentication_info_t *)msg_header_access((msg_pub_t *)(sip), sip_proxy_authentication_info_class)) \ |
9890 | ((sip_proxy_authentication_info_t *)msg_header_access((msg_pub_t*)(sip), sip_proxy_authentication_info_class)) |
9891 | |
9892 | /**Initializer for structure #sip_proxy_authentication_info_t. |
9893 | * |
9894 | * A static #sip_proxy_authentication_info_t structure for |
9895 | * @ref sip_proxy_authentication_info "Proxy-Authentication-Info header" must be initialized with |
9896 | * the SIP_PROXY_AUTHENTICATION_INFO_INIT() macro. |
9897 | * For instance, |
9898 | * @code |
9899 | * |
9900 | * sip_proxy_authentication_info_t sip_proxy_authentication_info = SIP_PROXY_AUTHENTICATION_INFO_INIT; |
9901 | * |
9902 | * @endcode |
9903 | * @HI |
9904 | * |
9905 | */ |
9906 | #define SIP_PROXY_AUTHENTICATION_INFO_INIT(){{{ 0, 0, sip_proxy_authentication_info_class }}} SIP_HDR_INIT(proxy_authentication_info){{{ 0, 0, sip_proxy_authentication_info_class }}} |
9907 | |
9908 | /**Initialize a structure #sip_proxy_authentication_info_t. |
9909 | * |
9910 | * An #sip_proxy_authentication_info_t structure for |
9911 | * @ref sip_proxy_authentication_info "Proxy-Authentication-Info header" can be initialized with the |
9912 | * sip_proxy_authentication_info_init() function/macro. For instance, |
9913 | * @code |
9914 | * |
9915 | * sip_proxy_authentication_info_t sip_proxy_authentication_info; |
9916 | * |
9917 | * sip_proxy_authentication_info_init(&sip_proxy_authentication_info); |
9918 | * |
9919 | * @endcode |
9920 | * @HI |
9921 | * |
9922 | */ |
9923 | #if SU_HAVE_INLINE1 |
9924 | su_inlinestatic inline sip_proxy_authentication_info_t *sip_proxy_authentication_info_init(sip_proxy_authentication_info_t x[1]) |
9925 | { |
9926 | return SIP_HEADER_INIT(x, sip_proxy_authentication_info_class, sizeof(sip_proxy_authentication_info_t))((void)memset((x), 0, (sizeof(sip_proxy_authentication_info_t ))), (void)(((sip_common_t *)(x))->h_class = (sip_proxy_authentication_info_class )), (x)); |
9927 | } |
9928 | #else |
9929 | #define sip_proxy_authentication_info_init(x) \ |
9930 | SIP_HEADER_INIT(x, sip_proxy_authentication_info_class, sizeof(sip_proxy_authentication_info_t))((void)memset((x), 0, (sizeof(sip_proxy_authentication_info_t ))), (void)(((sip_common_t *)(x))->h_class = (sip_proxy_authentication_info_class )), (x)) |
9931 | #endif |
9932 | |
9933 | /**Test if header object is instance of #sip_proxy_authentication_info_t. |
9934 | * |
9935 | * Check if the header class is an instance of |
9936 | * @ref sip_proxy_authentication_info "Proxy-Authentication-Info header" object and return true (nonzero), |
9937 | * otherwise return false (zero). |
9938 | * |
9939 | * @param header pointer to the header structure to be tested |
9940 | * |
9941 | * @retval 1 (true) if the @a header is an instance of header proxy_authentication_info |
9942 | * @retval 0 (false) otherwise |
9943 | * |
9944 | */ |
9945 | #if SU_HAVE_INLINE1 |
9946 | su_inlinestatic inline int sip_is_proxy_authentication_info(sip_header_t const *header) |
9947 | { |
9948 | return header && header->sh_classsh_common->h_class->hc_hash == sip_proxy_authentication_info_hash; |
9949 | } |
9950 | #else |
9951 | int sip_is_proxy_authentication_info(sip_header_t const *header); |
9952 | #endif |
9953 | |
9954 | #define sip_proxy_authentication_info_p(h)sip_is_proxy_authentication_info((h)) sip_is_proxy_authentication_info((h)) |
9955 | |
9956 | |
9957 | /**Duplicate a list of @ref sip_proxy_authentication_info "Proxy-Authentication-Info header" header structures #sip_proxy_authentication_info_t. |
9958 | * |
9959 | * Duplicate a header |
9960 | * structure @a hdr. If the header structure @a hdr |
9961 | * contains a reference (@c hdr->x_next) to a list of |
9962 | * headers, all the headers in the list are duplicated, too. |
9963 | * |
9964 | * @param home memory home used to allocate new structure |
9965 | * @param hdr header structure to be duplicated |
9966 | * |
9967 | * When duplicating, all parameter lists and non-constant |
9968 | * strings attached to the header are copied, too. The |
9969 | * function uses given memory @a home to allocate all the |
9970 | * memory areas used to copy the header. |
9971 | * |
9972 | * @par Example |
9973 | * @code |
9974 | * |
9975 | * proxy_authentication_info = sip_proxy_authentication_info_dup(home, sip->sip_proxy_authentication_info); |
9976 | * |
9977 | * @endcode |
9978 | * |
9979 | * @return |
9980 | * A pointer to the |
9981 | * newly duplicated #sip_proxy_authentication_info_t header structure, or NULL |
9982 | * upon an error. |
9983 | * |
9984 | */ |
9985 | #if SU_HAVE_INLINE1 |
9986 | su_inlinestatic inline |
9987 | #endif |
9988 | sip_proxy_authentication_info_t *sip_proxy_authentication_info_dup(su_home_t *home, sip_proxy_authentication_info_t const *hdr) |
9989 | __attribute__((__malloc__)); |
9990 | |
9991 | #if SU_HAVE_INLINE1 |
9992 | su_inlinestatic inline |
9993 | sip_proxy_authentication_info_t *sip_proxy_authentication_info_dup(su_home_t *home, sip_proxy_authentication_info_t const *hdr) |
9994 | { |
9995 | return (sip_proxy_authentication_info_t *) |
9996 | msg_header_dup_as(home, sip_proxy_authentication_info_class, (msg_header_t const *)hdr); |
9997 | } |
9998 | #endif |
9999 | |
10000 | /**Copy a list of @ref sip_proxy_authentication_info "Proxy-Authentication-Info header" header structures #sip_proxy_authentication_info_t. |
10001 | * |
10002 | * The function sip_proxy_authentication_info_copy() copies a header structure @a |
10003 | * hdr. If the header structure @a hdr contains a reference (@c |
10004 | * hdr->h_next) to a list of headers, all the headers in that |
10005 | * list are copied, too. The function uses given memory @a home |
10006 | * to allocate all the memory areas used to copy the list of header |
10007 | * structure @a hdr. |
10008 | * |
10009 | * @param home memory home used to allocate new structure |
10010 | * @param hdr pointer to the header structure to be copied |
10011 | * |
10012 | * When copying, only the header structure and parameter lists attached to |
10013 | * it are duplicated. The new header structure retains all the references to |
10014 | * the strings within the old @a hdr header, including the encoding of the |
10015 | * old header, if present. |
10016 | * |
10017 | * @par Example |
10018 | * @code |
10019 | * |
10020 | * proxy_authentication_info = sip_proxy_authentication_info_copy(home, sip->sip_proxy_authentication_info); |
10021 | * |
10022 | * @endcode |
10023 | * |
10024 | * @return |
10025 | * A pointer to newly copied header structure, or NULL upon an error. |
10026 | * |
10027 | */ |
10028 | #if SU_HAVE_INLINE1 |
10029 | su_inlinestatic inline |
10030 | #endif |
10031 | sip_proxy_authentication_info_t *sip_proxy_authentication_info_copy(su_home_t *home, sip_proxy_authentication_info_t const *hdr) |
10032 | __attribute__((__malloc__)); |
10033 | |
10034 | #if SU_HAVE_INLINE1 |
10035 | su_inlinestatic inline |
10036 | sip_proxy_authentication_info_t *sip_proxy_authentication_info_copy(su_home_t *home, sip_proxy_authentication_info_t const *hdr) |
10037 | { |
10038 | return (sip_proxy_authentication_info_t *) |
10039 | msg_header_copy_as(home, sip_proxy_authentication_info_class, (msg_header_t const *)hdr); |
10040 | } |
10041 | #endif |
10042 | |
10043 | /**Make a @ref sip_proxy_authentication_info "Proxy-Authentication-Info header" structure #sip_proxy_authentication_info_t. |
10044 | * |
10045 | * The function sip_proxy_authentication_info_make() makes a new |
10046 | * #sip_proxy_authentication_info_t header structure. It allocates a new |
10047 | * header structure, and decodes the string @a s as the |
10048 | * value of the structure. |
10049 | * |
10050 | * @param home memory home used to allocate new header structure. |
10051 | * @param s string to be decoded as value of the new header structure |
10052 | * |
10053 | * @return |
10054 | * A pointer to newly maked #sip_proxy_authentication_info_t header structure, or NULL upon an |
10055 | * error. |
10056 | * |
10057 | */ |
10058 | #if SU_HAVE_INLINE1 |
10059 | su_inlinestatic inline |
10060 | #endif |
10061 | sip_proxy_authentication_info_t *sip_proxy_authentication_info_make(su_home_t *home, char const *s) |
10062 | __attribute__((__malloc__)); |
10063 | |
10064 | #if SU_HAVE_INLINE1 |
10065 | su_inlinestatic inline sip_proxy_authentication_info_t *sip_proxy_authentication_info_make(su_home_t *home, char const *s) |
10066 | { |
10067 | return (sip_proxy_authentication_info_t *)sip_header_make(home, sip_proxy_authentication_info_class, s)((sip_header_t *)msg_header_make((home), (sip_proxy_authentication_info_class ), (s))); |
10068 | } |
10069 | #endif |
10070 | |
10071 | /**Make a @ref sip_proxy_authentication_info "Proxy-Authentication-Info header" from formatting result. |
10072 | * |
10073 | * Make a new #sip_proxy_authentication_info_t object using formatting result as its value. |
10074 | * The function first prints the arguments according to the format @a fmt |
10075 | * specified. Then it allocates a new header structure, and parses the |
10076 | * formatting result to the structure #sip_proxy_authentication_info_t. |
10077 | * |
10078 | * @param home memory home used to allocate new header structure. |
10079 | * @param fmt string used as a printf()-style format |
10080 | * @param ... argument list for format |
10081 | * |
10082 | * @return |
10083 | * A pointer to newly |
10084 | * makes header structure, or NULL upon an error. |
10085 | * |
10086 | * @HIDE |
10087 | * |
10088 | */ |
10089 | #if SU_HAVE_INLINE1 |
10090 | su_inlinestatic inline |
10091 | #endif |
10092 | sip_proxy_authentication_info_t *sip_proxy_authentication_info_format(su_home_t *home, char const *fmt, ...) |
10093 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
10094 | |
10095 | #if SU_HAVE_INLINE1 |
10096 | su_inlinestatic inline sip_proxy_authentication_info_t *sip_proxy_authentication_info_format(su_home_t *home, char const *fmt, ...) |
10097 | { |
10098 | sip_header_t *h; |
10099 | va_list ap; |
10100 | |
10101 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
10102 | h = sip_header_vformat(home, sip_proxy_authentication_info_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_proxy_authentication_info_class ), (fmt), (ap))); |
10103 | va_end(ap)__builtin_va_end(ap); |
10104 | |
10105 | return (sip_proxy_authentication_info_t *)h; |
10106 | } |
10107 | #endif |
10108 | |
10109 | /** @} */ |
10110 | |
10111 | /**@addtogroup sip_proxy_authorization |
10112 | * @{ |
10113 | */ |
10114 | |
10115 | /** Parse a SIP @ref sip_proxy_authorization "Proxy-Authorization header". @internal */ |
10116 | SOFIAPUBFUN issize_t sip_proxy_authorization_d(su_home_t *, msg_header_t *, |
10117 | char *s, isize_t slen); |
10118 | |
10119 | /** Print a SIP @ref sip_proxy_authorization "Proxy-Authorization header". @internal */ |
10120 | SOFIAPUBFUN issize_t sip_proxy_authorization_e(char b[], isize_t bsiz, |
10121 | msg_header_t const *h, int flags); |
10122 | |
10123 | /**Access a SIP @ref sip_proxy_authorization "Proxy-Authorization header" |
10124 | * structure #sip_proxy_authorization_t from #sip_t. |
10125 | * |
10126 | */ |
10127 | #define sip_proxy_authorization(sip)((sip_proxy_authorization_t *)msg_header_access((msg_pub_t*)( sip), sip_proxy_authorization_class)) \ |
10128 | ((sip_proxy_authorization_t *)msg_header_access((msg_pub_t*)(sip), sip_proxy_authorization_class)) |
10129 | |
10130 | /**Initializer for structure #sip_proxy_authorization_t. |
10131 | * |
10132 | * A static #sip_proxy_authorization_t structure for |
10133 | * @ref sip_proxy_authorization "Proxy-Authorization header" must be initialized with |
10134 | * the SIP_PROXY_AUTHORIZATION_INIT() macro. |
10135 | * For instance, |
10136 | * @code |
10137 | * |
10138 | * sip_proxy_authorization_t sip_proxy_authorization = SIP_PROXY_AUTHORIZATION_INIT; |
10139 | * |
10140 | * @endcode |
10141 | * @HI |
10142 | * |
10143 | */ |
10144 | #define SIP_PROXY_AUTHORIZATION_INIT(){{{ 0, 0, sip_proxy_authorization_class }}} SIP_HDR_INIT(proxy_authorization){{{ 0, 0, sip_proxy_authorization_class }}} |
10145 | |
10146 | /**Initialize a structure #sip_proxy_authorization_t. |
10147 | * |
10148 | * An #sip_proxy_authorization_t structure for |
10149 | * @ref sip_proxy_authorization "Proxy-Authorization header" can be initialized with the |
10150 | * sip_proxy_authorization_init() function/macro. For instance, |
10151 | * @code |
10152 | * |
10153 | * sip_proxy_authorization_t sip_proxy_authorization; |
10154 | * |
10155 | * sip_proxy_authorization_init(&sip_proxy_authorization); |
10156 | * |
10157 | * @endcode |
10158 | * @HI |
10159 | * |
10160 | */ |
10161 | #if SU_HAVE_INLINE1 |
10162 | su_inlinestatic inline sip_proxy_authorization_t *sip_proxy_authorization_init(sip_proxy_authorization_t x[1]) |
10163 | { |
10164 | return SIP_HEADER_INIT(x, sip_proxy_authorization_class, sizeof(sip_proxy_authorization_t))((void)memset((x), 0, (sizeof(sip_proxy_authorization_t))), ( void)(((sip_common_t *)(x))->h_class = (sip_proxy_authorization_class )), (x)); |
10165 | } |
10166 | #else |
10167 | #define sip_proxy_authorization_init(x) \ |
10168 | SIP_HEADER_INIT(x, sip_proxy_authorization_class, sizeof(sip_proxy_authorization_t))((void)memset((x), 0, (sizeof(sip_proxy_authorization_t))), ( void)(((sip_common_t *)(x))->h_class = (sip_proxy_authorization_class )), (x)) |
10169 | #endif |
10170 | |
10171 | /**Test if header object is instance of #sip_proxy_authorization_t. |
10172 | * |
10173 | * Check if the header class is an instance of |
10174 | * @ref sip_proxy_authorization "Proxy-Authorization header" object and return true (nonzero), |
10175 | * otherwise return false (zero). |
10176 | * |
10177 | * @param header pointer to the header structure to be tested |
10178 | * |
10179 | * @retval 1 (true) if the @a header is an instance of header proxy_authorization |
10180 | * @retval 0 (false) otherwise |
10181 | * |
10182 | */ |
10183 | #if SU_HAVE_INLINE1 |
10184 | su_inlinestatic inline int sip_is_proxy_authorization(sip_header_t const *header) |
10185 | { |
10186 | return header && header->sh_classsh_common->h_class->hc_hash == sip_proxy_authorization_hash; |
10187 | } |
10188 | #else |
10189 | int sip_is_proxy_authorization(sip_header_t const *header); |
10190 | #endif |
10191 | |
10192 | #define sip_proxy_authorization_p(h)sip_is_proxy_authorization((h)) sip_is_proxy_authorization((h)) |
10193 | |
10194 | |
10195 | /**Duplicate a list of @ref sip_proxy_authorization "Proxy-Authorization header" header structures #sip_proxy_authorization_t. |
10196 | * |
10197 | * Duplicate a header |
10198 | * structure @a hdr. If the header structure @a hdr |
10199 | * contains a reference (@c hdr->x_next) to a list of |
10200 | * headers, all the headers in the list are duplicated, too. |
10201 | * |
10202 | * @param home memory home used to allocate new structure |
10203 | * @param hdr header structure to be duplicated |
10204 | * |
10205 | * When duplicating, all parameter lists and non-constant |
10206 | * strings attached to the header are copied, too. The |
10207 | * function uses given memory @a home to allocate all the |
10208 | * memory areas used to copy the header. |
10209 | * |
10210 | * @par Example |
10211 | * @code |
10212 | * |
10213 | * proxy_authorization = sip_proxy_authorization_dup(home, sip->sip_proxy_authorization); |
10214 | * |
10215 | * @endcode |
10216 | * |
10217 | * @return |
10218 | * A pointer to the |
10219 | * newly duplicated #sip_proxy_authorization_t header structure, or NULL |
10220 | * upon an error. |
10221 | * |
10222 | */ |
10223 | #if SU_HAVE_INLINE1 |
10224 | su_inlinestatic inline |
10225 | #endif |
10226 | sip_proxy_authorization_t *sip_proxy_authorization_dup(su_home_t *home, sip_proxy_authorization_t const *hdr) |
10227 | __attribute__((__malloc__)); |
10228 | |
10229 | #if SU_HAVE_INLINE1 |
10230 | su_inlinestatic inline |
10231 | sip_proxy_authorization_t *sip_proxy_authorization_dup(su_home_t *home, sip_proxy_authorization_t const *hdr) |
10232 | { |
10233 | return (sip_proxy_authorization_t *) |
10234 | msg_header_dup_as(home, sip_proxy_authorization_class, (msg_header_t const *)hdr); |
10235 | } |
10236 | #endif |
10237 | |
10238 | /**Copy a list of @ref sip_proxy_authorization "Proxy-Authorization header" header structures #sip_proxy_authorization_t. |
10239 | * |
10240 | * The function sip_proxy_authorization_copy() copies a header structure @a |
10241 | * hdr. If the header structure @a hdr contains a reference (@c |
10242 | * hdr->h_next) to a list of headers, all the headers in that |
10243 | * list are copied, too. The function uses given memory @a home |
10244 | * to allocate all the memory areas used to copy the list of header |
10245 | * structure @a hdr. |
10246 | * |
10247 | * @param home memory home used to allocate new structure |
10248 | * @param hdr pointer to the header structure to be copied |
10249 | * |
10250 | * When copying, only the header structure and parameter lists attached to |
10251 | * it are duplicated. The new header structure retains all the references to |
10252 | * the strings within the old @a hdr header, including the encoding of the |
10253 | * old header, if present. |
10254 | * |
10255 | * @par Example |
10256 | * @code |
10257 | * |
10258 | * proxy_authorization = sip_proxy_authorization_copy(home, sip->sip_proxy_authorization); |
10259 | * |
10260 | * @endcode |
10261 | * |
10262 | * @return |
10263 | * A pointer to newly copied header structure, or NULL upon an error. |
10264 | * |
10265 | */ |
10266 | #if SU_HAVE_INLINE1 |
10267 | su_inlinestatic inline |
10268 | #endif |
10269 | sip_proxy_authorization_t *sip_proxy_authorization_copy(su_home_t *home, sip_proxy_authorization_t const *hdr) |
10270 | __attribute__((__malloc__)); |
10271 | |
10272 | #if SU_HAVE_INLINE1 |
10273 | su_inlinestatic inline |
10274 | sip_proxy_authorization_t *sip_proxy_authorization_copy(su_home_t *home, sip_proxy_authorization_t const *hdr) |
10275 | { |
10276 | return (sip_proxy_authorization_t *) |
10277 | msg_header_copy_as(home, sip_proxy_authorization_class, (msg_header_t const *)hdr); |
10278 | } |
10279 | #endif |
10280 | |
10281 | /**Make a @ref sip_proxy_authorization "Proxy-Authorization header" structure #sip_proxy_authorization_t. |
10282 | * |
10283 | * The function sip_proxy_authorization_make() makes a new |
10284 | * #sip_proxy_authorization_t header structure. It allocates a new |
10285 | * header structure, and decodes the string @a s as the |
10286 | * value of the structure. |
10287 | * |
10288 | * @param home memory home used to allocate new header structure. |
10289 | * @param s string to be decoded as value of the new header structure |
10290 | * |
10291 | * @return |
10292 | * A pointer to newly maked #sip_proxy_authorization_t header structure, or NULL upon an |
10293 | * error. |
10294 | * |
10295 | */ |
10296 | #if SU_HAVE_INLINE1 |
10297 | su_inlinestatic inline |
10298 | #endif |
10299 | sip_proxy_authorization_t *sip_proxy_authorization_make(su_home_t *home, char const *s) |
10300 | __attribute__((__malloc__)); |
10301 | |
10302 | #if SU_HAVE_INLINE1 |
10303 | su_inlinestatic inline sip_proxy_authorization_t *sip_proxy_authorization_make(su_home_t *home, char const *s) |
10304 | { |
10305 | return (sip_proxy_authorization_t *)sip_header_make(home, sip_proxy_authorization_class, s)((sip_header_t *)msg_header_make((home), (sip_proxy_authorization_class ), (s))); |
10306 | } |
10307 | #endif |
10308 | |
10309 | /**Make a @ref sip_proxy_authorization "Proxy-Authorization header" from formatting result. |
10310 | * |
10311 | * Make a new #sip_proxy_authorization_t object using formatting result as its value. |
10312 | * The function first prints the arguments according to the format @a fmt |
10313 | * specified. Then it allocates a new header structure, and parses the |
10314 | * formatting result to the structure #sip_proxy_authorization_t. |
10315 | * |
10316 | * @param home memory home used to allocate new header structure. |
10317 | * @param fmt string used as a printf()-style format |
10318 | * @param ... argument list for format |
10319 | * |
10320 | * @return |
10321 | * A pointer to newly |
10322 | * makes header structure, or NULL upon an error. |
10323 | * |
10324 | * @HIDE |
10325 | * |
10326 | */ |
10327 | #if SU_HAVE_INLINE1 |
10328 | su_inlinestatic inline |
10329 | #endif |
10330 | sip_proxy_authorization_t *sip_proxy_authorization_format(su_home_t *home, char const *fmt, ...) |
10331 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
10332 | |
10333 | #if SU_HAVE_INLINE1 |
10334 | su_inlinestatic inline sip_proxy_authorization_t *sip_proxy_authorization_format(su_home_t *home, char const *fmt, ...) |
10335 | { |
10336 | sip_header_t *h; |
10337 | va_list ap; |
10338 | |
10339 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
10340 | h = sip_header_vformat(home, sip_proxy_authorization_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_proxy_authorization_class ), (fmt), (ap))); |
10341 | va_end(ap)__builtin_va_end(ap); |
10342 | |
10343 | return (sip_proxy_authorization_t *)h; |
10344 | } |
10345 | #endif |
10346 | |
10347 | /** @} */ |
10348 | |
10349 | /**@addtogroup sip_authorization |
10350 | * @{ |
10351 | */ |
10352 | |
10353 | /** Parse a SIP @ref sip_authorization "Authorization header". @internal */ |
10354 | SOFIAPUBFUN issize_t sip_authorization_d(su_home_t *, msg_header_t *, |
10355 | char *s, isize_t slen); |
10356 | |
10357 | /** Print a SIP @ref sip_authorization "Authorization header". @internal */ |
10358 | SOFIAPUBFUN issize_t sip_authorization_e(char b[], isize_t bsiz, |
10359 | msg_header_t const *h, int flags); |
10360 | |
10361 | /**Access a SIP @ref sip_authorization "Authorization header" |
10362 | * structure #sip_authorization_t from #sip_t. |
10363 | * |
10364 | */ |
10365 | #define sip_authorization(sip)((sip_authorization_t *)msg_header_access((msg_pub_t*)(sip), sip_authorization_class )) \ |
10366 | ((sip_authorization_t *)msg_header_access((msg_pub_t*)(sip), sip_authorization_class)) |
10367 | |
10368 | /**Initializer for structure #sip_authorization_t. |
10369 | * |
10370 | * A static #sip_authorization_t structure for |
10371 | * @ref sip_authorization "Authorization header" must be initialized with |
10372 | * the SIP_AUTHORIZATION_INIT() macro. |
10373 | * For instance, |
10374 | * @code |
10375 | * |
10376 | * sip_authorization_t sip_authorization = SIP_AUTHORIZATION_INIT; |
10377 | * |
10378 | * @endcode |
10379 | * @HI |
10380 | * |
10381 | */ |
10382 | #define SIP_AUTHORIZATION_INIT(){{{ 0, 0, sip_authorization_class }}} SIP_HDR_INIT(authorization){{{ 0, 0, sip_authorization_class }}} |
10383 | |
10384 | /**Initialize a structure #sip_authorization_t. |
10385 | * |
10386 | * An #sip_authorization_t structure for |
10387 | * @ref sip_authorization "Authorization header" can be initialized with the |
10388 | * sip_authorization_init() function/macro. For instance, |
10389 | * @code |
10390 | * |
10391 | * sip_authorization_t sip_authorization; |
10392 | * |
10393 | * sip_authorization_init(&sip_authorization); |
10394 | * |
10395 | * @endcode |
10396 | * @HI |
10397 | * |
10398 | */ |
10399 | #if SU_HAVE_INLINE1 |
10400 | su_inlinestatic inline sip_authorization_t *sip_authorization_init(sip_authorization_t x[1]) |
10401 | { |
10402 | return SIP_HEADER_INIT(x, sip_authorization_class, sizeof(sip_authorization_t))((void)memset((x), 0, (sizeof(sip_authorization_t))), (void)( ((sip_common_t *)(x))->h_class = (sip_authorization_class) ), (x)); |
10403 | } |
10404 | #else |
10405 | #define sip_authorization_init(x) \ |
10406 | SIP_HEADER_INIT(x, sip_authorization_class, sizeof(sip_authorization_t))((void)memset((x), 0, (sizeof(sip_authorization_t))), (void)( ((sip_common_t *)(x))->h_class = (sip_authorization_class) ), (x)) |
10407 | #endif |
10408 | |
10409 | /**Test if header object is instance of #sip_authorization_t. |
10410 | * |
10411 | * Check if the header class is an instance of |
10412 | * @ref sip_authorization "Authorization header" object and return true (nonzero), |
10413 | * otherwise return false (zero). |
10414 | * |
10415 | * @param header pointer to the header structure to be tested |
10416 | * |
10417 | * @retval 1 (true) if the @a header is an instance of header authorization |
10418 | * @retval 0 (false) otherwise |
10419 | * |
10420 | */ |
10421 | #if SU_HAVE_INLINE1 |
10422 | su_inlinestatic inline int sip_is_authorization(sip_header_t const *header) |
10423 | { |
10424 | return header && header->sh_classsh_common->h_class->hc_hash == sip_authorization_hash; |
10425 | } |
10426 | #else |
10427 | int sip_is_authorization(sip_header_t const *header); |
10428 | #endif |
10429 | |
10430 | #define sip_authorization_p(h)sip_is_authorization((h)) sip_is_authorization((h)) |
10431 | |
10432 | |
10433 | /**Duplicate a list of @ref sip_authorization "Authorization header" header structures #sip_authorization_t. |
10434 | * |
10435 | * Duplicate a header |
10436 | * structure @a hdr. If the header structure @a hdr |
10437 | * contains a reference (@c hdr->x_next) to a list of |
10438 | * headers, all the headers in the list are duplicated, too. |
10439 | * |
10440 | * @param home memory home used to allocate new structure |
10441 | * @param hdr header structure to be duplicated |
10442 | * |
10443 | * When duplicating, all parameter lists and non-constant |
10444 | * strings attached to the header are copied, too. The |
10445 | * function uses given memory @a home to allocate all the |
10446 | * memory areas used to copy the header. |
10447 | * |
10448 | * @par Example |
10449 | * @code |
10450 | * |
10451 | * authorization = sip_authorization_dup(home, sip->sip_authorization); |
10452 | * |
10453 | * @endcode |
10454 | * |
10455 | * @return |
10456 | * A pointer to the |
10457 | * newly duplicated #sip_authorization_t header structure, or NULL |
10458 | * upon an error. |
10459 | * |
10460 | */ |
10461 | #if SU_HAVE_INLINE1 |
10462 | su_inlinestatic inline |
10463 | #endif |
10464 | sip_authorization_t *sip_authorization_dup(su_home_t *home, sip_authorization_t const *hdr) |
10465 | __attribute__((__malloc__)); |
10466 | |
10467 | #if SU_HAVE_INLINE1 |
10468 | su_inlinestatic inline |
10469 | sip_authorization_t *sip_authorization_dup(su_home_t *home, sip_authorization_t const *hdr) |
10470 | { |
10471 | return (sip_authorization_t *) |
10472 | msg_header_dup_as(home, sip_authorization_class, (msg_header_t const *)hdr); |
10473 | } |
10474 | #endif |
10475 | |
10476 | /**Copy a list of @ref sip_authorization "Authorization header" header structures #sip_authorization_t. |
10477 | * |
10478 | * The function sip_authorization_copy() copies a header structure @a |
10479 | * hdr. If the header structure @a hdr contains a reference (@c |
10480 | * hdr->h_next) to a list of headers, all the headers in that |
10481 | * list are copied, too. The function uses given memory @a home |
10482 | * to allocate all the memory areas used to copy the list of header |
10483 | * structure @a hdr. |
10484 | * |
10485 | * @param home memory home used to allocate new structure |
10486 | * @param hdr pointer to the header structure to be copied |
10487 | * |
10488 | * When copying, only the header structure and parameter lists attached to |
10489 | * it are duplicated. The new header structure retains all the references to |
10490 | * the strings within the old @a hdr header, including the encoding of the |
10491 | * old header, if present. |
10492 | * |
10493 | * @par Example |
10494 | * @code |
10495 | * |
10496 | * authorization = sip_authorization_copy(home, sip->sip_authorization); |
10497 | * |
10498 | * @endcode |
10499 | * |
10500 | * @return |
10501 | * A pointer to newly copied header structure, or NULL upon an error. |
10502 | * |
10503 | */ |
10504 | #if SU_HAVE_INLINE1 |
10505 | su_inlinestatic inline |
10506 | #endif |
10507 | sip_authorization_t *sip_authorization_copy(su_home_t *home, sip_authorization_t const *hdr) |
10508 | __attribute__((__malloc__)); |
10509 | |
10510 | #if SU_HAVE_INLINE1 |
10511 | su_inlinestatic inline |
10512 | sip_authorization_t *sip_authorization_copy(su_home_t *home, sip_authorization_t const *hdr) |
10513 | { |
10514 | return (sip_authorization_t *) |
10515 | msg_header_copy_as(home, sip_authorization_class, (msg_header_t const *)hdr); |
10516 | } |
10517 | #endif |
10518 | |
10519 | /**Make a @ref sip_authorization "Authorization header" structure #sip_authorization_t. |
10520 | * |
10521 | * The function sip_authorization_make() makes a new |
10522 | * #sip_authorization_t header structure. It allocates a new |
10523 | * header structure, and decodes the string @a s as the |
10524 | * value of the structure. |
10525 | * |
10526 | * @param home memory home used to allocate new header structure. |
10527 | * @param s string to be decoded as value of the new header structure |
10528 | * |
10529 | * @return |
10530 | * A pointer to newly maked #sip_authorization_t header structure, or NULL upon an |
10531 | * error. |
10532 | * |
10533 | */ |
10534 | #if SU_HAVE_INLINE1 |
10535 | su_inlinestatic inline |
10536 | #endif |
10537 | sip_authorization_t *sip_authorization_make(su_home_t *home, char const *s) |
10538 | __attribute__((__malloc__)); |
10539 | |
10540 | #if SU_HAVE_INLINE1 |
10541 | su_inlinestatic inline sip_authorization_t *sip_authorization_make(su_home_t *home, char const *s) |
10542 | { |
10543 | return (sip_authorization_t *)sip_header_make(home, sip_authorization_class, s)((sip_header_t *)msg_header_make((home), (sip_authorization_class ), (s))); |
10544 | } |
10545 | #endif |
10546 | |
10547 | /**Make a @ref sip_authorization "Authorization header" from formatting result. |
10548 | * |
10549 | * Make a new #sip_authorization_t object using formatting result as its value. |
10550 | * The function first prints the arguments according to the format @a fmt |
10551 | * specified. Then it allocates a new header structure, and parses the |
10552 | * formatting result to the structure #sip_authorization_t. |
10553 | * |
10554 | * @param home memory home used to allocate new header structure. |
10555 | * @param fmt string used as a printf()-style format |
10556 | * @param ... argument list for format |
10557 | * |
10558 | * @return |
10559 | * A pointer to newly |
10560 | * makes header structure, or NULL upon an error. |
10561 | * |
10562 | * @HIDE |
10563 | * |
10564 | */ |
10565 | #if SU_HAVE_INLINE1 |
10566 | su_inlinestatic inline |
10567 | #endif |
10568 | sip_authorization_t *sip_authorization_format(su_home_t *home, char const *fmt, ...) |
10569 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
10570 | |
10571 | #if SU_HAVE_INLINE1 |
10572 | su_inlinestatic inline sip_authorization_t *sip_authorization_format(su_home_t *home, char const *fmt, ...) |
10573 | { |
10574 | sip_header_t *h; |
10575 | va_list ap; |
10576 | |
10577 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
10578 | h = sip_header_vformat(home, sip_authorization_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_authorization_class ), (fmt), (ap))); |
10579 | va_end(ap)__builtin_va_end(ap); |
10580 | |
10581 | return (sip_authorization_t *)h; |
10582 | } |
10583 | #endif |
10584 | |
10585 | /** @} */ |
10586 | |
10587 | /**@addtogroup sip_www_authenticate |
10588 | * @{ |
10589 | */ |
10590 | |
10591 | /** Parse a SIP @ref sip_www_authenticate "WWW-Authenticate header". @internal */ |
10592 | SOFIAPUBFUN issize_t sip_www_authenticate_d(su_home_t *, msg_header_t *, |
10593 | char *s, isize_t slen); |
10594 | |
10595 | /** Print a SIP @ref sip_www_authenticate "WWW-Authenticate header". @internal */ |
10596 | SOFIAPUBFUN issize_t sip_www_authenticate_e(char b[], isize_t bsiz, |
10597 | msg_header_t const *h, int flags); |
10598 | |
10599 | /**Access a SIP @ref sip_www_authenticate "WWW-Authenticate header" |
10600 | * structure #sip_www_authenticate_t from #sip_t. |
10601 | * |
10602 | */ |
10603 | #define sip_www_authenticate(sip)((sip_www_authenticate_t *)msg_header_access((msg_pub_t*)(sip ), sip_www_authenticate_class)) \ |
10604 | ((sip_www_authenticate_t *)msg_header_access((msg_pub_t*)(sip), sip_www_authenticate_class)) |
10605 | |
10606 | /**Initializer for structure #sip_www_authenticate_t. |
10607 | * |
10608 | * A static #sip_www_authenticate_t structure for |
10609 | * @ref sip_www_authenticate "WWW-Authenticate header" must be initialized with |
10610 | * the SIP_WWW_AUTHENTICATE_INIT() macro. |
10611 | * For instance, |
10612 | * @code |
10613 | * |
10614 | * sip_www_authenticate_t sip_www_authenticate = SIP_WWW_AUTHENTICATE_INIT; |
10615 | * |
10616 | * @endcode |
10617 | * @HI |
10618 | * |
10619 | */ |
10620 | #define SIP_WWW_AUTHENTICATE_INIT(){{{ 0, 0, sip_www_authenticate_class }}} SIP_HDR_INIT(www_authenticate){{{ 0, 0, sip_www_authenticate_class }}} |
10621 | |
10622 | /**Initialize a structure #sip_www_authenticate_t. |
10623 | * |
10624 | * An #sip_www_authenticate_t structure for |
10625 | * @ref sip_www_authenticate "WWW-Authenticate header" can be initialized with the |
10626 | * sip_www_authenticate_init() function/macro. For instance, |
10627 | * @code |
10628 | * |
10629 | * sip_www_authenticate_t sip_www_authenticate; |
10630 | * |
10631 | * sip_www_authenticate_init(&sip_www_authenticate); |
10632 | * |
10633 | * @endcode |
10634 | * @HI |
10635 | * |
10636 | */ |
10637 | #if SU_HAVE_INLINE1 |
10638 | su_inlinestatic inline sip_www_authenticate_t *sip_www_authenticate_init(sip_www_authenticate_t x[1]) |
10639 | { |
10640 | return SIP_HEADER_INIT(x, sip_www_authenticate_class, sizeof(sip_www_authenticate_t))((void)memset((x), 0, (sizeof(sip_www_authenticate_t))), (void )(((sip_common_t *)(x))->h_class = (sip_www_authenticate_class )), (x)); |
10641 | } |
10642 | #else |
10643 | #define sip_www_authenticate_init(x) \ |
10644 | SIP_HEADER_INIT(x, sip_www_authenticate_class, sizeof(sip_www_authenticate_t))((void)memset((x), 0, (sizeof(sip_www_authenticate_t))), (void )(((sip_common_t *)(x))->h_class = (sip_www_authenticate_class )), (x)) |
10645 | #endif |
10646 | |
10647 | /**Test if header object is instance of #sip_www_authenticate_t. |
10648 | * |
10649 | * Check if the header class is an instance of |
10650 | * @ref sip_www_authenticate "WWW-Authenticate header" object and return true (nonzero), |
10651 | * otherwise return false (zero). |
10652 | * |
10653 | * @param header pointer to the header structure to be tested |
10654 | * |
10655 | * @retval 1 (true) if the @a header is an instance of header www_authenticate |
10656 | * @retval 0 (false) otherwise |
10657 | * |
10658 | */ |
10659 | #if SU_HAVE_INLINE1 |
10660 | su_inlinestatic inline int sip_is_www_authenticate(sip_header_t const *header) |
10661 | { |
10662 | return header && header->sh_classsh_common->h_class->hc_hash == sip_www_authenticate_hash; |
10663 | } |
10664 | #else |
10665 | int sip_is_www_authenticate(sip_header_t const *header); |
10666 | #endif |
10667 | |
10668 | #define sip_www_authenticate_p(h)sip_is_www_authenticate((h)) sip_is_www_authenticate((h)) |
10669 | |
10670 | |
10671 | /**Duplicate a list of @ref sip_www_authenticate "WWW-Authenticate header" header structures #sip_www_authenticate_t. |
10672 | * |
10673 | * Duplicate a header |
10674 | * structure @a hdr. If the header structure @a hdr |
10675 | * contains a reference (@c hdr->x_next) to a list of |
10676 | * headers, all the headers in the list are duplicated, too. |
10677 | * |
10678 | * @param home memory home used to allocate new structure |
10679 | * @param hdr header structure to be duplicated |
10680 | * |
10681 | * When duplicating, all parameter lists and non-constant |
10682 | * strings attached to the header are copied, too. The |
10683 | * function uses given memory @a home to allocate all the |
10684 | * memory areas used to copy the header. |
10685 | * |
10686 | * @par Example |
10687 | * @code |
10688 | * |
10689 | * www_authenticate = sip_www_authenticate_dup(home, sip->sip_www_authenticate); |
10690 | * |
10691 | * @endcode |
10692 | * |
10693 | * @return |
10694 | * A pointer to the |
10695 | * newly duplicated #sip_www_authenticate_t header structure, or NULL |
10696 | * upon an error. |
10697 | * |
10698 | */ |
10699 | #if SU_HAVE_INLINE1 |
10700 | su_inlinestatic inline |
10701 | #endif |
10702 | sip_www_authenticate_t *sip_www_authenticate_dup(su_home_t *home, sip_www_authenticate_t const *hdr) |
10703 | __attribute__((__malloc__)); |
10704 | |
10705 | #if SU_HAVE_INLINE1 |
10706 | su_inlinestatic inline |
10707 | sip_www_authenticate_t *sip_www_authenticate_dup(su_home_t *home, sip_www_authenticate_t const *hdr) |
10708 | { |
10709 | return (sip_www_authenticate_t *) |
10710 | msg_header_dup_as(home, sip_www_authenticate_class, (msg_header_t const *)hdr); |
10711 | } |
10712 | #endif |
10713 | |
10714 | /**Copy a list of @ref sip_www_authenticate "WWW-Authenticate header" header structures #sip_www_authenticate_t. |
10715 | * |
10716 | * The function sip_www_authenticate_copy() copies a header structure @a |
10717 | * hdr. If the header structure @a hdr contains a reference (@c |
10718 | * hdr->h_next) to a list of headers, all the headers in that |
10719 | * list are copied, too. The function uses given memory @a home |
10720 | * to allocate all the memory areas used to copy the list of header |
10721 | * structure @a hdr. |
10722 | * |
10723 | * @param home memory home used to allocate new structure |
10724 | * @param hdr pointer to the header structure to be copied |
10725 | * |
10726 | * When copying, only the header structure and parameter lists attached to |
10727 | * it are duplicated. The new header structure retains all the references to |
10728 | * the strings within the old @a hdr header, including the encoding of the |
10729 | * old header, if present. |
10730 | * |
10731 | * @par Example |
10732 | * @code |
10733 | * |
10734 | * www_authenticate = sip_www_authenticate_copy(home, sip->sip_www_authenticate); |
10735 | * |
10736 | * @endcode |
10737 | * |
10738 | * @return |
10739 | * A pointer to newly copied header structure, or NULL upon an error. |
10740 | * |
10741 | */ |
10742 | #if SU_HAVE_INLINE1 |
10743 | su_inlinestatic inline |
10744 | #endif |
10745 | sip_www_authenticate_t *sip_www_authenticate_copy(su_home_t *home, sip_www_authenticate_t const *hdr) |
10746 | __attribute__((__malloc__)); |
10747 | |
10748 | #if SU_HAVE_INLINE1 |
10749 | su_inlinestatic inline |
10750 | sip_www_authenticate_t *sip_www_authenticate_copy(su_home_t *home, sip_www_authenticate_t const *hdr) |
10751 | { |
10752 | return (sip_www_authenticate_t *) |
10753 | msg_header_copy_as(home, sip_www_authenticate_class, (msg_header_t const *)hdr); |
10754 | } |
10755 | #endif |
10756 | |
10757 | /**Make a @ref sip_www_authenticate "WWW-Authenticate header" structure #sip_www_authenticate_t. |
10758 | * |
10759 | * The function sip_www_authenticate_make() makes a new |
10760 | * #sip_www_authenticate_t header structure. It allocates a new |
10761 | * header structure, and decodes the string @a s as the |
10762 | * value of the structure. |
10763 | * |
10764 | * @param home memory home used to allocate new header structure. |
10765 | * @param s string to be decoded as value of the new header structure |
10766 | * |
10767 | * @return |
10768 | * A pointer to newly maked #sip_www_authenticate_t header structure, or NULL upon an |
10769 | * error. |
10770 | * |
10771 | */ |
10772 | #if SU_HAVE_INLINE1 |
10773 | su_inlinestatic inline |
10774 | #endif |
10775 | sip_www_authenticate_t *sip_www_authenticate_make(su_home_t *home, char const *s) |
10776 | __attribute__((__malloc__)); |
10777 | |
10778 | #if SU_HAVE_INLINE1 |
10779 | su_inlinestatic inline sip_www_authenticate_t *sip_www_authenticate_make(su_home_t *home, char const *s) |
10780 | { |
10781 | return (sip_www_authenticate_t *)sip_header_make(home, sip_www_authenticate_class, s)((sip_header_t *)msg_header_make((home), (sip_www_authenticate_class ), (s))); |
10782 | } |
10783 | #endif |
10784 | |
10785 | /**Make a @ref sip_www_authenticate "WWW-Authenticate header" from formatting result. |
10786 | * |
10787 | * Make a new #sip_www_authenticate_t object using formatting result as its value. |
10788 | * The function first prints the arguments according to the format @a fmt |
10789 | * specified. Then it allocates a new header structure, and parses the |
10790 | * formatting result to the structure #sip_www_authenticate_t. |
10791 | * |
10792 | * @param home memory home used to allocate new header structure. |
10793 | * @param fmt string used as a printf()-style format |
10794 | * @param ... argument list for format |
10795 | * |
10796 | * @return |
10797 | * A pointer to newly |
10798 | * makes header structure, or NULL upon an error. |
10799 | * |
10800 | * @HIDE |
10801 | * |
10802 | */ |
10803 | #if SU_HAVE_INLINE1 |
10804 | su_inlinestatic inline |
10805 | #endif |
10806 | sip_www_authenticate_t *sip_www_authenticate_format(su_home_t *home, char const *fmt, ...) |
10807 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
10808 | |
10809 | #if SU_HAVE_INLINE1 |
10810 | su_inlinestatic inline sip_www_authenticate_t *sip_www_authenticate_format(su_home_t *home, char const *fmt, ...) |
10811 | { |
10812 | sip_header_t *h; |
10813 | va_list ap; |
10814 | |
10815 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
10816 | h = sip_header_vformat(home, sip_www_authenticate_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_www_authenticate_class ), (fmt), (ap))); |
10817 | va_end(ap)__builtin_va_end(ap); |
10818 | |
10819 | return (sip_www_authenticate_t *)h; |
10820 | } |
10821 | #endif |
10822 | |
10823 | /** @} */ |
10824 | |
10825 | /**@addtogroup sip_authentication_info |
10826 | * @{ |
10827 | */ |
10828 | |
10829 | /** Parse a SIP @ref sip_authentication_info "Authentication-Info header". @internal */ |
10830 | SOFIAPUBFUN issize_t sip_authentication_info_d(su_home_t *, msg_header_t *, |
10831 | char *s, isize_t slen); |
10832 | |
10833 | /** Print a SIP @ref sip_authentication_info "Authentication-Info header". @internal */ |
10834 | SOFIAPUBFUN issize_t sip_authentication_info_e(char b[], isize_t bsiz, |
10835 | msg_header_t const *h, int flags); |
10836 | |
10837 | /**Access a SIP @ref sip_authentication_info "Authentication-Info header" |
10838 | * structure #sip_authentication_info_t from #sip_t. |
10839 | * |
10840 | */ |
10841 | #define sip_authentication_info(sip)((sip_authentication_info_t *)msg_header_access((msg_pub_t*)( sip), sip_authentication_info_class)) \ |
10842 | ((sip_authentication_info_t *)msg_header_access((msg_pub_t*)(sip), sip_authentication_info_class)) |
10843 | |
10844 | /**Initializer for structure #sip_authentication_info_t. |
10845 | * |
10846 | * A static #sip_authentication_info_t structure for |
10847 | * @ref sip_authentication_info "Authentication-Info header" must be initialized with |
10848 | * the SIP_AUTHENTICATION_INFO_INIT() macro. |
10849 | * For instance, |
10850 | * @code |
10851 | * |
10852 | * sip_authentication_info_t sip_authentication_info = SIP_AUTHENTICATION_INFO_INIT; |
10853 | * |
10854 | * @endcode |
10855 | * @HI |
10856 | * |
10857 | */ |
10858 | #define SIP_AUTHENTICATION_INFO_INIT(){{{ 0, 0, sip_authentication_info_class }}} SIP_HDR_INIT(authentication_info){{{ 0, 0, sip_authentication_info_class }}} |
10859 | |
10860 | /**Initialize a structure #sip_authentication_info_t. |
10861 | * |
10862 | * An #sip_authentication_info_t structure for |
10863 | * @ref sip_authentication_info "Authentication-Info header" can be initialized with the |
10864 | * sip_authentication_info_init() function/macro. For instance, |
10865 | * @code |
10866 | * |
10867 | * sip_authentication_info_t sip_authentication_info; |
10868 | * |
10869 | * sip_authentication_info_init(&sip_authentication_info); |
10870 | * |
10871 | * @endcode |
10872 | * @HI |
10873 | * |
10874 | */ |
10875 | #if SU_HAVE_INLINE1 |
10876 | su_inlinestatic inline sip_authentication_info_t *sip_authentication_info_init(sip_authentication_info_t x[1]) |
10877 | { |
10878 | return SIP_HEADER_INIT(x, sip_authentication_info_class, sizeof(sip_authentication_info_t))((void)memset((x), 0, (sizeof(sip_authentication_info_t))), ( void)(((sip_common_t *)(x))->h_class = (sip_authentication_info_class )), (x)); |
10879 | } |
10880 | #else |
10881 | #define sip_authentication_info_init(x) \ |
10882 | SIP_HEADER_INIT(x, sip_authentication_info_class, sizeof(sip_authentication_info_t))((void)memset((x), 0, (sizeof(sip_authentication_info_t))), ( void)(((sip_common_t *)(x))->h_class = (sip_authentication_info_class )), (x)) |
10883 | #endif |
10884 | |
10885 | /**Test if header object is instance of #sip_authentication_info_t. |
10886 | * |
10887 | * Check if the header class is an instance of |
10888 | * @ref sip_authentication_info "Authentication-Info header" object and return true (nonzero), |
10889 | * otherwise return false (zero). |
10890 | * |
10891 | * @param header pointer to the header structure to be tested |
10892 | * |
10893 | * @retval 1 (true) if the @a header is an instance of header authentication_info |
10894 | * @retval 0 (false) otherwise |
10895 | * |
10896 | */ |
10897 | #if SU_HAVE_INLINE1 |
10898 | su_inlinestatic inline int sip_is_authentication_info(sip_header_t const *header) |
10899 | { |
10900 | return header && header->sh_classsh_common->h_class->hc_hash == sip_authentication_info_hash; |
10901 | } |
10902 | #else |
10903 | int sip_is_authentication_info(sip_header_t const *header); |
10904 | #endif |
10905 | |
10906 | #define sip_authentication_info_p(h)sip_is_authentication_info((h)) sip_is_authentication_info((h)) |
10907 | |
10908 | |
10909 | /**Duplicate a list of @ref sip_authentication_info "Authentication-Info header" header structures #sip_authentication_info_t. |
10910 | * |
10911 | * Duplicate a header |
10912 | * structure @a hdr. If the header structure @a hdr |
10913 | * contains a reference (@c hdr->x_next) to a list of |
10914 | * headers, all the headers in the list are duplicated, too. |
10915 | * |
10916 | * @param home memory home used to allocate new structure |
10917 | * @param hdr header structure to be duplicated |
10918 | * |
10919 | * When duplicating, all parameter lists and non-constant |
10920 | * strings attached to the header are copied, too. The |
10921 | * function uses given memory @a home to allocate all the |
10922 | * memory areas used to copy the header. |
10923 | * |
10924 | * @par Example |
10925 | * @code |
10926 | * |
10927 | * authentication_info = sip_authentication_info_dup(home, sip->sip_authentication_info); |
10928 | * |
10929 | * @endcode |
10930 | * |
10931 | * @return |
10932 | * A pointer to the |
10933 | * newly duplicated #sip_authentication_info_t header structure, or NULL |
10934 | * upon an error. |
10935 | * |
10936 | */ |
10937 | #if SU_HAVE_INLINE1 |
10938 | su_inlinestatic inline |
10939 | #endif |
10940 | sip_authentication_info_t *sip_authentication_info_dup(su_home_t *home, sip_authentication_info_t const *hdr) |
10941 | __attribute__((__malloc__)); |
10942 | |
10943 | #if SU_HAVE_INLINE1 |
10944 | su_inlinestatic inline |
10945 | sip_authentication_info_t *sip_authentication_info_dup(su_home_t *home, sip_authentication_info_t const *hdr) |
10946 | { |
10947 | return (sip_authentication_info_t *) |
10948 | msg_header_dup_as(home, sip_authentication_info_class, (msg_header_t const *)hdr); |
10949 | } |
10950 | #endif |
10951 | |
10952 | /**Copy a list of @ref sip_authentication_info "Authentication-Info header" header structures #sip_authentication_info_t. |
10953 | * |
10954 | * The function sip_authentication_info_copy() copies a header structure @a |
10955 | * hdr. If the header structure @a hdr contains a reference (@c |
10956 | * hdr->h_next) to a list of headers, all the headers in that |
10957 | * list are copied, too. The function uses given memory @a home |
10958 | * to allocate all the memory areas used to copy the list of header |
10959 | * structure @a hdr. |
10960 | * |
10961 | * @param home memory home used to allocate new structure |
10962 | * @param hdr pointer to the header structure to be copied |
10963 | * |
10964 | * When copying, only the header structure and parameter lists attached to |
10965 | * it are duplicated. The new header structure retains all the references to |
10966 | * the strings within the old @a hdr header, including the encoding of the |
10967 | * old header, if present. |
10968 | * |
10969 | * @par Example |
10970 | * @code |
10971 | * |
10972 | * authentication_info = sip_authentication_info_copy(home, sip->sip_authentication_info); |
10973 | * |
10974 | * @endcode |
10975 | * |
10976 | * @return |
10977 | * A pointer to newly copied header structure, or NULL upon an error. |
10978 | * |
10979 | */ |
10980 | #if SU_HAVE_INLINE1 |
10981 | su_inlinestatic inline |
10982 | #endif |
10983 | sip_authentication_info_t *sip_authentication_info_copy(su_home_t *home, sip_authentication_info_t const *hdr) |
10984 | __attribute__((__malloc__)); |
10985 | |
10986 | #if SU_HAVE_INLINE1 |
10987 | su_inlinestatic inline |
10988 | sip_authentication_info_t *sip_authentication_info_copy(su_home_t *home, sip_authentication_info_t const *hdr) |
10989 | { |
10990 | return (sip_authentication_info_t *) |
10991 | msg_header_copy_as(home, sip_authentication_info_class, (msg_header_t const *)hdr); |
10992 | } |
10993 | #endif |
10994 | |
10995 | /**Make a @ref sip_authentication_info "Authentication-Info header" structure #sip_authentication_info_t. |
10996 | * |
10997 | * The function sip_authentication_info_make() makes a new |
10998 | * #sip_authentication_info_t header structure. It allocates a new |
10999 | * header structure, and decodes the string @a s as the |
11000 | * value of the structure. |
11001 | * |
11002 | * @param home memory home used to allocate new header structure. |
11003 | * @param s string to be decoded as value of the new header structure |
11004 | * |
11005 | * @return |
11006 | * A pointer to newly maked #sip_authentication_info_t header structure, or NULL upon an |
11007 | * error. |
11008 | * |
11009 | */ |
11010 | #if SU_HAVE_INLINE1 |
11011 | su_inlinestatic inline |
11012 | #endif |
11013 | sip_authentication_info_t *sip_authentication_info_make(su_home_t *home, char const *s) |
11014 | __attribute__((__malloc__)); |
11015 | |
11016 | #if SU_HAVE_INLINE1 |
11017 | su_inlinestatic inline sip_authentication_info_t *sip_authentication_info_make(su_home_t *home, char const *s) |
11018 | { |
11019 | return (sip_authentication_info_t *)sip_header_make(home, sip_authentication_info_class, s)((sip_header_t *)msg_header_make((home), (sip_authentication_info_class ), (s))); |
11020 | } |
11021 | #endif |
11022 | |
11023 | /**Make a @ref sip_authentication_info "Authentication-Info header" from formatting result. |
11024 | * |
11025 | * Make a new #sip_authentication_info_t object using formatting result as its value. |
11026 | * The function first prints the arguments according to the format @a fmt |
11027 | * specified. Then it allocates a new header structure, and parses the |
11028 | * formatting result to the structure #sip_authentication_info_t. |
11029 | * |
11030 | * @param home memory home used to allocate new header structure. |
11031 | * @param fmt string used as a printf()-style format |
11032 | * @param ... argument list for format |
11033 | * |
11034 | * @return |
11035 | * A pointer to newly |
11036 | * makes header structure, or NULL upon an error. |
11037 | * |
11038 | * @HIDE |
11039 | * |
11040 | */ |
11041 | #if SU_HAVE_INLINE1 |
11042 | su_inlinestatic inline |
11043 | #endif |
11044 | sip_authentication_info_t *sip_authentication_info_format(su_home_t *home, char const *fmt, ...) |
11045 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
11046 | |
11047 | #if SU_HAVE_INLINE1 |
11048 | su_inlinestatic inline sip_authentication_info_t *sip_authentication_info_format(su_home_t *home, char const *fmt, ...) |
11049 | { |
11050 | sip_header_t *h; |
11051 | va_list ap; |
11052 | |
11053 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
11054 | h = sip_header_vformat(home, sip_authentication_info_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_authentication_info_class ), (fmt), (ap))); |
11055 | va_end(ap)__builtin_va_end(ap); |
11056 | |
11057 | return (sip_authentication_info_t *)h; |
11058 | } |
11059 | #endif |
11060 | |
11061 | /** @} */ |
11062 | |
11063 | /**@addtogroup sip_error_info |
11064 | * @{ |
11065 | */ |
11066 | |
11067 | /** Parse a SIP @ref sip_error_info "Error-Info header". @internal */ |
11068 | SOFIAPUBFUN issize_t sip_error_info_d(su_home_t *, msg_header_t *, |
11069 | char *s, isize_t slen); |
11070 | |
11071 | /** Print a SIP @ref sip_error_info "Error-Info header". @internal */ |
11072 | SOFIAPUBFUN issize_t sip_error_info_e(char b[], isize_t bsiz, |
11073 | msg_header_t const *h, int flags); |
11074 | |
11075 | /**Access a SIP @ref sip_error_info "Error-Info header" |
11076 | * structure #sip_error_info_t from #sip_t. |
11077 | * |
11078 | */ |
11079 | #define sip_error_info(sip)((sip_error_info_t *)msg_header_access((msg_pub_t*)(sip), sip_error_info_class )) \ |
11080 | ((sip_error_info_t *)msg_header_access((msg_pub_t*)(sip), sip_error_info_class)) |
11081 | |
11082 | /**Initializer for structure #sip_error_info_t. |
11083 | * |
11084 | * A static #sip_error_info_t structure for |
11085 | * @ref sip_error_info "Error-Info header" must be initialized with |
11086 | * the SIP_ERROR_INFO_INIT() macro. |
11087 | * For instance, |
11088 | * @code |
11089 | * |
11090 | * sip_error_info_t sip_error_info = SIP_ERROR_INFO_INIT; |
11091 | * |
11092 | * @endcode |
11093 | * @HI |
11094 | * |
11095 | */ |
11096 | #define SIP_ERROR_INFO_INIT(){{{ 0, 0, sip_error_info_class }}} SIP_HDR_INIT(error_info){{{ 0, 0, sip_error_info_class }}} |
11097 | |
11098 | /**Initialize a structure #sip_error_info_t. |
11099 | * |
11100 | * An #sip_error_info_t structure for |
11101 | * @ref sip_error_info "Error-Info header" can be initialized with the |
11102 | * sip_error_info_init() function/macro. For instance, |
11103 | * @code |
11104 | * |
11105 | * sip_error_info_t sip_error_info; |
11106 | * |
11107 | * sip_error_info_init(&sip_error_info); |
11108 | * |
11109 | * @endcode |
11110 | * @HI |
11111 | * |
11112 | */ |
11113 | #if SU_HAVE_INLINE1 |
11114 | su_inlinestatic inline sip_error_info_t *sip_error_info_init(sip_error_info_t x[1]) |
11115 | { |
11116 | return SIP_HEADER_INIT(x, sip_error_info_class, sizeof(sip_error_info_t))((void)memset((x), 0, (sizeof(sip_error_info_t))), (void)(((sip_common_t *)(x))->h_class = (sip_error_info_class)), (x)); |
11117 | } |
11118 | #else |
11119 | #define sip_error_info_init(x) \ |
11120 | SIP_HEADER_INIT(x, sip_error_info_class, sizeof(sip_error_info_t))((void)memset((x), 0, (sizeof(sip_error_info_t))), (void)(((sip_common_t *)(x))->h_class = (sip_error_info_class)), (x)) |
11121 | #endif |
11122 | |
11123 | /**Test if header object is instance of #sip_error_info_t. |
11124 | * |
11125 | * Check if the header class is an instance of |
11126 | * @ref sip_error_info "Error-Info header" object and return true (nonzero), |
11127 | * otherwise return false (zero). |
11128 | * |
11129 | * @param header pointer to the header structure to be tested |
11130 | * |
11131 | * @retval 1 (true) if the @a header is an instance of header error_info |
11132 | * @retval 0 (false) otherwise |
11133 | * |
11134 | */ |
11135 | #if SU_HAVE_INLINE1 |
11136 | su_inlinestatic inline int sip_is_error_info(sip_header_t const *header) |
11137 | { |
11138 | return header && header->sh_classsh_common->h_class->hc_hash == sip_error_info_hash; |
11139 | } |
11140 | #else |
11141 | int sip_is_error_info(sip_header_t const *header); |
11142 | #endif |
11143 | |
11144 | #define sip_error_info_p(h)sip_is_error_info((h)) sip_is_error_info((h)) |
11145 | |
11146 | |
11147 | /**Duplicate a list of @ref sip_error_info "Error-Info header" header structures #sip_error_info_t. |
11148 | * |
11149 | * Duplicate a header |
11150 | * structure @a hdr. If the header structure @a hdr |
11151 | * contains a reference (@c hdr->x_next) to a list of |
11152 | * headers, all the headers in the list are duplicated, too. |
11153 | * |
11154 | * @param home memory home used to allocate new structure |
11155 | * @param hdr header structure to be duplicated |
11156 | * |
11157 | * When duplicating, all parameter lists and non-constant |
11158 | * strings attached to the header are copied, too. The |
11159 | * function uses given memory @a home to allocate all the |
11160 | * memory areas used to copy the header. |
11161 | * |
11162 | * @par Example |
11163 | * @code |
11164 | * |
11165 | * error_info = sip_error_info_dup(home, sip->sip_error_info); |
11166 | * |
11167 | * @endcode |
11168 | * |
11169 | * @return |
11170 | * A pointer to the |
11171 | * newly duplicated #sip_error_info_t header structure, or NULL |
11172 | * upon an error. |
11173 | * |
11174 | */ |
11175 | #if SU_HAVE_INLINE1 |
11176 | su_inlinestatic inline |
11177 | #endif |
11178 | sip_error_info_t *sip_error_info_dup(su_home_t *home, sip_error_info_t const *hdr) |
11179 | __attribute__((__malloc__)); |
11180 | |
11181 | #if SU_HAVE_INLINE1 |
11182 | su_inlinestatic inline |
11183 | sip_error_info_t *sip_error_info_dup(su_home_t *home, sip_error_info_t const *hdr) |
11184 | { |
11185 | return (sip_error_info_t *) |
11186 | msg_header_dup_as(home, sip_error_info_class, (msg_header_t const *)hdr); |
11187 | } |
11188 | #endif |
11189 | |
11190 | /**Copy a list of @ref sip_error_info "Error-Info header" header structures #sip_error_info_t. |
11191 | * |
11192 | * The function sip_error_info_copy() copies a header structure @a |
11193 | * hdr. If the header structure @a hdr contains a reference (@c |
11194 | * hdr->h_next) to a list of headers, all the headers in that |
11195 | * list are copied, too. The function uses given memory @a home |
11196 | * to allocate all the memory areas used to copy the list of header |
11197 | * structure @a hdr. |
11198 | * |
11199 | * @param home memory home used to allocate new structure |
11200 | * @param hdr pointer to the header structure to be copied |
11201 | * |
11202 | * When copying, only the header structure and parameter lists attached to |
11203 | * it are duplicated. The new header structure retains all the references to |
11204 | * the strings within the old @a hdr header, including the encoding of the |
11205 | * old header, if present. |
11206 | * |
11207 | * @par Example |
11208 | * @code |
11209 | * |
11210 | * error_info = sip_error_info_copy(home, sip->sip_error_info); |
11211 | * |
11212 | * @endcode |
11213 | * |
11214 | * @return |
11215 | * A pointer to newly copied header structure, or NULL upon an error. |
11216 | * |
11217 | */ |
11218 | #if SU_HAVE_INLINE1 |
11219 | su_inlinestatic inline |
11220 | #endif |
11221 | sip_error_info_t *sip_error_info_copy(su_home_t *home, sip_error_info_t const *hdr) |
11222 | __attribute__((__malloc__)); |
11223 | |
11224 | #if SU_HAVE_INLINE1 |
11225 | su_inlinestatic inline |
11226 | sip_error_info_t *sip_error_info_copy(su_home_t *home, sip_error_info_t const *hdr) |
11227 | { |
11228 | return (sip_error_info_t *) |
11229 | msg_header_copy_as(home, sip_error_info_class, (msg_header_t const *)hdr); |
11230 | } |
11231 | #endif |
11232 | |
11233 | /**Make a @ref sip_error_info "Error-Info header" structure #sip_error_info_t. |
11234 | * |
11235 | * The function sip_error_info_make() makes a new |
11236 | * #sip_error_info_t header structure. It allocates a new |
11237 | * header structure, and decodes the string @a s as the |
11238 | * value of the structure. |
11239 | * |
11240 | * @param home memory home used to allocate new header structure. |
11241 | * @param s string to be decoded as value of the new header structure |
11242 | * |
11243 | * @return |
11244 | * A pointer to newly maked #sip_error_info_t header structure, or NULL upon an |
11245 | * error. |
11246 | * |
11247 | */ |
11248 | #if SU_HAVE_INLINE1 |
11249 | su_inlinestatic inline |
11250 | #endif |
11251 | sip_error_info_t *sip_error_info_make(su_home_t *home, char const *s) |
11252 | __attribute__((__malloc__)); |
11253 | |
11254 | #if SU_HAVE_INLINE1 |
11255 | su_inlinestatic inline sip_error_info_t *sip_error_info_make(su_home_t *home, char const *s) |
11256 | { |
11257 | return (sip_error_info_t *)sip_header_make(home, sip_error_info_class, s)((sip_header_t *)msg_header_make((home), (sip_error_info_class ), (s))); |
11258 | } |
11259 | #endif |
11260 | |
11261 | /**Make a @ref sip_error_info "Error-Info header" from formatting result. |
11262 | * |
11263 | * Make a new #sip_error_info_t object using formatting result as its value. |
11264 | * The function first prints the arguments according to the format @a fmt |
11265 | * specified. Then it allocates a new header structure, and parses the |
11266 | * formatting result to the structure #sip_error_info_t. |
11267 | * |
11268 | * @param home memory home used to allocate new header structure. |
11269 | * @param fmt string used as a printf()-style format |
11270 | * @param ... argument list for format |
11271 | * |
11272 | * @return |
11273 | * A pointer to newly |
11274 | * makes header structure, or NULL upon an error. |
11275 | * |
11276 | * @HIDE |
11277 | * |
11278 | */ |
11279 | #if SU_HAVE_INLINE1 |
11280 | su_inlinestatic inline |
11281 | #endif |
11282 | sip_error_info_t *sip_error_info_format(su_home_t *home, char const *fmt, ...) |
11283 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
11284 | |
11285 | #if SU_HAVE_INLINE1 |
11286 | su_inlinestatic inline sip_error_info_t *sip_error_info_format(su_home_t *home, char const *fmt, ...) |
11287 | { |
11288 | sip_header_t *h; |
11289 | va_list ap; |
11290 | |
11291 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
11292 | h = sip_header_vformat(home, sip_error_info_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_error_info_class ), (fmt), (ap))); |
11293 | va_end(ap)__builtin_va_end(ap); |
11294 | |
11295 | return (sip_error_info_t *)h; |
11296 | } |
11297 | #endif |
11298 | |
11299 | /** @} */ |
11300 | |
11301 | /**@addtogroup sip_warning |
11302 | * @{ |
11303 | */ |
11304 | |
11305 | /** Parse a SIP @ref sip_warning "Warning header". @internal */ |
11306 | SOFIAPUBFUN issize_t sip_warning_d(su_home_t *, msg_header_t *, |
11307 | char *s, isize_t slen); |
11308 | |
11309 | /** Print a SIP @ref sip_warning "Warning header". @internal */ |
11310 | SOFIAPUBFUN issize_t sip_warning_e(char b[], isize_t bsiz, |
11311 | msg_header_t const *h, int flags); |
11312 | |
11313 | /**Access a SIP @ref sip_warning "Warning header" |
11314 | * structure #sip_warning_t from #sip_t. |
11315 | * |
11316 | */ |
11317 | #define sip_warning(sip)((sip_warning_t *)msg_header_access((msg_pub_t*)(sip), sip_warning_class )) \ |
11318 | ((sip_warning_t *)msg_header_access((msg_pub_t*)(sip), sip_warning_class)) |
11319 | |
11320 | /**Initializer for structure #sip_warning_t. |
11321 | * |
11322 | * A static #sip_warning_t structure for |
11323 | * @ref sip_warning "Warning header" must be initialized with |
11324 | * the SIP_WARNING_INIT() macro. |
11325 | * For instance, |
11326 | * @code |
11327 | * |
11328 | * sip_warning_t sip_warning = SIP_WARNING_INIT; |
11329 | * |
11330 | * @endcode |
11331 | * @HI |
11332 | * |
11333 | */ |
11334 | #define SIP_WARNING_INIT(){{{ 0, 0, sip_warning_class }}} SIP_HDR_INIT(warning){{{ 0, 0, sip_warning_class }}} |
11335 | |
11336 | /**Initialize a structure #sip_warning_t. |
11337 | * |
11338 | * An #sip_warning_t structure for |
11339 | * @ref sip_warning "Warning header" can be initialized with the |
11340 | * sip_warning_init() function/macro. For instance, |
11341 | * @code |
11342 | * |
11343 | * sip_warning_t sip_warning; |
11344 | * |
11345 | * sip_warning_init(&sip_warning); |
11346 | * |
11347 | * @endcode |
11348 | * @HI |
11349 | * |
11350 | */ |
11351 | #if SU_HAVE_INLINE1 |
11352 | su_inlinestatic inline sip_warning_t *sip_warning_init(sip_warning_t x[1]) |
11353 | { |
11354 | return SIP_HEADER_INIT(x, sip_warning_class, sizeof(sip_warning_t))((void)memset((x), 0, (sizeof(sip_warning_t))), (void)(((sip_common_t *)(x))->h_class = (sip_warning_class)), (x)); |
11355 | } |
11356 | #else |
11357 | #define sip_warning_init(x) \ |
11358 | SIP_HEADER_INIT(x, sip_warning_class, sizeof(sip_warning_t))((void)memset((x), 0, (sizeof(sip_warning_t))), (void)(((sip_common_t *)(x))->h_class = (sip_warning_class)), (x)) |
11359 | #endif |
11360 | |
11361 | /**Test if header object is instance of #sip_warning_t. |
11362 | * |
11363 | * Check if the header class is an instance of |
11364 | * @ref sip_warning "Warning header" object and return true (nonzero), |
11365 | * otherwise return false (zero). |
11366 | * |
11367 | * @param header pointer to the header structure to be tested |
11368 | * |
11369 | * @retval 1 (true) if the @a header is an instance of header warning |
11370 | * @retval 0 (false) otherwise |
11371 | * |
11372 | */ |
11373 | #if SU_HAVE_INLINE1 |
11374 | su_inlinestatic inline int sip_is_warning(sip_header_t const *header) |
11375 | { |
11376 | return header && header->sh_classsh_common->h_class->hc_hash == sip_warning_hash; |
11377 | } |
11378 | #else |
11379 | int sip_is_warning(sip_header_t const *header); |
11380 | #endif |
11381 | |
11382 | #define sip_warning_p(h)sip_is_warning((h)) sip_is_warning((h)) |
11383 | |
11384 | |
11385 | /**Duplicate a list of @ref sip_warning "Warning header" header structures #sip_warning_t. |
11386 | * |
11387 | * Duplicate a header |
11388 | * structure @a hdr. If the header structure @a hdr |
11389 | * contains a reference (@c hdr->x_next) to a list of |
11390 | * headers, all the headers in the list are duplicated, too. |
11391 | * |
11392 | * @param home memory home used to allocate new structure |
11393 | * @param hdr header structure to be duplicated |
11394 | * |
11395 | * When duplicating, all parameter lists and non-constant |
11396 | * strings attached to the header are copied, too. The |
11397 | * function uses given memory @a home to allocate all the |
11398 | * memory areas used to copy the header. |
11399 | * |
11400 | * @par Example |
11401 | * @code |
11402 | * |
11403 | * warning = sip_warning_dup(home, sip->sip_warning); |
11404 | * |
11405 | * @endcode |
11406 | * |
11407 | * @return |
11408 | * A pointer to the |
11409 | * newly duplicated #sip_warning_t header structure, or NULL |
11410 | * upon an error. |
11411 | * |
11412 | */ |
11413 | #if SU_HAVE_INLINE1 |
11414 | su_inlinestatic inline |
11415 | #endif |
11416 | sip_warning_t *sip_warning_dup(su_home_t *home, sip_warning_t const *hdr) |
11417 | __attribute__((__malloc__)); |
11418 | |
11419 | #if SU_HAVE_INLINE1 |
11420 | su_inlinestatic inline |
11421 | sip_warning_t *sip_warning_dup(su_home_t *home, sip_warning_t const *hdr) |
11422 | { |
11423 | return (sip_warning_t *) |
11424 | msg_header_dup_as(home, sip_warning_class, (msg_header_t const *)hdr); |
11425 | } |
11426 | #endif |
11427 | |
11428 | /**Copy a list of @ref sip_warning "Warning header" header structures #sip_warning_t. |
11429 | * |
11430 | * The function sip_warning_copy() copies a header structure @a |
11431 | * hdr. If the header structure @a hdr contains a reference (@c |
11432 | * hdr->h_next) to a list of headers, all the headers in that |
11433 | * list are copied, too. The function uses given memory @a home |
11434 | * to allocate all the memory areas used to copy the list of header |
11435 | * structure @a hdr. |
11436 | * |
11437 | * @param home memory home used to allocate new structure |
11438 | * @param hdr pointer to the header structure to be copied |
11439 | * |
11440 | * When copying, only the header structure and parameter lists attached to |
11441 | * it are duplicated. The new header structure retains all the references to |
11442 | * the strings within the old @a hdr header, including the encoding of the |
11443 | * old header, if present. |
11444 | * |
11445 | * @par Example |
11446 | * @code |
11447 | * |
11448 | * warning = sip_warning_copy(home, sip->sip_warning); |
11449 | * |
11450 | * @endcode |
11451 | * |
11452 | * @return |
11453 | * A pointer to newly copied header structure, or NULL upon an error. |
11454 | * |
11455 | */ |
11456 | #if SU_HAVE_INLINE1 |
11457 | su_inlinestatic inline |
11458 | #endif |
11459 | sip_warning_t *sip_warning_copy(su_home_t *home, sip_warning_t const *hdr) |
11460 | __attribute__((__malloc__)); |
11461 | |
11462 | #if SU_HAVE_INLINE1 |
11463 | su_inlinestatic inline |
11464 | sip_warning_t *sip_warning_copy(su_home_t *home, sip_warning_t const *hdr) |
11465 | { |
11466 | return (sip_warning_t *) |
11467 | msg_header_copy_as(home, sip_warning_class, (msg_header_t const *)hdr); |
11468 | } |
11469 | #endif |
11470 | |
11471 | /**Make a @ref sip_warning "Warning header" structure #sip_warning_t. |
11472 | * |
11473 | * The function sip_warning_make() makes a new |
11474 | * #sip_warning_t header structure. It allocates a new |
11475 | * header structure, and decodes the string @a s as the |
11476 | * value of the structure. |
11477 | * |
11478 | * @param home memory home used to allocate new header structure. |
11479 | * @param s string to be decoded as value of the new header structure |
11480 | * |
11481 | * @return |
11482 | * A pointer to newly maked #sip_warning_t header structure, or NULL upon an |
11483 | * error. |
11484 | * |
11485 | */ |
11486 | #if SU_HAVE_INLINE1 |
11487 | su_inlinestatic inline |
11488 | #endif |
11489 | sip_warning_t *sip_warning_make(su_home_t *home, char const *s) |
11490 | __attribute__((__malloc__)); |
11491 | |
11492 | #if SU_HAVE_INLINE1 |
11493 | su_inlinestatic inline sip_warning_t *sip_warning_make(su_home_t *home, char const *s) |
11494 | { |
11495 | return (sip_warning_t *)sip_header_make(home, sip_warning_class, s)((sip_header_t *)msg_header_make((home), (sip_warning_class), (s))); |
11496 | } |
11497 | #endif |
11498 | |
11499 | /**Make a @ref sip_warning "Warning header" from formatting result. |
11500 | * |
11501 | * Make a new #sip_warning_t object using formatting result as its value. |
11502 | * The function first prints the arguments according to the format @a fmt |
11503 | * specified. Then it allocates a new header structure, and parses the |
11504 | * formatting result to the structure #sip_warning_t. |
11505 | * |
11506 | * @param home memory home used to allocate new header structure. |
11507 | * @param fmt string used as a printf()-style format |
11508 | * @param ... argument list for format |
11509 | * |
11510 | * @return |
11511 | * A pointer to newly |
11512 | * makes header structure, or NULL upon an error. |
11513 | * |
11514 | * @HIDE |
11515 | * |
11516 | */ |
11517 | #if SU_HAVE_INLINE1 |
11518 | su_inlinestatic inline |
11519 | #endif |
11520 | sip_warning_t *sip_warning_format(su_home_t *home, char const *fmt, ...) |
11521 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
11522 | |
11523 | #if SU_HAVE_INLINE1 |
11524 | su_inlinestatic inline sip_warning_t *sip_warning_format(su_home_t *home, char const *fmt, ...) |
11525 | { |
11526 | sip_header_t *h; |
11527 | va_list ap; |
11528 | |
11529 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
11530 | h = sip_header_vformat(home, sip_warning_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_warning_class ), (fmt), (ap))); |
11531 | va_end(ap)__builtin_va_end(ap); |
11532 | |
11533 | return (sip_warning_t *)h; |
11534 | } |
11535 | #endif |
11536 | |
11537 | /** @} */ |
11538 | |
11539 | /**@addtogroup sip_refer_to |
11540 | * @{ |
11541 | */ |
11542 | |
11543 | /** Parse a SIP @ref sip_refer_to "Refer-To header". @internal */ |
11544 | SOFIAPUBFUN issize_t sip_refer_to_d(su_home_t *, msg_header_t *, |
11545 | char *s, isize_t slen); |
11546 | |
11547 | /** Print a SIP @ref sip_refer_to "Refer-To header". @internal */ |
11548 | SOFIAPUBFUN issize_t sip_refer_to_e(char b[], isize_t bsiz, |
11549 | msg_header_t const *h, int flags); |
11550 | |
11551 | /**Access a SIP @ref sip_refer_to "Refer-To header" |
11552 | * structure #sip_refer_to_t from #sip_t. |
11553 | * |
11554 | */ |
11555 | #define sip_refer_to(sip)((sip_refer_to_t *)msg_header_access((msg_pub_t*)(sip), sip_refer_to_class )) \ |
11556 | ((sip_refer_to_t *)msg_header_access((msg_pub_t*)(sip), sip_refer_to_class)) |
11557 | |
11558 | /**Initializer for structure #sip_refer_to_t. |
11559 | * |
11560 | * A static #sip_refer_to_t structure for |
11561 | * @ref sip_refer_to "Refer-To header" must be initialized with |
11562 | * the SIP_REFER_TO_INIT() macro. |
11563 | * For instance, |
11564 | * @code |
11565 | * |
11566 | * sip_refer_to_t sip_refer_to = SIP_REFER_TO_INIT; |
11567 | * |
11568 | * @endcode |
11569 | * @HI |
11570 | * |
11571 | */ |
11572 | #define SIP_REFER_TO_INIT(){{{ 0, 0, sip_refer_to_class }}} SIP_HDR_INIT(refer_to){{{ 0, 0, sip_refer_to_class }}} |
11573 | |
11574 | /**Initialize a structure #sip_refer_to_t. |
11575 | * |
11576 | * An #sip_refer_to_t structure for |
11577 | * @ref sip_refer_to "Refer-To header" can be initialized with the |
11578 | * sip_refer_to_init() function/macro. For instance, |
11579 | * @code |
11580 | * |
11581 | * sip_refer_to_t sip_refer_to; |
11582 | * |
11583 | * sip_refer_to_init(&sip_refer_to); |
11584 | * |
11585 | * @endcode |
11586 | * @HI |
11587 | * |
11588 | */ |
11589 | #if SU_HAVE_INLINE1 |
11590 | su_inlinestatic inline sip_refer_to_t *sip_refer_to_init(sip_refer_to_t x[1]) |
11591 | { |
11592 | return SIP_HEADER_INIT(x, sip_refer_to_class, sizeof(sip_refer_to_t))((void)memset((x), 0, (sizeof(sip_refer_to_t))), (void)(((sip_common_t *)(x))->h_class = (sip_refer_to_class)), (x)); |
11593 | } |
11594 | #else |
11595 | #define sip_refer_to_init(x) \ |
11596 | SIP_HEADER_INIT(x, sip_refer_to_class, sizeof(sip_refer_to_t))((void)memset((x), 0, (sizeof(sip_refer_to_t))), (void)(((sip_common_t *)(x))->h_class = (sip_refer_to_class)), (x)) |
11597 | #endif |
11598 | |
11599 | /**Test if header object is instance of #sip_refer_to_t. |
11600 | * |
11601 | * Check if the header class is an instance of |
11602 | * @ref sip_refer_to "Refer-To header" object and return true (nonzero), |
11603 | * otherwise return false (zero). |
11604 | * |
11605 | * @param header pointer to the header structure to be tested |
11606 | * |
11607 | * @retval 1 (true) if the @a header is an instance of header refer_to |
11608 | * @retval 0 (false) otherwise |
11609 | * |
11610 | */ |
11611 | #if SU_HAVE_INLINE1 |
11612 | su_inlinestatic inline int sip_is_refer_to(sip_header_t const *header) |
11613 | { |
11614 | return header && header->sh_classsh_common->h_class->hc_hash == sip_refer_to_hash; |
11615 | } |
11616 | #else |
11617 | int sip_is_refer_to(sip_header_t const *header); |
11618 | #endif |
11619 | |
11620 | #define sip_refer_to_p(h)sip_is_refer_to((h)) sip_is_refer_to((h)) |
11621 | |
11622 | |
11623 | /**Duplicate a list of @ref sip_refer_to "Refer-To header" header structures #sip_refer_to_t. |
11624 | * |
11625 | * Duplicate a header |
11626 | * structure @a hdr. If the header structure @a hdr |
11627 | * contains a reference (@c hdr->x_next) to a list of |
11628 | * headers, all the headers in the list are duplicated, too. |
11629 | * |
11630 | * @param home memory home used to allocate new structure |
11631 | * @param hdr header structure to be duplicated |
11632 | * |
11633 | * When duplicating, all parameter lists and non-constant |
11634 | * strings attached to the header are copied, too. The |
11635 | * function uses given memory @a home to allocate all the |
11636 | * memory areas used to copy the header. |
11637 | * |
11638 | * @par Example |
11639 | * @code |
11640 | * |
11641 | * refer_to = sip_refer_to_dup(home, sip->sip_refer_to); |
11642 | * |
11643 | * @endcode |
11644 | * |
11645 | * @return |
11646 | * A pointer to the |
11647 | * newly duplicated #sip_refer_to_t header structure, or NULL |
11648 | * upon an error. |
11649 | * |
11650 | */ |
11651 | #if SU_HAVE_INLINE1 |
11652 | su_inlinestatic inline |
11653 | #endif |
11654 | sip_refer_to_t *sip_refer_to_dup(su_home_t *home, sip_refer_to_t const *hdr) |
11655 | __attribute__((__malloc__)); |
11656 | |
11657 | #if SU_HAVE_INLINE1 |
11658 | su_inlinestatic inline |
11659 | sip_refer_to_t *sip_refer_to_dup(su_home_t *home, sip_refer_to_t const *hdr) |
11660 | { |
11661 | return (sip_refer_to_t *) |
11662 | msg_header_dup_as(home, sip_refer_to_class, (msg_header_t const *)hdr); |
11663 | } |
11664 | #endif |
11665 | |
11666 | /**Copy a list of @ref sip_refer_to "Refer-To header" header structures #sip_refer_to_t. |
11667 | * |
11668 | * The function sip_refer_to_copy() copies a header structure @a |
11669 | * hdr. If the header structure @a hdr contains a reference (@c |
11670 | * hdr->h_next) to a list of headers, all the headers in that |
11671 | * list are copied, too. The function uses given memory @a home |
11672 | * to allocate all the memory areas used to copy the list of header |
11673 | * structure @a hdr. |
11674 | * |
11675 | * @param home memory home used to allocate new structure |
11676 | * @param hdr pointer to the header structure to be copied |
11677 | * |
11678 | * When copying, only the header structure and parameter lists attached to |
11679 | * it are duplicated. The new header structure retains all the references to |
11680 | * the strings within the old @a hdr header, including the encoding of the |
11681 | * old header, if present. |
11682 | * |
11683 | * @par Example |
11684 | * @code |
11685 | * |
11686 | * refer_to = sip_refer_to_copy(home, sip->sip_refer_to); |
11687 | * |
11688 | * @endcode |
11689 | * |
11690 | * @return |
11691 | * A pointer to newly copied header structure, or NULL upon an error. |
11692 | * |
11693 | */ |
11694 | #if SU_HAVE_INLINE1 |
11695 | su_inlinestatic inline |
11696 | #endif |
11697 | sip_refer_to_t *sip_refer_to_copy(su_home_t *home, sip_refer_to_t const *hdr) |
11698 | __attribute__((__malloc__)); |
11699 | |
11700 | #if SU_HAVE_INLINE1 |
11701 | su_inlinestatic inline |
11702 | sip_refer_to_t *sip_refer_to_copy(su_home_t *home, sip_refer_to_t const *hdr) |
11703 | { |
11704 | return (sip_refer_to_t *) |
11705 | msg_header_copy_as(home, sip_refer_to_class, (msg_header_t const *)hdr); |
11706 | } |
11707 | #endif |
11708 | |
11709 | /**Make a @ref sip_refer_to "Refer-To header" structure #sip_refer_to_t. |
11710 | * |
11711 | * The function sip_refer_to_make() makes a new |
11712 | * #sip_refer_to_t header structure. It allocates a new |
11713 | * header structure, and decodes the string @a s as the |
11714 | * value of the structure. |
11715 | * |
11716 | * @param home memory home used to allocate new header structure. |
11717 | * @param s string to be decoded as value of the new header structure |
11718 | * |
11719 | * @return |
11720 | * A pointer to newly maked #sip_refer_to_t header structure, or NULL upon an |
11721 | * error. |
11722 | * |
11723 | */ |
11724 | #if SU_HAVE_INLINE1 |
11725 | su_inlinestatic inline |
11726 | #endif |
11727 | sip_refer_to_t *sip_refer_to_make(su_home_t *home, char const *s) |
11728 | __attribute__((__malloc__)); |
11729 | |
11730 | #if SU_HAVE_INLINE1 |
11731 | su_inlinestatic inline sip_refer_to_t *sip_refer_to_make(su_home_t *home, char const *s) |
11732 | { |
11733 | return (sip_refer_to_t *)sip_header_make(home, sip_refer_to_class, s)((sip_header_t *)msg_header_make((home), (sip_refer_to_class) , (s))); |
11734 | } |
11735 | #endif |
11736 | |
11737 | /**Make a @ref sip_refer_to "Refer-To header" from formatting result. |
11738 | * |
11739 | * Make a new #sip_refer_to_t object using formatting result as its value. |
11740 | * The function first prints the arguments according to the format @a fmt |
11741 | * specified. Then it allocates a new header structure, and parses the |
11742 | * formatting result to the structure #sip_refer_to_t. |
11743 | * |
11744 | * @param home memory home used to allocate new header structure. |
11745 | * @param fmt string used as a printf()-style format |
11746 | * @param ... argument list for format |
11747 | * |
11748 | * @return |
11749 | * A pointer to newly |
11750 | * makes header structure, or NULL upon an error. |
11751 | * |
11752 | * @HIDE |
11753 | * |
11754 | */ |
11755 | #if SU_HAVE_INLINE1 |
11756 | su_inlinestatic inline |
11757 | #endif |
11758 | sip_refer_to_t *sip_refer_to_format(su_home_t *home, char const *fmt, ...) |
11759 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
11760 | |
11761 | #if SU_HAVE_INLINE1 |
11762 | su_inlinestatic inline sip_refer_to_t *sip_refer_to_format(su_home_t *home, char const *fmt, ...) |
11763 | { |
11764 | sip_header_t *h; |
11765 | va_list ap; |
11766 | |
11767 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
11768 | h = sip_header_vformat(home, sip_refer_to_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_refer_to_class ), (fmt), (ap))); |
11769 | va_end(ap)__builtin_va_end(ap); |
11770 | |
11771 | return (sip_refer_to_t *)h; |
11772 | } |
11773 | #endif |
11774 | |
11775 | /** @} */ |
11776 | |
11777 | /**@addtogroup sip_referred_by |
11778 | * @{ |
11779 | */ |
11780 | |
11781 | /** Parse a SIP @ref sip_referred_by "Referred-By header". @internal */ |
11782 | SOFIAPUBFUN issize_t sip_referred_by_d(su_home_t *, msg_header_t *, |
11783 | char *s, isize_t slen); |
11784 | |
11785 | /** Print a SIP @ref sip_referred_by "Referred-By header". @internal */ |
11786 | SOFIAPUBFUN issize_t sip_referred_by_e(char b[], isize_t bsiz, |
11787 | msg_header_t const *h, int flags); |
11788 | |
11789 | /**Access a SIP @ref sip_referred_by "Referred-By header" |
11790 | * structure #sip_referred_by_t from #sip_t. |
11791 | * |
11792 | */ |
11793 | #define sip_referred_by(sip)((sip_referred_by_t *)msg_header_access((msg_pub_t*)(sip), sip_referred_by_class )) \ |
11794 | ((sip_referred_by_t *)msg_header_access((msg_pub_t*)(sip), sip_referred_by_class)) |
11795 | |
11796 | /**Initializer for structure #sip_referred_by_t. |
11797 | * |
11798 | * A static #sip_referred_by_t structure for |
11799 | * @ref sip_referred_by "Referred-By header" must be initialized with |
11800 | * the SIP_REFERRED_BY_INIT() macro. |
11801 | * For instance, |
11802 | * @code |
11803 | * |
11804 | * sip_referred_by_t sip_referred_by = SIP_REFERRED_BY_INIT; |
11805 | * |
11806 | * @endcode |
11807 | * @HI |
11808 | * |
11809 | */ |
11810 | #define SIP_REFERRED_BY_INIT(){{{ 0, 0, sip_referred_by_class }}} SIP_HDR_INIT(referred_by){{{ 0, 0, sip_referred_by_class }}} |
11811 | |
11812 | /**Initialize a structure #sip_referred_by_t. |
11813 | * |
11814 | * An #sip_referred_by_t structure for |
11815 | * @ref sip_referred_by "Referred-By header" can be initialized with the |
11816 | * sip_referred_by_init() function/macro. For instance, |
11817 | * @code |
11818 | * |
11819 | * sip_referred_by_t sip_referred_by; |
11820 | * |
11821 | * sip_referred_by_init(&sip_referred_by); |
11822 | * |
11823 | * @endcode |
11824 | * @HI |
11825 | * |
11826 | */ |
11827 | #if SU_HAVE_INLINE1 |
11828 | su_inlinestatic inline sip_referred_by_t *sip_referred_by_init(sip_referred_by_t x[1]) |
11829 | { |
11830 | return SIP_HEADER_INIT(x, sip_referred_by_class, sizeof(sip_referred_by_t))((void)memset((x), 0, (sizeof(sip_referred_by_t))), (void)((( sip_common_t *)(x))->h_class = (sip_referred_by_class)), ( x)); |
11831 | } |
11832 | #else |
11833 | #define sip_referred_by_init(x) \ |
11834 | SIP_HEADER_INIT(x, sip_referred_by_class, sizeof(sip_referred_by_t))((void)memset((x), 0, (sizeof(sip_referred_by_t))), (void)((( sip_common_t *)(x))->h_class = (sip_referred_by_class)), ( x)) |
11835 | #endif |
11836 | |
11837 | /**Test if header object is instance of #sip_referred_by_t. |
11838 | * |
11839 | * Check if the header class is an instance of |
11840 | * @ref sip_referred_by "Referred-By header" object and return true (nonzero), |
11841 | * otherwise return false (zero). |
11842 | * |
11843 | * @param header pointer to the header structure to be tested |
11844 | * |
11845 | * @retval 1 (true) if the @a header is an instance of header referred_by |
11846 | * @retval 0 (false) otherwise |
11847 | * |
11848 | */ |
11849 | #if SU_HAVE_INLINE1 |
11850 | su_inlinestatic inline int sip_is_referred_by(sip_header_t const *header) |
11851 | { |
11852 | return header && header->sh_classsh_common->h_class->hc_hash == sip_referred_by_hash; |
11853 | } |
11854 | #else |
11855 | int sip_is_referred_by(sip_header_t const *header); |
11856 | #endif |
11857 | |
11858 | #define sip_referred_by_p(h)sip_is_referred_by((h)) sip_is_referred_by((h)) |
11859 | |
11860 | |
11861 | /**Duplicate a list of @ref sip_referred_by "Referred-By header" header structures #sip_referred_by_t. |
11862 | * |
11863 | * Duplicate a header |
11864 | * structure @a hdr. If the header structure @a hdr |
11865 | * contains a reference (@c hdr->x_next) to a list of |
11866 | * headers, all the headers in the list are duplicated, too. |
11867 | * |
11868 | * @param home memory home used to allocate new structure |
11869 | * @param hdr header structure to be duplicated |
11870 | * |
11871 | * When duplicating, all parameter lists and non-constant |
11872 | * strings attached to the header are copied, too. The |
11873 | * function uses given memory @a home to allocate all the |
11874 | * memory areas used to copy the header. |
11875 | * |
11876 | * @par Example |
11877 | * @code |
11878 | * |
11879 | * referred_by = sip_referred_by_dup(home, sip->sip_referred_by); |
11880 | * |
11881 | * @endcode |
11882 | * |
11883 | * @return |
11884 | * A pointer to the |
11885 | * newly duplicated #sip_referred_by_t header structure, or NULL |
11886 | * upon an error. |
11887 | * |
11888 | */ |
11889 | #if SU_HAVE_INLINE1 |
11890 | su_inlinestatic inline |
11891 | #endif |
11892 | sip_referred_by_t *sip_referred_by_dup(su_home_t *home, sip_referred_by_t const *hdr) |
11893 | __attribute__((__malloc__)); |
11894 | |
11895 | #if SU_HAVE_INLINE1 |
11896 | su_inlinestatic inline |
11897 | sip_referred_by_t *sip_referred_by_dup(su_home_t *home, sip_referred_by_t const *hdr) |
11898 | { |
11899 | return (sip_referred_by_t *) |
11900 | msg_header_dup_as(home, sip_referred_by_class, (msg_header_t const *)hdr); |
11901 | } |
11902 | #endif |
11903 | |
11904 | /**Copy a list of @ref sip_referred_by "Referred-By header" header structures #sip_referred_by_t. |
11905 | * |
11906 | * The function sip_referred_by_copy() copies a header structure @a |
11907 | * hdr. If the header structure @a hdr contains a reference (@c |
11908 | * hdr->h_next) to a list of headers, all the headers in that |
11909 | * list are copied, too. The function uses given memory @a home |
11910 | * to allocate all the memory areas used to copy the list of header |
11911 | * structure @a hdr. |
11912 | * |
11913 | * @param home memory home used to allocate new structure |
11914 | * @param hdr pointer to the header structure to be copied |
11915 | * |
11916 | * When copying, only the header structure and parameter lists attached to |
11917 | * it are duplicated. The new header structure retains all the references to |
11918 | * the strings within the old @a hdr header, including the encoding of the |
11919 | * old header, if present. |
11920 | * |
11921 | * @par Example |
11922 | * @code |
11923 | * |
11924 | * referred_by = sip_referred_by_copy(home, sip->sip_referred_by); |
11925 | * |
11926 | * @endcode |
11927 | * |
11928 | * @return |
11929 | * A pointer to newly copied header structure, or NULL upon an error. |
11930 | * |
11931 | */ |
11932 | #if SU_HAVE_INLINE1 |
11933 | su_inlinestatic inline |
11934 | #endif |
11935 | sip_referred_by_t *sip_referred_by_copy(su_home_t *home, sip_referred_by_t const *hdr) |
11936 | __attribute__((__malloc__)); |
11937 | |
11938 | #if SU_HAVE_INLINE1 |
11939 | su_inlinestatic inline |
11940 | sip_referred_by_t *sip_referred_by_copy(su_home_t *home, sip_referred_by_t const *hdr) |
11941 | { |
11942 | return (sip_referred_by_t *) |
11943 | msg_header_copy_as(home, sip_referred_by_class, (msg_header_t const *)hdr); |
11944 | } |
11945 | #endif |
11946 | |
11947 | /**Make a @ref sip_referred_by "Referred-By header" structure #sip_referred_by_t. |
11948 | * |
11949 | * The function sip_referred_by_make() makes a new |
11950 | * #sip_referred_by_t header structure. It allocates a new |
11951 | * header structure, and decodes the string @a s as the |
11952 | * value of the structure. |
11953 | * |
11954 | * @param home memory home used to allocate new header structure. |
11955 | * @param s string to be decoded as value of the new header structure |
11956 | * |
11957 | * @return |
11958 | * A pointer to newly maked #sip_referred_by_t header structure, or NULL upon an |
11959 | * error. |
11960 | * |
11961 | */ |
11962 | #if SU_HAVE_INLINE1 |
11963 | su_inlinestatic inline |
11964 | #endif |
11965 | sip_referred_by_t *sip_referred_by_make(su_home_t *home, char const *s) |
11966 | __attribute__((__malloc__)); |
11967 | |
11968 | #if SU_HAVE_INLINE1 |
11969 | su_inlinestatic inline sip_referred_by_t *sip_referred_by_make(su_home_t *home, char const *s) |
11970 | { |
11971 | return (sip_referred_by_t *)sip_header_make(home, sip_referred_by_class, s)((sip_header_t *)msg_header_make((home), (sip_referred_by_class ), (s))); |
11972 | } |
11973 | #endif |
11974 | |
11975 | /**Make a @ref sip_referred_by "Referred-By header" from formatting result. |
11976 | * |
11977 | * Make a new #sip_referred_by_t object using formatting result as its value. |
11978 | * The function first prints the arguments according to the format @a fmt |
11979 | * specified. Then it allocates a new header structure, and parses the |
11980 | * formatting result to the structure #sip_referred_by_t. |
11981 | * |
11982 | * @param home memory home used to allocate new header structure. |
11983 | * @param fmt string used as a printf()-style format |
11984 | * @param ... argument list for format |
11985 | * |
11986 | * @return |
11987 | * A pointer to newly |
11988 | * makes header structure, or NULL upon an error. |
11989 | * |
11990 | * @HIDE |
11991 | * |
11992 | */ |
11993 | #if SU_HAVE_INLINE1 |
11994 | su_inlinestatic inline |
11995 | #endif |
11996 | sip_referred_by_t *sip_referred_by_format(su_home_t *home, char const *fmt, ...) |
11997 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
11998 | |
11999 | #if SU_HAVE_INLINE1 |
12000 | su_inlinestatic inline sip_referred_by_t *sip_referred_by_format(su_home_t *home, char const *fmt, ...) |
12001 | { |
12002 | sip_header_t *h; |
12003 | va_list ap; |
12004 | |
12005 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
12006 | h = sip_header_vformat(home, sip_referred_by_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_referred_by_class ), (fmt), (ap))); |
12007 | va_end(ap)__builtin_va_end(ap); |
12008 | |
12009 | return (sip_referred_by_t *)h; |
12010 | } |
12011 | #endif |
12012 | |
12013 | /** @} */ |
12014 | |
12015 | /**@addtogroup sip_replaces |
12016 | * @{ |
12017 | */ |
12018 | |
12019 | /** Parse a SIP @ref sip_replaces "Replaces header". @internal */ |
12020 | SOFIAPUBFUN issize_t sip_replaces_d(su_home_t *, msg_header_t *, |
12021 | char *s, isize_t slen); |
12022 | |
12023 | /** Print a SIP @ref sip_replaces "Replaces header". @internal */ |
12024 | SOFIAPUBFUN issize_t sip_replaces_e(char b[], isize_t bsiz, |
12025 | msg_header_t const *h, int flags); |
12026 | |
12027 | /**Access a SIP @ref sip_replaces "Replaces header" |
12028 | * structure #sip_replaces_t from #sip_t. |
12029 | * |
12030 | */ |
12031 | #define sip_replaces(sip)((sip_replaces_t *)msg_header_access((msg_pub_t*)(sip), sip_replaces_class )) \ |
12032 | ((sip_replaces_t *)msg_header_access((msg_pub_t*)(sip), sip_replaces_class)) |
12033 | |
12034 | /**Initializer for structure #sip_replaces_t. |
12035 | * |
12036 | * A static #sip_replaces_t structure for |
12037 | * @ref sip_replaces "Replaces header" must be initialized with |
12038 | * the SIP_REPLACES_INIT() macro. |
12039 | * For instance, |
12040 | * @code |
12041 | * |
12042 | * sip_replaces_t sip_replaces = SIP_REPLACES_INIT; |
12043 | * |
12044 | * @endcode |
12045 | * @HI |
12046 | * |
12047 | */ |
12048 | #define SIP_REPLACES_INIT(){{{ 0, 0, sip_replaces_class }}} SIP_HDR_INIT(replaces){{{ 0, 0, sip_replaces_class }}} |
12049 | |
12050 | /**Initialize a structure #sip_replaces_t. |
12051 | * |
12052 | * An #sip_replaces_t structure for |
12053 | * @ref sip_replaces "Replaces header" can be initialized with the |
12054 | * sip_replaces_init() function/macro. For instance, |
12055 | * @code |
12056 | * |
12057 | * sip_replaces_t sip_replaces; |
12058 | * |
12059 | * sip_replaces_init(&sip_replaces); |
12060 | * |
12061 | * @endcode |
12062 | * @HI |
12063 | * |
12064 | */ |
12065 | #if SU_HAVE_INLINE1 |
12066 | su_inlinestatic inline sip_replaces_t *sip_replaces_init(sip_replaces_t x[1]) |
12067 | { |
12068 | return SIP_HEADER_INIT(x, sip_replaces_class, sizeof(sip_replaces_t))((void)memset((x), 0, (sizeof(sip_replaces_t))), (void)(((sip_common_t *)(x))->h_class = (sip_replaces_class)), (x)); |
12069 | } |
12070 | #else |
12071 | #define sip_replaces_init(x) \ |
12072 | SIP_HEADER_INIT(x, sip_replaces_class, sizeof(sip_replaces_t))((void)memset((x), 0, (sizeof(sip_replaces_t))), (void)(((sip_common_t *)(x))->h_class = (sip_replaces_class)), (x)) |
12073 | #endif |
12074 | |
12075 | /**Test if header object is instance of #sip_replaces_t. |
12076 | * |
12077 | * Check if the header class is an instance of |
12078 | * @ref sip_replaces "Replaces header" object and return true (nonzero), |
12079 | * otherwise return false (zero). |
12080 | * |
12081 | * @param header pointer to the header structure to be tested |
12082 | * |
12083 | * @retval 1 (true) if the @a header is an instance of header replaces |
12084 | * @retval 0 (false) otherwise |
12085 | * |
12086 | */ |
12087 | #if SU_HAVE_INLINE1 |
12088 | su_inlinestatic inline int sip_is_replaces(sip_header_t const *header) |
12089 | { |
12090 | return header && header->sh_classsh_common->h_class->hc_hash == sip_replaces_hash; |
12091 | } |
12092 | #else |
12093 | int sip_is_replaces(sip_header_t const *header); |
12094 | #endif |
12095 | |
12096 | #define sip_replaces_p(h)sip_is_replaces((h)) sip_is_replaces((h)) |
12097 | |
12098 | |
12099 | /**Duplicate a list of @ref sip_replaces "Replaces header" header structures #sip_replaces_t. |
12100 | * |
12101 | * Duplicate a header |
12102 | * structure @a hdr. If the header structure @a hdr |
12103 | * contains a reference (@c hdr->x_next) to a list of |
12104 | * headers, all the headers in the list are duplicated, too. |
12105 | * |
12106 | * @param home memory home used to allocate new structure |
12107 | * @param hdr header structure to be duplicated |
12108 | * |
12109 | * When duplicating, all parameter lists and non-constant |
12110 | * strings attached to the header are copied, too. The |
12111 | * function uses given memory @a home to allocate all the |
12112 | * memory areas used to copy the header. |
12113 | * |
12114 | * @par Example |
12115 | * @code |
12116 | * |
12117 | * replaces = sip_replaces_dup(home, sip->sip_replaces); |
12118 | * |
12119 | * @endcode |
12120 | * |
12121 | * @return |
12122 | * A pointer to the |
12123 | * newly duplicated #sip_replaces_t header structure, or NULL |
12124 | * upon an error. |
12125 | * |
12126 | */ |
12127 | #if SU_HAVE_INLINE1 |
12128 | su_inlinestatic inline |
12129 | #endif |
12130 | sip_replaces_t *sip_replaces_dup(su_home_t *home, sip_replaces_t const *hdr) |
12131 | __attribute__((__malloc__)); |
12132 | |
12133 | #if SU_HAVE_INLINE1 |
12134 | su_inlinestatic inline |
12135 | sip_replaces_t *sip_replaces_dup(su_home_t *home, sip_replaces_t const *hdr) |
12136 | { |
12137 | return (sip_replaces_t *) |
12138 | msg_header_dup_as(home, sip_replaces_class, (msg_header_t const *)hdr); |
12139 | } |
12140 | #endif |
12141 | |
12142 | /**Copy a list of @ref sip_replaces "Replaces header" header structures #sip_replaces_t. |
12143 | * |
12144 | * The function sip_replaces_copy() copies a header structure @a |
12145 | * hdr. If the header structure @a hdr contains a reference (@c |
12146 | * hdr->h_next) to a list of headers, all the headers in that |
12147 | * list are copied, too. The function uses given memory @a home |
12148 | * to allocate all the memory areas used to copy the list of header |
12149 | * structure @a hdr. |
12150 | * |
12151 | * @param home memory home used to allocate new structure |
12152 | * @param hdr pointer to the header structure to be copied |
12153 | * |
12154 | * When copying, only the header structure and parameter lists attached to |
12155 | * it are duplicated. The new header structure retains all the references to |
12156 | * the strings within the old @a hdr header, including the encoding of the |
12157 | * old header, if present. |
12158 | * |
12159 | * @par Example |
12160 | * @code |
12161 | * |
12162 | * replaces = sip_replaces_copy(home, sip->sip_replaces); |
12163 | * |
12164 | * @endcode |
12165 | * |
12166 | * @return |
12167 | * A pointer to newly copied header structure, or NULL upon an error. |
12168 | * |
12169 | */ |
12170 | #if SU_HAVE_INLINE1 |
12171 | su_inlinestatic inline |
12172 | #endif |
12173 | sip_replaces_t *sip_replaces_copy(su_home_t *home, sip_replaces_t const *hdr) |
12174 | __attribute__((__malloc__)); |
12175 | |
12176 | #if SU_HAVE_INLINE1 |
12177 | su_inlinestatic inline |
12178 | sip_replaces_t *sip_replaces_copy(su_home_t *home, sip_replaces_t const *hdr) |
12179 | { |
12180 | return (sip_replaces_t *) |
12181 | msg_header_copy_as(home, sip_replaces_class, (msg_header_t const *)hdr); |
12182 | } |
12183 | #endif |
12184 | |
12185 | /**Make a @ref sip_replaces "Replaces header" structure #sip_replaces_t. |
12186 | * |
12187 | * The function sip_replaces_make() makes a new |
12188 | * #sip_replaces_t header structure. It allocates a new |
12189 | * header structure, and decodes the string @a s as the |
12190 | * value of the structure. |
12191 | * |
12192 | * @param home memory home used to allocate new header structure. |
12193 | * @param s string to be decoded as value of the new header structure |
12194 | * |
12195 | * @return |
12196 | * A pointer to newly maked #sip_replaces_t header structure, or NULL upon an |
12197 | * error. |
12198 | * |
12199 | */ |
12200 | #if SU_HAVE_INLINE1 |
12201 | su_inlinestatic inline |
12202 | #endif |
12203 | sip_replaces_t *sip_replaces_make(su_home_t *home, char const *s) |
12204 | __attribute__((__malloc__)); |
12205 | |
12206 | #if SU_HAVE_INLINE1 |
12207 | su_inlinestatic inline sip_replaces_t *sip_replaces_make(su_home_t *home, char const *s) |
12208 | { |
12209 | return (sip_replaces_t *)sip_header_make(home, sip_replaces_class, s)((sip_header_t *)msg_header_make((home), (sip_replaces_class) , (s))); |
12210 | } |
12211 | #endif |
12212 | |
12213 | /**Make a @ref sip_replaces "Replaces header" from formatting result. |
12214 | * |
12215 | * Make a new #sip_replaces_t object using formatting result as its value. |
12216 | * The function first prints the arguments according to the format @a fmt |
12217 | * specified. Then it allocates a new header structure, and parses the |
12218 | * formatting result to the structure #sip_replaces_t. |
12219 | * |
12220 | * @param home memory home used to allocate new header structure. |
12221 | * @param fmt string used as a printf()-style format |
12222 | * @param ... argument list for format |
12223 | * |
12224 | * @return |
12225 | * A pointer to newly |
12226 | * makes header structure, or NULL upon an error. |
12227 | * |
12228 | * @HIDE |
12229 | * |
12230 | */ |
12231 | #if SU_HAVE_INLINE1 |
12232 | su_inlinestatic inline |
12233 | #endif |
12234 | sip_replaces_t *sip_replaces_format(su_home_t *home, char const *fmt, ...) |
12235 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
12236 | |
12237 | #if SU_HAVE_INLINE1 |
12238 | su_inlinestatic inline sip_replaces_t *sip_replaces_format(su_home_t *home, char const *fmt, ...) |
12239 | { |
12240 | sip_header_t *h; |
12241 | va_list ap; |
12242 | |
12243 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
12244 | h = sip_header_vformat(home, sip_replaces_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_replaces_class ), (fmt), (ap))); |
12245 | va_end(ap)__builtin_va_end(ap); |
12246 | |
12247 | return (sip_replaces_t *)h; |
12248 | } |
12249 | #endif |
12250 | |
12251 | /** @} */ |
12252 | |
12253 | /**@addtogroup sip_session_expires |
12254 | * @{ |
12255 | */ |
12256 | |
12257 | /** Parse a SIP @ref sip_session_expires "Session-Expires header". @internal */ |
12258 | SOFIAPUBFUN issize_t sip_session_expires_d(su_home_t *, msg_header_t *, |
12259 | char *s, isize_t slen); |
12260 | |
12261 | /** Print a SIP @ref sip_session_expires "Session-Expires header". @internal */ |
12262 | SOFIAPUBFUN issize_t sip_session_expires_e(char b[], isize_t bsiz, |
12263 | msg_header_t const *h, int flags); |
12264 | |
12265 | /**Access a SIP @ref sip_session_expires "Session-Expires header" |
12266 | * structure #sip_session_expires_t from #sip_t. |
12267 | * |
12268 | */ |
12269 | #define sip_session_expires(sip)((sip_session_expires_t *)msg_header_access((msg_pub_t*)(sip) , sip_session_expires_class)) \ |
12270 | ((sip_session_expires_t *)msg_header_access((msg_pub_t*)(sip), sip_session_expires_class)) |
12271 | |
12272 | /**Initializer for structure #sip_session_expires_t. |
12273 | * |
12274 | * A static #sip_session_expires_t structure for |
12275 | * @ref sip_session_expires "Session-Expires header" must be initialized with |
12276 | * the SIP_SESSION_EXPIRES_INIT() macro. |
12277 | * For instance, |
12278 | * @code |
12279 | * |
12280 | * sip_session_expires_t sip_session_expires = SIP_SESSION_EXPIRES_INIT; |
12281 | * |
12282 | * @endcode |
12283 | * @HI |
12284 | * |
12285 | */ |
12286 | #define SIP_SESSION_EXPIRES_INIT(){{{ 0, 0, sip_session_expires_class }}} SIP_HDR_INIT(session_expires){{{ 0, 0, sip_session_expires_class }}} |
12287 | |
12288 | /**Initialize a structure #sip_session_expires_t. |
12289 | * |
12290 | * An #sip_session_expires_t structure for |
12291 | * @ref sip_session_expires "Session-Expires header" can be initialized with the |
12292 | * sip_session_expires_init() function/macro. For instance, |
12293 | * @code |
12294 | * |
12295 | * sip_session_expires_t sip_session_expires; |
12296 | * |
12297 | * sip_session_expires_init(&sip_session_expires); |
12298 | * |
12299 | * @endcode |
12300 | * @HI |
12301 | * |
12302 | */ |
12303 | #if SU_HAVE_INLINE1 |
12304 | su_inlinestatic inline sip_session_expires_t *sip_session_expires_init(sip_session_expires_t x[1]) |
12305 | { |
12306 | return SIP_HEADER_INIT(x, sip_session_expires_class, sizeof(sip_session_expires_t))((void)memset((x), 0, (sizeof(sip_session_expires_t))), (void )(((sip_common_t *)(x))->h_class = (sip_session_expires_class )), (x)); |
12307 | } |
12308 | #else |
12309 | #define sip_session_expires_init(x) \ |
12310 | SIP_HEADER_INIT(x, sip_session_expires_class, sizeof(sip_session_expires_t))((void)memset((x), 0, (sizeof(sip_session_expires_t))), (void )(((sip_common_t *)(x))->h_class = (sip_session_expires_class )), (x)) |
12311 | #endif |
12312 | |
12313 | /**Test if header object is instance of #sip_session_expires_t. |
12314 | * |
12315 | * Check if the header class is an instance of |
12316 | * @ref sip_session_expires "Session-Expires header" object and return true (nonzero), |
12317 | * otherwise return false (zero). |
12318 | * |
12319 | * @param header pointer to the header structure to be tested |
12320 | * |
12321 | * @retval 1 (true) if the @a header is an instance of header session_expires |
12322 | * @retval 0 (false) otherwise |
12323 | * |
12324 | */ |
12325 | #if SU_HAVE_INLINE1 |
12326 | su_inlinestatic inline int sip_is_session_expires(sip_header_t const *header) |
12327 | { |
12328 | return header && header->sh_classsh_common->h_class->hc_hash == sip_session_expires_hash; |
12329 | } |
12330 | #else |
12331 | int sip_is_session_expires(sip_header_t const *header); |
12332 | #endif |
12333 | |
12334 | #define sip_session_expires_p(h)sip_is_session_expires((h)) sip_is_session_expires((h)) |
12335 | |
12336 | |
12337 | /**Duplicate a list of @ref sip_session_expires "Session-Expires header" header structures #sip_session_expires_t. |
12338 | * |
12339 | * Duplicate a header |
12340 | * structure @a hdr. If the header structure @a hdr |
12341 | * contains a reference (@c hdr->x_next) to a list of |
12342 | * headers, all the headers in the list are duplicated, too. |
12343 | * |
12344 | * @param home memory home used to allocate new structure |
12345 | * @param hdr header structure to be duplicated |
12346 | * |
12347 | * When duplicating, all parameter lists and non-constant |
12348 | * strings attached to the header are copied, too. The |
12349 | * function uses given memory @a home to allocate all the |
12350 | * memory areas used to copy the header. |
12351 | * |
12352 | * @par Example |
12353 | * @code |
12354 | * |
12355 | * session_expires = sip_session_expires_dup(home, sip->sip_session_expires); |
12356 | * |
12357 | * @endcode |
12358 | * |
12359 | * @return |
12360 | * A pointer to the |
12361 | * newly duplicated #sip_session_expires_t header structure, or NULL |
12362 | * upon an error. |
12363 | * |
12364 | */ |
12365 | #if SU_HAVE_INLINE1 |
12366 | su_inlinestatic inline |
12367 | #endif |
12368 | sip_session_expires_t *sip_session_expires_dup(su_home_t *home, sip_session_expires_t const *hdr) |
12369 | __attribute__((__malloc__)); |
12370 | |
12371 | #if SU_HAVE_INLINE1 |
12372 | su_inlinestatic inline |
12373 | sip_session_expires_t *sip_session_expires_dup(su_home_t *home, sip_session_expires_t const *hdr) |
12374 | { |
12375 | return (sip_session_expires_t *) |
12376 | msg_header_dup_as(home, sip_session_expires_class, (msg_header_t const *)hdr); |
12377 | } |
12378 | #endif |
12379 | |
12380 | /**Copy a list of @ref sip_session_expires "Session-Expires header" header structures #sip_session_expires_t. |
12381 | * |
12382 | * The function sip_session_expires_copy() copies a header structure @a |
12383 | * hdr. If the header structure @a hdr contains a reference (@c |
12384 | * hdr->h_next) to a list of headers, all the headers in that |
12385 | * list are copied, too. The function uses given memory @a home |
12386 | * to allocate all the memory areas used to copy the list of header |
12387 | * structure @a hdr. |
12388 | * |
12389 | * @param home memory home used to allocate new structure |
12390 | * @param hdr pointer to the header structure to be copied |
12391 | * |
12392 | * When copying, only the header structure and parameter lists attached to |
12393 | * it are duplicated. The new header structure retains all the references to |
12394 | * the strings within the old @a hdr header, including the encoding of the |
12395 | * old header, if present. |
12396 | * |
12397 | * @par Example |
12398 | * @code |
12399 | * |
12400 | * session_expires = sip_session_expires_copy(home, sip->sip_session_expires); |
12401 | * |
12402 | * @endcode |
12403 | * |
12404 | * @return |
12405 | * A pointer to newly copied header structure, or NULL upon an error. |
12406 | * |
12407 | */ |
12408 | #if SU_HAVE_INLINE1 |
12409 | su_inlinestatic inline |
12410 | #endif |
12411 | sip_session_expires_t *sip_session_expires_copy(su_home_t *home, sip_session_expires_t const *hdr) |
12412 | __attribute__((__malloc__)); |
12413 | |
12414 | #if SU_HAVE_INLINE1 |
12415 | su_inlinestatic inline |
12416 | sip_session_expires_t *sip_session_expires_copy(su_home_t *home, sip_session_expires_t const *hdr) |
12417 | { |
12418 | return (sip_session_expires_t *) |
12419 | msg_header_copy_as(home, sip_session_expires_class, (msg_header_t const *)hdr); |
12420 | } |
12421 | #endif |
12422 | |
12423 | /**Make a @ref sip_session_expires "Session-Expires header" structure #sip_session_expires_t. |
12424 | * |
12425 | * The function sip_session_expires_make() makes a new |
12426 | * #sip_session_expires_t header structure. It allocates a new |
12427 | * header structure, and decodes the string @a s as the |
12428 | * value of the structure. |
12429 | * |
12430 | * @param home memory home used to allocate new header structure. |
12431 | * @param s string to be decoded as value of the new header structure |
12432 | * |
12433 | * @return |
12434 | * A pointer to newly maked #sip_session_expires_t header structure, or NULL upon an |
12435 | * error. |
12436 | * |
12437 | */ |
12438 | #if SU_HAVE_INLINE1 |
12439 | su_inlinestatic inline |
12440 | #endif |
12441 | sip_session_expires_t *sip_session_expires_make(su_home_t *home, char const *s) |
12442 | __attribute__((__malloc__)); |
12443 | |
12444 | #if SU_HAVE_INLINE1 |
12445 | su_inlinestatic inline sip_session_expires_t *sip_session_expires_make(su_home_t *home, char const *s) |
12446 | { |
12447 | return (sip_session_expires_t *)sip_header_make(home, sip_session_expires_class, s)((sip_header_t *)msg_header_make((home), (sip_session_expires_class ), (s))); |
12448 | } |
12449 | #endif |
12450 | |
12451 | /**Make a @ref sip_session_expires "Session-Expires header" from formatting result. |
12452 | * |
12453 | * Make a new #sip_session_expires_t object using formatting result as its value. |
12454 | * The function first prints the arguments according to the format @a fmt |
12455 | * specified. Then it allocates a new header structure, and parses the |
12456 | * formatting result to the structure #sip_session_expires_t. |
12457 | * |
12458 | * @param home memory home used to allocate new header structure. |
12459 | * @param fmt string used as a printf()-style format |
12460 | * @param ... argument list for format |
12461 | * |
12462 | * @return |
12463 | * A pointer to newly |
12464 | * makes header structure, or NULL upon an error. |
12465 | * |
12466 | * @HIDE |
12467 | * |
12468 | */ |
12469 | #if SU_HAVE_INLINE1 |
12470 | su_inlinestatic inline |
12471 | #endif |
12472 | sip_session_expires_t *sip_session_expires_format(su_home_t *home, char const *fmt, ...) |
12473 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
12474 | |
12475 | #if SU_HAVE_INLINE1 |
12476 | su_inlinestatic inline sip_session_expires_t *sip_session_expires_format(su_home_t *home, char const *fmt, ...) |
12477 | { |
12478 | sip_header_t *h; |
12479 | va_list ap; |
12480 | |
12481 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
12482 | h = sip_header_vformat(home, sip_session_expires_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_session_expires_class ), (fmt), (ap))); |
12483 | va_end(ap)__builtin_va_end(ap); |
12484 | |
12485 | return (sip_session_expires_t *)h; |
12486 | } |
12487 | #endif |
12488 | |
12489 | /** @} */ |
12490 | |
12491 | /**@addtogroup sip_min_se |
12492 | * @{ |
12493 | */ |
12494 | |
12495 | /** Parse a SIP @ref sip_min_se "Min-SE header". @internal */ |
12496 | SOFIAPUBFUN issize_t sip_min_se_d(su_home_t *, msg_header_t *, |
12497 | char *s, isize_t slen); |
12498 | |
12499 | /** Print a SIP @ref sip_min_se "Min-SE header". @internal */ |
12500 | SOFIAPUBFUN issize_t sip_min_se_e(char b[], isize_t bsiz, |
12501 | msg_header_t const *h, int flags); |
12502 | |
12503 | /**Access a SIP @ref sip_min_se "Min-SE header" |
12504 | * structure #sip_min_se_t from #sip_t. |
12505 | * |
12506 | */ |
12507 | #define sip_min_se(sip)((sip_min_se_t *)msg_header_access((msg_pub_t*)(sip), sip_min_se_class )) \ |
12508 | ((sip_min_se_t *)msg_header_access((msg_pub_t*)(sip), sip_min_se_class)) |
12509 | |
12510 | /**Initializer for structure #sip_min_se_t. |
12511 | * |
12512 | * A static #sip_min_se_t structure for |
12513 | * @ref sip_min_se "Min-SE header" must be initialized with |
12514 | * the SIP_MIN_SE_INIT() macro. |
12515 | * For instance, |
12516 | * @code |
12517 | * |
12518 | * sip_min_se_t sip_min_se = SIP_MIN_SE_INIT; |
12519 | * |
12520 | * @endcode |
12521 | * @HI |
12522 | * |
12523 | */ |
12524 | #define SIP_MIN_SE_INIT(){{{ 0, 0, sip_min_se_class }}} SIP_HDR_INIT(min_se){{{ 0, 0, sip_min_se_class }}} |
12525 | |
12526 | /**Initialize a structure #sip_min_se_t. |
12527 | * |
12528 | * An #sip_min_se_t structure for |
12529 | * @ref sip_min_se "Min-SE header" can be initialized with the |
12530 | * sip_min_se_init() function/macro. For instance, |
12531 | * @code |
12532 | * |
12533 | * sip_min_se_t sip_min_se; |
12534 | * |
12535 | * sip_min_se_init(&sip_min_se); |
12536 | * |
12537 | * @endcode |
12538 | * @HI |
12539 | * |
12540 | */ |
12541 | #if SU_HAVE_INLINE1 |
12542 | su_inlinestatic inline sip_min_se_t *sip_min_se_init(sip_min_se_t x[1]) |
12543 | { |
12544 | return SIP_HEADER_INIT(x, sip_min_se_class, sizeof(sip_min_se_t))((void)memset((x), 0, (sizeof(sip_min_se_t))), (void)(((sip_common_t *)(x))->h_class = (sip_min_se_class)), (x)); |
12545 | } |
12546 | #else |
12547 | #define sip_min_se_init(x) \ |
12548 | SIP_HEADER_INIT(x, sip_min_se_class, sizeof(sip_min_se_t))((void)memset((x), 0, (sizeof(sip_min_se_t))), (void)(((sip_common_t *)(x))->h_class = (sip_min_se_class)), (x)) |
12549 | #endif |
12550 | |
12551 | /**Test if header object is instance of #sip_min_se_t. |
12552 | * |
12553 | * Check if the header class is an instance of |
12554 | * @ref sip_min_se "Min-SE header" object and return true (nonzero), |
12555 | * otherwise return false (zero). |
12556 | * |
12557 | * @param header pointer to the header structure to be tested |
12558 | * |
12559 | * @retval 1 (true) if the @a header is an instance of header min_se |
12560 | * @retval 0 (false) otherwise |
12561 | * |
12562 | */ |
12563 | #if SU_HAVE_INLINE1 |
12564 | su_inlinestatic inline int sip_is_min_se(sip_header_t const *header) |
12565 | { |
12566 | return header && header->sh_classsh_common->h_class->hc_hash == sip_min_se_hash; |
12567 | } |
12568 | #else |
12569 | int sip_is_min_se(sip_header_t const *header); |
12570 | #endif |
12571 | |
12572 | #define sip_min_se_p(h)sip_is_min_se((h)) sip_is_min_se((h)) |
12573 | |
12574 | |
12575 | /**Duplicate a list of @ref sip_min_se "Min-SE header" header structures #sip_min_se_t. |
12576 | * |
12577 | * Duplicate a header |
12578 | * structure @a hdr. If the header structure @a hdr |
12579 | * contains a reference (@c hdr->x_next) to a list of |
12580 | * headers, all the headers in the list are duplicated, too. |
12581 | * |
12582 | * @param home memory home used to allocate new structure |
12583 | * @param hdr header structure to be duplicated |
12584 | * |
12585 | * When duplicating, all parameter lists and non-constant |
12586 | * strings attached to the header are copied, too. The |
12587 | * function uses given memory @a home to allocate all the |
12588 | * memory areas used to copy the header. |
12589 | * |
12590 | * @par Example |
12591 | * @code |
12592 | * |
12593 | * min_se = sip_min_se_dup(home, sip->sip_min_se); |
12594 | * |
12595 | * @endcode |
12596 | * |
12597 | * @return |
12598 | * A pointer to the |
12599 | * newly duplicated #sip_min_se_t header structure, or NULL |
12600 | * upon an error. |
12601 | * |
12602 | */ |
12603 | #if SU_HAVE_INLINE1 |
12604 | su_inlinestatic inline |
12605 | #endif |
12606 | sip_min_se_t *sip_min_se_dup(su_home_t *home, sip_min_se_t const *hdr) |
12607 | __attribute__((__malloc__)); |
12608 | |
12609 | #if SU_HAVE_INLINE1 |
12610 | su_inlinestatic inline |
12611 | sip_min_se_t *sip_min_se_dup(su_home_t *home, sip_min_se_t const *hdr) |
12612 | { |
12613 | return (sip_min_se_t *) |
12614 | msg_header_dup_as(home, sip_min_se_class, (msg_header_t const *)hdr); |
12615 | } |
12616 | #endif |
12617 | |
12618 | /**Copy a list of @ref sip_min_se "Min-SE header" header structures #sip_min_se_t. |
12619 | * |
12620 | * The function sip_min_se_copy() copies a header structure @a |
12621 | * hdr. If the header structure @a hdr contains a reference (@c |
12622 | * hdr->h_next) to a list of headers, all the headers in that |
12623 | * list are copied, too. The function uses given memory @a home |
12624 | * to allocate all the memory areas used to copy the list of header |
12625 | * structure @a hdr. |
12626 | * |
12627 | * @param home memory home used to allocate new structure |
12628 | * @param hdr pointer to the header structure to be copied |
12629 | * |
12630 | * When copying, only the header structure and parameter lists attached to |
12631 | * it are duplicated. The new header structure retains all the references to |
12632 | * the strings within the old @a hdr header, including the encoding of the |
12633 | * old header, if present. |
12634 | * |
12635 | * @par Example |
12636 | * @code |
12637 | * |
12638 | * min_se = sip_min_se_copy(home, sip->sip_min_se); |
12639 | * |
12640 | * @endcode |
12641 | * |
12642 | * @return |
12643 | * A pointer to newly copied header structure, or NULL upon an error. |
12644 | * |
12645 | */ |
12646 | #if SU_HAVE_INLINE1 |
12647 | su_inlinestatic inline |
12648 | #endif |
12649 | sip_min_se_t *sip_min_se_copy(su_home_t *home, sip_min_se_t const *hdr) |
12650 | __attribute__((__malloc__)); |
12651 | |
12652 | #if SU_HAVE_INLINE1 |
12653 | su_inlinestatic inline |
12654 | sip_min_se_t *sip_min_se_copy(su_home_t *home, sip_min_se_t const *hdr) |
12655 | { |
12656 | return (sip_min_se_t *) |
12657 | msg_header_copy_as(home, sip_min_se_class, (msg_header_t const *)hdr); |
12658 | } |
12659 | #endif |
12660 | |
12661 | /**Make a @ref sip_min_se "Min-SE header" structure #sip_min_se_t. |
12662 | * |
12663 | * The function sip_min_se_make() makes a new |
12664 | * #sip_min_se_t header structure. It allocates a new |
12665 | * header structure, and decodes the string @a s as the |
12666 | * value of the structure. |
12667 | * |
12668 | * @param home memory home used to allocate new header structure. |
12669 | * @param s string to be decoded as value of the new header structure |
12670 | * |
12671 | * @return |
12672 | * A pointer to newly maked #sip_min_se_t header structure, or NULL upon an |
12673 | * error. |
12674 | * |
12675 | */ |
12676 | #if SU_HAVE_INLINE1 |
12677 | su_inlinestatic inline |
12678 | #endif |
12679 | sip_min_se_t *sip_min_se_make(su_home_t *home, char const *s) |
12680 | __attribute__((__malloc__)); |
12681 | |
12682 | #if SU_HAVE_INLINE1 |
12683 | su_inlinestatic inline sip_min_se_t *sip_min_se_make(su_home_t *home, char const *s) |
12684 | { |
12685 | return (sip_min_se_t *)sip_header_make(home, sip_min_se_class, s)((sip_header_t *)msg_header_make((home), (sip_min_se_class), ( s))); |
12686 | } |
12687 | #endif |
12688 | |
12689 | /**Make a @ref sip_min_se "Min-SE header" from formatting result. |
12690 | * |
12691 | * Make a new #sip_min_se_t object using formatting result as its value. |
12692 | * The function first prints the arguments according to the format @a fmt |
12693 | * specified. Then it allocates a new header structure, and parses the |
12694 | * formatting result to the structure #sip_min_se_t. |
12695 | * |
12696 | * @param home memory home used to allocate new header structure. |
12697 | * @param fmt string used as a printf()-style format |
12698 | * @param ... argument list for format |
12699 | * |
12700 | * @return |
12701 | * A pointer to newly |
12702 | * makes header structure, or NULL upon an error. |
12703 | * |
12704 | * @HIDE |
12705 | * |
12706 | */ |
12707 | #if SU_HAVE_INLINE1 |
12708 | su_inlinestatic inline |
12709 | #endif |
12710 | sip_min_se_t *sip_min_se_format(su_home_t *home, char const *fmt, ...) |
12711 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
12712 | |
12713 | #if SU_HAVE_INLINE1 |
12714 | su_inlinestatic inline sip_min_se_t *sip_min_se_format(su_home_t *home, char const *fmt, ...) |
12715 | { |
12716 | sip_header_t *h; |
12717 | va_list ap; |
12718 | |
12719 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
12720 | h = sip_header_vformat(home, sip_min_se_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_min_se_class ), (fmt), (ap))); |
12721 | va_end(ap)__builtin_va_end(ap); |
12722 | |
12723 | return (sip_min_se_t *)h; |
12724 | } |
12725 | #endif |
12726 | |
12727 | /** @} */ |
12728 | |
12729 | /**@addtogroup sip_path |
12730 | * @{ |
12731 | */ |
12732 | |
12733 | /** Parse a SIP @ref sip_path "Path header". @internal */ |
12734 | SOFIAPUBFUN issize_t sip_path_d(su_home_t *, msg_header_t *, |
12735 | char *s, isize_t slen); |
12736 | |
12737 | /** Print a SIP @ref sip_path "Path header". @internal */ |
12738 | SOFIAPUBFUN issize_t sip_path_e(char b[], isize_t bsiz, |
12739 | msg_header_t const *h, int flags); |
12740 | |
12741 | /**Access a SIP @ref sip_path "Path header" |
12742 | * structure #sip_path_t from #sip_t. |
12743 | * |
12744 | */ |
12745 | #define sip_path(sip)((sip_path_t *)msg_header_access((msg_pub_t*)(sip), sip_path_class )) \ |
12746 | ((sip_path_t *)msg_header_access((msg_pub_t*)(sip), sip_path_class)) |
12747 | |
12748 | /**Initializer for structure #sip_path_t. |
12749 | * |
12750 | * A static #sip_path_t structure for |
12751 | * @ref sip_path "Path header" must be initialized with |
12752 | * the SIP_PATH_INIT() macro. |
12753 | * For instance, |
12754 | * @code |
12755 | * |
12756 | * sip_path_t sip_path = SIP_PATH_INIT; |
12757 | * |
12758 | * @endcode |
12759 | * @HI |
12760 | * |
12761 | */ |
12762 | #define SIP_PATH_INIT(){{{ 0, 0, sip_path_class }}} SIP_HDR_INIT(path){{{ 0, 0, sip_path_class }}} |
12763 | |
12764 | /**Initialize a structure #sip_path_t. |
12765 | * |
12766 | * An #sip_path_t structure for |
12767 | * @ref sip_path "Path header" can be initialized with the |
12768 | * sip_path_init() function/macro. For instance, |
12769 | * @code |
12770 | * |
12771 | * sip_path_t sip_path; |
12772 | * |
12773 | * sip_path_init(&sip_path); |
12774 | * |
12775 | * @endcode |
12776 | * @HI |
12777 | * |
12778 | */ |
12779 | #if SU_HAVE_INLINE1 |
12780 | su_inlinestatic inline sip_path_t *sip_path_init(sip_path_t x[1]) |
12781 | { |
12782 | return SIP_HEADER_INIT(x, sip_path_class, sizeof(sip_path_t))((void)memset((x), 0, (sizeof(sip_path_t))), (void)(((sip_common_t *)(x))->h_class = (sip_path_class)), (x)); |
12783 | } |
12784 | #else |
12785 | #define sip_path_init(x) \ |
12786 | SIP_HEADER_INIT(x, sip_path_class, sizeof(sip_path_t))((void)memset((x), 0, (sizeof(sip_path_t))), (void)(((sip_common_t *)(x))->h_class = (sip_path_class)), (x)) |
12787 | #endif |
12788 | |
12789 | /**Test if header object is instance of #sip_path_t. |
12790 | * |
12791 | * Check if the header class is an instance of |
12792 | * @ref sip_path "Path header" object and return true (nonzero), |
12793 | * otherwise return false (zero). |
12794 | * |
12795 | * @param header pointer to the header structure to be tested |
12796 | * |
12797 | * @retval 1 (true) if the @a header is an instance of header path |
12798 | * @retval 0 (false) otherwise |
12799 | * |
12800 | */ |
12801 | #if SU_HAVE_INLINE1 |
12802 | su_inlinestatic inline int sip_is_path(sip_header_t const *header) |
12803 | { |
12804 | return header && header->sh_classsh_common->h_class->hc_hash == sip_path_hash; |
12805 | } |
12806 | #else |
12807 | int sip_is_path(sip_header_t const *header); |
12808 | #endif |
12809 | |
12810 | #define sip_path_p(h)sip_is_path((h)) sip_is_path((h)) |
12811 | |
12812 | |
12813 | /**Duplicate a list of @ref sip_path "Path header" header structures #sip_path_t. |
12814 | * |
12815 | * Duplicate a header |
12816 | * structure @a hdr. If the header structure @a hdr |
12817 | * contains a reference (@c hdr->x_next) to a list of |
12818 | * headers, all the headers in the list are duplicated, too. |
12819 | * |
12820 | * @param home memory home used to allocate new structure |
12821 | * @param hdr header structure to be duplicated |
12822 | * |
12823 | * When duplicating, all parameter lists and non-constant |
12824 | * strings attached to the header are copied, too. The |
12825 | * function uses given memory @a home to allocate all the |
12826 | * memory areas used to copy the header. |
12827 | * |
12828 | * @par Example |
12829 | * @code |
12830 | * |
12831 | * path = sip_path_dup(home, sip->sip_path); |
12832 | * |
12833 | * @endcode |
12834 | * |
12835 | * @return |
12836 | * A pointer to the |
12837 | * newly duplicated #sip_path_t header structure, or NULL |
12838 | * upon an error. |
12839 | * |
12840 | */ |
12841 | #if SU_HAVE_INLINE1 |
12842 | su_inlinestatic inline |
12843 | #endif |
12844 | sip_path_t *sip_path_dup(su_home_t *home, sip_path_t const *hdr) |
12845 | __attribute__((__malloc__)); |
12846 | |
12847 | #if SU_HAVE_INLINE1 |
12848 | su_inlinestatic inline |
12849 | sip_path_t *sip_path_dup(su_home_t *home, sip_path_t const *hdr) |
12850 | { |
12851 | return (sip_path_t *) |
12852 | msg_header_dup_as(home, sip_path_class, (msg_header_t const *)hdr); |
12853 | } |
12854 | #endif |
12855 | |
12856 | /**Copy a list of @ref sip_path "Path header" header structures #sip_path_t. |
12857 | * |
12858 | * The function sip_path_copy() copies a header structure @a |
12859 | * hdr. If the header structure @a hdr contains a reference (@c |
12860 | * hdr->h_next) to a list of headers, all the headers in that |
12861 | * list are copied, too. The function uses given memory @a home |
12862 | * to allocate all the memory areas used to copy the list of header |
12863 | * structure @a hdr. |
12864 | * |
12865 | * @param home memory home used to allocate new structure |
12866 | * @param hdr pointer to the header structure to be copied |
12867 | * |
12868 | * When copying, only the header structure and parameter lists attached to |
12869 | * it are duplicated. The new header structure retains all the references to |
12870 | * the strings within the old @a hdr header, including the encoding of the |
12871 | * old header, if present. |
12872 | * |
12873 | * @par Example |
12874 | * @code |
12875 | * |
12876 | * path = sip_path_copy(home, sip->sip_path); |
12877 | * |
12878 | * @endcode |
12879 | * |
12880 | * @return |
12881 | * A pointer to newly copied header structure, or NULL upon an error. |
12882 | * |
12883 | */ |
12884 | #if SU_HAVE_INLINE1 |
12885 | su_inlinestatic inline |
12886 | #endif |
12887 | sip_path_t *sip_path_copy(su_home_t *home, sip_path_t const *hdr) |
12888 | __attribute__((__malloc__)); |
12889 | |
12890 | #if SU_HAVE_INLINE1 |
12891 | su_inlinestatic inline |
12892 | sip_path_t *sip_path_copy(su_home_t *home, sip_path_t const *hdr) |
12893 | { |
12894 | return (sip_path_t *) |
12895 | msg_header_copy_as(home, sip_path_class, (msg_header_t const *)hdr); |
12896 | } |
12897 | #endif |
12898 | |
12899 | /**Make a @ref sip_path "Path header" structure #sip_path_t. |
12900 | * |
12901 | * The function sip_path_make() makes a new |
12902 | * #sip_path_t header structure. It allocates a new |
12903 | * header structure, and decodes the string @a s as the |
12904 | * value of the structure. |
12905 | * |
12906 | * @param home memory home used to allocate new header structure. |
12907 | * @param s string to be decoded as value of the new header structure |
12908 | * |
12909 | * @return |
12910 | * A pointer to newly maked #sip_path_t header structure, or NULL upon an |
12911 | * error. |
12912 | * |
12913 | */ |
12914 | #if SU_HAVE_INLINE1 |
12915 | su_inlinestatic inline |
12916 | #endif |
12917 | sip_path_t *sip_path_make(su_home_t *home, char const *s) |
12918 | __attribute__((__malloc__)); |
12919 | |
12920 | #if SU_HAVE_INLINE1 |
12921 | su_inlinestatic inline sip_path_t *sip_path_make(su_home_t *home, char const *s) |
12922 | { |
12923 | return (sip_path_t *)sip_header_make(home, sip_path_class, s)((sip_header_t *)msg_header_make((home), (sip_path_class), (s ))); |
12924 | } |
12925 | #endif |
12926 | |
12927 | /**Make a @ref sip_path "Path header" from formatting result. |
12928 | * |
12929 | * Make a new #sip_path_t object using formatting result as its value. |
12930 | * The function first prints the arguments according to the format @a fmt |
12931 | * specified. Then it allocates a new header structure, and parses the |
12932 | * formatting result to the structure #sip_path_t. |
12933 | * |
12934 | * @param home memory home used to allocate new header structure. |
12935 | * @param fmt string used as a printf()-style format |
12936 | * @param ... argument list for format |
12937 | * |
12938 | * @return |
12939 | * A pointer to newly |
12940 | * makes header structure, or NULL upon an error. |
12941 | * |
12942 | * @HIDE |
12943 | * |
12944 | */ |
12945 | #if SU_HAVE_INLINE1 |
12946 | su_inlinestatic inline |
12947 | #endif |
12948 | sip_path_t *sip_path_format(su_home_t *home, char const *fmt, ...) |
12949 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
12950 | |
12951 | #if SU_HAVE_INLINE1 |
12952 | su_inlinestatic inline sip_path_t *sip_path_format(su_home_t *home, char const *fmt, ...) |
12953 | { |
12954 | sip_header_t *h; |
12955 | va_list ap; |
12956 | |
12957 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
12958 | h = sip_header_vformat(home, sip_path_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_path_class), (fmt), (ap))); |
12959 | va_end(ap)__builtin_va_end(ap); |
12960 | |
12961 | return (sip_path_t *)h; |
12962 | } |
12963 | #endif |
12964 | |
12965 | /** @} */ |
12966 | |
12967 | /**@addtogroup sip_service_route |
12968 | * @{ |
12969 | */ |
12970 | |
12971 | /** Parse a SIP @ref sip_service_route "Service-Route header". @internal */ |
12972 | SOFIAPUBFUN issize_t sip_service_route_d(su_home_t *, msg_header_t *, |
12973 | char *s, isize_t slen); |
12974 | |
12975 | /** Print a SIP @ref sip_service_route "Service-Route header". @internal */ |
12976 | SOFIAPUBFUN issize_t sip_service_route_e(char b[], isize_t bsiz, |
12977 | msg_header_t const *h, int flags); |
12978 | |
12979 | /**Access a SIP @ref sip_service_route "Service-Route header" |
12980 | * structure #sip_service_route_t from #sip_t. |
12981 | * |
12982 | */ |
12983 | #define sip_service_route(sip)((sip_service_route_t *)msg_header_access((msg_pub_t*)(sip), sip_service_route_class )) \ |
12984 | ((sip_service_route_t *)msg_header_access((msg_pub_t*)(sip), sip_service_route_class)) |
12985 | |
12986 | /**Initializer for structure #sip_service_route_t. |
12987 | * |
12988 | * A static #sip_service_route_t structure for |
12989 | * @ref sip_service_route "Service-Route header" must be initialized with |
12990 | * the SIP_SERVICE_ROUTE_INIT() macro. |
12991 | * For instance, |
12992 | * @code |
12993 | * |
12994 | * sip_service_route_t sip_service_route = SIP_SERVICE_ROUTE_INIT; |
12995 | * |
12996 | * @endcode |
12997 | * @HI |
12998 | * |
12999 | */ |
13000 | #define SIP_SERVICE_ROUTE_INIT(){{{ 0, 0, sip_service_route_class }}} SIP_HDR_INIT(service_route){{{ 0, 0, sip_service_route_class }}} |
13001 | |
13002 | /**Initialize a structure #sip_service_route_t. |
13003 | * |
13004 | * An #sip_service_route_t structure for |
13005 | * @ref sip_service_route "Service-Route header" can be initialized with the |
13006 | * sip_service_route_init() function/macro. For instance, |
13007 | * @code |
13008 | * |
13009 | * sip_service_route_t sip_service_route; |
13010 | * |
13011 | * sip_service_route_init(&sip_service_route); |
13012 | * |
13013 | * @endcode |
13014 | * @HI |
13015 | * |
13016 | */ |
13017 | #if SU_HAVE_INLINE1 |
13018 | su_inlinestatic inline sip_service_route_t *sip_service_route_init(sip_service_route_t x[1]) |
13019 | { |
13020 | return SIP_HEADER_INIT(x, sip_service_route_class, sizeof(sip_service_route_t))((void)memset((x), 0, (sizeof(sip_service_route_t))), (void)( ((sip_common_t *)(x))->h_class = (sip_service_route_class) ), (x)); |
13021 | } |
13022 | #else |
13023 | #define sip_service_route_init(x) \ |
13024 | SIP_HEADER_INIT(x, sip_service_route_class, sizeof(sip_service_route_t))((void)memset((x), 0, (sizeof(sip_service_route_t))), (void)( ((sip_common_t *)(x))->h_class = (sip_service_route_class) ), (x)) |
13025 | #endif |
13026 | |
13027 | /**Test if header object is instance of #sip_service_route_t. |
13028 | * |
13029 | * Check if the header class is an instance of |
13030 | * @ref sip_service_route "Service-Route header" object and return true (nonzero), |
13031 | * otherwise return false (zero). |
13032 | * |
13033 | * @param header pointer to the header structure to be tested |
13034 | * |
13035 | * @retval 1 (true) if the @a header is an instance of header service_route |
13036 | * @retval 0 (false) otherwise |
13037 | * |
13038 | */ |
13039 | #if SU_HAVE_INLINE1 |
13040 | su_inlinestatic inline int sip_is_service_route(sip_header_t const *header) |
13041 | { |
13042 | return header && header->sh_classsh_common->h_class->hc_hash == sip_service_route_hash; |
13043 | } |
13044 | #else |
13045 | int sip_is_service_route(sip_header_t const *header); |
13046 | #endif |
13047 | |
13048 | #define sip_service_route_p(h)sip_is_service_route((h)) sip_is_service_route((h)) |
13049 | |
13050 | |
13051 | /**Duplicate a list of @ref sip_service_route "Service-Route header" header structures #sip_service_route_t. |
13052 | * |
13053 | * Duplicate a header |
13054 | * structure @a hdr. If the header structure @a hdr |
13055 | * contains a reference (@c hdr->x_next) to a list of |
13056 | * headers, all the headers in the list are duplicated, too. |
13057 | * |
13058 | * @param home memory home used to allocate new structure |
13059 | * @param hdr header structure to be duplicated |
13060 | * |
13061 | * When duplicating, all parameter lists and non-constant |
13062 | * strings attached to the header are copied, too. The |
13063 | * function uses given memory @a home to allocate all the |
13064 | * memory areas used to copy the header. |
13065 | * |
13066 | * @par Example |
13067 | * @code |
13068 | * |
13069 | * service_route = sip_service_route_dup(home, sip->sip_service_route); |
13070 | * |
13071 | * @endcode |
13072 | * |
13073 | * @return |
13074 | * A pointer to the |
13075 | * newly duplicated #sip_service_route_t header structure, or NULL |
13076 | * upon an error. |
13077 | * |
13078 | */ |
13079 | #if SU_HAVE_INLINE1 |
13080 | su_inlinestatic inline |
13081 | #endif |
13082 | sip_service_route_t *sip_service_route_dup(su_home_t *home, sip_service_route_t const *hdr) |
13083 | __attribute__((__malloc__)); |
13084 | |
13085 | #if SU_HAVE_INLINE1 |
13086 | su_inlinestatic inline |
13087 | sip_service_route_t *sip_service_route_dup(su_home_t *home, sip_service_route_t const *hdr) |
13088 | { |
13089 | return (sip_service_route_t *) |
13090 | msg_header_dup_as(home, sip_service_route_class, (msg_header_t const *)hdr); |
13091 | } |
13092 | #endif |
13093 | |
13094 | /**Copy a list of @ref sip_service_route "Service-Route header" header structures #sip_service_route_t. |
13095 | * |
13096 | * The function sip_service_route_copy() copies a header structure @a |
13097 | * hdr. If the header structure @a hdr contains a reference (@c |
13098 | * hdr->h_next) to a list of headers, all the headers in that |
13099 | * list are copied, too. The function uses given memory @a home |
13100 | * to allocate all the memory areas used to copy the list of header |
13101 | * structure @a hdr. |
13102 | * |
13103 | * @param home memory home used to allocate new structure |
13104 | * @param hdr pointer to the header structure to be copied |
13105 | * |
13106 | * When copying, only the header structure and parameter lists attached to |
13107 | * it are duplicated. The new header structure retains all the references to |
13108 | * the strings within the old @a hdr header, including the encoding of the |
13109 | * old header, if present. |
13110 | * |
13111 | * @par Example |
13112 | * @code |
13113 | * |
13114 | * service_route = sip_service_route_copy(home, sip->sip_service_route); |
13115 | * |
13116 | * @endcode |
13117 | * |
13118 | * @return |
13119 | * A pointer to newly copied header structure, or NULL upon an error. |
13120 | * |
13121 | */ |
13122 | #if SU_HAVE_INLINE1 |
13123 | su_inlinestatic inline |
13124 | #endif |
13125 | sip_service_route_t *sip_service_route_copy(su_home_t *home, sip_service_route_t const *hdr) |
13126 | __attribute__((__malloc__)); |
13127 | |
13128 | #if SU_HAVE_INLINE1 |
13129 | su_inlinestatic inline |
13130 | sip_service_route_t *sip_service_route_copy(su_home_t *home, sip_service_route_t const *hdr) |
13131 | { |
13132 | return (sip_service_route_t *) |
13133 | msg_header_copy_as(home, sip_service_route_class, (msg_header_t const *)hdr); |
13134 | } |
13135 | #endif |
13136 | |
13137 | /**Make a @ref sip_service_route "Service-Route header" structure #sip_service_route_t. |
13138 | * |
13139 | * The function sip_service_route_make() makes a new |
13140 | * #sip_service_route_t header structure. It allocates a new |
13141 | * header structure, and decodes the string @a s as the |
13142 | * value of the structure. |
13143 | * |
13144 | * @param home memory home used to allocate new header structure. |
13145 | * @param s string to be decoded as value of the new header structure |
13146 | * |
13147 | * @return |
13148 | * A pointer to newly maked #sip_service_route_t header structure, or NULL upon an |
13149 | * error. |
13150 | * |
13151 | */ |
13152 | #if SU_HAVE_INLINE1 |
13153 | su_inlinestatic inline |
13154 | #endif |
13155 | sip_service_route_t *sip_service_route_make(su_home_t *home, char const *s) |
13156 | __attribute__((__malloc__)); |
13157 | |
13158 | #if SU_HAVE_INLINE1 |
13159 | su_inlinestatic inline sip_service_route_t *sip_service_route_make(su_home_t *home, char const *s) |
13160 | { |
13161 | return (sip_service_route_t *)sip_header_make(home, sip_service_route_class, s)((sip_header_t *)msg_header_make((home), (sip_service_route_class ), (s))); |
13162 | } |
13163 | #endif |
13164 | |
13165 | /**Make a @ref sip_service_route "Service-Route header" from formatting result. |
13166 | * |
13167 | * Make a new #sip_service_route_t object using formatting result as its value. |
13168 | * The function first prints the arguments according to the format @a fmt |
13169 | * specified. Then it allocates a new header structure, and parses the |
13170 | * formatting result to the structure #sip_service_route_t. |
13171 | * |
13172 | * @param home memory home used to allocate new header structure. |
13173 | * @param fmt string used as a printf()-style format |
13174 | * @param ... argument list for format |
13175 | * |
13176 | * @return |
13177 | * A pointer to newly |
13178 | * makes header structure, or NULL upon an error. |
13179 | * |
13180 | * @HIDE |
13181 | * |
13182 | */ |
13183 | #if SU_HAVE_INLINE1 |
13184 | su_inlinestatic inline |
13185 | #endif |
13186 | sip_service_route_t *sip_service_route_format(su_home_t *home, char const *fmt, ...) |
13187 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
13188 | |
13189 | #if SU_HAVE_INLINE1 |
13190 | su_inlinestatic inline sip_service_route_t *sip_service_route_format(su_home_t *home, char const *fmt, ...) |
13191 | { |
13192 | sip_header_t *h; |
13193 | va_list ap; |
13194 | |
13195 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
13196 | h = sip_header_vformat(home, sip_service_route_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_service_route_class ), (fmt), (ap))); |
13197 | va_end(ap)__builtin_va_end(ap); |
13198 | |
13199 | return (sip_service_route_t *)h; |
13200 | } |
13201 | #endif |
13202 | |
13203 | /** @} */ |
13204 | |
13205 | /**@addtogroup sip_reason |
13206 | * @{ |
13207 | */ |
13208 | |
13209 | /** Parse a SIP @ref sip_reason "Reason header". @internal */ |
13210 | SOFIAPUBFUN issize_t sip_reason_d(su_home_t *, msg_header_t *, |
13211 | char *s, isize_t slen); |
13212 | |
13213 | /** Print a SIP @ref sip_reason "Reason header". @internal */ |
13214 | SOFIAPUBFUN issize_t sip_reason_e(char b[], isize_t bsiz, |
13215 | msg_header_t const *h, int flags); |
13216 | |
13217 | /**Access a SIP @ref sip_reason "Reason header" |
13218 | * structure #sip_reason_t from #sip_t. |
13219 | * |
13220 | */ |
13221 | #define sip_reason(sip)((sip_reason_t *)msg_header_access((msg_pub_t*)(sip), sip_reason_class )) \ |
13222 | ((sip_reason_t *)msg_header_access((msg_pub_t*)(sip), sip_reason_class)) |
13223 | |
13224 | /**Initializer for structure #sip_reason_t. |
13225 | * |
13226 | * A static #sip_reason_t structure for |
13227 | * @ref sip_reason "Reason header" must be initialized with |
13228 | * the SIP_REASON_INIT() macro. |
13229 | * For instance, |
13230 | * @code |
13231 | * |
13232 | * sip_reason_t sip_reason = SIP_REASON_INIT; |
13233 | * |
13234 | * @endcode |
13235 | * @HI |
13236 | * |
13237 | */ |
13238 | #define SIP_REASON_INIT(){{{ 0, 0, sip_reason_class }}} SIP_HDR_INIT(reason){{{ 0, 0, sip_reason_class }}} |
13239 | |
13240 | /**Initialize a structure #sip_reason_t. |
13241 | * |
13242 | * An #sip_reason_t structure for |
13243 | * @ref sip_reason "Reason header" can be initialized with the |
13244 | * sip_reason_init() function/macro. For instance, |
13245 | * @code |
13246 | * |
13247 | * sip_reason_t sip_reason; |
13248 | * |
13249 | * sip_reason_init(&sip_reason); |
13250 | * |
13251 | * @endcode |
13252 | * @HI |
13253 | * |
13254 | */ |
13255 | #if SU_HAVE_INLINE1 |
13256 | su_inlinestatic inline sip_reason_t *sip_reason_init(sip_reason_t x[1]) |
13257 | { |
13258 | return SIP_HEADER_INIT(x, sip_reason_class, sizeof(sip_reason_t))((void)memset((x), 0, (sizeof(sip_reason_t))), (void)(((sip_common_t *)(x))->h_class = (sip_reason_class)), (x)); |
13259 | } |
13260 | #else |
13261 | #define sip_reason_init(x) \ |
13262 | SIP_HEADER_INIT(x, sip_reason_class, sizeof(sip_reason_t))((void)memset((x), 0, (sizeof(sip_reason_t))), (void)(((sip_common_t *)(x))->h_class = (sip_reason_class)), (x)) |
13263 | #endif |
13264 | |
13265 | /**Test if header object is instance of #sip_reason_t. |
13266 | * |
13267 | * Check if the header class is an instance of |
13268 | * @ref sip_reason "Reason header" object and return true (nonzero), |
13269 | * otherwise return false (zero). |
13270 | * |
13271 | * @param header pointer to the header structure to be tested |
13272 | * |
13273 | * @retval 1 (true) if the @a header is an instance of header reason |
13274 | * @retval 0 (false) otherwise |
13275 | * |
13276 | */ |
13277 | #if SU_HAVE_INLINE1 |
13278 | su_inlinestatic inline int sip_is_reason(sip_header_t const *header) |
13279 | { |
13280 | return header && header->sh_classsh_common->h_class->hc_hash == sip_reason_hash; |
13281 | } |
13282 | #else |
13283 | int sip_is_reason(sip_header_t const *header); |
13284 | #endif |
13285 | |
13286 | #define sip_reason_p(h)sip_is_reason((h)) sip_is_reason((h)) |
13287 | |
13288 | |
13289 | /**Duplicate a list of @ref sip_reason "Reason header" header structures #sip_reason_t. |
13290 | * |
13291 | * Duplicate a header |
13292 | * structure @a hdr. If the header structure @a hdr |
13293 | * contains a reference (@c hdr->x_next) to a list of |
13294 | * headers, all the headers in the list are duplicated, too. |
13295 | * |
13296 | * @param home memory home used to allocate new structure |
13297 | * @param hdr header structure to be duplicated |
13298 | * |
13299 | * When duplicating, all parameter lists and non-constant |
13300 | * strings attached to the header are copied, too. The |
13301 | * function uses given memory @a home to allocate all the |
13302 | * memory areas used to copy the header. |
13303 | * |
13304 | * @par Example |
13305 | * @code |
13306 | * |
13307 | * reason = sip_reason_dup(home, sip->sip_reason); |
13308 | * |
13309 | * @endcode |
13310 | * |
13311 | * @return |
13312 | * A pointer to the |
13313 | * newly duplicated #sip_reason_t header structure, or NULL |
13314 | * upon an error. |
13315 | * |
13316 | */ |
13317 | #if SU_HAVE_INLINE1 |
13318 | su_inlinestatic inline |
13319 | #endif |
13320 | sip_reason_t *sip_reason_dup(su_home_t *home, sip_reason_t const *hdr) |
13321 | __attribute__((__malloc__)); |
13322 | |
13323 | #if SU_HAVE_INLINE1 |
13324 | su_inlinestatic inline |
13325 | sip_reason_t *sip_reason_dup(su_home_t *home, sip_reason_t const *hdr) |
13326 | { |
13327 | return (sip_reason_t *) |
13328 | msg_header_dup_as(home, sip_reason_class, (msg_header_t const *)hdr); |
13329 | } |
13330 | #endif |
13331 | |
13332 | /**Copy a list of @ref sip_reason "Reason header" header structures #sip_reason_t. |
13333 | * |
13334 | * The function sip_reason_copy() copies a header structure @a |
13335 | * hdr. If the header structure @a hdr contains a reference (@c |
13336 | * hdr->h_next) to a list of headers, all the headers in that |
13337 | * list are copied, too. The function uses given memory @a home |
13338 | * to allocate all the memory areas used to copy the list of header |
13339 | * structure @a hdr. |
13340 | * |
13341 | * @param home memory home used to allocate new structure |
13342 | * @param hdr pointer to the header structure to be copied |
13343 | * |
13344 | * When copying, only the header structure and parameter lists attached to |
13345 | * it are duplicated. The new header structure retains all the references to |
13346 | * the strings within the old @a hdr header, including the encoding of the |
13347 | * old header, if present. |
13348 | * |
13349 | * @par Example |
13350 | * @code |
13351 | * |
13352 | * reason = sip_reason_copy(home, sip->sip_reason); |
13353 | * |
13354 | * @endcode |
13355 | * |
13356 | * @return |
13357 | * A pointer to newly copied header structure, or NULL upon an error. |
13358 | * |
13359 | */ |
13360 | #if SU_HAVE_INLINE1 |
13361 | su_inlinestatic inline |
13362 | #endif |
13363 | sip_reason_t *sip_reason_copy(su_home_t *home, sip_reason_t const *hdr) |
13364 | __attribute__((__malloc__)); |
13365 | |
13366 | #if SU_HAVE_INLINE1 |
13367 | su_inlinestatic inline |
13368 | sip_reason_t *sip_reason_copy(su_home_t *home, sip_reason_t const *hdr) |
13369 | { |
13370 | return (sip_reason_t *) |
13371 | msg_header_copy_as(home, sip_reason_class, (msg_header_t const *)hdr); |
13372 | } |
13373 | #endif |
13374 | |
13375 | /**Make a @ref sip_reason "Reason header" structure #sip_reason_t. |
13376 | * |
13377 | * The function sip_reason_make() makes a new |
13378 | * #sip_reason_t header structure. It allocates a new |
13379 | * header structure, and decodes the string @a s as the |
13380 | * value of the structure. |
13381 | * |
13382 | * @param home memory home used to allocate new header structure. |
13383 | * @param s string to be decoded as value of the new header structure |
13384 | * |
13385 | * @return |
13386 | * A pointer to newly maked #sip_reason_t header structure, or NULL upon an |
13387 | * error. |
13388 | * |
13389 | */ |
13390 | #if SU_HAVE_INLINE1 |
13391 | su_inlinestatic inline |
13392 | #endif |
13393 | sip_reason_t *sip_reason_make(su_home_t *home, char const *s) |
13394 | __attribute__((__malloc__)); |
13395 | |
13396 | #if SU_HAVE_INLINE1 |
13397 | su_inlinestatic inline sip_reason_t *sip_reason_make(su_home_t *home, char const *s) |
13398 | { |
13399 | return (sip_reason_t *)sip_header_make(home, sip_reason_class, s)((sip_header_t *)msg_header_make((home), (sip_reason_class), ( s))); |
13400 | } |
13401 | #endif |
13402 | |
13403 | /**Make a @ref sip_reason "Reason header" from formatting result. |
13404 | * |
13405 | * Make a new #sip_reason_t object using formatting result as its value. |
13406 | * The function first prints the arguments according to the format @a fmt |
13407 | * specified. Then it allocates a new header structure, and parses the |
13408 | * formatting result to the structure #sip_reason_t. |
13409 | * |
13410 | * @param home memory home used to allocate new header structure. |
13411 | * @param fmt string used as a printf()-style format |
13412 | * @param ... argument list for format |
13413 | * |
13414 | * @return |
13415 | * A pointer to newly |
13416 | * makes header structure, or NULL upon an error. |
13417 | * |
13418 | * @HIDE |
13419 | * |
13420 | */ |
13421 | #if SU_HAVE_INLINE1 |
13422 | su_inlinestatic inline |
13423 | #endif |
13424 | sip_reason_t *sip_reason_format(su_home_t *home, char const *fmt, ...) |
13425 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
13426 | |
13427 | #if SU_HAVE_INLINE1 |
13428 | su_inlinestatic inline sip_reason_t *sip_reason_format(su_home_t *home, char const *fmt, ...) |
13429 | { |
13430 | sip_header_t *h; |
13431 | va_list ap; |
13432 | |
13433 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
13434 | h = sip_header_vformat(home, sip_reason_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_reason_class ), (fmt), (ap))); |
13435 | va_end(ap)__builtin_va_end(ap); |
13436 | |
13437 | return (sip_reason_t *)h; |
13438 | } |
13439 | #endif |
13440 | |
13441 | /** @} */ |
13442 | |
13443 | /**@addtogroup sip_security_client |
13444 | * @{ |
13445 | */ |
13446 | |
13447 | /** Parse a SIP @ref sip_security_client "Security-Client header". @internal */ |
13448 | SOFIAPUBFUN issize_t sip_security_client_d(su_home_t *, msg_header_t *, |
13449 | char *s, isize_t slen); |
13450 | |
13451 | /** Print a SIP @ref sip_security_client "Security-Client header". @internal */ |
13452 | SOFIAPUBFUN issize_t sip_security_client_e(char b[], isize_t bsiz, |
13453 | msg_header_t const *h, int flags); |
13454 | |
13455 | /**Access a SIP @ref sip_security_client "Security-Client header" |
13456 | * structure #sip_security_client_t from #sip_t. |
13457 | * |
13458 | */ |
13459 | #define sip_security_client(sip)((sip_security_client_t *)msg_header_access((msg_pub_t*)(sip) , sip_security_client_class)) \ |
13460 | ((sip_security_client_t *)msg_header_access((msg_pub_t*)(sip), sip_security_client_class)) |
13461 | |
13462 | /**Initializer for structure #sip_security_client_t. |
13463 | * |
13464 | * A static #sip_security_client_t structure for |
13465 | * @ref sip_security_client "Security-Client header" must be initialized with |
13466 | * the SIP_SECURITY_CLIENT_INIT() macro. |
13467 | * For instance, |
13468 | * @code |
13469 | * |
13470 | * sip_security_client_t sip_security_client = SIP_SECURITY_CLIENT_INIT; |
13471 | * |
13472 | * @endcode |
13473 | * @HI |
13474 | * |
13475 | */ |
13476 | #define SIP_SECURITY_CLIENT_INIT(){{{ 0, 0, sip_security_client_class }}} SIP_HDR_INIT(security_client){{{ 0, 0, sip_security_client_class }}} |
13477 | |
13478 | /**Initialize a structure #sip_security_client_t. |
13479 | * |
13480 | * An #sip_security_client_t structure for |
13481 | * @ref sip_security_client "Security-Client header" can be initialized with the |
13482 | * sip_security_client_init() function/macro. For instance, |
13483 | * @code |
13484 | * |
13485 | * sip_security_client_t sip_security_client; |
13486 | * |
13487 | * sip_security_client_init(&sip_security_client); |
13488 | * |
13489 | * @endcode |
13490 | * @HI |
13491 | * |
13492 | */ |
13493 | #if SU_HAVE_INLINE1 |
13494 | su_inlinestatic inline sip_security_client_t *sip_security_client_init(sip_security_client_t x[1]) |
13495 | { |
13496 | return SIP_HEADER_INIT(x, sip_security_client_class, sizeof(sip_security_client_t))((void)memset((x), 0, (sizeof(sip_security_client_t))), (void )(((sip_common_t *)(x))->h_class = (sip_security_client_class )), (x)); |
13497 | } |
13498 | #else |
13499 | #define sip_security_client_init(x) \ |
13500 | SIP_HEADER_INIT(x, sip_security_client_class, sizeof(sip_security_client_t))((void)memset((x), 0, (sizeof(sip_security_client_t))), (void )(((sip_common_t *)(x))->h_class = (sip_security_client_class )), (x)) |
13501 | #endif |
13502 | |
13503 | /**Test if header object is instance of #sip_security_client_t. |
13504 | * |
13505 | * Check if the header class is an instance of |
13506 | * @ref sip_security_client "Security-Client header" object and return true (nonzero), |
13507 | * otherwise return false (zero). |
13508 | * |
13509 | * @param header pointer to the header structure to be tested |
13510 | * |
13511 | * @retval 1 (true) if the @a header is an instance of header security_client |
13512 | * @retval 0 (false) otherwise |
13513 | * |
13514 | */ |
13515 | #if SU_HAVE_INLINE1 |
13516 | su_inlinestatic inline int sip_is_security_client(sip_header_t const *header) |
13517 | { |
13518 | return header && header->sh_classsh_common->h_class->hc_hash == sip_security_client_hash; |
13519 | } |
13520 | #else |
13521 | int sip_is_security_client(sip_header_t const *header); |
13522 | #endif |
13523 | |
13524 | #define sip_security_client_p(h)sip_is_security_client((h)) sip_is_security_client((h)) |
13525 | |
13526 | |
13527 | /**Duplicate a list of @ref sip_security_client "Security-Client header" header structures #sip_security_client_t. |
13528 | * |
13529 | * Duplicate a header |
13530 | * structure @a hdr. If the header structure @a hdr |
13531 | * contains a reference (@c hdr->x_next) to a list of |
13532 | * headers, all the headers in the list are duplicated, too. |
13533 | * |
13534 | * @param home memory home used to allocate new structure |
13535 | * @param hdr header structure to be duplicated |
13536 | * |
13537 | * When duplicating, all parameter lists and non-constant |
13538 | * strings attached to the header are copied, too. The |
13539 | * function uses given memory @a home to allocate all the |
13540 | * memory areas used to copy the header. |
13541 | * |
13542 | * @par Example |
13543 | * @code |
13544 | * |
13545 | * security_client = sip_security_client_dup(home, sip->sip_security_client); |
13546 | * |
13547 | * @endcode |
13548 | * |
13549 | * @return |
13550 | * A pointer to the |
13551 | * newly duplicated #sip_security_client_t header structure, or NULL |
13552 | * upon an error. |
13553 | * |
13554 | */ |
13555 | #if SU_HAVE_INLINE1 |
13556 | su_inlinestatic inline |
13557 | #endif |
13558 | sip_security_client_t *sip_security_client_dup(su_home_t *home, sip_security_client_t const *hdr) |
13559 | __attribute__((__malloc__)); |
13560 | |
13561 | #if SU_HAVE_INLINE1 |
13562 | su_inlinestatic inline |
13563 | sip_security_client_t *sip_security_client_dup(su_home_t *home, sip_security_client_t const *hdr) |
13564 | { |
13565 | return (sip_security_client_t *) |
13566 | msg_header_dup_as(home, sip_security_client_class, (msg_header_t const *)hdr); |
13567 | } |
13568 | #endif |
13569 | |
13570 | /**Copy a list of @ref sip_security_client "Security-Client header" header structures #sip_security_client_t. |
13571 | * |
13572 | * The function sip_security_client_copy() copies a header structure @a |
13573 | * hdr. If the header structure @a hdr contains a reference (@c |
13574 | * hdr->h_next) to a list of headers, all the headers in that |
13575 | * list are copied, too. The function uses given memory @a home |
13576 | * to allocate all the memory areas used to copy the list of header |
13577 | * structure @a hdr. |
13578 | * |
13579 | * @param home memory home used to allocate new structure |
13580 | * @param hdr pointer to the header structure to be copied |
13581 | * |
13582 | * When copying, only the header structure and parameter lists attached to |
13583 | * it are duplicated. The new header structure retains all the references to |
13584 | * the strings within the old @a hdr header, including the encoding of the |
13585 | * old header, if present. |
13586 | * |
13587 | * @par Example |
13588 | * @code |
13589 | * |
13590 | * security_client = sip_security_client_copy(home, sip->sip_security_client); |
13591 | * |
13592 | * @endcode |
13593 | * |
13594 | * @return |
13595 | * A pointer to newly copied header structure, or NULL upon an error. |
13596 | * |
13597 | */ |
13598 | #if SU_HAVE_INLINE1 |
13599 | su_inlinestatic inline |
13600 | #endif |
13601 | sip_security_client_t *sip_security_client_copy(su_home_t *home, sip_security_client_t const *hdr) |
13602 | __attribute__((__malloc__)); |
13603 | |
13604 | #if SU_HAVE_INLINE1 |
13605 | su_inlinestatic inline |
13606 | sip_security_client_t *sip_security_client_copy(su_home_t *home, sip_security_client_t const *hdr) |
13607 | { |
13608 | return (sip_security_client_t *) |
13609 | msg_header_copy_as(home, sip_security_client_class, (msg_header_t const *)hdr); |
13610 | } |
13611 | #endif |
13612 | |
13613 | /**Make a @ref sip_security_client "Security-Client header" structure #sip_security_client_t. |
13614 | * |
13615 | * The function sip_security_client_make() makes a new |
13616 | * #sip_security_client_t header structure. It allocates a new |
13617 | * header structure, and decodes the string @a s as the |
13618 | * value of the structure. |
13619 | * |
13620 | * @param home memory home used to allocate new header structure. |
13621 | * @param s string to be decoded as value of the new header structure |
13622 | * |
13623 | * @return |
13624 | * A pointer to newly maked #sip_security_client_t header structure, or NULL upon an |
13625 | * error. |
13626 | * |
13627 | */ |
13628 | #if SU_HAVE_INLINE1 |
13629 | su_inlinestatic inline |
13630 | #endif |
13631 | sip_security_client_t *sip_security_client_make(su_home_t *home, char const *s) |
13632 | __attribute__((__malloc__)); |
13633 | |
13634 | #if SU_HAVE_INLINE1 |
13635 | su_inlinestatic inline sip_security_client_t *sip_security_client_make(su_home_t *home, char const *s) |
13636 | { |
13637 | return (sip_security_client_t *)sip_header_make(home, sip_security_client_class, s)((sip_header_t *)msg_header_make((home), (sip_security_client_class ), (s))); |
13638 | } |
13639 | #endif |
13640 | |
13641 | /**Make a @ref sip_security_client "Security-Client header" from formatting result. |
13642 | * |
13643 | * Make a new #sip_security_client_t object using formatting result as its value. |
13644 | * The function first prints the arguments according to the format @a fmt |
13645 | * specified. Then it allocates a new header structure, and parses the |
13646 | * formatting result to the structure #sip_security_client_t. |
13647 | * |
13648 | * @param home memory home used to allocate new header structure. |
13649 | * @param fmt string used as a printf()-style format |
13650 | * @param ... argument list for format |
13651 | * |
13652 | * @return |
13653 | * A pointer to newly |
13654 | * makes header structure, or NULL upon an error. |
13655 | * |
13656 | * @HIDE |
13657 | * |
13658 | */ |
13659 | #if SU_HAVE_INLINE1 |
13660 | su_inlinestatic inline |
13661 | #endif |
13662 | sip_security_client_t *sip_security_client_format(su_home_t *home, char const *fmt, ...) |
13663 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
13664 | |
13665 | #if SU_HAVE_INLINE1 |
13666 | su_inlinestatic inline sip_security_client_t *sip_security_client_format(su_home_t *home, char const *fmt, ...) |
13667 | { |
13668 | sip_header_t *h; |
13669 | va_list ap; |
13670 | |
13671 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
13672 | h = sip_header_vformat(home, sip_security_client_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_security_client_class ), (fmt), (ap))); |
13673 | va_end(ap)__builtin_va_end(ap); |
13674 | |
13675 | return (sip_security_client_t *)h; |
13676 | } |
13677 | #endif |
13678 | |
13679 | /** @} */ |
13680 | |
13681 | /**@addtogroup sip_security_server |
13682 | * @{ |
13683 | */ |
13684 | |
13685 | /** Parse a SIP @ref sip_security_server "Security-Server header". @internal */ |
13686 | SOFIAPUBFUN issize_t sip_security_server_d(su_home_t *, msg_header_t *, |
13687 | char *s, isize_t slen); |
13688 | |
13689 | /** Print a SIP @ref sip_security_server "Security-Server header". @internal */ |
13690 | SOFIAPUBFUN issize_t sip_security_server_e(char b[], isize_t bsiz, |
13691 | msg_header_t const *h, int flags); |
13692 | |
13693 | /**Access a SIP @ref sip_security_server "Security-Server header" |
13694 | * structure #sip_security_server_t from #sip_t. |
13695 | * |
13696 | */ |
13697 | #define sip_security_server(sip)((sip_security_server_t *)msg_header_access((msg_pub_t*)(sip) , sip_security_server_class)) \ |
13698 | ((sip_security_server_t *)msg_header_access((msg_pub_t*)(sip), sip_security_server_class)) |
13699 | |
13700 | /**Initializer for structure #sip_security_server_t. |
13701 | * |
13702 | * A static #sip_security_server_t structure for |
13703 | * @ref sip_security_server "Security-Server header" must be initialized with |
13704 | * the SIP_SECURITY_SERVER_INIT() macro. |
13705 | * For instance, |
13706 | * @code |
13707 | * |
13708 | * sip_security_server_t sip_security_server = SIP_SECURITY_SERVER_INIT; |
13709 | * |
13710 | * @endcode |
13711 | * @HI |
13712 | * |
13713 | */ |
13714 | #define SIP_SECURITY_SERVER_INIT(){{{ 0, 0, sip_security_server_class }}} SIP_HDR_INIT(security_server){{{ 0, 0, sip_security_server_class }}} |
13715 | |
13716 | /**Initialize a structure #sip_security_server_t. |
13717 | * |
13718 | * An #sip_security_server_t structure for |
13719 | * @ref sip_security_server "Security-Server header" can be initialized with the |
13720 | * sip_security_server_init() function/macro. For instance, |
13721 | * @code |
13722 | * |
13723 | * sip_security_server_t sip_security_server; |
13724 | * |
13725 | * sip_security_server_init(&sip_security_server); |
13726 | * |
13727 | * @endcode |
13728 | * @HI |
13729 | * |
13730 | */ |
13731 | #if SU_HAVE_INLINE1 |
13732 | su_inlinestatic inline sip_security_server_t *sip_security_server_init(sip_security_server_t x[1]) |
13733 | { |
13734 | return SIP_HEADER_INIT(x, sip_security_server_class, sizeof(sip_security_server_t))((void)memset((x), 0, (sizeof(sip_security_server_t))), (void )(((sip_common_t *)(x))->h_class = (sip_security_server_class )), (x)); |
13735 | } |
13736 | #else |
13737 | #define sip_security_server_init(x) \ |
13738 | SIP_HEADER_INIT(x, sip_security_server_class, sizeof(sip_security_server_t))((void)memset((x), 0, (sizeof(sip_security_server_t))), (void )(((sip_common_t *)(x))->h_class = (sip_security_server_class )), (x)) |
13739 | #endif |
13740 | |
13741 | /**Test if header object is instance of #sip_security_server_t. |
13742 | * |
13743 | * Check if the header class is an instance of |
13744 | * @ref sip_security_server "Security-Server header" object and return true (nonzero), |
13745 | * otherwise return false (zero). |
13746 | * |
13747 | * @param header pointer to the header structure to be tested |
13748 | * |
13749 | * @retval 1 (true) if the @a header is an instance of header security_server |
13750 | * @retval 0 (false) otherwise |
13751 | * |
13752 | */ |
13753 | #if SU_HAVE_INLINE1 |
13754 | su_inlinestatic inline int sip_is_security_server(sip_header_t const *header) |
13755 | { |
13756 | return header && header->sh_classsh_common->h_class->hc_hash == sip_security_server_hash; |
13757 | } |
13758 | #else |
13759 | int sip_is_security_server(sip_header_t const *header); |
13760 | #endif |
13761 | |
13762 | #define sip_security_server_p(h)sip_is_security_server((h)) sip_is_security_server((h)) |
13763 | |
13764 | |
13765 | /**Duplicate a list of @ref sip_security_server "Security-Server header" header structures #sip_security_server_t. |
13766 | * |
13767 | * Duplicate a header |
13768 | * structure @a hdr. If the header structure @a hdr |
13769 | * contains a reference (@c hdr->x_next) to a list of |
13770 | * headers, all the headers in the list are duplicated, too. |
13771 | * |
13772 | * @param home memory home used to allocate new structure |
13773 | * @param hdr header structure to be duplicated |
13774 | * |
13775 | * When duplicating, all parameter lists and non-constant |
13776 | * strings attached to the header are copied, too. The |
13777 | * function uses given memory @a home to allocate all the |
13778 | * memory areas used to copy the header. |
13779 | * |
13780 | * @par Example |
13781 | * @code |
13782 | * |
13783 | * security_server = sip_security_server_dup(home, sip->sip_security_server); |
13784 | * |
13785 | * @endcode |
13786 | * |
13787 | * @return |
13788 | * A pointer to the |
13789 | * newly duplicated #sip_security_server_t header structure, or NULL |
13790 | * upon an error. |
13791 | * |
13792 | */ |
13793 | #if SU_HAVE_INLINE1 |
13794 | su_inlinestatic inline |
13795 | #endif |
13796 | sip_security_server_t *sip_security_server_dup(su_home_t *home, sip_security_server_t const *hdr) |
13797 | __attribute__((__malloc__)); |
13798 | |
13799 | #if SU_HAVE_INLINE1 |
13800 | su_inlinestatic inline |
13801 | sip_security_server_t *sip_security_server_dup(su_home_t *home, sip_security_server_t const *hdr) |
13802 | { |
13803 | return (sip_security_server_t *) |
13804 | msg_header_dup_as(home, sip_security_server_class, (msg_header_t const *)hdr); |
13805 | } |
13806 | #endif |
13807 | |
13808 | /**Copy a list of @ref sip_security_server "Security-Server header" header structures #sip_security_server_t. |
13809 | * |
13810 | * The function sip_security_server_copy() copies a header structure @a |
13811 | * hdr. If the header structure @a hdr contains a reference (@c |
13812 | * hdr->h_next) to a list of headers, all the headers in that |
13813 | * list are copied, too. The function uses given memory @a home |
13814 | * to allocate all the memory areas used to copy the list of header |
13815 | * structure @a hdr. |
13816 | * |
13817 | * @param home memory home used to allocate new structure |
13818 | * @param hdr pointer to the header structure to be copied |
13819 | * |
13820 | * When copying, only the header structure and parameter lists attached to |
13821 | * it are duplicated. The new header structure retains all the references to |
13822 | * the strings within the old @a hdr header, including the encoding of the |
13823 | * old header, if present. |
13824 | * |
13825 | * @par Example |
13826 | * @code |
13827 | * |
13828 | * security_server = sip_security_server_copy(home, sip->sip_security_server); |
13829 | * |
13830 | * @endcode |
13831 | * |
13832 | * @return |
13833 | * A pointer to newly copied header structure, or NULL upon an error. |
13834 | * |
13835 | */ |
13836 | #if SU_HAVE_INLINE1 |
13837 | su_inlinestatic inline |
13838 | #endif |
13839 | sip_security_server_t *sip_security_server_copy(su_home_t *home, sip_security_server_t const *hdr) |
13840 | __attribute__((__malloc__)); |
13841 | |
13842 | #if SU_HAVE_INLINE1 |
13843 | su_inlinestatic inline |
13844 | sip_security_server_t *sip_security_server_copy(su_home_t *home, sip_security_server_t const *hdr) |
13845 | { |
13846 | return (sip_security_server_t *) |
13847 | msg_header_copy_as(home, sip_security_server_class, (msg_header_t const *)hdr); |
13848 | } |
13849 | #endif |
13850 | |
13851 | /**Make a @ref sip_security_server "Security-Server header" structure #sip_security_server_t. |
13852 | * |
13853 | * The function sip_security_server_make() makes a new |
13854 | * #sip_security_server_t header structure. It allocates a new |
13855 | * header structure, and decodes the string @a s as the |
13856 | * value of the structure. |
13857 | * |
13858 | * @param home memory home used to allocate new header structure. |
13859 | * @param s string to be decoded as value of the new header structure |
13860 | * |
13861 | * @return |
13862 | * A pointer to newly maked #sip_security_server_t header structure, or NULL upon an |
13863 | * error. |
13864 | * |
13865 | */ |
13866 | #if SU_HAVE_INLINE1 |
13867 | su_inlinestatic inline |
13868 | #endif |
13869 | sip_security_server_t *sip_security_server_make(su_home_t *home, char const *s) |
13870 | __attribute__((__malloc__)); |
13871 | |
13872 | #if SU_HAVE_INLINE1 |
13873 | su_inlinestatic inline sip_security_server_t *sip_security_server_make(su_home_t *home, char const *s) |
13874 | { |
13875 | return (sip_security_server_t *)sip_header_make(home, sip_security_server_class, s)((sip_header_t *)msg_header_make((home), (sip_security_server_class ), (s))); |
13876 | } |
13877 | #endif |
13878 | |
13879 | /**Make a @ref sip_security_server "Security-Server header" from formatting result. |
13880 | * |
13881 | * Make a new #sip_security_server_t object using formatting result as its value. |
13882 | * The function first prints the arguments according to the format @a fmt |
13883 | * specified. Then it allocates a new header structure, and parses the |
13884 | * formatting result to the structure #sip_security_server_t. |
13885 | * |
13886 | * @param home memory home used to allocate new header structure. |
13887 | * @param fmt string used as a printf()-style format |
13888 | * @param ... argument list for format |
13889 | * |
13890 | * @return |
13891 | * A pointer to newly |
13892 | * makes header structure, or NULL upon an error. |
13893 | * |
13894 | * @HIDE |
13895 | * |
13896 | */ |
13897 | #if SU_HAVE_INLINE1 |
13898 | su_inlinestatic inline |
13899 | #endif |
13900 | sip_security_server_t *sip_security_server_format(su_home_t *home, char const *fmt, ...) |
13901 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
13902 | |
13903 | #if SU_HAVE_INLINE1 |
13904 | su_inlinestatic inline sip_security_server_t *sip_security_server_format(su_home_t *home, char const *fmt, ...) |
13905 | { |
13906 | sip_header_t *h; |
13907 | va_list ap; |
13908 | |
13909 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
13910 | h = sip_header_vformat(home, sip_security_server_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_security_server_class ), (fmt), (ap))); |
13911 | va_end(ap)__builtin_va_end(ap); |
13912 | |
13913 | return (sip_security_server_t *)h; |
13914 | } |
13915 | #endif |
13916 | |
13917 | /** @} */ |
13918 | |
13919 | /**@addtogroup sip_security_verify |
13920 | * @{ |
13921 | */ |
13922 | |
13923 | /** Parse a SIP @ref sip_security_verify "Security-Verify header". @internal */ |
13924 | SOFIAPUBFUN issize_t sip_security_verify_d(su_home_t *, msg_header_t *, |
13925 | char *s, isize_t slen); |
13926 | |
13927 | /** Print a SIP @ref sip_security_verify "Security-Verify header". @internal */ |
13928 | SOFIAPUBFUN issize_t sip_security_verify_e(char b[], isize_t bsiz, |
13929 | msg_header_t const *h, int flags); |
13930 | |
13931 | /**Access a SIP @ref sip_security_verify "Security-Verify header" |
13932 | * structure #sip_security_verify_t from #sip_t. |
13933 | * |
13934 | */ |
13935 | #define sip_security_verify(sip)((sip_security_verify_t *)msg_header_access((msg_pub_t*)(sip) , sip_security_verify_class)) \ |
13936 | ((sip_security_verify_t *)msg_header_access((msg_pub_t*)(sip), sip_security_verify_class)) |
13937 | |
13938 | /**Initializer for structure #sip_security_verify_t. |
13939 | * |
13940 | * A static #sip_security_verify_t structure for |
13941 | * @ref sip_security_verify "Security-Verify header" must be initialized with |
13942 | * the SIP_SECURITY_VERIFY_INIT() macro. |
13943 | * For instance, |
13944 | * @code |
13945 | * |
13946 | * sip_security_verify_t sip_security_verify = SIP_SECURITY_VERIFY_INIT; |
13947 | * |
13948 | * @endcode |
13949 | * @HI |
13950 | * |
13951 | */ |
13952 | #define SIP_SECURITY_VERIFY_INIT(){{{ 0, 0, sip_security_verify_class }}} SIP_HDR_INIT(security_verify){{{ 0, 0, sip_security_verify_class }}} |
13953 | |
13954 | /**Initialize a structure #sip_security_verify_t. |
13955 | * |
13956 | * An #sip_security_verify_t structure for |
13957 | * @ref sip_security_verify "Security-Verify header" can be initialized with the |
13958 | * sip_security_verify_init() function/macro. For instance, |
13959 | * @code |
13960 | * |
13961 | * sip_security_verify_t sip_security_verify; |
13962 | * |
13963 | * sip_security_verify_init(&sip_security_verify); |
13964 | * |
13965 | * @endcode |
13966 | * @HI |
13967 | * |
13968 | */ |
13969 | #if SU_HAVE_INLINE1 |
13970 | su_inlinestatic inline sip_security_verify_t *sip_security_verify_init(sip_security_verify_t x[1]) |
13971 | { |
13972 | return SIP_HEADER_INIT(x, sip_security_verify_class, sizeof(sip_security_verify_t))((void)memset((x), 0, (sizeof(sip_security_verify_t))), (void )(((sip_common_t *)(x))->h_class = (sip_security_verify_class )), (x)); |
13973 | } |
13974 | #else |
13975 | #define sip_security_verify_init(x) \ |
13976 | SIP_HEADER_INIT(x, sip_security_verify_class, sizeof(sip_security_verify_t))((void)memset((x), 0, (sizeof(sip_security_verify_t))), (void )(((sip_common_t *)(x))->h_class = (sip_security_verify_class )), (x)) |
13977 | #endif |
13978 | |
13979 | /**Test if header object is instance of #sip_security_verify_t. |
13980 | * |
13981 | * Check if the header class is an instance of |
13982 | * @ref sip_security_verify "Security-Verify header" object and return true (nonzero), |
13983 | * otherwise return false (zero). |
13984 | * |
13985 | * @param header pointer to the header structure to be tested |
13986 | * |
13987 | * @retval 1 (true) if the @a header is an instance of header security_verify |
13988 | * @retval 0 (false) otherwise |
13989 | * |
13990 | */ |
13991 | #if SU_HAVE_INLINE1 |
13992 | su_inlinestatic inline int sip_is_security_verify(sip_header_t const *header) |
13993 | { |
13994 | return header && header->sh_classsh_common->h_class->hc_hash == sip_security_verify_hash; |
13995 | } |
13996 | #else |
13997 | int sip_is_security_verify(sip_header_t const *header); |
13998 | #endif |
13999 | |
14000 | #define sip_security_verify_p(h)sip_is_security_verify((h)) sip_is_security_verify((h)) |
14001 | |
14002 | |
14003 | /**Duplicate a list of @ref sip_security_verify "Security-Verify header" header structures #sip_security_verify_t. |
14004 | * |
14005 | * Duplicate a header |
14006 | * structure @a hdr. If the header structure @a hdr |
14007 | * contains a reference (@c hdr->x_next) to a list of |
14008 | * headers, all the headers in the list are duplicated, too. |
14009 | * |
14010 | * @param home memory home used to allocate new structure |
14011 | * @param hdr header structure to be duplicated |
14012 | * |
14013 | * When duplicating, all parameter lists and non-constant |
14014 | * strings attached to the header are copied, too. The |
14015 | * function uses given memory @a home to allocate all the |
14016 | * memory areas used to copy the header. |
14017 | * |
14018 | * @par Example |
14019 | * @code |
14020 | * |
14021 | * security_verify = sip_security_verify_dup(home, sip->sip_security_verify); |
14022 | * |
14023 | * @endcode |
14024 | * |
14025 | * @return |
14026 | * A pointer to the |
14027 | * newly duplicated #sip_security_verify_t header structure, or NULL |
14028 | * upon an error. |
14029 | * |
14030 | */ |
14031 | #if SU_HAVE_INLINE1 |
14032 | su_inlinestatic inline |
14033 | #endif |
14034 | sip_security_verify_t *sip_security_verify_dup(su_home_t *home, sip_security_verify_t const *hdr) |
14035 | __attribute__((__malloc__)); |
14036 | |
14037 | #if SU_HAVE_INLINE1 |
14038 | su_inlinestatic inline |
14039 | sip_security_verify_t *sip_security_verify_dup(su_home_t *home, sip_security_verify_t const *hdr) |
14040 | { |
14041 | return (sip_security_verify_t *) |
14042 | msg_header_dup_as(home, sip_security_verify_class, (msg_header_t const *)hdr); |
14043 | } |
14044 | #endif |
14045 | |
14046 | /**Copy a list of @ref sip_security_verify "Security-Verify header" header structures #sip_security_verify_t. |
14047 | * |
14048 | * The function sip_security_verify_copy() copies a header structure @a |
14049 | * hdr. If the header structure @a hdr contains a reference (@c |
14050 | * hdr->h_next) to a list of headers, all the headers in that |
14051 | * list are copied, too. The function uses given memory @a home |
14052 | * to allocate all the memory areas used to copy the list of header |
14053 | * structure @a hdr. |
14054 | * |
14055 | * @param home memory home used to allocate new structure |
14056 | * @param hdr pointer to the header structure to be copied |
14057 | * |
14058 | * When copying, only the header structure and parameter lists attached to |
14059 | * it are duplicated. The new header structure retains all the references to |
14060 | * the strings within the old @a hdr header, including the encoding of the |
14061 | * old header, if present. |
14062 | * |
14063 | * @par Example |
14064 | * @code |
14065 | * |
14066 | * security_verify = sip_security_verify_copy(home, sip->sip_security_verify); |
14067 | * |
14068 | * @endcode |
14069 | * |
14070 | * @return |
14071 | * A pointer to newly copied header structure, or NULL upon an error. |
14072 | * |
14073 | */ |
14074 | #if SU_HAVE_INLINE1 |
14075 | su_inlinestatic inline |
14076 | #endif |
14077 | sip_security_verify_t *sip_security_verify_copy(su_home_t *home, sip_security_verify_t const *hdr) |
14078 | __attribute__((__malloc__)); |
14079 | |
14080 | #if SU_HAVE_INLINE1 |
14081 | su_inlinestatic inline |
14082 | sip_security_verify_t *sip_security_verify_copy(su_home_t *home, sip_security_verify_t const *hdr) |
14083 | { |
14084 | return (sip_security_verify_t *) |
14085 | msg_header_copy_as(home, sip_security_verify_class, (msg_header_t const *)hdr); |
14086 | } |
14087 | #endif |
14088 | |
14089 | /**Make a @ref sip_security_verify "Security-Verify header" structure #sip_security_verify_t. |
14090 | * |
14091 | * The function sip_security_verify_make() makes a new |
14092 | * #sip_security_verify_t header structure. It allocates a new |
14093 | * header structure, and decodes the string @a s as the |
14094 | * value of the structure. |
14095 | * |
14096 | * @param home memory home used to allocate new header structure. |
14097 | * @param s string to be decoded as value of the new header structure |
14098 | * |
14099 | * @return |
14100 | * A pointer to newly maked #sip_security_verify_t header structure, or NULL upon an |
14101 | * error. |
14102 | * |
14103 | */ |
14104 | #if SU_HAVE_INLINE1 |
14105 | su_inlinestatic inline |
14106 | #endif |
14107 | sip_security_verify_t *sip_security_verify_make(su_home_t *home, char const *s) |
14108 | __attribute__((__malloc__)); |
14109 | |
14110 | #if SU_HAVE_INLINE1 |
14111 | su_inlinestatic inline sip_security_verify_t *sip_security_verify_make(su_home_t *home, char const *s) |
14112 | { |
14113 | return (sip_security_verify_t *)sip_header_make(home, sip_security_verify_class, s)((sip_header_t *)msg_header_make((home), (sip_security_verify_class ), (s))); |
14114 | } |
14115 | #endif |
14116 | |
14117 | /**Make a @ref sip_security_verify "Security-Verify header" from formatting result. |
14118 | * |
14119 | * Make a new #sip_security_verify_t object using formatting result as its value. |
14120 | * The function first prints the arguments according to the format @a fmt |
14121 | * specified. Then it allocates a new header structure, and parses the |
14122 | * formatting result to the structure #sip_security_verify_t. |
14123 | * |
14124 | * @param home memory home used to allocate new header structure. |
14125 | * @param fmt string used as a printf()-style format |
14126 | * @param ... argument list for format |
14127 | * |
14128 | * @return |
14129 | * A pointer to newly |
14130 | * makes header structure, or NULL upon an error. |
14131 | * |
14132 | * @HIDE |
14133 | * |
14134 | */ |
14135 | #if SU_HAVE_INLINE1 |
14136 | su_inlinestatic inline |
14137 | #endif |
14138 | sip_security_verify_t *sip_security_verify_format(su_home_t *home, char const *fmt, ...) |
14139 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
14140 | |
14141 | #if SU_HAVE_INLINE1 |
14142 | su_inlinestatic inline sip_security_verify_t *sip_security_verify_format(su_home_t *home, char const *fmt, ...) |
14143 | { |
14144 | sip_header_t *h; |
14145 | va_list ap; |
14146 | |
14147 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
14148 | h = sip_header_vformat(home, sip_security_verify_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_security_verify_class ), (fmt), (ap))); |
14149 | va_end(ap)__builtin_va_end(ap); |
14150 | |
14151 | return (sip_security_verify_t *)h; |
14152 | } |
14153 | #endif |
14154 | |
14155 | /** @} */ |
14156 | |
14157 | /**@addtogroup sip_privacy |
14158 | * @{ |
14159 | */ |
14160 | |
14161 | /** Parse a SIP @ref sip_privacy "Privacy header". @internal */ |
14162 | SOFIAPUBFUN issize_t sip_privacy_d(su_home_t *, msg_header_t *, |
14163 | char *s, isize_t slen); |
14164 | |
14165 | /** Print a SIP @ref sip_privacy "Privacy header". @internal */ |
14166 | SOFIAPUBFUN issize_t sip_privacy_e(char b[], isize_t bsiz, |
14167 | msg_header_t const *h, int flags); |
14168 | |
14169 | /**Access a SIP @ref sip_privacy "Privacy header" |
14170 | * structure #sip_privacy_t from #sip_t. |
14171 | * |
14172 | */ |
14173 | #define sip_privacy(sip)((sip_privacy_t *)msg_header_access((msg_pub_t*)(sip), sip_privacy_class )) \ |
14174 | ((sip_privacy_t *)msg_header_access((msg_pub_t*)(sip), sip_privacy_class)) |
14175 | |
14176 | /**Initializer for structure #sip_privacy_t. |
14177 | * |
14178 | * A static #sip_privacy_t structure for |
14179 | * @ref sip_privacy "Privacy header" must be initialized with |
14180 | * the SIP_PRIVACY_INIT() macro. |
14181 | * For instance, |
14182 | * @code |
14183 | * |
14184 | * sip_privacy_t sip_privacy = SIP_PRIVACY_INIT; |
14185 | * |
14186 | * @endcode |
14187 | * @HI |
14188 | * |
14189 | */ |
14190 | #define SIP_PRIVACY_INIT(){{{ 0, 0, sip_privacy_class }}} SIP_HDR_INIT(privacy){{{ 0, 0, sip_privacy_class }}} |
14191 | |
14192 | /**Initialize a structure #sip_privacy_t. |
14193 | * |
14194 | * An #sip_privacy_t structure for |
14195 | * @ref sip_privacy "Privacy header" can be initialized with the |
14196 | * sip_privacy_init() function/macro. For instance, |
14197 | * @code |
14198 | * |
14199 | * sip_privacy_t sip_privacy; |
14200 | * |
14201 | * sip_privacy_init(&sip_privacy); |
14202 | * |
14203 | * @endcode |
14204 | * @HI |
14205 | * |
14206 | */ |
14207 | #if SU_HAVE_INLINE1 |
14208 | su_inlinestatic inline sip_privacy_t *sip_privacy_init(sip_privacy_t x[1]) |
14209 | { |
14210 | return SIP_HEADER_INIT(x, sip_privacy_class, sizeof(sip_privacy_t))((void)memset((x), 0, (sizeof(sip_privacy_t))), (void)(((sip_common_t *)(x))->h_class = (sip_privacy_class)), (x)); |
14211 | } |
14212 | #else |
14213 | #define sip_privacy_init(x) \ |
14214 | SIP_HEADER_INIT(x, sip_privacy_class, sizeof(sip_privacy_t))((void)memset((x), 0, (sizeof(sip_privacy_t))), (void)(((sip_common_t *)(x))->h_class = (sip_privacy_class)), (x)) |
14215 | #endif |
14216 | |
14217 | /**Test if header object is instance of #sip_privacy_t. |
14218 | * |
14219 | * Check if the header class is an instance of |
14220 | * @ref sip_privacy "Privacy header" object and return true (nonzero), |
14221 | * otherwise return false (zero). |
14222 | * |
14223 | * @param header pointer to the header structure to be tested |
14224 | * |
14225 | * @retval 1 (true) if the @a header is an instance of header privacy |
14226 | * @retval 0 (false) otherwise |
14227 | * |
14228 | */ |
14229 | #if SU_HAVE_INLINE1 |
14230 | su_inlinestatic inline int sip_is_privacy(sip_header_t const *header) |
14231 | { |
14232 | return header && header->sh_classsh_common->h_class->hc_hash == sip_privacy_hash; |
14233 | } |
14234 | #else |
14235 | int sip_is_privacy(sip_header_t const *header); |
14236 | #endif |
14237 | |
14238 | #define sip_privacy_p(h)sip_is_privacy((h)) sip_is_privacy((h)) |
14239 | |
14240 | |
14241 | /**Duplicate a list of @ref sip_privacy "Privacy header" header structures #sip_privacy_t. |
14242 | * |
14243 | * Duplicate a header |
14244 | * structure @a hdr. If the header structure @a hdr |
14245 | * contains a reference (@c hdr->x_next) to a list of |
14246 | * headers, all the headers in the list are duplicated, too. |
14247 | * |
14248 | * @param home memory home used to allocate new structure |
14249 | * @param hdr header structure to be duplicated |
14250 | * |
14251 | * When duplicating, all parameter lists and non-constant |
14252 | * strings attached to the header are copied, too. The |
14253 | * function uses given memory @a home to allocate all the |
14254 | * memory areas used to copy the header. |
14255 | * |
14256 | * @par Example |
14257 | * @code |
14258 | * |
14259 | * privacy = sip_privacy_dup(home, sip->sip_privacy); |
14260 | * |
14261 | * @endcode |
14262 | * |
14263 | * @return |
14264 | * A pointer to the |
14265 | * newly duplicated #sip_privacy_t header structure, or NULL |
14266 | * upon an error. |
14267 | * |
14268 | */ |
14269 | #if SU_HAVE_INLINE1 |
14270 | su_inlinestatic inline |
14271 | #endif |
14272 | sip_privacy_t *sip_privacy_dup(su_home_t *home, sip_privacy_t const *hdr) |
14273 | __attribute__((__malloc__)); |
14274 | |
14275 | #if SU_HAVE_INLINE1 |
14276 | su_inlinestatic inline |
14277 | sip_privacy_t *sip_privacy_dup(su_home_t *home, sip_privacy_t const *hdr) |
14278 | { |
14279 | return (sip_privacy_t *) |
14280 | msg_header_dup_as(home, sip_privacy_class, (msg_header_t const *)hdr); |
14281 | } |
14282 | #endif |
14283 | |
14284 | /**Copy a list of @ref sip_privacy "Privacy header" header structures #sip_privacy_t. |
14285 | * |
14286 | * The function sip_privacy_copy() copies a header structure @a |
14287 | * hdr. If the header structure @a hdr contains a reference (@c |
14288 | * hdr->h_next) to a list of headers, all the headers in that |
14289 | * list are copied, too. The function uses given memory @a home |
14290 | * to allocate all the memory areas used to copy the list of header |
14291 | * structure @a hdr. |
14292 | * |
14293 | * @param home memory home used to allocate new structure |
14294 | * @param hdr pointer to the header structure to be copied |
14295 | * |
14296 | * When copying, only the header structure and parameter lists attached to |
14297 | * it are duplicated. The new header structure retains all the references to |
14298 | * the strings within the old @a hdr header, including the encoding of the |
14299 | * old header, if present. |
14300 | * |
14301 | * @par Example |
14302 | * @code |
14303 | * |
14304 | * privacy = sip_privacy_copy(home, sip->sip_privacy); |
14305 | * |
14306 | * @endcode |
14307 | * |
14308 | * @return |
14309 | * A pointer to newly copied header structure, or NULL upon an error. |
14310 | * |
14311 | */ |
14312 | #if SU_HAVE_INLINE1 |
14313 | su_inlinestatic inline |
14314 | #endif |
14315 | sip_privacy_t *sip_privacy_copy(su_home_t *home, sip_privacy_t const *hdr) |
14316 | __attribute__((__malloc__)); |
14317 | |
14318 | #if SU_HAVE_INLINE1 |
14319 | su_inlinestatic inline |
14320 | sip_privacy_t *sip_privacy_copy(su_home_t *home, sip_privacy_t const *hdr) |
14321 | { |
14322 | return (sip_privacy_t *) |
14323 | msg_header_copy_as(home, sip_privacy_class, (msg_header_t const *)hdr); |
14324 | } |
14325 | #endif |
14326 | |
14327 | /**Make a @ref sip_privacy "Privacy header" structure #sip_privacy_t. |
14328 | * |
14329 | * The function sip_privacy_make() makes a new |
14330 | * #sip_privacy_t header structure. It allocates a new |
14331 | * header structure, and decodes the string @a s as the |
14332 | * value of the structure. |
14333 | * |
14334 | * @param home memory home used to allocate new header structure. |
14335 | * @param s string to be decoded as value of the new header structure |
14336 | * |
14337 | * @return |
14338 | * A pointer to newly maked #sip_privacy_t header structure, or NULL upon an |
14339 | * error. |
14340 | * |
14341 | */ |
14342 | #if SU_HAVE_INLINE1 |
14343 | su_inlinestatic inline |
14344 | #endif |
14345 | sip_privacy_t *sip_privacy_make(su_home_t *home, char const *s) |
14346 | __attribute__((__malloc__)); |
14347 | |
14348 | #if SU_HAVE_INLINE1 |
14349 | su_inlinestatic inline sip_privacy_t *sip_privacy_make(su_home_t *home, char const *s) |
14350 | { |
14351 | return (sip_privacy_t *)sip_header_make(home, sip_privacy_class, s)((sip_header_t *)msg_header_make((home), (sip_privacy_class), (s))); |
14352 | } |
14353 | #endif |
14354 | |
14355 | /**Make a @ref sip_privacy "Privacy header" from formatting result. |
14356 | * |
14357 | * Make a new #sip_privacy_t object using formatting result as its value. |
14358 | * The function first prints the arguments according to the format @a fmt |
14359 | * specified. Then it allocates a new header structure, and parses the |
14360 | * formatting result to the structure #sip_privacy_t. |
14361 | * |
14362 | * @param home memory home used to allocate new header structure. |
14363 | * @param fmt string used as a printf()-style format |
14364 | * @param ... argument list for format |
14365 | * |
14366 | * @return |
14367 | * A pointer to newly |
14368 | * makes header structure, or NULL upon an error. |
14369 | * |
14370 | * @HIDE |
14371 | * |
14372 | */ |
14373 | #if SU_HAVE_INLINE1 |
14374 | su_inlinestatic inline |
14375 | #endif |
14376 | sip_privacy_t *sip_privacy_format(su_home_t *home, char const *fmt, ...) |
14377 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
14378 | |
14379 | #if SU_HAVE_INLINE1 |
14380 | su_inlinestatic inline sip_privacy_t *sip_privacy_format(su_home_t *home, char const *fmt, ...) |
14381 | { |
14382 | sip_header_t *h; |
14383 | va_list ap; |
14384 | |
14385 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
14386 | h = sip_header_vformat(home, sip_privacy_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_privacy_class ), (fmt), (ap))); |
14387 | va_end(ap)__builtin_va_end(ap); |
14388 | |
14389 | return (sip_privacy_t *)h; |
14390 | } |
14391 | #endif |
14392 | |
14393 | /** @} */ |
14394 | |
14395 | /**@addtogroup sip_etag |
14396 | * @{ |
14397 | */ |
14398 | |
14399 | /** Parse a SIP @ref sip_etag "SIP-ETag header". @internal */ |
14400 | SOFIAPUBFUN issize_t sip_etag_d(su_home_t *, msg_header_t *, |
14401 | char *s, isize_t slen); |
14402 | |
14403 | /** Print a SIP @ref sip_etag "SIP-ETag header". @internal */ |
14404 | SOFIAPUBFUN issize_t sip_etag_e(char b[], isize_t bsiz, |
14405 | msg_header_t const *h, int flags); |
14406 | |
14407 | /**Access a SIP @ref sip_etag "SIP-ETag header" |
14408 | * structure #sip_etag_t from #sip_t. |
14409 | * |
14410 | */ |
14411 | #define sip_etag(sip)((sip_etag_t *)msg_header_access((msg_pub_t*)(sip), sip_etag_class )) \ |
14412 | ((sip_etag_t *)msg_header_access((msg_pub_t*)(sip), sip_etag_class)) |
14413 | |
14414 | /**Initializer for structure #sip_etag_t. |
14415 | * |
14416 | * A static #sip_etag_t structure for |
14417 | * @ref sip_etag "SIP-ETag header" must be initialized with |
14418 | * the SIP_ETAG_INIT() macro. |
14419 | * For instance, |
14420 | * @code |
14421 | * |
14422 | * sip_etag_t sip_etag = SIP_ETAG_INIT; |
14423 | * |
14424 | * @endcode |
14425 | * @HI |
14426 | * |
14427 | */ |
14428 | #define SIP_ETAG_INIT(){{{ 0, 0, sip_etag_class }}} SIP_HDR_INIT(etag){{{ 0, 0, sip_etag_class }}} |
14429 | |
14430 | /**Initialize a structure #sip_etag_t. |
14431 | * |
14432 | * An #sip_etag_t structure for |
14433 | * @ref sip_etag "SIP-ETag header" can be initialized with the |
14434 | * sip_etag_init() function/macro. For instance, |
14435 | * @code |
14436 | * |
14437 | * sip_etag_t sip_etag; |
14438 | * |
14439 | * sip_etag_init(&sip_etag); |
14440 | * |
14441 | * @endcode |
14442 | * @HI |
14443 | * |
14444 | */ |
14445 | #if SU_HAVE_INLINE1 |
14446 | su_inlinestatic inline sip_etag_t *sip_etag_init(sip_etag_t x[1]) |
14447 | { |
14448 | return SIP_HEADER_INIT(x, sip_etag_class, sizeof(sip_etag_t))((void)memset((x), 0, (sizeof(sip_etag_t))), (void)(((sip_common_t *)(x))->h_class = (sip_etag_class)), (x)); |
14449 | } |
14450 | #else |
14451 | #define sip_etag_init(x) \ |
14452 | SIP_HEADER_INIT(x, sip_etag_class, sizeof(sip_etag_t))((void)memset((x), 0, (sizeof(sip_etag_t))), (void)(((sip_common_t *)(x))->h_class = (sip_etag_class)), (x)) |
14453 | #endif |
14454 | |
14455 | /**Test if header object is instance of #sip_etag_t. |
14456 | * |
14457 | * Check if the header class is an instance of |
14458 | * @ref sip_etag "SIP-ETag header" object and return true (nonzero), |
14459 | * otherwise return false (zero). |
14460 | * |
14461 | * @param header pointer to the header structure to be tested |
14462 | * |
14463 | * @retval 1 (true) if the @a header is an instance of header etag |
14464 | * @retval 0 (false) otherwise |
14465 | * |
14466 | */ |
14467 | #if SU_HAVE_INLINE1 |
14468 | su_inlinestatic inline int sip_is_etag(sip_header_t const *header) |
14469 | { |
14470 | return header && header->sh_classsh_common->h_class->hc_hash == sip_etag_hash; |
14471 | } |
14472 | #else |
14473 | int sip_is_etag(sip_header_t const *header); |
14474 | #endif |
14475 | |
14476 | #define sip_etag_p(h)sip_is_etag((h)) sip_is_etag((h)) |
14477 | |
14478 | |
14479 | /**Duplicate a list of @ref sip_etag "SIP-ETag header" header structures #sip_etag_t. |
14480 | * |
14481 | * Duplicate a header |
14482 | * structure @a hdr. If the header structure @a hdr |
14483 | * contains a reference (@c hdr->x_next) to a list of |
14484 | * headers, all the headers in the list are duplicated, too. |
14485 | * |
14486 | * @param home memory home used to allocate new structure |
14487 | * @param hdr header structure to be duplicated |
14488 | * |
14489 | * When duplicating, all parameter lists and non-constant |
14490 | * strings attached to the header are copied, too. The |
14491 | * function uses given memory @a home to allocate all the |
14492 | * memory areas used to copy the header. |
14493 | * |
14494 | * @par Example |
14495 | * @code |
14496 | * |
14497 | * etag = sip_etag_dup(home, sip->sip_etag); |
14498 | * |
14499 | * @endcode |
14500 | * |
14501 | * @return |
14502 | * A pointer to the |
14503 | * newly duplicated #sip_etag_t header structure, or NULL |
14504 | * upon an error. |
14505 | * |
14506 | */ |
14507 | #if SU_HAVE_INLINE1 |
14508 | su_inlinestatic inline |
14509 | #endif |
14510 | sip_etag_t *sip_etag_dup(su_home_t *home, sip_etag_t const *hdr) |
14511 | __attribute__((__malloc__)); |
14512 | |
14513 | #if SU_HAVE_INLINE1 |
14514 | su_inlinestatic inline |
14515 | sip_etag_t *sip_etag_dup(su_home_t *home, sip_etag_t const *hdr) |
14516 | { |
14517 | return (sip_etag_t *) |
14518 | msg_header_dup_as(home, sip_etag_class, (msg_header_t const *)hdr); |
14519 | } |
14520 | #endif |
14521 | |
14522 | /**Copy a list of @ref sip_etag "SIP-ETag header" header structures #sip_etag_t. |
14523 | * |
14524 | * The function sip_etag_copy() copies a header structure @a |
14525 | * hdr. If the header structure @a hdr contains a reference (@c |
14526 | * hdr->h_next) to a list of headers, all the headers in that |
14527 | * list are copied, too. The function uses given memory @a home |
14528 | * to allocate all the memory areas used to copy the list of header |
14529 | * structure @a hdr. |
14530 | * |
14531 | * @param home memory home used to allocate new structure |
14532 | * @param hdr pointer to the header structure to be copied |
14533 | * |
14534 | * When copying, only the header structure and parameter lists attached to |
14535 | * it are duplicated. The new header structure retains all the references to |
14536 | * the strings within the old @a hdr header, including the encoding of the |
14537 | * old header, if present. |
14538 | * |
14539 | * @par Example |
14540 | * @code |
14541 | * |
14542 | * etag = sip_etag_copy(home, sip->sip_etag); |
14543 | * |
14544 | * @endcode |
14545 | * |
14546 | * @return |
14547 | * A pointer to newly copied header structure, or NULL upon an error. |
14548 | * |
14549 | */ |
14550 | #if SU_HAVE_INLINE1 |
14551 | su_inlinestatic inline |
14552 | #endif |
14553 | sip_etag_t *sip_etag_copy(su_home_t *home, sip_etag_t const *hdr) |
14554 | __attribute__((__malloc__)); |
14555 | |
14556 | #if SU_HAVE_INLINE1 |
14557 | su_inlinestatic inline |
14558 | sip_etag_t *sip_etag_copy(su_home_t *home, sip_etag_t const *hdr) |
14559 | { |
14560 | return (sip_etag_t *) |
14561 | msg_header_copy_as(home, sip_etag_class, (msg_header_t const *)hdr); |
14562 | } |
14563 | #endif |
14564 | |
14565 | /**Make a @ref sip_etag "SIP-ETag header" structure #sip_etag_t. |
14566 | * |
14567 | * The function sip_etag_make() makes a new |
14568 | * #sip_etag_t header structure. It allocates a new |
14569 | * header structure, and decodes the string @a s as the |
14570 | * value of the structure. |
14571 | * |
14572 | * @param home memory home used to allocate new header structure. |
14573 | * @param s string to be decoded as value of the new header structure |
14574 | * |
14575 | * @return |
14576 | * A pointer to newly maked #sip_etag_t header structure, or NULL upon an |
14577 | * error. |
14578 | * |
14579 | */ |
14580 | #if SU_HAVE_INLINE1 |
14581 | su_inlinestatic inline |
14582 | #endif |
14583 | sip_etag_t *sip_etag_make(su_home_t *home, char const *s) |
14584 | __attribute__((__malloc__)); |
14585 | |
14586 | #if SU_HAVE_INLINE1 |
14587 | su_inlinestatic inline sip_etag_t *sip_etag_make(su_home_t *home, char const *s) |
14588 | { |
14589 | return (sip_etag_t *)sip_header_make(home, sip_etag_class, s)((sip_header_t *)msg_header_make((home), (sip_etag_class), (s ))); |
14590 | } |
14591 | #endif |
14592 | |
14593 | /**Make a @ref sip_etag "SIP-ETag header" from formatting result. |
14594 | * |
14595 | * Make a new #sip_etag_t object using formatting result as its value. |
14596 | * The function first prints the arguments according to the format @a fmt |
14597 | * specified. Then it allocates a new header structure, and parses the |
14598 | * formatting result to the structure #sip_etag_t. |
14599 | * |
14600 | * @param home memory home used to allocate new header structure. |
14601 | * @param fmt string used as a printf()-style format |
14602 | * @param ... argument list for format |
14603 | * |
14604 | * @return |
14605 | * A pointer to newly |
14606 | * makes header structure, or NULL upon an error. |
14607 | * |
14608 | * @HIDE |
14609 | * |
14610 | */ |
14611 | #if SU_HAVE_INLINE1 |
14612 | su_inlinestatic inline |
14613 | #endif |
14614 | sip_etag_t *sip_etag_format(su_home_t *home, char const *fmt, ...) |
14615 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
14616 | |
14617 | #if SU_HAVE_INLINE1 |
14618 | su_inlinestatic inline sip_etag_t *sip_etag_format(su_home_t *home, char const *fmt, ...) |
14619 | { |
14620 | sip_header_t *h; |
14621 | va_list ap; |
14622 | |
14623 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
14624 | h = sip_header_vformat(home, sip_etag_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_etag_class), (fmt), (ap))); |
14625 | va_end(ap)__builtin_va_end(ap); |
14626 | |
14627 | return (sip_etag_t *)h; |
14628 | } |
14629 | #endif |
14630 | |
14631 | /** @} */ |
14632 | |
14633 | /**@addtogroup sip_if_match |
14634 | * @{ |
14635 | */ |
14636 | |
14637 | /** Parse a SIP @ref sip_if_match "SIP-If-Match header". @internal */ |
14638 | SOFIAPUBFUN issize_t sip_if_match_d(su_home_t *, msg_header_t *, |
14639 | char *s, isize_t slen); |
14640 | |
14641 | /** Print a SIP @ref sip_if_match "SIP-If-Match header". @internal */ |
14642 | SOFIAPUBFUN issize_t sip_if_match_e(char b[], isize_t bsiz, |
14643 | msg_header_t const *h, int flags); |
14644 | |
14645 | /**Access a SIP @ref sip_if_match "SIP-If-Match header" |
14646 | * structure #sip_if_match_t from #sip_t. |
14647 | * |
14648 | */ |
14649 | #define sip_if_match(sip)((sip_if_match_t *)msg_header_access((msg_pub_t*)(sip), sip_if_match_class )) \ |
14650 | ((sip_if_match_t *)msg_header_access((msg_pub_t*)(sip), sip_if_match_class)) |
14651 | |
14652 | /**Initializer for structure #sip_if_match_t. |
14653 | * |
14654 | * A static #sip_if_match_t structure for |
14655 | * @ref sip_if_match "SIP-If-Match header" must be initialized with |
14656 | * the SIP_IF_MATCH_INIT() macro. |
14657 | * For instance, |
14658 | * @code |
14659 | * |
14660 | * sip_if_match_t sip_if_match = SIP_IF_MATCH_INIT; |
14661 | * |
14662 | * @endcode |
14663 | * @HI |
14664 | * |
14665 | */ |
14666 | #define SIP_IF_MATCH_INIT(){{{ 0, 0, sip_if_match_class }}} SIP_HDR_INIT(if_match){{{ 0, 0, sip_if_match_class }}} |
14667 | |
14668 | /**Initialize a structure #sip_if_match_t. |
14669 | * |
14670 | * An #sip_if_match_t structure for |
14671 | * @ref sip_if_match "SIP-If-Match header" can be initialized with the |
14672 | * sip_if_match_init() function/macro. For instance, |
14673 | * @code |
14674 | * |
14675 | * sip_if_match_t sip_if_match; |
14676 | * |
14677 | * sip_if_match_init(&sip_if_match); |
14678 | * |
14679 | * @endcode |
14680 | * @HI |
14681 | * |
14682 | */ |
14683 | #if SU_HAVE_INLINE1 |
14684 | su_inlinestatic inline sip_if_match_t *sip_if_match_init(sip_if_match_t x[1]) |
14685 | { |
14686 | return SIP_HEADER_INIT(x, sip_if_match_class, sizeof(sip_if_match_t))((void)memset((x), 0, (sizeof(sip_if_match_t))), (void)(((sip_common_t *)(x))->h_class = (sip_if_match_class)), (x)); |
14687 | } |
14688 | #else |
14689 | #define sip_if_match_init(x) \ |
14690 | SIP_HEADER_INIT(x, sip_if_match_class, sizeof(sip_if_match_t))((void)memset((x), 0, (sizeof(sip_if_match_t))), (void)(((sip_common_t *)(x))->h_class = (sip_if_match_class)), (x)) |
14691 | #endif |
14692 | |
14693 | /**Test if header object is instance of #sip_if_match_t. |
14694 | * |
14695 | * Check if the header class is an instance of |
14696 | * @ref sip_if_match "SIP-If-Match header" object and return true (nonzero), |
14697 | * otherwise return false (zero). |
14698 | * |
14699 | * @param header pointer to the header structure to be tested |
14700 | * |
14701 | * @retval 1 (true) if the @a header is an instance of header if_match |
14702 | * @retval 0 (false) otherwise |
14703 | * |
14704 | */ |
14705 | #if SU_HAVE_INLINE1 |
14706 | su_inlinestatic inline int sip_is_if_match(sip_header_t const *header) |
14707 | { |
14708 | return header && header->sh_classsh_common->h_class->hc_hash == sip_if_match_hash; |
14709 | } |
14710 | #else |
14711 | int sip_is_if_match(sip_header_t const *header); |
14712 | #endif |
14713 | |
14714 | #define sip_if_match_p(h)sip_is_if_match((h)) sip_is_if_match((h)) |
14715 | |
14716 | |
14717 | /**Duplicate a list of @ref sip_if_match "SIP-If-Match header" header structures #sip_if_match_t. |
14718 | * |
14719 | * Duplicate a header |
14720 | * structure @a hdr. If the header structure @a hdr |
14721 | * contains a reference (@c hdr->x_next) to a list of |
14722 | * headers, all the headers in the list are duplicated, too. |
14723 | * |
14724 | * @param home memory home used to allocate new structure |
14725 | * @param hdr header structure to be duplicated |
14726 | * |
14727 | * When duplicating, all parameter lists and non-constant |
14728 | * strings attached to the header are copied, too. The |
14729 | * function uses given memory @a home to allocate all the |
14730 | * memory areas used to copy the header. |
14731 | * |
14732 | * @par Example |
14733 | * @code |
14734 | * |
14735 | * if_match = sip_if_match_dup(home, sip->sip_if_match); |
14736 | * |
14737 | * @endcode |
14738 | * |
14739 | * @return |
14740 | * A pointer to the |
14741 | * newly duplicated #sip_if_match_t header structure, or NULL |
14742 | * upon an error. |
14743 | * |
14744 | */ |
14745 | #if SU_HAVE_INLINE1 |
14746 | su_inlinestatic inline |
14747 | #endif |
14748 | sip_if_match_t *sip_if_match_dup(su_home_t *home, sip_if_match_t const *hdr) |
14749 | __attribute__((__malloc__)); |
14750 | |
14751 | #if SU_HAVE_INLINE1 |
14752 | su_inlinestatic inline |
14753 | sip_if_match_t *sip_if_match_dup(su_home_t *home, sip_if_match_t const *hdr) |
14754 | { |
14755 | return (sip_if_match_t *) |
14756 | msg_header_dup_as(home, sip_if_match_class, (msg_header_t const *)hdr); |
14757 | } |
14758 | #endif |
14759 | |
14760 | /**Copy a list of @ref sip_if_match "SIP-If-Match header" header structures #sip_if_match_t. |
14761 | * |
14762 | * The function sip_if_match_copy() copies a header structure @a |
14763 | * hdr. If the header structure @a hdr contains a reference (@c |
14764 | * hdr->h_next) to a list of headers, all the headers in that |
14765 | * list are copied, too. The function uses given memory @a home |
14766 | * to allocate all the memory areas used to copy the list of header |
14767 | * structure @a hdr. |
14768 | * |
14769 | * @param home memory home used to allocate new structure |
14770 | * @param hdr pointer to the header structure to be copied |
14771 | * |
14772 | * When copying, only the header structure and parameter lists attached to |
14773 | * it are duplicated. The new header structure retains all the references to |
14774 | * the strings within the old @a hdr header, including the encoding of the |
14775 | * old header, if present. |
14776 | * |
14777 | * @par Example |
14778 | * @code |
14779 | * |
14780 | * if_match = sip_if_match_copy(home, sip->sip_if_match); |
14781 | * |
14782 | * @endcode |
14783 | * |
14784 | * @return |
14785 | * A pointer to newly copied header structure, or NULL upon an error. |
14786 | * |
14787 | */ |
14788 | #if SU_HAVE_INLINE1 |
14789 | su_inlinestatic inline |
14790 | #endif |
14791 | sip_if_match_t *sip_if_match_copy(su_home_t *home, sip_if_match_t const *hdr) |
14792 | __attribute__((__malloc__)); |
14793 | |
14794 | #if SU_HAVE_INLINE1 |
14795 | su_inlinestatic inline |
14796 | sip_if_match_t *sip_if_match_copy(su_home_t *home, sip_if_match_t const *hdr) |
14797 | { |
14798 | return (sip_if_match_t *) |
14799 | msg_header_copy_as(home, sip_if_match_class, (msg_header_t const *)hdr); |
14800 | } |
14801 | #endif |
14802 | |
14803 | /**Make a @ref sip_if_match "SIP-If-Match header" structure #sip_if_match_t. |
14804 | * |
14805 | * The function sip_if_match_make() makes a new |
14806 | * #sip_if_match_t header structure. It allocates a new |
14807 | * header structure, and decodes the string @a s as the |
14808 | * value of the structure. |
14809 | * |
14810 | * @param home memory home used to allocate new header structure. |
14811 | * @param s string to be decoded as value of the new header structure |
14812 | * |
14813 | * @return |
14814 | * A pointer to newly maked #sip_if_match_t header structure, or NULL upon an |
14815 | * error. |
14816 | * |
14817 | */ |
14818 | #if SU_HAVE_INLINE1 |
14819 | su_inlinestatic inline |
14820 | #endif |
14821 | sip_if_match_t *sip_if_match_make(su_home_t *home, char const *s) |
14822 | __attribute__((__malloc__)); |
14823 | |
14824 | #if SU_HAVE_INLINE1 |
14825 | su_inlinestatic inline sip_if_match_t *sip_if_match_make(su_home_t *home, char const *s) |
14826 | { |
14827 | return (sip_if_match_t *)sip_header_make(home, sip_if_match_class, s)((sip_header_t *)msg_header_make((home), (sip_if_match_class) , (s))); |
14828 | } |
14829 | #endif |
14830 | |
14831 | /**Make a @ref sip_if_match "SIP-If-Match header" from formatting result. |
14832 | * |
14833 | * Make a new #sip_if_match_t object using formatting result as its value. |
14834 | * The function first prints the arguments according to the format @a fmt |
14835 | * specified. Then it allocates a new header structure, and parses the |
14836 | * formatting result to the structure #sip_if_match_t. |
14837 | * |
14838 | * @param home memory home used to allocate new header structure. |
14839 | * @param fmt string used as a printf()-style format |
14840 | * @param ... argument list for format |
14841 | * |
14842 | * @return |
14843 | * A pointer to newly |
14844 | * makes header structure, or NULL upon an error. |
14845 | * |
14846 | * @HIDE |
14847 | * |
14848 | */ |
14849 | #if SU_HAVE_INLINE1 |
14850 | su_inlinestatic inline |
14851 | #endif |
14852 | sip_if_match_t *sip_if_match_format(su_home_t *home, char const *fmt, ...) |
14853 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
14854 | |
14855 | #if SU_HAVE_INLINE1 |
14856 | su_inlinestatic inline sip_if_match_t *sip_if_match_format(su_home_t *home, char const *fmt, ...) |
14857 | { |
14858 | sip_header_t *h; |
14859 | va_list ap; |
14860 | |
14861 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
14862 | h = sip_header_vformat(home, sip_if_match_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_if_match_class ), (fmt), (ap))); |
14863 | va_end(ap)__builtin_va_end(ap); |
14864 | |
14865 | return (sip_if_match_t *)h; |
14866 | } |
14867 | #endif |
14868 | |
14869 | /** @} */ |
14870 | |
14871 | /**@addtogroup sip_mime_version |
14872 | * @{ |
14873 | */ |
14874 | |
14875 | /** Parse a SIP @ref sip_mime_version "MIME-Version header". @internal */ |
14876 | SOFIAPUBFUN issize_t sip_mime_version_d(su_home_t *, msg_header_t *, |
14877 | char *s, isize_t slen); |
14878 | |
14879 | /** Print a SIP @ref sip_mime_version "MIME-Version header". @internal */ |
14880 | SOFIAPUBFUN issize_t sip_mime_version_e(char b[], isize_t bsiz, |
14881 | msg_header_t const *h, int flags); |
14882 | |
14883 | /**Access a SIP @ref sip_mime_version "MIME-Version header" |
14884 | * structure #sip_mime_version_t from #sip_t. |
14885 | * |
14886 | */ |
14887 | #define sip_mime_version(sip)((sip_mime_version_t *)msg_header_access((msg_pub_t*)(sip), sip_mime_version_class )) \ |
14888 | ((sip_mime_version_t *)msg_header_access((msg_pub_t*)(sip), sip_mime_version_class)) |
14889 | |
14890 | /**Initializer for structure #sip_mime_version_t. |
14891 | * |
14892 | * A static #sip_mime_version_t structure for |
14893 | * @ref sip_mime_version "MIME-Version header" must be initialized with |
14894 | * the SIP_MIME_VERSION_INIT() macro. |
14895 | * For instance, |
14896 | * @code |
14897 | * |
14898 | * sip_mime_version_t sip_mime_version = SIP_MIME_VERSION_INIT; |
14899 | * |
14900 | * @endcode |
14901 | * @HI |
14902 | * |
14903 | */ |
14904 | #define SIP_MIME_VERSION_INIT(){{{ 0, 0, sip_mime_version_class }}} SIP_HDR_INIT(mime_version){{{ 0, 0, sip_mime_version_class }}} |
14905 | |
14906 | /**Initialize a structure #sip_mime_version_t. |
14907 | * |
14908 | * An #sip_mime_version_t structure for |
14909 | * @ref sip_mime_version "MIME-Version header" can be initialized with the |
14910 | * sip_mime_version_init() function/macro. For instance, |
14911 | * @code |
14912 | * |
14913 | * sip_mime_version_t sip_mime_version; |
14914 | * |
14915 | * sip_mime_version_init(&sip_mime_version); |
14916 | * |
14917 | * @endcode |
14918 | * @HI |
14919 | * |
14920 | */ |
14921 | #if SU_HAVE_INLINE1 |
14922 | su_inlinestatic inline sip_mime_version_t *sip_mime_version_init(sip_mime_version_t x[1]) |
14923 | { |
14924 | return SIP_HEADER_INIT(x, sip_mime_version_class, sizeof(sip_mime_version_t))((void)memset((x), 0, (sizeof(sip_mime_version_t))), (void)(( (sip_common_t *)(x))->h_class = (sip_mime_version_class)), (x)); |
14925 | } |
14926 | #else |
14927 | #define sip_mime_version_init(x) \ |
14928 | SIP_HEADER_INIT(x, sip_mime_version_class, sizeof(sip_mime_version_t))((void)memset((x), 0, (sizeof(sip_mime_version_t))), (void)(( (sip_common_t *)(x))->h_class = (sip_mime_version_class)), (x)) |
14929 | #endif |
14930 | |
14931 | /**Test if header object is instance of #sip_mime_version_t. |
14932 | * |
14933 | * Check if the header class is an instance of |
14934 | * @ref sip_mime_version "MIME-Version header" object and return true (nonzero), |
14935 | * otherwise return false (zero). |
14936 | * |
14937 | * @param header pointer to the header structure to be tested |
14938 | * |
14939 | * @retval 1 (true) if the @a header is an instance of header mime_version |
14940 | * @retval 0 (false) otherwise |
14941 | * |
14942 | */ |
14943 | #if SU_HAVE_INLINE1 |
14944 | su_inlinestatic inline int sip_is_mime_version(sip_header_t const *header) |
14945 | { |
14946 | return header && header->sh_classsh_common->h_class->hc_hash == sip_mime_version_hash; |
14947 | } |
14948 | #else |
14949 | int sip_is_mime_version(sip_header_t const *header); |
14950 | #endif |
14951 | |
14952 | #define sip_mime_version_p(h)sip_is_mime_version((h)) sip_is_mime_version((h)) |
14953 | |
14954 | |
14955 | /**Duplicate a list of @ref sip_mime_version "MIME-Version header" header structures #sip_mime_version_t. |
14956 | * |
14957 | * Duplicate a header |
14958 | * structure @a hdr. If the header structure @a hdr |
14959 | * contains a reference (@c hdr->x_next) to a list of |
14960 | * headers, all the headers in the list are duplicated, too. |
14961 | * |
14962 | * @param home memory home used to allocate new structure |
14963 | * @param hdr header structure to be duplicated |
14964 | * |
14965 | * When duplicating, all parameter lists and non-constant |
14966 | * strings attached to the header are copied, too. The |
14967 | * function uses given memory @a home to allocate all the |
14968 | * memory areas used to copy the header. |
14969 | * |
14970 | * @par Example |
14971 | * @code |
14972 | * |
14973 | * mime_version = sip_mime_version_dup(home, sip->sip_mime_version); |
14974 | * |
14975 | * @endcode |
14976 | * |
14977 | * @return |
14978 | * A pointer to the |
14979 | * newly duplicated #sip_mime_version_t header structure, or NULL |
14980 | * upon an error. |
14981 | * |
14982 | */ |
14983 | #if SU_HAVE_INLINE1 |
14984 | su_inlinestatic inline |
14985 | #endif |
14986 | sip_mime_version_t *sip_mime_version_dup(su_home_t *home, sip_mime_version_t const *hdr) |
14987 | __attribute__((__malloc__)); |
14988 | |
14989 | #if SU_HAVE_INLINE1 |
14990 | su_inlinestatic inline |
14991 | sip_mime_version_t *sip_mime_version_dup(su_home_t *home, sip_mime_version_t const *hdr) |
14992 | { |
14993 | return (sip_mime_version_t *) |
14994 | msg_header_dup_as(home, sip_mime_version_class, (msg_header_t const *)hdr); |
14995 | } |
14996 | #endif |
14997 | |
14998 | /**Copy a list of @ref sip_mime_version "MIME-Version header" header structures #sip_mime_version_t. |
14999 | * |
15000 | * The function sip_mime_version_copy() copies a header structure @a |
15001 | * hdr. If the header structure @a hdr contains a reference (@c |
15002 | * hdr->h_next) to a list of headers, all the headers in that |
15003 | * list are copied, too. The function uses given memory @a home |
15004 | * to allocate all the memory areas used to copy the list of header |
15005 | * structure @a hdr. |
15006 | * |
15007 | * @param home memory home used to allocate new structure |
15008 | * @param hdr pointer to the header structure to be copied |
15009 | * |
15010 | * When copying, only the header structure and parameter lists attached to |
15011 | * it are duplicated. The new header structure retains all the references to |
15012 | * the strings within the old @a hdr header, including the encoding of the |
15013 | * old header, if present. |
15014 | * |
15015 | * @par Example |
15016 | * @code |
15017 | * |
15018 | * mime_version = sip_mime_version_copy(home, sip->sip_mime_version); |
15019 | * |
15020 | * @endcode |
15021 | * |
15022 | * @return |
15023 | * A pointer to newly copied header structure, or NULL upon an error. |
15024 | * |
15025 | */ |
15026 | #if SU_HAVE_INLINE1 |
15027 | su_inlinestatic inline |
15028 | #endif |
15029 | sip_mime_version_t *sip_mime_version_copy(su_home_t *home, sip_mime_version_t const *hdr) |
15030 | __attribute__((__malloc__)); |
15031 | |
15032 | #if SU_HAVE_INLINE1 |
15033 | su_inlinestatic inline |
15034 | sip_mime_version_t *sip_mime_version_copy(su_home_t *home, sip_mime_version_t const *hdr) |
15035 | { |
15036 | return (sip_mime_version_t *) |
15037 | msg_header_copy_as(home, sip_mime_version_class, (msg_header_t const *)hdr); |
15038 | } |
15039 | #endif |
15040 | |
15041 | /**Make a @ref sip_mime_version "MIME-Version header" structure #sip_mime_version_t. |
15042 | * |
15043 | * The function sip_mime_version_make() makes a new |
15044 | * #sip_mime_version_t header structure. It allocates a new |
15045 | * header structure, and decodes the string @a s as the |
15046 | * value of the structure. |
15047 | * |
15048 | * @param home memory home used to allocate new header structure. |
15049 | * @param s string to be decoded as value of the new header structure |
15050 | * |
15051 | * @return |
15052 | * A pointer to newly maked #sip_mime_version_t header structure, or NULL upon an |
15053 | * error. |
15054 | * |
15055 | */ |
15056 | #if SU_HAVE_INLINE1 |
15057 | su_inlinestatic inline |
15058 | #endif |
15059 | sip_mime_version_t *sip_mime_version_make(su_home_t *home, char const *s) |
15060 | __attribute__((__malloc__)); |
15061 | |
15062 | #if SU_HAVE_INLINE1 |
15063 | su_inlinestatic inline sip_mime_version_t *sip_mime_version_make(su_home_t *home, char const *s) |
15064 | { |
15065 | return (sip_mime_version_t *)sip_header_make(home, sip_mime_version_class, s)((sip_header_t *)msg_header_make((home), (sip_mime_version_class ), (s))); |
15066 | } |
15067 | #endif |
15068 | |
15069 | /**Make a @ref sip_mime_version "MIME-Version header" from formatting result. |
15070 | * |
15071 | * Make a new #sip_mime_version_t object using formatting result as its value. |
15072 | * The function first prints the arguments according to the format @a fmt |
15073 | * specified. Then it allocates a new header structure, and parses the |
15074 | * formatting result to the structure #sip_mime_version_t. |
15075 | * |
15076 | * @param home memory home used to allocate new header structure. |
15077 | * @param fmt string used as a printf()-style format |
15078 | * @param ... argument list for format |
15079 | * |
15080 | * @return |
15081 | * A pointer to newly |
15082 | * makes header structure, or NULL upon an error. |
15083 | * |
15084 | * @HIDE |
15085 | * |
15086 | */ |
15087 | #if SU_HAVE_INLINE1 |
15088 | su_inlinestatic inline |
15089 | #endif |
15090 | sip_mime_version_t *sip_mime_version_format(su_home_t *home, char const *fmt, ...) |
15091 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
15092 | |
15093 | #if SU_HAVE_INLINE1 |
15094 | su_inlinestatic inline sip_mime_version_t *sip_mime_version_format(su_home_t *home, char const *fmt, ...) |
15095 | { |
15096 | sip_header_t *h; |
15097 | va_list ap; |
15098 | |
15099 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
15100 | h = sip_header_vformat(home, sip_mime_version_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_mime_version_class ), (fmt), (ap))); |
15101 | va_end(ap)__builtin_va_end(ap); |
15102 | |
15103 | return (sip_mime_version_t *)h; |
15104 | } |
15105 | #endif |
15106 | |
15107 | /** @} */ |
15108 | |
15109 | /**@addtogroup sip_content_type |
15110 | * @{ |
15111 | */ |
15112 | |
15113 | /** Parse a SIP @ref sip_content_type "Content-Type header". @internal */ |
15114 | SOFIAPUBFUN issize_t sip_content_type_d(su_home_t *, msg_header_t *, |
15115 | char *s, isize_t slen); |
15116 | |
15117 | /** Print a SIP @ref sip_content_type "Content-Type header". @internal */ |
15118 | SOFIAPUBFUN issize_t sip_content_type_e(char b[], isize_t bsiz, |
15119 | msg_header_t const *h, int flags); |
15120 | |
15121 | /**Access a SIP @ref sip_content_type "Content-Type header" |
15122 | * structure #sip_content_type_t from #sip_t. |
15123 | * |
15124 | */ |
15125 | #define sip_content_type(sip)((sip_content_type_t *)msg_header_access((msg_pub_t*)(sip), sip_content_type_class )) \ |
15126 | ((sip_content_type_t *)msg_header_access((msg_pub_t*)(sip), sip_content_type_class)) |
15127 | |
15128 | /**Initializer for structure #sip_content_type_t. |
15129 | * |
15130 | * A static #sip_content_type_t structure for |
15131 | * @ref sip_content_type "Content-Type header" must be initialized with |
15132 | * the SIP_CONTENT_TYPE_INIT() macro. |
15133 | * For instance, |
15134 | * @code |
15135 | * |
15136 | * sip_content_type_t sip_content_type = SIP_CONTENT_TYPE_INIT; |
15137 | * |
15138 | * @endcode |
15139 | * @HI |
15140 | * |
15141 | */ |
15142 | #define SIP_CONTENT_TYPE_INIT(){{{ 0, 0, sip_content_type_class }}} SIP_HDR_INIT(content_type){{{ 0, 0, sip_content_type_class }}} |
15143 | |
15144 | /**Initialize a structure #sip_content_type_t. |
15145 | * |
15146 | * An #sip_content_type_t structure for |
15147 | * @ref sip_content_type "Content-Type header" can be initialized with the |
15148 | * sip_content_type_init() function/macro. For instance, |
15149 | * @code |
15150 | * |
15151 | * sip_content_type_t sip_content_type; |
15152 | * |
15153 | * sip_content_type_init(&sip_content_type); |
15154 | * |
15155 | * @endcode |
15156 | * @HI |
15157 | * |
15158 | */ |
15159 | #if SU_HAVE_INLINE1 |
15160 | su_inlinestatic inline sip_content_type_t *sip_content_type_init(sip_content_type_t x[1]) |
15161 | { |
15162 | return SIP_HEADER_INIT(x, sip_content_type_class, sizeof(sip_content_type_t))((void)memset((x), 0, (sizeof(sip_content_type_t))), (void)(( (sip_common_t *)(x))->h_class = (sip_content_type_class)), (x)); |
15163 | } |
15164 | #else |
15165 | #define sip_content_type_init(x) \ |
15166 | SIP_HEADER_INIT(x, sip_content_type_class, sizeof(sip_content_type_t))((void)memset((x), 0, (sizeof(sip_content_type_t))), (void)(( (sip_common_t *)(x))->h_class = (sip_content_type_class)), (x)) |
15167 | #endif |
15168 | |
15169 | /**Test if header object is instance of #sip_content_type_t. |
15170 | * |
15171 | * Check if the header class is an instance of |
15172 | * @ref sip_content_type "Content-Type header" object and return true (nonzero), |
15173 | * otherwise return false (zero). |
15174 | * |
15175 | * @param header pointer to the header structure to be tested |
15176 | * |
15177 | * @retval 1 (true) if the @a header is an instance of header content_type |
15178 | * @retval 0 (false) otherwise |
15179 | * |
15180 | */ |
15181 | #if SU_HAVE_INLINE1 |
15182 | su_inlinestatic inline int sip_is_content_type(sip_header_t const *header) |
15183 | { |
15184 | return header && header->sh_classsh_common->h_class->hc_hash == sip_content_type_hash; |
15185 | } |
15186 | #else |
15187 | int sip_is_content_type(sip_header_t const *header); |
15188 | #endif |
15189 | |
15190 | #define sip_content_type_p(h)sip_is_content_type((h)) sip_is_content_type((h)) |
15191 | |
15192 | |
15193 | /**Duplicate a list of @ref sip_content_type "Content-Type header" header structures #sip_content_type_t. |
15194 | * |
15195 | * Duplicate a header |
15196 | * structure @a hdr. If the header structure @a hdr |
15197 | * contains a reference (@c hdr->x_next) to a list of |
15198 | * headers, all the headers in the list are duplicated, too. |
15199 | * |
15200 | * @param home memory home used to allocate new structure |
15201 | * @param hdr header structure to be duplicated |
15202 | * |
15203 | * When duplicating, all parameter lists and non-constant |
15204 | * strings attached to the header are copied, too. The |
15205 | * function uses given memory @a home to allocate all the |
15206 | * memory areas used to copy the header. |
15207 | * |
15208 | * @par Example |
15209 | * @code |
15210 | * |
15211 | * content_type = sip_content_type_dup(home, sip->sip_content_type); |
15212 | * |
15213 | * @endcode |
15214 | * |
15215 | * @return |
15216 | * A pointer to the |
15217 | * newly duplicated #sip_content_type_t header structure, or NULL |
15218 | * upon an error. |
15219 | * |
15220 | */ |
15221 | #if SU_HAVE_INLINE1 |
15222 | su_inlinestatic inline |
15223 | #endif |
15224 | sip_content_type_t *sip_content_type_dup(su_home_t *home, sip_content_type_t const *hdr) |
15225 | __attribute__((__malloc__)); |
15226 | |
15227 | #if SU_HAVE_INLINE1 |
15228 | su_inlinestatic inline |
15229 | sip_content_type_t *sip_content_type_dup(su_home_t *home, sip_content_type_t const *hdr) |
15230 | { |
15231 | return (sip_content_type_t *) |
15232 | msg_header_dup_as(home, sip_content_type_class, (msg_header_t const *)hdr); |
15233 | } |
15234 | #endif |
15235 | |
15236 | /**Copy a list of @ref sip_content_type "Content-Type header" header structures #sip_content_type_t. |
15237 | * |
15238 | * The function sip_content_type_copy() copies a header structure @a |
15239 | * hdr. If the header structure @a hdr contains a reference (@c |
15240 | * hdr->h_next) to a list of headers, all the headers in that |
15241 | * list are copied, too. The function uses given memory @a home |
15242 | * to allocate all the memory areas used to copy the list of header |
15243 | * structure @a hdr. |
15244 | * |
15245 | * @param home memory home used to allocate new structure |
15246 | * @param hdr pointer to the header structure to be copied |
15247 | * |
15248 | * When copying, only the header structure and parameter lists attached to |
15249 | * it are duplicated. The new header structure retains all the references to |
15250 | * the strings within the old @a hdr header, including the encoding of the |
15251 | * old header, if present. |
15252 | * |
15253 | * @par Example |
15254 | * @code |
15255 | * |
15256 | * content_type = sip_content_type_copy(home, sip->sip_content_type); |
15257 | * |
15258 | * @endcode |
15259 | * |
15260 | * @return |
15261 | * A pointer to newly copied header structure, or NULL upon an error. |
15262 | * |
15263 | */ |
15264 | #if SU_HAVE_INLINE1 |
15265 | su_inlinestatic inline |
15266 | #endif |
15267 | sip_content_type_t *sip_content_type_copy(su_home_t *home, sip_content_type_t const *hdr) |
15268 | __attribute__((__malloc__)); |
15269 | |
15270 | #if SU_HAVE_INLINE1 |
15271 | su_inlinestatic inline |
15272 | sip_content_type_t *sip_content_type_copy(su_home_t *home, sip_content_type_t const *hdr) |
15273 | { |
15274 | return (sip_content_type_t *) |
15275 | msg_header_copy_as(home, sip_content_type_class, (msg_header_t const *)hdr); |
15276 | } |
15277 | #endif |
15278 | |
15279 | /**Make a @ref sip_content_type "Content-Type header" structure #sip_content_type_t. |
15280 | * |
15281 | * The function sip_content_type_make() makes a new |
15282 | * #sip_content_type_t header structure. It allocates a new |
15283 | * header structure, and decodes the string @a s as the |
15284 | * value of the structure. |
15285 | * |
15286 | * @param home memory home used to allocate new header structure. |
15287 | * @param s string to be decoded as value of the new header structure |
15288 | * |
15289 | * @return |
15290 | * A pointer to newly maked #sip_content_type_t header structure, or NULL upon an |
15291 | * error. |
15292 | * |
15293 | */ |
15294 | #if SU_HAVE_INLINE1 |
15295 | su_inlinestatic inline |
15296 | #endif |
15297 | sip_content_type_t *sip_content_type_make(su_home_t *home, char const *s) |
15298 | __attribute__((__malloc__)); |
15299 | |
15300 | #if SU_HAVE_INLINE1 |
15301 | su_inlinestatic inline sip_content_type_t *sip_content_type_make(su_home_t *home, char const *s) |
15302 | { |
15303 | return (sip_content_type_t *)sip_header_make(home, sip_content_type_class, s)((sip_header_t *)msg_header_make((home), (sip_content_type_class ), (s))); |
15304 | } |
15305 | #endif |
15306 | |
15307 | /**Make a @ref sip_content_type "Content-Type header" from formatting result. |
15308 | * |
15309 | * Make a new #sip_content_type_t object using formatting result as its value. |
15310 | * The function first prints the arguments according to the format @a fmt |
15311 | * specified. Then it allocates a new header structure, and parses the |
15312 | * formatting result to the structure #sip_content_type_t. |
15313 | * |
15314 | * @param home memory home used to allocate new header structure. |
15315 | * @param fmt string used as a printf()-style format |
15316 | * @param ... argument list for format |
15317 | * |
15318 | * @return |
15319 | * A pointer to newly |
15320 | * makes header structure, or NULL upon an error. |
15321 | * |
15322 | * @HIDE |
15323 | * |
15324 | */ |
15325 | #if SU_HAVE_INLINE1 |
15326 | su_inlinestatic inline |
15327 | #endif |
15328 | sip_content_type_t *sip_content_type_format(su_home_t *home, char const *fmt, ...) |
15329 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
15330 | |
15331 | #if SU_HAVE_INLINE1 |
15332 | su_inlinestatic inline sip_content_type_t *sip_content_type_format(su_home_t *home, char const *fmt, ...) |
15333 | { |
15334 | sip_header_t *h; |
15335 | va_list ap; |
15336 | |
15337 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
15338 | h = sip_header_vformat(home, sip_content_type_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_content_type_class ), (fmt), (ap))); |
15339 | va_end(ap)__builtin_va_end(ap); |
15340 | |
15341 | return (sip_content_type_t *)h; |
15342 | } |
15343 | #endif |
15344 | |
15345 | /** @} */ |
15346 | |
15347 | /**@addtogroup sip_content_encoding |
15348 | * @{ |
15349 | */ |
15350 | |
15351 | /** Parse a SIP @ref sip_content_encoding "Content-Encoding header". @internal */ |
15352 | SOFIAPUBFUN issize_t sip_content_encoding_d(su_home_t *, msg_header_t *, |
15353 | char *s, isize_t slen); |
15354 | |
15355 | /** Print a SIP @ref sip_content_encoding "Content-Encoding header". @internal */ |
15356 | SOFIAPUBFUN issize_t sip_content_encoding_e(char b[], isize_t bsiz, |
15357 | msg_header_t const *h, int flags); |
15358 | |
15359 | /**Access a SIP @ref sip_content_encoding "Content-Encoding header" |
15360 | * structure #sip_content_encoding_t from #sip_t. |
15361 | * |
15362 | */ |
15363 | #define sip_content_encoding(sip)((sip_content_encoding_t *)msg_header_access((msg_pub_t*)(sip ), sip_content_encoding_class)) \ |
15364 | ((sip_content_encoding_t *)msg_header_access((msg_pub_t*)(sip), sip_content_encoding_class)) |
15365 | |
15366 | /**Initializer for structure #sip_content_encoding_t. |
15367 | * |
15368 | * A static #sip_content_encoding_t structure for |
15369 | * @ref sip_content_encoding "Content-Encoding header" must be initialized with |
15370 | * the SIP_CONTENT_ENCODING_INIT() macro. |
15371 | * For instance, |
15372 | * @code |
15373 | * |
15374 | * sip_content_encoding_t sip_content_encoding = SIP_CONTENT_ENCODING_INIT; |
15375 | * |
15376 | * @endcode |
15377 | * @HI |
15378 | * |
15379 | */ |
15380 | #define SIP_CONTENT_ENCODING_INIT(){{{ 0, 0, sip_content_encoding_class }}} SIP_HDR_INIT(content_encoding){{{ 0, 0, sip_content_encoding_class }}} |
15381 | |
15382 | /**Initialize a structure #sip_content_encoding_t. |
15383 | * |
15384 | * An #sip_content_encoding_t structure for |
15385 | * @ref sip_content_encoding "Content-Encoding header" can be initialized with the |
15386 | * sip_content_encoding_init() function/macro. For instance, |
15387 | * @code |
15388 | * |
15389 | * sip_content_encoding_t sip_content_encoding; |
15390 | * |
15391 | * sip_content_encoding_init(&sip_content_encoding); |
15392 | * |
15393 | * @endcode |
15394 | * @HI |
15395 | * |
15396 | */ |
15397 | #if SU_HAVE_INLINE1 |
15398 | su_inlinestatic inline sip_content_encoding_t *sip_content_encoding_init(sip_content_encoding_t x[1]) |
15399 | { |
15400 | return SIP_HEADER_INIT(x, sip_content_encoding_class, sizeof(sip_content_encoding_t))((void)memset((x), 0, (sizeof(sip_content_encoding_t))), (void )(((sip_common_t *)(x))->h_class = (sip_content_encoding_class )), (x)); |
15401 | } |
15402 | #else |
15403 | #define sip_content_encoding_init(x) \ |
15404 | SIP_HEADER_INIT(x, sip_content_encoding_class, sizeof(sip_content_encoding_t))((void)memset((x), 0, (sizeof(sip_content_encoding_t))), (void )(((sip_common_t *)(x))->h_class = (sip_content_encoding_class )), (x)) |
15405 | #endif |
15406 | |
15407 | /**Test if header object is instance of #sip_content_encoding_t. |
15408 | * |
15409 | * Check if the header class is an instance of |
15410 | * @ref sip_content_encoding "Content-Encoding header" object and return true (nonzero), |
15411 | * otherwise return false (zero). |
15412 | * |
15413 | * @param header pointer to the header structure to be tested |
15414 | * |
15415 | * @retval 1 (true) if the @a header is an instance of header content_encoding |
15416 | * @retval 0 (false) otherwise |
15417 | * |
15418 | */ |
15419 | #if SU_HAVE_INLINE1 |
15420 | su_inlinestatic inline int sip_is_content_encoding(sip_header_t const *header) |
15421 | { |
15422 | return header && header->sh_classsh_common->h_class->hc_hash == sip_content_encoding_hash; |
15423 | } |
15424 | #else |
15425 | int sip_is_content_encoding(sip_header_t const *header); |
15426 | #endif |
15427 | |
15428 | #define sip_content_encoding_p(h)sip_is_content_encoding((h)) sip_is_content_encoding((h)) |
15429 | |
15430 | |
15431 | /**Duplicate a list of @ref sip_content_encoding "Content-Encoding header" header structures #sip_content_encoding_t. |
15432 | * |
15433 | * Duplicate a header |
15434 | * structure @a hdr. If the header structure @a hdr |
15435 | * contains a reference (@c hdr->x_next) to a list of |
15436 | * headers, all the headers in the list are duplicated, too. |
15437 | * |
15438 | * @param home memory home used to allocate new structure |
15439 | * @param hdr header structure to be duplicated |
15440 | * |
15441 | * When duplicating, all parameter lists and non-constant |
15442 | * strings attached to the header are copied, too. The |
15443 | * function uses given memory @a home to allocate all the |
15444 | * memory areas used to copy the header. |
15445 | * |
15446 | * @par Example |
15447 | * @code |
15448 | * |
15449 | * content_encoding = sip_content_encoding_dup(home, sip->sip_content_encoding); |
15450 | * |
15451 | * @endcode |
15452 | * |
15453 | * @return |
15454 | * A pointer to the |
15455 | * newly duplicated #sip_content_encoding_t header structure, or NULL |
15456 | * upon an error. |
15457 | * |
15458 | */ |
15459 | #if SU_HAVE_INLINE1 |
15460 | su_inlinestatic inline |
15461 | #endif |
15462 | sip_content_encoding_t *sip_content_encoding_dup(su_home_t *home, sip_content_encoding_t const *hdr) |
15463 | __attribute__((__malloc__)); |
15464 | |
15465 | #if SU_HAVE_INLINE1 |
15466 | su_inlinestatic inline |
15467 | sip_content_encoding_t *sip_content_encoding_dup(su_home_t *home, sip_content_encoding_t const *hdr) |
15468 | { |
15469 | return (sip_content_encoding_t *) |
15470 | msg_header_dup_as(home, sip_content_encoding_class, (msg_header_t const *)hdr); |
15471 | } |
15472 | #endif |
15473 | |
15474 | /**Copy a list of @ref sip_content_encoding "Content-Encoding header" header structures #sip_content_encoding_t. |
15475 | * |
15476 | * The function sip_content_encoding_copy() copies a header structure @a |
15477 | * hdr. If the header structure @a hdr contains a reference (@c |
15478 | * hdr->h_next) to a list of headers, all the headers in that |
15479 | * list are copied, too. The function uses given memory @a home |
15480 | * to allocate all the memory areas used to copy the list of header |
15481 | * structure @a hdr. |
15482 | * |
15483 | * @param home memory home used to allocate new structure |
15484 | * @param hdr pointer to the header structure to be copied |
15485 | * |
15486 | * When copying, only the header structure and parameter lists attached to |
15487 | * it are duplicated. The new header structure retains all the references to |
15488 | * the strings within the old @a hdr header, including the encoding of the |
15489 | * old header, if present. |
15490 | * |
15491 | * @par Example |
15492 | * @code |
15493 | * |
15494 | * content_encoding = sip_content_encoding_copy(home, sip->sip_content_encoding); |
15495 | * |
15496 | * @endcode |
15497 | * |
15498 | * @return |
15499 | * A pointer to newly copied header structure, or NULL upon an error. |
15500 | * |
15501 | */ |
15502 | #if SU_HAVE_INLINE1 |
15503 | su_inlinestatic inline |
15504 | #endif |
15505 | sip_content_encoding_t *sip_content_encoding_copy(su_home_t *home, sip_content_encoding_t const *hdr) |
15506 | __attribute__((__malloc__)); |
15507 | |
15508 | #if SU_HAVE_INLINE1 |
15509 | su_inlinestatic inline |
15510 | sip_content_encoding_t *sip_content_encoding_copy(su_home_t *home, sip_content_encoding_t const *hdr) |
15511 | { |
15512 | return (sip_content_encoding_t *) |
15513 | msg_header_copy_as(home, sip_content_encoding_class, (msg_header_t const *)hdr); |
15514 | } |
15515 | #endif |
15516 | |
15517 | /**Make a @ref sip_content_encoding "Content-Encoding header" structure #sip_content_encoding_t. |
15518 | * |
15519 | * The function sip_content_encoding_make() makes a new |
15520 | * #sip_content_encoding_t header structure. It allocates a new |
15521 | * header structure, and decodes the string @a s as the |
15522 | * value of the structure. |
15523 | * |
15524 | * @param home memory home used to allocate new header structure. |
15525 | * @param s string to be decoded as value of the new header structure |
15526 | * |
15527 | * @return |
15528 | * A pointer to newly maked #sip_content_encoding_t header structure, or NULL upon an |
15529 | * error. |
15530 | * |
15531 | */ |
15532 | #if SU_HAVE_INLINE1 |
15533 | su_inlinestatic inline |
15534 | #endif |
15535 | sip_content_encoding_t *sip_content_encoding_make(su_home_t *home, char const *s) |
15536 | __attribute__((__malloc__)); |
15537 | |
15538 | #if SU_HAVE_INLINE1 |
15539 | su_inlinestatic inline sip_content_encoding_t *sip_content_encoding_make(su_home_t *home, char const *s) |
15540 | { |
15541 | return (sip_content_encoding_t *)sip_header_make(home, sip_content_encoding_class, s)((sip_header_t *)msg_header_make((home), (sip_content_encoding_class ), (s))); |
15542 | } |
15543 | #endif |
15544 | |
15545 | /**Make a @ref sip_content_encoding "Content-Encoding header" from formatting result. |
15546 | * |
15547 | * Make a new #sip_content_encoding_t object using formatting result as its value. |
15548 | * The function first prints the arguments according to the format @a fmt |
15549 | * specified. Then it allocates a new header structure, and parses the |
15550 | * formatting result to the structure #sip_content_encoding_t. |
15551 | * |
15552 | * @param home memory home used to allocate new header structure. |
15553 | * @param fmt string used as a printf()-style format |
15554 | * @param ... argument list for format |
15555 | * |
15556 | * @return |
15557 | * A pointer to newly |
15558 | * makes header structure, or NULL upon an error. |
15559 | * |
15560 | * @HIDE |
15561 | * |
15562 | */ |
15563 | #if SU_HAVE_INLINE1 |
15564 | su_inlinestatic inline |
15565 | #endif |
15566 | sip_content_encoding_t *sip_content_encoding_format(su_home_t *home, char const *fmt, ...) |
15567 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
15568 | |
15569 | #if SU_HAVE_INLINE1 |
15570 | su_inlinestatic inline sip_content_encoding_t *sip_content_encoding_format(su_home_t *home, char const *fmt, ...) |
15571 | { |
15572 | sip_header_t *h; |
15573 | va_list ap; |
15574 | |
15575 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
15576 | h = sip_header_vformat(home, sip_content_encoding_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_content_encoding_class ), (fmt), (ap))); |
15577 | va_end(ap)__builtin_va_end(ap); |
15578 | |
15579 | return (sip_content_encoding_t *)h; |
15580 | } |
15581 | #endif |
15582 | |
15583 | /** @} */ |
15584 | |
15585 | /**@addtogroup sip_content_language |
15586 | * @{ |
15587 | */ |
15588 | |
15589 | /** Parse a SIP @ref sip_content_language "Content-Language header". @internal */ |
15590 | SOFIAPUBFUN issize_t sip_content_language_d(su_home_t *, msg_header_t *, |
15591 | char *s, isize_t slen); |
15592 | |
15593 | /** Print a SIP @ref sip_content_language "Content-Language header". @internal */ |
15594 | SOFIAPUBFUN issize_t sip_content_language_e(char b[], isize_t bsiz, |
15595 | msg_header_t const *h, int flags); |
15596 | |
15597 | /**Access a SIP @ref sip_content_language "Content-Language header" |
15598 | * structure #sip_content_language_t from #sip_t. |
15599 | * |
15600 | */ |
15601 | #define sip_content_language(sip)((sip_content_language_t *)msg_header_access((msg_pub_t*)(sip ), sip_content_language_class)) \ |
15602 | ((sip_content_language_t *)msg_header_access((msg_pub_t*)(sip), sip_content_language_class)) |
15603 | |
15604 | /**Initializer for structure #sip_content_language_t. |
15605 | * |
15606 | * A static #sip_content_language_t structure for |
15607 | * @ref sip_content_language "Content-Language header" must be initialized with |
15608 | * the SIP_CONTENT_LANGUAGE_INIT() macro. |
15609 | * For instance, |
15610 | * @code |
15611 | * |
15612 | * sip_content_language_t sip_content_language = SIP_CONTENT_LANGUAGE_INIT; |
15613 | * |
15614 | * @endcode |
15615 | * @HI |
15616 | * |
15617 | */ |
15618 | #define SIP_CONTENT_LANGUAGE_INIT(){{{ 0, 0, sip_content_language_class }}} SIP_HDR_INIT(content_language){{{ 0, 0, sip_content_language_class }}} |
15619 | |
15620 | /**Initialize a structure #sip_content_language_t. |
15621 | * |
15622 | * An #sip_content_language_t structure for |
15623 | * @ref sip_content_language "Content-Language header" can be initialized with the |
15624 | * sip_content_language_init() function/macro. For instance, |
15625 | * @code |
15626 | * |
15627 | * sip_content_language_t sip_content_language; |
15628 | * |
15629 | * sip_content_language_init(&sip_content_language); |
15630 | * |
15631 | * @endcode |
15632 | * @HI |
15633 | * |
15634 | */ |
15635 | #if SU_HAVE_INLINE1 |
15636 | su_inlinestatic inline sip_content_language_t *sip_content_language_init(sip_content_language_t x[1]) |
15637 | { |
15638 | return SIP_HEADER_INIT(x, sip_content_language_class, sizeof(sip_content_language_t))((void)memset((x), 0, (sizeof(sip_content_language_t))), (void )(((sip_common_t *)(x))->h_class = (sip_content_language_class )), (x)); |
15639 | } |
15640 | #else |
15641 | #define sip_content_language_init(x) \ |
15642 | SIP_HEADER_INIT(x, sip_content_language_class, sizeof(sip_content_language_t))((void)memset((x), 0, (sizeof(sip_content_language_t))), (void )(((sip_common_t *)(x))->h_class = (sip_content_language_class )), (x)) |
15643 | #endif |
15644 | |
15645 | /**Test if header object is instance of #sip_content_language_t. |
15646 | * |
15647 | * Check if the header class is an instance of |
15648 | * @ref sip_content_language "Content-Language header" object and return true (nonzero), |
15649 | * otherwise return false (zero). |
15650 | * |
15651 | * @param header pointer to the header structure to be tested |
15652 | * |
15653 | * @retval 1 (true) if the @a header is an instance of header content_language |
15654 | * @retval 0 (false) otherwise |
15655 | * |
15656 | */ |
15657 | #if SU_HAVE_INLINE1 |
15658 | su_inlinestatic inline int sip_is_content_language(sip_header_t const *header) |
15659 | { |
15660 | return header && header->sh_classsh_common->h_class->hc_hash == sip_content_language_hash; |
15661 | } |
15662 | #else |
15663 | int sip_is_content_language(sip_header_t const *header); |
15664 | #endif |
15665 | |
15666 | #define sip_content_language_p(h)sip_is_content_language((h)) sip_is_content_language((h)) |
15667 | |
15668 | |
15669 | /**Duplicate a list of @ref sip_content_language "Content-Language header" header structures #sip_content_language_t. |
15670 | * |
15671 | * Duplicate a header |
15672 | * structure @a hdr. If the header structure @a hdr |
15673 | * contains a reference (@c hdr->x_next) to a list of |
15674 | * headers, all the headers in the list are duplicated, too. |
15675 | * |
15676 | * @param home memory home used to allocate new structure |
15677 | * @param hdr header structure to be duplicated |
15678 | * |
15679 | * When duplicating, all parameter lists and non-constant |
15680 | * strings attached to the header are copied, too. The |
15681 | * function uses given memory @a home to allocate all the |
15682 | * memory areas used to copy the header. |
15683 | * |
15684 | * @par Example |
15685 | * @code |
15686 | * |
15687 | * content_language = sip_content_language_dup(home, sip->sip_content_language); |
15688 | * |
15689 | * @endcode |
15690 | * |
15691 | * @return |
15692 | * A pointer to the |
15693 | * newly duplicated #sip_content_language_t header structure, or NULL |
15694 | * upon an error. |
15695 | * |
15696 | */ |
15697 | #if SU_HAVE_INLINE1 |
15698 | su_inlinestatic inline |
15699 | #endif |
15700 | sip_content_language_t *sip_content_language_dup(su_home_t *home, sip_content_language_t const *hdr) |
15701 | __attribute__((__malloc__)); |
15702 | |
15703 | #if SU_HAVE_INLINE1 |
15704 | su_inlinestatic inline |
15705 | sip_content_language_t *sip_content_language_dup(su_home_t *home, sip_content_language_t const *hdr) |
15706 | { |
15707 | return (sip_content_language_t *) |
15708 | msg_header_dup_as(home, sip_content_language_class, (msg_header_t const *)hdr); |
15709 | } |
15710 | #endif |
15711 | |
15712 | /**Copy a list of @ref sip_content_language "Content-Language header" header structures #sip_content_language_t. |
15713 | * |
15714 | * The function sip_content_language_copy() copies a header structure @a |
15715 | * hdr. If the header structure @a hdr contains a reference (@c |
15716 | * hdr->h_next) to a list of headers, all the headers in that |
15717 | * list are copied, too. The function uses given memory @a home |
15718 | * to allocate all the memory areas used to copy the list of header |
15719 | * structure @a hdr. |
15720 | * |
15721 | * @param home memory home used to allocate new structure |
15722 | * @param hdr pointer to the header structure to be copied |
15723 | * |
15724 | * When copying, only the header structure and parameter lists attached to |
15725 | * it are duplicated. The new header structure retains all the references to |
15726 | * the strings within the old @a hdr header, including the encoding of the |
15727 | * old header, if present. |
15728 | * |
15729 | * @par Example |
15730 | * @code |
15731 | * |
15732 | * content_language = sip_content_language_copy(home, sip->sip_content_language); |
15733 | * |
15734 | * @endcode |
15735 | * |
15736 | * @return |
15737 | * A pointer to newly copied header structure, or NULL upon an error. |
15738 | * |
15739 | */ |
15740 | #if SU_HAVE_INLINE1 |
15741 | su_inlinestatic inline |
15742 | #endif |
15743 | sip_content_language_t *sip_content_language_copy(su_home_t *home, sip_content_language_t const *hdr) |
15744 | __attribute__((__malloc__)); |
15745 | |
15746 | #if SU_HAVE_INLINE1 |
15747 | su_inlinestatic inline |
15748 | sip_content_language_t *sip_content_language_copy(su_home_t *home, sip_content_language_t const *hdr) |
15749 | { |
15750 | return (sip_content_language_t *) |
15751 | msg_header_copy_as(home, sip_content_language_class, (msg_header_t const *)hdr); |
15752 | } |
15753 | #endif |
15754 | |
15755 | /**Make a @ref sip_content_language "Content-Language header" structure #sip_content_language_t. |
15756 | * |
15757 | * The function sip_content_language_make() makes a new |
15758 | * #sip_content_language_t header structure. It allocates a new |
15759 | * header structure, and decodes the string @a s as the |
15760 | * value of the structure. |
15761 | * |
15762 | * @param home memory home used to allocate new header structure. |
15763 | * @param s string to be decoded as value of the new header structure |
15764 | * |
15765 | * @return |
15766 | * A pointer to newly maked #sip_content_language_t header structure, or NULL upon an |
15767 | * error. |
15768 | * |
15769 | */ |
15770 | #if SU_HAVE_INLINE1 |
15771 | su_inlinestatic inline |
15772 | #endif |
15773 | sip_content_language_t *sip_content_language_make(su_home_t *home, char const *s) |
15774 | __attribute__((__malloc__)); |
15775 | |
15776 | #if SU_HAVE_INLINE1 |
15777 | su_inlinestatic inline sip_content_language_t *sip_content_language_make(su_home_t *home, char const *s) |
15778 | { |
15779 | return (sip_content_language_t *)sip_header_make(home, sip_content_language_class, s)((sip_header_t *)msg_header_make((home), (sip_content_language_class ), (s))); |
15780 | } |
15781 | #endif |
15782 | |
15783 | /**Make a @ref sip_content_language "Content-Language header" from formatting result. |
15784 | * |
15785 | * Make a new #sip_content_language_t object using formatting result as its value. |
15786 | * The function first prints the arguments according to the format @a fmt |
15787 | * specified. Then it allocates a new header structure, and parses the |
15788 | * formatting result to the structure #sip_content_language_t. |
15789 | * |
15790 | * @param home memory home used to allocate new header structure. |
15791 | * @param fmt string used as a printf()-style format |
15792 | * @param ... argument list for format |
15793 | * |
15794 | * @return |
15795 | * A pointer to newly |
15796 | * makes header structure, or NULL upon an error. |
15797 | * |
15798 | * @HIDE |
15799 | * |
15800 | */ |
15801 | #if SU_HAVE_INLINE1 |
15802 | su_inlinestatic inline |
15803 | #endif |
15804 | sip_content_language_t *sip_content_language_format(su_home_t *home, char const *fmt, ...) |
15805 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
15806 | |
15807 | #if SU_HAVE_INLINE1 |
15808 | su_inlinestatic inline sip_content_language_t *sip_content_language_format(su_home_t *home, char const *fmt, ...) |
15809 | { |
15810 | sip_header_t *h; |
15811 | va_list ap; |
15812 | |
15813 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
15814 | h = sip_header_vformat(home, sip_content_language_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_content_language_class ), (fmt), (ap))); |
15815 | va_end(ap)__builtin_va_end(ap); |
15816 | |
15817 | return (sip_content_language_t *)h; |
15818 | } |
15819 | #endif |
15820 | |
15821 | /** @} */ |
15822 | |
15823 | /**@addtogroup sip_content_disposition |
15824 | * @{ |
15825 | */ |
15826 | |
15827 | /** Parse a SIP @ref sip_content_disposition "Content-Disposition header". @internal */ |
15828 | SOFIAPUBFUN issize_t sip_content_disposition_d(su_home_t *, msg_header_t *, |
15829 | char *s, isize_t slen); |
15830 | |
15831 | /** Print a SIP @ref sip_content_disposition "Content-Disposition header". @internal */ |
15832 | SOFIAPUBFUN issize_t sip_content_disposition_e(char b[], isize_t bsiz, |
15833 | msg_header_t const *h, int flags); |
15834 | |
15835 | /**Access a SIP @ref sip_content_disposition "Content-Disposition header" |
15836 | * structure #sip_content_disposition_t from #sip_t. |
15837 | * |
15838 | */ |
15839 | #define sip_content_disposition(sip)((sip_content_disposition_t *)msg_header_access((msg_pub_t*)( sip), sip_content_disposition_class)) \ |
15840 | ((sip_content_disposition_t *)msg_header_access((msg_pub_t*)(sip), sip_content_disposition_class)) |
15841 | |
15842 | /**Initializer for structure #sip_content_disposition_t. |
15843 | * |
15844 | * A static #sip_content_disposition_t structure for |
15845 | * @ref sip_content_disposition "Content-Disposition header" must be initialized with |
15846 | * the SIP_CONTENT_DISPOSITION_INIT() macro. |
15847 | * For instance, |
15848 | * @code |
15849 | * |
15850 | * sip_content_disposition_t sip_content_disposition = SIP_CONTENT_DISPOSITION_INIT; |
15851 | * |
15852 | * @endcode |
15853 | * @HI |
15854 | * |
15855 | */ |
15856 | #define SIP_CONTENT_DISPOSITION_INIT(){{{ 0, 0, sip_content_disposition_class }}} SIP_HDR_INIT(content_disposition){{{ 0, 0, sip_content_disposition_class }}} |
15857 | |
15858 | /**Initialize a structure #sip_content_disposition_t. |
15859 | * |
15860 | * An #sip_content_disposition_t structure for |
15861 | * @ref sip_content_disposition "Content-Disposition header" can be initialized with the |
15862 | * sip_content_disposition_init() function/macro. For instance, |
15863 | * @code |
15864 | * |
15865 | * sip_content_disposition_t sip_content_disposition; |
15866 | * |
15867 | * sip_content_disposition_init(&sip_content_disposition); |
15868 | * |
15869 | * @endcode |
15870 | * @HI |
15871 | * |
15872 | */ |
15873 | #if SU_HAVE_INLINE1 |
15874 | su_inlinestatic inline sip_content_disposition_t *sip_content_disposition_init(sip_content_disposition_t x[1]) |
15875 | { |
15876 | return SIP_HEADER_INIT(x, sip_content_disposition_class, sizeof(sip_content_disposition_t))((void)memset((x), 0, (sizeof(sip_content_disposition_t))), ( void)(((sip_common_t *)(x))->h_class = (sip_content_disposition_class )), (x)); |
15877 | } |
15878 | #else |
15879 | #define sip_content_disposition_init(x) \ |
15880 | SIP_HEADER_INIT(x, sip_content_disposition_class, sizeof(sip_content_disposition_t))((void)memset((x), 0, (sizeof(sip_content_disposition_t))), ( void)(((sip_common_t *)(x))->h_class = (sip_content_disposition_class )), (x)) |
15881 | #endif |
15882 | |
15883 | /**Test if header object is instance of #sip_content_disposition_t. |
15884 | * |
15885 | * Check if the header class is an instance of |
15886 | * @ref sip_content_disposition "Content-Disposition header" object and return true (nonzero), |
15887 | * otherwise return false (zero). |
15888 | * |
15889 | * @param header pointer to the header structure to be tested |
15890 | * |
15891 | * @retval 1 (true) if the @a header is an instance of header content_disposition |
15892 | * @retval 0 (false) otherwise |
15893 | * |
15894 | */ |
15895 | #if SU_HAVE_INLINE1 |
15896 | su_inlinestatic inline int sip_is_content_disposition(sip_header_t const *header) |
15897 | { |
15898 | return header && header->sh_classsh_common->h_class->hc_hash == sip_content_disposition_hash; |
15899 | } |
15900 | #else |
15901 | int sip_is_content_disposition(sip_header_t const *header); |
15902 | #endif |
15903 | |
15904 | #define sip_content_disposition_p(h)sip_is_content_disposition((h)) sip_is_content_disposition((h)) |
15905 | |
15906 | |
15907 | /**Duplicate a list of @ref sip_content_disposition "Content-Disposition header" header structures #sip_content_disposition_t. |
15908 | * |
15909 | * Duplicate a header |
15910 | * structure @a hdr. If the header structure @a hdr |
15911 | * contains a reference (@c hdr->x_next) to a list of |
15912 | * headers, all the headers in the list are duplicated, too. |
15913 | * |
15914 | * @param home memory home used to allocate new structure |
15915 | * @param hdr header structure to be duplicated |
15916 | * |
15917 | * When duplicating, all parameter lists and non-constant |
15918 | * strings attached to the header are copied, too. The |
15919 | * function uses given memory @a home to allocate all the |
15920 | * memory areas used to copy the header. |
15921 | * |
15922 | * @par Example |
15923 | * @code |
15924 | * |
15925 | * content_disposition = sip_content_disposition_dup(home, sip->sip_content_disposition); |
15926 | * |
15927 | * @endcode |
15928 | * |
15929 | * @return |
15930 | * A pointer to the |
15931 | * newly duplicated #sip_content_disposition_t header structure, or NULL |
15932 | * upon an error. |
15933 | * |
15934 | */ |
15935 | #if SU_HAVE_INLINE1 |
15936 | su_inlinestatic inline |
15937 | #endif |
15938 | sip_content_disposition_t *sip_content_disposition_dup(su_home_t *home, sip_content_disposition_t const *hdr) |
15939 | __attribute__((__malloc__)); |
15940 | |
15941 | #if SU_HAVE_INLINE1 |
15942 | su_inlinestatic inline |
15943 | sip_content_disposition_t *sip_content_disposition_dup(su_home_t *home, sip_content_disposition_t const *hdr) |
15944 | { |
15945 | return (sip_content_disposition_t *) |
15946 | msg_header_dup_as(home, sip_content_disposition_class, (msg_header_t const *)hdr); |
15947 | } |
15948 | #endif |
15949 | |
15950 | /**Copy a list of @ref sip_content_disposition "Content-Disposition header" header structures #sip_content_disposition_t. |
15951 | * |
15952 | * The function sip_content_disposition_copy() copies a header structure @a |
15953 | * hdr. If the header structure @a hdr contains a reference (@c |
15954 | * hdr->h_next) to a list of headers, all the headers in that |
15955 | * list are copied, too. The function uses given memory @a home |
15956 | * to allocate all the memory areas used to copy the list of header |
15957 | * structure @a hdr. |
15958 | * |
15959 | * @param home memory home used to allocate new structure |
15960 | * @param hdr pointer to the header structure to be copied |
15961 | * |
15962 | * When copying, only the header structure and parameter lists attached to |
15963 | * it are duplicated. The new header structure retains all the references to |
15964 | * the strings within the old @a hdr header, including the encoding of the |
15965 | * old header, if present. |
15966 | * |
15967 | * @par Example |
15968 | * @code |
15969 | * |
15970 | * content_disposition = sip_content_disposition_copy(home, sip->sip_content_disposition); |
15971 | * |
15972 | * @endcode |
15973 | * |
15974 | * @return |
15975 | * A pointer to newly copied header structure, or NULL upon an error. |
15976 | * |
15977 | */ |
15978 | #if SU_HAVE_INLINE1 |
15979 | su_inlinestatic inline |
15980 | #endif |
15981 | sip_content_disposition_t *sip_content_disposition_copy(su_home_t *home, sip_content_disposition_t const *hdr) |
15982 | __attribute__((__malloc__)); |
15983 | |
15984 | #if SU_HAVE_INLINE1 |
15985 | su_inlinestatic inline |
15986 | sip_content_disposition_t *sip_content_disposition_copy(su_home_t *home, sip_content_disposition_t const *hdr) |
15987 | { |
15988 | return (sip_content_disposition_t *) |
15989 | msg_header_copy_as(home, sip_content_disposition_class, (msg_header_t const *)hdr); |
15990 | } |
15991 | #endif |
15992 | |
15993 | /**Make a @ref sip_content_disposition "Content-Disposition header" structure #sip_content_disposition_t. |
15994 | * |
15995 | * The function sip_content_disposition_make() makes a new |
15996 | * #sip_content_disposition_t header structure. It allocates a new |
15997 | * header structure, and decodes the string @a s as the |
15998 | * value of the structure. |
15999 | * |
16000 | * @param home memory home used to allocate new header structure. |
16001 | * @param s string to be decoded as value of the new header structure |
16002 | * |
16003 | * @return |
16004 | * A pointer to newly maked #sip_content_disposition_t header structure, or NULL upon an |
16005 | * error. |
16006 | * |
16007 | */ |
16008 | #if SU_HAVE_INLINE1 |
16009 | su_inlinestatic inline |
16010 | #endif |
16011 | sip_content_disposition_t *sip_content_disposition_make(su_home_t *home, char const *s) |
16012 | __attribute__((__malloc__)); |
16013 | |
16014 | #if SU_HAVE_INLINE1 |
16015 | su_inlinestatic inline sip_content_disposition_t *sip_content_disposition_make(su_home_t *home, char const *s) |
16016 | { |
16017 | return (sip_content_disposition_t *)sip_header_make(home, sip_content_disposition_class, s)((sip_header_t *)msg_header_make((home), (sip_content_disposition_class ), (s))); |
16018 | } |
16019 | #endif |
16020 | |
16021 | /**Make a @ref sip_content_disposition "Content-Disposition header" from formatting result. |
16022 | * |
16023 | * Make a new #sip_content_disposition_t object using formatting result as its value. |
16024 | * The function first prints the arguments according to the format @a fmt |
16025 | * specified. Then it allocates a new header structure, and parses the |
16026 | * formatting result to the structure #sip_content_disposition_t. |
16027 | * |
16028 | * @param home memory home used to allocate new header structure. |
16029 | * @param fmt string used as a printf()-style format |
16030 | * @param ... argument list for format |
16031 | * |
16032 | * @return |
16033 | * A pointer to newly |
16034 | * makes header structure, or NULL upon an error. |
16035 | * |
16036 | * @HIDE |
16037 | * |
16038 | */ |
16039 | #if SU_HAVE_INLINE1 |
16040 | su_inlinestatic inline |
16041 | #endif |
16042 | sip_content_disposition_t *sip_content_disposition_format(su_home_t *home, char const *fmt, ...) |
16043 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
16044 | |
16045 | #if SU_HAVE_INLINE1 |
16046 | su_inlinestatic inline sip_content_disposition_t *sip_content_disposition_format(su_home_t *home, char const *fmt, ...) |
16047 | { |
16048 | sip_header_t *h; |
16049 | va_list ap; |
16050 | |
16051 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
16052 | h = sip_header_vformat(home, sip_content_disposition_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_content_disposition_class ), (fmt), (ap))); |
16053 | va_end(ap)__builtin_va_end(ap); |
16054 | |
16055 | return (sip_content_disposition_t *)h; |
16056 | } |
16057 | #endif |
16058 | |
16059 | /** @} */ |
16060 | |
16061 | /**@addtogroup sip_content_length |
16062 | * @{ |
16063 | */ |
16064 | |
16065 | /** Parse a SIP @ref sip_content_length "Content-Length header". @internal */ |
16066 | SOFIAPUBFUN issize_t sip_content_length_d(su_home_t *, msg_header_t *, |
16067 | char *s, isize_t slen); |
16068 | |
16069 | /** Print a SIP @ref sip_content_length "Content-Length header". @internal */ |
16070 | SOFIAPUBFUN issize_t sip_content_length_e(char b[], isize_t bsiz, |
16071 | msg_header_t const *h, int flags); |
16072 | |
16073 | /**Access a SIP @ref sip_content_length "Content-Length header" |
16074 | * structure #sip_content_length_t from #sip_t. |
16075 | * |
16076 | */ |
16077 | #define sip_content_length(sip)((sip_content_length_t *)msg_header_access((msg_pub_t*)(sip), sip_content_length_class)) \ |
16078 | ((sip_content_length_t *)msg_header_access((msg_pub_t*)(sip), sip_content_length_class)) |
16079 | |
16080 | /**Initializer for structure #sip_content_length_t. |
16081 | * |
16082 | * A static #sip_content_length_t structure for |
16083 | * @ref sip_content_length "Content-Length header" must be initialized with |
16084 | * the SIP_CONTENT_LENGTH_INIT() macro. |
16085 | * For instance, |
16086 | * @code |
16087 | * |
16088 | * sip_content_length_t sip_content_length = SIP_CONTENT_LENGTH_INIT; |
16089 | * |
16090 | * @endcode |
16091 | * @HI |
16092 | * |
16093 | */ |
16094 | #define SIP_CONTENT_LENGTH_INIT(){{{ 0, 0, sip_content_length_class }}} SIP_HDR_INIT(content_length){{{ 0, 0, sip_content_length_class }}} |
16095 | |
16096 | /**Initialize a structure #sip_content_length_t. |
16097 | * |
16098 | * An #sip_content_length_t structure for |
16099 | * @ref sip_content_length "Content-Length header" can be initialized with the |
16100 | * sip_content_length_init() function/macro. For instance, |
16101 | * @code |
16102 | * |
16103 | * sip_content_length_t sip_content_length; |
16104 | * |
16105 | * sip_content_length_init(&sip_content_length); |
16106 | * |
16107 | * @endcode |
16108 | * @HI |
16109 | * |
16110 | */ |
16111 | #if SU_HAVE_INLINE1 |
16112 | su_inlinestatic inline sip_content_length_t *sip_content_length_init(sip_content_length_t x[1]) |
16113 | { |
16114 | return SIP_HEADER_INIT(x, sip_content_length_class, sizeof(sip_content_length_t))((void)memset((x), 0, (sizeof(sip_content_length_t))), (void) (((sip_common_t *)(x))->h_class = (sip_content_length_class )), (x)); |
16115 | } |
16116 | #else |
16117 | #define sip_content_length_init(x) \ |
16118 | SIP_HEADER_INIT(x, sip_content_length_class, sizeof(sip_content_length_t))((void)memset((x), 0, (sizeof(sip_content_length_t))), (void) (((sip_common_t *)(x))->h_class = (sip_content_length_class )), (x)) |
16119 | #endif |
16120 | |
16121 | /**Test if header object is instance of #sip_content_length_t. |
16122 | * |
16123 | * Check if the header class is an instance of |
16124 | * @ref sip_content_length "Content-Length header" object and return true (nonzero), |
16125 | * otherwise return false (zero). |
16126 | * |
16127 | * @param header pointer to the header structure to be tested |
16128 | * |
16129 | * @retval 1 (true) if the @a header is an instance of header content_length |
16130 | * @retval 0 (false) otherwise |
16131 | * |
16132 | */ |
16133 | #if SU_HAVE_INLINE1 |
16134 | su_inlinestatic inline int sip_is_content_length(sip_header_t const *header) |
16135 | { |
16136 | return header && header->sh_classsh_common->h_class->hc_hash == sip_content_length_hash; |
16137 | } |
16138 | #else |
16139 | int sip_is_content_length(sip_header_t const *header); |
16140 | #endif |
16141 | |
16142 | #define sip_content_length_p(h)sip_is_content_length((h)) sip_is_content_length((h)) |
16143 | |
16144 | |
16145 | /**Duplicate a list of @ref sip_content_length "Content-Length header" header structures #sip_content_length_t. |
16146 | * |
16147 | * Duplicate a header |
16148 | * structure @a hdr. If the header structure @a hdr |
16149 | * contains a reference (@c hdr->x_next) to a list of |
16150 | * headers, all the headers in the list are duplicated, too. |
16151 | * |
16152 | * @param home memory home used to allocate new structure |
16153 | * @param hdr header structure to be duplicated |
16154 | * |
16155 | * When duplicating, all parameter lists and non-constant |
16156 | * strings attached to the header are copied, too. The |
16157 | * function uses given memory @a home to allocate all the |
16158 | * memory areas used to copy the header. |
16159 | * |
16160 | * @par Example |
16161 | * @code |
16162 | * |
16163 | * content_length = sip_content_length_dup(home, sip->sip_content_length); |
16164 | * |
16165 | * @endcode |
16166 | * |
16167 | * @return |
16168 | * A pointer to the |
16169 | * newly duplicated #sip_content_length_t header structure, or NULL |
16170 | * upon an error. |
16171 | * |
16172 | */ |
16173 | #if SU_HAVE_INLINE1 |
16174 | su_inlinestatic inline |
16175 | #endif |
16176 | sip_content_length_t *sip_content_length_dup(su_home_t *home, sip_content_length_t const *hdr) |
16177 | __attribute__((__malloc__)); |
16178 | |
16179 | #if SU_HAVE_INLINE1 |
16180 | su_inlinestatic inline |
16181 | sip_content_length_t *sip_content_length_dup(su_home_t *home, sip_content_length_t const *hdr) |
16182 | { |
16183 | return (sip_content_length_t *) |
16184 | msg_header_dup_as(home, sip_content_length_class, (msg_header_t const *)hdr); |
16185 | } |
16186 | #endif |
16187 | |
16188 | /**Copy a list of @ref sip_content_length "Content-Length header" header structures #sip_content_length_t. |
16189 | * |
16190 | * The function sip_content_length_copy() copies a header structure @a |
16191 | * hdr. If the header structure @a hdr contains a reference (@c |
16192 | * hdr->h_next) to a list of headers, all the headers in that |
16193 | * list are copied, too. The function uses given memory @a home |
16194 | * to allocate all the memory areas used to copy the list of header |
16195 | * structure @a hdr. |
16196 | * |
16197 | * @param home memory home used to allocate new structure |
16198 | * @param hdr pointer to the header structure to be copied |
16199 | * |
16200 | * When copying, only the header structure and parameter lists attached to |
16201 | * it are duplicated. The new header structure retains all the references to |
16202 | * the strings within the old @a hdr header, including the encoding of the |
16203 | * old header, if present. |
16204 | * |
16205 | * @par Example |
16206 | * @code |
16207 | * |
16208 | * content_length = sip_content_length_copy(home, sip->sip_content_length); |
16209 | * |
16210 | * @endcode |
16211 | * |
16212 | * @return |
16213 | * A pointer to newly copied header structure, or NULL upon an error. |
16214 | * |
16215 | */ |
16216 | #if SU_HAVE_INLINE1 |
16217 | su_inlinestatic inline |
16218 | #endif |
16219 | sip_content_length_t *sip_content_length_copy(su_home_t *home, sip_content_length_t const *hdr) |
16220 | __attribute__((__malloc__)); |
16221 | |
16222 | #if SU_HAVE_INLINE1 |
16223 | su_inlinestatic inline |
16224 | sip_content_length_t *sip_content_length_copy(su_home_t *home, sip_content_length_t const *hdr) |
16225 | { |
16226 | return (sip_content_length_t *) |
16227 | msg_header_copy_as(home, sip_content_length_class, (msg_header_t const *)hdr); |
16228 | } |
16229 | #endif |
16230 | |
16231 | /**Make a @ref sip_content_length "Content-Length header" structure #sip_content_length_t. |
16232 | * |
16233 | * The function sip_content_length_make() makes a new |
16234 | * #sip_content_length_t header structure. It allocates a new |
16235 | * header structure, and decodes the string @a s as the |
16236 | * value of the structure. |
16237 | * |
16238 | * @param home memory home used to allocate new header structure. |
16239 | * @param s string to be decoded as value of the new header structure |
16240 | * |
16241 | * @return |
16242 | * A pointer to newly maked #sip_content_length_t header structure, or NULL upon an |
16243 | * error. |
16244 | * |
16245 | */ |
16246 | #if SU_HAVE_INLINE1 |
16247 | su_inlinestatic inline |
16248 | #endif |
16249 | sip_content_length_t *sip_content_length_make(su_home_t *home, char const *s) |
16250 | __attribute__((__malloc__)); |
16251 | |
16252 | #if SU_HAVE_INLINE1 |
16253 | su_inlinestatic inline sip_content_length_t *sip_content_length_make(su_home_t *home, char const *s) |
16254 | { |
16255 | return (sip_content_length_t *)sip_header_make(home, sip_content_length_class, s)((sip_header_t *)msg_header_make((home), (sip_content_length_class ), (s))); |
16256 | } |
16257 | #endif |
16258 | |
16259 | /**Make a @ref sip_content_length "Content-Length header" from formatting result. |
16260 | * |
16261 | * Make a new #sip_content_length_t object using formatting result as its value. |
16262 | * The function first prints the arguments according to the format @a fmt |
16263 | * specified. Then it allocates a new header structure, and parses the |
16264 | * formatting result to the structure #sip_content_length_t. |
16265 | * |
16266 | * @param home memory home used to allocate new header structure. |
16267 | * @param fmt string used as a printf()-style format |
16268 | * @param ... argument list for format |
16269 | * |
16270 | * @return |
16271 | * A pointer to newly |
16272 | * makes header structure, or NULL upon an error. |
16273 | * |
16274 | * @HIDE |
16275 | * |
16276 | */ |
16277 | #if SU_HAVE_INLINE1 |
16278 | su_inlinestatic inline |
16279 | #endif |
16280 | sip_content_length_t *sip_content_length_format(su_home_t *home, char const *fmt, ...) |
16281 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
16282 | |
16283 | #if SU_HAVE_INLINE1 |
16284 | su_inlinestatic inline sip_content_length_t *sip_content_length_format(su_home_t *home, char const *fmt, ...) |
16285 | { |
16286 | sip_header_t *h; |
16287 | va_list ap; |
16288 | |
16289 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
16290 | h = sip_header_vformat(home, sip_content_length_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_content_length_class ), (fmt), (ap))); |
16291 | va_end(ap)__builtin_va_end(ap); |
16292 | |
16293 | return (sip_content_length_t *)h; |
16294 | } |
16295 | #endif |
16296 | |
16297 | /** @} */ |
16298 | |
16299 | /**@addtogroup sip_unknown |
16300 | * @{ |
16301 | */ |
16302 | |
16303 | /** Parse a SIP @ref sip_unknown "unknown headers". @internal */ |
16304 | SOFIAPUBFUN issize_t sip_unknown_d(su_home_t *, msg_header_t *, |
16305 | char *s, isize_t slen); |
16306 | |
16307 | /** Print a SIP @ref sip_unknown "unknown headers". @internal */ |
16308 | SOFIAPUBFUN issize_t sip_unknown_e(char b[], isize_t bsiz, |
16309 | msg_header_t const *h, int flags); |
16310 | |
16311 | /**Access a SIP @ref sip_unknown "unknown headers" |
16312 | * structure #sip_unknown_t from #sip_t. |
16313 | * |
16314 | */ |
16315 | #define sip_unknown(sip)((sip_unknown_t *)msg_header_access((msg_pub_t*)(sip), sip_unknown_class )) \ |
16316 | ((sip_unknown_t *)msg_header_access((msg_pub_t*)(sip), sip_unknown_class)) |
16317 | |
16318 | /**Initializer for structure #sip_unknown_t. |
16319 | * |
16320 | * A static #sip_unknown_t structure for |
16321 | * @ref sip_unknown "unknown headers" must be initialized with |
16322 | * the SIP_UNKNOWN_INIT() macro. |
16323 | * For instance, |
16324 | * @code |
16325 | * |
16326 | * sip_unknown_t sip_unknown = SIP_UNKNOWN_INIT; |
16327 | * |
16328 | * @endcode |
16329 | * @HI |
16330 | * |
16331 | */ |
16332 | #define SIP_UNKNOWN_INIT(){{{ 0, 0, sip_unknown_class }}} SIP_HDR_INIT(unknown){{{ 0, 0, sip_unknown_class }}} |
16333 | |
16334 | /**Initialize a structure #sip_unknown_t. |
16335 | * |
16336 | * An #sip_unknown_t structure for |
16337 | * @ref sip_unknown "unknown headers" can be initialized with the |
16338 | * sip_unknown_init() function/macro. For instance, |
16339 | * @code |
16340 | * |
16341 | * sip_unknown_t sip_unknown; |
16342 | * |
16343 | * sip_unknown_init(&sip_unknown); |
16344 | * |
16345 | * @endcode |
16346 | * @HI |
16347 | * |
16348 | */ |
16349 | #if SU_HAVE_INLINE1 |
16350 | su_inlinestatic inline sip_unknown_t *sip_unknown_init(sip_unknown_t x[1]) |
16351 | { |
16352 | return SIP_HEADER_INIT(x, sip_unknown_class, sizeof(sip_unknown_t))((void)memset((x), 0, (sizeof(sip_unknown_t))), (void)(((sip_common_t *)(x))->h_class = (sip_unknown_class)), (x)); |
16353 | } |
16354 | #else |
16355 | #define sip_unknown_init(x) \ |
16356 | SIP_HEADER_INIT(x, sip_unknown_class, sizeof(sip_unknown_t))((void)memset((x), 0, (sizeof(sip_unknown_t))), (void)(((sip_common_t *)(x))->h_class = (sip_unknown_class)), (x)) |
16357 | #endif |
16358 | |
16359 | /**Test if header object is instance of #sip_unknown_t. |
16360 | * |
16361 | * Check if the header class is an instance of |
16362 | * @ref sip_unknown "unknown headers" object and return true (nonzero), |
16363 | * otherwise return false (zero). |
16364 | * |
16365 | * @param header pointer to the header structure to be tested |
16366 | * |
16367 | * @retval 1 (true) if the @a header is an instance of header unknown |
16368 | * @retval 0 (false) otherwise |
16369 | * |
16370 | */ |
16371 | #if SU_HAVE_INLINE1 |
16372 | su_inlinestatic inline int sip_is_unknown(sip_header_t const *header) |
16373 | { |
16374 | return header && header->sh_classsh_common->h_class->hc_hash == sip_unknown_hash; |
16375 | } |
16376 | #else |
16377 | int sip_is_unknown(sip_header_t const *header); |
16378 | #endif |
16379 | |
16380 | #define sip_unknown_p(h)sip_is_unknown((h)) sip_is_unknown((h)) |
16381 | |
16382 | |
16383 | /**Duplicate a list of @ref sip_unknown "unknown headers" header structures #sip_unknown_t. |
16384 | * |
16385 | * Duplicate a header |
16386 | * structure @a hdr. If the header structure @a hdr |
16387 | * contains a reference (@c hdr->x_next) to a list of |
16388 | * headers, all the headers in the list are duplicated, too. |
16389 | * |
16390 | * @param home memory home used to allocate new structure |
16391 | * @param hdr header structure to be duplicated |
16392 | * |
16393 | * When duplicating, all parameter lists and non-constant |
16394 | * strings attached to the header are copied, too. The |
16395 | * function uses given memory @a home to allocate all the |
16396 | * memory areas used to copy the header. |
16397 | * |
16398 | * @par Example |
16399 | * @code |
16400 | * |
16401 | * unknown = sip_unknown_dup(home, sip->sip_unknown); |
16402 | * |
16403 | * @endcode |
16404 | * |
16405 | * @return |
16406 | * A pointer to the |
16407 | * newly duplicated #sip_unknown_t header structure, or NULL |
16408 | * upon an error. |
16409 | * |
16410 | */ |
16411 | #if SU_HAVE_INLINE1 |
16412 | su_inlinestatic inline |
16413 | #endif |
16414 | sip_unknown_t *sip_unknown_dup(su_home_t *home, sip_unknown_t const *hdr) |
16415 | __attribute__((__malloc__)); |
16416 | |
16417 | #if SU_HAVE_INLINE1 |
16418 | su_inlinestatic inline |
16419 | sip_unknown_t *sip_unknown_dup(su_home_t *home, sip_unknown_t const *hdr) |
16420 | { |
16421 | return (sip_unknown_t *) |
16422 | msg_header_dup_as(home, sip_unknown_class, (msg_header_t const *)hdr); |
16423 | } |
16424 | #endif |
16425 | |
16426 | /**Copy a list of @ref sip_unknown "unknown headers" header structures #sip_unknown_t. |
16427 | * |
16428 | * The function sip_unknown_copy() copies a header structure @a |
16429 | * hdr. If the header structure @a hdr contains a reference (@c |
16430 | * hdr->h_next) to a list of headers, all the headers in that |
16431 | * list are copied, too. The function uses given memory @a home |
16432 | * to allocate all the memory areas used to copy the list of header |
16433 | * structure @a hdr. |
16434 | * |
16435 | * @param home memory home used to allocate new structure |
16436 | * @param hdr pointer to the header structure to be copied |
16437 | * |
16438 | * When copying, only the header structure and parameter lists attached to |
16439 | * it are duplicated. The new header structure retains all the references to |
16440 | * the strings within the old @a hdr header, including the encoding of the |
16441 | * old header, if present. |
16442 | * |
16443 | * @par Example |
16444 | * @code |
16445 | * |
16446 | * unknown = sip_unknown_copy(home, sip->sip_unknown); |
16447 | * |
16448 | * @endcode |
16449 | * |
16450 | * @return |
16451 | * A pointer to newly copied header structure, or NULL upon an error. |
16452 | * |
16453 | */ |
16454 | #if SU_HAVE_INLINE1 |
16455 | su_inlinestatic inline |
16456 | #endif |
16457 | sip_unknown_t *sip_unknown_copy(su_home_t *home, sip_unknown_t const *hdr) |
16458 | __attribute__((__malloc__)); |
16459 | |
16460 | #if SU_HAVE_INLINE1 |
16461 | su_inlinestatic inline |
16462 | sip_unknown_t *sip_unknown_copy(su_home_t *home, sip_unknown_t const *hdr) |
16463 | { |
16464 | return (sip_unknown_t *) |
16465 | msg_header_copy_as(home, sip_unknown_class, (msg_header_t const *)hdr); |
16466 | } |
16467 | #endif |
16468 | |
16469 | /**Make a @ref sip_unknown "unknown headers" structure #sip_unknown_t. |
16470 | * |
16471 | * The function sip_unknown_make() makes a new |
16472 | * #sip_unknown_t header structure. It allocates a new |
16473 | * header structure, and decodes the string @a s as the |
16474 | * value of the structure. |
16475 | * |
16476 | * @param home memory home used to allocate new header structure. |
16477 | * @param s string to be decoded as value of the new header structure |
16478 | * |
16479 | * @return |
16480 | * A pointer to newly maked #sip_unknown_t header structure, or NULL upon an |
16481 | * error. |
16482 | * |
16483 | */ |
16484 | #if SU_HAVE_INLINE1 |
16485 | su_inlinestatic inline |
16486 | #endif |
16487 | sip_unknown_t *sip_unknown_make(su_home_t *home, char const *s) |
16488 | __attribute__((__malloc__)); |
16489 | |
16490 | #if SU_HAVE_INLINE1 |
16491 | su_inlinestatic inline sip_unknown_t *sip_unknown_make(su_home_t *home, char const *s) |
16492 | { |
16493 | return (sip_unknown_t *)sip_header_make(home, sip_unknown_class, s)((sip_header_t *)msg_header_make((home), (sip_unknown_class), (s))); |
16494 | } |
16495 | #endif |
16496 | |
16497 | /**Make a @ref sip_unknown "unknown headers" from formatting result. |
16498 | * |
16499 | * Make a new #sip_unknown_t object using formatting result as its value. |
16500 | * The function first prints the arguments according to the format @a fmt |
16501 | * specified. Then it allocates a new header structure, and parses the |
16502 | * formatting result to the structure #sip_unknown_t. |
16503 | * |
16504 | * @param home memory home used to allocate new header structure. |
16505 | * @param fmt string used as a printf()-style format |
16506 | * @param ... argument list for format |
16507 | * |
16508 | * @return |
16509 | * A pointer to newly |
16510 | * makes header structure, or NULL upon an error. |
16511 | * |
16512 | * @HIDE |
16513 | * |
16514 | */ |
16515 | #if SU_HAVE_INLINE1 |
16516 | su_inlinestatic inline |
16517 | #endif |
16518 | sip_unknown_t *sip_unknown_format(su_home_t *home, char const *fmt, ...) |
16519 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
16520 | |
16521 | #if SU_HAVE_INLINE1 |
16522 | su_inlinestatic inline sip_unknown_t *sip_unknown_format(su_home_t *home, char const *fmt, ...) |
16523 | { |
16524 | sip_header_t *h; |
16525 | va_list ap; |
16526 | |
16527 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
16528 | h = sip_header_vformat(home, sip_unknown_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_unknown_class ), (fmt), (ap))); |
16529 | va_end(ap)__builtin_va_end(ap); |
16530 | |
16531 | return (sip_unknown_t *)h; |
16532 | } |
16533 | #endif |
16534 | |
16535 | /** @} */ |
16536 | |
16537 | /**@addtogroup sip_error |
16538 | * @{ |
16539 | */ |
16540 | |
16541 | /** Parse a SIP @ref sip_error "erroneous headers". @internal */ |
16542 | SOFIAPUBFUN issize_t sip_error_d(su_home_t *, msg_header_t *, |
16543 | char *s, isize_t slen); |
16544 | |
16545 | /** Print a SIP @ref sip_error "erroneous headers". @internal */ |
16546 | SOFIAPUBFUN issize_t sip_error_e(char b[], isize_t bsiz, |
16547 | msg_header_t const *h, int flags); |
16548 | |
16549 | /**Access a SIP @ref sip_error "erroneous headers" |
16550 | * structure #sip_error_t from #sip_t. |
16551 | * |
16552 | */ |
16553 | #define sip_error(sip)((sip_error_t *)msg_header_access((msg_pub_t*)(sip), sip_error_class )) \ |
16554 | ((sip_error_t *)msg_header_access((msg_pub_t*)(sip), sip_error_class)) |
16555 | |
16556 | /**Initializer for structure #sip_error_t. |
16557 | * |
16558 | * A static #sip_error_t structure for |
16559 | * @ref sip_error "erroneous headers" must be initialized with |
16560 | * the SIP_ERROR_INIT() macro. |
16561 | * For instance, |
16562 | * @code |
16563 | * |
16564 | * sip_error_t sip_error = SIP_ERROR_INIT; |
16565 | * |
16566 | * @endcode |
16567 | * @HI |
16568 | * |
16569 | */ |
16570 | #define SIP_ERROR_INIT(){{{ 0, 0, sip_error_class }}} SIP_HDR_INIT(error){{{ 0, 0, sip_error_class }}} |
16571 | |
16572 | /**Initialize a structure #sip_error_t. |
16573 | * |
16574 | * An #sip_error_t structure for |
16575 | * @ref sip_error "erroneous headers" can be initialized with the |
16576 | * sip_error_init() function/macro. For instance, |
16577 | * @code |
16578 | * |
16579 | * sip_error_t sip_error; |
16580 | * |
16581 | * sip_error_init(&sip_error); |
16582 | * |
16583 | * @endcode |
16584 | * @HI |
16585 | * |
16586 | */ |
16587 | #if SU_HAVE_INLINE1 |
16588 | su_inlinestatic inline sip_error_t *sip_error_init(sip_error_t x[1]) |
16589 | { |
16590 | return SIP_HEADER_INIT(x, sip_error_class, sizeof(sip_error_t))((void)memset((x), 0, (sizeof(sip_error_t))), (void)(((sip_common_t *)(x))->h_class = (sip_error_class)), (x)); |
16591 | } |
16592 | #else |
16593 | #define sip_error_init(x) \ |
16594 | SIP_HEADER_INIT(x, sip_error_class, sizeof(sip_error_t))((void)memset((x), 0, (sizeof(sip_error_t))), (void)(((sip_common_t *)(x))->h_class = (sip_error_class)), (x)) |
16595 | #endif |
16596 | |
16597 | /**Test if header object is instance of #sip_error_t. |
16598 | * |
16599 | * Check if the header class is an instance of |
16600 | * @ref sip_error "erroneous headers" object and return true (nonzero), |
16601 | * otherwise return false (zero). |
16602 | * |
16603 | * @param header pointer to the header structure to be tested |
16604 | * |
16605 | * @retval 1 (true) if the @a header is an instance of header error |
16606 | * @retval 0 (false) otherwise |
16607 | * |
16608 | */ |
16609 | #if SU_HAVE_INLINE1 |
16610 | su_inlinestatic inline int sip_is_error(sip_header_t const *header) |
16611 | { |
16612 | return header && header->sh_classsh_common->h_class->hc_hash == sip_error_hash; |
16613 | } |
16614 | #else |
16615 | int sip_is_error(sip_header_t const *header); |
16616 | #endif |
16617 | |
16618 | #define sip_error_p(h)sip_is_error((h)) sip_is_error((h)) |
16619 | |
16620 | |
16621 | /**Duplicate a list of @ref sip_error "erroneous headers" header structures #sip_error_t. |
16622 | * |
16623 | * Duplicate a header |
16624 | * structure @a hdr. If the header structure @a hdr |
16625 | * contains a reference (@c hdr->x_next) to a list of |
16626 | * headers, all the headers in the list are duplicated, too. |
16627 | * |
16628 | * @param home memory home used to allocate new structure |
16629 | * @param hdr header structure to be duplicated |
16630 | * |
16631 | * When duplicating, all parameter lists and non-constant |
16632 | * strings attached to the header are copied, too. The |
16633 | * function uses given memory @a home to allocate all the |
16634 | * memory areas used to copy the header. |
16635 | * |
16636 | * @par Example |
16637 | * @code |
16638 | * |
16639 | * error = sip_error_dup(home, sip->sip_error); |
16640 | * |
16641 | * @endcode |
16642 | * |
16643 | * @return |
16644 | * A pointer to the |
16645 | * newly duplicated #sip_error_t header structure, or NULL |
16646 | * upon an error. |
16647 | * |
16648 | */ |
16649 | #if SU_HAVE_INLINE1 |
16650 | su_inlinestatic inline |
16651 | #endif |
16652 | sip_error_t *sip_error_dup(su_home_t *home, sip_error_t const *hdr) |
16653 | __attribute__((__malloc__)); |
16654 | |
16655 | #if SU_HAVE_INLINE1 |
16656 | su_inlinestatic inline |
16657 | sip_error_t *sip_error_dup(su_home_t *home, sip_error_t const *hdr) |
16658 | { |
16659 | return (sip_error_t *) |
16660 | msg_header_dup_as(home, sip_error_class, (msg_header_t const *)hdr); |
16661 | } |
16662 | #endif |
16663 | |
16664 | /**Copy a list of @ref sip_error "erroneous headers" header structures #sip_error_t. |
16665 | * |
16666 | * The function sip_error_copy() copies a header structure @a |
16667 | * hdr. If the header structure @a hdr contains a reference (@c |
16668 | * hdr->h_next) to a list of headers, all the headers in that |
16669 | * list are copied, too. The function uses given memory @a home |
16670 | * to allocate all the memory areas used to copy the list of header |
16671 | * structure @a hdr. |
16672 | * |
16673 | * @param home memory home used to allocate new structure |
16674 | * @param hdr pointer to the header structure to be copied |
16675 | * |
16676 | * When copying, only the header structure and parameter lists attached to |
16677 | * it are duplicated. The new header structure retains all the references to |
16678 | * the strings within the old @a hdr header, including the encoding of the |
16679 | * old header, if present. |
16680 | * |
16681 | * @par Example |
16682 | * @code |
16683 | * |
16684 | * error = sip_error_copy(home, sip->sip_error); |
16685 | * |
16686 | * @endcode |
16687 | * |
16688 | * @return |
16689 | * A pointer to newly copied header structure, or NULL upon an error. |
16690 | * |
16691 | */ |
16692 | #if SU_HAVE_INLINE1 |
16693 | su_inlinestatic inline |
16694 | #endif |
16695 | sip_error_t *sip_error_copy(su_home_t *home, sip_error_t const *hdr) |
16696 | __attribute__((__malloc__)); |
16697 | |
16698 | #if SU_HAVE_INLINE1 |
16699 | su_inlinestatic inline |
16700 | sip_error_t *sip_error_copy(su_home_t *home, sip_error_t const *hdr) |
16701 | { |
16702 | return (sip_error_t *) |
16703 | msg_header_copy_as(home, sip_error_class, (msg_header_t const *)hdr); |
16704 | } |
16705 | #endif |
16706 | |
16707 | /**Make a @ref sip_error "erroneous headers" structure #sip_error_t. |
16708 | * |
16709 | * The function sip_error_make() makes a new |
16710 | * #sip_error_t header structure. It allocates a new |
16711 | * header structure, and decodes the string @a s as the |
16712 | * value of the structure. |
16713 | * |
16714 | * @param home memory home used to allocate new header structure. |
16715 | * @param s string to be decoded as value of the new header structure |
16716 | * |
16717 | * @return |
16718 | * A pointer to newly maked #sip_error_t header structure, or NULL upon an |
16719 | * error. |
16720 | * |
16721 | */ |
16722 | #if SU_HAVE_INLINE1 |
16723 | su_inlinestatic inline |
16724 | #endif |
16725 | sip_error_t *sip_error_make(su_home_t *home, char const *s) |
16726 | __attribute__((__malloc__)); |
16727 | |
16728 | #if SU_HAVE_INLINE1 |
16729 | su_inlinestatic inline sip_error_t *sip_error_make(su_home_t *home, char const *s) |
16730 | { |
16731 | return (sip_error_t *)sip_header_make(home, sip_error_class, s)((sip_header_t *)msg_header_make((home), (sip_error_class), ( s))); |
16732 | } |
16733 | #endif |
16734 | |
16735 | /**Make a @ref sip_error "erroneous headers" from formatting result. |
16736 | * |
16737 | * Make a new #sip_error_t object using formatting result as its value. |
16738 | * The function first prints the arguments according to the format @a fmt |
16739 | * specified. Then it allocates a new header structure, and parses the |
16740 | * formatting result to the structure #sip_error_t. |
16741 | * |
16742 | * @param home memory home used to allocate new header structure. |
16743 | * @param fmt string used as a printf()-style format |
16744 | * @param ... argument list for format |
16745 | * |
16746 | * @return |
16747 | * A pointer to newly |
16748 | * makes header structure, or NULL upon an error. |
16749 | * |
16750 | * @HIDE |
16751 | * |
16752 | */ |
16753 | #if SU_HAVE_INLINE1 |
16754 | su_inlinestatic inline |
16755 | #endif |
16756 | sip_error_t *sip_error_format(su_home_t *home, char const *fmt, ...) |
16757 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
16758 | |
16759 | #if SU_HAVE_INLINE1 |
16760 | su_inlinestatic inline sip_error_t *sip_error_format(su_home_t *home, char const *fmt, ...) |
16761 | { |
16762 | sip_header_t *h; |
16763 | va_list ap; |
16764 | |
16765 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
16766 | h = sip_header_vformat(home, sip_error_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_error_class) , (fmt), (ap))); |
16767 | va_end(ap)__builtin_va_end(ap); |
16768 | |
16769 | return (sip_error_t *)h; |
16770 | } |
16771 | #endif |
16772 | |
16773 | /** @} */ |
16774 | |
16775 | /**@addtogroup sip_separator |
16776 | * @{ |
16777 | */ |
16778 | |
16779 | /** Parse a SIP @ref sip_separator "separator line between headers and body". @internal */ |
16780 | SOFIAPUBFUN issize_t sip_separator_d(su_home_t *, msg_header_t *, |
16781 | char *s, isize_t slen); |
16782 | |
16783 | /** Print a SIP @ref sip_separator "separator line between headers and body". @internal */ |
16784 | SOFIAPUBFUN issize_t sip_separator_e(char b[], isize_t bsiz, |
16785 | msg_header_t const *h, int flags); |
16786 | |
16787 | /**Access a SIP @ref sip_separator "separator line between headers and body" |
16788 | * structure #sip_separator_t from #sip_t. |
16789 | * |
16790 | */ |
16791 | #define sip_separator(sip)((sip_separator_t *)msg_header_access((msg_pub_t*)(sip), sip_separator_class )) \ |
16792 | ((sip_separator_t *)msg_header_access((msg_pub_t*)(sip), sip_separator_class)) |
16793 | |
16794 | /**Initializer for structure #sip_separator_t. |
16795 | * |
16796 | * A static #sip_separator_t structure for |
16797 | * @ref sip_separator "separator line between headers and body" must be initialized with |
16798 | * the SIP_SEPARATOR_INIT() macro. |
16799 | * For instance, |
16800 | * @code |
16801 | * |
16802 | * sip_separator_t sip_separator = SIP_SEPARATOR_INIT; |
16803 | * |
16804 | * @endcode |
16805 | * @HI |
16806 | * |
16807 | */ |
16808 | #define SIP_SEPARATOR_INIT(){{{ 0, 0, sip_separator_class }}} SIP_HDR_INIT(separator){{{ 0, 0, sip_separator_class }}} |
16809 | |
16810 | /**Initialize a structure #sip_separator_t. |
16811 | * |
16812 | * An #sip_separator_t structure for |
16813 | * @ref sip_separator "separator line between headers and body" can be initialized with the |
16814 | * sip_separator_init() function/macro. For instance, |
16815 | * @code |
16816 | * |
16817 | * sip_separator_t sip_separator; |
16818 | * |
16819 | * sip_separator_init(&sip_separator); |
16820 | * |
16821 | * @endcode |
16822 | * @HI |
16823 | * |
16824 | */ |
16825 | #if SU_HAVE_INLINE1 |
16826 | su_inlinestatic inline sip_separator_t *sip_separator_init(sip_separator_t x[1]) |
16827 | { |
16828 | return SIP_HEADER_INIT(x, sip_separator_class, sizeof(sip_separator_t))((void)memset((x), 0, (sizeof(sip_separator_t))), (void)(((sip_common_t *)(x))->h_class = (sip_separator_class)), (x)); |
16829 | } |
16830 | #else |
16831 | #define sip_separator_init(x) \ |
16832 | SIP_HEADER_INIT(x, sip_separator_class, sizeof(sip_separator_t))((void)memset((x), 0, (sizeof(sip_separator_t))), (void)(((sip_common_t *)(x))->h_class = (sip_separator_class)), (x)) |
16833 | #endif |
16834 | |
16835 | /**Test if header object is instance of #sip_separator_t. |
16836 | * |
16837 | * Check if the header class is an instance of |
16838 | * @ref sip_separator "separator line between headers and body" object and return true (nonzero), |
16839 | * otherwise return false (zero). |
16840 | * |
16841 | * @param header pointer to the header structure to be tested |
16842 | * |
16843 | * @retval 1 (true) if the @a header is an instance of header separator |
16844 | * @retval 0 (false) otherwise |
16845 | * |
16846 | */ |
16847 | #if SU_HAVE_INLINE1 |
16848 | su_inlinestatic inline int sip_is_separator(sip_header_t const *header) |
16849 | { |
16850 | return header && header->sh_classsh_common->h_class->hc_hash == sip_separator_hash; |
16851 | } |
16852 | #else |
16853 | int sip_is_separator(sip_header_t const *header); |
16854 | #endif |
16855 | |
16856 | #define sip_separator_p(h)sip_is_separator((h)) sip_is_separator((h)) |
16857 | |
16858 | |
16859 | /**Duplicate a list of @ref sip_separator "separator line between headers and body" header structures #sip_separator_t. |
16860 | * |
16861 | * Duplicate a header |
16862 | * structure @a hdr. If the header structure @a hdr |
16863 | * contains a reference (@c hdr->x_next) to a list of |
16864 | * headers, all the headers in the list are duplicated, too. |
16865 | * |
16866 | * @param home memory home used to allocate new structure |
16867 | * @param hdr header structure to be duplicated |
16868 | * |
16869 | * When duplicating, all parameter lists and non-constant |
16870 | * strings attached to the header are copied, too. The |
16871 | * function uses given memory @a home to allocate all the |
16872 | * memory areas used to copy the header. |
16873 | * |
16874 | * @par Example |
16875 | * @code |
16876 | * |
16877 | * separator = sip_separator_dup(home, sip->sip_separator); |
16878 | * |
16879 | * @endcode |
16880 | * |
16881 | * @return |
16882 | * A pointer to the |
16883 | * newly duplicated #sip_separator_t header structure, or NULL |
16884 | * upon an error. |
16885 | * |
16886 | */ |
16887 | #if SU_HAVE_INLINE1 |
16888 | su_inlinestatic inline |
16889 | #endif |
16890 | sip_separator_t *sip_separator_dup(su_home_t *home, sip_separator_t const *hdr) |
16891 | __attribute__((__malloc__)); |
16892 | |
16893 | #if SU_HAVE_INLINE1 |
16894 | su_inlinestatic inline |
16895 | sip_separator_t *sip_separator_dup(su_home_t *home, sip_separator_t const *hdr) |
16896 | { |
16897 | return (sip_separator_t *) |
16898 | msg_header_dup_as(home, sip_separator_class, (msg_header_t const *)hdr); |
16899 | } |
16900 | #endif |
16901 | |
16902 | /**Copy a list of @ref sip_separator "separator line between headers and body" header structures #sip_separator_t. |
16903 | * |
16904 | * The function sip_separator_copy() copies a header structure @a |
16905 | * hdr. If the header structure @a hdr contains a reference (@c |
16906 | * hdr->h_next) to a list of headers, all the headers in that |
16907 | * list are copied, too. The function uses given memory @a home |
16908 | * to allocate all the memory areas used to copy the list of header |
16909 | * structure @a hdr. |
16910 | * |
16911 | * @param home memory home used to allocate new structure |
16912 | * @param hdr pointer to the header structure to be copied |
16913 | * |
16914 | * When copying, only the header structure and parameter lists attached to |
16915 | * it are duplicated. The new header structure retains all the references to |
16916 | * the strings within the old @a hdr header, including the encoding of the |
16917 | * old header, if present. |
16918 | * |
16919 | * @par Example |
16920 | * @code |
16921 | * |
16922 | * separator = sip_separator_copy(home, sip->sip_separator); |
16923 | * |
16924 | * @endcode |
16925 | * |
16926 | * @return |
16927 | * A pointer to newly copied header structure, or NULL upon an error. |
16928 | * |
16929 | */ |
16930 | #if SU_HAVE_INLINE1 |
16931 | su_inlinestatic inline |
16932 | #endif |
16933 | sip_separator_t *sip_separator_copy(su_home_t *home, sip_separator_t const *hdr) |
16934 | __attribute__((__malloc__)); |
16935 | |
16936 | #if SU_HAVE_INLINE1 |
16937 | su_inlinestatic inline |
16938 | sip_separator_t *sip_separator_copy(su_home_t *home, sip_separator_t const *hdr) |
16939 | { |
16940 | return (sip_separator_t *) |
16941 | msg_header_copy_as(home, sip_separator_class, (msg_header_t const *)hdr); |
16942 | } |
16943 | #endif |
16944 | |
16945 | /**Make a @ref sip_separator "separator line between headers and body" structure #sip_separator_t. |
16946 | * |
16947 | * The function sip_separator_make() makes a new |
16948 | * #sip_separator_t header structure. It allocates a new |
16949 | * header structure, and decodes the string @a s as the |
16950 | * value of the structure. |
16951 | * |
16952 | * @param home memory home used to allocate new header structure. |
16953 | * @param s string to be decoded as value of the new header structure |
16954 | * |
16955 | * @return |
16956 | * A pointer to newly maked #sip_separator_t header structure, or NULL upon an |
16957 | * error. |
16958 | * |
16959 | */ |
16960 | #if SU_HAVE_INLINE1 |
16961 | su_inlinestatic inline |
16962 | #endif |
16963 | sip_separator_t *sip_separator_make(su_home_t *home, char const *s) |
16964 | __attribute__((__malloc__)); |
16965 | |
16966 | #if SU_HAVE_INLINE1 |
16967 | su_inlinestatic inline sip_separator_t *sip_separator_make(su_home_t *home, char const *s) |
16968 | { |
16969 | return (sip_separator_t *)sip_header_make(home, sip_separator_class, s)((sip_header_t *)msg_header_make((home), (sip_separator_class ), (s))); |
16970 | } |
16971 | #endif |
16972 | |
16973 | /**Make a @ref sip_separator "separator line between headers and body" from formatting result. |
16974 | * |
16975 | * Make a new #sip_separator_t object using formatting result as its value. |
16976 | * The function first prints the arguments according to the format @a fmt |
16977 | * specified. Then it allocates a new header structure, and parses the |
16978 | * formatting result to the structure #sip_separator_t. |
16979 | * |
16980 | * @param home memory home used to allocate new header structure. |
16981 | * @param fmt string used as a printf()-style format |
16982 | * @param ... argument list for format |
16983 | * |
16984 | * @return |
16985 | * A pointer to newly |
16986 | * makes header structure, or NULL upon an error. |
16987 | * |
16988 | * @HIDE |
16989 | * |
16990 | */ |
16991 | #if SU_HAVE_INLINE1 |
16992 | su_inlinestatic inline |
16993 | #endif |
16994 | sip_separator_t *sip_separator_format(su_home_t *home, char const *fmt, ...) |
16995 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
16996 | |
16997 | #if SU_HAVE_INLINE1 |
16998 | su_inlinestatic inline sip_separator_t *sip_separator_format(su_home_t *home, char const *fmt, ...) |
16999 | { |
17000 | sip_header_t *h; |
17001 | va_list ap; |
17002 | |
17003 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
17004 | h = sip_header_vformat(home, sip_separator_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_separator_class ), (fmt), (ap))); |
17005 | va_end(ap)__builtin_va_end(ap); |
17006 | |
17007 | return (sip_separator_t *)h; |
17008 | } |
17009 | #endif |
17010 | |
17011 | /** @} */ |
17012 | |
17013 | /**@addtogroup sip_payload |
17014 | * @{ |
17015 | */ |
17016 | |
17017 | /** Parse a SIP @ref sip_payload "message payload". @internal */ |
17018 | SOFIAPUBFUN issize_t sip_payload_d(su_home_t *, msg_header_t *, |
17019 | char *s, isize_t slen); |
17020 | |
17021 | /** Print a SIP @ref sip_payload "message payload". @internal */ |
17022 | SOFIAPUBFUN issize_t sip_payload_e(char b[], isize_t bsiz, |
17023 | msg_header_t const *h, int flags); |
17024 | |
17025 | /**Access a SIP @ref sip_payload "message payload" |
17026 | * structure #sip_payload_t from #sip_t. |
17027 | * |
17028 | */ |
17029 | #define sip_payload(sip)((sip_payload_t *)msg_header_access((msg_pub_t*)(sip), sip_payload_class )) \ |
17030 | ((sip_payload_t *)msg_header_access((msg_pub_t*)(sip), sip_payload_class)) |
17031 | |
17032 | /**Initializer for structure #sip_payload_t. |
17033 | * |
17034 | * A static #sip_payload_t structure for |
17035 | * @ref sip_payload "message payload" must be initialized with |
17036 | * the SIP_PAYLOAD_INIT() macro. |
17037 | * For instance, |
17038 | * @code |
17039 | * |
17040 | * sip_payload_t sip_payload = SIP_PAYLOAD_INIT; |
17041 | * |
17042 | * @endcode |
17043 | * @HI |
17044 | * |
17045 | */ |
17046 | #define SIP_PAYLOAD_INIT(){{{ 0, 0, sip_payload_class }}} SIP_HDR_INIT(payload){{{ 0, 0, sip_payload_class }}} |
17047 | |
17048 | /**Initialize a structure #sip_payload_t. |
17049 | * |
17050 | * An #sip_payload_t structure for |
17051 | * @ref sip_payload "message payload" can be initialized with the |
17052 | * sip_payload_init() function/macro. For instance, |
17053 | * @code |
17054 | * |
17055 | * sip_payload_t sip_payload; |
17056 | * |
17057 | * sip_payload_init(&sip_payload); |
17058 | * |
17059 | * @endcode |
17060 | * @HI |
17061 | * |
17062 | */ |
17063 | #if SU_HAVE_INLINE1 |
17064 | su_inlinestatic inline sip_payload_t *sip_payload_init(sip_payload_t x[1]) |
17065 | { |
17066 | return SIP_HEADER_INIT(x, sip_payload_class, sizeof(sip_payload_t))((void)memset((x), 0, (sizeof(sip_payload_t))), (void)(((sip_common_t *)(x))->h_class = (sip_payload_class)), (x)); |
17067 | } |
17068 | #else |
17069 | #define sip_payload_init(x) \ |
17070 | SIP_HEADER_INIT(x, sip_payload_class, sizeof(sip_payload_t))((void)memset((x), 0, (sizeof(sip_payload_t))), (void)(((sip_common_t *)(x))->h_class = (sip_payload_class)), (x)) |
17071 | #endif |
17072 | |
17073 | /**Test if header object is instance of #sip_payload_t. |
17074 | * |
17075 | * Check if the header class is an instance of |
17076 | * @ref sip_payload "message payload" object and return true (nonzero), |
17077 | * otherwise return false (zero). |
17078 | * |
17079 | * @param header pointer to the header structure to be tested |
17080 | * |
17081 | * @retval 1 (true) if the @a header is an instance of header payload |
17082 | * @retval 0 (false) otherwise |
17083 | * |
17084 | */ |
17085 | #if SU_HAVE_INLINE1 |
17086 | su_inlinestatic inline int sip_is_payload(sip_header_t const *header) |
17087 | { |
17088 | return header && header->sh_classsh_common->h_class->hc_hash == sip_payload_hash; |
17089 | } |
17090 | #else |
17091 | int sip_is_payload(sip_header_t const *header); |
17092 | #endif |
17093 | |
17094 | #define sip_payload_p(h)sip_is_payload((h)) sip_is_payload((h)) |
17095 | |
17096 | |
17097 | /**Duplicate a list of @ref sip_payload "message payload" header structures #sip_payload_t. |
17098 | * |
17099 | * Duplicate a header |
17100 | * structure @a hdr. If the header structure @a hdr |
17101 | * contains a reference (@c hdr->x_next) to a list of |
17102 | * headers, all the headers in the list are duplicated, too. |
17103 | * |
17104 | * @param home memory home used to allocate new structure |
17105 | * @param hdr header structure to be duplicated |
17106 | * |
17107 | * When duplicating, all parameter lists and non-constant |
17108 | * strings attached to the header are copied, too. The |
17109 | * function uses given memory @a home to allocate all the |
17110 | * memory areas used to copy the header. |
17111 | * |
17112 | * @par Example |
17113 | * @code |
17114 | * |
17115 | * payload = sip_payload_dup(home, sip->sip_payload); |
17116 | * |
17117 | * @endcode |
17118 | * |
17119 | * @return |
17120 | * A pointer to the |
17121 | * newly duplicated #sip_payload_t header structure, or NULL |
17122 | * upon an error. |
17123 | * |
17124 | */ |
17125 | #if SU_HAVE_INLINE1 |
17126 | su_inlinestatic inline |
17127 | #endif |
17128 | sip_payload_t *sip_payload_dup(su_home_t *home, sip_payload_t const *hdr) |
17129 | __attribute__((__malloc__)); |
17130 | |
17131 | #if SU_HAVE_INLINE1 |
17132 | su_inlinestatic inline |
17133 | sip_payload_t *sip_payload_dup(su_home_t *home, sip_payload_t const *hdr) |
17134 | { |
17135 | return (sip_payload_t *) |
17136 | msg_header_dup_as(home, sip_payload_class, (msg_header_t const *)hdr); |
17137 | } |
17138 | #endif |
17139 | |
17140 | /**Copy a list of @ref sip_payload "message payload" header structures #sip_payload_t. |
17141 | * |
17142 | * The function sip_payload_copy() copies a header structure @a |
17143 | * hdr. If the header structure @a hdr contains a reference (@c |
17144 | * hdr->h_next) to a list of headers, all the headers in that |
17145 | * list are copied, too. The function uses given memory @a home |
17146 | * to allocate all the memory areas used to copy the list of header |
17147 | * structure @a hdr. |
17148 | * |
17149 | * @param home memory home used to allocate new structure |
17150 | * @param hdr pointer to the header structure to be copied |
17151 | * |
17152 | * When copying, only the header structure and parameter lists attached to |
17153 | * it are duplicated. The new header structure retains all the references to |
17154 | * the strings within the old @a hdr header, including the encoding of the |
17155 | * old header, if present. |
17156 | * |
17157 | * @par Example |
17158 | * @code |
17159 | * |
17160 | * payload = sip_payload_copy(home, sip->sip_payload); |
17161 | * |
17162 | * @endcode |
17163 | * |
17164 | * @return |
17165 | * A pointer to newly copied header structure, or NULL upon an error. |
17166 | * |
17167 | */ |
17168 | #if SU_HAVE_INLINE1 |
17169 | su_inlinestatic inline |
17170 | #endif |
17171 | sip_payload_t *sip_payload_copy(su_home_t *home, sip_payload_t const *hdr) |
17172 | __attribute__((__malloc__)); |
17173 | |
17174 | #if SU_HAVE_INLINE1 |
17175 | su_inlinestatic inline |
17176 | sip_payload_t *sip_payload_copy(su_home_t *home, sip_payload_t const *hdr) |
17177 | { |
17178 | return (sip_payload_t *) |
17179 | msg_header_copy_as(home, sip_payload_class, (msg_header_t const *)hdr); |
17180 | } |
17181 | #endif |
17182 | |
17183 | /**Make a @ref sip_payload "message payload" structure #sip_payload_t. |
17184 | * |
17185 | * The function sip_payload_make() makes a new |
17186 | * #sip_payload_t header structure. It allocates a new |
17187 | * header structure, and decodes the string @a s as the |
17188 | * value of the structure. |
17189 | * |
17190 | * @param home memory home used to allocate new header structure. |
17191 | * @param s string to be decoded as value of the new header structure |
17192 | * |
17193 | * @return |
17194 | * A pointer to newly maked #sip_payload_t header structure, or NULL upon an |
17195 | * error. |
17196 | * |
17197 | */ |
17198 | #if SU_HAVE_INLINE1 |
17199 | su_inlinestatic inline |
17200 | #endif |
17201 | sip_payload_t *sip_payload_make(su_home_t *home, char const *s) |
17202 | __attribute__((__malloc__)); |
17203 | |
17204 | #if SU_HAVE_INLINE1 |
17205 | su_inlinestatic inline sip_payload_t *sip_payload_make(su_home_t *home, char const *s) |
17206 | { |
17207 | return (sip_payload_t *)sip_header_make(home, sip_payload_class, s)((sip_header_t *)msg_header_make((home), (sip_payload_class), (s))); |
17208 | } |
17209 | #endif |
17210 | |
17211 | /**Make a @ref sip_payload "message payload" from formatting result. |
17212 | * |
17213 | * Make a new #sip_payload_t object using formatting result as its value. |
17214 | * The function first prints the arguments according to the format @a fmt |
17215 | * specified. Then it allocates a new header structure, and parses the |
17216 | * formatting result to the structure #sip_payload_t. |
17217 | * |
17218 | * @param home memory home used to allocate new header structure. |
17219 | * @param fmt string used as a printf()-style format |
17220 | * @param ... argument list for format |
17221 | * |
17222 | * @return |
17223 | * A pointer to newly |
17224 | * makes header structure, or NULL upon an error. |
17225 | * |
17226 | * @HIDE |
17227 | * |
17228 | */ |
17229 | #if SU_HAVE_INLINE1 |
17230 | su_inlinestatic inline |
17231 | #endif |
17232 | sip_payload_t *sip_payload_format(su_home_t *home, char const *fmt, ...) |
17233 | __attribute__((__malloc__, __format__ (printf, 2, 3))); |
17234 | |
17235 | #if SU_HAVE_INLINE1 |
17236 | su_inlinestatic inline sip_payload_t *sip_payload_format(su_home_t *home, char const *fmt, ...) |
17237 | { |
17238 | sip_header_t *h; |
17239 | va_list ap; |
17240 | |
17241 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
17242 | h = sip_header_vformat(home, sip_payload_class, fmt, ap)((sip_header_t *)msg_header_vformat((home), (sip_payload_class ), (fmt), (ap))); |
17243 | va_end(ap)__builtin_va_end(ap); |
17244 | |
17245 | return (sip_payload_t *)h; |
17246 | } |
17247 | #endif |
17248 | |
17249 | /** @} */ |
17250 | |
17251 | SOFIA_END_DECLS |
17252 | #endif /* !defined(SIP_PROTOS_H) */ |