File: | nta/nta.c |
Warning: | line 2453, 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.5"; | |||||
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 | ||||||
183 | unsigned sa_udp_mtu; /**< Maximum size of outgoing UDP requests */ | |||||
184 | ||||||
185 | unsigned sa_t1; /**< SIP T1 - initial retransmit interval (500 ms) */ | |||||
186 | unsigned sa_t2; /**< SIP T2 - maximum retransmit interval (4000 ms) */ | |||||
187 | unsigned sa_t4; /**< SIP T4 - clear message time (5000 ms) */ | |||||
188 | ||||||
189 | ||||||
190 | unsigned sa_t1x64; /**< SIP T1X64 - transaction lifetime (32 s) */ | |||||
191 | ||||||
192 | unsigned sa_tls_orq_connect_timeout; /**< Connect Timeout for outgoing requests using TLS (ms) */ | |||||
193 | ||||||
194 | unsigned sa_progress; /**< Progress timer. | |||||
195 | Interval between retransmitting | |||||
196 | provisional responses. */ | |||||
197 | ||||||
198 | unsigned sa_timer_c; /**< SIP timer C. | |||||
199 | Maximum interval between receiving | |||||
200 | provisional responses. */ | |||||
201 | ||||||
202 | unsigned sa_graylist; /**< Graylisting period */ | |||||
203 | unsigned sa_blacklist; /**< Blacklisting period */ | |||||
204 | ||||||
205 | unsigned sa_drop_prob : 10; /**< NTA is used to test packet drop */ | |||||
206 | unsigned sa_is_a_uas : 1; /**< NTA is acting as an User Agent server */ | |||||
207 | unsigned sa_is_stateless : 1; /**< Process requests statelessly | |||||
208 | * unless they match existing dialog. | |||||
209 | */ | |||||
210 | unsigned sa_user_via:1; /**< Let application provide @Via headers */ | |||||
211 | unsigned sa_extra_100:1; /**< Allow NTA to return "100 Trying" response | |||||
212 | * even if application has not responded. | |||||
213 | */ | |||||
214 | unsigned sa_pass_100:1; /**< Pass the "100 Trying" | |||||
215 | * provisional responses to the application | |||||
216 | */ | |||||
217 | unsigned sa_timeout_408:1; /**< A "408 Request Timeout" message | |||||
218 | * is generated when outgoing request expires. | |||||
219 | */ | |||||
220 | unsigned sa_pass_408:1; /**< A "408 Request Timeout" responses | |||||
221 | * are passed to client. | |||||
222 | */ | |||||
223 | unsigned sa_merge_482 : 1; /**< A "482 Request Merged" response is returned | |||||
224 | * to merged requests. | |||||
225 | */ | |||||
226 | unsigned sa_cancel_2543 : 1; /**< Send a CANCEL to an INVITE without | |||||
227 | * waiting for an provisional response. | |||||
228 | */ | |||||
229 | unsigned sa_cancel_487 : 1; /**< Return 487 response automatically when | |||||
230 | * a CANCEL is received. | |||||
231 | */ | |||||
232 | ||||||
233 | unsigned sa_invite_100rel:1; /**< Include 100rel in INVITE requests. */ | |||||
234 | unsigned sa_timestamp : 1; /**< Insert @Timestamp in requests. */ | |||||
235 | ||||||
236 | unsigned sa_tport_ip4 : 1; /**< Transports support IPv4. */ | |||||
237 | unsigned sa_tport_ip6 : 1; /**< Transports support IPv6. */ | |||||
238 | unsigned sa_tport_udp : 1; /**< Transports support UDP. */ | |||||
239 | unsigned sa_tport_tcp : 1; /**< Transports support TCP. */ | |||||
240 | unsigned sa_tport_sctp : 1; /**< Transports support SCTP. */ | |||||
241 | unsigned sa_tport_tls : 1; /**< Transports support TLS. */ | |||||
242 | unsigned sa_tport_ws : 1; /**< Transports support WS. */ | |||||
243 | unsigned sa_tport_wss : 1; /**< Transports support WSS. */ | |||||
244 | ||||||
245 | unsigned sa_use_naptr : 1; /**< Use NAPTR lookup */ | |||||
246 | unsigned sa_use_srv : 1; /**< Use SRV lookup */ | |||||
247 | ||||||
248 | unsigned sa_srv_503 : 1; /**< SRV: choice another destination on 503 RFC 3263 */ | |||||
249 | ||||||
250 | unsigned sa_tport_threadpool:1; /**< Transports use threadpool */ | |||||
251 | ||||||
252 | unsigned sa_rport:1; /**< Use rport at client */ | |||||
253 | unsigned sa_server_rport:2; /**< Use rport at server */ | |||||
254 | unsigned sa_tcp_rport:1; /**< Use rport with tcp, too */ | |||||
255 | unsigned sa_tls_rport:1; /**< Use rport with tls, too */ | |||||
256 | ||||||
257 | unsigned sa_auto_comp:1; /**< Automatically create compartments */ | |||||
258 | unsigned sa_in_timer:1; /**< Set when executing timers */ | |||||
259 | unsigned sa_use_timer_c:1; /**< Application has set value for timer C */ | |||||
260 | ||||||
261 | unsigned :0; | |||||
262 | ||||||
263 | #if HAVE_SMIME | |||||
264 | sm_object_t *sa_smime; | |||||
265 | #else | |||||
266 | void *sa_smime; | |||||
267 | #endif | |||||
268 | ||||||
269 | /** @MaxForwards */ | |||||
270 | sip_max_forwards_t sa_max_forwards[1]; | |||||
271 | ||||||
272 | /** Name of SigComp algorithm */ | |||||
273 | char const *sa_algorithm; | |||||
274 | /** Options for SigComp. */ | |||||
275 | char const *sa_sigcomp_options; | |||||
276 | char const* const *sa_sigcomp_option_list; | |||||
277 | char const *sa_sigcomp_option_free; | |||||
278 | ||||||
279 | nta_compressor_t *sa_compressor; | |||||
280 | ||||||
281 | /* Statistics */ | |||||
282 | struct { | |||||
283 | usize_t as_recv_msg; | |||||
284 | usize_t as_recv_request; | |||||
285 | usize_t as_recv_response; | |||||
286 | usize_t as_bad_message; | |||||
287 | usize_t as_bad_request; | |||||
288 | usize_t as_bad_response; | |||||
289 | usize_t as_drop_request; | |||||
290 | usize_t as_drop_response; | |||||
291 | usize_t as_client_tr; | |||||
292 | usize_t as_server_tr; | |||||
293 | usize_t as_dialog_tr; | |||||
294 | usize_t as_acked_tr; | |||||
295 | usize_t as_canceled_tr; | |||||
296 | usize_t as_trless_request; | |||||
297 | usize_t as_trless_to_tr; | |||||
298 | usize_t as_trless_response; | |||||
299 | usize_t as_trless_200; | |||||
300 | usize_t as_merged_request; | |||||
301 | usize_t as_sent_msg; | |||||
302 | usize_t as_sent_request; | |||||
303 | usize_t as_sent_response; | |||||
304 | usize_t as_retry_request; | |||||
305 | usize_t as_retry_response; | |||||
306 | usize_t as_recv_retry; | |||||
307 | usize_t as_tout_request; | |||||
308 | usize_t as_tout_response; | |||||
309 | } sa_stats[1]; | |||||
310 | ||||||
311 | /** Hash of dialogs. */ | |||||
312 | leg_htable_t sa_dialogs[1]; | |||||
313 | /** Default leg */ | |||||
314 | nta_leg_t *sa_default_leg; | |||||
315 | /** Hash of legs without dialogs. */ | |||||
316 | leg_htable_t sa_defaults[1]; | |||||
317 | /** Hash table for outgoing transactions */ | |||||
318 | outgoing_htable_t sa_outgoing[1]; | |||||
319 | nta_outgoing_t *sa_default_outgoing; | |||||
320 | /** Hash table for incoming transactions */ | |||||
321 | incoming_htable_t sa_incoming[1]; | |||||
322 | nta_incoming_t *sa_default_incoming; | |||||
323 | ||||||
324 | /* Queues (states) for outgoing client transactions */ | |||||
325 | struct { | |||||
326 | /** Queue for retrying client transactions */ | |||||
327 | nta_outgoing_t *re_list; | |||||
328 | nta_outgoing_t **re_t1; /**< Special place for T1 timer */ | |||||
329 | size_t re_length; /**< Length of sa_out.re_list */ | |||||
330 | ||||||
331 | outgoing_queue_t delayed[1]; | |||||
332 | outgoing_queue_t resolving[1]; | |||||
333 | ||||||
334 | outgoing_queue_t trying[1]; /* Timer F / Timer E */ | |||||
335 | outgoing_queue_t completed[1]; /* Timer K */ | |||||
336 | outgoing_queue_t terminated[1]; | |||||
337 | ||||||
338 | /* Special queues (states) for outgoing INVITE transactions */ | |||||
339 | outgoing_queue_t inv_calling[1]; /* Timer B/A */ | |||||
340 | outgoing_queue_t inv_proceeding[1]; /* Timer C */ | |||||
341 | outgoing_queue_t inv_completed[1]; /* Timer D */ | |||||
342 | ||||||
343 | /* Temporary queue for transactions waiting to be freed */ | |||||
344 | outgoing_queue_t *free; | |||||
345 | } sa_out; | |||||
346 | ||||||
347 | /* Queues (states) for incoming server transactions */ | |||||
348 | struct { | |||||
349 | /** Queue for retransmitting response of server transactions */ | |||||
350 | nta_incoming_t *re_list; | |||||
351 | nta_incoming_t **re_t1; /**< Special place for T1 timer */ | |||||
352 | size_t re_length; /**< Length of sa_in.re_list */ | |||||
353 | ||||||
354 | incoming_queue_t proceeding[1]; /**< Request received */ | |||||
355 | incoming_queue_t preliminary[1]; /**< 100rel sent */ | |||||
356 | incoming_queue_t completed[1]; /**< Final answer sent (non-invite). */ | |||||
357 | incoming_queue_t inv_completed[1]; /**< Final answer sent (INVITE). */ | |||||
358 | incoming_queue_t inv_confirmed[1]; /**< Final answer sent, ACK recvd. */ | |||||
359 | incoming_queue_t terminated[1]; /**< Terminated, ready to free. */ | |||||
360 | incoming_queue_t final_failed[1]; | |||||
361 | } sa_in; | |||||
362 | ||||||
363 | /* Special task for freeing memory */ | |||||
364 | su_clone_r sa_terminator; | |||||
365 | }; | |||||
366 | ||||||
367 | struct nta_leg_s | |||||
368 | { | |||||
369 | su_home_t leg_home[1]; | |||||
370 | hash_value_t leg_hash; | |||||
371 | ||||||
372 | unsigned leg_dialog : 1; | |||||
373 | unsigned leg_stateless : 1; /**< Process requests statelessly */ | |||||
374 | #ifdef NTA_STRICT_ROUTING | |||||
375 | unsigned leg_contact_set : 1; | |||||
376 | #else | |||||
377 | unsigned leg_loose_route : 1; /**< Topmost route in set is LR */ | |||||
378 | #endif | |||||
379 | unsigned leg_route_set : 1; /**< Route set has been saved */ | |||||
380 | unsigned leg_local_is_to : 1; /**< Backwards-compatibility. */ | |||||
381 | unsigned leg_tagged : 1; /**< Tagged after creation. | |||||
382 | * | |||||
383 | * Request missing @To tag matches | |||||
384 | * a tagged leg even after tagging. | |||||
385 | */ | |||||
386 | unsigned leg_compressed:1; | |||||
387 | unsigned:0; | |||||
388 | nta_request_f *leg_callback; | |||||
389 | nta_leg_magic_t *leg_magic; | |||||
390 | nta_agent_t *leg_agent; | |||||
391 | ||||||
392 | url_t const *leg_url; /**< Match incoming requests. */ | |||||
393 | char const *leg_method; /**< Match incoming requests. */ | |||||
394 | ||||||
395 | uint32_t leg_seq; /**< Sequence number for next transaction */ | |||||
396 | uint32_t leg_rseq; /**< Remote sequence number */ | |||||
397 | sip_call_id_t *leg_id; /**< Call ID */ | |||||
398 | sip_from_t *leg_remote; /**< Remote address (@To/@From) */ | |||||
399 | sip_to_t *leg_local; /**< Local address (@From/@To) */ | |||||
400 | ||||||
401 | sip_route_t *leg_route; /**< @Route for outgoing requests. */ | |||||
402 | sip_contact_t *leg_target; /**< Remote destination (from @Contact). */ | |||||
403 | }; | |||||
404 | ||||||
405 | struct nta_incoming_s | |||||
406 | { | |||||
407 | su_home_t *irq_home; | |||||
408 | hash_value_t irq_hash; | |||||
409 | nta_agent_t *irq_agent; | |||||
410 | nta_ack_cancel_f *irq_callback; | |||||
411 | nta_incoming_magic_t *irq_magic; | |||||
412 | ||||||
413 | /* Timeout/state queue */ | |||||
414 | nta_incoming_t **irq_prev; | |||||
415 | nta_incoming_t *irq_next; | |||||
416 | incoming_queue_t *irq_queue; | |||||
417 | ||||||
418 | /* Retry queue */ | |||||
419 | nta_incoming_t **irq_rprev; | |||||
420 | nta_incoming_t *irq_rnext; | |||||
421 | ||||||
422 | sip_method_t irq_method; | |||||
423 | sip_request_t *irq_rq; | |||||
424 | sip_from_t *irq_from; | |||||
425 | sip_to_t *irq_to; | |||||
426 | char const *irq_tag; | |||||
427 | sip_cseq_t *irq_cseq; | |||||
428 | sip_call_id_t *irq_call_id; | |||||
429 | sip_via_t *irq_via; | |||||
430 | sip_record_route_t *irq_record_route; | |||||
431 | char const *irq_branch; | |||||
432 | ||||||
433 | uint32_t irq_rseq; | |||||
434 | ||||||
435 | sip_timestamp_t *irq_timestamp; | |||||
436 | su_time_t irq_received; | |||||
437 | ||||||
438 | uint32_t irq_timeout; /**< Timer H, I, J */ | |||||
439 | uint32_t irq_retry; /**< Timer G */ | |||||
440 | unsigned short irq_interval; /**< Next timer */ | |||||
441 | ||||||
442 | short irq_status; | |||||
443 | ||||||
444 | unsigned irq_retries:8; | |||||
445 | unsigned irq_default:1; /**< Default transaction */ | |||||
446 | unsigned irq_canceled:1; /**< Transaction is canceled */ | |||||
447 | unsigned irq_completed:1; /**< Transaction is completed */ | |||||
448 | unsigned irq_confirmed:1; /**< Response has been acked */ | |||||
449 | unsigned irq_terminated:1; /**< Transaction is terminated */ | |||||
450 | unsigned irq_final_failed:1; /**< Sending final response failed */ | |||||
451 | unsigned irq_destroyed :1; /**< Transaction is destroyed */ | |||||
452 | unsigned irq_in_callback:1; /**< Callback is being invoked */ | |||||
453 | unsigned irq_reliable_tp:1; /**< Transport is reliable */ | |||||
454 | unsigned irq_sigcomp_zap:1; /**< Reset SigComp */ | |||||
455 | unsigned irq_must_100rel:1; /**< 100rel is required */ | |||||
456 | unsigned irq_extra_100:1; /**< 100 Trying should be sent */ | |||||
457 | unsigned irq_tag_set:1; /**< Tag is not from request */ | |||||
458 | unsigned irq_compressed:1; | |||||
459 | unsigned :0; | |||||
460 | ||||||
461 | tp_name_t irq_tpn[1]; | |||||
462 | tport_t *irq_tport; | |||||
463 | struct sigcomp_compartment *irq_cc; | |||||
464 | msg_t *irq_request; | |||||
465 | msg_t *irq_request2; /**< ACK/CANCEL */ | |||||
466 | msg_t *irq_response; | |||||
467 | ||||||
468 | nta_reliable_t *irq_reliable; /**< List of reliable responses */ | |||||
469 | }; | |||||
470 | ||||||
471 | struct nta_reliable_s | |||||
472 | { | |||||
473 | nta_reliable_t *rel_next; | |||||
474 | nta_incoming_t *rel_irq; | |||||
475 | nta_prack_f *rel_callback; | |||||
476 | nta_reliable_magic_t *rel_magic; | |||||
477 | uint32_t rel_rseq; | |||||
478 | unsigned short rel_status; | |||||
479 | unsigned rel_pracked:1; | |||||
480 | unsigned rel_precious:1; | |||||
481 | msg_t *rel_response; | |||||
482 | msg_t *rel_unsent; | |||||
483 | }; | |||||
484 | ||||||
485 | typedef struct sipdns_resolver sipdns_resolver_t; | |||||
486 | ||||||
487 | struct nta_outgoing_s | |||||
488 | { | |||||
489 | hash_value_t orq_hash; /**< Hash value */ | |||||
490 | nta_agent_t *orq_agent; | |||||
491 | nta_response_f *orq_callback; | |||||
492 | nta_outgoing_magic_t *orq_magic; | |||||
493 | ||||||
494 | /* Timeout/state queue */ | |||||
495 | nta_outgoing_t **orq_prev; | |||||
496 | nta_outgoing_t *orq_next; | |||||
497 | outgoing_queue_t *orq_queue; | |||||
498 | ||||||
499 | /* Retry queue */ | |||||
500 | nta_outgoing_t **orq_rprev; | |||||
501 | nta_outgoing_t *orq_rnext; | |||||
502 | ||||||
503 | sip_method_t orq_method; | |||||
504 | char const *orq_method_name; | |||||
505 | url_t const *orq_url; /**< Original RequestURI */ | |||||
506 | ||||||
507 | sip_from_t const *orq_from; | |||||
508 | sip_to_t const *orq_to; | |||||
509 | char const *orq_tag; /**< Tag from final response. */ | |||||
510 | ||||||
511 | sip_cseq_t const *orq_cseq; | |||||
512 | sip_call_id_t const *orq_call_id; | |||||
513 | ||||||
514 | msg_t *orq_request; | |||||
515 | msg_t *orq_response; | |||||
516 | ||||||
517 | su_time_t orq_sent; /**< When request was sent? */ | |||||
518 | unsigned orq_delay; /**< RTT estimate */ | |||||
519 | ||||||
520 | uint32_t orq_retry; /**< Timer A, E */ | |||||
521 | uint32_t orq_timeout; /**< Timer B, D, F, K */ | |||||
522 | ||||||
523 | unsigned short orq_interval; /**< Next timer A/E */ | |||||
524 | ||||||
525 | unsigned short orq_status; | |||||
526 | unsigned char orq_retries; /**< Number of tries this far */ | |||||
527 | ||||||
528 | unsigned orq_default:1; /**< This is default transaction */ | |||||
529 | unsigned orq_inserted:1; | |||||
530 | unsigned orq_resolved:1; | |||||
531 | unsigned orq_via_added:1; | |||||
532 | unsigned orq_prepared:1; | |||||
533 | unsigned orq_canceled:1; | |||||
534 | unsigned orq_terminated:1; | |||||
535 | unsigned orq_destroyed:1; | |||||
536 | unsigned orq_completed:1; | |||||
537 | unsigned orq_delayed:1; | |||||
538 | unsigned orq_user_tport:1; /**< Application provided tport - don't retry */ | |||||
539 | unsigned orq_try_tcp_instead:1; | |||||
540 | unsigned orq_try_udp_instead:1; | |||||
541 | unsigned orq_reliable:1; /**< Transport is reliable */ | |||||
542 | unsigned orq_call_tls_connect_timeout_is_set:1; /** Per Call connect timeout for outgoing requests using TLS set flag*/ | |||||
543 | ||||||
544 | unsigned orq_forked:1; /**< Tagged fork */ | |||||
545 | ||||||
546 | /* Attributes */ | |||||
547 | unsigned orq_sips:1; | |||||
548 | unsigned orq_uas:1; /**< Running this transaction as UAS */ | |||||
549 | unsigned orq_user_via:1; | |||||
550 | unsigned orq_stateless:1; | |||||
551 | unsigned orq_pass_100:1; | |||||
552 | unsigned orq_sigcomp_new:1; /**< Create compartment if needed */ | |||||
553 | unsigned orq_sigcomp_zap:1; /**< Reset SigComp after completing */ | |||||
554 | unsigned orq_must_100rel:1; | |||||
555 | unsigned orq_timestamp:1; /**< Insert @Timestamp header. */ | |||||
556 | unsigned orq_100rel:1; /**< Support 100rel */ | |||||
557 | unsigned:0; /* pad */ | |||||
558 | ||||||
559 | #if HAVE_SOFIA_SRESOLV1 | |||||
560 | sipdns_resolver_t *orq_resolver; | |||||
561 | #endif | |||||
562 | url_t *orq_route; /**< Route URL */ | |||||
563 | tp_name_t orq_tpn[1]; /**< Where to send request */ | |||||
564 | ||||||
565 | tport_t *orq_tport; | |||||
566 | struct sigcomp_compartment *orq_cc; | |||||
567 | tagi_t *orq_tags; /**< Tport tag items */ | |||||
568 | ||||||
569 | char const *orq_branch; /**< Transaction branch */ | |||||
570 | char const *orq_via_branch; /**< @Via branch */ | |||||
571 | ||||||
572 | int *orq_status2b; /**< Delayed response */ | |||||
573 | ||||||
574 | nta_outgoing_t *orq_cancel; /**< Delayed CANCEL transaction */ | |||||
575 | ||||||
576 | nta_outgoing_t *orq_forking; /**< Untagged transaction */ | |||||
577 | nta_outgoing_t *orq_forks; /**< Tagged transactions */ | |||||
578 | uint32_t orq_rseq; /**< Latest incoming rseq */ | |||||
579 | int orq_pending; /**< Request is pending in tport */ | |||||
580 | uint32_t orq_call_tls_connect_timeout; /** Per Call connect timeout for outgoing requests using TLS */ | |||||
581 | }; | |||||
582 | ||||||
583 | /* ------------------------------------------------------------------------- */ | |||||
584 | ||||||
585 | /* Internal tags */ | |||||
586 | ||||||
587 | /* Delay sending of request */ | |||||
588 | #define NTATAG_DELAY_SENDING(x)ntatag_delay_sending, tag_bool_v((x)) ntatag_delay_sending, tag_bool_v((x)) | |||||
589 | #define NTATAG_DELAY_SENDING_REF(x)ntatag_delay_sending_ref, tag_bool_vr(&(x)) \ | |||||
590 | ntatag_delay_sending_ref, tag_bool_vr(&(x)) | |||||
591 | ||||||
592 | extern tag_typedef_t ntatag_delay_sending; | |||||
593 | extern tag_typedef_t ntatag_delay_sending_ref; | |||||
594 | ||||||
595 | /* Allow sending incomplete responses */ | |||||
596 | #define NTATAG_INCOMPLETE(x)ntatag_incomplete, tag_bool_v((x)) ntatag_incomplete, tag_bool_v((x)) | |||||
597 | #define NTATAG_INCOMPLETE_REF(x)ntatag_incomplete_ref, tag_bool_vr(&(x)) \ | |||||
598 | ntatag_incomplete_ref, tag_bool_vr(&(x)) | |||||
599 | ||||||
600 | extern tag_typedef_t ntatag_incomplete; | |||||
601 | extern tag_typedef_t ntatag_incomplete_ref; | |||||
602 | ||||||
603 | nta_compressor_vtable_t *nta_compressor_vtable = NULL((void*)0); | |||||
604 | ||||||
605 | /* Agent */ | |||||
606 | static int agent_tag_init(nta_agent_t *self); | |||||
607 | static int agent_timer_init(nta_agent_t *agent); | |||||
608 | static void agent_timer(su_root_magic_t *rm, su_timer_t *, nta_agent_t *); | |||||
609 | static int agent_launch_terminator(nta_agent_t *agent); | |||||
610 | static void agent_kill_terminator(nta_agent_t *agent); | |||||
611 | static int agent_set_params(nta_agent_t *agent, tagi_t *tags); | |||||
612 | static void agent_set_udp_params(nta_agent_t *self, usize_t udp_mtu); | |||||
613 | static int agent_get_params(nta_agent_t *agent, tagi_t *tags); | |||||
614 | ||||||
615 | /* Transport interface */ | |||||
616 | static sip_via_t const *agent_tport_via(tport_t *tport); | |||||
617 | static int outgoing_insert_via(nta_outgoing_t *orq, sip_via_t const *); | |||||
618 | static int nta_tpn_by_via(tp_name_t *tpn, sip_via_t const *v, int *using_rport); | |||||
619 | ||||||
620 | static msg_t *nta_msg_create_for_transport(nta_agent_t *agent, int flags, | |||||
621 | char const data[], usize_t dlen, | |||||
622 | tport_t const *tport, | |||||
623 | tp_client_t *via); | |||||
624 | ||||||
625 | static int complete_response(msg_t *response, | |||||
626 | int status, char const *phrase, | |||||
627 | msg_t *request); | |||||
628 | ||||||
629 | static int mreply(nta_agent_t *agent, | |||||
630 | msg_t *reply, | |||||
631 | int status, char const *phrase, | |||||
632 | msg_t *req_msg, | |||||
633 | tport_t *tport, | |||||
634 | int incomplete, | |||||
635 | int sdwn_after, | |||||
636 | char const *to_tag, | |||||
637 | tag_type_t tag, tag_value_t value, ...); | |||||
638 | ||||||
639 | #define IF_SIGCOMP_TPTAG_COMPARTMENT(cc)!(cc && cc != ((void *)-1)) ? tag_skip : tptag_compartment , tag_ptr_v((cc)), TAG_IF(cc && cc != NONE, TPTAG_COMPARTMENT(cc))!(cc && cc != ((void *)-1)) ? tag_skip : tptag_compartment , tag_ptr_v((cc)), | |||||
640 | #define IF_SIGCOMP_TPTAG_COMPARTMENT_REF(cc)tptag_compartment_ref, tag_ptr_vr(&(cc), cc), TPTAG_COMPARTMENT_REF(cc)tptag_compartment_ref, tag_ptr_vr(&(cc), cc), | |||||
641 | ||||||
642 | struct sigcomp_compartment; | |||||
643 | ||||||
644 | struct sigcomp_compartment * | |||||
645 | nta_compartment_ref(struct sigcomp_compartment *cc); | |||||
646 | ||||||
647 | static | |||||
648 | struct sigcomp_compartment * | |||||
649 | agent_compression_compartment(nta_agent_t *sa, tport_t *tp, tp_name_t const *tpn, | |||||
650 | int new_if_needed); | |||||
651 | ||||||
652 | static | |||||
653 | int agent_accept_compressed(nta_agent_t *sa, msg_t *msg, | |||||
654 | struct sigcomp_compartment *cc); | |||||
655 | ||||||
656 | static int agent_close_compressor(nta_agent_t *sa, | |||||
657 | struct sigcomp_compartment *cc); | |||||
658 | ||||||
659 | static int agent_zap_compressor(nta_agent_t *sa, | |||||
660 | struct sigcomp_compartment *cc); | |||||
661 | ||||||
662 | ||||||
663 | static char const * stateful_branch(su_home_t *home, nta_agent_t *); | |||||
664 | static char const * stateless_branch(nta_agent_t *, msg_t *, sip_t const *, | |||||
665 | tp_name_t const *tp); | |||||
666 | ||||||
667 | #define NTA_BRANCH_PRIME(uint64_t)(0xB9591D1C361C6521ULL) SU_U64_C(0xB9591D1C361C6521)(uint64_t)(0xB9591D1C361C6521ULL) | |||||
668 | #define NTA_TAG_PRIME(uint64_t)(0xB9591D1C361C6521ULL) SU_U64_C(0xB9591D1C361C6521)(uint64_t)(0xB9591D1C361C6521ULL) | |||||
669 | ||||||
670 | #ifndef UINT32_MAX(4294967295U) | |||||
671 | #define UINT32_MAX(4294967295U) (0xffffffffU) | |||||
672 | #endif | |||||
673 | ||||||
674 | 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); | |||||
675 | static nta_leg_t *leg_find(nta_agent_t const *sa, | |||||
676 | char const *method_name, | |||||
677 | url_t const *request_uri, | |||||
678 | sip_call_id_t const *i, | |||||
679 | char const *from_tag, | |||||
680 | char const *to_tag); | |||||
681 | static nta_leg_t *dst_find(nta_agent_t const *sa, url_t const *u0, | |||||
682 | char const *method); | |||||
683 | static void leg_recv(nta_leg_t *, msg_t *, sip_t *, tport_t *); | |||||
684 | static void leg_free(nta_agent_t *sa, nta_leg_t *leg); | |||||
685 | ||||||
686 | #define NTA_HASH(i, cs)((i)->i_hash + 26839U * (uint32_t)(cs)) ((i)->i_hash + 26839U * (uint32_t)(cs)) | |||||
687 | ||||||
688 | 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); | |||||
689 | static nta_incoming_t *incoming_create(nta_agent_t *agent, | |||||
690 | msg_t *request, | |||||
691 | sip_t *sip, | |||||
692 | tport_t *tport, | |||||
693 | char const *tag); | |||||
694 | static int incoming_callback(nta_leg_t *leg, nta_incoming_t *irq, sip_t *sip); | |||||
695 | static void incoming_free(nta_incoming_t *irq); | |||||
696 | su_inlinestatic inline void incoming_cut_off(nta_incoming_t *irq); | |||||
697 | su_inlinestatic inline void incoming_reclaim(nta_incoming_t *irq); | |||||
698 | static void incoming_queue_init(incoming_queue_t *, | |||||
699 | unsigned timeout); | |||||
700 | static void incoming_queue_adjust(nta_agent_t *sa, | |||||
701 | incoming_queue_t *queue, | |||||
702 | unsigned timeout); | |||||
703 | ||||||
704 | static nta_incoming_t *incoming_find(nta_agent_t const *agent, | |||||
705 | sip_t const *sip, | |||||
706 | sip_via_t const *v, | |||||
707 | nta_incoming_t **merge, | |||||
708 | nta_incoming_t **ack, | |||||
709 | nta_incoming_t **cancel); | |||||
710 | static int incoming_reply(nta_incoming_t *irq, msg_t *msg, sip_t *sip); | |||||
711 | su_inlinestatic inline int incoming_recv(nta_incoming_t *irq, msg_t *msg, sip_t *sip, | |||||
712 | tport_t *tport); | |||||
713 | su_inlinestatic inline int incoming_ack(nta_incoming_t *irq, msg_t *msg, sip_t *sip, | |||||
714 | tport_t *tport); | |||||
715 | su_inlinestatic inline int incoming_cancel(nta_incoming_t *irq, msg_t *msg, sip_t *sip, | |||||
716 | tport_t *tport); | |||||
717 | static void request_merge(nta_agent_t *, | |||||
718 | msg_t *msg, sip_t *sip, tport_t *tport, | |||||
719 | char const *to_tag); | |||||
720 | su_inlinestatic inline int incoming_timestamp(nta_incoming_t *, msg_t *, sip_t *); | |||||
721 | static void _nta_incoming_timer(nta_agent_t *); | |||||
722 | ||||||
723 | static nta_reliable_t *reliable_mreply(nta_incoming_t *, | |||||
724 | nta_prack_f *, nta_reliable_magic_t *, | |||||
725 | msg_t *, sip_t *); | |||||
726 | static int reliable_send(nta_incoming_t *, nta_reliable_t *, msg_t *, sip_t *); | |||||
727 | static int reliable_final(nta_incoming_t *irq, msg_t *msg, sip_t *sip); | |||||
728 | static msg_t *reliable_response(nta_incoming_t *irq); | |||||
729 | static nta_reliable_t *reliable_find(nta_agent_t const *, sip_t const *); | |||||
730 | static int reliable_recv(nta_reliable_t *rel, msg_t *, sip_t *, tport_t *); | |||||
731 | static void reliable_flush(nta_incoming_t *irq); | |||||
732 | static void reliable_timeout(nta_incoming_t *irq, int timeout); | |||||
733 | ||||||
734 | 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); | |||||
735 | static nta_outgoing_t *outgoing_create(nta_agent_t *agent, | |||||
736 | nta_response_f *callback, | |||||
737 | nta_outgoing_magic_t *magic, | |||||
738 | url_string_t const *route_url, | |||||
739 | tp_name_t const *tpn, | |||||
740 | msg_t *msg, | |||||
741 | tag_type_t tag, tag_value_t value, ...); | |||||
742 | static void outgoing_queue_init(outgoing_queue_t *, | |||||
743 | unsigned timeout); | |||||
744 | static void outgoing_queue_adjust(nta_agent_t *sa, | |||||
745 | outgoing_queue_t *queue, | |||||
746 | unsigned timeout); | |||||
747 | static void outgoing_free(nta_outgoing_t *orq); | |||||
748 | su_inlinestatic inline void outgoing_cut_off(nta_outgoing_t *orq); | |||||
749 | su_inlinestatic inline void outgoing_reclaim(nta_outgoing_t *orq); | |||||
750 | static nta_outgoing_t *outgoing_find(nta_agent_t const *sa, | |||||
751 | msg_t const *msg, | |||||
752 | sip_t const *sip, | |||||
753 | sip_via_t const *v); | |||||
754 | static int outgoing_recv(nta_outgoing_t *orq, int status, msg_t *, sip_t *); | |||||
755 | static void outgoing_default_recv(nta_outgoing_t *, int, msg_t *, sip_t *); | |||||
756 | static void _nta_outgoing_timer(nta_agent_t *); | |||||
757 | static int outgoing_recv_reliable(nta_outgoing_t *orq, msg_t *msg, sip_t *sip); | |||||
758 | ||||||
759 | /* Internal message passing */ | |||||
760 | union sm_arg_u { | |||||
761 | struct outgoing_recv_s { | |||||
762 | nta_outgoing_t *orq; | |||||
763 | msg_t *msg; | |||||
764 | sip_t *sip; | |||||
765 | int status; | |||||
766 | } a_outgoing_recv[1]; | |||||
767 | ||||||
768 | incoming_queue_t a_incoming_queue[1]; | |||||
769 | outgoing_queue_t a_outgoing_queue[1]; | |||||
770 | }; | |||||
771 | ||||||
772 | /* Global module data */ | |||||
773 | ||||||
774 | /**@var char const NTA_DEBUG[]; | |||||
775 | * | |||||
776 | * Environment variable determining the default debug log level. | |||||
777 | * | |||||
778 | * The NTA_DEBUG environment variable is used to determine the default | |||||
779 | * debug logging level. The normal level is 3. | |||||
780 | * | |||||
781 | * @sa <sofia-sip/su_debug.h>, #su_log_global, #SOFIA_DEBUG | |||||
782 | */ | |||||
783 | #ifdef DOXYGEN | |||||
784 | extern char const NTA_DEBUG[]; /* dummy declaration for Doxygen */ | |||||
785 | #endif | |||||
786 | ||||||
787 | #ifndef SU_DEBUG0 | |||||
788 | #define SU_DEBUG0 3 | |||||
789 | #endif | |||||
790 | ||||||
791 | /**Debug log for @b nta module. | |||||
792 | * | |||||
793 | * The nta_log is the log object used by @b nta module. The level of | |||||
794 | * nta_log is set using #NTA_DEBUG environment variable. | |||||
795 | */ | |||||
796 | 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), } }; | |||||
797 | ||||||
798 | /* ====================================================================== */ | |||||
799 | /* 1) Agent */ | |||||
800 | ||||||
801 | /** | |||||
802 | * Create an NTA agent object. | |||||
803 | * | |||||
804 | * Create an NTA agent object. The agent | |||||
805 | * object creates and binds a server socket with address specified in @e url. | |||||
806 | * If the @e host portion of the @e url is @c "*", the agent listens to all | |||||
807 | * addresses available on the host. | |||||
808 | * | |||||
809 | * When a message is received, the agent object parses it. If the result is | |||||
810 | * a valid SIP message, the agent object passes the message to the | |||||
811 | * application by invoking the nta_message_f @e callback function. | |||||
812 | * | |||||
813 | * @note | |||||
814 | * The @e url can be either parsed url (of type url_t ()), or a valid | |||||
815 | * SIP URL as a string. | |||||
816 | * | |||||
817 | * @note | |||||
818 | * If @e url is @c NULL, the default @e url @c "sip:*" is used. | |||||
819 | * @par | |||||
820 | * If @e url is @c NONE (iow, (void*)-1), no server sockets are bound. | |||||
821 | * @par | |||||
822 | * If @p transport parameters are specified in @a url, agent uses only | |||||
823 | * specified transport type. | |||||
824 | * | |||||
825 | * @par | |||||
826 | * If an @p maddr parameter is specified in @e url, agent binds to the | |||||
827 | * specified address, but uses @e host part of @e url when it generates | |||||
828 | * @Contact and @Via headers. The @p maddr parameter is also included, | |||||
829 | * unless it equals to @c INADDR_ANY (@p 0.0.0.0 or @p [::]). | |||||
830 | * | |||||
831 | * @param root pointer to a su_root_t used for synchronization | |||||
832 | * @param contact_url URL that agent uses to bind the server sockets | |||||
833 | * @param callback pointer to callback function | |||||
834 | * @param magic pointer to user data | |||||
835 | * @param tag,value,... tagged arguments | |||||
836 | * | |||||
837 | * @TAGS | |||||
838 | * NTATAG_ALIASES(), | |||||
839 | * NTATAG_BAD_REQ_MASK(), NTATAG_BAD_RESP_MASK(), NTATAG_BLACKLIST(), | |||||
840 | * NTATAG_CANCEL_2543(), NTATAG_CANCEL_487(), NTATAG_CLIENT_RPORT(), | |||||
841 | * NTATAG_DEBUG_DROP_PROB(), NTATAG_DEFAULT_PROXY(), | |||||
842 | * NTATAG_EXTRA_100(), NTATAG_GRAYLIST(), | |||||
843 | * NTATAG_MAXSIZE(), NTATAG_MAX_FORWARDS(), NTATAG_MERGE_482(), NTATAG_MCLASS() | |||||
844 | * NTATAG_PASS_100(), NTATAG_PASS_408(), NTATAG_PRELOAD(), NTATAG_PROGRESS(), | |||||
845 | * NTATAG_REL100(), | |||||
846 | * NTATAG_SERVER_RPORT(), | |||||
847 | * NTATAG_SIPFLAGS(), | |||||
848 | * NTATAG_SIP_T1X64(), NTATAG_SIP_T1(), NTATAG_SIP_T2(), NTATAG_SIP_T4(), | |||||
849 | * NTATAG_STATELESS(), | |||||
850 | * NTATAG_TAG_3261(), NTATAG_TCP_RPORT(), NTATAG_TIMEOUT_408(), | |||||
851 | * NTATAG_TLS_RPORT(), NTATAG_TLS_ORQ_CONNECT_TIMEOUT(), | |||||
852 | * NTATAG_TIMER_C(), NTATAG_MAX_PROCEEDING(), | |||||
853 | * NTATAG_UA(), NTATAG_UDP_MTU(), NTATAG_USER_VIA(), | |||||
854 | * NTATAG_USE_NAPTR(), NTATAG_USE_SRV() and NTATAG_USE_TIMESTAMP(). | |||||
855 | * | |||||
856 | * @note The value from following tags are stored, but they currently do nothing: | |||||
857 | * NTATAG_SIGCOMP_ALGORITHM(), NTATAG_SIGCOMP_OPTIONS(), NTATAG_SMIME() | |||||
858 | * | |||||
859 | * @note It is possible to provide @c (url_string_t*)-1 as @a contact_url. | |||||
860 | * In that case, no server sockets are bound. | |||||
861 | * | |||||
862 | * @retval handle to the agent when successful, | |||||
863 | * @retval NULL upon an error. | |||||
864 | * | |||||
865 | * @sa NUTAG_ | |||||
866 | */ | |||||
867 | nta_agent_t *nta_agent_create(su_root_t *root, | |||||
868 | url_string_t const *contact_url, | |||||
869 | nta_message_f *callback, | |||||
870 | nta_agent_magic_t *magic, | |||||
871 | tag_type_t tag, tag_value_t value, ...) | |||||
872 | { | |||||
873 | nta_agent_t *agent; | |||||
874 | ta_list ta; | |||||
875 | ||||||
876 | if (root == NULL((void*)0)) | |||||
877 | return su_seterrno(EINVAL22), NULL((void*)0); | |||||
878 | ||||||
879 | ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value = (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag ) == tag_next && (ta_start__value) != 0) { ta_start__tag = ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag == tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag == tag_next) { ta_start__value = ((tagi_t *)ta_start__value) ->t_value; } else { ta_start__tag = tag_next; break; } } ( ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value ; if (ta_start__tag != ((void*)0) && ta_start__tag != tag_null && ta_start__tag != tag_next) { va_list ta_start__ap ; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag = tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap ); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value = 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0); | |||||
880 | ||||||
881 | if ((agent = su_home_new(sizeof(*agent)))) { | |||||
882 | unsigned timer_c = 0, timer_d = 32000; | |||||
883 | ||||||
884 | agent->sa_root = root; | |||||
885 | agent->sa_callback = callback; | |||||
886 | agent->sa_magic = magic; | |||||
887 | agent->sa_flags = MSG_DO_CANONICMSG_FLG_CANONIC; | |||||
888 | ||||||
889 | agent->sa_maxsize = 2 * 1024 * 1024; /* 2 MB */ | |||||
890 | agent->sa_bad_req_mask = | |||||
891 | /* | |||||
892 | * Bit-wise not of these - what is left is suitable for UAs with | |||||
893 | * 100rel, timer, events, publish | |||||
894 | */ | |||||
895 | (unsigned) ~(sip_mask_response | sip_mask_proxy | sip_mask_registrar | | |||||
896 | sip_mask_pref | sip_mask_privacy); | |||||
897 | agent->sa_bad_resp_mask = | |||||
898 | (unsigned) ~(sip_mask_request | sip_mask_proxy | sip_mask_registrar | | |||||
899 | sip_mask_pref | sip_mask_privacy); | |||||
900 | agent->sa_t1 = NTA_SIP_T1; | |||||
901 | agent->sa_t2 = NTA_SIP_T2; | |||||
902 | agent->sa_t4 = NTA_SIP_T4; | |||||
903 | agent->sa_t1x64 = 64 * NTA_SIP_T1; | |||||
904 | agent->sa_timer_c = 185 * 1000; | |||||
905 | agent->sa_graylist = 600; | |||||
906 | agent->sa_drop_prob = 0; | |||||
907 | agent->sa_is_a_uas = 0; | |||||
908 | agent->sa_progress = 60 * 1000; | |||||
909 | agent->sa_user_via = 0; | |||||
910 | agent->sa_extra_100 = 0; | |||||
911 | agent->sa_pass_100 = 0; | |||||
912 | agent->sa_timeout_408 = 1; | |||||
913 | agent->sa_pass_408 = 0; | |||||
914 | agent->sa_merge_482 = 0; | |||||
915 | agent->sa_cancel_2543 = 0; | |||||
916 | agent->sa_cancel_487 = 1; | |||||
917 | agent->sa_invite_100rel = 0; | |||||
918 | agent->sa_timestamp = 0; | |||||
919 | agent->sa_use_naptr = 1; | |||||
920 | agent->sa_use_srv = 1; | |||||
921 | agent->sa_srv_503 = 1; | |||||
922 | agent->sa_auto_comp = 0; | |||||
923 | agent->sa_server_rport = 1; | |||||
924 | ||||||
925 | /* RFC 3261 section 8.1.1.6 */ | |||||
926 | sip_max_forwards_init(agent->sa_max_forwards); | |||||
927 | ||||||
928 | if (getenv("SIPCOMPACT")) | |||||
929 | agent->sa_flags |= MSG_DO_COMPACTMSG_FLG_COMPACT; | |||||
930 | ||||||
931 | agent_set_params(agent, ta_args(ta)(ta).tl); | |||||
932 | ||||||
933 | if (agent->sa_mclass == NULL((void*)0)) | |||||
934 | agent->sa_mclass = sip_default_mclass(); | |||||
935 | ||||||
936 | agent->sa_in.re_t1 = &agent->sa_in.re_list; | |||||
937 | ||||||
938 | incoming_queue_init(agent->sa_in.proceeding, 0); | |||||
939 | incoming_queue_init(agent->sa_in.preliminary, agent->sa_t1x64); /* P1 */ | |||||
940 | incoming_queue_init(agent->sa_in.inv_completed, agent->sa_t1x64); /* H */ | |||||
941 | incoming_queue_init(agent->sa_in.inv_confirmed, agent->sa_t4); /* I */ | |||||
942 | incoming_queue_init(agent->sa_in.completed, agent->sa_t1x64); /* J */ | |||||
943 | incoming_queue_init(agent->sa_in.terminated, 0); | |||||
944 | incoming_queue_init(agent->sa_in.final_failed, 0); | |||||
945 | ||||||
946 | agent->sa_out.re_t1 = &agent->sa_out.re_list; | |||||
947 | ||||||
948 | if (agent->sa_use_timer_c || !agent->sa_is_a_uas) | |||||
949 | timer_c = agent->sa_timer_c; | |||||
950 | if (timer_d < agent->sa_t1x64) | |||||
951 | timer_d = agent->sa_t1x64; | |||||
952 | ||||||
953 | outgoing_queue_init(agent->sa_out.delayed, 0); | |||||
954 | outgoing_queue_init(agent->sa_out.resolving, 0); | |||||
955 | outgoing_queue_init(agent->sa_out.trying, agent->sa_t1x64); /* F */ | |||||
956 | outgoing_queue_init(agent->sa_out.completed, agent->sa_t4); /* K */ | |||||
957 | outgoing_queue_init(agent->sa_out.terminated, 0); | |||||
958 | /* Special queues (states) for outgoing INVITE transactions */ | |||||
959 | outgoing_queue_init(agent->sa_out.inv_calling, agent->sa_t1x64); /* B */ | |||||
960 | outgoing_queue_init(agent->sa_out.inv_proceeding, timer_c); /* C */ | |||||
961 | outgoing_queue_init(agent->sa_out.inv_completed, timer_d); /* D */ | |||||
962 | ||||||
963 | if (leg_htable_resize(agent->sa_home, agent->sa_dialogs, 0) < 0 || | |||||
964 | leg_htable_resize(agent->sa_home, agent->sa_defaults, 0) < 0 || | |||||
965 | outgoing_htable_resize(agent->sa_home, agent->sa_outgoing, 0) < 0 || | |||||
966 | incoming_htable_resize(agent->sa_home, agent->sa_incoming, 0) < 0) { | |||||
967 | SU_DEBUG_0(("nta_agent_create: failure with %s\n", "hash tables"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 0 ? (_su_llog(nta_log, 0, "nta.c", (const char *)__func__ , 967, "nta_agent_create: failure with %s\n", "hash tables")) : (void)0); | |||||
968 | goto deinit; | |||||
969 | } | |||||
970 | SU_DEBUG_9(("nta_agent_create: initialized %s\n", "hash tables"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 970, "nta_agent_create: initialized %s\n", "hash tables")) : (void)0); | |||||
971 | ||||||
972 | if (contact_url != (url_string_t *)-1 && | |||||
973 | nta_agent_add_tport(agent, contact_url, ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta). tl[1].t_value) < 0) { | |||||
974 | SU_DEBUG_7(("nta_agent_create: failure with %s\n", "transport"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__ , 974, "nta_agent_create: failure with %s\n", "transport")) : (void)0); | |||||
975 | goto deinit; | |||||
976 | } | |||||
977 | SU_DEBUG_9(("nta_agent_create: initialized %s\n", "transports"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 977, "nta_agent_create: initialized %s\n", "transports")) : (void)0); | |||||
978 | ||||||
979 | if (agent_tag_init(agent) < 0) { | |||||
980 | SU_DEBUG_3(("nta_agent_create: failure with %s\n", "random identifiers"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 980, "nta_agent_create: failure with %s\n", "random identifiers" )) : (void)0); | |||||
981 | goto deinit; | |||||
982 | } | |||||
983 | SU_DEBUG_9(("nta_agent_create: initialized %s\n", "random identifiers"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 983, "nta_agent_create: initialized %s\n", "random identifiers" )) : (void)0); | |||||
984 | ||||||
985 | if (agent_timer_init(agent) < 0) { | |||||
986 | SU_DEBUG_0(("nta_agent_create: failure with %s\n", "timer"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 0 ? (_su_llog(nta_log, 0, "nta.c", (const char *)__func__ , 986, "nta_agent_create: failure with %s\n", "timer")) : (void )0); | |||||
987 | goto deinit; | |||||
988 | } | |||||
989 | SU_DEBUG_9(("nta_agent_create: initialized %s\n", "timer"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 989, "nta_agent_create: initialized %s\n", "timer")) : (void )0); | |||||
990 | ||||||
991 | if (agent_launch_terminator(agent) == 0) | |||||
992 | SU_DEBUG_9(("nta_agent_create: initialized %s\n", "threads"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 992, "nta_agent_create: initialized %s\n", "threads")) : (void )0); | |||||
993 | ||||||
994 | #if HAVE_SOFIA_SRESOLV1 | |||||
995 | agent->sa_resolver = sres_resolver_create(root, NULL((void*)0), ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta). tl[1].t_value); | |||||
996 | if (!agent->sa_resolver) { | |||||
997 | SU_DEBUG_0(("nta_agent_create: failure with %s\n", "resolver"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 0 ? (_su_llog(nta_log, 0, "nta.c", (const char *)__func__ , 997, "nta_agent_create: failure with %s\n", "resolver")) : ( void)0); | |||||
998 | } | |||||
999 | SU_DEBUG_9(("nta_agent_create: initialized %s\n", "resolver"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 999, "nta_agent_create: initialized %s\n", "resolver")) : ( void)0); | |||||
1000 | #endif | |||||
1001 | ||||||
1002 | ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value ))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta) .ap)); | |||||
1003 | ||||||
1004 | return agent; | |||||
1005 | ||||||
1006 | deinit: | |||||
1007 | nta_agent_destroy(agent); | |||||
1008 | } | |||||
1009 | ||||||
1010 | ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value ))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta) .ap)); | |||||
1011 | ||||||
1012 | return NULL((void*)0); | |||||
1013 | } | |||||
1014 | ||||||
1015 | /** | |||||
1016 | * Destroy an NTA agent object. | |||||
1017 | * | |||||
1018 | * @param agent the NTA agent object to be destroyed. | |||||
1019 | * | |||||
1020 | */ | |||||
1021 | void nta_agent_destroy(nta_agent_t *agent) | |||||
1022 | { | |||||
1023 | if (agent) { | |||||
1024 | size_t i; | |||||
1025 | outgoing_htable_t *oht = agent->sa_outgoing; | |||||
1026 | incoming_htable_t *iht = agent->sa_incoming; | |||||
1027 | /* Currently, this is pretty pointless, as legs don't keep any resources */ | |||||
1028 | leg_htable_t *lht; | |||||
1029 | nta_leg_t *leg; | |||||
1030 | ||||||
1031 | for (i = 0, lht = agent->sa_dialogs; i < lht->lht_size; i++) { | |||||
1032 | if ((leg = lht->lht_table[i])) { | |||||
1033 | SU_DEBUG_3(("nta_agent_destroy: destroying dialog with <"(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 1035, "nta_agent_destroy: destroying dialog with <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">\n", (leg->leg_remote->a_url)->url_scheme ? (leg ->leg_remote->a_url)->url_scheme : "", (leg->leg_remote ->a_url)->url_type != url_any && (leg->leg_remote ->a_url)->url_scheme && (leg->leg_remote-> a_url)->url_scheme[0] ? ":" : "", (leg->leg_remote-> a_url)->url_root && ((leg->leg_remote->a_url )->url_host || (leg->leg_remote->a_url)->url_user ) ? "//" : "", (leg->leg_remote->a_url)->url_user ? ( leg->leg_remote->a_url)->url_user : "", (leg->leg_remote ->a_url)->url_user && (leg->leg_remote->a_url )->url_password ? ":" : "", (leg->leg_remote->a_url) ->url_user && (leg->leg_remote->a_url)->url_password ? (leg->leg_remote->a_url)->url_password : "", (leg ->leg_remote->a_url)->url_user && (leg->leg_remote ->a_url)->url_host ? "@" : "", (leg->leg_remote-> a_url)->url_host ? (leg->leg_remote->a_url)->url_host : "", (leg->leg_remote->a_url)->url_host && (leg->leg_remote->a_url)->url_port ? ":" : "", (leg ->leg_remote->a_url)->url_host && (leg->leg_remote ->a_url)->url_port ? (leg->leg_remote->a_url)-> url_port : "", (leg->leg_remote->a_url)->url_root && (leg->leg_remote->a_url)->url_path ? "/" : "", (leg ->leg_remote->a_url)->url_path ? (leg->leg_remote ->a_url)->url_path : "", (leg->leg_remote->a_url) ->url_params ? ";" : "", (leg->leg_remote->a_url)-> url_params ? (leg->leg_remote->a_url)->url_params : "" , (leg->leg_remote->a_url)->url_headers ? "?" : "", ( leg->leg_remote->a_url)->url_headers ? (leg->leg_remote ->a_url)->url_headers : "", (leg->leg_remote->a_url )->url_fragment ? "#" : "", (leg->leg_remote->a_url) ->url_fragment ? (leg->leg_remote->a_url)->url_fragment : "")) : (void)0) | |||||
1034 | URL_PRINT_FORMAT ">\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 1035, "nta_agent_destroy: destroying dialog with <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">\n", (leg->leg_remote->a_url)->url_scheme ? (leg ->leg_remote->a_url)->url_scheme : "", (leg->leg_remote ->a_url)->url_type != url_any && (leg->leg_remote ->a_url)->url_scheme && (leg->leg_remote-> a_url)->url_scheme[0] ? ":" : "", (leg->leg_remote-> a_url)->url_root && ((leg->leg_remote->a_url )->url_host || (leg->leg_remote->a_url)->url_user ) ? "//" : "", (leg->leg_remote->a_url)->url_user ? ( leg->leg_remote->a_url)->url_user : "", (leg->leg_remote ->a_url)->url_user && (leg->leg_remote->a_url )->url_password ? ":" : "", (leg->leg_remote->a_url) ->url_user && (leg->leg_remote->a_url)->url_password ? (leg->leg_remote->a_url)->url_password : "", (leg ->leg_remote->a_url)->url_user && (leg->leg_remote ->a_url)->url_host ? "@" : "", (leg->leg_remote-> a_url)->url_host ? (leg->leg_remote->a_url)->url_host : "", (leg->leg_remote->a_url)->url_host && (leg->leg_remote->a_url)->url_port ? ":" : "", (leg ->leg_remote->a_url)->url_host && (leg->leg_remote ->a_url)->url_port ? (leg->leg_remote->a_url)-> url_port : "", (leg->leg_remote->a_url)->url_root && (leg->leg_remote->a_url)->url_path ? "/" : "", (leg ->leg_remote->a_url)->url_path ? (leg->leg_remote ->a_url)->url_path : "", (leg->leg_remote->a_url) ->url_params ? ";" : "", (leg->leg_remote->a_url)-> url_params ? (leg->leg_remote->a_url)->url_params : "" , (leg->leg_remote->a_url)->url_headers ? "?" : "", ( leg->leg_remote->a_url)->url_headers ? (leg->leg_remote ->a_url)->url_headers : "", (leg->leg_remote->a_url )->url_fragment ? "#" : "", (leg->leg_remote->a_url) ->url_fragment ? (leg->leg_remote->a_url)->url_fragment : "")) : (void)0) | |||||
1035 | URL_PRINT_ARGS(leg->leg_remote->a_url)))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 1035, "nta_agent_destroy: destroying dialog with <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">\n", (leg->leg_remote->a_url)->url_scheme ? (leg ->leg_remote->a_url)->url_scheme : "", (leg->leg_remote ->a_url)->url_type != url_any && (leg->leg_remote ->a_url)->url_scheme && (leg->leg_remote-> a_url)->url_scheme[0] ? ":" : "", (leg->leg_remote-> a_url)->url_root && ((leg->leg_remote->a_url )->url_host || (leg->leg_remote->a_url)->url_user ) ? "//" : "", (leg->leg_remote->a_url)->url_user ? ( leg->leg_remote->a_url)->url_user : "", (leg->leg_remote ->a_url)->url_user && (leg->leg_remote->a_url )->url_password ? ":" : "", (leg->leg_remote->a_url) ->url_user && (leg->leg_remote->a_url)->url_password ? (leg->leg_remote->a_url)->url_password : "", (leg ->leg_remote->a_url)->url_user && (leg->leg_remote ->a_url)->url_host ? "@" : "", (leg->leg_remote-> a_url)->url_host ? (leg->leg_remote->a_url)->url_host : "", (leg->leg_remote->a_url)->url_host && (leg->leg_remote->a_url)->url_port ? ":" : "", (leg ->leg_remote->a_url)->url_host && (leg->leg_remote ->a_url)->url_port ? (leg->leg_remote->a_url)-> url_port : "", (leg->leg_remote->a_url)->url_root && (leg->leg_remote->a_url)->url_path ? "/" : "", (leg ->leg_remote->a_url)->url_path ? (leg->leg_remote ->a_url)->url_path : "", (leg->leg_remote->a_url) ->url_params ? ";" : "", (leg->leg_remote->a_url)-> url_params ? (leg->leg_remote->a_url)->url_params : "" , (leg->leg_remote->a_url)->url_headers ? "?" : "", ( leg->leg_remote->a_url)->url_headers ? (leg->leg_remote ->a_url)->url_headers : "", (leg->leg_remote->a_url )->url_fragment ? "#" : "", (leg->leg_remote->a_url) ->url_fragment ? (leg->leg_remote->a_url)->url_fragment : "")) : (void)0); | |||||
1036 | leg_free(agent, leg); | |||||
1037 | } | |||||
1038 | } | |||||
1039 | ||||||
1040 | for (i = 0, lht = agent->sa_defaults; i < lht->lht_size; i++) { | |||||
1041 | if ((leg = lht->lht_table[i])) { | |||||
1042 | SU_DEBUG_3(("%s: destroying leg for <"(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 1044, "%s: destroying leg for <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">\n", __func__, (leg->leg_url)->url_scheme ? (leg-> leg_url)->url_scheme : "", (leg->leg_url)->url_type != url_any && (leg->leg_url)->url_scheme && (leg->leg_url)->url_scheme[0] ? ":" : "", (leg->leg_url )->url_root && ((leg->leg_url)->url_host || ( leg->leg_url)->url_user) ? "//" : "", (leg->leg_url) ->url_user ? (leg->leg_url)->url_user : "", (leg-> leg_url)->url_user && (leg->leg_url)->url_password ? ":" : "", (leg->leg_url)->url_user && (leg-> leg_url)->url_password ? (leg->leg_url)->url_password : "", (leg->leg_url)->url_user && (leg->leg_url )->url_host ? "@" : "", (leg->leg_url)->url_host ? ( leg->leg_url)->url_host : "", (leg->leg_url)->url_host && (leg->leg_url)->url_port ? ":" : "", (leg-> leg_url)->url_host && (leg->leg_url)->url_port ? (leg->leg_url)->url_port : "", (leg->leg_url)-> url_root && (leg->leg_url)->url_path ? "/" : "" , (leg->leg_url)->url_path ? (leg->leg_url)->url_path : "", (leg->leg_url)->url_params ? ";" : "", (leg-> leg_url)->url_params ? (leg->leg_url)->url_params : "" , (leg->leg_url)->url_headers ? "?" : "", (leg->leg_url )->url_headers ? (leg->leg_url)->url_headers : "", ( leg->leg_url)->url_fragment ? "#" : "", (leg->leg_url )->url_fragment ? (leg->leg_url)->url_fragment : "") ) : (void)0) | |||||
1043 | URL_PRINT_FORMAT ">\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 1044, "%s: destroying leg for <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">\n", __func__, (leg->leg_url)->url_scheme ? (leg-> leg_url)->url_scheme : "", (leg->leg_url)->url_type != url_any && (leg->leg_url)->url_scheme && (leg->leg_url)->url_scheme[0] ? ":" : "", (leg->leg_url )->url_root && ((leg->leg_url)->url_host || ( leg->leg_url)->url_user) ? "//" : "", (leg->leg_url) ->url_user ? (leg->leg_url)->url_user : "", (leg-> leg_url)->url_user && (leg->leg_url)->url_password ? ":" : "", (leg->leg_url)->url_user && (leg-> leg_url)->url_password ? (leg->leg_url)->url_password : "", (leg->leg_url)->url_user && (leg->leg_url )->url_host ? "@" : "", (leg->leg_url)->url_host ? ( leg->leg_url)->url_host : "", (leg->leg_url)->url_host && (leg->leg_url)->url_port ? ":" : "", (leg-> leg_url)->url_host && (leg->leg_url)->url_port ? (leg->leg_url)->url_port : "", (leg->leg_url)-> url_root && (leg->leg_url)->url_path ? "/" : "" , (leg->leg_url)->url_path ? (leg->leg_url)->url_path : "", (leg->leg_url)->url_params ? ";" : "", (leg-> leg_url)->url_params ? (leg->leg_url)->url_params : "" , (leg->leg_url)->url_headers ? "?" : "", (leg->leg_url )->url_headers ? (leg->leg_url)->url_headers : "", ( leg->leg_url)->url_fragment ? "#" : "", (leg->leg_url )->url_fragment ? (leg->leg_url)->url_fragment : "") ) : (void)0) | |||||
1044 | __func__, URL_PRINT_ARGS(leg->leg_url)))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 1044, "%s: destroying leg for <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">\n", __func__, (leg->leg_url)->url_scheme ? (leg-> leg_url)->url_scheme : "", (leg->leg_url)->url_type != url_any && (leg->leg_url)->url_scheme && (leg->leg_url)->url_scheme[0] ? ":" : "", (leg->leg_url )->url_root && ((leg->leg_url)->url_host || ( leg->leg_url)->url_user) ? "//" : "", (leg->leg_url) ->url_user ? (leg->leg_url)->url_user : "", (leg-> leg_url)->url_user && (leg->leg_url)->url_password ? ":" : "", (leg->leg_url)->url_user && (leg-> leg_url)->url_password ? (leg->leg_url)->url_password : "", (leg->leg_url)->url_user && (leg->leg_url )->url_host ? "@" : "", (leg->leg_url)->url_host ? ( leg->leg_url)->url_host : "", (leg->leg_url)->url_host && (leg->leg_url)->url_port ? ":" : "", (leg-> leg_url)->url_host && (leg->leg_url)->url_port ? (leg->leg_url)->url_port : "", (leg->leg_url)-> url_root && (leg->leg_url)->url_path ? "/" : "" , (leg->leg_url)->url_path ? (leg->leg_url)->url_path : "", (leg->leg_url)->url_params ? ";" : "", (leg-> leg_url)->url_params ? (leg->leg_url)->url_params : "" , (leg->leg_url)->url_headers ? "?" : "", (leg->leg_url )->url_headers ? (leg->leg_url)->url_headers : "", ( leg->leg_url)->url_fragment ? "#" : "", (leg->leg_url )->url_fragment ? (leg->leg_url)->url_fragment : "") ) : (void)0); | |||||
1045 | leg_free(agent, leg); | |||||
1046 | } | |||||
1047 | } | |||||
1048 | ||||||
1049 | if (agent->sa_default_leg) | |||||
1050 | leg_free(agent, agent->sa_default_leg); | |||||
1051 | ||||||
1052 | for (i = iht->iht_size; i-- > 0; ) | |||||
1053 | while (iht->iht_table[i]) { | |||||
1054 | nta_incoming_t *irq = iht->iht_table[i]; | |||||
1055 | ||||||
1056 | if (!irq->irq_destroyed) | |||||
1057 | SU_DEBUG_3(("%s: destroying %s server transaction from <"(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 1060, "%s: destroying %s server transaction from <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">\n", __func__, irq->irq_rq->rq_method_name, (irq-> irq_from->a_url)->url_scheme ? (irq->irq_from->a_url )->url_scheme : "", (irq->irq_from->a_url)->url_type != url_any && (irq->irq_from->a_url)->url_scheme && (irq->irq_from->a_url)->url_scheme[0] ? ":" : "", (irq->irq_from->a_url)->url_root && ( (irq->irq_from->a_url)->url_host || (irq->irq_from ->a_url)->url_user) ? "//" : "", (irq->irq_from-> a_url)->url_user ? (irq->irq_from->a_url)->url_user : "", (irq->irq_from->a_url)->url_user && ( irq->irq_from->a_url)->url_password ? ":" : "", (irq ->irq_from->a_url)->url_user && (irq->irq_from ->a_url)->url_password ? (irq->irq_from->a_url)-> url_password : "", (irq->irq_from->a_url)->url_user && (irq->irq_from->a_url)->url_host ? "@" : "", (irq-> irq_from->a_url)->url_host ? (irq->irq_from->a_url )->url_host : "", (irq->irq_from->a_url)->url_host && (irq->irq_from->a_url)->url_port ? ":" : "", (irq->irq_from->a_url)->url_host && (irq ->irq_from->a_url)->url_port ? (irq->irq_from-> a_url)->url_port : "", (irq->irq_from->a_url)->url_root && (irq->irq_from->a_url)->url_path ? "/" : "", (irq->irq_from->a_url)->url_path ? (irq->irq_from ->a_url)->url_path : "", (irq->irq_from->a_url)-> url_params ? ";" : "", (irq->irq_from->a_url)->url_params ? (irq->irq_from->a_url)->url_params : "", (irq-> irq_from->a_url)->url_headers ? "?" : "", (irq->irq_from ->a_url)->url_headers ? (irq->irq_from->a_url)-> url_headers : "", (irq->irq_from->a_url)->url_fragment ? "#" : "", (irq->irq_from->a_url)->url_fragment ? ( irq->irq_from->a_url)->url_fragment : "")) : (void)0 ) | |||||
1058 | URL_PRINT_FORMAT ">\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 1060, "%s: destroying %s server transaction from <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">\n", __func__, irq->irq_rq->rq_method_name, (irq-> irq_from->a_url)->url_scheme ? (irq->irq_from->a_url )->url_scheme : "", (irq->irq_from->a_url)->url_type != url_any && (irq->irq_from->a_url)->url_scheme && (irq->irq_from->a_url)->url_scheme[0] ? ":" : "", (irq->irq_from->a_url)->url_root && ( (irq->irq_from->a_url)->url_host || (irq->irq_from ->a_url)->url_user) ? "//" : "", (irq->irq_from-> a_url)->url_user ? (irq->irq_from->a_url)->url_user : "", (irq->irq_from->a_url)->url_user && ( irq->irq_from->a_url)->url_password ? ":" : "", (irq ->irq_from->a_url)->url_user && (irq->irq_from ->a_url)->url_password ? (irq->irq_from->a_url)-> url_password : "", (irq->irq_from->a_url)->url_user && (irq->irq_from->a_url)->url_host ? "@" : "", (irq-> irq_from->a_url)->url_host ? (irq->irq_from->a_url )->url_host : "", (irq->irq_from->a_url)->url_host && (irq->irq_from->a_url)->url_port ? ":" : "", (irq->irq_from->a_url)->url_host && (irq ->irq_from->a_url)->url_port ? (irq->irq_from-> a_url)->url_port : "", (irq->irq_from->a_url)->url_root && (irq->irq_from->a_url)->url_path ? "/" : "", (irq->irq_from->a_url)->url_path ? (irq->irq_from ->a_url)->url_path : "", (irq->irq_from->a_url)-> url_params ? ";" : "", (irq->irq_from->a_url)->url_params ? (irq->irq_from->a_url)->url_params : "", (irq-> irq_from->a_url)->url_headers ? "?" : "", (irq->irq_from ->a_url)->url_headers ? (irq->irq_from->a_url)-> url_headers : "", (irq->irq_from->a_url)->url_fragment ? "#" : "", (irq->irq_from->a_url)->url_fragment ? ( irq->irq_from->a_url)->url_fragment : "")) : (void)0 ) | |||||
1059 | __func__, irq->irq_rq->rq_method_name,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 1060, "%s: destroying %s server transaction from <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">\n", __func__, irq->irq_rq->rq_method_name, (irq-> irq_from->a_url)->url_scheme ? (irq->irq_from->a_url )->url_scheme : "", (irq->irq_from->a_url)->url_type != url_any && (irq->irq_from->a_url)->url_scheme && (irq->irq_from->a_url)->url_scheme[0] ? ":" : "", (irq->irq_from->a_url)->url_root && ( (irq->irq_from->a_url)->url_host || (irq->irq_from ->a_url)->url_user) ? "//" : "", (irq->irq_from-> a_url)->url_user ? (irq->irq_from->a_url)->url_user : "", (irq->irq_from->a_url)->url_user && ( irq->irq_from->a_url)->url_password ? ":" : "", (irq ->irq_from->a_url)->url_user && (irq->irq_from ->a_url)->url_password ? (irq->irq_from->a_url)-> url_password : "", (irq->irq_from->a_url)->url_user && (irq->irq_from->a_url)->url_host ? "@" : "", (irq-> irq_from->a_url)->url_host ? (irq->irq_from->a_url )->url_host : "", (irq->irq_from->a_url)->url_host && (irq->irq_from->a_url)->url_port ? ":" : "", (irq->irq_from->a_url)->url_host && (irq ->irq_from->a_url)->url_port ? (irq->irq_from-> a_url)->url_port : "", (irq->irq_from->a_url)->url_root && (irq->irq_from->a_url)->url_path ? "/" : "", (irq->irq_from->a_url)->url_path ? (irq->irq_from ->a_url)->url_path : "", (irq->irq_from->a_url)-> url_params ? ";" : "", (irq->irq_from->a_url)->url_params ? (irq->irq_from->a_url)->url_params : "", (irq-> irq_from->a_url)->url_headers ? "?" : "", (irq->irq_from ->a_url)->url_headers ? (irq->irq_from->a_url)-> url_headers : "", (irq->irq_from->a_url)->url_fragment ? "#" : "", (irq->irq_from->a_url)->url_fragment ? ( irq->irq_from->a_url)->url_fragment : "")) : (void)0 ) | |||||
1060 | URL_PRINT_ARGS(irq->irq_from->a_url)))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 1060, "%s: destroying %s server transaction from <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">\n", __func__, irq->irq_rq->rq_method_name, (irq-> irq_from->a_url)->url_scheme ? (irq->irq_from->a_url )->url_scheme : "", (irq->irq_from->a_url)->url_type != url_any && (irq->irq_from->a_url)->url_scheme && (irq->irq_from->a_url)->url_scheme[0] ? ":" : "", (irq->irq_from->a_url)->url_root && ( (irq->irq_from->a_url)->url_host || (irq->irq_from ->a_url)->url_user) ? "//" : "", (irq->irq_from-> a_url)->url_user ? (irq->irq_from->a_url)->url_user : "", (irq->irq_from->a_url)->url_user && ( irq->irq_from->a_url)->url_password ? ":" : "", (irq ->irq_from->a_url)->url_user && (irq->irq_from ->a_url)->url_password ? (irq->irq_from->a_url)-> url_password : "", (irq->irq_from->a_url)->url_user && (irq->irq_from->a_url)->url_host ? "@" : "", (irq-> irq_from->a_url)->url_host ? (irq->irq_from->a_url )->url_host : "", (irq->irq_from->a_url)->url_host && (irq->irq_from->a_url)->url_port ? ":" : "", (irq->irq_from->a_url)->url_host && (irq ->irq_from->a_url)->url_port ? (irq->irq_from-> a_url)->url_port : "", (irq->irq_from->a_url)->url_root && (irq->irq_from->a_url)->url_path ? "/" : "", (irq->irq_from->a_url)->url_path ? (irq->irq_from ->a_url)->url_path : "", (irq->irq_from->a_url)-> url_params ? ";" : "", (irq->irq_from->a_url)->url_params ? (irq->irq_from->a_url)->url_params : "", (irq-> irq_from->a_url)->url_headers ? "?" : "", (irq->irq_from ->a_url)->url_headers ? (irq->irq_from->a_url)-> url_headers : "", (irq->irq_from->a_url)->url_fragment ? "#" : "", (irq->irq_from->a_url)->url_fragment ? ( irq->irq_from->a_url)->url_fragment : "")) : (void)0 ); | |||||
1061 | ||||||
1062 | incoming_free(irq); | |||||
1063 | } | |||||
1064 | ||||||
1065 | for (i = oht->oht_size; i-- > 0;) | |||||
1066 | while (oht->oht_table[i]) { | |||||
1067 | nta_outgoing_t *orq = oht->oht_table[i]; | |||||
1068 | ||||||
1069 | if (!orq->orq_destroyed) | |||||
1070 | SU_DEBUG_3(("%s: destroying %s%s client transaction to <"(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 1075, "%s: destroying %s%s client transaction to <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">\n", __func__, (orq->orq_forking || orq->orq_forks ) ? "forked " : "forking", orq->orq_method_name, (orq-> orq_to->a_url)->url_scheme ? (orq->orq_to->a_url) ->url_scheme : "", (orq->orq_to->a_url)->url_type != url_any && (orq->orq_to->a_url)->url_scheme && (orq->orq_to->a_url)->url_scheme[0] ? ":" : "", (orq->orq_to->a_url)->url_root && ((orq ->orq_to->a_url)->url_host || (orq->orq_to->a_url )->url_user) ? "//" : "", (orq->orq_to->a_url)->url_user ? (orq->orq_to->a_url)->url_user : "", (orq->orq_to ->a_url)->url_user && (orq->orq_to->a_url )->url_password ? ":" : "", (orq->orq_to->a_url)-> url_user && (orq->orq_to->a_url)->url_password ? (orq->orq_to->a_url)->url_password : "", (orq-> orq_to->a_url)->url_user && (orq->orq_to-> a_url)->url_host ? "@" : "", (orq->orq_to->a_url)-> url_host ? (orq->orq_to->a_url)->url_host : "", (orq ->orq_to->a_url)->url_host && (orq->orq_to ->a_url)->url_port ? ":" : "", (orq->orq_to->a_url )->url_host && (orq->orq_to->a_url)->url_port ? (orq->orq_to->a_url)->url_port : "", (orq->orq_to ->a_url)->url_root && (orq->orq_to->a_url )->url_path ? "/" : "", (orq->orq_to->a_url)->url_path ? (orq->orq_to->a_url)->url_path : "", (orq->orq_to ->a_url)->url_params ? ";" : "", (orq->orq_to->a_url )->url_params ? (orq->orq_to->a_url)->url_params : "", (orq->orq_to->a_url)->url_headers ? "?" : "", ( orq->orq_to->a_url)->url_headers ? (orq->orq_to-> a_url)->url_headers : "", (orq->orq_to->a_url)->url_fragment ? "#" : "", (orq->orq_to->a_url)->url_fragment ? (orq ->orq_to->a_url)->url_fragment : "")) : (void)0) | |||||
1071 | URL_PRINT_FORMAT ">\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 1075, "%s: destroying %s%s client transaction to <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">\n", __func__, (orq->orq_forking || orq->orq_forks ) ? "forked " : "forking", orq->orq_method_name, (orq-> orq_to->a_url)->url_scheme ? (orq->orq_to->a_url) ->url_scheme : "", (orq->orq_to->a_url)->url_type != url_any && (orq->orq_to->a_url)->url_scheme && (orq->orq_to->a_url)->url_scheme[0] ? ":" : "", (orq->orq_to->a_url)->url_root && ((orq ->orq_to->a_url)->url_host || (orq->orq_to->a_url )->url_user) ? "//" : "", (orq->orq_to->a_url)->url_user ? (orq->orq_to->a_url)->url_user : "", (orq->orq_to ->a_url)->url_user && (orq->orq_to->a_url )->url_password ? ":" : "", (orq->orq_to->a_url)-> url_user && (orq->orq_to->a_url)->url_password ? (orq->orq_to->a_url)->url_password : "", (orq-> orq_to->a_url)->url_user && (orq->orq_to-> a_url)->url_host ? "@" : "", (orq->orq_to->a_url)-> url_host ? (orq->orq_to->a_url)->url_host : "", (orq ->orq_to->a_url)->url_host && (orq->orq_to ->a_url)->url_port ? ":" : "", (orq->orq_to->a_url )->url_host && (orq->orq_to->a_url)->url_port ? (orq->orq_to->a_url)->url_port : "", (orq->orq_to ->a_url)->url_root && (orq->orq_to->a_url )->url_path ? "/" : "", (orq->orq_to->a_url)->url_path ? (orq->orq_to->a_url)->url_path : "", (orq->orq_to ->a_url)->url_params ? ";" : "", (orq->orq_to->a_url )->url_params ? (orq->orq_to->a_url)->url_params : "", (orq->orq_to->a_url)->url_headers ? "?" : "", ( orq->orq_to->a_url)->url_headers ? (orq->orq_to-> a_url)->url_headers : "", (orq->orq_to->a_url)->url_fragment ? "#" : "", (orq->orq_to->a_url)->url_fragment ? (orq ->orq_to->a_url)->url_fragment : "")) : (void)0) | |||||
1072 | __func__,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 1075, "%s: destroying %s%s client transaction to <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">\n", __func__, (orq->orq_forking || orq->orq_forks ) ? "forked " : "forking", orq->orq_method_name, (orq-> orq_to->a_url)->url_scheme ? (orq->orq_to->a_url) ->url_scheme : "", (orq->orq_to->a_url)->url_type != url_any && (orq->orq_to->a_url)->url_scheme && (orq->orq_to->a_url)->url_scheme[0] ? ":" : "", (orq->orq_to->a_url)->url_root && ((orq ->orq_to->a_url)->url_host || (orq->orq_to->a_url )->url_user) ? "//" : "", (orq->orq_to->a_url)->url_user ? (orq->orq_to->a_url)->url_user : "", (orq->orq_to ->a_url)->url_user && (orq->orq_to->a_url )->url_password ? ":" : "", (orq->orq_to->a_url)-> url_user && (orq->orq_to->a_url)->url_password ? (orq->orq_to->a_url)->url_password : "", (orq-> orq_to->a_url)->url_user && (orq->orq_to-> a_url)->url_host ? "@" : "", (orq->orq_to->a_url)-> url_host ? (orq->orq_to->a_url)->url_host : "", (orq ->orq_to->a_url)->url_host && (orq->orq_to ->a_url)->url_port ? ":" : "", (orq->orq_to->a_url )->url_host && (orq->orq_to->a_url)->url_port ? (orq->orq_to->a_url)->url_port : "", (orq->orq_to ->a_url)->url_root && (orq->orq_to->a_url )->url_path ? "/" : "", (orq->orq_to->a_url)->url_path ? (orq->orq_to->a_url)->url_path : "", (orq->orq_to ->a_url)->url_params ? ";" : "", (orq->orq_to->a_url )->url_params ? (orq->orq_to->a_url)->url_params : "", (orq->orq_to->a_url)->url_headers ? "?" : "", ( orq->orq_to->a_url)->url_headers ? (orq->orq_to-> a_url)->url_headers : "", (orq->orq_to->a_url)->url_fragment ? "#" : "", (orq->orq_to->a_url)->url_fragment ? (orq ->orq_to->a_url)->url_fragment : "")) : (void)0) | |||||
1073 | (orq->orq_forking || orq->orq_forks) ? "forked " : "forking",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 1075, "%s: destroying %s%s client transaction to <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">\n", __func__, (orq->orq_forking || orq->orq_forks ) ? "forked " : "forking", orq->orq_method_name, (orq-> orq_to->a_url)->url_scheme ? (orq->orq_to->a_url) ->url_scheme : "", (orq->orq_to->a_url)->url_type != url_any && (orq->orq_to->a_url)->url_scheme && (orq->orq_to->a_url)->url_scheme[0] ? ":" : "", (orq->orq_to->a_url)->url_root && ((orq ->orq_to->a_url)->url_host || (orq->orq_to->a_url )->url_user) ? "//" : "", (orq->orq_to->a_url)->url_user ? (orq->orq_to->a_url)->url_user : "", (orq->orq_to ->a_url)->url_user && (orq->orq_to->a_url )->url_password ? ":" : "", (orq->orq_to->a_url)-> url_user && (orq->orq_to->a_url)->url_password ? (orq->orq_to->a_url)->url_password : "", (orq-> orq_to->a_url)->url_user && (orq->orq_to-> a_url)->url_host ? "@" : "", (orq->orq_to->a_url)-> url_host ? (orq->orq_to->a_url)->url_host : "", (orq ->orq_to->a_url)->url_host && (orq->orq_to ->a_url)->url_port ? ":" : "", (orq->orq_to->a_url )->url_host && (orq->orq_to->a_url)->url_port ? (orq->orq_to->a_url)->url_port : "", (orq->orq_to ->a_url)->url_root && (orq->orq_to->a_url )->url_path ? "/" : "", (orq->orq_to->a_url)->url_path ? (orq->orq_to->a_url)->url_path : "", (orq->orq_to ->a_url)->url_params ? ";" : "", (orq->orq_to->a_url )->url_params ? (orq->orq_to->a_url)->url_params : "", (orq->orq_to->a_url)->url_headers ? "?" : "", ( orq->orq_to->a_url)->url_headers ? (orq->orq_to-> a_url)->url_headers : "", (orq->orq_to->a_url)->url_fragment ? "#" : "", (orq->orq_to->a_url)->url_fragment ? (orq ->orq_to->a_url)->url_fragment : "")) : (void)0) | |||||
1074 | orq->orq_method_name,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 1075, "%s: destroying %s%s client transaction to <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">\n", __func__, (orq->orq_forking || orq->orq_forks ) ? "forked " : "forking", orq->orq_method_name, (orq-> orq_to->a_url)->url_scheme ? (orq->orq_to->a_url) ->url_scheme : "", (orq->orq_to->a_url)->url_type != url_any && (orq->orq_to->a_url)->url_scheme && (orq->orq_to->a_url)->url_scheme[0] ? ":" : "", (orq->orq_to->a_url)->url_root && ((orq ->orq_to->a_url)->url_host || (orq->orq_to->a_url )->url_user) ? "//" : "", (orq->orq_to->a_url)->url_user ? (orq->orq_to->a_url)->url_user : "", (orq->orq_to ->a_url)->url_user && (orq->orq_to->a_url )->url_password ? ":" : "", (orq->orq_to->a_url)-> url_user && (orq->orq_to->a_url)->url_password ? (orq->orq_to->a_url)->url_password : "", (orq-> orq_to->a_url)->url_user && (orq->orq_to-> a_url)->url_host ? "@" : "", (orq->orq_to->a_url)-> url_host ? (orq->orq_to->a_url)->url_host : "", (orq ->orq_to->a_url)->url_host && (orq->orq_to ->a_url)->url_port ? ":" : "", (orq->orq_to->a_url )->url_host && (orq->orq_to->a_url)->url_port ? (orq->orq_to->a_url)->url_port : "", (orq->orq_to ->a_url)->url_root && (orq->orq_to->a_url )->url_path ? "/" : "", (orq->orq_to->a_url)->url_path ? (orq->orq_to->a_url)->url_path : "", (orq->orq_to ->a_url)->url_params ? ";" : "", (orq->orq_to->a_url )->url_params ? (orq->orq_to->a_url)->url_params : "", (orq->orq_to->a_url)->url_headers ? "?" : "", ( orq->orq_to->a_url)->url_headers ? (orq->orq_to-> a_url)->url_headers : "", (orq->orq_to->a_url)->url_fragment ? "#" : "", (orq->orq_to->a_url)->url_fragment ? (orq ->orq_to->a_url)->url_fragment : "")) : (void)0) | |||||
1075 | URL_PRINT_ARGS(orq->orq_to->a_url)))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 1075, "%s: destroying %s%s client transaction to <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">\n", __func__, (orq->orq_forking || orq->orq_forks ) ? "forked " : "forking", orq->orq_method_name, (orq-> orq_to->a_url)->url_scheme ? (orq->orq_to->a_url) ->url_scheme : "", (orq->orq_to->a_url)->url_type != url_any && (orq->orq_to->a_url)->url_scheme && (orq->orq_to->a_url)->url_scheme[0] ? ":" : "", (orq->orq_to->a_url)->url_root && ((orq ->orq_to->a_url)->url_host || (orq->orq_to->a_url )->url_user) ? "//" : "", (orq->orq_to->a_url)->url_user ? (orq->orq_to->a_url)->url_user : "", (orq->orq_to ->a_url)->url_user && (orq->orq_to->a_url )->url_password ? ":" : "", (orq->orq_to->a_url)-> url_user && (orq->orq_to->a_url)->url_password ? (orq->orq_to->a_url)->url_password : "", (orq-> orq_to->a_url)->url_user && (orq->orq_to-> a_url)->url_host ? "@" : "", (orq->orq_to->a_url)-> url_host ? (orq->orq_to->a_url)->url_host : "", (orq ->orq_to->a_url)->url_host && (orq->orq_to ->a_url)->url_port ? ":" : "", (orq->orq_to->a_url )->url_host && (orq->orq_to->a_url)->url_port ? (orq->orq_to->a_url)->url_port : "", (orq->orq_to ->a_url)->url_root && (orq->orq_to->a_url )->url_path ? "/" : "", (orq->orq_to->a_url)->url_path ? (orq->orq_to->a_url)->url_path : "", (orq->orq_to ->a_url)->url_params ? ";" : "", (orq->orq_to->a_url )->url_params ? (orq->orq_to->a_url)->url_params : "", (orq->orq_to->a_url)->url_headers ? "?" : "", ( orq->orq_to->a_url)->url_headers ? (orq->orq_to-> a_url)->url_headers : "", (orq->orq_to->a_url)->url_fragment ? "#" : "", (orq->orq_to->a_url)->url_fragment ? (orq ->orq_to->a_url)->url_fragment : "")) : (void)0); | |||||
1076 | ||||||
1077 | orq->orq_forks = NULL((void*)0), orq->orq_forking = NULL((void*)0); | |||||
1078 | outgoing_free(orq); | |||||
1079 | } | |||||
1080 | ||||||
1081 | su_timer_destroy(agent->sa_timer), agent->sa_timer = NULL((void*)0); | |||||
1082 | ||||||
1083 | # if HAVE_SOFIA_SRESOLV1 | |||||
1084 | sres_resolver_destroy(agent->sa_resolver), agent->sa_resolver = NULL((void*)0); | |||||
1085 | # endif | |||||
1086 | ||||||
1087 | tport_destroy(agent->sa_tports), agent->sa_tports = NULL((void*)0); | |||||
1088 | ||||||
1089 | agent_kill_terminator(agent); | |||||
1090 | ||||||
1091 | su_home_unref(agent->sa_home); | |||||
1092 | } | |||||
1093 | } | |||||
1094 | ||||||
1095 | /** Return agent context. */ | |||||
1096 | nta_agent_magic_t *nta_agent_magic(nta_agent_t const *agent) | |||||
1097 | { | |||||
1098 | return agent ? agent->sa_magic : NULL((void*)0); | |||||
1099 | } | |||||
1100 | ||||||
1101 | /** Return @Contact header. | |||||
1102 | * | |||||
1103 | * Get a @Contact header, which can be used to reach @a agent. | |||||
1104 | * | |||||
1105 | * @param agent NTA agent object | |||||
1106 | * | |||||
1107 | * User agents can insert the @Contact header in the outgoing REGISTER, | |||||
1108 | * INVITE, and ACK requests and replies to incoming INVITE and OPTIONS | |||||
1109 | * transactions. | |||||
1110 | * | |||||
1111 | * Proxies can use the @Contact header to create appropriate @RecordRoute | |||||
1112 | * headers: | |||||
1113 | * @code | |||||
1114 | * r_r = sip_record_route_create(msg_home(msg), | |||||
1115 | * sip->sip_request->rq_url, | |||||
1116 | * contact->m_url); | |||||
1117 | * @endcode | |||||
1118 | * | |||||
1119 | * @return A sip_contact_t object corresponding to the @a agent. | |||||
1120 | */ | |||||
1121 | sip_contact_t *nta_agent_contact(nta_agent_t const *agent) | |||||
1122 | { | |||||
1123 | return agent ? agent->sa_contact : NULL((void*)0); | |||||
1124 | } | |||||
1125 | ||||||
1126 | /** Return a list of @Via headers. | |||||
1127 | * | |||||
1128 | * Get @Via headers for all activated transport. | |||||
1129 | * | |||||
1130 | * @param agent NTA agent object | |||||
1131 | * | |||||
1132 | * @return A list of #sip_via_t objects used by the @a agent. | |||||
1133 | */ | |||||
1134 | sip_via_t *nta_agent_via(nta_agent_t const *agent) | |||||
1135 | { | |||||
1136 | return agent ? agent->sa_vias : NULL((void*)0); | |||||
1137 | } | |||||
1138 | ||||||
1139 | /** Return a list of public (UPnP, STUN) @Via headers. | |||||
1140 | * | |||||
1141 | * Get public @Via headers for all activated transports. | |||||
1142 | * | |||||
1143 | * @param agent NTA agent object | |||||
1144 | * | |||||
1145 | * @return A list of #sip_via_t objects used by the @a agent. | |||||
1146 | */ | |||||
1147 | sip_via_t *nta_agent_public_via(nta_agent_t const *agent) | |||||
1148 | { | |||||
1149 | return agent ? agent->sa_public_vias : NULL((void*)0); | |||||
1150 | } | |||||
1151 | ||||||
1152 | /** Match a @Via header @a v with @Via headers in @a agent. | |||||
1153 | * | |||||
1154 | */ | |||||
1155 | static | |||||
1156 | sip_via_t *agent_has_via(nta_agent_t const *agent, sip_via_t const *via) | |||||
1157 | { | |||||
1158 | sip_via_t const *v; | |||||
1159 | ||||||
1160 | for (v = agent->sa_public_vias; v; v = v->v_next) { | |||||
1161 | if (!su_casematch(via->v_host, v->v_host)) | |||||
1162 | continue; | |||||
1163 | if (!su_strmatch(via->v_port, v->v_port)) | |||||
1164 | continue; | |||||
1165 | if (!su_casematch(via->v_protocol, v->v_protocol)) | |||||
1166 | continue; | |||||
1167 | return (sip_via_t *)v; | |||||
1168 | } | |||||
1169 | ||||||
1170 | for (v = agent->sa_vias; v; v = v->v_next) { | |||||
1171 | if (!su_casematch(via->v_host, v->v_host)) | |||||
1172 | continue; | |||||
1173 | if (!su_strmatch(via->v_port, v->v_port)) | |||||
1174 | continue; | |||||
1175 | if (!su_casematch(via->v_protocol, v->v_protocol)) | |||||
1176 | continue; | |||||
1177 | return (sip_via_t *)v; | |||||
1178 | } | |||||
1179 | ||||||
1180 | return NULL((void*)0); | |||||
1181 | } | |||||
1182 | ||||||
1183 | /** Return @UserAgent header. | |||||
1184 | * | |||||
1185 | * Get @UserAgent information with NTA version. | |||||
1186 | * | |||||
1187 | * @param agent NTA agent object (may be NULL) | |||||
1188 | * | |||||
1189 | * @return A string containing the @a agent version. | |||||
1190 | */ | |||||
1191 | char const *nta_agent_version(nta_agent_t const *agent) | |||||
1192 | { | |||||
1193 | return "nta" "/" VERSION"1.13.5"; | |||||
1194 | } | |||||
1195 | ||||||
1196 | /** Initialize default tag */ | |||||
1197 | static int agent_tag_init(nta_agent_t *self) | |||||
1198 | { | |||||
1199 | sip_contact_t *m = self->sa_contact; | |||||
1200 | uint32_t hash = su_random(); | |||||
1201 | ||||||
1202 | if (m) { | |||||
1203 | if (m->m_url->url_user) | |||||
1204 | hash = 914715421U * hash + msg_hash_string(m->m_url->url_user); | |||||
1205 | if (m->m_url->url_host) | |||||
1206 | hash = 914715421U * hash + msg_hash_string(m->m_url->url_host); | |||||
1207 | if (m->m_url->url_port) | |||||
1208 | hash = 914715421U * hash + msg_hash_string(m->m_url->url_port); | |||||
1209 | if (m->m_url->url_params) | |||||
1210 | hash = 914715421U * hash + msg_hash_string(m->m_url->url_params); | |||||
1211 | } | |||||
1212 | ||||||
1213 | if (hash == 0) | |||||
1214 | hash = 914715421U; | |||||
1215 | ||||||
1216 | self->sa_branch = NTA_BRANCH_PRIME(uint64_t)(0xB9591D1C361C6521ULL) * (uint64_t)su_nanotime(NULL((void*)0)); | |||||
1217 | self->sa_branch *= hash; | |||||
1218 | ||||||
1219 | self->sa_tags = NTA_TAG_PRIME(uint64_t)(0xB9591D1C361C6521ULL) * self->sa_branch; | |||||
1220 | ||||||
1221 | return 0; | |||||
1222 | } | |||||
1223 | ||||||
1224 | /** Initialize agent timer. */ | |||||
1225 | static | |||||
1226 | int agent_timer_init(nta_agent_t *agent) | |||||
1227 | { | |||||
1228 | agent->sa_timer = su_timer_create(su_root_task(agent->sa_root), | |||||
1229 | NTA_SIP_T1 / 8); | |||||
1230 | #if 0 | |||||
1231 | return su_timer_set(agent->sa_timer, | |||||
1232 | agent_timer, | |||||
1233 | agent); | |||||
1234 | #endif | |||||
1235 | return -(agent->sa_timer == NULL((void*)0)); | |||||
1236 | } | |||||
1237 | ||||||
1238 | /** | |||||
1239 | * Agent timer routine. | |||||
1240 | */ | |||||
1241 | static | |||||
1242 | void agent_timer(su_root_magic_t *rm, su_timer_t *timer, nta_agent_t *agent) | |||||
1243 | { | |||||
1244 | su_time_t stamp = su_now(); | |||||
1245 | uint32_t now = su_time_ms(stamp), next, latest; | |||||
1246 | ||||||
1247 | now += now == 0; | |||||
1248 | ||||||
1249 | agent->sa_next = 0; | |||||
1250 | ||||||
1251 | agent->sa_in_timer = 1; | |||||
1252 | ||||||
1253 | ||||||
1254 | _nta_outgoing_timer(agent); | |||||
1255 | _nta_incoming_timer(agent); | |||||
1256 | ||||||
1257 | agent->sa_in_timer = 0; | |||||
1258 | ||||||
1259 | /* Calculate next timeout */ | |||||
1260 | next = latest = now + NTA_TIME_MAX + 1; | |||||
1261 | ||||||
1262 | #define NEXT_TIMEOUT(next, p, f, now) \ | |||||
1263 | (void)(p && (int32_t)(p->f - (next)) < 0 && \ | |||||
1264 | ((next) = ((int32_t)(p->f - (now)) > 0 ? p->f : (now)))) | |||||
1265 | ||||||
1266 | NEXT_TIMEOUT(next, agent->sa_out.re_list, orq_retry, now); | |||||
1267 | NEXT_TIMEOUT(next, agent->sa_out.inv_completed->q_head, orq_timeout, now); | |||||
1268 | NEXT_TIMEOUT(next, agent->sa_out.completed->q_head, orq_timeout, now); | |||||
1269 | NEXT_TIMEOUT(next, agent->sa_out.inv_calling->q_head, orq_timeout, now); | |||||
1270 | if (agent->sa_out.inv_proceeding->q_timeout) | |||||
1271 | NEXT_TIMEOUT(next, agent->sa_out.inv_proceeding->q_head, orq_timeout, now); | |||||
1272 | NEXT_TIMEOUT(next, agent->sa_out.trying->q_head, orq_timeout, now); | |||||
1273 | ||||||
1274 | NEXT_TIMEOUT(next, agent->sa_in.preliminary->q_head, irq_timeout, now); | |||||
1275 | NEXT_TIMEOUT(next, agent->sa_in.inv_completed->q_head, irq_timeout, now); | |||||
1276 | NEXT_TIMEOUT(next, agent->sa_in.inv_confirmed->q_head, irq_timeout, now); | |||||
1277 | NEXT_TIMEOUT(next, agent->sa_in.completed->q_head, irq_timeout, now); | |||||
1278 | NEXT_TIMEOUT(next, agent->sa_in.re_list, irq_retry, now); | |||||
1279 | ||||||
1280 | if (agent->sa_next) | |||||
1281 | NEXT_TIMEOUT(next, agent, sa_next, now); | |||||
1282 | ||||||
1283 | #undef NEXT_TIMEOUT | |||||
1284 | ||||||
1285 | if (next == latest) { | |||||
1286 | /* Do not set timer? */ | |||||
1287 | /* check it there are still things queued, if there are, that means everything scheduled is > 15 days in the future */ | |||||
1288 | /* in this case, we had a large time shift, we should schedule for 15 days in the future (which is probably still before now) */ | |||||
1289 | /* and this should sort itself out on the next run through */ | |||||
1290 | if ( !agent->sa_out.completed->q_head && !agent->sa_out.trying->q_head && !agent->sa_out.inv_calling->q_head && | |||||
1291 | !agent->sa_out.re_list && !agent->sa_in.inv_confirmed->q_head && !agent->sa_in.preliminary->q_head && | |||||
1292 | !agent->sa_in.completed->q_head && !agent->sa_in.inv_completed->q_head && !agent->sa_in.re_list ) { | |||||
1293 | SU_DEBUG_9(("nta: timer not set\n" VA_NONE))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 1293, "nta: timer not set\n" "%s", "")) : (void)0); | |||||
1294 | return; | |||||
1295 | } | |||||
1296 | } | |||||
1297 | ||||||
1298 | if (next == now) if (++next == 0) ++next; | |||||
1299 | ||||||
1300 | SU_DEBUG_9(("nta: timer %s to %ld ms\n", "set next", (long)(next - now)))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 1300, "nta: timer %s to %ld ms\n", "set next", (long)(next - now))) : (void)0); | |||||
1301 | ||||||
1302 | agent->sa_next = next; | |||||
1303 | ||||||
1304 | su_timer_set_at(timer, agent_timer, agent, su_time_add(stamp, next - now)); | |||||
1305 | } | |||||
1306 | ||||||
1307 | /** Add uin32_t milliseconds to the time. */ | |||||
1308 | static su_time_t add_milliseconds(su_time_t t0, uint32_t ms) | |||||
1309 | { | |||||
1310 | unsigned long sec = ms / 1000, usec = (ms % 1000) * 1000; | |||||
1311 | ||||||
1312 | t0.tv_usec += usec; | |||||
1313 | t0.tv_sec += sec; | |||||
1314 | ||||||
1315 | if (t0.tv_usec >= 1000000) { | |||||
1316 | t0.tv_sec += 1; | |||||
1317 | t0.tv_usec -= 1000000; | |||||
1318 | } | |||||
1319 | ||||||
1320 | return t0; | |||||
1321 | } | |||||
1322 | ||||||
1323 | /** Calculate nonzero value for timeout. | |||||
1324 | * | |||||
1325 | * Sets or adjusts agent timer when needed. | |||||
1326 | * | |||||
1327 | * @retval 0 if offset is 0 | |||||
1328 | * @retval timeout (millisecond counter) otherwise | |||||
1329 | */ | |||||
1330 | static | |||||
1331 | uint32_t set_timeout(nta_agent_t *agent, uint32_t offset) | |||||
1332 | { | |||||
1333 | su_time_t now; | |||||
1334 | uint32_t next, ms; | |||||
1335 | ||||||
1336 | if (offset == 0) | |||||
1337 | return 0; | |||||
1338 | ||||||
1339 | now = su_now(); | |||||
1340 | ms = su_time_ms(now); | |||||
1341 | ||||||
1342 | next = ms + offset; | |||||
1343 | ||||||
1344 | if (next == 0) next = 1; | |||||
1345 | ||||||
1346 | if (agent->sa_in_timer) /* Currently executing timer */ | |||||
1347 | return next; | |||||
1348 | ||||||
1349 | if (agent->sa_next == 0 || (int32_t)(agent->sa_next - next - 5L) > 0) { | |||||
1350 | /* Set timer */ | |||||
1351 | if (agent->sa_next) | |||||
1352 | SU_DEBUG_9(("nta: timer %s to %ld ms\n", "shortened", (long)offset))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 1352, "nta: timer %s to %ld ms\n", "shortened", (long)offset )) : (void)0); | |||||
1353 | else | |||||
1354 | SU_DEBUG_9(("nta: timer %s to %ld ms\n", "set", (long)offset))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 1354, "nta: timer %s to %ld ms\n", "set", (long)offset)) : ( void)0); | |||||
1355 | ||||||
1356 | su_timer_set_at(agent->sa_timer, agent_timer, agent, | |||||
1357 | add_milliseconds(now, offset)); | |||||
1358 | agent->sa_next = next; | |||||
1359 | } | |||||
1360 | ||||||
1361 | return next; | |||||
1362 | } | |||||
1363 | ||||||
1364 | ||||||
1365 | /** Return current timeval. */ | |||||
1366 | static | |||||
1367 | su_time_t agent_now(nta_agent_t const *agent) | |||||
1368 | { | |||||
1369 | return su_now(); | |||||
1370 | } | |||||
1371 | ||||||
1372 | ||||||
1373 | /** Launch transaction terminator task */ | |||||
1374 | static | |||||
1375 | int agent_launch_terminator(nta_agent_t *agent) | |||||
1376 | { | |||||
1377 | #ifdef TPTAG_THRPSIZE | |||||
1378 | if (agent->sa_tport_threadpool) { | |||||
1379 | su_home_threadsafe(agent->sa_home); | |||||
1380 | return su_clone_start(agent->sa_root, | |||||
1381 | agent->sa_terminator, | |||||
1382 | NULL((void*)0), | |||||
1383 | NULL((void*)0), | |||||
1384 | NULL((void*)0)); | |||||
1385 | } | |||||
1386 | #endif | |||||
1387 | return -1; | |||||
1388 | } | |||||
1389 | ||||||
1390 | /** Kill transaction terminator task */ | |||||
1391 | static | |||||
1392 | void agent_kill_terminator(nta_agent_t *agent) | |||||
1393 | { | |||||
1394 | su_clone_wait(agent->sa_root, agent->sa_terminator); | |||||
1395 | } | |||||
1396 | ||||||
1397 | ||||||
1398 | /**Set NTA Parameters. | |||||
1399 | * | |||||
1400 | * The nta_agent_set_params() function sets the stack parameters. The | |||||
1401 | * parameters determine the way NTA handles the retransmissions, how long | |||||
1402 | * NTA keeps transactions alive, does NTA apply proxy or user-agent logic to | |||||
1403 | * INVITE transactions, or how the @Via headers are generated. | |||||
1404 | * | |||||
1405 | * @note | |||||
1406 | * Setting the parameters NTATAG_MAXSIZE(), NTATAG_UDP_MTU(), NTATAG_MAX_PROCEEDING(), | |||||
1407 | * NTATAG_SIP_T1X64(), NTATAG_SIP_T1(), NTATAG_SIP_T2(), NTATAG_SIP_T4() to | |||||
1408 | * 0 selects the default value. | |||||
1409 | * | |||||
1410 | * @TAGS | |||||
1411 | * NTATAG_ALIASES(), | |||||
1412 | * NTATAG_BAD_REQ_MASK(), NTATAG_BAD_RESP_MASK(), NTATAG_BLACKLIST(), | |||||
1413 | * NTATAG_CANCEL_2543(), NTATAG_CANCEL_487(), NTATAG_CLIENT_RPORT(), | |||||
1414 | * NTATAG_DEBUG_DROP_PROB(), NTATAG_DEFAULT_PROXY(), | |||||
1415 | * NTATAG_EXTRA_100(), NTATAG_GRAYLIST(), | |||||
1416 | * NTATAG_MAXSIZE(), NTATAG_MAX_FORWARDS(), NTATAG_MERGE_482(), NTATAG_MCLASS() | |||||
1417 | * NTATAG_PASS_100(), NTATAG_PASS_408(), NTATAG_PRELOAD(), NTATAG_PROGRESS(), | |||||
1418 | * NTATAG_REL100(), | |||||
1419 | * NTATAG_SERVER_RPORT(), | |||||
1420 | * NTATAG_SIPFLAGS(), | |||||
1421 | * NTATAG_SIP_T1X64(), NTATAG_SIP_T1(), NTATAG_SIP_T2(), NTATAG_SIP_T4(), | |||||
1422 | * NTATAG_STATELESS(), | |||||
1423 | * NTATAG_TAG_3261(), NTATAG_TCP_RPORT(), NTATAG_TIMEOUT_408(), | |||||
1424 | * NTATAG_TLS_RPORT(), NTATAG_TLS_ORQ_CONNECT_TIMEOUT(), | |||||
1425 | * NTATAG_TIMER_C(), NTATAG_MAX_PROCEEDING(), | |||||
1426 | * NTATAG_UA(), NTATAG_UDP_MTU(), NTATAG_USER_VIA(), | |||||
1427 | * NTATAG_USE_NAPTR(), NTATAG_USE_SRV() and NTATAG_USE_TIMESTAMP(). | |||||
1428 | * | |||||
1429 | * @note The value from following tags are stored, but they currently do nothing: | |||||
1430 | * NTATAG_SIGCOMP_ALGORITHM(), NTATAG_SIGCOMP_OPTIONS(), NTATAG_SMIME() | |||||
1431 | */ | |||||
1432 | int nta_agent_set_params(nta_agent_t *agent, | |||||
1433 | tag_type_t tag, tag_value_t value, ...) | |||||
1434 | { | |||||
1435 | int retval; | |||||
1436 | ||||||
1437 | if (agent) { | |||||
1438 | ta_list ta; | |||||
1439 | ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value = (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag ) == tag_next && (ta_start__value) != 0) { ta_start__tag = ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag == tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag == tag_next) { ta_start__value = ((tagi_t *)ta_start__value) ->t_value; } else { ta_start__tag = tag_next; break; } } ( ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value ; if (ta_start__tag != ((void*)0) && ta_start__tag != tag_null && ta_start__tag != tag_next) { va_list ta_start__ap ; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag = tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap ); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value = 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0); | |||||
1440 | retval = agent_set_params(agent, ta_args(ta)(ta).tl); | |||||
1441 | ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value ))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta) .ap)); | |||||
1442 | } else { | |||||
1443 | su_seterrno(EINVAL22); | |||||
1444 | retval = -1; | |||||
1445 | } | |||||
1446 | ||||||
1447 | return retval; | |||||
1448 | } | |||||
1449 | ||||||
1450 | /** Internal function for setting tags */ | |||||
1451 | static | |||||
1452 | int agent_set_params(nta_agent_t *agent, tagi_t *tags) | |||||
1453 | { | |||||
1454 | int n, nC, m; | |||||
1455 | unsigned bad_req_mask = agent->sa_bad_req_mask; | |||||
1456 | unsigned bad_resp_mask = agent->sa_bad_resp_mask; | |||||
1457 | usize_t maxsize = agent->sa_maxsize; | |||||
1458 | usize_t max_proceeding = agent->sa_max_proceeding; | |||||
1459 | unsigned max_forwards = agent->sa_max_forwards->mf_count; | |||||
1460 | unsigned udp_mtu = agent->sa_udp_mtu; | |||||
1461 | unsigned sip_t1 = agent->sa_t1; | |||||
1462 | unsigned sip_t2 = agent->sa_t2; | |||||
1463 | unsigned sip_t4 = agent->sa_t4; | |||||
1464 | unsigned sip_t1x64 = agent->sa_t1x64; | |||||
1465 | unsigned tls_orq_connect_timeout = agent->sa_tls_orq_connect_timeout; | |||||
1466 | unsigned timer_c = agent->sa_timer_c; | |||||
1467 | unsigned timer_d = 32000; | |||||
1468 | unsigned graylist = agent->sa_graylist; | |||||
1469 | unsigned blacklist = agent->sa_blacklist; | |||||
1470 | int ua = agent->sa_is_a_uas; | |||||
1471 | unsigned progress = agent->sa_progress; | |||||
1472 | int stateless = agent->sa_is_stateless; | |||||
1473 | unsigned drop_prob = agent->sa_drop_prob; | |||||
1474 | int user_via = agent->sa_user_via; | |||||
1475 | int extra_100 = agent->sa_extra_100; | |||||
1476 | int pass_100 = agent->sa_pass_100; | |||||
1477 | int timeout_408 = agent->sa_timeout_408; | |||||
1478 | int pass_408 = agent->sa_pass_408; | |||||
1479 | int merge_482 = agent->sa_merge_482; | |||||
1480 | int cancel_2543 = agent->sa_cancel_2543; | |||||
1481 | int cancel_487 = agent->sa_cancel_487; | |||||
1482 | int invite_100rel = agent->sa_invite_100rel; | |||||
1483 | int use_timestamp = agent->sa_timestamp; | |||||
1484 | int use_naptr = agent->sa_use_naptr; | |||||
1485 | int use_srv = agent->sa_use_srv; | |||||
1486 | int srv_503 = agent->sa_srv_503; | |||||
1487 | void *smime = agent->sa_smime; | |||||
1488 | uint32_t flags = agent->sa_flags; | |||||
1489 | int rport = agent->sa_rport; | |||||
1490 | int server_rport = agent->sa_server_rport; | |||||
1491 | int tcp_rport = agent->sa_tcp_rport; | |||||
1492 | int tls_rport = agent->sa_tls_rport; | |||||
1493 | unsigned preload = agent->sa_preload; | |||||
1494 | unsigned threadpool = agent->sa_tport_threadpool; | |||||
1495 | char const *sigcomp = agent->sa_sigcomp_options; | |||||
1496 | char const *algorithm = NONE((void *)-1); | |||||
1497 | msg_mclass_t const *mclass = NONE((void *)-1); | |||||
1498 | sip_contact_t const *aliases = NONE((void *)-1); | |||||
1499 | url_string_t const *proxy = NONE((void *)-1); | |||||
1500 | tport_t *tport; | |||||
1501 | ||||||
1502 | su_home_t *home = agent->sa_home; | |||||
1503 | ||||||
1504 | n = tl_gets(tags, | |||||
1505 | NTATAG_ALIASES_REF(aliases)ntatag_aliases_ref, siptag_contact_vr(&(aliases)), | |||||
1506 | NTATAG_BAD_REQ_MASK_REF(bad_req_mask)ntatag_bad_req_mask_ref, tag_uint_vr(&(bad_req_mask)), | |||||
1507 | NTATAG_BAD_RESP_MASK_REF(bad_resp_mask)ntatag_bad_resp_mask_ref, tag_uint_vr(&(bad_resp_mask)), | |||||
1508 | NTATAG_BLACKLIST_REF(blacklist)ntatag_blacklist_ref, tag_uint_vr(&(blacklist)), | |||||
1509 | NTATAG_CANCEL_2543_REF(cancel_2543)ntatag_cancel_2543_ref, tag_bool_vr(&(cancel_2543)), | |||||
1510 | NTATAG_CANCEL_487_REF(cancel_487)ntatag_cancel_487_ref, tag_bool_vr(&(cancel_487)), | |||||
1511 | NTATAG_DEBUG_DROP_PROB_REF(drop_prob)ntatag_debug_drop_prob_ref, tag_uint_vr(&(drop_prob)), | |||||
1512 | NTATAG_DEFAULT_PROXY_REF(proxy)ntatag_default_proxy_ref, urltag_url_vr(&(proxy)), | |||||
1513 | NTATAG_EXTRA_100_REF(extra_100)ntatag_extra_100_ref, tag_bool_vr(&(extra_100)), | |||||
1514 | NTATAG_GRAYLIST_REF(graylist)ntatag_graylist_ref, tag_uint_vr(&(graylist)), | |||||
1515 | NTATAG_MAXSIZE_REF(maxsize)ntatag_maxsize_ref, tag_usize_vr(&(maxsize)), | |||||
1516 | NTATAG_MAX_PROCEEDING_REF(max_proceeding)ntatag_max_proceeding_ref, tag_usize_vr(&(max_proceeding) ), | |||||
1517 | NTATAG_MAX_FORWARDS_REF(max_forwards)ntatag_max_forwards_ref, tag_uint_vr(&(max_forwards)), | |||||
1518 | NTATAG_MCLASS_REF(mclass)ntatag_mclass_ref, tag_cptr_vr(&(mclass), (mclass)), | |||||
1519 | NTATAG_MERGE_482_REF(merge_482)ntatag_merge_482_ref, tag_bool_vr(&(merge_482)), | |||||
1520 | NTATAG_PASS_100_REF(pass_100)ntatag_pass_100_ref, tag_bool_vr(&(pass_100)), | |||||
1521 | NTATAG_PASS_408_REF(pass_408)ntatag_pass_408_ref, tag_bool_vr(&(pass_408)), | |||||
1522 | NTATAG_PRELOAD_REF(preload)ntatag_preload_ref, tag_uint_vr(&(preload)), | |||||
1523 | NTATAG_PROGRESS_REF(progress)ntatag_progress_ref, tag_uint_vr(&(progress)), | |||||
1524 | NTATAG_REL100_REF(invite_100rel)ntatag_rel100_ref, tag_bool_vr(&(invite_100rel)), | |||||
1525 | NTATAG_RPORT_REF(rport)ntatag_client_rport_ref, tag_bool_vr(&(rport)), | |||||
1526 | NTATAG_SERVER_RPORT_REF(server_rport)ntatag_server_rport_ref, tag_int_vr(&(server_rport)), | |||||
1527 | NTATAG_SIGCOMP_ALGORITHM_REF(algorithm)ntatag_sigcomp_algorithm_ref, tag_str_vr(&(algorithm)), | |||||
1528 | NTATAG_SIGCOMP_OPTIONS_REF(sigcomp)ntatag_sigcomp_options_ref, tag_str_vr(&(sigcomp)), | |||||
1529 | NTATAG_SIPFLAGS_REF(flags)ntatag_sipflags_ref, tag_uint_vr(&(flags)), | |||||
1530 | NTATAG_SIP_T1X64_REF(sip_t1x64)ntatag_sip_t1x64_ref, tag_uint_vr(&(sip_t1x64)), | |||||
1531 | NTATAG_SIP_T1_REF(sip_t1)ntatag_sip_t1_ref, tag_uint_vr(&(sip_t1)), | |||||
1532 | NTATAG_SIP_T2_REF(sip_t2)ntatag_sip_t2_ref, tag_uint_vr(&(sip_t2)), | |||||
1533 | NTATAG_SIP_T4_REF(sip_t4)ntatag_sip_t4_ref, tag_uint_vr(&(sip_t4)), | |||||
1534 | #if HAVE_SOFIA_SMIME0 | |||||
1535 | NTATAG_SMIME_REF(smime)ntatag_smime_ref, tag_ptr_vr(&(smime), (smime)), | |||||
1536 | #endif | |||||
1537 | NTATAG_STATELESS_REF(stateless)ntatag_stateless_ref, tag_bool_vr(&(stateless)), | |||||
1538 | NTATAG_TCP_RPORT_REF(tcp_rport)ntatag_tcp_rport_ref, tag_bool_vr(&(tcp_rport)), | |||||
1539 | NTATAG_TLS_RPORT_REF(tls_rport)ntatag_tls_rport_ref, tag_bool_vr(&(tls_rport)), | |||||
1540 | NTATAG_TLS_ORQ_CONNECT_TIMEOUT_REF(tls_orq_connect_timeout)ntatag_tls_orq_connect_timeout_ref, tag_uint_vr(&(tls_orq_connect_timeout )), | |||||
1541 | NTATAG_TIMEOUT_408_REF(timeout_408)ntatag_timeout_408_ref, tag_bool_vr(&(timeout_408)), | |||||
1542 | NTATAG_UA_REF(ua)ntatag_ua_ref, tag_bool_vr(&(ua)), | |||||
1543 | NTATAG_UDP_MTU_REF(udp_mtu)ntatag_udp_mtu_ref, tag_uint_vr(&(udp_mtu)), | |||||
1544 | NTATAG_USER_VIA_REF(user_via)ntatag_user_via_ref, tag_bool_vr(&(user_via)), | |||||
1545 | NTATAG_USE_NAPTR_REF(use_naptr)ntatag_use_naptr_ref, tag_bool_vr(&(use_naptr)), | |||||
1546 | NTATAG_USE_SRV_REF(use_srv)ntatag_use_srv_ref, tag_bool_vr(&(use_srv)), | |||||
1547 | NTATAG_USE_TIMESTAMP_REF(use_timestamp)ntatag_use_timestamp_ref, tag_bool_vr(&(use_timestamp)), | |||||
1548 | #ifdef TPTAG_THRPSIZE | |||||
1549 | /* If threadpool is enabled, start a separate "reaper thread" */ | |||||
1550 | TPTAG_THRPSIZE_REF(threadpool)tptag_thrpsize_ref, tag_uint_vr(&(threadpool)), | |||||
1551 | #endif | |||||
1552 | NTATAG_SRV_503_REF(srv_503)ntatag_srv_503_ref, tag_bool_vr(&(srv_503)), | |||||
1553 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
1554 | nC = tl_gets(tags, | |||||
1555 | NTATAG_TIMER_C_REF(timer_c)ntatag_timer_c_ref, tag_uint_vr(&(timer_c)), | |||||
1556 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
1557 | n += nC; | |||||
1558 | ||||||
1559 | if (mclass != NONE((void *)-1)) | |||||
1560 | agent->sa_mclass = mclass ? mclass : sip_default_mclass(); | |||||
1561 | ||||||
1562 | m = 0; | |||||
1563 | for (tport = agent->sa_tports; tport; tport = tport_next(tport)) { | |||||
1564 | int m0 = tport_set_params(tport, TAG_NEXT(tags)tag_next, (tag_value_t)(tags)); | |||||
1565 | if (m0 < 0) | |||||
1566 | return m0; | |||||
1567 | if (m0 > m) | |||||
1568 | m = m0; | |||||
1569 | } | |||||
1570 | ||||||
1571 | n += m; | |||||
1572 | ||||||
1573 | if (aliases != NONE((void *)-1)) { | |||||
1574 | sip_contact_t const *m, *m_next; | |||||
1575 | ||||||
1576 | m = agent->sa_aliases; | |||||
1577 | agent->sa_aliases = sip_contact_dup(home, aliases); | |||||
1578 | ||||||
1579 | for (; m; m = m_next) { /* Free old aliases */ | |||||
1580 | m_next = m->m_next; | |||||
1581 | su_free(home, (void *)m); | |||||
1582 | } | |||||
1583 | } | |||||
1584 | ||||||
1585 | if (proxy != NONE((void *)-1)) { | |||||
1586 | url_t *dp = url_hdup(home, proxy->us_url); | |||||
1587 | ||||||
1588 | url_sanitize(dp); | |||||
1589 | ||||||
1590 | if (dp == NULL((void*)0) || dp->url_type == url_sip || dp->url_type == url_sips || dp->url_type == url_urn) { | |||||
1591 | if (agent->sa_default_proxy) | |||||
1592 | su_free(home, agent->sa_default_proxy); | |||||
1593 | agent->sa_default_proxy = dp; | |||||
1594 | } | |||||
1595 | else | |||||
1596 | n = -1; | |||||
1597 | } | |||||
1598 | ||||||
1599 | if (algorithm != NONE((void *)-1)) | |||||
1600 | agent->sa_algorithm = su_strdup(home, algorithm); | |||||
1601 | ||||||
1602 | if (!su_strmatch(sigcomp, agent->sa_sigcomp_options)) { | |||||
1603 | msg_param_t const *l = NULL((void*)0); | |||||
1604 | char *s = su_strdup(home, sigcomp); | |||||
1605 | char *s1 = su_strdup(home, s), *s2 = s1; | |||||
1606 | ||||||
1607 | if (s && s2 && msg_avlist_d(home, &s2, &l) == 0 && *s2 == '\0') { | |||||
1608 | su_free(home, (void *)agent->sa_sigcomp_options); | |||||
1609 | su_free(home, (void *)agent->sa_sigcomp_option_list); | |||||
1610 | agent->sa_sigcomp_options = s; | |||||
1611 | agent->sa_sigcomp_option_free = s1; | |||||
1612 | agent->sa_sigcomp_option_list = l; | |||||
1613 | } else { | |||||
1614 | su_free(home, s); | |||||
1615 | su_free(home, s1); | |||||
1616 | su_free(home, (void *)l); | |||||
1617 | n = -1; | |||||
1618 | } | |||||
1619 | } | |||||
1620 | ||||||
1621 | if (maxsize == 0) maxsize = 2 * 1024 * 1024; | |||||
1622 | if (maxsize > UINT32_MAX(4294967295U)) maxsize = UINT32_MAX(4294967295U); | |||||
1623 | agent->sa_maxsize = maxsize; | |||||
1624 | ||||||
1625 | if (max_proceeding == 0) max_proceeding = USIZE_MAX(2147483647 *2U +1U); | |||||
1626 | agent->sa_max_proceeding = max_proceeding; | |||||
1627 | ||||||
1628 | if (max_forwards == 0) max_forwards = 70; /* Default value */ | |||||
1629 | agent->sa_max_forwards->mf_count = max_forwards; | |||||
1630 | ||||||
1631 | if (udp_mtu == 0) udp_mtu = 1300; | |||||
1632 | if (udp_mtu > 65535) udp_mtu = 65535; | |||||
1633 | if (agent->sa_udp_mtu != udp_mtu) { | |||||
1634 | agent->sa_udp_mtu = udp_mtu; | |||||
1635 | agent_set_udp_params(agent, udp_mtu); | |||||
1636 | } | |||||
1637 | ||||||
1638 | if (sip_t1 == 0) sip_t1 = NTA_SIP_T1; | |||||
1639 | if (sip_t1 > NTA_TIME_MAX) sip_t1 = NTA_TIME_MAX; | |||||
1640 | agent->sa_t1 = sip_t1; | |||||
1641 | ||||||
1642 | if (sip_t2 == 0) sip_t2 = NTA_SIP_T2; | |||||
1643 | if (sip_t2 > NTA_TIME_MAX) sip_t2 = NTA_TIME_MAX; | |||||
1644 | agent->sa_t2 = sip_t2; | |||||
1645 | ||||||
1646 | if (sip_t4 == 0) sip_t4 = NTA_SIP_T4; | |||||
1647 | if (sip_t4 > NTA_TIME_MAX) sip_t4 = NTA_TIME_MAX; | |||||
1648 | if (agent->sa_t4 != sip_t4) { | |||||
1649 | incoming_queue_adjust(agent, agent->sa_in.inv_confirmed, sip_t4); | |||||
1650 | outgoing_queue_adjust(agent, agent->sa_out.completed, sip_t4); | |||||
1651 | } | |||||
1652 | agent->sa_t4 = sip_t4; | |||||
1653 | ||||||
1654 | if (sip_t1x64 == 0) sip_t1x64 = NTA_SIP_T1 * 64; | |||||
1655 | if (sip_t1x64 > NTA_TIME_MAX) sip_t1x64 = NTA_TIME_MAX; | |||||
1656 | if (agent->sa_t1x64 != sip_t1x64) { | |||||
1657 | incoming_queue_adjust(agent, agent->sa_in.preliminary, sip_t1x64); | |||||
1658 | incoming_queue_adjust(agent, agent->sa_in.completed, sip_t1x64); | |||||
1659 | incoming_queue_adjust(agent, agent->sa_in.inv_completed, sip_t1x64); | |||||
1660 | outgoing_queue_adjust(agent, agent->sa_out.trying, sip_t1x64); | |||||
1661 | outgoing_queue_adjust(agent, agent->sa_out.inv_calling, sip_t1x64); | |||||
1662 | } | |||||
1663 | agent->sa_t1x64 = sip_t1x64; | |||||
1664 | if (nC == 1) { | |||||
1665 | agent->sa_use_timer_c = 1; | |||||
1666 | if (timer_c == 0) | |||||
1667 | timer_c = 185 * 1000; | |||||
1668 | agent->sa_timer_c = timer_c; | |||||
1669 | outgoing_queue_adjust(agent, agent->sa_out.inv_proceeding, timer_c); | |||||
1670 | } | |||||
1671 | if (timer_d < sip_t1x64) | |||||
1672 | timer_d = sip_t1x64; | |||||
1673 | outgoing_queue_adjust(agent, agent->sa_out.inv_completed, timer_d); | |||||
1674 | ||||||
1675 | if (tls_orq_connect_timeout > NTA_TIME_MAX) tls_orq_connect_timeout = NTA_TIME_MAX; | |||||
1676 | agent->sa_tls_orq_connect_timeout = tls_orq_connect_timeout; | |||||
1677 | ||||||
1678 | if (graylist > 24 * 60 * 60) | |||||
1679 | graylist = 24 * 60 * 60; | |||||
1680 | agent->sa_graylist = graylist; | |||||
1681 | ||||||
1682 | if (blacklist > 24 * 60 * 60) | |||||
1683 | blacklist = 24 * 60 * 60; | |||||
1684 | agent->sa_blacklist = blacklist; | |||||
1685 | ||||||
1686 | if (progress == 0) | |||||
1687 | progress = 60 * 1000; | |||||
1688 | agent->sa_progress = progress; | |||||
1689 | ||||||
1690 | if (server_rport > 3) | |||||
1691 | server_rport = 1; | |||||
1692 | else if (server_rport < 0) | |||||
1693 | server_rport = 1; | |||||
1694 | agent->sa_server_rport = server_rport; | |||||
1695 | ||||||
1696 | agent->sa_bad_req_mask = bad_req_mask; | |||||
1697 | agent->sa_bad_resp_mask = bad_resp_mask; | |||||
1698 | ||||||
1699 | agent->sa_is_a_uas = ua != 0; | |||||
1700 | agent->sa_is_stateless = stateless != 0; | |||||
1701 | agent->sa_drop_prob = drop_prob < 1000 ? drop_prob : 1000; | |||||
1702 | agent->sa_user_via = user_via != 0; | |||||
1703 | agent->sa_extra_100 = extra_100 != 0; | |||||
1704 | agent->sa_pass_100 = pass_100 != 0; | |||||
1705 | agent->sa_timeout_408 = timeout_408 != 0; | |||||
1706 | agent->sa_pass_408 = pass_408 != 0; | |||||
1707 | agent->sa_merge_482 = merge_482 != 0; | |||||
1708 | agent->sa_cancel_2543 = cancel_2543 != 0; | |||||
1709 | agent->sa_cancel_487 = cancel_487 != 0; | |||||
1710 | agent->sa_invite_100rel = invite_100rel != 0; | |||||
1711 | agent->sa_timestamp = use_timestamp != 0; | |||||
1712 | agent->sa_use_naptr = use_naptr != 0; | |||||
1713 | agent->sa_use_srv = use_srv != 0; | |||||
1714 | agent->sa_srv_503 = srv_503 != 0; | |||||
1715 | agent->sa_smime = smime; | |||||
1716 | agent->sa_flags = flags & MSG_FLG_USERMASK; | |||||
1717 | agent->sa_rport = rport != 0; | |||||
1718 | agent->sa_tcp_rport = tcp_rport != 0; | |||||
1719 | agent->sa_tls_rport = tls_rport != 0; | |||||
1720 | agent->sa_preload = preload; | |||||
1721 | agent->sa_tport_threadpool = threadpool; | |||||
1722 | ||||||
1723 | return n; | |||||
1724 | } | |||||
1725 | ||||||
1726 | static | |||||
1727 | void agent_set_udp_params(nta_agent_t *self, usize_t udp_mtu) | |||||
1728 | { | |||||
1729 | tport_t *tp; | |||||
1730 | ||||||
1731 | /* Set via fields for the tports */ | |||||
1732 | for (tp = tport_primaries(self->sa_tports); tp; tp = tport_next(tp)) { | |||||
1733 | if (tport_is_udp(tp)) | |||||
1734 | tport_set_params(tp, | |||||
1735 | TPTAG_TIMEOUT(2 * self->sa_t1x64)tptag_timeout, tag_uint_v((2 * self->sa_t1x64)), | |||||
1736 | TPTAG_MTU(udp_mtu)tptag_mtu, tag_usize_v((udp_mtu)), | |||||
1737 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
1738 | } | |||||
1739 | } | |||||
1740 | ||||||
1741 | /**Get NTA Parameters. | |||||
1742 | * | |||||
1743 | * The nta_agent_get_params() function retrieves the stack parameters. The | |||||
1744 | * parameters determine the way NTA handles the retransmissions, how long | |||||
1745 | * NTA keeps transactions alive, does NTA apply proxy or user-agent logic to | |||||
1746 | * INVITE transactions, or how the @Via headers are generated. | |||||
1747 | * | |||||
1748 | * @TAGS | |||||
1749 | * NTATAG_ALIASES_REF(), NTATAG_BLACKLIST_REF(), | |||||
1750 | * NTATAG_CANCEL_2543_REF(), NTATAG_CANCEL_487_REF(), | |||||
1751 | * NTATAG_CLIENT_RPORT_REF(), NTATAG_CONTACT_REF(), | |||||
1752 | * NTATAG_DEBUG_DROP_PROB_REF(), NTATAG_DEFAULT_PROXY_REF(), | |||||
1753 | * NTATAG_EXTRA_100_REF(), NTATAG_GRAYLIST_REF(), | |||||
1754 | * NTATAG_MAXSIZE_REF(), NTATAG_MAX_FORWARDS_REF(), NTATAG_MCLASS_REF(), | |||||
1755 | * NTATAG_MERGE_482_REF(), NTATAG_MAX_PROCEEDING_REF(), | |||||
1756 | * NTATAG_PASS_100_REF(), NTATAG_PASS_408_REF(), NTATAG_PRELOAD_REF(), | |||||
1757 | * NTATAG_PROGRESS_REF(), | |||||
1758 | * NTATAG_REL100_REF(), | |||||
1759 | * NTATAG_SERVER_RPORT_REF(), | |||||
1760 | * NTATAG_SIGCOMP_ALGORITHM_REF(), NTATAG_SIGCOMP_OPTIONS_REF(), | |||||
1761 | * NTATAG_SIPFLAGS_REF(), | |||||
1762 | * NTATAG_SIP_T1_REF(), NTATAG_SIP_T1X64_REF(), NTATAG_SIP_T2_REF(), | |||||
1763 | * NTATAG_SIP_T4_REF(), NTATAG_SMIME_REF(), NTATAG_STATELESS_REF(), | |||||
1764 | * NTATAG_TAG_3261_REF(), NTATAG_TIMEOUT_408_REF(), NTATAG_TIMER_C_REF(), | |||||
1765 | * NTATAG_UA_REF(), NTATAG_UDP_MTU_REF(), NTATAG_USER_VIA_REF(), | |||||
1766 | * NTATAG_USE_NAPTR_REF(), NTATAG_USE_SRV_REF(), | |||||
1767 | * and NTATAG_USE_TIMESTAMP_REF(). | |||||
1768 | * | |||||
1769 | */ | |||||
1770 | int nta_agent_get_params(nta_agent_t *agent, | |||||
1771 | tag_type_t tag, tag_value_t value, ...) | |||||
1772 | { | |||||
1773 | int n; | |||||
1774 | ta_list ta; | |||||
1775 | ||||||
1776 | if (agent) { | |||||
1777 | ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value = (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag ) == tag_next && (ta_start__value) != 0) { ta_start__tag = ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag == tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag == tag_next) { ta_start__value = ((tagi_t *)ta_start__value) ->t_value; } else { ta_start__tag = tag_next; break; } } ( ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value ; if (ta_start__tag != ((void*)0) && ta_start__tag != tag_null && ta_start__tag != tag_next) { va_list ta_start__ap ; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag = tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap ); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value = 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0); | |||||
1778 | n = agent_get_params(agent, ta_args(ta)(ta).tl); | |||||
1779 | ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value ))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta) .ap)); | |||||
1780 | return n; | |||||
1781 | } | |||||
1782 | ||||||
1783 | su_seterrno(EINVAL22); | |||||
1784 | return -1; | |||||
1785 | } | |||||
1786 | ||||||
1787 | /** Get NTA parameters */ | |||||
1788 | static | |||||
1789 | int agent_get_params(nta_agent_t *agent, tagi_t *tags) | |||||
1790 | { | |||||
1791 | return | |||||
1792 | tl_tgets(tags, | |||||
1793 | NTATAG_ALIASES(agent->sa_aliases)ntatag_aliases, siptag_contact_v((agent->sa_aliases)), | |||||
1794 | NTATAG_BLACKLIST(agent->sa_blacklist)ntatag_blacklist, tag_uint_v((agent->sa_blacklist)), | |||||
1795 | NTATAG_CANCEL_2543(agent->sa_cancel_2543)ntatag_cancel_2543, tag_bool_v((agent->sa_cancel_2543)), | |||||
1796 | NTATAG_CANCEL_487(agent->sa_cancel_487)ntatag_cancel_487, tag_bool_v((agent->sa_cancel_487)), | |||||
1797 | NTATAG_CLIENT_RPORT(agent->sa_rport)ntatag_client_rport, tag_bool_v((agent->sa_rport)), | |||||
1798 | NTATAG_CONTACT(agent->sa_contact)ntatag_contact, siptag_contact_v((agent->sa_contact)), | |||||
1799 | NTATAG_DEBUG_DROP_PROB(agent->sa_drop_prob)ntatag_debug_drop_prob, tag_uint_v((agent->sa_drop_prob)), | |||||
1800 | NTATAG_DEFAULT_PROXY(agent->sa_default_proxy)ntatag_default_proxy, urltag_url_v((agent->sa_default_proxy )), | |||||
1801 | NTATAG_EXTRA_100(agent->sa_extra_100)ntatag_extra_100, tag_bool_v((agent->sa_extra_100)), | |||||
1802 | NTATAG_GRAYLIST(agent->sa_graylist)ntatag_graylist, tag_uint_v((agent->sa_graylist)), | |||||
1803 | NTATAG_MAXSIZE(agent->sa_maxsize)ntatag_maxsize, tag_usize_v((agent->sa_maxsize)), | |||||
1804 | NTATAG_MAX_PROCEEDING(agent->sa_max_proceeding)ntatag_max_proceeding, tag_usize_v((agent->sa_max_proceeding )), | |||||
1805 | NTATAG_MAX_FORWARDS(agent->sa_max_forwards->mf_count)ntatag_max_forwards, tag_uint_v((agent->sa_max_forwards-> mf_count)), | |||||
1806 | NTATAG_MCLASS(agent->sa_mclass)ntatag_mclass, tag_cptr_v((agent->sa_mclass)), | |||||
1807 | NTATAG_MERGE_482(agent->sa_merge_482)ntatag_merge_482, tag_bool_v((agent->sa_merge_482)), | |||||
1808 | NTATAG_PASS_100(agent->sa_pass_100)ntatag_pass_100, tag_bool_v((agent->sa_pass_100)), | |||||
1809 | NTATAG_PASS_408(agent->sa_pass_408)ntatag_pass_408, tag_bool_v((agent->sa_pass_408)), | |||||
1810 | NTATAG_PRELOAD(agent->sa_preload)ntatag_preload, tag_uint_v((agent->sa_preload)), | |||||
1811 | NTATAG_PROGRESS(agent->sa_progress)ntatag_progress, tag_uint_v((agent->sa_progress)), | |||||
1812 | NTATAG_REL100(agent->sa_invite_100rel)ntatag_rel100, tag_bool_v((agent->sa_invite_100rel)), | |||||
1813 | NTATAG_SERVER_RPORT((int)(agent->sa_server_rport))ntatag_server_rport, tag_int_v(((int)(agent->sa_server_rport ))), | |||||
1814 | NTATAG_SIGCOMP_ALGORITHM(agent->sa_algorithm)ntatag_sigcomp_algorithm, tag_str_v((agent->sa_algorithm)), | |||||
1815 | NTATAG_SIGCOMP_OPTIONS(agent->sa_sigcomp_options ?ntatag_sigcomp_options, tag_str_v((agent->sa_sigcomp_options ? agent->sa_sigcomp_options : "sip")) | |||||
1816 | agent->sa_sigcomp_options :ntatag_sigcomp_options, tag_str_v((agent->sa_sigcomp_options ? agent->sa_sigcomp_options : "sip")) | |||||
1817 | "sip")ntatag_sigcomp_options, tag_str_v((agent->sa_sigcomp_options ? agent->sa_sigcomp_options : "sip")), | |||||
1818 | NTATAG_SIPFLAGS(agent->sa_flags)ntatag_sipflags, tag_uint_v((agent->sa_flags)), | |||||
1819 | NTATAG_SIP_T1(agent->sa_t1)ntatag_sip_t1, tag_uint_v((agent->sa_t1)), | |||||
1820 | NTATAG_SIP_T1X64(agent->sa_t1x64)ntatag_sip_t1x64, tag_uint_v((agent->sa_t1x64)), | |||||
1821 | NTATAG_SIP_T2(agent->sa_t2)ntatag_sip_t2, tag_uint_v((agent->sa_t2)), | |||||
1822 | NTATAG_SIP_T4(agent->sa_t4)ntatag_sip_t4, tag_uint_v((agent->sa_t4)), | |||||
1823 | #if HAVE_SOFIA_SMIME0 | |||||
1824 | NTATAG_SMIME(agent->sa_smime)ntatag_smime, tag_ptr_v((agent->sa_smime)), | |||||
1825 | #else | |||||
1826 | NTATAG_SMIME(NULL)ntatag_smime, tag_ptr_v((((void*)0))), | |||||
1827 | #endif | |||||
1828 | NTATAG_STATELESS(agent->sa_is_stateless)ntatag_stateless, tag_bool_v((agent->sa_is_stateless)), | |||||
1829 | NTATAG_TAG_3261(1)ntatag_tag_3261, tag_bool_v((1)), | |||||
1830 | NTATAG_TIMEOUT_408(agent->sa_timeout_408)ntatag_timeout_408, tag_bool_v((agent->sa_timeout_408)), | |||||
1831 | NTATAG_TIMER_C(agent->sa_timer_c)ntatag_timer_c, tag_uint_v((agent->sa_timer_c)), | |||||
1832 | NTATAG_UA(agent->sa_is_a_uas)ntatag_ua, tag_bool_v((agent->sa_is_a_uas)), | |||||
1833 | NTATAG_UDP_MTU(agent->sa_udp_mtu)ntatag_udp_mtu, tag_uint_v((agent->sa_udp_mtu)), | |||||
1834 | NTATAG_USER_VIA(agent->sa_user_via)ntatag_user_via, tag_bool_v((agent->sa_user_via)), | |||||
1835 | NTATAG_USE_NAPTR(agent->sa_use_naptr)ntatag_use_naptr, tag_bool_v((agent->sa_use_naptr)), | |||||
1836 | NTATAG_USE_SRV(agent->sa_use_srv)ntatag_use_srv, tag_bool_v((agent->sa_use_srv)), | |||||
1837 | NTATAG_USE_TIMESTAMP(agent->sa_timestamp)ntatag_use_timestamp, tag_bool_v((agent->sa_timestamp)), | |||||
1838 | NTATAG_SRV_503(agent->sa_srv_503)ntatag_srv_503, tag_bool_v((agent->sa_srv_503)), | |||||
1839 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
1840 | } | |||||
1841 | ||||||
1842 | /**Get NTA statistics. | |||||
1843 | * | |||||
1844 | * The nta_agent_get_stats() function retrieves the stack statistics. | |||||
1845 | * | |||||
1846 | * @TAGS | |||||
1847 | * NTATAG_S_ACKED_TR_REF(), | |||||
1848 | * NTATAG_S_BAD_MESSAGE_REF(), | |||||
1849 | * NTATAG_S_BAD_REQUEST_REF(), | |||||
1850 | * NTATAG_S_BAD_RESPONSE_REF(), | |||||
1851 | * NTATAG_S_CANCELED_TR_REF(), | |||||
1852 | * NTATAG_S_CLIENT_TR_REF(), | |||||
1853 | * NTATAG_S_DIALOG_TR_REF(), | |||||
1854 | * NTATAG_S_DROP_REQUEST_REF(), | |||||
1855 | * NTATAG_S_DROP_RESPONSE_REF(), | |||||
1856 | * NTATAG_S_IRQ_HASH_REF(), | |||||
1857 | * NTATAG_S_IRQ_HASH_USED_REF(), | |||||
1858 | * NTATAG_S_LEG_HASH_REF(), | |||||
1859 | * NTATAG_S_LEG_HASH_USED_REF(), | |||||
1860 | * NTATAG_S_MERGED_REQUEST_REF(), | |||||
1861 | * NTATAG_S_ORQ_HASH_REF(), | |||||
1862 | * NTATAG_S_ORQ_HASH_USED_REF(), | |||||
1863 | * NTATAG_S_RECV_MSG_REF(), | |||||
1864 | * NTATAG_S_RECV_REQUEST_REF(), | |||||
1865 | * NTATAG_S_RECV_RESPONSE_REF(), | |||||
1866 | * NTATAG_S_RECV_RETRY_REF(), | |||||
1867 | * NTATAG_S_RETRY_REQUEST_REF(), | |||||
1868 | * NTATAG_S_RETRY_RESPONSE_REF(), | |||||
1869 | * NTATAG_S_SENT_MSG_REF(), | |||||
1870 | * NTATAG_S_SENT_REQUEST_REF(), | |||||
1871 | * NTATAG_S_SENT_RESPONSE_REF(), | |||||
1872 | * NTATAG_S_SERVER_TR_REF(), | |||||
1873 | * NTATAG_S_TOUT_REQUEST_REF(), | |||||
1874 | * NTATAG_S_TOUT_RESPONSE_REF(), | |||||
1875 | * NTATAG_S_TRLESS_200_REF(), | |||||
1876 | * NTATAG_S_TRLESS_REQUEST_REF(), | |||||
1877 | * NTATAG_S_TRLESS_RESPONSE_REF(), and | |||||
1878 | * NTATAG_S_TRLESS_TO_TR_REF(), | |||||
1879 | */ | |||||
1880 | int nta_agent_get_stats(nta_agent_t *agent, | |||||
1881 | tag_type_t tag, tag_value_t value, ...) | |||||
1882 | { | |||||
1883 | int n; | |||||
1884 | ta_list ta; | |||||
1885 | ||||||
1886 | if (!agent) | |||||
1887 | return su_seterrno(EINVAL22), -1; | |||||
1888 | ||||||
1889 | ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value = (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag ) == tag_next && (ta_start__value) != 0) { ta_start__tag = ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag == tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag == tag_next) { ta_start__value = ((tagi_t *)ta_start__value) ->t_value; } else { ta_start__tag = tag_next; break; } } ( ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value ; if (ta_start__tag != ((void*)0) && ta_start__tag != tag_null && ta_start__tag != tag_next) { va_list ta_start__ap ; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag = tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap ); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value = 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0); | |||||
1890 | ||||||
1891 | n = tl_tgets(ta_args(ta)(ta).tl, | |||||
1892 | NTATAG_S_IRQ_HASH(agent->sa_incoming->iht_size)ntatag_s_irq_hash, tag_usize_v(agent->sa_incoming->iht_size ), | |||||
1893 | NTATAG_S_ORQ_HASH(agent->sa_outgoing->oht_size)ntatag_s_orq_hash, tag_usize_v(agent->sa_outgoing->oht_size ), | |||||
1894 | NTATAG_S_LEG_HASH(agent->sa_dialogs->lht_size)ntatag_s_leg_hash, tag_usize_v(agent->sa_dialogs->lht_size ), | |||||
1895 | NTATAG_S_IRQ_HASH_USED(agent->sa_incoming->iht_used)ntatag_s_irq_hash_used, tag_usize_v(agent->sa_incoming-> iht_used), | |||||
1896 | NTATAG_S_ORQ_HASH_USED(agent->sa_outgoing->oht_used)ntatag_s_orq_hash_used, tag_usize_v(agent->sa_outgoing-> oht_used), | |||||
1897 | NTATAG_S_LEG_HASH_USED(agent->sa_dialogs->lht_used)ntatag_s_leg_hash_used, tag_usize_v(agent->sa_dialogs-> lht_used), | |||||
1898 | NTATAG_S_RECV_MSG(agent->sa_stats->as_recv_msg)ntatag_s_recv_msg, tag_usize_v(agent->sa_stats->as_recv_msg ), | |||||
1899 | NTATAG_S_RECV_REQUEST(agent->sa_stats->as_recv_request)ntatag_s_recv_request, tag_usize_v(agent->sa_stats->as_recv_request ), | |||||
1900 | NTATAG_S_RECV_RESPONSE(agent->sa_stats->as_recv_response)ntatag_s_recv_response, tag_usize_v(agent->sa_stats->as_recv_response ), | |||||
1901 | NTATAG_S_BAD_MESSAGE(agent->sa_stats->as_bad_message)ntatag_s_bad_message, tag_usize_v(agent->sa_stats->as_bad_message ), | |||||
1902 | NTATAG_S_BAD_REQUEST(agent->sa_stats->as_bad_request)ntatag_s_bad_request, tag_usize_v(agent->sa_stats->as_bad_request ), | |||||
1903 | NTATAG_S_BAD_RESPONSE(agent->sa_stats->as_bad_response)ntatag_s_bad_response, tag_usize_v(agent->sa_stats->as_bad_response ), | |||||
1904 | NTATAG_S_DROP_REQUEST(agent->sa_stats->as_drop_request)ntatag_s_drop_request, tag_usize_v(agent->sa_stats->as_drop_request ), | |||||
1905 | NTATAG_S_DROP_RESPONSE(agent->sa_stats->as_drop_response)ntatag_s_drop_response, tag_usize_v(agent->sa_stats->as_drop_response ), | |||||
1906 | NTATAG_S_CLIENT_TR(agent->sa_stats->as_client_tr)ntatag_s_client_tr, tag_usize_v(agent->sa_stats->as_client_tr ), | |||||
1907 | NTATAG_S_SERVER_TR(agent->sa_stats->as_server_tr)ntatag_s_server_tr, tag_usize_v(agent->sa_stats->as_server_tr ), | |||||
1908 | NTATAG_S_DIALOG_TR(agent->sa_stats->as_dialog_tr)ntatag_s_dialog_tr, tag_usize_v(agent->sa_stats->as_dialog_tr ), | |||||
1909 | NTATAG_S_ACKED_TR(agent->sa_stats->as_acked_tr)ntatag_s_acked_tr, tag_usize_v(agent->sa_stats->as_acked_tr ), | |||||
1910 | NTATAG_S_CANCELED_TR(agent->sa_stats->as_canceled_tr)ntatag_s_canceled_tr, tag_usize_v(agent->sa_stats->as_canceled_tr ), | |||||
1911 | NTATAG_S_TRLESS_REQUEST(agent->sa_stats->as_trless_request)ntatag_s_trless_request, tag_usize_v(agent->sa_stats->as_trless_request ), | |||||
1912 | NTATAG_S_TRLESS_TO_TR(agent->sa_stats->as_trless_to_tr)ntatag_s_trless_to_tr, tag_usize_v(agent->sa_stats->as_trless_to_tr ), | |||||
1913 | NTATAG_S_TRLESS_RESPONSE(agent->sa_stats->as_trless_response)ntatag_s_trless_response, tag_usize_v(agent->sa_stats-> as_trless_response), | |||||
1914 | NTATAG_S_TRLESS_200(agent->sa_stats->as_trless_200)ntatag_s_trless_200, tag_usize_v(agent->sa_stats->as_trless_200 ), | |||||
1915 | NTATAG_S_MERGED_REQUEST(agent->sa_stats->as_merged_request)ntatag_s_merged_request, tag_usize_v(agent->sa_stats->as_merged_request ), | |||||
1916 | NTATAG_S_SENT_MSG(agent->sa_stats->as_sent_msg)ntatag_s_sent_msg, tag_usize_v(agent->sa_stats->as_sent_msg ), | |||||
1917 | NTATAG_S_SENT_REQUEST(agent->sa_stats->as_sent_request)ntatag_s_sent_request, tag_usize_v(agent->sa_stats->as_sent_request ), | |||||
1918 | NTATAG_S_SENT_RESPONSE(agent->sa_stats->as_sent_response)ntatag_s_sent_response, tag_usize_v(agent->sa_stats->as_sent_response ), | |||||
1919 | NTATAG_S_RETRY_REQUEST(agent->sa_stats->as_retry_request)ntatag_s_retry_request, tag_usize_v(agent->sa_stats->as_retry_request ), | |||||
1920 | NTATAG_S_RETRY_RESPONSE(agent->sa_stats->as_retry_response)ntatag_s_retry_response, tag_usize_v(agent->sa_stats->as_retry_response ), | |||||
1921 | NTATAG_S_RECV_RETRY(agent->sa_stats->as_recv_retry)ntatag_s_recv_retry, tag_usize_v(agent->sa_stats->as_recv_retry ), | |||||
1922 | NTATAG_S_TOUT_REQUEST(agent->sa_stats->as_tout_request)ntatag_s_tout_request, tag_usize_v(agent->sa_stats->as_tout_request ), | |||||
1923 | NTATAG_S_TOUT_RESPONSE(agent->sa_stats->as_tout_response)ntatag_s_tout_response, tag_usize_v(agent->sa_stats->as_tout_response ), | |||||
1924 | NTATAG_Q_IN_COMPLETED(agent->sa_in.completed->q_length)ntatag_q_in_completed, tag_size_v(agent->sa_in.completed-> q_length), | |||||
1925 | NTATAG_Q_IN_FINAL_FAILED(agent->sa_in.final_failed->q_length)ntatag_q_in_final_failed, tag_size_v(agent->sa_in.final_failed ->q_length), | |||||
1926 | NTATAG_Q_IN_INV_COMPLETED(agent->sa_in.inv_completed->q_length)ntatag_q_in_inv_completed, tag_size_v(agent->sa_in.inv_completed ->q_length), | |||||
1927 | NTATAG_Q_IN_INV_CONFIRMED(agent->sa_in.inv_confirmed->q_length)ntatag_q_in_inv_confirmed, tag_size_v(agent->sa_in.inv_confirmed ->q_length), | |||||
1928 | NTATAG_Q_IN_PRELIMINARY(agent->sa_in.preliminary->q_length)ntatag_q_in_preliminary, tag_size_v(agent->sa_in.preliminary ->q_length), | |||||
1929 | NTATAG_Q_IN_PROCEEDING(agent->sa_in.proceeding->q_length)ntatag_q_in_proceeding, tag_size_v(agent->sa_in.proceeding ->q_length), | |||||
1930 | NTATAG_Q_IN_TERMINATED(agent->sa_in.terminated->q_length)ntatag_q_in_terminated, tag_size_v(agent->sa_in.terminated ->q_length), | |||||
1931 | NTATAG_Q_OUT_COMPLETED(agent->sa_out.completed->q_length)ntatag_q_out_completed, tag_size_v(agent->sa_out.completed ->q_length), | |||||
1932 | NTATAG_Q_OUT_DELAYED(agent->sa_out.delayed->q_length)ntatag_q_out_delayed, tag_size_v(agent->sa_out.delayed-> q_length), | |||||
1933 | NTATAG_Q_OUT_INV_CALLING(agent->sa_out.inv_calling->q_length)ntatag_q_out_inv_calling, tag_size_v(agent->sa_out.inv_calling ->q_length), | |||||
1934 | NTATAG_Q_OUT_INV_COMPLETED(agent->sa_out.inv_completed->q_length)ntatag_q_out_inv_completed, tag_size_v(agent->sa_out.inv_completed ->q_length), | |||||
1935 | NTATAG_Q_OUT_INV_PROCEEDING(agent->sa_out.inv_proceeding->q_length)ntatag_q_out_inv_proceeding, tag_size_v(agent->sa_out.inv_proceeding ->q_length), | |||||
1936 | NTATAG_Q_OUT_RESOLVING(agent->sa_out.resolving->q_length)ntatag_q_out_resolving, tag_size_v(agent->sa_out.resolving ->q_length), | |||||
1937 | NTATAG_Q_OUT_TERMINATED(agent->sa_out.terminated->q_length)ntatag_q_out_terminated, tag_size_v(agent->sa_out.terminated ->q_length), | |||||
1938 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
1939 | ||||||
1940 | ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value ))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta) .ap)); | |||||
1941 | ||||||
1942 | return n; | |||||
1943 | } | |||||
1944 | ||||||
1945 | /**Calculate a new unique tag. | |||||
1946 | * | |||||
1947 | * This function generates a series of 2**64 unique tags for @From or @To | |||||
1948 | * headers. The start of the tag series is derived from the NTP time the NTA | |||||
1949 | * agent was initialized. | |||||
1950 | * | |||||
1951 | */ | |||||
1952 | char const *nta_agent_newtag(su_home_t *home, char const *fmt, nta_agent_t *sa) | |||||
1953 | { | |||||
1954 | char tag[(8 * 8 + 4)/ 5 + 1]; | |||||
1955 | ||||||
1956 | if (sa == NULL((void*)0)) | |||||
1957 | return su_seterrno(EINVAL22), NULL((void*)0); | |||||
1958 | ||||||
1959 | /* XXX - use a cryptographically safe func here? */ | |||||
1960 | sa->sa_tags += NTA_TAG_PRIME(uint64_t)(0xB9591D1C361C6521ULL); | |||||
1961 | ||||||
1962 | msg_random_token(tag, sizeof(tag) - 1, &sa->sa_tags, sizeof(sa->sa_tags)); | |||||
1963 | ||||||
1964 | if (fmt && fmt[0]) | |||||
1965 | return su_sprintf(home, fmt, tag); | |||||
1966 | else | |||||
1967 | return su_strdup(home, tag); | |||||
1968 | } | |||||
1969 | ||||||
1970 | /** | |||||
1971 | * Calculate branch value. | |||||
1972 | */ | |||||
1973 | static char const *stateful_branch(su_home_t *home, nta_agent_t *sa) | |||||
1974 | { | |||||
1975 | char branch[(8 * 8 + 4)/ 5 + 1]; | |||||
1976 | ||||||
1977 | /* XXX - use a cryptographically safe func here? */ | |||||
1978 | sa->sa_branch += NTA_BRANCH_PRIME(uint64_t)(0xB9591D1C361C6521ULL); | |||||
1979 | ||||||
1980 | msg_random_token(branch, sizeof(branch) - 1, | |||||
1981 | &sa->sa_branch, sizeof(sa->sa_branch)); | |||||
1982 | ||||||
1983 | return su_sprintf(home, "branch=z9hG4bK%s", branch); | |||||
1984 | } | |||||
1985 | ||||||
1986 | #include <sofia-sip/su_md5.h> | |||||
1987 | ||||||
1988 | /** | |||||
1989 | * Calculate branch value for stateless operation. | |||||
1990 | * | |||||
1991 | * XXX - should include HMAC of previous @Via line. | |||||
1992 | */ | |||||
1993 | static | |||||
1994 | char const *stateless_branch(nta_agent_t *sa, | |||||
1995 | msg_t *msg, | |||||
1996 | sip_t const *sip, | |||||
1997 | tp_name_t const *tpn) | |||||
1998 | { | |||||
1999 | su_md5_t md5[1]; | |||||
2000 | uint8_t digest[SU_MD5_DIGEST_SIZE16]; | |||||
2001 | char branch[(SU_MD5_DIGEST_SIZE16 * 8 + 4)/ 5 + 1]; | |||||
2002 | sip_route_t const *r; | |||||
2003 | ||||||
2004 | assert(sip->sip_request)((void) sizeof ((sip->sip_request) ? 1 : 0), __extension__ ({ if (sip->sip_request) ; else __assert_fail ("sip->sip_request" , "nta.c", 2004, __extension__ __PRETTY_FUNCTION__); })); | |||||
2005 | ||||||
2006 | if (!sip->sip_via) | |||||
2007 | return stateful_branch(msg_home(msg)((su_home_t*)(msg)), sa); | |||||
2008 | ||||||
2009 | su_md5_init(md5); | |||||
2010 | ||||||
2011 | su_md5_str0update(md5, tpn->tpn_host); | |||||
2012 | su_md5_str0update(md5, tpn->tpn_port); | |||||
2013 | ||||||
2014 | url_update(md5, sip->sip_request->rq_url); | |||||
2015 | if (sip->sip_call_id) { | |||||
2016 | su_md5_str0update(md5, sip->sip_call_id->i_id); | |||||
2017 | } | |||||
2018 | if (sip->sip_from) { | |||||
2019 | url_update(md5, sip->sip_from->a_url); | |||||
2020 | su_md5_stri0update(md5, sip->sip_from->a_tag); | |||||
2021 | } | |||||
2022 | if (sip->sip_to) { | |||||
2023 | url_update(md5, sip->sip_to->a_url); | |||||
2024 | /* XXX - some broken implementations include To tag in CANCEL */ | |||||
2025 | /* su_md5_str0update(md5, sip->sip_to->a_tag); */ | |||||
2026 | } | |||||
2027 | if (sip->sip_cseq) { | |||||
2028 | uint32_t cseq = htonl(sip->sip_cseq->cs_seq); | |||||
2029 | su_md5_update(md5, &cseq, sizeof(cseq)); | |||||
2030 | } | |||||
2031 | ||||||
2032 | for (r = sip->sip_route; r; r = r->r_next) | |||||
2033 | url_update(md5, r->r_url); | |||||
2034 | ||||||
2035 | su_md5_digest(md5, digest); | |||||
2036 | ||||||
2037 | msg_random_token(branch, sizeof(branch) - 1, digest, sizeof(digest)); | |||||
2038 | ||||||
2039 | return su_sprintf(msg_home(msg)((su_home_t*)(msg)), "branch=z9hG4bK.%s", branch); | |||||
2040 | } | |||||
2041 | ||||||
2042 | /* ====================================================================== */ | |||||
2043 | /* 2) Transport interface */ | |||||
2044 | ||||||
2045 | /* Local prototypes */ | |||||
2046 | static int agent_create_master_transport(nta_agent_t *self, tagi_t *tags); | |||||
2047 | static int agent_init_via(nta_agent_t *self, tport_t *primaries, int use_maddr); | |||||
2048 | static int agent_init_contact(nta_agent_t *self); | |||||
2049 | static void agent_recv_message(nta_agent_t *agent, | |||||
2050 | tport_t *tport, | |||||
2051 | msg_t *msg, | |||||
2052 | sip_via_t *tport_via, | |||||
2053 | su_time_t now); | |||||
2054 | static void agent_tp_error(nta_agent_t *agent, | |||||
2055 | tport_t *tport, | |||||
2056 | int errcode, | |||||
2057 | char const *remote); | |||||
2058 | static void agent_update_tport(nta_agent_t *agent, tport_t *); | |||||
2059 | ||||||
2060 | /**For each transport, we have name used by tport module, SRV prefixes used | |||||
2061 | * for resolving, and NAPTR service/conversion. | |||||
2062 | */ | |||||
2063 | static | |||||
2064 | struct sipdns_tport { | |||||
2065 | char name[6]; /**< Named used by tport module */ | |||||
2066 | char port[6]; /**< Default port number */ | |||||
2067 | char prefix[14]; /**< Prefix for SRV domains */ | |||||
2068 | char service[10]; /**< NAPTR service */ | |||||
2069 | } | |||||
2070 | #define SIPDNS_TRANSPORTS(6) (6) | |||||
2071 | const sipdns_tports[SIPDNS_TRANSPORTS(6)] = { | |||||
2072 | { "udp", "5060", "_sip._udp.", "SIP+D2U" }, | |||||
2073 | { "tcp", "5060", "_sip._tcp.", "SIP+D2T" }, | |||||
2074 | { "sctp", "5060", "_sip._sctp.", "SIP+D2S" }, | |||||
2075 | { "tls", "5061", "_sips._tcp.", "SIPS+D2T" }, | |||||
2076 | { "ws", "5080", "_sips._ws.", "SIP+D2W" }, | |||||
2077 | { "wss", "5081", "_sips._wss.", "SIPS+D2W" }, | |||||
2078 | }; | |||||
2079 | ||||||
2080 | static char const * const tports_sip[] = | |||||
2081 | { | |||||
2082 | "udp", "tcp", "sctp", "ws", NULL((void*)0) | |||||
2083 | }; | |||||
2084 | ||||||
2085 | static char const * const tports_sips[] = | |||||
2086 | { | |||||
2087 | "tls", "wss", "ws", NULL((void*)0) | |||||
2088 | }; | |||||
2089 | ||||||
2090 | static tport_stack_class_t nta_agent_class[1] = | |||||
2091 | {{ | |||||
2092 | sizeof(nta_agent_class), | |||||
2093 | agent_recv_message, | |||||
2094 | agent_tp_error, | |||||
2095 | nta_msg_create_for_transport, | |||||
2096 | agent_update_tport, | |||||
2097 | }}; | |||||
2098 | ||||||
2099 | ||||||
2100 | /** Add a transport to the agent. | |||||
2101 | * | |||||
2102 | * Creates a new transport and binds it | |||||
2103 | * to the port specified by the @a uri. The @a uri must have sip: or sips: | |||||
2104 | * scheme or be a wildcard uri ("*"). The @a uri syntax allowed is as | |||||
2105 | * follows: | |||||
2106 | * | |||||
2107 | * @code url <scheme>:<host>[:<port>]<url-params> @endcode | |||||
2108 | * where <url-params> may be | |||||
2109 | * @code | |||||
2110 | * ;transport=<xxx> | |||||
2111 | * ;maddr=<actual addr> | |||||
2112 | * ;comp=sigcomp | |||||
2113 | * @endcode | |||||
2114 | * | |||||
2115 | * The scheme part determines which transports are used. "sip" implies UDP | |||||
2116 | * and TCP, "sips" TLS over TCP. In the future, more transports can be | |||||
2117 | * supported, for instance, "sip" can use SCTP or DCCP, "sips" DTLS or TLS | |||||
2118 | * over SCTP. | |||||
2119 | * | |||||
2120 | * The "host" part determines what address/domain name is used in @Contact. | |||||
2121 | * An "*" in "host" part is shorthand for any local IP address. 0.0.0.0 | |||||
2122 | * means that the only the IPv4 addresses are used. [::] means that only | |||||
2123 | * the IPv6 addresses are used. If a domain name or a specific IP address | |||||
2124 | * is given as "host" part, an additional "maddr" parameter can be used to | |||||
2125 | * control which addresses are used by the stack when binding listen | |||||
2126 | * sockets for incoming requests. | |||||
2127 | * | |||||
2128 | * The "port" determines what port is used in contact, and to which port the | |||||
2129 | * stack binds in order to listen for incoming requests. Empty or missing | |||||
2130 | * port means that default port should be used (5060 for sip, 5061 for | |||||
2131 | * sips). An "*" in "port" part means any port, i.e., the stack binds to an | |||||
2132 | * ephemeral port. | |||||
2133 | * | |||||
2134 | * The "transport" parameter determines the transport protocol that is used | |||||
2135 | * and how they are preferred. If no protocol is specified, both UDP and TCP | |||||
2136 | * are used for SIP URL and TLS for SIPS URL. The preference can be | |||||
2137 | * indicated with a comma-separated list of transports, for instance, | |||||
2138 | * parameter @code transport=tcp,udp @endcode indicates that TCP is | |||||
2139 | * preferred to UDP. | |||||
2140 | * | |||||
2141 | * The "maddr" parameter determines to which address the stack binds in | |||||
2142 | * order to listen for incoming requests. An "*" in "maddr" parameter is | |||||
2143 | * shorthand for any local IP address. 0.0.0.0 means that only IPv4 sockets | |||||
2144 | * are created. [::] means that only IPv6 sockets are created. | |||||
2145 | * | |||||
2146 | * The "comp" parameter determines the supported compression protocol. | |||||
2147 | * Currently only sigcomp is supported (with suitable library). | |||||
2148 | * | |||||
2149 | * @par Examples: | |||||
2150 | * @code sip:172.21.40.24;maddr=* @endcode \n | |||||
2151 | * @code sip:172.21.40.24:50600;transport=TCP,UDP;comp=sigcomp @endcode \n | |||||
2152 | * @code sips:* @endcode | |||||
2153 | * | |||||
2154 | * @return | |||||
2155 | * On success, zero is returned. On error, -1 is returned, and @a errno is | |||||
2156 | * set appropriately. | |||||
2157 | */ | |||||
2158 | int nta_agent_add_tport(nta_agent_t *self, | |||||
2159 | url_string_t const *uri, | |||||
2160 | tag_type_t tag, tag_value_t value, ...) | |||||
2161 | { | |||||
2162 | url_t *url; | |||||
2163 | char tp[32]; | |||||
2164 | char maddr[256]; | |||||
2165 | char comp[32]; | |||||
2166 | tp_name_t tpn[1] = {{ NULL((void*)0) }}; | |||||
2167 | char const * const * tports = tports_sip; | |||||
2168 | int error; | |||||
2169 | ta_list ta; | |||||
2170 | char *tps[9] = {0}; | |||||
2171 | ||||||
2172 | if (self == NULL((void*)0)) { | |||||
2173 | su_seterrno(EINVAL22); | |||||
2174 | return -1; | |||||
2175 | } | |||||
2176 | ||||||
2177 | if (uri == NULL((void*)0)) | |||||
2178 | uri = (url_string_t *)"sip:*"; | |||||
2179 | else if (url_string_p(uri) ? | |||||
2180 | strcmp(uri->us_str, "*") == 0 : | |||||
2181 | uri->us_url->url_type == url_any) { | |||||
2182 | uri = (url_string_t *)"sip:*:*"; | |||||
2183 | } | |||||
2184 | ||||||
2185 | if (!(url = url_hdup(self->sa_home, uri->us_url)) || | |||||
2186 | (url->url_type != url_sip && url->url_type != url_sips && url->url_type != url_urn)) { | |||||
2187 | if (url_string_p(uri)) | |||||
2188 | SU_DEBUG_1(("nta: %s: invalid bind URL\n", uri->us_str))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 2188, "nta: %s: invalid bind URL\n", uri->us_str)) : (void )0); | |||||
2189 | else | |||||
2190 | SU_DEBUG_1(("nta: invalid bind URL\n" VA_NONE))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 2190, "nta: invalid bind URL\n" "%s", "")) : (void)0); | |||||
2191 | su_seterrno(EINVAL22); | |||||
2192 | return -1; | |||||
2193 | } | |||||
2194 | ||||||
2195 | tpn->tpn_canon = url->url_host; | |||||
2196 | tpn->tpn_host = url->url_host; | |||||
2197 | tpn->tpn_port = url_port(url); | |||||
2198 | ||||||
2199 | if (url->url_type == url_sip || url->url_type == url_urn) { | |||||
2200 | tpn->tpn_proto = "*"; | |||||
2201 | tports = tports_sip; | |||||
2202 | if (!tpn->tpn_port || !tpn->tpn_port[0]) | |||||
2203 | tpn->tpn_port = SIP_DEFAULT_SERV"5060"; | |||||
2204 | } | |||||
2205 | else { | |||||
2206 | assert(url->url_type == url_sips)((void) sizeof ((url->url_type == url_sips) ? 1 : 0), __extension__ ({ if (url->url_type == url_sips) ; else __assert_fail ("url->url_type == url_sips" , "nta.c", 2206, __extension__ __PRETTY_FUNCTION__); })); | |||||
2207 | tpn->tpn_proto = "*"; | |||||
2208 | tports = tports_sips; | |||||
2209 | if (!tpn->tpn_port || !tpn->tpn_port[0]) | |||||
2210 | tpn->tpn_port = SIPS_DEFAULT_SERV"5061"; | |||||
2211 | } | |||||
2212 | ||||||
2213 | if (url->url_params) { | |||||
2214 | if (url_param(url->url_params, "transport", tp, sizeof(tp)) > 0) { | |||||
2215 | if (strchr(tp, ',')) { | |||||
2216 | int i; char *t; | |||||
2217 | ||||||
2218 | /* Split tp into transports */ | |||||
2219 | for (i = 0, t = tp; t && i < 8; i++) { | |||||
2220 | tps[i] = t; | |||||
2221 | if ((t = strchr(t, ','))) | |||||
2222 | *t++ = '\0'; | |||||
2223 | } | |||||
2224 | ||||||
2225 | tps[i] = NULL((void*)0); | |||||
2226 | tports = (char const * const *)tps; | |||||
2227 | } else { | |||||
2228 | tpn->tpn_proto = tp; | |||||
2229 | } | |||||
2230 | } | |||||
2231 | if (url_param(url->url_params, "maddr", maddr, sizeof(maddr)) > 0) | |||||
2232 | tpn->tpn_host = maddr; | |||||
2233 | if (url_param(url->url_params, "comp", comp, sizeof(comp)) > 0) | |||||
2234 | tpn->tpn_comp = comp; | |||||
2235 | ||||||
2236 | if (tpn->tpn_comp && | |||||
2237 | (nta_compressor_vtable == NULL((void*)0) || | |||||
2238 | !su_casematch(tpn->tpn_comp, nta_compressor_vtable->ncv_name))) { | |||||
2239 | SU_DEBUG_1(("nta(%p): comp=%s not supported for " URL_PRINT_FORMAT "\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 2240, "nta(%p): comp=%s not supported for " "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" "\n", (void *)self, tpn->tpn_comp, (url)->url_scheme ? (url)->url_scheme : "", (url)->url_type != url_any && (url)->url_scheme && (url)->url_scheme[0] ? ":" : "", (url)->url_root && ((url)->url_host || ( url)->url_user) ? "//" : "", (url)->url_user ? (url)-> url_user : "", (url)->url_user && (url)->url_password ? ":" : "", (url)->url_user && (url)->url_password ? (url)->url_password : "", (url)->url_user && (url)->url_host ? "@" : "", (url)->url_host ? (url)-> url_host : "", (url)->url_host && (url)->url_port ? ":" : "", (url)->url_host && (url)->url_port ? (url)->url_port : "", (url)->url_root && (url )->url_path ? "/" : "", (url)->url_path ? (url)->url_path : "", (url)->url_params ? ";" : "", (url)->url_params ? (url)->url_params : "", (url)->url_headers ? "?" : "", (url)->url_headers ? (url)->url_headers : "", (url)-> url_fragment ? "#" : "", (url)->url_fragment ? (url)->url_fragment : "")) : (void)0) | |||||
2240 | (void *)self, tpn->tpn_comp, URL_PRINT_ARGS(url)))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 2240, "nta(%p): comp=%s not supported for " "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" "\n", (void *)self, tpn->tpn_comp, (url)->url_scheme ? (url)->url_scheme : "", (url)->url_type != url_any && (url)->url_scheme && (url)->url_scheme[0] ? ":" : "", (url)->url_root && ((url)->url_host || ( url)->url_user) ? "//" : "", (url)->url_user ? (url)-> url_user : "", (url)->url_user && (url)->url_password ? ":" : "", (url)->url_user && (url)->url_password ? (url)->url_password : "", (url)->url_user && (url)->url_host ? "@" : "", (url)->url_host ? (url)-> url_host : "", (url)->url_host && (url)->url_port ? ":" : "", (url)->url_host && (url)->url_port ? (url)->url_port : "", (url)->url_root && (url )->url_path ? "/" : "", (url)->url_path ? (url)->url_path : "", (url)->url_params ? ";" : "", (url)->url_params ? (url)->url_params : "", (url)->url_headers ? "?" : "", (url)->url_headers ? (url)->url_headers : "", (url)-> url_fragment ? "#" : "", (url)->url_fragment ? (url)->url_fragment : "")) : (void)0); | |||||
2241 | } | |||||
2242 | } | |||||
2243 | ||||||
2244 | ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value = (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag ) == tag_next && (ta_start__value) != 0) { ta_start__tag = ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag == tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag == tag_next) { ta_start__value = ((tagi_t *)ta_start__value) ->t_value; } else { ta_start__tag = tag_next; break; } } ( ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value ; if (ta_start__tag != ((void*)0) && ta_start__tag != tag_null && ta_start__tag != tag_next) { va_list ta_start__ap ; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag = tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap ); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value = 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0); | |||||
2245 | ||||||
2246 | if (self->sa_tports == NULL((void*)0)) { | |||||
2247 | if (agent_create_master_transport(self, ta_args(ta)(ta).tl) < 0) { | |||||
2248 | error = su_errno(); | |||||
2249 | SU_DEBUG_1(("nta: cannot create master transport: %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 2250, "nta: cannot create master transport: %s\n", su_strerror (error))) : (void)0) | |||||
2250 | su_strerror(error)))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 2250, "nta: cannot create master transport: %s\n", su_strerror (error))) : (void)0); | |||||
2251 | goto error; | |||||
2252 | } | |||||
2253 | } | |||||
2254 | ||||||
2255 | if (tport_tbind(self->sa_tports, tpn, tports, ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta). tl[1].t_value) < 0) { | |||||
2256 | error = su_errno(); | |||||
2257 | SU_DEBUG_1(("nta: bind(%s:%s;transport=%s%s%s%s%s): %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 2263, "nta: bind(%s:%s;transport=%s%s%s%s%s): %s\n", tpn-> tpn_canon, tpn->tpn_port, tpn->tpn_proto, tpn->tpn_canon != tpn->tpn_host ? ";maddr=" : "", tpn->tpn_canon != tpn ->tpn_host ? tpn->tpn_host : "", tpn->tpn_comp ? ";comp=" : "", tpn->tpn_comp ? tpn->tpn_comp : "", su_strerror( error))) : (void)0) | |||||
2258 | tpn->tpn_canon, tpn->tpn_port, tpn->tpn_proto,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 2263, "nta: bind(%s:%s;transport=%s%s%s%s%s): %s\n", tpn-> tpn_canon, tpn->tpn_port, tpn->tpn_proto, tpn->tpn_canon != tpn->tpn_host ? ";maddr=" : "", tpn->tpn_canon != tpn ->tpn_host ? tpn->tpn_host : "", tpn->tpn_comp ? ";comp=" : "", tpn->tpn_comp ? tpn->tpn_comp : "", su_strerror( error))) : (void)0) | |||||
2259 | tpn->tpn_canon != tpn->tpn_host ? ";maddr=" : "",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 2263, "nta: bind(%s:%s;transport=%s%s%s%s%s): %s\n", tpn-> tpn_canon, tpn->tpn_port, tpn->tpn_proto, tpn->tpn_canon != tpn->tpn_host ? ";maddr=" : "", tpn->tpn_canon != tpn ->tpn_host ? tpn->tpn_host : "", tpn->tpn_comp ? ";comp=" : "", tpn->tpn_comp ? tpn->tpn_comp : "", su_strerror( error))) : (void)0) | |||||
2260 | tpn->tpn_canon != tpn->tpn_host ? tpn->tpn_host : "",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 2263, "nta: bind(%s:%s;transport=%s%s%s%s%s): %s\n", tpn-> tpn_canon, tpn->tpn_port, tpn->tpn_proto, tpn->tpn_canon != tpn->tpn_host ? ";maddr=" : "", tpn->tpn_canon != tpn ->tpn_host ? tpn->tpn_host : "", tpn->tpn_comp ? ";comp=" : "", tpn->tpn_comp ? tpn->tpn_comp : "", su_strerror( error))) : (void)0) | |||||
2261 | tpn->tpn_comp ? ";comp=" : "",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 2263, "nta: bind(%s:%s;transport=%s%s%s%s%s): %s\n", tpn-> tpn_canon, tpn->tpn_port, tpn->tpn_proto, tpn->tpn_canon != tpn->tpn_host ? ";maddr=" : "", tpn->tpn_canon != tpn ->tpn_host ? tpn->tpn_host : "", tpn->tpn_comp ? ";comp=" : "", tpn->tpn_comp ? tpn->tpn_comp : "", su_strerror( error))) : (void)0) | |||||
2262 | tpn->tpn_comp ? tpn->tpn_comp : "",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 2263, "nta: bind(%s:%s;transport=%s%s%s%s%s): %s\n", tpn-> tpn_canon, tpn->tpn_port, tpn->tpn_proto, tpn->tpn_canon != tpn->tpn_host ? ";maddr=" : "", tpn->tpn_canon != tpn ->tpn_host ? tpn->tpn_host : "", tpn->tpn_comp ? ";comp=" : "", tpn->tpn_comp ? tpn->tpn_comp : "", su_strerror( error))) : (void)0) | |||||
2263 | su_strerror(error)))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 2263, "nta: bind(%s:%s;transport=%s%s%s%s%s): %s\n", tpn-> tpn_canon, tpn->tpn_port, tpn->tpn_proto, tpn->tpn_canon != tpn->tpn_host ? ";maddr=" : "", tpn->tpn_canon != tpn ->tpn_host ? tpn->tpn_host : "", tpn->tpn_comp ? ";comp=" : "", tpn->tpn_comp ? tpn->tpn_comp : "", su_strerror( error))) : (void)0); | |||||
2264 | goto error; | |||||
2265 | } | |||||
2266 | else | |||||
2267 | SU_DEBUG_5(("nta: bound to (%s:%s;transport=%s%s%s%s%s)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 2272, "nta: bound to (%s:%s;transport=%s%s%s%s%s)\n", tpn-> tpn_canon, tpn->tpn_port, tpn->tpn_proto, tpn->tpn_canon != tpn->tpn_host ? ";maddr=" : "", tpn->tpn_canon != tpn ->tpn_host ? tpn->tpn_host : "", tpn->tpn_comp ? ";comp=" : "", tpn->tpn_comp ? tpn->tpn_comp : "")) : (void)0) | |||||
2268 | tpn->tpn_canon, tpn->tpn_port, tpn->tpn_proto,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 2272, "nta: bound to (%s:%s;transport=%s%s%s%s%s)\n", tpn-> tpn_canon, tpn->tpn_port, tpn->tpn_proto, tpn->tpn_canon != tpn->tpn_host ? ";maddr=" : "", tpn->tpn_canon != tpn ->tpn_host ? tpn->tpn_host : "", tpn->tpn_comp ? ";comp=" : "", tpn->tpn_comp ? tpn->tpn_comp : "")) : (void)0) | |||||
2269 | tpn->tpn_canon != tpn->tpn_host ? ";maddr=" : "",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 2272, "nta: bound to (%s:%s;transport=%s%s%s%s%s)\n", tpn-> tpn_canon, tpn->tpn_port, tpn->tpn_proto, tpn->tpn_canon != tpn->tpn_host ? ";maddr=" : "", tpn->tpn_canon != tpn ->tpn_host ? tpn->tpn_host : "", tpn->tpn_comp ? ";comp=" : "", tpn->tpn_comp ? tpn->tpn_comp : "")) : (void)0) | |||||
2270 | tpn->tpn_canon != tpn->tpn_host ? tpn->tpn_host : "",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 2272, "nta: bound to (%s:%s;transport=%s%s%s%s%s)\n", tpn-> tpn_canon, tpn->tpn_port, tpn->tpn_proto, tpn->tpn_canon != tpn->tpn_host ? ";maddr=" : "", tpn->tpn_canon != tpn ->tpn_host ? tpn->tpn_host : "", tpn->tpn_comp ? ";comp=" : "", tpn->tpn_comp ? tpn->tpn_comp : "")) : (void)0) | |||||
2271 | tpn->tpn_comp ? ";comp=" : "",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 2272, "nta: bound to (%s:%s;transport=%s%s%s%s%s)\n", tpn-> tpn_canon, tpn->tpn_port, tpn->tpn_proto, tpn->tpn_canon != tpn->tpn_host ? ";maddr=" : "", tpn->tpn_canon != tpn ->tpn_host ? tpn->tpn_host : "", tpn->tpn_comp ? ";comp=" : "", tpn->tpn_comp ? tpn->tpn_comp : "")) : (void)0) | |||||
2272 | tpn->tpn_comp ? tpn->tpn_comp : ""))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 2272, "nta: bound to (%s:%s;transport=%s%s%s%s%s)\n", tpn-> tpn_canon, tpn->tpn_port, tpn->tpn_proto, tpn->tpn_canon != tpn->tpn_host ? ";maddr=" : "", tpn->tpn_canon != tpn ->tpn_host ? tpn->tpn_host : "", tpn->tpn_comp ? ";comp=" : "", tpn->tpn_comp ? tpn->tpn_comp : "")) : (void)0); | |||||
2273 | ||||||
2274 | /* XXX - when to use maddr? */ | |||||
2275 | if ((agent_init_via(self, tport_primaries(self->sa_tports), 0)) < 0) { | |||||
2276 | error = su_errno(); | |||||
2277 | SU_DEBUG_1(("nta: cannot create Via headers\n" VA_NONE))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 2277, "nta: cannot create Via headers\n" "%s", "")) : (void )0); | |||||
2278 | goto error; | |||||
2279 | } | |||||
2280 | else | |||||
2281 | SU_DEBUG_9(("nta: Via fields initialized\n" VA_NONE))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 2281, "nta: Via fields initialized\n" "%s", "")) : (void)0); | |||||
2282 | ||||||
2283 | if ((agent_init_contact(self)) < 0) { | |||||
2284 | error = su_errno(); | |||||
2285 | SU_DEBUG_1(("nta: cannot create Contact header\n" VA_NONE))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 2285, "nta: cannot create Contact header\n" "%s", "")) : (void )0); | |||||
2286 | goto error; | |||||
2287 | } | |||||
2288 | else | |||||
2289 | SU_DEBUG_9(("nta: Contact header created\n" VA_NONE))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 2289, "nta: Contact header created\n" "%s", "")) : (void)0); | |||||
2290 | ||||||
2291 | su_free(self->sa_home, url); | |||||
2292 | ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value ))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta) .ap)); | |||||
2293 | ||||||
2294 | return 0; | |||||
2295 | ||||||
2296 | error: | |||||
2297 | ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value ))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta) .ap)); | |||||
2298 | su_seterrno(error); | |||||
2299 | return -1; | |||||
2300 | } | |||||
2301 | ||||||
2302 | static | |||||
2303 | int agent_create_master_transport(nta_agent_t *self, tagi_t *tags) | |||||
2304 | { | |||||
2305 | self->sa_tports = | |||||
2306 | tport_tcreate(self, nta_agent_class, self->sa_root, | |||||
2307 | TPTAG_IDLE(1800000)tptag_idle, tag_uint_v((1800000)), | |||||
2308 | TAG_NEXT(tags)tag_next, (tag_value_t)(tags)); | |||||
2309 | ||||||
2310 | if (!self->sa_tports) | |||||
2311 | return -1; | |||||
2312 | ||||||
2313 | SU_DEBUG_9(("nta: master transport created\n" VA_NONE))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 2313, "nta: master transport created\n" "%s", "")) : (void) 0); | |||||
2314 | ||||||
2315 | return 0; | |||||
2316 | } | |||||
2317 | ||||||
2318 | ||||||
2319 | /** Initialize @Via headers. */ | |||||
2320 | static | |||||
2321 | int agent_init_via(nta_agent_t *self, tport_t *primaries, int use_maddr) | |||||
2322 | { | |||||
2323 | sip_via_t *via = NULL((void*)0), *new_via, *dup_via, *v, **vv = &via; | |||||
2324 | sip_via_t *new_vias, **next_new_via, *new_publics, **next_new_public; | |||||
2325 | tport_t *tp; | |||||
2326 | su_addrinfo_t const *ai; | |||||
2327 | ||||||
2328 | su_home_t autohome[SU_HOME_AUTO_SIZE(2048)(((2048) + ((sizeof(su_home_t) + 7) & (size_t)~8) + ((3 * sizeof (void *) + 4 * sizeof(unsigned) + 7 * (sizeof (long) + sizeof(void *)) + 7) & (size_t)~8)) / sizeof(su_home_t))]; | |||||
2329 | ||||||
2330 | su_home_auto(autohome, sizeof autohome); | |||||
2331 | ||||||
2332 | self->sa_tport_ip4 = 0; | |||||
2333 | self->sa_tport_ip6 = 0; | |||||
2334 | self->sa_tport_udp = 0; | |||||
2335 | self->sa_tport_tcp = 0; | |||||
2336 | self->sa_tport_sctp = 0; | |||||
2337 | self->sa_tport_tls = 0; | |||||
2338 | self->sa_tport_ws = 0; | |||||
2339 | self->sa_tport_wss = 0; | |||||
2340 | ||||||
2341 | /* Set via fields for the tports */ | |||||
2342 | for (tp = primaries; tp; tp = tport_next(tp)) { | |||||
| ||||||
2343 | int maddr; | |||||
2344 | tp_name_t tpn[1]; | |||||
2345 | char const *comp = NULL((void*)0); | |||||
2346 | ||||||
2347 | *tpn = *tport_name(tp); | |||||
2348 | ||||||
2349 | assert(tpn->tpn_proto)((void) sizeof ((tpn->tpn_proto) ? 1 : 0), __extension__ ( { if (tpn->tpn_proto) ; else __assert_fail ("tpn->tpn_proto" , "nta.c", 2349, __extension__ __PRETTY_FUNCTION__); })); | |||||
2350 | assert(tpn->tpn_canon)((void) sizeof ((tpn->tpn_canon) ? 1 : 0), __extension__ ( { if (tpn->tpn_canon) ; else __assert_fail ("tpn->tpn_canon" , "nta.c", 2350, __extension__ __PRETTY_FUNCTION__); })); | |||||
2351 | assert(tpn->tpn_host)((void) sizeof ((tpn->tpn_host) ? 1 : 0), __extension__ ({ if (tpn->tpn_host) ; else __assert_fail ("tpn->tpn_host" , "nta.c", 2351, __extension__ __PRETTY_FUNCTION__); })); | |||||
2352 | assert(tpn->tpn_port)((void) sizeof ((tpn->tpn_port) ? 1 : 0), __extension__ ({ if (tpn->tpn_port) ; else __assert_fail ("tpn->tpn_port" , "nta.c", 2352, __extension__ __PRETTY_FUNCTION__); })); | |||||
2353 | ||||||
2354 | #if 0 | |||||
2355 | if (getenv("SIP_UDP_CONNECT") | |||||
2356 | && strcmp(tpn->tpn_proto, "udp") == 0) | |||||
2357 | tport_set_params(tp, TPTAG_CONNECT(1)tptag_connect, tag_bool_v((1)), TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
2358 | #endif | |||||
2359 | ||||||
2360 | if (tport_has_ip4(tp)) self->sa_tport_ip4 = 1; | |||||
2361 | ||||||
2362 | #if SU_HAVE_IN61 | |||||
2363 | if (tport_has_ip6(tp)) self->sa_tport_ip6 = 1; | |||||
2364 | #endif | |||||
2365 | ||||||
2366 | if (su_casematch(tpn->tpn_proto, "udp")) | |||||
2367 | self->sa_tport_udp = 1; | |||||
2368 | else if (su_casematch(tpn->tpn_proto, "tcp")) | |||||
2369 | self->sa_tport_tcp = 1; | |||||
2370 | else if (su_casematch(tpn->tpn_proto, "sctp")) | |||||
2371 | self->sa_tport_sctp = 1; | |||||
2372 | else if (su_casematch(tpn->tpn_proto, "ws")) | |||||
2373 | self->sa_tport_ws = 1; | |||||
2374 | else if (su_casematch(tpn->tpn_proto, "wss")) | |||||
2375 | self->sa_tport_wss = 1; | |||||
2376 | ||||||
2377 | if (tport_has_tls(tp)) self->sa_tport_tls = 1; | |||||
2378 | ||||||
2379 | ai = tport_get_address(tp); | |||||
2380 | ||||||
2381 | for (; ai; ai = ai->ai_next) { | |||||
2382 | char host[TPORT_HOSTPORTSIZE(55)] = ""; | |||||
2383 | char sport[8]; | |||||
2384 | char const *canon = ai->ai_canonname; | |||||
2385 | su_sockaddr_t *su = (void *)ai->ai_addr; | |||||
2386 | int port; | |||||
2387 | ||||||
2388 | if (su) { | |||||
2389 | su_inet_ntopinet_ntop(su->su_familysu_sa.sa_family, SU_ADDR(su)((su)->su_sa.sa_family == 2 ? (void *)&(su)->su_sin .sin_addr : ((su)->su_sa.sa_family == 10 ? (void *)&(su )->su_sin6.sin6_addr : (void *)&(su)->su_sa.sa_data )), host, sizeof host); | |||||
2390 | maddr = use_maddr && !su_casematch(canon, host); | |||||
2391 | port = ntohs(su->su_portsu_sin.sin_port); | |||||
2392 | } | |||||
2393 | else { | |||||
2394 | msg_random_token(host, 16, NULL((void*)0), 0); | |||||
2395 | canon = strcat(host, ".is.invalid"); | |||||
2396 | maddr = 0; | |||||
2397 | port = 0; | |||||
2398 | } | |||||
2399 | ||||||
2400 | if (su_casenmatch(tpn->tpn_proto, "tls", 3) | |||||
2401 | ? port == SIPS_DEFAULT_PORTSIPS_DEFAULT_PORT | |||||
2402 | : port == SIP_DEFAULT_PORTSIP_DEFAULT_PORT) | |||||
2403 | port = 0; | |||||
2404 | ||||||
2405 | snprintf(sport, sizeof sport, ":%u", port); | |||||
2406 | ||||||
2407 | comp = tpn->tpn_comp; | |||||
2408 | ||||||
2409 | SU_DEBUG_9(("nta: agent_init_via: "(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 2415, "nta: agent_init_via: " "%s/%s %s%s%s%s%s%s (%s)\n", sip_version_2_0 , tpn->tpn_proto, canon, port ? sport : "", maddr ? ";maddr=" : "", maddr ? host : "", comp ? ";comp=" : "", comp ? comp : "", tpn->tpn_ident ? tpn->tpn_ident : "*")) : (void)0) | |||||
2410 | "%s/%s %s%s%s%s%s%s (%s)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 2415, "nta: agent_init_via: " "%s/%s %s%s%s%s%s%s (%s)\n", sip_version_2_0 , tpn->tpn_proto, canon, port ? sport : "", maddr ? ";maddr=" : "", maddr ? host : "", comp ? ";comp=" : "", comp ? comp : "", tpn->tpn_ident ? tpn->tpn_ident : "*")) : (void)0) | |||||
2411 | SIP_VERSION_CURRENT, tpn->tpn_proto,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 2415, "nta: agent_init_via: " "%s/%s %s%s%s%s%s%s (%s)\n", sip_version_2_0 , tpn->tpn_proto, canon, port ? sport : "", maddr ? ";maddr=" : "", maddr ? host : "", comp ? ";comp=" : "", comp ? comp : "", tpn->tpn_ident ? tpn->tpn_ident : "*")) : (void)0) | |||||
2412 | canon, port ? sport : "",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 2415, "nta: agent_init_via: " "%s/%s %s%s%s%s%s%s (%s)\n", sip_version_2_0 , tpn->tpn_proto, canon, port ? sport : "", maddr ? ";maddr=" : "", maddr ? host : "", comp ? ";comp=" : "", comp ? comp : "", tpn->tpn_ident ? tpn->tpn_ident : "*")) : (void)0) | |||||
2413 | maddr ? ";maddr=" : "", maddr ? host : "",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 2415, "nta: agent_init_via: " "%s/%s %s%s%s%s%s%s (%s)\n", sip_version_2_0 , tpn->tpn_proto, canon, port ? sport : "", maddr ? ";maddr=" : "", maddr ? host : "", comp ? ";comp=" : "", comp ? comp : "", tpn->tpn_ident ? tpn->tpn_ident : "*")) : (void)0) | |||||
2414 | comp ? ";comp=" : "", comp ? comp : "",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 2415, "nta: agent_init_via: " "%s/%s %s%s%s%s%s%s (%s)\n", sip_version_2_0 , tpn->tpn_proto, canon, port ? sport : "", maddr ? ";maddr=" : "", maddr ? host : "", comp ? ";comp=" : "", comp ? comp : "", tpn->tpn_ident ? tpn->tpn_ident : "*")) : (void)0) | |||||
2415 | tpn->tpn_ident ? tpn->tpn_ident : "*"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 2415, "nta: agent_init_via: " "%s/%s %s%s%s%s%s%s (%s)\n", sip_version_2_0 , tpn->tpn_proto, canon, port ? sport : "", maddr ? ";maddr=" : "", maddr ? host : "", comp ? ";comp=" : "", comp ? comp : "", tpn->tpn_ident ? tpn->tpn_ident : "*")) : (void)0); | |||||
2416 | ||||||
2417 | v = sip_via_format(autohome, | |||||
2418 | "%s/%s %s%s%s%s%s%s", | |||||
2419 | SIP_VERSION_CURRENTsip_version_2_0, tpn->tpn_proto, | |||||
2420 | canon, port ? sport : "", | |||||
2421 | maddr ? ";maddr=" : "", maddr ? host : "", | |||||
2422 | comp ? ";comp=" : "", comp ? comp : ""); | |||||
2423 | if (v == NULL((void*)0)) | |||||
2424 | goto error; | |||||
2425 | ||||||
2426 | v->v_comment = tpn->tpn_ident; | |||||
2427 | v->v_common->h_data = tp; /* Nasty trick */ | |||||
2428 | *vv = v; vv = &(*vv)->v_next; | |||||
2429 | } | |||||
2430 | } | |||||
2431 | ||||||
2432 | if (!via) { | |||||
2433 | SU_DEBUG_9(("nta: agent_init_via failed\n" VA_NONE))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 2433, "nta: agent_init_via failed\n" "%s", "")) : (void)0); | |||||
2434 | goto error; | |||||
2435 | } | |||||
2436 | ||||||
2437 | /* Duplicate the list bind to the transports */ | |||||
2438 | new_via = sip_via_dup(self->sa_home, via); | |||||
2439 | /* Duplicate the complete list shown to the application */ | |||||
2440 | dup_via = sip_via_dup(self->sa_home, via); | |||||
2441 | ||||||
2442 | if (via && (!new_via || !dup_via)) { | |||||
2443 | msg_header_free(self->sa_home, (void *)new_via); | |||||
2444 | msg_header_free(self->sa_home, (void *)dup_via); | |||||
2445 | goto error; | |||||
2446 | } | |||||
2447 | ||||||
2448 | new_vias = NULL((void*)0), next_new_via = &new_vias; | |||||
2449 | new_publics = NULL((void*)0), next_new_public = &new_publics; | |||||
2450 | ||||||
2451 | /* Set via field magic for the tports */ | |||||
2452 | for (tp = primaries; tp; tp = tport_next(tp)) { | |||||
2453 | assert(via->v_common->h_data == tp)((void) sizeof ((via->v_common->h_data == tp) ? 1 : 0), __extension__ ({ if (via->v_common->h_data == tp) ; else __assert_fail ("via->v_common->h_data == tp", "nta.c", 2453, __extension__ __PRETTY_FUNCTION__); })); | |||||
| ||||||
2454 | v = tport_magic(tp); | |||||
2455 | tport_set_magic(tp, new_via); | |||||
2456 | msg_header_free(self->sa_home, (void *)v); | |||||
2457 | ||||||
2458 | if (tport_is_public(tp)) | |||||
2459 | *next_new_public = dup_via; | |||||
2460 | else | |||||
2461 | *next_new_via = dup_via; | |||||
2462 | ||||||
2463 | while (via->v_next && via->v_next->v_common->h_data == tp) | |||||
2464 | via = via->v_next, new_via = new_via->v_next, dup_via = dup_via->v_next; | |||||
2465 | ||||||
2466 | via = via->v_next; | |||||
2467 | /* Break the link in via list between transports */ | |||||
2468 | vv = &new_via->v_next, new_via = *vv, *vv = NULL((void*)0); | |||||
2469 | vv = &dup_via->v_next, dup_via = *vv, *vv = NULL((void*)0); | |||||
2470 | ||||||
2471 | if (tport_is_public(tp)) | |||||
2472 | while (*next_new_public) next_new_public = &(*next_new_public)->v_next; | |||||
2473 | else | |||||
2474 | while (*next_new_via) next_new_via = &(*next_new_via)->v_next; | |||||
2475 | } | |||||
2476 | ||||||
2477 | assert(dup_via == NULL)((void) sizeof ((dup_via == ((void*)0)) ? 1 : 0), __extension__ ({ if (dup_via == ((void*)0)) ; else __assert_fail ("dup_via == NULL" , "nta.c", 2477, __extension__ __PRETTY_FUNCTION__); })); | |||||
2478 | assert(new_via == NULL)((void) sizeof ((new_via == ((void*)0)) ? 1 : 0), __extension__ ({ if (new_via == ((void*)0)) ; else __assert_fail ("new_via == NULL" , "nta.c", 2478, __extension__ __PRETTY_FUNCTION__); })); | |||||
2479 | ||||||
2480 | if (self->sa_tport_udp) | |||||
2481 | agent_set_udp_params(self, self->sa_udp_mtu); | |||||
2482 | ||||||
2483 | v = self->sa_vias; | |||||
2484 | self->sa_vias = new_vias; | |||||
2485 | msg_header_free(self->sa_home, (void *)v); | |||||
2486 | ||||||
2487 | v = self->sa_public_vias; | |||||
2488 | self->sa_public_vias = new_publics; | |||||
2489 | msg_header_free(self->sa_home, (void *)v); | |||||
2490 | ||||||
2491 | su_home_deinit(autohome); | |||||
2492 | ||||||
2493 | return 0; | |||||
2494 | ||||||
2495 | error: | |||||
2496 | su_home_deinit(autohome); | |||||
2497 | return -1; | |||||
2498 | } | |||||
2499 | ||||||
2500 | ||||||
2501 | /** Initialize main contact header. */ | |||||
2502 | static | |||||
2503 | int agent_init_contact(nta_agent_t *self) | |||||
2504 | { | |||||
2505 | sip_via_t const *v1, *v2; | |||||
2506 | char const *tp; | |||||
2507 | ||||||
2508 | if (self->sa_contact) | |||||
2509 | return 0; | |||||
2510 | ||||||
2511 | for (v1 = self->sa_vias ? self->sa_vias : self->sa_public_vias; | |||||
2512 | v1; | |||||
2513 | v1 = v1->v_next) { | |||||
2514 | if (host_is_ip_address(v1->v_host)) { | |||||
2515 | if (!host_is_local(v1->v_host)) | |||||
2516 | break; | |||||
2517 | } | |||||
2518 | else if (!host_has_domain_invalid(v1->v_host)) { | |||||
2519 | break; | |||||
2520 | } | |||||
2521 | } | |||||
2522 | ||||||
2523 | if (v1 == NULL((void*)0)) | |||||
2524 | v1 = self->sa_vias ? self->sa_vias : self->sa_public_vias; | |||||
2525 | ||||||
2526 | if (!v1) | |||||
2527 | return -1; | |||||
2528 | ||||||
2529 | tp = strrchr(v1->v_protocol, '/'); | |||||
2530 | if (!tp++) | |||||
2531 | return -1; | |||||
2532 | ||||||
2533 | v2 = v1->v_next; | |||||
2534 | ||||||
2535 | if (v2 && | |||||
2536 | su_casematch(v1->v_host, v2->v_host) && | |||||
2537 | su_casematch(v1->v_port, v2->v_port)) { | |||||
2538 | char const *p1 = v1->v_protocol, *p2 = v2->v_protocol; | |||||
2539 | ||||||
2540 | if (!su_casematch(p1, sip_transport_udp)) | |||||
2541 | p1 = v2->v_protocol, p2 = v1->v_protocol; | |||||
2542 | ||||||
2543 | if (su_casematch(p1, sip_transport_udp) && | |||||
2544 | su_casematch(p2, sip_transport_tcp)) | |||||
2545 | /* Do not include transport if we have both UDP and TCP */ | |||||
2546 | tp = NULL((void*)0); | |||||
2547 | } | |||||
2548 | ||||||
2549 | self->sa_contact = | |||||
2550 | sip_contact_create_from_via_with_transport(self->sa_home, v1, NULL((void*)0), tp); | |||||
2551 | ||||||
2552 | if (!self->sa_contact) | |||||
2553 | return -1; | |||||
2554 | ||||||
2555 | agent_tag_init(self); | |||||
2556 | ||||||
2557 | return 0; | |||||
2558 | } | |||||
2559 | ||||||
2560 | /** Return @Via line corresponging to tport. */ | |||||
2561 | static | |||||
2562 | sip_via_t const *agent_tport_via(tport_t *tport) | |||||
2563 | { | |||||
2564 | sip_via_t *v = tport_magic(tport); | |||||
2565 | while (v && v->v_next) | |||||
2566 | v = v->v_next; | |||||
2567 | return v; | |||||
2568 | } | |||||
2569 | ||||||
2570 | /** Insert @Via to a request message */ | |||||
2571 | static | |||||
2572 | int outgoing_insert_via(nta_outgoing_t *orq, | |||||
2573 | sip_via_t const *via) | |||||
2574 | { | |||||
2575 | nta_agent_t *self = orq->orq_agent; | |||||
2576 | msg_t *msg = orq->orq_request; | |||||
2577 | sip_t *sip = sip_object(msg); | |||||
2578 | char const *branch = orq->orq_via_branch; | |||||
2579 | int already = orq->orq_user_via || orq->orq_via_added; | |||||
2580 | int user_via = orq->orq_user_via; | |||||
2581 | sip_via_t *v; | |||||
2582 | int clear = 0; | |||||
2583 | ||||||
2584 | assert(sip)((void) sizeof ((sip) ? 1 : 0), __extension__ ({ if (sip) ; else __assert_fail ("sip", "nta.c", 2584, __extension__ __PRETTY_FUNCTION__ ); })); assert(via)((void) sizeof ((via) ? 1 : 0), __extension__ ({ if (via) ; else __assert_fail ("via", "nta.c", 2584, __extension__ __PRETTY_FUNCTION__ ); })); | |||||
2585 | ||||||
2586 | if (already && sip->sip_via) { | |||||
2587 | /* Use existing @Via */ | |||||
2588 | v = sip->sip_via; | |||||
2589 | } | |||||
2590 | else if (msg && via && sip->sip_request && | |||||
2591 | (v = sip_via_copy(msg_home(msg)((su_home_t*)(msg)), via))) { | |||||
2592 | if (msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)v) < 0) | |||||
2593 | return -1; | |||||
2594 | orq->orq_via_added = 1; | |||||
2595 | } | |||||
2596 | else | |||||
2597 | return -1; | |||||
2598 | ||||||
2599 | if (!v->v_rport && | |||||
2600 | ((self->sa_rport && v->v_protocol == sip_transport_udp) || | |||||
2601 | (self->sa_tcp_rport && v->v_protocol == sip_transport_tcp) || | |||||
2602 | (self->sa_tls_rport && v->v_protocol == sip_transport_tls))) | |||||
2603 | msg_header_add_param(msg_home(msg)((su_home_t*)(msg)), v->v_common, "rport"); | |||||
2604 | ||||||
2605 | if (!orq->orq_tpn->tpn_comp) | |||||
2606 | msg_header_remove_param(v->v_common, "comp"); | |||||
2607 | ||||||
2608 | if (branch && branch != v->v_branch) { | |||||
2609 | char const *bvalue = branch + strcspn(branch, "="); | |||||
2610 | if (*bvalue) bvalue++; | |||||
2611 | if (!v->v_branch || !su_casematch(bvalue, v->v_branch)) | |||||
2612 | msg_header_replace_param(msg_home(msg)((su_home_t*)(msg)), v->v_common, branch); | |||||
2613 | } | |||||
2614 | ||||||
2615 | if (!su_casematch(via->v_protocol, v->v_protocol)) | |||||
2616 | clear = 1, v->v_protocol = via->v_protocol; | |||||
2617 | ||||||
2618 | /* XXX - should we do this? */ | |||||
2619 | if ((!user_via || !v->v_host) && | |||||
2620 | !su_strmatch(via->v_host, v->v_host)) | |||||
2621 | clear = 1, v->v_host = via->v_host; | |||||
2622 | ||||||
2623 | if ((!user_via || !v->v_port || | |||||
2624 | /* Replace port in user Via only if we use udp and no rport */ | |||||
2625 | (v->v_protocol == sip_transport_udp && !v->v_rport && | |||||
2626 | !orq->orq_stateless)) && | |||||
2627 | !su_strmatch(via->v_port, v->v_port)) | |||||
2628 | clear = 1, v->v_port = via->v_port; | |||||
2629 | ||||||
2630 | if (clear) | |||||
2631 | msg_fragment_clear(v->v_common); | |||||
2632 | ||||||
2633 | return 0; | |||||
2634 | } | |||||
2635 | ||||||
2636 | /** Get destination name from @Via. | |||||
2637 | * | |||||
2638 | * If @a using_rport is non-null, try rport. | |||||
2639 | * If *using_rport is non-zero, try rport even if <protocol> is not UDP. | |||||
2640 | * If <protocol> is UDP, set *using_rport to zero. | |||||
2641 | */ | |||||
2642 | static | |||||
2643 | int nta_tpn_by_via(tp_name_t *tpn, sip_via_t const *v, int *using_rport) | |||||
2644 | { | |||||
2645 | if (!v) | |||||
2646 | return -1; | |||||
2647 | ||||||
2648 | tpn->tpn_proto = sip_via_transport(v); | |||||
2649 | tpn->tpn_canon = v->v_host; | |||||
2650 | ||||||
2651 | if (v->v_maddr) | |||||
2652 | tpn->tpn_host = v->v_maddr; | |||||
2653 | else if (v->v_received) | |||||
2654 | tpn->tpn_host = v->v_received; | |||||
2655 | else | |||||
2656 | tpn->tpn_host = v->v_host; | |||||
2657 | ||||||
2658 | tpn->tpn_port = sip_via_port(v, using_rport); | |||||
2659 | tpn->tpn_comp = v->v_comp; | |||||
2660 | tpn->tpn_ident = NULL((void*)0); | |||||
2661 | ||||||
2662 | return 0; | |||||
2663 | } | |||||
2664 | ||||||
2665 | /** Get transport name from URL. */ | |||||
2666 | static int | |||||
2667 | nta_tpn_by_url(su_home_t *home, | |||||
2668 | tp_name_t *tpn, | |||||
2669 | char const **scheme, | |||||
2670 | char const **port, | |||||
2671 | url_string_t const *us) | |||||
2672 | { | |||||
2673 | url_t url[1]; | |||||
2674 | isize_t n; | |||||
2675 | char *b; | |||||
2676 | ||||||
2677 | n = url_xtra(us->us_url); | |||||
2678 | b = su_alloc(home, n); | |||||
2679 | ||||||
2680 | if (b == NULL((void*)0) || url_dup(b, n, url, us->us_url) < 0) { | |||||
2681 | su_free(home, b); | |||||
2682 | return -1; | |||||
2683 | } | |||||
2684 | ||||||
2685 | if (url->url_type != url_sip && | |||||
2686 | url->url_type != url_urn && | |||||
2687 | url->url_type != url_sips && | |||||
2688 | url->url_type != url_im && | |||||
2689 | url->url_type != url_pres) { | |||||
2690 | su_free(home, b); | |||||
2691 | return -1; | |||||
2692 | } | |||||
2693 | ||||||
2694 | SU_DEBUG_7(("nta: selecting scheme %s\n", url->url_scheme))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__ , 2694, "nta: selecting scheme %s\n", url->url_scheme)) : ( void)0); | |||||
2695 | ||||||
2696 | *scheme = url->url_scheme; | |||||
2697 | ||||||
2698 | tpn->tpn_proto = NULL((void*)0); | |||||
2699 | tpn->tpn_canon = url->url_host; | |||||
2700 | tpn->tpn_host = url->url_host; | |||||
2701 | ||||||
2702 | if (url->url_params) { | |||||
2703 | for (b = (char *)url->url_params; b[0]; b += n) { | |||||
2704 | n = strcspn(b, ";"); | |||||
2705 | ||||||
2706 | if (n > 10 && su_casenmatch(b, "transport=", 10)) | |||||
2707 | tpn->tpn_proto = b + 10; | |||||
2708 | else if (n > 5 && su_casenmatch(b, "comp=", 5)) | |||||
2709 | tpn->tpn_comp = b + 5; | |||||
2710 | else if (n > 6 && su_casenmatch(b, "maddr=", 6)) | |||||
2711 | tpn->tpn_host = b + 6; | |||||
2712 | ||||||
2713 | if (b[n]) | |||||
2714 | b[n++] = '\0'; | |||||
2715 | } | |||||
2716 | } | |||||
2717 | ||||||
2718 | if ((*port = url->url_port)) | |||||
2719 | tpn->tpn_port = url->url_port; | |||||
2720 | ||||||
2721 | tpn->tpn_ident = NULL((void*)0); | |||||
2722 | ||||||
2723 | if (tpn->tpn_proto) { | |||||
2724 | if (su_casematch(url->url_scheme, "sips") && su_casematch(tpn->tpn_proto, "ws")) { | |||||
2725 | tpn->tpn_proto = "wss"; | |||||
2726 | } | |||||
2727 | return 1; | |||||
2728 | } | |||||
2729 | ||||||
2730 | if (su_casematch(url->url_scheme, "sips")) | |||||
2731 | tpn->tpn_proto = "tls"; | |||||
2732 | else | |||||
2733 | tpn->tpn_proto = "*"; | |||||
2734 | ||||||
2735 | return 0; | |||||
2736 | } | |||||
2737 | ||||||
2738 | /** Handle transport errors. */ | |||||
2739 | static | |||||
2740 | void agent_tp_error(nta_agent_t *agent, | |||||
2741 | tport_t *tport, | |||||
2742 | int errcode, | |||||
2743 | char const *remote) | |||||
2744 | { | |||||
2745 | su_llog(nta_log, 1,_su_llog(nta_log, 1, "nta.c", (const char *)__func__, 2748, "nta_agent: tport: %s%s%s\n" , remote ? remote : "", remote ? ": " : "", su_strerror(errcode )) | |||||
2746 | "nta_agent: tport: %s%s%s\n",_su_llog(nta_log, 1, "nta.c", (const char *)__func__, 2748, "nta_agent: tport: %s%s%s\n" , remote ? remote : "", remote ? ": " : "", su_strerror(errcode )) | |||||
2747 | remote ? remote : "", remote ? ": " : "",_su_llog(nta_log, 1, "nta.c", (const char *)__func__, 2748, "nta_agent: tport: %s%s%s\n" , remote ? remote : "", remote ? ": " : "", su_strerror(errcode )) | |||||
2748 | su_strerror(errcode))_su_llog(nta_log, 1, "nta.c", (const char *)__func__, 2748, "nta_agent: tport: %s%s%s\n" , remote ? remote : "", remote ? ": " : "", su_strerror(errcode )); | |||||
2749 | ||||||
2750 | if (agent->sa_error_tport) { | |||||
2751 | agent->sa_error_tport(agent->sa_error_magic, agent, tport); | |||||
2752 | } | |||||
2753 | } | |||||
2754 | ||||||
2755 | /** Handle updated transport addresses */ | |||||
2756 | static void agent_update_tport(nta_agent_t *self, tport_t *tport) | |||||
2757 | { | |||||
2758 | /* Initialize local Vias first */ | |||||
2759 | agent_init_via(self, tport_primaries(self->sa_tports), 0); | |||||
2760 | ||||||
2761 | if (self->sa_update_tport) { | |||||
2762 | self->sa_update_tport(self->sa_update_magic, self); | |||||
2763 | } | |||||
2764 | else { | |||||
2765 | /* XXX - we should do something else? */ | |||||
2766 | SU_DEBUG_3(("%s(%p): %s\n", "nta", (void *)self,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 2767, "%s(%p): %s\n", "nta", (void *)self, "transport address updated" )) : (void)0) | |||||
2767 | "transport address updated"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 2767, "%s(%p): %s\n", "nta", (void *)self, "transport address updated" )) : (void)0); | |||||
2768 | } | |||||
2769 | } | |||||
2770 | ||||||
2771 | /* ====================================================================== */ | |||||
2772 | /* 3) Message dispatch */ | |||||
2773 | ||||||
2774 | static void agent_recv_request(nta_agent_t *agent, | |||||
2775 | msg_t *msg, | |||||
2776 | sip_t *sip, | |||||
2777 | tport_t *tport); | |||||
2778 | static int agent_check_request_via(nta_agent_t *agent, | |||||
2779 | msg_t *msg, | |||||
2780 | sip_t *sip, | |||||
2781 | sip_via_t *v, | |||||
2782 | tport_t *tport); | |||||
2783 | static int agent_aliases(nta_agent_t const *, url_t [], tport_t *); | |||||
2784 | static void agent_recv_response(nta_agent_t*, msg_t *, sip_t *, | |||||
2785 | sip_via_t *, tport_t*); | |||||
2786 | static void agent_recv_garbage(nta_agent_t*, msg_t*, tport_t*); | |||||
2787 | ||||||
2788 | #if HAVE_SOFIA_SRESOLV1 | |||||
2789 | static void outgoing_resolve(nta_outgoing_t *orq, | |||||
2790 | int explicit_transport, | |||||
2791 | enum nta_res_order_e order); | |||||
2792 | su_inlinestatic inline void outgoing_cancel_resolver(nta_outgoing_t *orq); | |||||
2793 | su_inlinestatic inline void outgoing_destroy_resolver(nta_outgoing_t *orq); | |||||
2794 | static int outgoing_other_destinations(nta_outgoing_t const *orq); | |||||
2795 | static int outgoing_try_another(nta_outgoing_t *orq); | |||||
2796 | #else | |||||
2797 | #define outgoing_other_destinations(orq) (0) | |||||
2798 | #define outgoing_try_another(orq) (0) | |||||
2799 | #endif | |||||
2800 | ||||||
2801 | /** Handle incoming message. */ | |||||
2802 | static | |||||
2803 | void agent_recv_message(nta_agent_t *agent, | |||||
2804 | tport_t *tport, | |||||
2805 | msg_t *msg, | |||||
2806 | sip_via_t *tport_via, | |||||
2807 | su_time_t now) | |||||
2808 | { | |||||
2809 | sip_t *sip = sip_object(msg); | |||||
2810 | ||||||
2811 | if (sip && sip->sip_request) { | |||||
2812 | agent_recv_request(agent, msg, sip, tport); | |||||
2813 | } | |||||
2814 | else if (sip && sip->sip_status) { | |||||
2815 | agent_recv_response(agent, msg, sip, tport_via, tport); | |||||
2816 | } | |||||
2817 | else { | |||||
2818 | agent_recv_garbage(agent, msg, tport); | |||||
2819 | } | |||||
2820 | } | |||||
2821 | ||||||
2822 | #ifdef HAVE_ZLIB_COMPRESS1 | |||||
2823 | int sip_content_encoding_Xflate(msg_t *msg, sip_t *sip, int inflate, int check) | |||||
2824 | { | |||||
2825 | char const *method_name; | |||||
2826 | unsigned cseq = sip->sip_cseq ? sip->sip_cseq->cs_seq : 0; | |||||
2827 | int ok = !check; | |||||
2828 | ||||||
2829 | if (!sip->sip_payload) { | |||||
2830 | return 0; | |||||
2831 | } | |||||
2832 | ||||||
2833 | if (sip->sip_request) { | |||||
2834 | method_name = sip->sip_request->rq_method_name; | |||||
2835 | } else if (sip->sip_cseq) { | |||||
2836 | method_name = sip->sip_cseq->cs_method_name; | |||||
2837 | } else { | |||||
2838 | method_name = "Unknown"; | |||||
2839 | } | |||||
2840 | ||||||
2841 | if (!ok) { | |||||
2842 | if (sip->sip_content_encoding && sip->sip_content_encoding->k_items) { | |||||
2843 | const char *val = sip->sip_content_encoding->k_items[0]; | |||||
2844 | if (val && (!strcasecmp(val, "gzip") || !strcasecmp(val, "deflate"))) { | |||||
2845 | ok = 1; | |||||
2846 | } | |||||
2847 | } | |||||
2848 | } | |||||
2849 | ||||||
2850 | if (ok) { | |||||
2851 | unsigned long n = 0; | |||||
2852 | void *decoded = NULL((void*)0); | |||||
2853 | const char *id = "N/A"; | |||||
2854 | const char *orig_payload = sip->sip_payload->pl_data; | |||||
2855 | ||||||
2856 | n = sip->sip_payload->pl_len * 10; | |||||
2857 | ||||||
2858 | decoded = su_alloc(msg_home(msg)((su_home_t*)(msg)), n); | |||||
2859 | assert(decoded)((void) sizeof ((decoded) ? 1 : 0), __extension__ ({ if (decoded ) ; else __assert_fail ("decoded", "nta.c", 2859, __extension__ __PRETTY_FUNCTION__); })); | |||||
2860 | ||||||
2861 | if (inflate) { | |||||
2862 | uncompress(decoded, &n, (void *)sip->sip_payload->pl_data, (unsigned long)sip->sip_payload->pl_len); | |||||
2863 | } else { | |||||
2864 | compress(decoded, &n, (void *)sip->sip_payload->pl_data, (unsigned long)sip->sip_payload->pl_len); | |||||
2865 | } | |||||
2866 | ||||||
2867 | sip->sip_payload = sip_payload_create(msg_home(msg)((su_home_t*)(msg)), decoded, n); | |||||
2868 | sip->sip_content_encoding = sip_content_encoding_make(msg_home(msg)((su_home_t*)(msg)), "deflate"); | |||||
2869 | ||||||
2870 | if (sip->sip_call_id) { | |||||
2871 | id = sip->sip_call_id->i_id; | |||||
2872 | } | |||||
2873 | ||||||
2874 | if (inflate) { | |||||
2875 | SU_DEBUG_1(("nta: %s (%u) (%s) Inflating compressed body:\n%s\n", method_name, cseq, id, (char *)decoded))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 2875, "nta: %s (%u) (%s) Inflating compressed body:\n%s\n", method_name, cseq, id, (char *)decoded)) : (void)0); | |||||
2876 | } else { | |||||
2877 | SU_DEBUG_1(("nta: %s (%u) (%s) Deflating compressed body:\n%s\n", method_name, cseq, id, orig_payload))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 2877, "nta: %s (%u) (%s) Deflating compressed body:\n%s\n", method_name, cseq, id, orig_payload)) : (void)0); | |||||
2878 | } | |||||
2879 | ||||||
2880 | return 1; | |||||
2881 | } | |||||
2882 | ||||||
2883 | return 0; | |||||
2884 | } | |||||
2885 | #endif | |||||
2886 | ||||||
2887 | /** @internal Handle incoming requests. */ | |||||
2888 | static | |||||
2889 | void agent_recv_request(nta_agent_t *agent, | |||||
2890 | msg_t *msg, | |||||
2891 | sip_t *sip, | |||||
2892 | tport_t *tport) | |||||
2893 | { | |||||
2894 | nta_leg_t *leg; | |||||
2895 | nta_incoming_t *irq, *merge = NULL((void*)0), *ack = NULL((void*)0), *cancel = NULL((void*)0); | |||||
2896 | sip_method_t method = sip->sip_request->rq_method; | |||||
2897 | char const *method_name = sip->sip_request->rq_method_name; | |||||
2898 | url_t url[1]; | |||||
2899 | unsigned cseq = sip->sip_cseq ? sip->sip_cseq->cs_seq : 0; | |||||
2900 | int insane, errors, stream; | |||||
2901 | unsigned compressed = 0; | |||||
2902 | ||||||
2903 | agent->sa_stats->as_recv_msg++; | |||||
2904 | agent->sa_stats->as_recv_request++; | |||||
2905 | ||||||
2906 | SU_DEBUG_5(("nta: received %s " URL_PRINT_FORMAT " %s (CSeq %u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 2909, "nta: received %s " "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" " %s (CSeq %u)\n", method_name, (sip->sip_request->rq_url )->url_scheme ? (sip->sip_request->rq_url)->url_scheme : "", (sip->sip_request->rq_url)->url_type != url_any && (sip->sip_request->rq_url)->url_scheme && (sip->sip_request->rq_url)->url_scheme[0] ? ":" : "" , (sip->sip_request->rq_url)->url_root && (( sip->sip_request->rq_url)->url_host || (sip->sip_request ->rq_url)->url_user) ? "//" : "", (sip->sip_request-> rq_url)->url_user ? (sip->sip_request->rq_url)->url_user : "", (sip->sip_request->rq_url)->url_user && (sip->sip_request->rq_url)->url_password ? ":" : "" , (sip->sip_request->rq_url)->url_user && (sip ->sip_request->rq_url)->url_password ? (sip->sip_request ->rq_url)->url_password : "", (sip->sip_request-> rq_url)->url_user && (sip->sip_request->rq_url )->url_host ? "@" : "", (sip->sip_request->rq_url)-> url_host ? (sip->sip_request->rq_url)->url_host : "" , (sip->sip_request->rq_url)->url_host && (sip ->sip_request->rq_url)->url_port ? ":" : "", (sip-> sip_request->rq_url)->url_host && (sip->sip_request ->rq_url)->url_port ? (sip->sip_request->rq_url)-> url_port : "", (sip->sip_request->rq_url)->url_root && (sip->sip_request->rq_url)->url_path ? "/" : "", (sip ->sip_request->rq_url)->url_path ? (sip->sip_request ->rq_url)->url_path : "", (sip->sip_request->rq_url )->url_params ? ";" : "", (sip->sip_request->rq_url) ->url_params ? (sip->sip_request->rq_url)->url_params : "", (sip->sip_request->rq_url)->url_headers ? "?" : "", (sip->sip_request->rq_url)->url_headers ? (sip ->sip_request->rq_url)->url_headers : "", (sip->sip_request ->rq_url)->url_fragment ? "#" : "", (sip->sip_request ->rq_url)->url_fragment ? (sip->sip_request->rq_url )->url_fragment : "", sip->sip_request->rq_version, cseq )) : (void)0) | |||||
2907 | method_name,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 2909, "nta: received %s " "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" " %s (CSeq %u)\n", method_name, (sip->sip_request->rq_url )->url_scheme ? (sip->sip_request->rq_url)->url_scheme : "", (sip->sip_request->rq_url)->url_type != url_any && (sip->sip_request->rq_url)->url_scheme && (sip->sip_request->rq_url)->url_scheme[0] ? ":" : "" , (sip->sip_request->rq_url)->url_root && (( sip->sip_request->rq_url)->url_host || (sip->sip_request ->rq_url)->url_user) ? "//" : "", (sip->sip_request-> rq_url)->url_user ? (sip->sip_request->rq_url)->url_user : "", (sip->sip_request->rq_url)->url_user && (sip->sip_request->rq_url)->url_password ? ":" : "" , (sip->sip_request->rq_url)->url_user && (sip ->sip_request->rq_url)->url_password ? (sip->sip_request ->rq_url)->url_password : "", (sip->sip_request-> rq_url)->url_user && (sip->sip_request->rq_url )->url_host ? "@" : "", (sip->sip_request->rq_url)-> url_host ? (sip->sip_request->rq_url)->url_host : "" , (sip->sip_request->rq_url)->url_host && (sip ->sip_request->rq_url)->url_port ? ":" : "", (sip-> sip_request->rq_url)->url_host && (sip->sip_request ->rq_url)->url_port ? (sip->sip_request->rq_url)-> url_port : "", (sip->sip_request->rq_url)->url_root && (sip->sip_request->rq_url)->url_path ? "/" : "", (sip ->sip_request->rq_url)->url_path ? (sip->sip_request ->rq_url)->url_path : "", (sip->sip_request->rq_url )->url_params ? ";" : "", (sip->sip_request->rq_url) ->url_params ? (sip->sip_request->rq_url)->url_params : "", (sip->sip_request->rq_url)->url_headers ? "?" : "", (sip->sip_request->rq_url)->url_headers ? (sip ->sip_request->rq_url)->url_headers : "", (sip->sip_request ->rq_url)->url_fragment ? "#" : "", (sip->sip_request ->rq_url)->url_fragment ? (sip->sip_request->rq_url )->url_fragment : "", sip->sip_request->rq_version, cseq )) : (void)0) | |||||
2908 | URL_PRINT_ARGS(sip->sip_request->rq_url),(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 2909, "nta: received %s " "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" " %s (CSeq %u)\n", method_name, (sip->sip_request->rq_url )->url_scheme ? (sip->sip_request->rq_url)->url_scheme : "", (sip->sip_request->rq_url)->url_type != url_any && (sip->sip_request->rq_url)->url_scheme && (sip->sip_request->rq_url)->url_scheme[0] ? ":" : "" , (sip->sip_request->rq_url)->url_root && (( sip->sip_request->rq_url)->url_host || (sip->sip_request ->rq_url)->url_user) ? "//" : "", (sip->sip_request-> rq_url)->url_user ? (sip->sip_request->rq_url)->url_user : "", (sip->sip_request->rq_url)->url_user && (sip->sip_request->rq_url)->url_password ? ":" : "" , (sip->sip_request->rq_url)->url_user && (sip ->sip_request->rq_url)->url_password ? (sip->sip_request ->rq_url)->url_password : "", (sip->sip_request-> rq_url)->url_user && (sip->sip_request->rq_url )->url_host ? "@" : "", (sip->sip_request->rq_url)-> url_host ? (sip->sip_request->rq_url)->url_host : "" , (sip->sip_request->rq_url)->url_host && (sip ->sip_request->rq_url)->url_port ? ":" : "", (sip-> sip_request->rq_url)->url_host && (sip->sip_request ->rq_url)->url_port ? (sip->sip_request->rq_url)-> url_port : "", (sip->sip_request->rq_url)->url_root && (sip->sip_request->rq_url)->url_path ? "/" : "", (sip ->sip_request->rq_url)->url_path ? (sip->sip_request ->rq_url)->url_path : "", (sip->sip_request->rq_url )->url_params ? ";" : "", (sip->sip_request->rq_url) ->url_params ? (sip->sip_request->rq_url)->url_params : "", (sip->sip_request->rq_url)->url_headers ? "?" : "", (sip->sip_request->rq_url)->url_headers ? (sip ->sip_request->rq_url)->url_headers : "", (sip->sip_request ->rq_url)->url_fragment ? "#" : "", (sip->sip_request ->rq_url)->url_fragment ? (sip->sip_request->rq_url )->url_fragment : "", sip->sip_request->rq_version, cseq )) : (void)0) | |||||
2909 | sip->sip_request->rq_version, cseq))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 2909, "nta: received %s " "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" " %s (CSeq %u)\n", method_name, (sip->sip_request->rq_url )->url_scheme ? (sip->sip_request->rq_url)->url_scheme : "", (sip->sip_request->rq_url)->url_type != url_any && (sip->sip_request->rq_url)->url_scheme && (sip->sip_request->rq_url)->url_scheme[0] ? ":" : "" , (sip->sip_request->rq_url)->url_root && (( sip->sip_request->rq_url)->url_host || (sip->sip_request ->rq_url)->url_user) ? "//" : "", (sip->sip_request-> rq_url)->url_user ? (sip->sip_request->rq_url)->url_user : "", (sip->sip_request->rq_url)->url_user && (sip->sip_request->rq_url)->url_password ? ":" : "" , (sip->sip_request->rq_url)->url_user && (sip ->sip_request->rq_url)->url_password ? (sip->sip_request ->rq_url)->url_password : "", (sip->sip_request-> rq_url)->url_user && (sip->sip_request->rq_url )->url_host ? "@" : "", (sip->sip_request->rq_url)-> url_host ? (sip->sip_request->rq_url)->url_host : "" , (sip->sip_request->rq_url)->url_host && (sip ->sip_request->rq_url)->url_port ? ":" : "", (sip-> sip_request->rq_url)->url_host && (sip->sip_request ->rq_url)->url_port ? (sip->sip_request->rq_url)-> url_port : "", (sip->sip_request->rq_url)->url_root && (sip->sip_request->rq_url)->url_path ? "/" : "", (sip ->sip_request->rq_url)->url_path ? (sip->sip_request ->rq_url)->url_path : "", (sip->sip_request->rq_url )->url_params ? ";" : "", (sip->sip_request->rq_url) ->url_params ? (sip->sip_request->rq_url)->url_params : "", (sip->sip_request->rq_url)->url_headers ? "?" : "", (sip->sip_request->rq_url)->url_headers ? (sip ->sip_request->rq_url)->url_headers : "", (sip->sip_request ->rq_url)->url_fragment ? "#" : "", (sip->sip_request ->rq_url)->url_fragment ? (sip->sip_request->rq_url )->url_fragment : "", sip->sip_request->rq_version, cseq )) : (void)0); | |||||
2910 | ||||||
2911 | if (agent->sa_drop_prob && !tport_is_reliable(tport)) { | |||||
2912 | if ((unsigned)su_randint(0, 1000) < agent->sa_drop_prob) { | |||||
2913 | SU_DEBUG_5(("nta: %s (%u) is %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 2914, "nta: %s (%u) is %s\n", method_name, cseq, "dropped simulating packet loss" )) : (void)0) | |||||
2914 | method_name, cseq, "dropped simulating packet loss"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 2914, "nta: %s (%u) is %s\n", method_name, cseq, "dropped simulating packet loss" )) : (void)0); | |||||
2915 | agent->sa_stats->as_drop_request++; | |||||
2916 | msg_destroy(msg); | |||||
2917 | return; | |||||
2918 | } | |||||
2919 | } | |||||
2920 | ||||||
2921 | stream = tport_is_stream(tport); | |||||
2922 | ||||||
2923 | /* Try to use compression on reverse direction if @Via has comp=sigcomp */ | |||||
2924 | if (stream && | |||||
2925 | sip->sip_via && sip->sip_via->v_comp && | |||||
2926 | tport_can_send_sigcomp(tport) && | |||||
2927 | tport_name(tport)->tpn_comp == NULL((void*)0) && | |||||
2928 | tport_has_compression(tport_parent(tport), sip->sip_via->v_comp)) { | |||||
2929 | tport_set_compression(tport, sip->sip_via->v_comp); | |||||
2930 | } | |||||
2931 | ||||||
2932 | if (sip->sip_flags & MSG_FLG_TOOLARGE) { | |||||
2933 | SU_DEBUG_5(("nta: %s (%u) is %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 2934, "nta: %s (%u) is %s\n", method_name, cseq, sip_413_Request_too_large )) : (void)0) | |||||
2934 | method_name, cseq, sip_413_Request_too_large))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 2934, "nta: %s (%u) is %s\n", method_name, cseq, sip_413_Request_too_large )) : (void)0); | |||||
2935 | agent->sa_stats->as_bad_request++; | |||||
2936 | mreply(agent, NULL((void*)0), SIP_413_REQUEST_TOO_LARGE413, sip_413_Request_too_large, msg, | |||||
2937 | tport, 1, stream, NULL((void*)0), | |||||
2938 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
2939 | return; | |||||
2940 | } | |||||
2941 | ||||||
2942 | insane = 0; | |||||
2943 | ||||||
2944 | if (agent->sa_bad_req_mask != ~0U) | |||||
2945 | errors = msg_extract_errors(msg) & agent->sa_bad_req_mask; | |||||
2946 | else | |||||
2947 | errors = sip->sip_error != NULL((void*)0); | |||||
2948 | ||||||
2949 | if (errors || | |||||
2950 | (sip->sip_flags & MSG_FLG_ERROR) /* Fatal error */ || | |||||
2951 | (insane = (sip_sanity_check(sip) < 0))) { | |||||
2952 | sip_header_t const *h; | |||||
2953 | char const *badname = NULL((void*)0), *phrase; | |||||
2954 | ||||||
2955 | agent->sa_stats->as_bad_message++; | |||||
2956 | agent->sa_stats->as_bad_request++; | |||||
2957 | ||||||
2958 | if (insane) | |||||
2959 | SU_DEBUG_5(("nta: %s (%u) %s\n", method_name, cseq,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 2960, "nta: %s (%u) %s\n", method_name, cseq, "failed sanity check" )) : (void)0) | |||||
2960 | "failed sanity check"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 2960, "nta: %s (%u) %s\n", method_name, cseq, "failed sanity check" )) : (void)0); | |||||
2961 | ||||||
2962 | for (h = (sip_header_t const *)sip->sip_error; h; h = h->sh_nextsh_header_next->shn_next) { | |||||
2963 | char const *bad; | |||||
2964 | ||||||
2965 | if (h->sh_classsh_common->h_class == sip_error_class) | |||||
2966 | bad = h->sh_error->er_name; | |||||
2967 | else | |||||
2968 | bad = h->sh_classsh_common->h_class->hc_name; | |||||
2969 | ||||||
2970 | if (bad) | |||||
2971 | SU_DEBUG_5(("nta: %s has bad %s header\n", method_name, bad))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 2971, "nta: %s has bad %s header\n", method_name, bad)) : ( void)0); | |||||
2972 | ||||||
2973 | if (!badname) | |||||
2974 | badname = bad; | |||||
2975 | } | |||||
2976 | ||||||
2977 | if (sip->sip_via && method != sip_method_ack) { | |||||
2978 | msg_t *reply = nta_msg_create(agent, 0); | |||||
2979 | ||||||
2980 | agent_check_request_via(agent, msg, sip, sip->sip_via, tport); | |||||
2981 | ||||||
2982 | if (badname && reply) | |||||
2983 | phrase = su_sprintf(msg_home(reply)((su_home_t*)(reply)), "Bad %s Header", badname); | |||||
2984 | else | |||||
2985 | phrase = sip_400_Bad_request; | |||||
2986 | ||||||
2987 | SU_DEBUG_5(("nta: %s (%u) is %s\n", method_name, cseq, phrase))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 2987, "nta: %s (%u) is %s\n", method_name, cseq, phrase)) : (void)0); | |||||
2988 | ||||||
2989 | mreply(agent, reply, 400, phrase, msg, | |||||
2990 | tport, 1, stream, NULL((void*)0), | |||||
2991 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
2992 | } | |||||
2993 | else { | |||||
2994 | msg_destroy(msg); | |||||
2995 | if (stream) /* Send FIN */ | |||||
2996 | tport_shutdown(tport, 1); | |||||
2997 | } | |||||
2998 | ||||||
2999 | return; | |||||
3000 | } | |||||
3001 | ||||||
3002 | if (!su_casematch(sip->sip_request->rq_version, sip_version_2_0)) { | |||||
3003 | agent->sa_stats->as_bad_request++; | |||||
3004 | agent->sa_stats->as_bad_message++; | |||||
3005 | ||||||
3006 | SU_DEBUG_5(("nta: bad version %s for %s (%u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3007, "nta: bad version %s for %s (%u)\n", sip->sip_request ->rq_version, method_name, cseq)) : (void)0) | |||||
3007 | sip->sip_request->rq_version, method_name, cseq))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3007, "nta: bad version %s for %s (%u)\n", sip->sip_request ->rq_version, method_name, cseq)) : (void)0); | |||||
3008 | ||||||
3009 | mreply(agent, NULL((void*)0), SIP_505_VERSION_NOT_SUPPORTED505, sip_505_Version_not_supported, msg, | |||||
3010 | tport, 0, stream, NULL((void*)0), | |||||
3011 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
3012 | ||||||
3013 | return; | |||||
3014 | } | |||||
3015 | ||||||
3016 | if (agent_check_request_via(agent, msg, sip, sip->sip_via, tport) < 0) { | |||||
3017 | agent->sa_stats->as_bad_message++; | |||||
3018 | agent->sa_stats->as_bad_request++; | |||||
3019 | SU_DEBUG_5(("nta: %s (%u) %s\n", method_name, cseq, "has invalid Via"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3019, "nta: %s (%u) %s\n", method_name, cseq, "has invalid Via" )) : (void)0); | |||||
3020 | msg_destroy(msg); | |||||
3021 | return; | |||||
3022 | } | |||||
3023 | ||||||
3024 | #ifdef HAVE_ZLIB_COMPRESS1 | |||||
3025 | compressed = sip_content_encoding_Xflate(msg, sip, 1, 1); | |||||
3026 | #endif | |||||
3027 | ||||||
3028 | /* First, try existing incoming requests */ | |||||
3029 | irq = incoming_find(agent, sip, sip->sip_via, | |||||
3030 | agent->sa_merge_482 && | |||||
3031 | !sip->sip_to->a_tag && | |||||
3032 | method != sip_method_ack | |||||
3033 | ? &merge | |||||
3034 | : NULL((void*)0), | |||||
3035 | method == sip_method_ack ? &ack : NULL((void*)0), | |||||
3036 | method == sip_method_cancel ? &cancel : NULL((void*)0)); | |||||
3037 | ||||||
3038 | if (irq) { | |||||
3039 | /* Match - this is a retransmission */ | |||||
3040 | SU_DEBUG_5(("nta: %s (%u) going to existing %s transaction\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3041, "nta: %s (%u) going to existing %s transaction\n", method_name , cseq, irq->irq_rq->rq_method_name)) : (void)0) | |||||
3041 | method_name, cseq, irq->irq_rq->rq_method_name))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3041, "nta: %s (%u) going to existing %s transaction\n", method_name , cseq, irq->irq_rq->rq_method_name)) : (void)0); | |||||
3042 | if (incoming_recv(irq, msg, sip, tport) >= 0) | |||||
3043 | return; | |||||
3044 | } | |||||
3045 | else if (ack) { | |||||
3046 | SU_DEBUG_5(("nta: %s (%u) is going to %s (%u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3048, "nta: %s (%u) is going to %s (%u)\n", method_name, cseq , ack->irq_cseq->cs_method_name, ack->irq_cseq->cs_seq )) : (void)0) | |||||
3047 | method_name, cseq,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3048, "nta: %s (%u) is going to %s (%u)\n", method_name, cseq , ack->irq_cseq->cs_method_name, ack->irq_cseq->cs_seq )) : (void)0) | |||||
3048 | ack->irq_cseq->cs_method_name, ack->irq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3048, "nta: %s (%u) is going to %s (%u)\n", method_name, cseq , ack->irq_cseq->cs_method_name, ack->irq_cseq->cs_seq )) : (void)0); | |||||
3049 | if (incoming_ack(ack, msg, sip, tport) >= 0) | |||||
3050 | return; | |||||
3051 | } | |||||
3052 | else if (cancel) { | |||||
3053 | SU_DEBUG_5(("nta: %s (%u) is going to %s (%u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3055, "nta: %s (%u) is going to %s (%u)\n", method_name, cseq , cancel->irq_cseq->cs_method_name, cancel->irq_cseq ->cs_seq)) : (void)0) | |||||
3054 | method_name, cseq,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3055, "nta: %s (%u) is going to %s (%u)\n", method_name, cseq , cancel->irq_cseq->cs_method_name, cancel->irq_cseq ->cs_seq)) : (void)0) | |||||
3055 | cancel->irq_cseq->cs_method_name, cancel->irq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3055, "nta: %s (%u) is going to %s (%u)\n", method_name, cseq , cancel->irq_cseq->cs_method_name, cancel->irq_cseq ->cs_seq)) : (void)0); | |||||
3056 | if (incoming_cancel(cancel, msg, sip, tport) >= 0) | |||||
3057 | return; | |||||
3058 | } | |||||
3059 | else if (merge) { | |||||
3060 | SU_DEBUG_5(("nta: %s (%u) %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3061, "nta: %s (%u) %s\n", method_name, cseq, "is a merged request" )) : (void)0) | |||||
3061 | method_name, cseq, "is a merged request"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3061, "nta: %s (%u) %s\n", method_name, cseq, "is a merged request" )) : (void)0); | |||||
3062 | request_merge(agent, msg, sip, tport, merge->irq_tag); | |||||
3063 | return; | |||||
3064 | } | |||||
3065 | ||||||
3066 | if (method == sip_method_prack && sip->sip_rack) { | |||||
3067 | nta_reliable_t *rel = reliable_find(agent, sip); | |||||
3068 | if (rel) { | |||||
3069 | SU_DEBUG_5(("nta: %s (%u) is going to %s (%u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3072, "nta: %s (%u) is going to %s (%u)\n", method_name, cseq , rel->rel_irq->irq_cseq->cs_method_name, rel->rel_irq ->irq_cseq->cs_seq)) : (void)0) | |||||
3070 | method_name, cseq,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3072, "nta: %s (%u) is going to %s (%u)\n", method_name, cseq , rel->rel_irq->irq_cseq->cs_method_name, rel->rel_irq ->irq_cseq->cs_seq)) : (void)0) | |||||
3071 | rel->rel_irq->irq_cseq->cs_method_name,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3072, "nta: %s (%u) is going to %s (%u)\n", method_name, cseq , rel->rel_irq->irq_cseq->cs_method_name, rel->rel_irq ->irq_cseq->cs_seq)) : (void)0) | |||||
3072 | rel->rel_irq->irq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3072, "nta: %s (%u) is going to %s (%u)\n", method_name, cseq , rel->rel_irq->irq_cseq->cs_method_name, rel->rel_irq ->irq_cseq->cs_seq)) : (void)0); | |||||
3073 | reliable_recv(rel, msg, sip, tport); | |||||
3074 | return; | |||||
3075 | } | |||||
3076 | } | |||||
3077 | ||||||
3078 | *url = *sip->sip_request->rq_url; | |||||
3079 | url->url_params = NULL((void*)0); | |||||
3080 | agent_aliases(agent, url, tport); /* canonize urls */ | |||||
3081 | ||||||
3082 | if (method != sip_method_subscribe && (leg = leg_find(agent, | |||||
3083 | method_name, url, | |||||
3084 | sip->sip_call_id, | |||||
3085 | sip->sip_from->a_tag, | |||||
3086 | sip->sip_to->a_tag))) { | |||||
3087 | /* Try existing dialog */ | |||||
3088 | SU_DEBUG_5(("nta: %s (%u) %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3089, "nta: %s (%u) %s\n", method_name, cseq, "going to existing leg" )) : (void)0) | |||||
3089 | method_name, cseq, "going to existing leg"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3089, "nta: %s (%u) %s\n", method_name, cseq, "going to existing leg" )) : (void)0); | |||||
3090 | leg->leg_compressed = compressed; | |||||
3091 | leg_recv(leg, msg, sip, tport); | |||||
3092 | return; | |||||
3093 | } | |||||
3094 | else if (!agent->sa_is_stateless && | |||||
3095 | (leg = dst_find(agent, url, method_name))) { | |||||
3096 | /* Dialogless legs - let application process transactions statefully */ | |||||
3097 | SU_DEBUG_5(("nta: %s (%u) %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3098, "nta: %s (%u) %s\n", method_name, cseq, "going to a dialogless leg" )) : (void)0) | |||||
3098 | method_name, cseq, "going to a dialogless leg"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3098, "nta: %s (%u) %s\n", method_name, cseq, "going to a dialogless leg" )) : (void)0); | |||||
3099 | leg->leg_compressed = compressed; | |||||
3100 | leg_recv(leg, msg, sip, tport); | |||||
3101 | } | |||||
3102 | else if (!agent->sa_is_stateless && (leg = agent->sa_default_leg)) { | |||||
3103 | if (method == sip_method_invite && | |||||
3104 | agent->sa_in.proceeding->q_length >= agent->sa_max_proceeding) { | |||||
3105 | SU_DEBUG_5(("nta: proceeding queue full for %s (%u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3106, "nta: proceeding queue full for %s (%u)\n", method_name , cseq)) : (void)0) | |||||
3106 | method_name, cseq))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3106, "nta: proceeding queue full for %s (%u)\n", method_name , cseq)) : (void)0); | |||||
3107 | mreply(agent, NULL((void*)0), SIP_503_SERVICE_UNAVAILABLE503, sip_503_Service_unavailable, msg, | |||||
3108 | tport, 0, 0, NULL((void*)0), | |||||
3109 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
3110 | return; | |||||
3111 | } | |||||
3112 | else { | |||||
3113 | SU_DEBUG_5(("nta: %s (%u) %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3114, "nta: %s (%u) %s\n", method_name, cseq, "going to a default leg" )) : (void)0) | |||||
3114 | method_name, cseq, "going to a default leg"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3114, "nta: %s (%u) %s\n", method_name, cseq, "going to a default leg" )) : (void)0); | |||||
3115 | leg->leg_compressed = compressed; | |||||
3116 | leg_recv(leg, msg, sip, tport); | |||||
3117 | } | |||||
3118 | } | |||||
3119 | else if (agent->sa_callback) { | |||||
3120 | /* Stateless processing for request */ | |||||
3121 | agent->sa_stats->as_trless_request++; | |||||
3122 | SU_DEBUG_5(("nta: %s (%u) %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3123, "nta: %s (%u) %s\n", method_name, cseq, "to message callback" )) : (void)0) | |||||
3123 | method_name, cseq, "to message callback"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3123, "nta: %s (%u) %s\n", method_name, cseq, "to message callback" )) : (void)0); | |||||
3124 | (void)agent->sa_callback(agent->sa_magic, agent, msg, sip); | |||||
3125 | } | |||||
3126 | else { | |||||
3127 | agent->sa_stats->as_trless_request++; | |||||
3128 | SU_DEBUG_5(("nta: %s (%u) %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3130, "nta: %s (%u) %s\n", method_name, cseq, "not processed by application: returning 501" )) : (void)0) | |||||
3129 | method_name, cseq,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3130, "nta: %s (%u) %s\n", method_name, cseq, "not processed by application: returning 501" )) : (void)0) | |||||
3130 | "not processed by application: returning 501"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3130, "nta: %s (%u) %s\n", method_name, cseq, "not processed by application: returning 501" )) : (void)0); | |||||
3131 | if (method != sip_method_ack) | |||||
3132 | mreply(agent, NULL((void*)0), SIP_501_NOT_IMPLEMENTED501, sip_501_Not_implemented, msg, | |||||
3133 | tport, 0, 0, NULL((void*)0), | |||||
3134 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
3135 | else | |||||
3136 | msg_destroy(msg); | |||||
3137 | } | |||||
3138 | } | |||||
3139 | ||||||
3140 | /** Check @Via header. | |||||
3141 | * | |||||
3142 | */ | |||||
3143 | static | |||||
3144 | int agent_check_request_via(nta_agent_t *agent, | |||||
3145 | msg_t *msg, | |||||
3146 | sip_t *sip, | |||||
3147 | sip_via_t *v, | |||||
3148 | tport_t *tport) | |||||
3149 | { | |||||
3150 | enum { receivedlen = sizeof("received=") - 1 }; | |||||
3151 | char received[receivedlen + TPORT_HOSTPORTSIZE(55)]; | |||||
3152 | char *hostport = received + receivedlen; | |||||
3153 | char const *rport; | |||||
3154 | su_sockaddr_t const *from; | |||||
3155 | sip_via_t const *tpv = agent_tport_via(tport); | |||||
3156 | ||||||
3157 | assert(tport)((void) sizeof ((tport) ? 1 : 0), __extension__ ({ if (tport) ; else __assert_fail ("tport", "nta.c", 3157, __extension__ __PRETTY_FUNCTION__ ); })); assert(msg)((void) sizeof ((msg) ? 1 : 0), __extension__ ({ if (msg) ; else __assert_fail ("msg", "nta.c", 3157, __extension__ __PRETTY_FUNCTION__ ); })); assert(sip)((void) sizeof ((sip) ? 1 : 0), __extension__ ({ if (sip) ; else __assert_fail ("sip", "nta.c", 3157, __extension__ __PRETTY_FUNCTION__ ); })); | |||||
3158 | assert(sip->sip_request)((void) sizeof ((sip->sip_request) ? 1 : 0), __extension__ ({ if (sip->sip_request) ; else __assert_fail ("sip->sip_request" , "nta.c", 3158, __extension__ __PRETTY_FUNCTION__); })); assert(tpv)((void) sizeof ((tpv) ? 1 : 0), __extension__ ({ if (tpv) ; else __assert_fail ("tpv", "nta.c", 3158, __extension__ __PRETTY_FUNCTION__ ); })); | |||||
3159 | ||||||
3160 | from = msg_addr(msg); | |||||
3161 | ||||||
3162 | if (v == NULL((void*)0)) { | |||||
3163 | /* Make up a via line */ | |||||
3164 | v = sip_via_format(msg_home(msg)((su_home_t*)(msg)), "SIP/2.0/%s %s", | |||||
3165 | tport_name(tport)->tpn_proto, | |||||
3166 | tport_hostport(hostport, TPORT_HOSTPORTSIZE(55), from, 1)); | |||||
3167 | msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)v); | |||||
3168 | ||||||
3169 | return v ? 0 : -1; | |||||
3170 | } | |||||
3171 | ||||||
3172 | if (!su_strmatch(v->v_protocol, tpv->v_protocol)) { | |||||
3173 | tport_hostport(hostport, TPORT_HOSTPORTSIZE(55), from, 1); | |||||
3174 | SU_DEBUG_1(("nta: Via check: invalid transport \"%s\" from %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 3175, "nta: Via check: invalid transport \"%s\" from %s\n", v->v_protocol, hostport)) : (void)0) | |||||
3175 | v->v_protocol, hostport))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 3175, "nta: Via check: invalid transport \"%s\" from %s\n", v->v_protocol, hostport)) : (void)0); | |||||
3176 | return -1; | |||||
3177 | } | |||||
3178 | ||||||
3179 | if (v->v_received) { | |||||
3180 | /* Nasty, nasty */ | |||||
3181 | tport_hostport(hostport, TPORT_HOSTPORTSIZE(55), from, 1); | |||||
3182 | SU_DEBUG_1(("nta: Via check: extra received=%s from %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 3183, "nta: Via check: extra received=%s from %s\n", v-> v_received, hostport)) : (void)0) | |||||
3183 | v->v_received, hostport))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 3183, "nta: Via check: extra received=%s from %s\n", v-> v_received, hostport)) : (void)0); | |||||
3184 | msg_header_remove_param(v->v_common, "received"); | |||||
3185 | } | |||||
3186 | ||||||
3187 | if (!tport_hostport(hostport, TPORT_HOSTPORTSIZE(55), from, 0)) | |||||
3188 | return -1; | |||||
3189 | ||||||
3190 | if (!su_casematch(hostport, v->v_host)) { | |||||
3191 | size_t rlen; | |||||
3192 | /* Add the "received" field */ | |||||
3193 | memcpy(received, "received=", receivedlen); | |||||
3194 | ||||||
3195 | if (hostport[0] == '[') { | |||||
3196 | rlen = strlen(hostport + 1) - 1; | |||||
3197 | memmove(hostport, hostport + 1, rlen); | |||||
3198 | hostport[rlen] = '\0'; | |||||
3199 | } | |||||
3200 | ||||||
3201 | msg_header_replace_param(msg_home(msg)((su_home_t*)(msg)), v->v_common, | |||||
3202 | su_strdup(msg_home(msg)((su_home_t*)(msg)), received)); | |||||
3203 | SU_DEBUG_5(("nta: Via check: %s\n", received))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3203, "nta: Via check: %s\n", received)) : (void)0); | |||||
3204 | } | |||||
3205 | ||||||
3206 | if (!agent->sa_server_rport) { | |||||
3207 | /*Xyzzy*/; | |||||
3208 | } | |||||
3209 | else if (v->v_rport) { | |||||
3210 | rport = su_sprintf(msg_home(msg)((su_home_t*)(msg)), "rport=%u", ntohs(from->su_portsu_sin.sin_port)); | |||||
3211 | msg_header_replace_param(msg_home(msg)((su_home_t*)(msg)), v->v_common, rport); | |||||
3212 | } | |||||
3213 | else if (tport_is_tcp(tport)) { | |||||
3214 | rport = su_sprintf(msg_home(msg)((su_home_t*)(msg)), "rport=%u", ntohs(from->su_portsu_sin.sin_port)); | |||||
3215 | msg_header_replace_param(msg_home(msg)((su_home_t*)(msg)), v->v_common, rport); | |||||
3216 | } | |||||
3217 | else if (agent->sa_server_rport == 2 || | |||||
3218 | (agent->sa_server_rport == 3 && sip && sip->sip_user_agent && | |||||
3219 | sip->sip_user_agent->g_string && | |||||
3220 | (!strncasecmp(sip->sip_user_agent->g_string, "Polycom", 7) || | |||||
3221 | !strncasecmp(sip->sip_user_agent->g_string, "KIRK Wireless Server", 20) || | |||||
3222 | !strncasecmp(sip->sip_user_agent->g_string, "ADTRAN_Total_Access", 19)))) { | |||||
3223 | rport = su_sprintf(msg_home(msg)((su_home_t*)(msg)), "rport=%u", ntohs(from->su_portsu_sin.sin_port)); | |||||
3224 | msg_header_replace_param(msg_home(msg)((su_home_t*)(msg)), v->v_common, rport); | |||||
3225 | } | |||||
3226 | ||||||
3227 | return 0; | |||||
3228 | } | |||||
3229 | ||||||
3230 | /** @internal Handle aliases of local node. | |||||
3231 | * | |||||
3232 | * Return true if @a url is modified. | |||||
3233 | */ | |||||
3234 | static | |||||
3235 | int agent_aliases(nta_agent_t const *agent, url_t url[], tport_t *tport) | |||||
3236 | { | |||||
3237 | sip_contact_t *m; | |||||
3238 | sip_via_t const *lv; | |||||
3239 | char const *tport_port = ""; | |||||
3240 | ||||||
3241 | if (!url->url_host) | |||||
3242 | return 0; | |||||
3243 | ||||||
3244 | if (tport) | |||||
3245 | tport_port = tport_name(tport)->tpn_port; | |||||
3246 | ||||||
3247 | assert(tport_port)((void) sizeof ((tport_port) ? 1 : 0), __extension__ ({ if (tport_port ) ; else __assert_fail ("tport_port", "nta.c", 3247, __extension__ __PRETTY_FUNCTION__); })); | |||||
3248 | ||||||
3249 | for (m = agent->sa_aliases ? agent->sa_aliases : agent->sa_contact; | |||||
3250 | m; | |||||
3251 | m = m->m_next) { | |||||
3252 | if (url->url_type != m->m_url->url_type) | |||||
3253 | continue; | |||||
3254 | ||||||
3255 | if (host_cmp(url->url_host, m->m_url->url_host)) | |||||
3256 | continue; | |||||
3257 | ||||||
3258 | if (url->url_port == NULL((void*)0)) | |||||
3259 | break; | |||||
3260 | ||||||
3261 | if (m->m_url->url_port) { | |||||
3262 | if (strcmp(url->url_port, m->m_url->url_port)) | |||||
3263 | continue; | |||||
3264 | } else { | |||||
3265 | if (strcmp(url->url_port, tport_port)) | |||||
3266 | continue; | |||||
3267 | } | |||||
3268 | ||||||
3269 | break; | |||||
3270 | } | |||||
3271 | ||||||
3272 | if (!m) | |||||
3273 | return 0; | |||||
3274 | ||||||
3275 | SU_DEBUG_7(("nta: canonizing " URL_PRINT_FORMAT " with %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__ , 3277, "nta: canonizing " "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" " with %s\n", (url)->url_scheme ? (url)->url_scheme : "" , (url)->url_type != url_any && (url)->url_scheme && (url)->url_scheme[0] ? ":" : "", (url)->url_root && ((url)->url_host || (url)->url_user) ? "//" : "", (url)->url_user ? (url)->url_user : "", (url)-> url_user && (url)->url_password ? ":" : "", (url)-> url_user && (url)->url_password ? (url)->url_password : "", (url)->url_user && (url)->url_host ? "@" : "", (url)->url_host ? (url)->url_host : "", (url)-> url_host && (url)->url_port ? ":" : "", (url)-> url_host && (url)->url_port ? (url)->url_port : "", (url)->url_root && (url)->url_path ? "/" : "", (url)->url_path ? (url)->url_path : "", (url)-> url_params ? ";" : "", (url)->url_params ? (url)->url_params : "", (url)->url_headers ? "?" : "", (url)->url_headers ? (url)->url_headers : "", (url)->url_fragment ? "#" : "", (url)->url_fragment ? (url)->url_fragment : "", agent ->sa_aliases ? "aliases" : "contact")) : (void)0) | |||||
3276 | URL_PRINT_ARGS(url),(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__ , 3277, "nta: canonizing " "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" " with %s\n", (url)->url_scheme ? (url)->url_scheme : "" , (url)->url_type != url_any && (url)->url_scheme && (url)->url_scheme[0] ? ":" : "", (url)->url_root && ((url)->url_host || (url)->url_user) ? "//" : "", (url)->url_user ? (url)->url_user : "", (url)-> url_user && (url)->url_password ? ":" : "", (url)-> url_user && (url)->url_password ? (url)->url_password : "", (url)->url_user && (url)->url_host ? "@" : "", (url)->url_host ? (url)->url_host : "", (url)-> url_host && (url)->url_port ? ":" : "", (url)-> url_host && (url)->url_port ? (url)->url_port : "", (url)->url_root && (url)->url_path ? "/" : "", (url)->url_path ? (url)->url_path : "", (url)-> url_params ? ";" : "", (url)->url_params ? (url)->url_params : "", (url)->url_headers ? "?" : "", (url)->url_headers ? (url)->url_headers : "", (url)->url_fragment ? "#" : "", (url)->url_fragment ? (url)->url_fragment : "", agent ->sa_aliases ? "aliases" : "contact")) : (void)0) | |||||
3277 | agent->sa_aliases ? "aliases" : "contact"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__ , 3277, "nta: canonizing " "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" " with %s\n", (url)->url_scheme ? (url)->url_scheme : "" , (url)->url_type != url_any && (url)->url_scheme && (url)->url_scheme[0] ? ":" : "", (url)->url_root && ((url)->url_host || (url)->url_user) ? "//" : "", (url)->url_user ? (url)->url_user : "", (url)-> url_user && (url)->url_password ? ":" : "", (url)-> url_user && (url)->url_password ? (url)->url_password : "", (url)->url_user && (url)->url_host ? "@" : "", (url)->url_host ? (url)->url_host : "", (url)-> url_host && (url)->url_port ? ":" : "", (url)-> url_host && (url)->url_port ? (url)->url_port : "", (url)->url_root && (url)->url_path ? "/" : "", (url)->url_path ? (url)->url_path : "", (url)-> url_params ? ";" : "", (url)->url_params ? (url)->url_params : "", (url)->url_headers ? "?" : "", (url)->url_headers ? (url)->url_headers : "", (url)->url_fragment ? "#" : "", (url)->url_fragment ? (url)->url_fragment : "", agent ->sa_aliases ? "aliases" : "contact")) : (void)0); | |||||
3278 | ||||||
3279 | url->url_host = "%"; | |||||
3280 | ||||||
3281 | if (agent->sa_aliases) { | |||||
3282 | url->url_type = agent->sa_aliases->m_url->url_type; | |||||
3283 | url->url_scheme = agent->sa_aliases->m_url->url_scheme; | |||||
3284 | url->url_port = agent->sa_aliases->m_url->url_port; | |||||
3285 | return 1; | |||||
3286 | } | |||||
3287 | else { | |||||
3288 | /* Canonize the request URL port */ | |||||
3289 | if (tport) { | |||||
3290 | lv = agent_tport_via(tport_parent(tport)); assert(lv)((void) sizeof ((lv) ? 1 : 0), __extension__ ({ if (lv) ; else __assert_fail ("lv", "nta.c", 3290, __extension__ __PRETTY_FUNCTION__ ); })); | |||||
3291 | if (lv->v_port) | |||||
3292 | /* Add non-default port */ | |||||
3293 | url->url_port = lv->v_port; | |||||
3294 | return 1; | |||||
3295 | } | |||||
3296 | if (su_strmatch(url->url_port, url_port_default((enum url_type_e)url->url_type)) || | |||||
3297 | su_strmatch(url->url_port, "")) | |||||
3298 | /* Remove default or empty port */ | |||||
3299 | url->url_port = NULL((void*)0); | |||||
3300 | ||||||
3301 | return 0; | |||||
3302 | } | |||||
3303 | } | |||||
3304 | ||||||
3305 | /** @internal Handle incoming responses. */ | |||||
3306 | static | |||||
3307 | void agent_recv_response(nta_agent_t *agent, | |||||
3308 | msg_t *msg, | |||||
3309 | sip_t *sip, | |||||
3310 | sip_via_t *tport_via, | |||||
3311 | tport_t *tport) | |||||
3312 | { | |||||
3313 | int status = sip->sip_status->st_status; | |||||
3314 | int errors; | |||||
3315 | char const *phrase = sip->sip_status->st_phrase; | |||||
3316 | char const *method = | |||||
3317 | sip->sip_cseq ? sip->sip_cseq->cs_method_name : "<UNKNOWN>"; | |||||
3318 | uint32_t cseq = sip->sip_cseq ? sip->sip_cseq->cs_seq : 0; | |||||
3319 | nta_outgoing_t *orq; | |||||
3320 | su_home_t *home; | |||||
3321 | char const *branch = NONE((void *)-1); | |||||
3322 | ||||||
3323 | ||||||
3324 | agent->sa_stats->as_recv_msg++; | |||||
3325 | agent->sa_stats->as_recv_response++; | |||||
3326 | ||||||
3327 | SU_DEBUG_5(("nta: received %03d %s for %s (%u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3328, "nta: received %03d %s for %s (%u)\n", status, phrase , method, cseq)) : (void)0) | |||||
3328 | status, phrase, method, cseq))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3328, "nta: received %03d %s for %s (%u)\n", status, phrase , method, cseq)) : (void)0); | |||||
3329 | ||||||
3330 | if (agent->sa_drop_prob && !tport_is_reliable(tport)) { | |||||
3331 | if ((unsigned)su_randint(0, 1000) < agent->sa_drop_prob) { | |||||
3332 | SU_DEBUG_5(("nta: %03d %s %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3333, "nta: %03d %s %s\n", status, phrase, "dropped simulating packet loss" )) : (void)0) | |||||
3333 | status, phrase, "dropped simulating packet loss"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3333, "nta: %03d %s %s\n", status, phrase, "dropped simulating packet loss" )) : (void)0); | |||||
3334 | agent->sa_stats->as_drop_response++; | |||||
3335 | msg_destroy(msg); | |||||
3336 | return; | |||||
3337 | } | |||||
3338 | } | |||||
3339 | ||||||
3340 | if (agent->sa_bad_resp_mask) | |||||
3341 | errors = msg_extract_errors(msg) & agent->sa_bad_resp_mask; | |||||
3342 | else | |||||
3343 | errors = sip->sip_error != NULL((void*)0); | |||||
3344 | ||||||
3345 | if (errors || | |||||
3346 | sip_sanity_check(sip) < 0) { | |||||
3347 | sip_header_t const *h; | |||||
3348 | ||||||
3349 | agent->sa_stats->as_bad_response++; | |||||
3350 | agent->sa_stats->as_bad_message++; | |||||
3351 | ||||||
3352 | SU_DEBUG_5(("nta: %03d %s %s\n", status, phrase,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3355, "nta: %03d %s %s\n", status, phrase, errors ? "has fatal syntax errors" : "failed sanity check")) : (void)0) | |||||
3353 | errors(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3355, "nta: %03d %s %s\n", status, phrase, errors ? "has fatal syntax errors" : "failed sanity check")) : (void)0) | |||||
3354 | ? "has fatal syntax errors"(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3355, "nta: %03d %s %s\n", status, phrase, errors ? "has fatal syntax errors" : "failed sanity check")) : (void)0) | |||||
3355 | : "failed sanity check"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3355, "nta: %03d %s %s\n", status, phrase, errors ? "has fatal syntax errors" : "failed sanity check")) : (void)0); | |||||
3356 | ||||||
3357 | for (h = (sip_header_t const *)sip->sip_error; h; h = h->sh_nextsh_header_next->shn_next) { | |||||
3358 | if (h->sh_classsh_common->h_class->hc_name) { | |||||
3359 | SU_DEBUG_5(("nta: %03d has bad %s header\n", status,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3360, "nta: %03d has bad %s header\n", status, h->sh_common ->h_class->hc_name)) : (void)0) | |||||
3360 | h->sh_class->hc_name))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3360, "nta: %03d has bad %s header\n", status, h->sh_common ->h_class->hc_name)) : (void)0); | |||||
3361 | } | |||||
3362 | } | |||||
3363 | ||||||
3364 | msg_destroy(msg); | |||||
3365 | return; | |||||
3366 | } | |||||
3367 | ||||||
3368 | if (!su_casematch(sip->sip_status->st_version, sip_version_2_0)) { | |||||
3369 | agent->sa_stats->as_bad_response++; | |||||
3370 | agent->sa_stats->as_bad_message++; | |||||
3371 | ||||||
3372 | SU_DEBUG_5(("nta: bad version %s %03d %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3373, "nta: bad version %s %03d %s\n", sip->sip_status-> st_version, status, phrase)) : (void)0) | |||||
3373 | sip->sip_status->st_version, status, phrase))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3373, "nta: bad version %s %03d %s\n", sip->sip_status-> st_version, status, phrase)) : (void)0); | |||||
3374 | msg_destroy(msg); | |||||
3375 | return; | |||||
3376 | } | |||||
3377 | ||||||
3378 | if (sip->sip_cseq && sip->sip_cseq->cs_method == sip_method_ack) { | |||||
3379 | /* Drop response messages to ACK */ | |||||
3380 | agent->sa_stats->as_bad_response++; | |||||
3381 | agent->sa_stats->as_bad_message++; | |||||
3382 | SU_DEBUG_5(("nta: %03d %s %s\n", status, phrase, "is response to ACK"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3382, "nta: %03d %s %s\n", status, phrase, "is response to ACK" )) : (void)0); | |||||
3383 | msg_destroy(msg); | |||||
3384 | return; | |||||
3385 | } | |||||
3386 | ||||||
3387 | /* XXX - should check if msg should be discarded based on via? */ | |||||
3388 | ||||||
3389 | #ifdef HAVE_ZLIB_COMPRESS1 | |||||
3390 | sip_content_encoding_Xflate(msg, sip, 1, 1); | |||||
3391 | #endif | |||||
3392 | ||||||
3393 | if ((orq = outgoing_find(agent, msg, sip, sip->sip_via))) { | |||||
3394 | SU_DEBUG_5(("nta: %03d %s %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3395, "nta: %03d %s %s\n", status, phrase, "is going to a transaction" )) : (void)0) | |||||
3395 | status, phrase, "is going to a transaction"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3395, "nta: %03d %s %s\n", status, phrase, "is going to a transaction" )) : (void)0); | |||||
3396 | /* RFC3263 4.3 "503 error response" */ | |||||
3397 | if(agent->sa_srv_503 && status == 503 && outgoing_other_destinations(orq)) { | |||||
3398 | SU_DEBUG_5(("%s(%p): <%03d> for <%s>, %s\n", "nta", (void *)orq, status, method, "try next after timeout"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3398, "%s(%p): <%03d> for <%s>, %s\n", "nta", ( void *)orq, status, method, "try next after timeout")) : (void )0); | |||||
3399 | home = msg_home(msg)((su_home_t*)(msg)); | |||||
3400 | if (agent->sa_is_stateless) | |||||
3401 | branch = stateless_branch(agent, msg, sip, orq->orq_tpn); | |||||
3402 | else | |||||
3403 | branch = stateful_branch(home, agent); | |||||
3404 | ||||||
3405 | orq->orq_branch = branch; | |||||
3406 | orq->orq_via_branch = branch; | |||||
3407 | outgoing_try_another(orq); | |||||
3408 | return; | |||||
3409 | } | |||||
3410 | ||||||
3411 | if (outgoing_recv(orq, status, msg, sip) == 0) | |||||
3412 | return; | |||||
3413 | } | |||||
3414 | ||||||
3415 | ||||||
3416 | agent->sa_stats->as_trless_response++; | |||||
3417 | ||||||
3418 | if ((orq = agent->sa_default_outgoing)) { | |||||
3419 | SU_DEBUG_5(("nta: %03d %s %s\n", status, phrase,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3420, "nta: %03d %s %s\n", status, phrase, "to the default transaction" )) : (void)0) | |||||
3420 | "to the default transaction"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3420, "nta: %03d %s %s\n", status, phrase, "to the default transaction" )) : (void)0); | |||||
3421 | outgoing_default_recv(orq, status, msg, sip); | |||||
3422 | return; | |||||
3423 | } | |||||
3424 | else if (agent->sa_callback) { | |||||
3425 | SU_DEBUG_5(("nta: %03d %s %s\n", status, phrase, "to message callback"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3425, "nta: %03d %s %s\n", status, phrase, "to message callback" )) : (void)0); | |||||
3426 | /* | |||||
3427 | * Store message and transport to hook for the duration of the callback | |||||
3428 | * so that the transport can be obtained by nta_transport(). | |||||
3429 | */ | |||||
3430 | (void)agent->sa_callback(agent->sa_magic, agent, msg, sip); | |||||
3431 | return; | |||||
3432 | } | |||||
3433 | ||||||
3434 | if (sip->sip_cseq->cs_method == sip_method_invite | |||||
3435 | && 200 <= sip->sip_status->st_status | |||||
3436 | && sip->sip_status->st_status < 300 | |||||
3437 | /* Exactly one Via header, belonging to us */ | |||||
3438 | && sip->sip_via && !sip->sip_via->v_next | |||||
3439 | && agent_has_via(agent, sip->sip_via)) { | |||||
3440 | agent->sa_stats->as_trless_200++; | |||||
3441 | } | |||||
3442 | ||||||
3443 | SU_DEBUG_5(("nta: %03d %s %s\n", status, phrase, "was discarded"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3443, "nta: %03d %s %s\n", status, phrase, "was discarded") ) : (void)0); | |||||
3444 | msg_destroy(msg); | |||||
3445 | } | |||||
3446 | ||||||
3447 | /** @internal Agent receives garbage */ | |||||
3448 | static | |||||
3449 | void agent_recv_garbage(nta_agent_t *agent, | |||||
3450 | msg_t *msg, | |||||
3451 | tport_t *tport) | |||||
3452 | { | |||||
3453 | agent->sa_stats->as_recv_msg++; | |||||
3454 | agent->sa_stats->as_bad_message++; | |||||
3455 | ||||||
3456 | #if SU_DEBUG0 >= 3 | |||||
3457 | if (nta_log->log_level >= 3) { | |||||
3458 | tp_name_t tpn[1]; | |||||
3459 | ||||||
3460 | tport_delivered_from(tport, msg, tpn); | |||||
3461 | ||||||
3462 | SU_DEBUG_3(("nta_agent: received garbage from " TPN_FORMAT "\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 3463, "nta_agent: received garbage from " "%s/%s:%s%s%s%s%s" "\n", (tpn)->tpn_proto, (tpn)->tpn_host, (tpn)->tpn_port , (tpn)->tpn_comp ? ";comp=" : "", (tpn)->tpn_comp ? (tpn )->tpn_comp : "", (tpn)->tpn_ident ? "/" : "", (tpn)-> tpn_ident ? (tpn)->tpn_ident : "")) : (void)0) | |||||
3463 | TPN_ARGS(tpn)))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 3463, "nta_agent: received garbage from " "%s/%s:%s%s%s%s%s" "\n", (tpn)->tpn_proto, (tpn)->tpn_host, (tpn)->tpn_port , (tpn)->tpn_comp ? ";comp=" : "", (tpn)->tpn_comp ? (tpn )->tpn_comp : "", (tpn)->tpn_ident ? "/" : "", (tpn)-> tpn_ident ? (tpn)->tpn_ident : "")) : (void)0); | |||||
3464 | } | |||||
3465 | #endif | |||||
3466 | ||||||
3467 | msg_destroy(msg); | |||||
3468 | } | |||||
3469 | ||||||
3470 | /* ====================================================================== */ | |||||
3471 | /* 4) Message handling - create, complete, destroy */ | |||||
3472 | ||||||
3473 | /** Create a new message belonging to the agent */ | |||||
3474 | msg_t *nta_msg_create(nta_agent_t *agent, int flags) | |||||
3475 | { | |||||
3476 | msg_t *msg; | |||||
3477 | ||||||
3478 | if (agent == NULL((void*)0)) | |||||
3479 | return su_seterrno(EINVAL22), NULL((void*)0); | |||||
3480 | ||||||
3481 | msg = msg_create(agent->sa_mclass, agent->sa_flags | flags); | |||||
3482 | ||||||
3483 | if (agent->sa_preload) | |||||
3484 | su_home_preload(msg_home(msg)((su_home_t*)(msg)), 1, agent->sa_preload); | |||||
3485 | ||||||
3486 | return msg; | |||||
3487 | } | |||||
3488 | ||||||
3489 | /** Create a new message for transport */ | |||||
3490 | msg_t *nta_msg_create_for_transport(nta_agent_t *agent, int flags, | |||||
3491 | char const data[], usize_t dlen, | |||||
3492 | tport_t const *tport, tp_client_t *via) | |||||
3493 | { | |||||
3494 | msg_t *msg = msg_create(agent->sa_mclass, agent->sa_flags | flags); | |||||
3495 | ||||||
3496 | msg_maxsize(msg, agent->sa_maxsize); | |||||
3497 | ||||||
3498 | if (agent->sa_preload) | |||||
3499 | su_home_preload(msg_home(msg)((su_home_t*)(msg)), 1, dlen + agent->sa_preload); | |||||
3500 | ||||||
3501 | return msg; | |||||
3502 | } | |||||
3503 | ||||||
3504 | /** Complete a message. */ | |||||
3505 | int nta_msg_complete(msg_t *msg) | |||||
3506 | { | |||||
3507 | return sip_complete_message(msg); | |||||
3508 | } | |||||
3509 | ||||||
3510 | /** Discard a message */ | |||||
3511 | void nta_msg_discard(nta_agent_t *agent, msg_t *msg) | |||||
3512 | { | |||||
3513 | msg_destroy(msg); | |||||
3514 | } | |||||
3515 | ||||||
3516 | /** Check if the headers are from response generated locally by NTA. */ | |||||
3517 | int nta_sip_is_internal(sip_t const *sip) | |||||
3518 | { | |||||
3519 | return | |||||
3520 | sip == NULL((void*)0) /* No message generated */ | |||||
3521 | || (sip->sip_flags & NTA_INTERNAL_MSG(1<<15)) == NTA_INTERNAL_MSG(1<<15); | |||||
3522 | } | |||||
3523 | ||||||
3524 | /** Check if the message is internally generated by NTA. */ | |||||
3525 | int nta_msg_is_internal(msg_t const *msg) | |||||
3526 | { | |||||
3527 | return msg_get_flags(msg, NTA_INTERNAL_MSG(1<<15)) == NTA_INTERNAL_MSG(1<<15); | |||||
3528 | } | |||||
3529 | ||||||
3530 | /** Check if the message is internally generated by NTA. | |||||
3531 | * | |||||
3532 | * @deprecated Use nta_msg_is_internal() instead | |||||
3533 | */ | |||||
3534 | int nta_is_internal_msg(msg_t const *msg) { return nta_msg_is_internal(msg); } | |||||
3535 | ||||||
3536 | /* ====================================================================== */ | |||||
3537 | /* 5) Stateless operation */ | |||||
3538 | ||||||
3539 | /**Forward a request or response message. | |||||
3540 | * | |||||
3541 | * @note | |||||
3542 | * The ownership of @a msg is taken over by the function even if the | |||||
3543 | * function fails. | |||||
3544 | */ | |||||
3545 | int nta_msg_tsend(nta_agent_t *agent, msg_t *msg, url_string_t const *u, | |||||
3546 | tag_type_t tag, tag_value_t value, ...) | |||||
3547 | { | |||||
3548 | int retval = -1; | |||||
3549 | ta_list ta; | |||||
3550 | sip_t *sip = sip_object(msg); | |||||
3551 | tp_name_t tpn[1] = {{ NULL((void*)0) }}; | |||||
3552 | char const *what; | |||||
3553 | ||||||
3554 | if (!sip) { | |||||
3555 | msg_destroy(msg); | |||||
3556 | return -1; | |||||
3557 | } | |||||
3558 | ||||||
3559 | what = | |||||
3560 | sip->sip_status ? "nta_msg_tsend(response)" : | |||||
3561 | sip->sip_request ? "nta_msg_tsend(request)" : | |||||
3562 | "nta_msg_tsend()"; | |||||
3563 | ||||||
3564 | ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value = (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag ) == tag_next && (ta_start__value) != 0) { ta_start__tag = ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag == tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag == tag_next) { ta_start__value = ((tagi_t *)ta_start__value) ->t_value; } else { ta_start__tag = tag_next; break; } } ( ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value ; if (ta_start__tag != ((void*)0) && ta_start__tag != tag_null && ta_start__tag != tag_next) { va_list ta_start__ap ; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag = tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap ); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value = 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0); | |||||
3565 | ||||||
3566 | if (sip_add_tl(msg, sip, ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta). tl[1].t_value) < 0) | |||||
3567 | SU_DEBUG_3(("%s: cannot add headers\n", what))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 3567, "%s: cannot add headers\n", what)) : (void)0); | |||||
3568 | else if (sip->sip_status) { | |||||
3569 | tport_t *tport = NULL((void*)0); | |||||
3570 | int *use_rport = NULL((void*)0); | |||||
3571 | int retry_without_rport = 0; | |||||
3572 | ||||||
3573 | struct sigcomp_compartment *cc; cc = NONE((void *)-1); | |||||
3574 | ||||||
3575 | if (agent->sa_server_rport) | |||||
3576 | use_rport = &retry_without_rport, retry_without_rport = 1; | |||||
3577 | ||||||
3578 | tl_gets(ta_args(ta)(ta).tl, | |||||
3579 | NTATAG_TPORT_REF(tport)ntatag_tport_ref, tag_ptr_vr(&(tport), (tport)), | |||||
3580 | IF_SIGCOMP_TPTAG_COMPARTMENT_REF(cc)tptag_compartment_ref, tag_ptr_vr(&(cc), cc), | |||||
3581 | /* NTATAG_INCOMPLETE_REF(incomplete), */ | |||||
3582 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
3583 | ||||||
3584 | if (!sip->sip_separator && | |||||
3585 | !(sip->sip_separator = sip_separator_create(msg_home(msg)((su_home_t*)(msg))))) | |||||
3586 | SU_DEBUG_3(("%s: cannot create sip_separator\n", what))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 3586, "%s: cannot create sip_separator\n", what)) : (void)0 ); | |||||
3587 | else if (msg_serialize(msg, (msg_pub_t *)sip) != 0) | |||||
3588 | SU_DEBUG_3(("%s: sip_serialize() failed\n", what))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 3588, "%s: sip_serialize() failed\n", what)) : (void)0); | |||||
3589 | else if (!sip_via_remove(msg, sip)) | |||||
3590 | SU_DEBUG_3(("%s: cannot remove Via\n", what))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 3590, "%s: cannot remove Via\n", what)) : (void)0); | |||||
3591 | else if (nta_tpn_by_via(tpn, sip->sip_via, use_rport) < 0) | |||||
3592 | SU_DEBUG_3(("%s: bad via\n", what))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 3592, "%s: bad via\n", what)) : (void)0); | |||||
3593 | else { | |||||
3594 | if (!tport) | |||||
3595 | tport = tport_by_name(agent->sa_tports, tpn); | |||||
3596 | if (!tport) | |||||
3597 | tport = tport_by_protocol(agent->sa_tports, tpn->tpn_proto); | |||||
3598 | ||||||
3599 | if (retry_without_rport) | |||||
3600 | tpn->tpn_port = sip_via_port(sip->sip_via, NULL((void*)0)); | |||||
3601 | ||||||
3602 | if (tport && tpn->tpn_comp && cc == NONE((void *)-1)) | |||||
3603 | cc = agent_compression_compartment(agent, tport, tpn, -1); | |||||
3604 | ||||||
3605 | if (tport_tsend(tport, msg, tpn, | |||||
3606 | IF_SIGCOMP_TPTAG_COMPARTMENT(cc)!(cc && cc != ((void *)-1)) ? tag_skip : tptag_compartment , tag_ptr_v((cc)), | |||||
3607 | TPTAG_MTU(INT_MAX)tptag_mtu, tag_usize_v((2147483647)), ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta). tl[1].t_value, TAG_END()(tag_type_t)0, (tag_value_t)0)) { | |||||
3608 | agent->sa_stats->as_sent_msg++; | |||||
3609 | agent->sa_stats->as_sent_response++; | |||||
3610 | retval = 0; | |||||
3611 | } | |||||
3612 | else { | |||||
3613 | SU_DEBUG_3(("%s: send fails\n", what))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 3613, "%s: send fails\n", what)) : (void)0); | |||||
3614 | } | |||||
3615 | } | |||||
3616 | } | |||||
3617 | else { | |||||
3618 | /* Send request */ | |||||
3619 | if (outgoing_create(agent, NULL((void*)0), NULL((void*)0), u, NULL((void*)0), msg_ref_create(msg), | |||||
3620 | NTATAG_STATELESS(1)ntatag_stateless, tag_bool_v((1)), | |||||
3621 | ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta). tl[1].t_value)) | |||||
3622 | retval = 0; | |||||
3623 | } | |||||
3624 | ||||||
3625 | if (retval == 0) | |||||
3626 | SU_DEBUG_5(("%s\n", what))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 3626, "%s\n", what)) : (void)0); | |||||
3627 | ||||||
3628 | ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value ))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta) .ap)); | |||||
3629 | ||||||
3630 | msg_destroy(msg); | |||||
3631 | ||||||
3632 | return retval; | |||||
3633 | } | |||||
3634 | ||||||
3635 | /** Reply to a request message. | |||||
3636 | * | |||||
3637 | * @param agent nta agent object | |||||
3638 | * @param req_msg request message | |||||
3639 | * @param status status code | |||||
3640 | * @param phrase status phrase (may be NULL if status code is well-known) | |||||
3641 | * @param tag, value, ... optional additional headers terminated by TAG_END() | |||||
3642 | * | |||||
3643 | * @retval 0 when succesful | |||||
3644 | * @retval -1 upon an error | |||||
3645 | * | |||||
3646 | * @note | |||||
3647 | * The ownership of @a msg is taken over by the function even if the | |||||
3648 | * function fails. | |||||
3649 | */ | |||||
3650 | int nta_msg_treply(nta_agent_t *agent, | |||||
3651 | msg_t *req_msg, | |||||
3652 | int status, char const *phrase, | |||||
3653 | tag_type_t tag, tag_value_t value, ...) | |||||
3654 | { | |||||
3655 | int retval; | |||||
3656 | ta_list ta; | |||||
3657 | ||||||
3658 | ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value = (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag ) == tag_next && (ta_start__value) != 0) { ta_start__tag = ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag == tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag == tag_next) { ta_start__value = ((tagi_t *)ta_start__value) ->t_value; } else { ta_start__tag = tag_next; break; } } ( ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value ; if (ta_start__tag != ((void*)0) && ta_start__tag != tag_null && ta_start__tag != tag_next) { va_list ta_start__ap ; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag = tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap ); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value = 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0); | |||||
3659 | ||||||
3660 | retval = mreply(agent, NULL((void*)0), status, phrase, req_msg, | |||||
3661 | NULL((void*)0), 0, 0, NULL((void*)0), | |||||
3662 | ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta). tl[1].t_value); | |||||
3663 | ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value ))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta) .ap)); | |||||
3664 | ||||||
3665 | return retval; | |||||
3666 | } | |||||
3667 | ||||||
3668 | /**Reply to the request message. | |||||
3669 | * | |||||
3670 | * @note | |||||
3671 | * The ownership of @a msg is taken over by the function even if the | |||||
3672 | * function fails. | |||||
3673 | */ | |||||
3674 | int nta_msg_mreply(nta_agent_t *agent, | |||||
3675 | msg_t *reply, sip_t *sip, | |||||
3676 | int status, char const *phrase, | |||||
3677 | msg_t *req_msg, | |||||
3678 | tag_type_t tag, tag_value_t value, ...) | |||||
3679 | { | |||||
3680 | int retval = -1; | |||||
3681 | ta_list ta; | |||||
3682 | ||||||
3683 | ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value = (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag ) == tag_next && (ta_start__value) != 0) { ta_start__tag = ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag == tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag == tag_next) { ta_start__value = ((tagi_t *)ta_start__value) ->t_value; } else { ta_start__tag = tag_next; break; } } ( ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value ; if (ta_start__tag != ((void*)0) && ta_start__tag != tag_null && ta_start__tag != tag_next) { va_list ta_start__ap ; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag = tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap ); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value = 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0); | |||||
3684 | ||||||
3685 | retval = mreply(agent, reply, status, phrase, req_msg, | |||||
3686 | NULL((void*)0), 0, 0, NULL((void*)0), | |||||
3687 | ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta). tl[1].t_value); | |||||
3688 | ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value ))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta) .ap)); | |||||
3689 | ||||||
3690 | return retval; | |||||
3691 | } | |||||
3692 | ||||||
3693 | static | |||||
3694 | int mreply(nta_agent_t *agent, | |||||
3695 | msg_t *reply, | |||||
3696 | int status, char const *phrase, | |||||
3697 | msg_t *req_msg, | |||||
3698 | tport_t *tport, | |||||
3699 | int incomplete, | |||||
3700 | int sdwn_after, | |||||
3701 | char const *to_tag, | |||||
3702 | tag_type_t tag, tag_value_t value, ...) | |||||
3703 | { | |||||
3704 | ta_list ta; | |||||
3705 | sip_t *sip; | |||||
3706 | int *use_rport = NULL((void*)0); | |||||
3707 | int retry_without_rport = 0; | |||||
3708 | tp_name_t tpn[1]; | |||||
3709 | int retval = -1; | |||||
3710 | ||||||
3711 | if (!agent) | |||||
3712 | return -1; | |||||
3713 | ||||||
3714 | if (agent->sa_server_rport) | |||||
3715 | use_rport = &retry_without_rport, retry_without_rport = 1; | |||||
3716 | ||||||
3717 | ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value = (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag ) == tag_next && (ta_start__value) != 0) { ta_start__tag = ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag == tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag == tag_next) { ta_start__value = ((tagi_t *)ta_start__value) ->t_value; } else { ta_start__tag = tag_next; break; } } ( ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value ; if (ta_start__tag != ((void*)0) && ta_start__tag != tag_null && ta_start__tag != tag_next) { va_list ta_start__ap ; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag = tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap ); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value = 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0); | |||||
3718 | ||||||
3719 | tl_gets(ta_args(ta)(ta).tl, NTATAG_TPORT_REF(tport)ntatag_tport_ref, tag_ptr_vr(&(tport), (tport)), TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
3720 | ||||||
3721 | if (reply == NULL((void*)0)) { | |||||
3722 | reply = nta_msg_create(agent, 0); | |||||
3723 | } | |||||
3724 | sip = sip_object(reply); | |||||
3725 | ||||||
3726 | if (!sip) { | |||||
3727 | SU_DEBUG_3(("%s: cannot create response msg\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 3727, "%s: cannot create response msg\n", __func__)) : (void )0); | |||||
3728 | } | |||||
3729 | else if (sip_add_tl(reply, sip, ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta). tl[1].t_value) < 0) { | |||||
3730 | SU_DEBUG_3(("%s: cannot add user headers\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 3730, "%s: cannot add user headers\n", __func__)) : (void)0 ); | |||||
3731 | } | |||||
3732 | else if (complete_response(reply, status, phrase, req_msg) < 0 && | |||||
3733 | !incomplete) { | |||||
3734 | SU_DEBUG_3(("%s: cannot complete message\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 3734, "%s: cannot complete message\n", __func__)) : (void)0 ); | |||||
3735 | } | |||||
3736 | else if (sip->sip_status && sip->sip_status->st_status > 100 && | |||||
3737 | sip->sip_to && !sip->sip_to->a_tag && | |||||
3738 | (to_tag == NONE((void *)-1) ? 0 : | |||||
3739 | to_tag != NULL((void*)0) | |||||
3740 | ? sip_to_tag(msg_home(reply)((su_home_t*)(reply)), sip->sip_to, to_tag) < 0 | |||||
3741 | : sip_to_tag(msg_home(reply)((su_home_t*)(reply)), sip->sip_to, | |||||
3742 | nta_agent_newtag(msg_home(reply)((su_home_t*)(reply)), "tag=%s", agent)) < 0)) { | |||||
3743 | SU_DEBUG_3(("%s: cannot add To tag\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 3743, "%s: cannot add To tag\n", __func__)) : (void)0); | |||||
3744 | } | |||||
3745 | else if (nta_tpn_by_via(tpn, sip->sip_via, use_rport) < 0) { | |||||
3746 | SU_DEBUG_3(("%s: no Via\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 3746, "%s: no Via\n", __func__)) : (void)0); | |||||
3747 | } | |||||
3748 | else { | |||||
3749 | struct sigcomp_compartment *cc = NONE((void *)-1); | |||||
3750 | ||||||
3751 | if (tport == NULL((void*)0)) | |||||
3752 | tport = tport_delivered_by(agent->sa_tports, req_msg); | |||||
3753 | ||||||
3754 | if (!tport) { | |||||
3755 | tport_t *primary = tport_by_protocol(agent->sa_tports, tpn->tpn_proto); | |||||
3756 | ||||||
3757 | tport = tport_by_name(primary, tpn); | |||||
3758 | ||||||
3759 | if (!tport) | |||||
3760 | tport = primary; | |||||
3761 | } | |||||
3762 | ||||||
3763 | if (retry_without_rport) | |||||
3764 | tpn->tpn_port = sip_via_port(sip->sip_via, NULL((void*)0)); | |||||
3765 | ||||||
3766 | if (tport && tpn->tpn_comp) { | |||||
3767 | tl_gets(ta_args(ta)(ta).tl, TPTAG_COMPARTMENT_REF(cc)tptag_compartment_ref, tag_ptr_vr(&(cc), cc), | |||||
3768 | /* XXX - should also check ntatag_sigcomp_close() */ | |||||
3769 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
3770 | if (cc == NONE((void *)-1)) | |||||
3771 | cc = agent_compression_compartment(agent, tport, tpn, -1); | |||||
3772 | ||||||
3773 | if (cc != NULL((void*)0) && cc != NONE((void *)-1) && | |||||
3774 | tport_delivered_with_comp(tport, req_msg, NULL((void*)0)) != -1) { | |||||
3775 | agent_accept_compressed(agent, req_msg, cc); | |||||
3776 | } | |||||
3777 | } | |||||
3778 | ||||||
3779 | if (tport_tsend(tport, reply, tpn, | |||||
3780 | IF_SIGCOMP_TPTAG_COMPARTMENT(cc)!(cc && cc != ((void *)-1)) ? tag_skip : tptag_compartment , tag_ptr_v((cc)), | |||||
3781 | TPTAG_MTU(INT_MAX)tptag_mtu, tag_usize_v((2147483647)), | |||||
3782 | TPTAG_SDWN_AFTER(sdwn_after)tptag_sdwn_after, tag_bool_v((sdwn_after)), | |||||
3783 | ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta). tl[1].t_value)) { | |||||
3784 | agent->sa_stats->as_sent_msg++; | |||||
3785 | agent->sa_stats->as_sent_response++; | |||||
3786 | retval = 0; /* Success! */ | |||||
3787 | } | |||||
3788 | else { | |||||
3789 | SU_DEBUG_3(("%s: send fails\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 3789, "%s: send fails\n", __func__)) : (void)0); | |||||
3790 | } | |||||
3791 | } | |||||
3792 | ||||||
3793 | msg_destroy(reply); | |||||
3794 | msg_destroy(req_msg); | |||||
3795 | ||||||
3796 | ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value ))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta) .ap)); | |||||
3797 | ||||||
3798 | return retval; | |||||
3799 | } | |||||
3800 | ||||||
3801 | /** Add headers from the request to the response message. */ | |||||
3802 | static | |||||
3803 | int complete_response(msg_t *response, | |||||
3804 | int status, char const *phrase, | |||||
3805 | msg_t *request) | |||||
3806 | { | |||||
3807 | su_home_t *home = msg_home(response)((su_home_t*)(response)); | |||||
3808 | sip_t *response_sip = sip_object(response); | |||||
3809 | sip_t const *request_sip = sip_object(request); | |||||
3810 | ||||||
3811 | int incomplete = 0; | |||||
3812 | ||||||
3813 | if (!response_sip || !request_sip || !request_sip->sip_request) | |||||
3814 | return -1; | |||||
3815 | ||||||
3816 | if (!response_sip->sip_status) | |||||
3817 | response_sip->sip_status = sip_status_create(home, status, phrase, NULL((void*)0)); | |||||
3818 | if (!response_sip->sip_via) | |||||
3819 | response_sip->sip_via = sip_via_dup(home, request_sip->sip_via); | |||||
3820 | if (!response_sip->sip_from) | |||||
3821 | response_sip->sip_from = sip_from_dup(home, request_sip->sip_from); | |||||
3822 | if (!response_sip->sip_to) | |||||
3823 | response_sip->sip_to = sip_to_dup(home, request_sip->sip_to); | |||||
3824 | if (!response_sip->sip_call_id) | |||||
3825 | response_sip->sip_call_id = | |||||
3826 | sip_call_id_dup(home, request_sip->sip_call_id); | |||||
3827 | if (!response_sip->sip_cseq) | |||||
3828 | response_sip->sip_cseq = sip_cseq_dup(home, request_sip->sip_cseq); | |||||
3829 | ||||||
3830 | if (!response_sip->sip_record_route && request_sip->sip_record_route) | |||||
3831 | sip_add_dup(response, response_sip, (void*)request_sip->sip_record_route); | |||||
3832 | ||||||
3833 | incomplete = sip_complete_message(response) < 0; | |||||
3834 | ||||||
3835 | msg_serialize(response, (msg_pub_t *)response_sip); | |||||
3836 | ||||||
3837 | if (incomplete || | |||||
3838 | !response_sip->sip_status || | |||||
3839 | !response_sip->sip_via || | |||||
3840 | !response_sip->sip_from || | |||||
3841 | !response_sip->sip_to || | |||||
3842 | !response_sip->sip_call_id || | |||||
3843 | !response_sip->sip_cseq || | |||||
3844 | !response_sip->sip_content_length || | |||||
3845 | !response_sip->sip_separator || | |||||
3846 | (request_sip->sip_record_route && !response_sip->sip_record_route)) | |||||
3847 | return -1; | |||||
3848 | ||||||
3849 | return 0; | |||||
3850 | } | |||||
3851 | ||||||
3852 | /** ACK and BYE an unknown 200 OK response to INVITE. | |||||
3853 | * | |||||
3854 | * A UAS may still return a 2XX series response to client request after the | |||||
3855 | * client transactions has been terminated. In that case, the UAC can not | |||||
3856 | * really accept the call. This function was used to accept and immediately | |||||
3857 | * terminate such a call. | |||||
3858 | * | |||||
3859 | * @deprecated This was a bad idea: see sf.net bug #1750691. It can be used | |||||
3860 | * to amplify DoS attacks. Let UAS take care of retransmission timeout and | |||||
3861 | * let it terminate the session. As of @VERSION_1_12_7, this function just | |||||
3862 | * returns -1. | |||||
3863 | */ | |||||
3864 | int nta_msg_ackbye(nta_agent_t *agent, msg_t *msg) | |||||
3865 | { | |||||
3866 | sip_t *sip = sip_object(msg); | |||||
3867 | msg_t *amsg = nta_msg_create(agent, 0); | |||||
3868 | sip_t *asip = sip_object(amsg); | |||||
3869 | msg_t *bmsg = NULL((void*)0); | |||||
3870 | sip_t *bsip; | |||||
3871 | url_string_t const *ruri; | |||||
3872 | nta_outgoing_t *ack = NULL((void*)0), *bye = NULL((void*)0); | |||||
3873 | sip_cseq_t *cseq; | |||||
3874 | sip_request_t *rq; | |||||
3875 | sip_route_t *route = NULL((void*)0), *r, r0[1]; | |||||
3876 | su_home_t *home = msg_home(amsg)((su_home_t*)(amsg)); | |||||
3877 | ||||||
3878 | if (asip == NULL((void*)0)) | |||||
3879 | return -1; | |||||
3880 | ||||||
3881 | sip_add_tl(amsg, asip, | |||||
3882 | SIPTAG_TO(sip->sip_to)siptag_to, siptag_to_v(sip->sip_to), | |||||
3883 | SIPTAG_FROM(sip->sip_from)siptag_from, siptag_from_v(sip->sip_from), | |||||
3884 | SIPTAG_CALL_ID(sip->sip_call_id)siptag_call_id, siptag_call_id_v(sip->sip_call_id), | |||||
3885 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
3886 | ||||||
3887 | if (sip->sip_contact) { | |||||
3888 | ruri = (url_string_t const *)sip->sip_contact->m_url; | |||||
3889 | } else { | |||||
3890 | ruri = (url_string_t const *)sip->sip_to->a_url; | |||||
3891 | } | |||||
3892 | ||||||
3893 | /* Reverse (and fix) record route */ | |||||
3894 | route = sip_route_reverse(home, sip->sip_record_route); | |||||
3895 | ||||||
3896 | if (route && !url_has_param(route->r_url, "lr")) { | |||||
3897 | for (r = route; r->r_next; r = r->r_next) | |||||
3898 | ; | |||||
3899 | ||||||
3900 | /* Append r-uri */ | |||||
3901 | *sip_route_init(r0)->r_url = *ruri->us_url; | |||||
3902 | r->r_next = sip_route_dup(home, r0); | |||||
3903 | ||||||
3904 | /* Use topmost route as request-uri */ | |||||
3905 | ruri = (url_string_t const *)route->r_url; | |||||
3906 | route = route->r_next; | |||||
3907 | } | |||||
3908 | ||||||
3909 | msg_header_insert(amsg, (msg_pub_t *)asip, (msg_header_t *)route); | |||||
3910 | ||||||
3911 | bmsg = msg_copy(amsg); bsip = sip_object(bmsg); | |||||
3912 | ||||||
3913 | if (!(cseq = sip_cseq_create(home, sip->sip_cseq->cs_seq, SIP_METHOD_ACKsip_method_ack, "ACK"))) | |||||
3914 | goto err; | |||||
3915 | else | |||||
3916 | msg_header_insert(amsg, (msg_pub_t *)asip, (msg_header_t *)cseq); | |||||
3917 | ||||||
3918 | if (!(rq = sip_request_create(home, SIP_METHOD_ACKsip_method_ack, "ACK", ruri, NULL((void*)0)))) | |||||
3919 | goto err; | |||||
3920 | else | |||||
3921 | msg_header_insert(amsg, (msg_pub_t *)asip, (msg_header_t *)rq); | |||||
3922 | ||||||
3923 | if (!(ack = nta_outgoing_mcreate(agent, NULL((void*)0), NULL((void*)0), NULL((void*)0), amsg, | |||||
3924 | NTATAG_ACK_BRANCH(sip->sip_via->v_branch)ntatag_ack_branch, tag_str_v((sip->sip_via->v_branch)), | |||||
3925 | NTATAG_STATELESS(1)ntatag_stateless, tag_bool_v((1)), | |||||
3926 | TAG_END()(tag_type_t)0, (tag_value_t)0))) | |||||
3927 | goto err; | |||||
3928 | else | |||||
3929 | nta_outgoing_destroy(ack); | |||||
3930 | ||||||
3931 | home = msg_home(bmsg)((su_home_t*)(bmsg)); | |||||
3932 | ||||||
3933 | if (!(cseq = sip_cseq_create(home, 0x7fffffff, SIP_METHOD_BYEsip_method_bye, "BYE"))) | |||||
3934 | goto err; | |||||
3935 | else | |||||
3936 | msg_header_insert(bmsg, (msg_pub_t *)bsip, (msg_header_t *)cseq); | |||||
3937 | ||||||
3938 | if (!(rq = sip_request_create(home, SIP_METHOD_BYEsip_method_bye, "BYE", ruri, NULL((void*)0)))) | |||||
3939 | goto err; | |||||
3940 | else | |||||
3941 | msg_header_insert(bmsg, (msg_pub_t *)bsip, (msg_header_t *)rq); | |||||
3942 | ||||||
3943 | if (!(bye = nta_outgoing_mcreate(agent, NULL((void*)0), NULL((void*)0), NULL((void*)0), bmsg, | |||||
3944 | NTATAG_STATELESS(1)ntatag_stateless, tag_bool_v((1)), | |||||
3945 | TAG_END()(tag_type_t)0, (tag_value_t)0))) | |||||
3946 | goto err; | |||||
3947 | ||||||
3948 | msg_destroy(msg); | |||||
3949 | return 0; | |||||
3950 | ||||||
3951 | err: | |||||
3952 | ||||||
3953 | msg_destroy(bmsg); | |||||
3954 | msg_destroy(amsg); | |||||
3955 | ||||||
3956 | return -1; | |||||
3957 | } | |||||
3958 | ||||||
3959 | /**Complete a request with values from dialog. | |||||
3960 | * | |||||
3961 | * Complete a request message @a msg belonging to a dialog associated with | |||||
3962 | * @a leg. It increments the local @CSeq value, adds @CallID, @To, @From and | |||||
3963 | * @Route headers (if there is such headers present in @a leg), and creates | |||||
3964 | * a new request line object from @a method, @a method_name and @a | |||||
3965 | * request_uri. | |||||
3966 | * | |||||
3967 | * @param msg pointer to a request message object | |||||
3968 | * @param leg pointer to a #nta_leg_t object | |||||
3969 | * @param method request method number or #sip_method_unknown | |||||
3970 | * @param method_name method name (if @a method == #sip_method_unknown) | |||||
3971 | * @param request_uri request URI | |||||
3972 | * | |||||
3973 | * If @a request_uri contains query part, the query part is converted as SIP | |||||
3974 | * headers and added to the request. | |||||
3975 | * | |||||
3976 | * @retval 0 when successful | |||||
3977 | * @retval -1 upon an error | |||||
3978 | * | |||||
3979 | * @sa nta_outgoing_mcreate(), nta_outgoing_tcreate() | |||||
3980 | */ | |||||
3981 | int nta_msg_request_complete(msg_t *msg, | |||||
3982 | nta_leg_t *leg, | |||||
3983 | sip_method_t method, | |||||
3984 | char const *method_name, | |||||
3985 | url_string_t const *request_uri) | |||||
3986 | { | |||||
3987 | su_home_t *home = msg_home(msg)((su_home_t*)(msg)); | |||||
3988 | sip_t *sip = sip_object(msg); | |||||
3989 | sip_to_t const *to; | |||||
3990 | uint32_t seq; | |||||
3991 | url_t reg_url[1]; | |||||
3992 | url_string_t const *original = request_uri; | |||||
3993 | ||||||
3994 | if (!leg || !msg || !sip) | |||||
3995 | return -1; | |||||
3996 | ||||||
3997 | if (!sip->sip_route && leg->leg_route) { | |||||
3998 | if (leg->leg_loose_route) { | |||||
3999 | if (leg->leg_target) { | |||||
4000 | request_uri = (url_string_t *)leg->leg_target->m_url; | |||||
4001 | } | |||||
4002 | sip->sip_route = sip_route_dup(home, leg->leg_route); | |||||
4003 | } | |||||
4004 | else { | |||||
4005 | sip_route_t **rr; | |||||
4006 | ||||||
4007 | request_uri = (url_string_t *)leg->leg_route->r_url; | |||||
4008 | sip->sip_route = sip_route_dup(home, leg->leg_route->r_next); | |||||
4009 | ||||||
4010 | for (rr = &sip->sip_route; *rr; rr = &(*rr)->r_next) | |||||
4011 | ; | |||||
4012 | ||||||
4013 | if (leg->leg_target) | |||||
4014 | *rr = sip_route_dup(home, (sip_route_t *)leg->leg_target); | |||||
4015 | } | |||||
4016 | } | |||||
4017 | else if (leg->leg_target) | |||||
4018 | request_uri = (url_string_t *)leg->leg_target->m_url; | |||||
4019 | ||||||
4020 | if (!request_uri && sip->sip_request) | |||||
4021 | request_uri = (url_string_t *)sip->sip_request->rq_url; | |||||
4022 | ||||||
4023 | to = sip->sip_to ? sip->sip_to : leg->leg_remote; | |||||
4024 | ||||||
4025 | if (!request_uri && to) { | |||||
4026 | if (method != sip_method_register) | |||||
4027 | request_uri = (url_string_t *)to->a_url; | |||||
4028 | else { | |||||
4029 | /* Remove user part from REGISTER requests */ | |||||
4030 | *reg_url = *to->a_url; | |||||
4031 | reg_url->url_user = reg_url->url_password = NULL((void*)0); | |||||
4032 | request_uri = (url_string_t *)reg_url; | |||||
4033 | } | |||||
4034 | } | |||||
4035 | ||||||
4036 | if (!request_uri) | |||||
4037 | return -1; | |||||
4038 | ||||||
4039 | if (method || method_name) { | |||||
4040 | sip_request_t *rq = sip->sip_request; | |||||
4041 | int use_headers = | |||||
4042 | request_uri == original || (url_t *)request_uri == rq->rq_url; | |||||
4043 | ||||||
4044 | if (!rq | |||||
4045 | || request_uri != (url_string_t *)rq->rq_url | |||||
4046 | || method != rq->rq_method | |||||
4047 | || !su_strmatch(method_name, rq->rq_method_name)) | |||||
4048 | rq = NULL((void*)0); | |||||
4049 | ||||||
4050 | if (rq == NULL((void*)0)) { | |||||
4051 | rq = sip_request_create(home, method, method_name, request_uri, NULL((void*)0)); | |||||
4052 | if (msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)rq) < 0) | |||||
4053 | return -1; | |||||
4054 | } | |||||
4055 | ||||||
4056 | /* @RFC3261 table 1 (page 152): | |||||
4057 | * Req-URI cannot contain method parameter or headers | |||||
4058 | */ | |||||
4059 | if (rq->rq_url->url_params) { | |||||
4060 | rq->rq_url->url_params = | |||||
4061 | url_strip_param_string((char *)rq->rq_url->url_params, "method"); | |||||
4062 | sip_fragment_clear(rq->rq_common)((rq->rq_common)->h_data = ((void*)0), (rq->rq_common )->h_len = 0); | |||||
4063 | } | |||||
4064 | ||||||
4065 | if (rq->rq_url->url_headers) { | |||||
4066 | if (use_headers) { | |||||
4067 | char *s = url_query_as_header_string(msg_home(msg)((su_home_t*)(msg)), | |||||
4068 | rq->rq_url->url_headers); | |||||
4069 | if (!s) | |||||
4070 | return -1; | |||||
4071 | msg_header_parse_str(msg, (msg_pub_t*)sip, s); | |||||
4072 | } | |||||
4073 | rq->rq_url->url_headers = NULL((void*)0), sip_fragment_clear(rq->rq_common)((rq->rq_common)->h_data = ((void*)0), (rq->rq_common )->h_len = 0); | |||||
4074 | } | |||||
4075 | } | |||||
4076 | ||||||
4077 | if (!sip->sip_request) | |||||
4078 | return -1; | |||||
4079 | ||||||
4080 | if (!sip->sip_max_forwards) | |||||
4081 | sip_add_dup(msg, sip, (sip_header_t *)leg->leg_agent->sa_max_forwards); | |||||
4082 | ||||||
4083 | if (!sip->sip_from) | |||||
4084 | sip->sip_from = sip_from_dup(home, leg->leg_local); | |||||
4085 | else if (leg->leg_local && leg->leg_local->a_tag && | |||||
4086 | (!sip->sip_from->a_tag || | |||||
4087 | !su_casematch(sip->sip_from->a_tag, leg->leg_local->a_tag))) | |||||
4088 | sip_from_tag(home, sip->sip_from, leg->leg_local->a_tag); | |||||
4089 | ||||||
4090 | if (sip->sip_from && !sip->sip_from->a_tag) { | |||||
4091 | sip_fragment_clear(sip->sip_from->a_common)((sip->sip_from->a_common)->h_data = ((void*)0), (sip ->sip_from->a_common)->h_len = 0); | |||||
4092 | sip_from_add_param(home, sip->sip_from, | |||||
4093 | nta_agent_newtag(home, "tag=%s", leg->leg_agent)); | |||||
4094 | } | |||||
4095 | ||||||
4096 | if (sip->sip_to) { | |||||
4097 | if (leg->leg_remote && leg->leg_remote->a_tag) | |||||
4098 | sip_to_tag(home, sip->sip_to, leg->leg_remote->a_tag); | |||||
4099 | } | |||||
4100 | else if (leg->leg_remote) { | |||||
4101 | sip->sip_to = sip_to_dup(home, leg->leg_remote); | |||||
4102 | } | |||||
4103 | else { | |||||
4104 | sip_to_t *to = sip_to_create(home, request_uri); | |||||
4105 | if (to) sip_aor_strip(to->a_url); | |||||
4106 | sip->sip_to = to; | |||||
4107 | } | |||||
4108 | ||||||
4109 | if (!sip->sip_from || !sip->sip_from || !sip->sip_to) | |||||
4110 | return -1; | |||||
4111 | ||||||
4112 | method = sip->sip_request->rq_method; | |||||
4113 | method_name = sip->sip_request->rq_method_name; | |||||
4114 | ||||||
4115 | if (!leg->leg_id && sip->sip_cseq) | |||||
4116 | seq = sip->sip_cseq->cs_seq; | |||||
4117 | else if (method == sip_method_ack || method == sip_method_cancel) | |||||
4118 | /* Dangerous - we may do PRACK/UPDATE meanwhile */ | |||||
4119 | seq = sip->sip_cseq ? sip->sip_cseq->cs_seq : leg->leg_seq; | |||||
4120 | else if (leg->leg_seq) | |||||
4121 | seq = ++leg->leg_seq; | |||||
4122 | else if (sip->sip_cseq) /* Obtain initial value from existing CSeq header */ | |||||
4123 | seq = leg->leg_seq = sip->sip_cseq->cs_seq; | |||||
4124 | else | |||||
4125 | seq = leg->leg_seq = (sip_now() >> 1) & 0x7ffffff; | |||||
4126 | ||||||
4127 | if (!sip->sip_call_id) { | |||||
4128 | if (leg->leg_id) | |||||
4129 | sip->sip_call_id = sip_call_id_dup(home, leg->leg_id); | |||||
4130 | else | |||||
4131 | sip->sip_call_id = sip_call_id_create(home, NULL((void*)0)); | |||||
4132 | } | |||||
4133 | ||||||
4134 | if (!sip->sip_cseq || | |||||
4135 | seq != sip->sip_cseq->cs_seq || | |||||
4136 | method != sip->sip_cseq->cs_method || | |||||
4137 | !su_strmatch(method_name, sip->sip_cseq->cs_method_name)) { | |||||
4138 | sip_cseq_t *cseq = sip_cseq_create(home, seq, method, method_name); | |||||
4139 | if (msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)cseq) < 0) | |||||
4140 | return -1; | |||||
4141 | } | |||||
4142 | ||||||
4143 | return 0; | |||||
4144 | } | |||||
4145 | ||||||
4146 | /* ====================================================================== */ | |||||
4147 | /* 6) Dialogs (legs) */ | |||||
4148 | ||||||
4149 | static void leg_insert(nta_agent_t *agent, nta_leg_t *leg); | |||||
4150 | static int leg_route(nta_leg_t *leg, | |||||
4151 | sip_record_route_t const *route, | |||||
4152 | sip_record_route_t const *reverse, | |||||
4153 | sip_contact_t const *contact, | |||||
4154 | int reroute); | |||||
4155 | static int leg_callback_default(nta_leg_magic_t*, nta_leg_t*, | |||||
4156 | nta_incoming_t*, sip_t const *); | |||||
4157 | #define HTABLE_HASH_LEG(leg)((leg)->leg_hash) ((leg)->leg_hash) | |||||
4158 | ||||||
4159 | #ifdef __clang__1 | |||||
4160 | #pragma clang diagnostic push | |||||
4161 | #pragma clang diagnostic ignored "-Wunused-function" | |||||
4162 | #endif | |||||
4163 | ||||||
4164 | 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, collisions = 0; if (new_size == 0) new_size = 2 * lht->lht_size + 1; if (new_size < 31) new_size = 31; if (new_size < 5 * lht->lht_used / 4 ) new_size = 5 * lht->lht_used / 4; if (!(new_hash = su_zalloc (home, sizeof(*new_hash) * new_size))) return -1; old_size = lht ->lht_size; do for (j = 0; j < old_size; j++) { if (!old_hash [j]) continue; if (again < 2 && ((old_hash[j])-> leg_hash) % old_size > j) { again = 1; continue; } i0 = (( old_hash[j])->leg_hash) % new_size; for (i = i0; new_hash[ i]; i = (i + 1) % new_size, ((void) sizeof ((i != i0) ? 1 : 0 ), __extension__ ({ if (i != i0) ; else __assert_fail ("i != i0" , "nta.c", 4164, __extension__ __PRETTY_FUNCTION__); }))) collisions ++; new_hash[i] = old_hash[j], old_hash[j] = ((void*)0); used ++; } while (again++ == 1); lht->lht_table = new_hash, lht ->lht_size = new_size; ((void) sizeof ((lht->lht_used == used) ? 1 : 0), __extension__ ({ if (lht->lht_used == used ) ; else __assert_fail ("lht->lht_used == used", "nta.c", 4164 , __extension__ __PRETTY_FUNCTION__); })); su_free(home, old_hash ); return 0; } static inline int leg_htable_is_full(leg_htable_t const *lht) { return lht->lht_table == ((void*)0) || 3 * lht ->lht_used > 2 * lht->lht_size; } static inline nta_leg_t **leg_htable_hash(leg_htable_t const *lht, hash_value_t hv) { return lht->lht_table + hv % lht->lht_size; } static inline nta_leg_t **leg_htable_next(leg_htable_t const *lht, nta_leg_t * const *ee) { if (++ee < lht->lht_table + lht->lht_size && ee >= lht->lht_table) return (nta_leg_t **) ee; else return lht->lht_table; } static inline void leg_htable_append (leg_htable_t *lht, nta_leg_t const *e) { nta_leg_t **ee; lht ->lht_used++; for (ee = leg_htable_hash(lht, ((e)->leg_hash )); *ee; ee = leg_htable_next(lht, ee)) ; *ee = (nta_leg_t *) e; } static inline void leg_htable_insert(leg_htable_t *lht, nta_leg_t const *e) { nta_leg_t *e0, **ee; lht->lht_used++; for (ee = leg_htable_hash(lht, ((e)->leg_hash)); (e0 = *ee); ee = leg_htable_next(lht, ee)) *ee = (nta_leg_t *)e, e = e0; *ee = (nta_leg_t *)e; } static inline int leg_htable_remove(leg_htable_t *lht, nta_leg_t const *e) { size_t i, j, k; size_t size = lht ->lht_size; nta_leg_t **htable = lht->lht_table; if (!e ) return -1; for (i = ((e)->leg_hash) % size; htable[i]; i = (i + 1) % size) if (e == htable[i]) break; if (!htable[i]) return -1; for (j = (i + 1) % size; htable[j]; j = (j + 1) % size) { k = ((htable[j])->leg_hash) % size; if (k == j) continue ; if (j > i ? (i < k && k < j) : (i < k || k < j)) continue; htable[i] = htable[j], i = j; } lht-> lht_used--; htable[i] = ((void*)0); return 0; } extern int leg_htable_dummy; | |||||
4165 | ||||||
4166 | #ifdef __clang__1 | |||||
4167 | #pragma clang diagnostic pop | |||||
4168 | #endif | |||||
4169 | ||||||
4170 | su_inlinestatic inline | |||||
4171 | hash_value_t hash_istring(char const *, char const *, hash_value_t); | |||||
4172 | ||||||
4173 | /**@typedef nta_request_f | |||||
4174 | * | |||||
4175 | * Callback for incoming requests | |||||
4176 | * | |||||
4177 | * This is a callback function invoked by NTA for each incoming SIP request. | |||||
4178 | * | |||||
4179 | * @param lmagic call leg context | |||||
4180 | * @param leg call leg handle | |||||
4181 | * @param ireq incoming request | |||||
4182 | * @param sip incoming request contents | |||||
4183 | * | |||||
4184 | * @retval 100..699 | |||||
4185 | * NTA constructs a reply message with given error code and corresponding | |||||
4186 | * standard phrase, then sends the reply. | |||||
4187 | * | |||||
4188 | * @retval 0 | |||||
4189 | * The application takes care of sending (or not sending) the reply. | |||||
4190 | * | |||||
4191 | * @retval other | |||||
4192 | * All other return values will be interpreted as | |||||
4193 | * @e 500 @e Internal @e server @e error. | |||||
4194 | */ | |||||
4195 | ||||||
4196 | ||||||
4197 | /** | |||||
4198 | * Create a new leg object. | |||||
4199 | * | |||||
4200 | * Creates a leg object, which is used to represent dialogs, partial dialogs | |||||
4201 | * (for example, in case of REGISTER), and destinations within a particular | |||||
4202 | * NTA object. | |||||
4203 | * | |||||
4204 | * When a leg is created, a callback pointer and a application context is | |||||
4205 | * provided. All other parameters are optional. | |||||
4206 | * | |||||
4207 | * @param agent agent object | |||||
4208 | * @param callback function which is called for each | |||||
4209 | * incoming request belonging to this leg | |||||
4210 | * @param magic call leg context | |||||
4211 | * @param tag,value,... optional extra headers in taglist | |||||
4212 | * | |||||
4213 | * When a leg representing dialog is created, the tags SIPTAG_CALL_ID(), | |||||
4214 | * SIPTAG_FROM(), SIPTAG_TO(), and SIPTAG_CSEQ() (for local @CSeq number) are used | |||||
4215 | * to establish dialog context. The SIPTAG_FROM() is used to pass local | |||||
4216 | * address (@From header when making a call, @To header when answering | |||||
4217 | * to a call) to the newly created leg. Respectively, the SIPTAG_TO() is | |||||
4218 | * used to pass remote address (@To header when making a call, @From | |||||
4219 | * header when answering to a call). | |||||
4220 | * | |||||
4221 | * If there is a (preloaded) route associated with the leg, SIPTAG_ROUTE() | |||||
4222 | * and NTATAG_TARGET() can be used. A client or server can also set the | |||||
4223 | * route using @RecordRoute and @Contact headers from a response or | |||||
4224 | * request message with the functions nta_leg_client_route() and | |||||
4225 | * nta_leg_server_route(), respectively. | |||||
4226 | * | |||||
4227 | * When a leg representing a local destination is created, the tags | |||||
4228 | * NTATAG_NO_DIALOG(1), NTATAG_METHOD(), and URLTAG_URL() are used. When a | |||||
4229 | * request with matching request-URI (URLTAG_URL()) and method | |||||
4230 | * (NTATAG_METHOD()) is received, it is passed to the callback function | |||||
4231 | * provided with the leg. | |||||
4232 | * | |||||
4233 | * @sa nta_leg_stateful(), nta_leg_bind(), | |||||
4234 | * nta_leg_tag(), nta_leg_rtag(), | |||||
4235 | * nta_leg_client_route(), nta_leg_server_route(), | |||||
4236 | * nta_leg_destroy(), nta_outgoing_tcreate(), and nta_request_f(). | |||||
4237 | * | |||||
4238 | * @TAGS | |||||
4239 | * NTATAG_NO_DIALOG(), NTATAG_STATELESS(), NTATAG_METHOD(), | |||||
4240 | * URLTAG_URL(), SIPTAG_CALL_ID(), SIPTAG_CALL_ID_STR(), SIPTAG_FROM(), | |||||
4241 | * SIPTAG_FROM_STR(), SIPTAG_TO(), SIPTAG_TO_STR(), SIPTAG_ROUTE(), | |||||
4242 | * NTATAG_TARGET() and SIPTAG_CSEQ(). | |||||
4243 | * | |||||
4244 | */ | |||||
4245 | nta_leg_t *nta_leg_tcreate(nta_agent_t *agent, | |||||
4246 | nta_request_f *callback, | |||||
4247 | nta_leg_magic_t *magic, | |||||
4248 | tag_type_t tag, tag_value_t value, ...) | |||||
4249 | { | |||||
4250 | sip_route_t const *route = NULL((void*)0); | |||||
4251 | sip_contact_t const *contact = NULL((void*)0); | |||||
4252 | sip_cseq_t const *cs = NULL((void*)0); | |||||
4253 | sip_call_id_t const *i = NULL((void*)0); | |||||
4254 | sip_from_t const *from = NULL((void*)0); | |||||
4255 | sip_to_t const *to = NULL((void*)0); | |||||
4256 | char const *method = NULL((void*)0); | |||||
4257 | char const *i_str = NULL((void*)0), *to_str = NULL((void*)0), *from_str = NULL((void*)0), *cs_str = NULL((void*)0); | |||||
4258 | url_string_t const *url_string = NULL((void*)0); | |||||
4259 | int no_dialog = 0; | |||||
4260 | unsigned rseq = 0; | |||||
4261 | /* RFC 3261 section 12.2.1.1 */ | |||||
4262 | uint32_t seq = 0; | |||||
4263 | ta_list ta; | |||||
4264 | nta_leg_t *leg; | |||||
4265 | su_home_t *home; | |||||
4266 | url_t *url; | |||||
4267 | char const *what = NULL((void*)0); | |||||
4268 | ||||||
4269 | if (agent == NULL((void*)0)) | |||||
4270 | return su_seterrno(EINVAL22), NULL((void*)0); | |||||
4271 | ||||||
4272 | ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value = (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag ) == tag_next && (ta_start__value) != 0) { ta_start__tag = ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag == tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag == tag_next) { ta_start__value = ((tagi_t *)ta_start__value) ->t_value; } else { ta_start__tag = tag_next; break; } } ( ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value ; if (ta_start__tag != ((void*)0) && ta_start__tag != tag_null && ta_start__tag != tag_next) { va_list ta_start__ap ; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag = tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap ); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value = 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0); | |||||
4273 | ||||||
4274 | tl_gets(ta_args(ta)(ta).tl, | |||||
4275 | NTATAG_NO_DIALOG_REF(no_dialog)ntatag_no_dialog_ref, tag_bool_vr(&(no_dialog)), | |||||
4276 | NTATAG_METHOD_REF(method)ntatag_method_ref, tag_str_vr(&(method)), | |||||
4277 | URLTAG_URL_REF(url_string)urltag_url_ref, urltag_url_vr(&(url_string)), | |||||
4278 | SIPTAG_CALL_ID_REF(i)siptag_call_id_ref, siptag_call_id_vr(&(i)), | |||||
4279 | SIPTAG_CALL_ID_STR_REF(i_str)siptag_call_id_str_ref, tag_str_vr(&(i_str)), | |||||
4280 | SIPTAG_FROM_REF(from)siptag_from_ref, siptag_from_vr(&(from)), | |||||
4281 | SIPTAG_FROM_STR_REF(from_str)siptag_from_str_ref, tag_str_vr(&(from_str)), | |||||
4282 | SIPTAG_TO_REF(to)siptag_to_ref, siptag_to_vr(&(to)), | |||||
4283 | SIPTAG_TO_STR_REF(to_str)siptag_to_str_ref, tag_str_vr(&(to_str)), | |||||
4284 | SIPTAG_ROUTE_REF(route)siptag_route_ref, siptag_route_vr(&(route)), | |||||
4285 | NTATAG_TARGET_REF(contact)ntatag_target_ref, siptag_contact_vr(&(contact)), | |||||
4286 | NTATAG_REMOTE_CSEQ_REF(rseq)ntatag_remote_cseq_ref, tag_uint_vr(&(rseq)), | |||||
4287 | SIPTAG_CSEQ_REF(cs)siptag_cseq_ref, siptag_cseq_vr(&(cs)), | |||||
4288 | SIPTAG_CSEQ_STR_REF(cs_str)siptag_cseq_str_ref, tag_str_vr(&(cs_str)), | |||||
4289 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
4290 | ||||||
4291 | ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value ))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta) .ap)); | |||||
4292 | ||||||
4293 | if (cs) | |||||
4294 | seq = cs->cs_seq; | |||||
4295 | else if (cs_str) | |||||
4296 | seq = strtoul(cs_str, (char **)&cs_str, 10); | |||||
4297 | ||||||
4298 | if (i == NONE((void *)-1)) /* Magic value, used for compatibility */ | |||||
4299 | no_dialog = 1; | |||||
4300 | ||||||
4301 | if (!(leg = su_home_clone(NULL((void*)0), sizeof(*leg)))) | |||||
4302 | return NULL((void*)0); | |||||
4303 | home = leg->leg_home; | |||||
4304 | ||||||
4305 | leg->leg_agent = agent; | |||||
4306 | nta_leg_bind(leg, callback, magic); | |||||
4307 | ||||||
4308 | if (from) { | |||||
4309 | /* Now this is kludge */ | |||||
4310 | leg->leg_local_is_to = sip_is_to((sip_header_t*)from); | |||||
4311 | leg->leg_local = sip_to_dup(home, from); | |||||
4312 | } | |||||
4313 | else if (from_str) | |||||
4314 | leg->leg_local = sip_to_make(home, from_str); | |||||
4315 | ||||||
4316 | if (to && no_dialog) { | |||||
4317 | /* Remove tag, if any */ | |||||
4318 | sip_to_t to0[1]; *to0 = *to; to0->a_params = NULL((void*)0); | |||||
4319 | leg->leg_remote = sip_from_dup(home, to0); | |||||
4320 | } | |||||
4321 | else if (to) | |||||
4322 | leg->leg_remote = sip_from_dup(home, to); | |||||
4323 | else if (to_str) | |||||
4324 | leg->leg_remote = sip_from_make(home, to_str); | |||||
4325 | ||||||
4326 | if (route && route != NONE((void *)-1)) | |||||
4327 | leg->leg_route = sip_route_dup(home, route), leg->leg_route_set = 1; | |||||
4328 | ||||||
4329 | if (contact && contact != NONE((void *)-1)) { | |||||
4330 | sip_contact_t m[1]; | |||||
4331 | sip_contact_init(m); | |||||
4332 | *m->m_url = *contact->m_url; | |||||
4333 | m->m_url->url_headers = NULL((void*)0); | |||||
4334 | leg->leg_target = sip_contact_dup(home, m); | |||||
4335 | } | |||||
4336 | ||||||
4337 | url = url_hdup(home, url_string->us_url); | |||||
4338 | ||||||
4339 | /* Match to local hosts */ | |||||
4340 | if (url && agent_aliases(agent, url, NULL((void*)0))) { | |||||
4341 | url_t *changed = url_hdup(home, url); | |||||
4342 | su_free(home, url); | |||||
4343 | url = changed; | |||||
4344 | } | |||||
4345 | ||||||
4346 | leg->leg_rseq = rseq; | |||||
4347 | leg->leg_seq = seq; | |||||
4348 | leg->leg_url = url; | |||||
4349 | ||||||
4350 | if (from && from != NONE((void *)-1) && leg->leg_local == NULL((void*)0)) { | |||||
4351 | what = "cannot duplicate local address"; | |||||
4352 | goto err; | |||||
4353 | } | |||||
4354 | else if (to && to != NONE((void *)-1) && leg->leg_remote == NULL((void*)0)) { | |||||
4355 | what = "cannot duplicate remote address"; | |||||
4356 | goto err; | |||||
4357 | } | |||||
4358 | else if (route && route != NONE((void *)-1) && leg->leg_route == NULL((void*)0)) { | |||||
4359 | what = "cannot duplicate route"; | |||||
4360 | goto err; | |||||
4361 | } | |||||
4362 | else if (contact && contact != NONE((void *)-1) && leg->leg_target == NULL((void*)0)) { | |||||
4363 | what = "cannot duplicate target"; | |||||
4364 | goto err; | |||||
4365 | } | |||||
4366 | else if (url_string && leg->leg_url == NULL((void*)0)) { | |||||
4367 | what = "cannot duplicate local destination"; | |||||
4368 | goto err; | |||||
4369 | } | |||||
4370 | ||||||
4371 | if (!no_dialog) { | |||||
4372 | if (!leg->leg_local || !leg->leg_remote) { | |||||
4373 | /* To and/or From header missing */ | |||||
4374 | if (leg->leg_remote) | |||||
4375 | what = "Missing local dialog address"; | |||||
4376 | else if (leg->leg_local) | |||||
4377 | what = "Missing remote dialog address"; | |||||
4378 | else | |||||
4379 | what = "Missing dialog addresses"; | |||||
4380 | goto err; | |||||
4381 | } | |||||
4382 | ||||||
4383 | leg->leg_dialog = 1; | |||||
4384 | ||||||
4385 | if (i != NULL((void*)0)) | |||||
4386 | leg->leg_id = sip_call_id_dup(home, i); | |||||
4387 | else if (i_str != NULL((void*)0)) | |||||
4388 | leg->leg_id = sip_call_id_make(home, i_str); | |||||
4389 | else | |||||
4390 | leg->leg_id = sip_call_id_create(home, NULL((void*)0)); | |||||
4391 | ||||||
4392 | if (!leg->leg_id) { | |||||
4393 | what = "cannot create Call-ID"; | |||||
4394 | goto err; | |||||
4395 | } | |||||
4396 | ||||||
4397 | leg->leg_hash = leg->leg_id->i_hash; | |||||
4398 | } | |||||
4399 | else if (url) { | |||||
4400 | /* This is "default leg" with a destination URL. */ | |||||
4401 | hash_value_t hash = 0; | |||||
4402 | ||||||
4403 | if (method) { | |||||
4404 | leg->leg_method = su_strdup(home, method); | |||||
4405 | } | |||||
4406 | #if 0 | |||||
4407 | else if (url->url_params) { | |||||
4408 | int len = url_param(url->url_params, "method", NULL((void*)0), 0); | |||||
4409 | if (len) { | |||||
4410 | char *tmp = su_alloc(home, len); | |||||
4411 | leg->leg_method = tmp; | |||||
4412 | url_param(url->url_params, "method", tmp, len); | |||||
4413 | } | |||||
4414 | } | |||||
4415 | #endif | |||||
4416 | ||||||
4417 | if (url->url_user && strcmp(url->url_user, "") == 0) | |||||
4418 | url->url_user = "%"; /* Match to any user */ | |||||
4419 | ||||||
4420 | hash = hash_istring(url->url_scheme, ":", 0); | |||||
4421 | hash = hash_istring(url->url_host, "", hash); | |||||
4422 | hash = hash_istring(url->url_user, "@", hash); | |||||
4423 | ||||||
4424 | leg->leg_hash = hash; | |||||
4425 | } | |||||
4426 | else { | |||||
4427 | /* This is "default leg" without a destination URL. */ | |||||
4428 | if (agent->sa_default_leg) { | |||||
4429 | SU_DEBUG_1(("%s(): %s\n", "nta_leg_tcreate", "tried to create second default leg"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 4429, "%s(): %s\n", "nta_leg_tcreate", "tried to create second default leg" )) : (void)0); | |||||
4430 | su_seterrno(EEXIST17); | |||||
4431 | goto err; | |||||
4432 | } | |||||
4433 | else { | |||||
4434 | agent->sa_default_leg = leg; | |||||
4435 | } | |||||
4436 | return leg; | |||||
4437 | } | |||||
4438 | ||||||
4439 | if (url) { | |||||
4440 | /* Parameters are ignored when comparing incoming URLs */ | |||||
4441 | url->url_params = NULL((void*)0); | |||||
4442 | } | |||||
4443 | ||||||
4444 | leg_insert(agent, leg); | |||||
4445 | ||||||
4446 | SU_DEBUG_9(("%s(%p)\n", "nta_leg_tcreate", (void *)leg))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 4446, "%s(%p)\n", "nta_leg_tcreate", (void *)leg)) : (void) 0); | |||||
4447 | ||||||
4448 | return leg; | |||||
4449 | ||||||
4450 | err: | |||||
4451 | if (what) | |||||
4452 | SU_DEBUG_9(("%s(): %s\n", "nta_leg_tcreate", what))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 4452, "%s(): %s\n", "nta_leg_tcreate", what)) : (void)0); | |||||
4453 | ||||||
4454 | su_home_zap(leg->leg_home)su_home_unref((leg->leg_home)); | |||||
4455 | ||||||
4456 | return NULL((void*)0); | |||||
4457 | } | |||||
4458 | ||||||
4459 | /** Return the default leg, if any */ | |||||
4460 | nta_leg_t *nta_default_leg(nta_agent_t const *agent) | |||||
4461 | { | |||||
4462 | return agent ? agent->sa_default_leg : NULL((void*)0); | |||||
4463 | } | |||||
4464 | ||||||
4465 | ||||||
4466 | /** | |||||
4467 | * Insert a call leg to agent. | |||||
4468 | */ | |||||
4469 | static | |||||
4470 | void leg_insert(nta_agent_t *sa, nta_leg_t *leg) | |||||
4471 | { | |||||
4472 | leg_htable_t *leg_hash; | |||||
4473 | assert(leg)((void) sizeof ((leg) ? 1 : 0), __extension__ ({ if (leg) ; else __assert_fail ("leg", "nta.c", 4473, __extension__ __PRETTY_FUNCTION__ ); })); | |||||
4474 | assert(sa)((void) sizeof ((sa) ? 1 : 0), __extension__ ({ if (sa) ; else __assert_fail ("sa", "nta.c", 4474, __extension__ __PRETTY_FUNCTION__ ); })); | |||||
4475 | ||||||
4476 | if (leg->leg_dialog) | |||||
4477 | leg_hash = sa->sa_dialogs; | |||||
4478 | else | |||||
4479 | leg_hash = sa->sa_defaults; | |||||
4480 | ||||||
4481 | if (leg_htable_is_full(leg_hash)) { | |||||
4482 | leg_htable_resize(sa->sa_home, leg_hash, 0); | |||||
4483 | assert(leg_hash->lht_table)((void) sizeof ((leg_hash->lht_table) ? 1 : 0), __extension__ ({ if (leg_hash->lht_table) ; else __assert_fail ("leg_hash->lht_table" , "nta.c", 4483, __extension__ __PRETTY_FUNCTION__); })); | |||||
4484 | SU_DEBUG_7(("nta: resized%s leg hash to "MOD_ZU"\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__ , 4485, "nta: resized%s leg hash to ""%zu""\n", leg->leg_dialog ? "" : " default", leg_hash->lht_size)) : (void)0) | |||||
4485 | leg->leg_dialog ? "" : " default", leg_hash->lht_size))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__ , 4485, "nta: resized%s leg hash to ""%zu""\n", leg->leg_dialog ? "" : " default", leg_hash->lht_size)) : (void)0); | |||||
4486 | } | |||||
4487 | ||||||
4488 | /* Insert entry into hash table (before other legs with same hash) */ | |||||
4489 | leg_htable_insert(leg_hash, leg); | |||||
4490 | } | |||||
4491 | ||||||
4492 | /** | |||||
4493 | * Destroy a leg. | |||||
4494 | * | |||||
4495 | * @param leg leg to be destroyed | |||||
4496 | */ | |||||
4497 | void nta_leg_destroy(nta_leg_t *leg) | |||||
4498 | { | |||||
4499 | SU_DEBUG_9(("nta_leg_destroy(%p)\n", (void *)leg))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 4499, "nta_leg_destroy(%p)\n", (void *)leg)) : (void)0); | |||||
4500 | ||||||
4501 | if (leg) { | |||||
4502 | leg_htable_t *leg_hash; | |||||
4503 | nta_agent_t *sa = leg->leg_agent; | |||||
4504 | ||||||
4505 | assert(sa)((void) sizeof ((sa) ? 1 : 0), __extension__ ({ if (sa) ; else __assert_fail ("sa", "nta.c", 4505, __extension__ __PRETTY_FUNCTION__ ); })); | |||||
4506 | ||||||
4507 | if (leg->leg_dialog) { | |||||
4508 | assert(sa->sa_dialogs)((void) sizeof ((sa->sa_dialogs) ? 1 : 0), __extension__ ( { if (sa->sa_dialogs) ; else __assert_fail ("sa->sa_dialogs" , "nta.c", 4508, __extension__ __PRETTY_FUNCTION__); })); | |||||
4509 | leg_hash = sa->sa_dialogs; | |||||
4510 | } | |||||
4511 | else if (leg != sa->sa_default_leg) { | |||||
4512 | assert(sa->sa_defaults)((void) sizeof ((sa->sa_defaults) ? 1 : 0), __extension__ ( { if (sa->sa_defaults) ; else __assert_fail ("sa->sa_defaults" , "nta.c", 4512, __extension__ __PRETTY_FUNCTION__); })); | |||||
4513 | leg_hash = sa->sa_defaults; | |||||
4514 | } | |||||
4515 | else { | |||||
4516 | sa->sa_default_leg = NULL((void*)0); | |||||
4517 | leg_hash = NULL((void*)0); | |||||
4518 | } | |||||
4519 | ||||||
4520 | if (leg_hash) | |||||
4521 | leg_htable_remove(leg_hash, leg); | |||||
4522 | ||||||
4523 | leg_free(sa, leg); | |||||
4524 | } | |||||
4525 | } | |||||
4526 | ||||||
4527 | static | |||||
4528 | void leg_free(nta_agent_t *sa, nta_leg_t *leg) | |||||
4529 | { | |||||
4530 | //su_free(sa->sa_home, leg); | |||||
4531 | su_home_unref((su_home_t *)leg); | |||||
4532 | } | |||||
4533 | ||||||
4534 | /** Return application context for the leg */ | |||||
4535 | nta_leg_magic_t *nta_leg_magic(nta_leg_t const *leg, | |||||
4536 | nta_request_f *callback) | |||||
4537 | { | |||||
4538 | if (leg) | |||||
4539 | if (!callback || leg->leg_callback == callback) | |||||
4540 | return leg->leg_magic; | |||||
4541 | ||||||
4542 | return NULL((void*)0); | |||||
4543 | } | |||||
4544 | ||||||
4545 | /**Bind a callback function and context to a leg object. | |||||
4546 | * | |||||
4547 | * Change the callback function and context pointer attached to a leg | |||||
4548 | * object. | |||||
4549 | * | |||||
4550 | * @param leg leg object to be bound | |||||
4551 | * @param callback new callback function (or NULL if no callback is desired) | |||||
4552 | * @param magic new context pointer | |||||
4553 | */ | |||||
4554 | void nta_leg_bind(nta_leg_t *leg, | |||||
4555 | nta_request_f *callback, | |||||
4556 | nta_leg_magic_t *magic) | |||||
4557 | { | |||||
4558 | if (leg) { | |||||
4559 | if (callback) | |||||
4560 | leg->leg_callback = callback; | |||||
4561 | else | |||||
4562 | leg->leg_callback = leg_callback_default; | |||||
4563 | leg->leg_magic = magic; | |||||
4564 | } | |||||
4565 | } | |||||
4566 | ||||||
4567 | /** Add a local tag to the leg. | |||||
4568 | * | |||||
4569 | * @param leg leg to be tagged | |||||
4570 | * @param tag tag to be added (if NULL, a tag generated by @b NTA is added) | |||||
4571 | * | |||||
4572 | * @return | |||||
4573 | * Pointer to tag if successful, NULL otherwise. | |||||
4574 | */ | |||||
4575 | char const *nta_leg_tag(nta_leg_t *leg, char const *tag) | |||||
4576 | { | |||||
4577 | if (!leg || !leg->leg_local) | |||||
4578 | return su_seterrno(EINVAL22), NULL((void*)0); | |||||
4579 | ||||||
4580 | if (tag && strchr(tag, '=')) | |||||
4581 | tag = strchr(tag, '=') + 1; | |||||
4582 | ||||||
4583 | /* If there already is a tag, | |||||
4584 | return NULL if it does not match with new one */ | |||||
4585 | if (leg->leg_local->a_tag) { | |||||
4586 | if (tag == NULL((void*)0) || su_casematch(tag, leg->leg_local->a_tag)) | |||||
4587 | return leg->leg_local->a_tag; | |||||
4588 | else | |||||
4589 | return NULL((void*)0); | |||||
4590 | } | |||||
4591 | ||||||
4592 | if (tag) { | |||||
4593 | if (sip_to_tag(leg->leg_home, leg->leg_local, tag) < 0) | |||||
4594 | return NULL((void*)0); | |||||
4595 | leg->leg_tagged = 1; | |||||
4596 | return leg->leg_local->a_tag; | |||||
4597 | } | |||||
4598 | ||||||
4599 | tag = nta_agent_newtag(leg->leg_home, "tag=%s", leg->leg_agent); | |||||
4600 | ||||||
4601 | if (!tag || sip_to_add_param(leg->leg_home, leg->leg_local, tag) < 0) | |||||
4602 | return NULL((void*)0); | |||||
4603 | ||||||
4604 | leg->leg_tagged = 1; | |||||
4605 | ||||||
4606 | return leg->leg_local->a_tag; | |||||
4607 | } | |||||
4608 | ||||||
4609 | /** Get local tag. */ | |||||
4610 | char const *nta_leg_get_tag(nta_leg_t const *leg) | |||||
4611 | { | |||||
4612 | if (leg && leg->leg_local) | |||||
4613 | return leg->leg_local->a_tag; | |||||
4614 | else | |||||
4615 | return NULL((void*)0); | |||||
4616 | } | |||||
4617 | ||||||
4618 | /** Add a remote tag to the leg. | |||||
4619 | * | |||||
4620 | * @note No remote tag is ever generated. | |||||
4621 | * | |||||
4622 | * @param leg leg to be tagged | |||||
4623 | * @param tag tag to be added (@b must be non-NULL) | |||||
4624 | * | |||||
4625 | * @return | |||||
4626 | * Pointer to tag if successful, NULL otherwise. | |||||
4627 | */ | |||||
4628 | char const *nta_leg_rtag(nta_leg_t *leg, char const *tag) | |||||
4629 | { | |||||
4630 | /* Add a tag parameter, unless there already is a tag */ | |||||
4631 | if (leg && leg->leg_remote && tag) { | |||||
4632 | if (sip_from_tag(leg->leg_home, leg->leg_remote, tag) < 0) | |||||
4633 | return NULL((void*)0); | |||||
4634 | } | |||||
4635 | ||||||
4636 | if (leg && leg->leg_remote) | |||||
4637 | return leg->leg_remote->a_tag; | |||||
4638 | else | |||||
4639 | return NULL((void*)0); | |||||
4640 | } | |||||
4641 | ||||||
4642 | /** Get remote tag. */ | |||||
4643 | char const *nta_leg_get_rtag(nta_leg_t const *leg) | |||||
4644 | { | |||||
4645 | if (leg && leg->leg_remote) | |||||
4646 | return leg->leg_remote->a_tag; | |||||
4647 | else | |||||
4648 | return NULL((void*)0); | |||||
4649 | } | |||||
4650 | ||||||
4651 | /** Get local request sequence number. */ | |||||
4652 | uint32_t nta_leg_get_seq(nta_leg_t const *leg) | |||||
4653 | { | |||||
4654 | return leg ? leg->leg_seq : 0; | |||||
4655 | } | |||||
4656 | ||||||
4657 | /** Get remote request sequence number. */ | |||||
4658 | uint32_t nta_leg_get_rseq(nta_leg_t const *leg) | |||||
4659 | { | |||||
4660 | return leg ? leg->leg_rseq : 0; | |||||
4661 | } | |||||
4662 | ||||||
4663 | /** Save target and route set at UAC side. | |||||
4664 | * | |||||
4665 | * @sa nta_leg_client_reroute(), nta_leg_server_route(), @RFC3261 section 12.1.2 | |||||
4666 | * | |||||
4667 | * @bug Allows modifying the route set after initial transaction, if initial | |||||
4668 | * transaction had no @RecordRoute headers. | |||||
4669 | * | |||||
4670 | * @deprecated Use nta_leg_client_reroute() instead. | |||||
4671 | */ | |||||
4672 | int nta_leg_client_route(nta_leg_t *leg, | |||||
4673 | sip_record_route_t const *route, | |||||
4674 | sip_contact_t const *contact) | |||||
4675 | { | |||||
4676 | return leg_route(leg, NULL((void*)0), route, contact, 0); | |||||
4677 | } | |||||
4678 | ||||||
4679 | /** Save target and route set at UAC side. | |||||
4680 | * | |||||
4681 | * If @a initial is true, the route set is modified even if it has been set | |||||
4682 | * earlier. | |||||
4683 | * | |||||
4684 | * @param leg pointer to dialog leg | |||||
4685 | * @param route @RecordRoute headers from response | |||||
4686 | * @param contact @Contact header from response | |||||
4687 | * @param initial true if response to initial transaction | |||||
4688 | * | |||||
4689 | * @sa nta_leg_client_route(), nta_leg_server_route(), @RFC3261 section 12.1.2 | |||||
4690 | * | |||||
4691 | * @NEW_1_12_11 | |||||
4692 | */ | |||||
4693 | int nta_leg_client_reroute(nta_leg_t *leg, | |||||
4694 | sip_record_route_t const *route, | |||||
4695 | sip_contact_t const *contact, | |||||
4696 | int initial) | |||||
4697 | { | |||||
4698 | return leg_route(leg, NULL((void*)0), route, contact, initial ? 2 : 1); | |||||
4699 | } | |||||
4700 | ||||||
4701 | /** Save target and route set at UAS side. | |||||
4702 | * | |||||
4703 | * @param leg pointer to dialog leg | |||||
4704 | * @param route @RecordRoute headers from request | |||||
4705 | * @param contact @Contact header from request | |||||
4706 | * | |||||
4707 | * @sa nta_leg_client_reroute(), @RFC3261 section 12.1.1 | |||||
4708 | */ | |||||
4709 | int nta_leg_server_route(nta_leg_t *leg, | |||||
4710 | sip_record_route_t const *route, | |||||
4711 | sip_contact_t const *contact) | |||||
4712 | { | |||||
4713 | return leg_route(leg, route, NULL((void*)0), contact, 1); | |||||
4714 | } | |||||
4715 | ||||||
4716 | /** Return route components. */ | |||||
4717 | int nta_leg_get_route(nta_leg_t *leg, | |||||
4718 | sip_route_t const **return_route, | |||||
4719 | sip_contact_t const **return_target) | |||||
4720 | { | |||||
4721 | if (!leg) | |||||
4722 | return -1; | |||||
4723 | ||||||
4724 | if (return_route) | |||||
4725 | *return_route = leg->leg_route; | |||||
4726 | ||||||
4727 | if (return_target) | |||||
4728 | *return_target = leg->leg_target; | |||||
4729 | ||||||
4730 | return 0; | |||||
4731 | } | |||||
4732 | ||||||
4733 | /** Generate @Replaces header. | |||||
4734 | * | |||||
4735 | * @since New in @VERSION_1_12_2. | |||||
4736 | */ | |||||
4737 | sip_replaces_t * | |||||
4738 | nta_leg_make_replaces(nta_leg_t *leg, | |||||
4739 | su_home_t *home, | |||||
4740 | int early_only) | |||||
4741 | { | |||||
4742 | char const *from_tag, *to_tag; | |||||
4743 | ||||||
4744 | if (!leg) | |||||
4745 | return NULL((void*)0); | |||||
4746 | if (!leg->leg_dialog || !leg->leg_local || !leg->leg_remote || !leg->leg_id) | |||||
4747 | return NULL((void*)0); | |||||
4748 | ||||||
4749 | from_tag = leg->leg_local->a_tag; if (!from_tag) from_tag = "0"; | |||||
4750 | to_tag = leg->leg_remote->a_tag; if (!to_tag) to_tag = "0"; | |||||
4751 | ||||||
4752 | return sip_replaces_format(home, "%s;from-tag=%s;to-tag=%s%s", | |||||
4753 | leg->leg_id->i_id, from_tag, to_tag, | |||||
4754 | early_only ? ";early-only" : ""); | |||||
4755 | } | |||||
4756 | ||||||
4757 | /** Get dialog leg by @Replaces header. | |||||
4758 | * | |||||
4759 | * @since New in @VERSION_1_12_2. | |||||
4760 | */ | |||||
4761 | nta_leg_t * | |||||
4762 | nta_leg_by_replaces(nta_agent_t *sa, sip_replaces_t const *rp) | |||||
4763 | { | |||||
4764 | nta_leg_t *leg = NULL((void*)0); | |||||
4765 | ||||||
4766 | if (sa && rp && rp->rp_call_id && rp->rp_from_tag && rp->rp_to_tag) { | |||||
4767 | char const *from_tag = rp->rp_from_tag, *to_tag = rp->rp_to_tag; | |||||
4768 | sip_call_id_t id[1]; | |||||
4769 | sip_call_id_init(id); | |||||
4770 | ||||||
4771 | id->i_hash = msg_hash_string(id->i_id = rp->rp_call_id); | |||||
4772 | ||||||
4773 | leg = leg_find(sa, NULL((void*)0), NULL((void*)0), id, from_tag, to_tag); | |||||
4774 | ||||||
4775 | if (leg == NULL((void*)0) && strcmp(from_tag, "0") == 0) | |||||
4776 | leg = leg_find(sa, NULL((void*)0), NULL((void*)0), id, NULL((void*)0), to_tag); | |||||
4777 | if (leg == NULL((void*)0) && strcmp(to_tag, "0") == 0) | |||||
4778 | leg = leg_find(sa, NULL((void*)0), NULL((void*)0), id, from_tag, NULL((void*)0)); | |||||
4779 | } | |||||
4780 | ||||||
4781 | return leg; | |||||
4782 | } | |||||
4783 | ||||||
4784 | /**@internal | |||||
4785 | * Find a leg corresponding to the request message. | |||||
4786 | * | |||||
4787 | */ | |||||
4788 | static nta_leg_t * | |||||
4789 | leg_find_call_id(nta_agent_t const *sa, | |||||
4790 | sip_call_id_t const *i) | |||||
4791 | { | |||||
4792 | hash_value_t hash = i->i_hash; | |||||
4793 | leg_htable_t const *lht = sa->sa_dialogs; | |||||
4794 | nta_leg_t **ll, *leg = NULL((void*)0); | |||||
4795 | ||||||
4796 | for (ll = leg_htable_hash(lht, hash); | |||||
4797 | (leg = *ll); | |||||
4798 | ll = leg_htable_next(lht, ll)) { | |||||
4799 | sip_call_id_t const *leg_i = leg->leg_id; | |||||
4800 | ||||||
4801 | if (leg->leg_hash != hash) | |||||
4802 | continue; | |||||
4803 | if (strcmp(leg_i->i_id, i->i_id) != 0) | |||||
4804 | continue; | |||||
4805 | ||||||
4806 | return leg; | |||||
4807 | } | |||||
4808 | ||||||
4809 | return leg; | |||||
4810 | } | |||||
4811 | ||||||
4812 | /** Get dialog leg by @CallID. | |||||
4813 | * | |||||
4814 | * @note Usually there should be only single dialog per @CallID on | |||||
4815 | * User-Agents. However, proxies may fork requests initiating the dialog and | |||||
4816 | * result in multiple calls per @CallID. | |||||
4817 | * | |||||
4818 | * @since New in @VERSION_1_12_9. | |||||
4819 | */ | |||||
4820 | nta_leg_t * | |||||
4821 | nta_leg_by_call_id(nta_agent_t *sa, const char *call_id) | |||||
4822 | { | |||||
4823 | nta_leg_t *leg = NULL((void*)0); | |||||
4824 | ||||||
4825 | if (call_id) { | |||||
4826 | sip_call_id_t id[1]; | |||||
4827 | sip_call_id_init(id); | |||||
4828 | ||||||
4829 | id->i_hash = msg_hash_string(id->i_id = call_id); | |||||
4830 | ||||||
4831 | leg = leg_find_call_id(sa, id); | |||||
4832 | } | |||||
4833 | ||||||
4834 | return leg; | |||||
4835 | } | |||||
4836 | ||||||
4837 | /** Calculate a simple case-insensitive hash over a string */ | |||||
4838 | su_inlinestatic inline | |||||
4839 | hash_value_t hash_istring(char const *s, char const *term, hash_value_t hash) | |||||
4840 | { | |||||
4841 | if (s) { | |||||
4842 | for (; *s; s++) { | |||||
4843 | unsigned char c = *s; | |||||
4844 | if ('A' <= c && c <= 'Z') | |||||
4845 | c += 'a' - 'A'; | |||||
4846 | hash = 38501U * (hash + c); | |||||
4847 | } | |||||
4848 | for (s = term; *s; s++) { | |||||
4849 | unsigned char c = *s; | |||||
4850 | hash = 38501U * (hash + c); | |||||
4851 | } | |||||
4852 | } | |||||
4853 | ||||||
4854 | return hash; | |||||
4855 | } | |||||
4856 | ||||||
4857 | /** @internal Handle requests intended for this leg. */ | |||||
4858 | static | |||||
4859 | void leg_recv(nta_leg_t *leg, msg_t *msg, sip_t *sip, tport_t *tport) | |||||
4860 | { | |||||
4861 | nta_agent_t *agent = leg->leg_agent; | |||||
4862 | nta_incoming_t *irq; | |||||
4863 | sip_method_t method = sip->sip_request->rq_method; | |||||
4864 | char const *method_name = sip->sip_request->rq_method_name; | |||||
4865 | char const *tag = NULL((void*)0); | |||||
4866 | int status; | |||||
4867 | ||||||
4868 | if (leg->leg_local) | |||||
4869 | tag = leg->leg_local->a_tag; | |||||
4870 | ||||||
4871 | if (leg->leg_dialog) | |||||
4872 | agent->sa_stats->as_dialog_tr++; | |||||
4873 | ||||||
4874 | /* RFC-3262 section 3 (page 4) */ | |||||
4875 | if (agent->sa_is_a_uas && method == sip_method_prack) { | |||||
4876 | mreply(agent, NULL((void*)0), 481, "No such response", msg, | |||||
4877 | tport, 0, 0, NULL((void*)0), | |||||
4878 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
4879 | return; | |||||
4880 | } | |||||
4881 | ||||||
4882 | if (!(irq = incoming_create(agent, msg, sip, tport, tag))) { | |||||
4883 | SU_DEBUG_3(("nta: leg_recv(%p): cannot create transaction for %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 4884, "nta: leg_recv(%p): cannot create transaction for %s\n" , (void *)leg, method_name)) : (void)0) | |||||
4884 | (void *)leg, method_name))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 4884, "nta: leg_recv(%p): cannot create transaction for %s\n" , (void *)leg, method_name)) : (void)0); | |||||
4885 | mreply(agent, NULL((void*)0), SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error, msg, | |||||
4886 | tport, 0, 0, NULL((void*)0), | |||||
4887 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
4888 | return; | |||||
4889 | } | |||||
4890 | ||||||
4891 | irq->irq_compressed = leg->leg_compressed; | |||||
4892 | irq->irq_in_callback = 1; | |||||
4893 | status = incoming_callback(leg, irq, sip); | |||||
4894 | irq->irq_in_callback = 0; | |||||
4895 | ||||||
4896 | if (irq->irq_destroyed) { | |||||
4897 | if (irq->irq_terminated) { | |||||
4898 | incoming_free(irq); | |||||
4899 | return; | |||||
4900 | } | |||||
4901 | if (status < 200) | |||||
4902 | status = 500; | |||||
4903 | } | |||||
4904 | ||||||
4905 | if (status == 0) | |||||
4906 | return; | |||||
4907 | ||||||
4908 | if (status < 100 || status > 699) { | |||||
4909 | SU_DEBUG_3(("nta_leg(%p): invalid status %03d from callback\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 4910, "nta_leg(%p): invalid status %03d from callback\n", ( void *)leg, status)) : (void)0) | |||||
4910 | (void *)leg, status))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 4910, "nta_leg(%p): invalid status %03d from callback\n", ( void *)leg, status)) : (void)0); | |||||
4911 | status = 500; | |||||
4912 | } | |||||
4913 | else if (method == sip_method_invite && status >= 200 && status < 300) { | |||||
4914 | SU_DEBUG_3(("nta_leg(%p): invalid INVITE status %03d from callback\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 4915, "nta_leg(%p): invalid INVITE status %03d from callback\n" , (void *)leg, status)) : (void)0) | |||||
4915 | (void *)leg, status))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 4915, "nta_leg(%p): invalid INVITE status %03d from callback\n" , (void *)leg, status)) : (void)0); | |||||
4916 | status = 500; | |||||
4917 | } | |||||
4918 | ||||||
4919 | if (status >= 100 && irq->irq_status < 200) | |||||
4920 | nta_incoming_treply(irq, status, NULL((void*)0), TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
4921 | ||||||
4922 | if (status >= 200) | |||||
4923 | nta_incoming_destroy(irq); | |||||
4924 | } | |||||
4925 | ||||||
4926 | #if 0 | |||||
4927 | /**Compare two SIP from/to fields. | |||||
4928 | * | |||||
4929 | * @retval nonzero if matching. | |||||
4930 | * @retval zero if not matching. | |||||
4931 | */ | |||||
4932 | su_inlinestatic inline | |||||
4933 | int addr_cmp(url_t const *a, url_t const *b) | |||||
4934 | { | |||||
4935 | if (b == NULL((void*)0)) | |||||
4936 | return 0; | |||||
4937 | else | |||||
4938 | return | |||||
4939 | host_cmp(a->url_host, b->url_host) || | |||||
4940 | su_strcmp(a->url_port, b->url_port) || | |||||
4941 | su_strcmp(a->url_user, b->url_user); | |||||
4942 | } | |||||
4943 | #endif | |||||
4944 | ||||||
4945 | /** Get a leg by dialog. | |||||
4946 | * | |||||
4947 | * Search for a dialog leg from agent's hash table. The matching rules based | |||||
4948 | * on parameters are as follows: | |||||
4949 | * | |||||
4950 | * @param agent pointer to agent object | |||||
4951 | * @param request_uri if non-NULL, and there is destination URI | |||||
4952 | * associated with the dialog, these URIs must match | |||||
4953 | * @param call_id if non-NULL, must match with @CallID header contents | |||||
4954 | * @param remote_tag if there is remote tag | |||||
4955 | * associated with dialog, @a remote_tag must match | |||||
4956 | * @param remote_uri ignored | |||||
4957 | * @param local_tag if non-NULL and there is local tag associated with leg, | |||||
4958 | * it must math | |||||
4959 | * @param local_uri ignored | |||||
4960 | * | |||||
4961 | * @note | |||||
4962 | * If @a remote_tag or @a local_tag is an empty string (""), the tag is | |||||
4963 | * ignored when matching legs. | |||||
4964 | */ | |||||
4965 | nta_leg_t *nta_leg_by_dialog(nta_agent_t const *agent, | |||||
4966 | url_t const *request_uri, | |||||
4967 | sip_call_id_t const *call_id, | |||||
4968 | char const *remote_tag, | |||||
4969 | url_t const *remote_uri, | |||||
4970 | char const *local_tag, | |||||
4971 | url_t const *local_uri) | |||||
4972 | { | |||||
4973 | void *to_be_freed = NULL((void*)0); | |||||
4974 | url_t *url; | |||||
4975 | url_t url0[1]; | |||||
4976 | nta_leg_t *leg; | |||||
4977 | ||||||
4978 | if (!agent || !call_id) | |||||
4979 | return su_seterrno(EINVAL22), NULL((void*)0); | |||||
4980 | ||||||
4981 | if (request_uri == NULL((void*)0)) { | |||||
4982 | url = NULL((void*)0); | |||||
4983 | } | |||||
4984 | else if (URL_IS_STRING(request_uri)((request_uri) && *((url_string_t*)(request_uri))-> us_str != 0)) { | |||||
4985 | /* accept a string as URL */ | |||||
4986 | to_be_freed = url = url_hdup(NULL((void*)0), request_uri); | |||||
4987 | } | |||||
4988 | else { | |||||
4989 | *url0 = *request_uri, url = url0; | |||||
4990 | } | |||||
4991 | ||||||
4992 | if (url) { | |||||
4993 | url->url_params = NULL((void*)0); | |||||
4994 | agent_aliases(agent, url, NULL((void*)0)); /* canonize url */ | |||||
4995 | } | |||||
4996 | ||||||
4997 | if (remote_tag && remote_tag[0] == '\0') | |||||
4998 | remote_tag = NULL((void*)0); | |||||
4999 | if (local_tag && local_tag[0] == '\0') | |||||
5000 | local_tag = NULL((void*)0); | |||||
5001 | ||||||
5002 | leg = leg_find(agent, | |||||
5003 | NULL((void*)0), url, | |||||
5004 | call_id, | |||||
5005 | remote_tag, | |||||
5006 | local_tag); | |||||
5007 | ||||||
5008 | if (to_be_freed) su_free(NULL((void*)0), to_be_freed); | |||||
5009 | ||||||
5010 | return leg; | |||||
5011 | } | |||||
5012 | ||||||
5013 | /**@internal | |||||
5014 | * Find a leg corresponding to the request message. | |||||
5015 | * | |||||
5016 | * A leg matches to message if leg_match_request() returns true ("Call-ID", | |||||
5017 | * "To"-tag, and "From"-tag match). | |||||
5018 | */ | |||||
5019 | static | |||||
5020 | nta_leg_t *leg_find(nta_agent_t const *sa, | |||||
5021 | char const *method_name, | |||||
5022 | url_t const *request_uri, | |||||
5023 | sip_call_id_t const *i, | |||||
5024 | char const *from_tag, | |||||
5025 | char const *to_tag) | |||||
5026 | { | |||||
5027 | hash_value_t hash = i->i_hash; | |||||
5028 | leg_htable_t const *lht = sa->sa_dialogs; | |||||
5029 | nta_leg_t **ll, *leg, *loose_match = NULL((void*)0); | |||||
5030 | ||||||
5031 | for (ll = leg_htable_hash(lht, hash); | |||||
5032 | (leg = *ll); | |||||
5033 | ll = leg_htable_next(lht, ll)) { | |||||
5034 | sip_call_id_t const *leg_i = leg->leg_id; | |||||
5035 | char const *remote_tag = leg->leg_remote->a_tag; | |||||
5036 | char const *local_tag = leg->leg_local->a_tag; | |||||
5037 | ||||||
5038 | url_t const *leg_url = leg->leg_url; | |||||
5039 | char const *leg_method = leg->leg_method; | |||||
5040 | ||||||
5041 | if (leg->leg_hash != hash) | |||||
5042 | continue; | |||||
5043 | if (strcmp(leg_i->i_id, i->i_id) != 0) | |||||
5044 | continue; | |||||
5045 | ||||||
5046 | /* Do not match if the incoming To has tag, but the local does not */ | |||||
5047 | if (!local_tag && to_tag) | |||||
5048 | continue; | |||||
5049 | ||||||
5050 | /* | |||||
5051 | * Do not match if incoming To has no tag and we have local tag | |||||
5052 | * and the tag has been there from the beginning. | |||||
5053 | */ | |||||
5054 | if (local_tag && !to_tag && !leg->leg_tagged) | |||||
5055 | continue; | |||||
5056 | ||||||
5057 | /* Do not match if incoming From has no tag but remote has a tag */ | |||||
5058 | if (remote_tag && !from_tag) | |||||
5059 | continue; | |||||
5060 | ||||||
5061 | /* Avoid matching with itself */ | |||||
5062 | if (!remote_tag != !from_tag && !local_tag != !to_tag) | |||||
5063 | continue; | |||||
5064 | ||||||
5065 | if (local_tag && to_tag && !su_casematch(local_tag, to_tag) && to_tag[0]) | |||||
5066 | continue; | |||||
5067 | if (remote_tag && from_tag && !su_casematch(remote_tag, from_tag) && from_tag[0]) | |||||
5068 | continue; | |||||
5069 | ||||||
5070 | if (leg_url && request_uri && url_cmp(leg_url, request_uri)) | |||||
5071 | continue; | |||||
5072 | if (leg_method && method_name && !su_casematch(method_name, leg_method)) | |||||
5073 | continue; | |||||
5074 | ||||||
5075 | /* Perfect match if both local and To have tag | |||||
5076 | * or local does not have tag. | |||||
5077 | */ | |||||
5078 | if ((!local_tag || to_tag)) | |||||
5079 | return leg; | |||||
5080 | ||||||
5081 | if (loose_match == NULL((void*)0)) | |||||
5082 | loose_match = leg; | |||||
5083 | } | |||||
5084 | ||||||
5085 | return loose_match; | |||||
5086 | } | |||||
5087 | ||||||
5088 | /** Get leg by destination */ | |||||
5089 | nta_leg_t *nta_leg_by_uri(nta_agent_t const *agent, url_string_t const *us) | |||||
5090 | { | |||||
5091 | url_t *url; | |||||
5092 | nta_leg_t *leg = NULL((void*)0); | |||||
5093 | ||||||
5094 | if (!agent) | |||||
5095 | return NULL((void*)0); | |||||
5096 | ||||||
5097 | if (!us) | |||||
5098 | return agent->sa_default_leg; | |||||
5099 | ||||||
5100 | url = url_hdup(NULL((void*)0), us->us_url); | |||||
5101 | ||||||
5102 | if (url) { | |||||
5103 | agent_aliases(agent, url, NULL((void*)0)); | |||||
5104 | leg = dst_find(agent, url, NULL((void*)0)); | |||||
5105 | su_free(NULL((void*)0), url); | |||||
5106 | } | |||||
5107 | ||||||
5108 | return leg; | |||||
5109 | } | |||||
5110 | ||||||
5111 | /** Find a non-dialog leg corresponding to the request uri u0 */ | |||||
5112 | static | |||||
5113 | nta_leg_t *dst_find(nta_agent_t const *sa, | |||||
5114 | url_t const *u0, | |||||
5115 | char const *method_name) | |||||
5116 | { | |||||
5117 | hash_value_t hash, hash2; | |||||
5118 | leg_htable_t const *lht = sa->sa_defaults; | |||||
5119 | nta_leg_t **ll, *leg, *loose_match = NULL((void*)0); | |||||
5120 | int again; | |||||
5121 | url_t url[1]; | |||||
5122 | ||||||
5123 | *url = *u0; | |||||
5124 | hash = hash_istring(url->url_scheme, ":", 0); | |||||
5125 | hash = hash_istring(url->url_host, "", hash); | |||||
5126 | hash2 = hash_istring("%", "@", hash); | |||||
5127 | hash = hash_istring(url->url_user, "@", hash); | |||||
5128 | ||||||
5129 | /* First round, search with user name */ | |||||
5130 | /* Second round, search without user name */ | |||||
5131 | do { | |||||
5132 | for (ll = leg_htable_hash(lht, hash); | |||||
5133 | (leg = *ll); | |||||
5134 | ll = leg_htable_next(lht, ll)) { | |||||
5135 | if (leg->leg_hash != hash) | |||||
5136 | continue; | |||||
5137 | if (url_cmp(url, leg->leg_url)) | |||||
5138 | continue; | |||||
5139 | if (!method_name) { | |||||
5140 | if (leg->leg_method) | |||||
5141 | continue; | |||||
5142 | return leg; | |||||
5143 | } | |||||
5144 | else if (leg->leg_method) { | |||||
5145 | if (!su_casematch(method_name, leg->leg_method)) | |||||
5146 | continue; | |||||
5147 | return leg; | |||||
5148 | } | |||||
5149 | loose_match = leg; | |||||
5150 | } | |||||
5151 | if (loose_match) | |||||
5152 | return loose_match; | |||||
5153 | ||||||
5154 | again = 0; | |||||
5155 | ||||||
5156 | if (url->url_user && strcmp(url->url_user, "%")) { | |||||
5157 | url->url_user = "%"; | |||||
5158 | hash = hash2; | |||||
5159 | again = 1; | |||||
5160 | } | |||||
5161 | } while (again); | |||||
5162 | ||||||
5163 | return NULL((void*)0); | |||||
5164 | } | |||||
5165 | ||||||
5166 | /** Set leg route and target URL. | |||||
5167 | * | |||||
5168 | * Sets the leg route and contact using the @RecordRoute and @Contact | |||||
5169 | * headers. | |||||
5170 | * | |||||
5171 | * @param reroute - allow rerouting | |||||
5172 | * - if 1, follow @RFC3261 semantics | |||||
5173 | * - if 2, response to initial transaction) | |||||
5174 | */ | |||||
5175 | static | |||||
5176 | int leg_route(nta_leg_t *leg, | |||||
5177 | sip_record_route_t const *route, | |||||
5178 | sip_record_route_t const *reverse, | |||||
5179 | sip_contact_t const *contact, | |||||
5180 | int reroute) | |||||
5181 | { | |||||
5182 | su_home_t *home = leg->leg_home; | |||||
5183 | sip_route_t *r, r0[1], *old; | |||||
5184 | int route_is_set; | |||||
5185 | ||||||
5186 | if (!leg) | |||||
5187 | return -1; | |||||
5188 | ||||||
5189 | if (route == NULL((void*)0) && reverse == NULL((void*)0) && contact == NULL((void*)0)) | |||||
5190 | return 0; | |||||
5191 | ||||||
5192 | sip_route_init(r0); | |||||
5193 | ||||||
5194 | route_is_set = reroute ? leg->leg_route_set : leg->leg_route != NULL((void*)0); | |||||
5195 | ||||||
5196 | if (route_is_set && reroute <= 1) { | |||||
5197 | r = leg->leg_route; | |||||
5198 | } | |||||
5199 | else if (route) { | |||||
5200 | r = sip_route_fixdup(home, route); if (!r) return -1; | |||||
5201 | } | |||||
5202 | else if (reverse) { | |||||
5203 | r = sip_route_reverse(home, reverse); if (!r) return -1; | |||||
5204 | } | |||||
5205 | else | |||||
5206 | r = NULL((void*)0); | |||||
5207 | ||||||
5208 | #ifdef NTA_STRICT_ROUTING | |||||
5209 | /* | |||||
5210 | * Handle Contact according to the RFC2543bis04 sections 16.1, 16.2 and 16.4. | |||||
5211 | */ | |||||
5212 | if (contact) { | |||||
5213 | *r0->r_url = *contact->m_url; | |||||
5214 | ||||||
5215 | if (!(m_r = sip_route_dup(leg->leg_home, r0))) | |||||
5216 | return -1; | |||||
5217 | ||||||
5218 | /* Append, but replace last entry if it was generated from contact */ | |||||
5219 | for (rr = &r; *rr; rr = &(*rr)->r_next) | |||||
5220 | if (leg->leg_contact_set && (*rr)->r_next == NULL((void*)0)) | |||||
5221 | break; | |||||
5222 | } | |||||
5223 | else | |||||
5224 | rr = NULL((void*)0); | |||||
5225 | ||||||
5226 | if (rr) { | |||||
5227 | if (*rr) | |||||
5228 | su_free(leg->leg_home, *rr); | |||||
5229 | *rr = m_r; | |||||
5230 | } | |||||
5231 | if (m_r != NULL((void*)0)) | |||||
5232 | leg->leg_contact_set = 1; | |||||
5233 | ||||||
5234 | #else | |||||
5235 | if (r && r->r_url->url_params) | |||||
5236 | leg->leg_loose_route = url_has_param(r->r_url, "lr"); | |||||
5237 | ||||||
5238 | if (contact) { | |||||
5239 | sip_contact_t *target, m[1], *m0; | |||||
5240 | ||||||
5241 | sip_contact_init(m); | |||||
5242 | *m->m_url = *contact->m_url; | |||||
5243 | m->m_url->url_headers = NULL((void*)0); | |||||
5244 | target = sip_contact_dup(leg->leg_home, m); | |||||
5245 | ||||||
5246 | if (target && target->m_url->url_params) { | |||||
5247 | /* Remove ttl, method. @RFC3261 table 1, page 152 */ | |||||
5248 | char *p = (char *)target->m_url->url_params; | |||||
5249 | p = url_strip_param_string(p, "method"); | |||||
5250 | p = url_strip_param_string(p, "ttl"); | |||||
5251 | target->m_url->url_params = p; | |||||
5252 | } | |||||
5253 | ||||||
5254 | m0 = leg->leg_target, leg->leg_target = target; | |||||
5255 | ||||||
5256 | if (m0) | |||||
5257 | su_free(leg->leg_home, m0); | |||||
5258 | } | |||||
5259 | #endif | |||||
5260 | ||||||
5261 | old = leg->leg_route; | |||||
5262 | leg->leg_route = r; | |||||
5263 | ||||||
5264 | if (old && old != r) | |||||
5265 | msg_header_free(leg->leg_home, (msg_header_t *)old); | |||||
5266 | ||||||
5267 | leg->leg_route_set = 1; | |||||
5268 | ||||||
5269 | return 0; | |||||
5270 | } | |||||
5271 | ||||||
5272 | /** @internal Default leg callback. */ | |||||
5273 | static int | |||||
5274 | leg_callback_default(nta_leg_magic_t *magic, | |||||
5275 | nta_leg_t *leg, | |||||
5276 | nta_incoming_t *irq, | |||||
5277 | sip_t const *sip) | |||||
5278 | { | |||||
5279 | nta_incoming_treply(irq, | |||||
5280 | SIP_501_NOT_IMPLEMENTED501, sip_501_Not_implemented, | |||||
5281 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
5282 | return 501; | |||||
5283 | } | |||||
5284 | ||||||
5285 | /* ====================================================================== */ | |||||
5286 | /* 7) Server-side (incoming) transactions */ | |||||
5287 | ||||||
5288 | #define HTABLE_HASH_IRQ(irq)((irq)->irq_hash) ((irq)->irq_hash) | |||||
5289 | 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, collisions = 0; if (new_size == 0) new_size = 2 * iht->iht_size + 1; if (new_size < 31) new_size = 31; if (new_size < 5 * iht->iht_used / 4) new_size = 5 * iht->iht_used / 4; if (!(new_hash = su_zalloc (home, sizeof(*new_hash) * new_size))) return -1; old_size = iht ->iht_size; do for (j = 0; j < old_size; j++) { if (!old_hash [j]) continue; if (again < 2 && ((old_hash[j])-> irq_hash) % old_size > j) { again = 1; continue; } i0 = (( old_hash[j])->irq_hash) % new_size; for (i = i0; new_hash[ i]; i = (i + 1) % new_size, ((void) sizeof ((i != i0) ? 1 : 0 ), __extension__ ({ if (i != i0) ; else __assert_fail ("i != i0" , "nta.c", 5290, __extension__ __PRETTY_FUNCTION__); }))) collisions ++; new_hash[i] = old_hash[j], old_hash[j] = ((void*)0); used ++; } while (again++ == 1); iht->iht_table = new_hash, iht ->iht_size = new_size; ((void) sizeof ((iht->iht_used == used) ? 1 : 0), __extension__ ({ if (iht->iht_used == used ) ; else __assert_fail ("iht->iht_used == used", "nta.c", 5290 , __extension__ __PRETTY_FUNCTION__); })); su_free(home, old_hash ); return 0; } static inline int incoming_htable_is_full(incoming_htable_t const *iht) { return iht->iht_table == ((void*)0) || 3 * iht ->iht_used > 2 * iht->iht_size; } static inline nta_incoming_t **incoming_htable_hash(incoming_htable_t const *iht, hash_value_t hv) { return iht->iht_table + hv % iht->iht_size; } static inline nta_incoming_t **incoming_htable_next(incoming_htable_t const *iht, nta_incoming_t * const *ee) { if (++ee < iht-> iht_table + iht->iht_size && ee >= iht->iht_table ) return (nta_incoming_t **)ee; else return iht->iht_table ; } static inline void incoming_htable_append(incoming_htable_t *iht, nta_incoming_t const *e) { nta_incoming_t **ee; iht-> iht_used++; for (ee = incoming_htable_hash(iht, ((e)->irq_hash )); *ee; ee = incoming_htable_next(iht, ee)) ; *ee = (nta_incoming_t *)e; } static inline void incoming_htable_insert(incoming_htable_t *iht, nta_incoming_t const *e) { nta_incoming_t *e0, **ee; iht ->iht_used++; for (ee = incoming_htable_hash(iht, ((e)-> irq_hash)); (e0 = *ee); ee = incoming_htable_next(iht, ee)) * ee = (nta_incoming_t *)e, e = e0; *ee = (nta_incoming_t *)e; } static inline int incoming_htable_remove(incoming_htable_t * iht, nta_incoming_t const *e) { size_t i, j, k; size_t size = iht->iht_size; nta_incoming_t **htable = iht->iht_table ; if (!e) return -1; for (i = ((e)->irq_hash) % size; htable [i]; i = (i + 1) % size) if (e == htable[i]) break; if (!htable [i]) return -1; for (j = (i + 1) % size; htable[j]; j = (j + 1 ) % size) { k = ((htable[j])->irq_hash) % size; if (k == j ) continue; if (j > i ? (i < k && k < j) : ( i < k || k < j)) continue; htable[i] = htable[j], i = j ; } iht->iht_used--; htable[i] = ((void*)0); return 0; } extern int incoming_htable_dummy | |||||
5290 | size_t, hash_value_t)static inline int incoming_htable_resize(su_home_t *home, incoming_htable_t iht[], size_t new_size) { nta_incoming_t **new_hash; nta_incoming_t **old_hash = iht->iht_table; size_t old_size; size_t i, j , i0; unsigned again = 0; size_t used = 0, collisions = 0; if (new_size == 0) new_size = 2 * iht->iht_size + 1; if (new_size < 31) new_size = 31; if (new_size < 5 * iht->iht_used / 4) new_size = 5 * iht->iht_used / 4; if (!(new_hash = su_zalloc (home, sizeof(*new_hash) * new_size))) return -1; old_size = iht ->iht_size; do for (j = 0; j < old_size; j++) { if (!old_hash [j]) continue; if (again < 2 && ((old_hash[j])-> irq_hash) % old_size > j) { again = 1; continue; } i0 = (( old_hash[j])->irq_hash) % new_size; for (i = i0; new_hash[ i]; i = (i + 1) % new_size, ((void) sizeof ((i != i0) ? 1 : 0 ), __extension__ ({ if (i != i0) ; else __assert_fail ("i != i0" , "nta.c", 5290, __extension__ __PRETTY_FUNCTION__); }))) collisions ++; new_hash[i] = old_hash[j], old_hash[j] = ((void*)0); used ++; } while (again++ == 1); iht->iht_table = new_hash, iht ->iht_size = new_size; ((void) sizeof ((iht->iht_used == used) ? 1 : 0), __extension__ ({ if (iht->iht_used == used ) ; else __assert_fail ("iht->iht_used == used", "nta.c", 5290 , __extension__ __PRETTY_FUNCTION__); })); su_free(home, old_hash ); return 0; } static inline int incoming_htable_is_full(incoming_htable_t const *iht) { return iht->iht_table == ((void*)0) || 3 * iht ->iht_used > 2 * iht->iht_size; } static inline nta_incoming_t **incoming_htable_hash(incoming_htable_t const *iht, hash_value_t hv) { return iht->iht_table + hv % iht->iht_size; } static inline nta_incoming_t **incoming_htable_next(incoming_htable_t const *iht, nta_incoming_t * const *ee) { if (++ee < iht-> iht_table + iht->iht_size && ee >= iht->iht_table ) return (nta_incoming_t **)ee; else return iht->iht_table ; } static inline void incoming_htable_append(incoming_htable_t *iht, nta_incoming_t const *e) { nta_incoming_t **ee; iht-> iht_used++; for (ee = incoming_htable_hash(iht, ((e)->irq_hash )); *ee; ee = incoming_htable_next(iht, ee)) ; *ee = (nta_incoming_t *)e; } static inline void incoming_htable_insert(incoming_htable_t *iht, nta_incoming_t const *e) { nta_incoming_t *e0, **ee; iht ->iht_used++; for (ee = incoming_htable_hash(iht, ((e)-> irq_hash)); (e0 = *ee); ee = incoming_htable_next(iht, ee)) * ee = (nta_incoming_t *)e, e = e0; *ee = (nta_incoming_t *)e; } static inline int incoming_htable_remove(incoming_htable_t * iht, nta_incoming_t const *e) { size_t i, j, k; size_t size = iht->iht_size; nta_incoming_t **htable = iht->iht_table ; if (!e) return -1; for (i = ((e)->irq_hash) % size; htable [i]; i = (i + 1) % size) if (e == htable[i]) break; if (!htable [i]) return -1; for (j = (i + 1) % size; htable[j]; j = (j + 1 ) % size) { k = ((htable[j])->irq_hash) % size; if (k == j ) continue; if (j > i ? (i < k && k < j) : ( i < k || k < j)) continue; htable[i] = htable[j], i = j ; } iht->iht_used--; htable[i] = ((void*)0); return 0; } extern int incoming_htable_dummy; | |||||
5291 | ||||||
5292 | static void incoming_insert(nta_agent_t *agent, | |||||
5293 | incoming_queue_t *queue, | |||||
5294 | nta_incoming_t *irq); | |||||
5295 | ||||||
5296 | su_inlinestatic inline int incoming_is_queued(nta_incoming_t const *irq); | |||||
5297 | su_inlinestatic inline void incoming_queue(incoming_queue_t *queue, nta_incoming_t *); | |||||
5298 | su_inlinestatic inline void incoming_remove(nta_incoming_t *irq); | |||||
5299 | su_inlinestatic inline void incoming_set_timer(nta_incoming_t *, uint32_t interval); | |||||
5300 | su_inlinestatic inline void incoming_reset_timer(nta_incoming_t *); | |||||
5301 | su_inlinestatic inline size_t incoming_mass_destroy(nta_agent_t *, incoming_queue_t *); | |||||
5302 | ||||||
5303 | static int incoming_set_params(nta_incoming_t *irq, tagi_t const *tags); | |||||
5304 | su_inlinestatic inline | |||||
5305 | int incoming_set_compartment(nta_incoming_t *irq, tport_t *tport, msg_t *msg, | |||||
5306 | int create_if_needed); | |||||
5307 | ||||||
5308 | su_inlinestatic inline nta_incoming_t | |||||
5309 | *incoming_call_callback(nta_incoming_t *, msg_t *, sip_t *); | |||||
5310 | su_inlinestatic inline int incoming_final_failed(nta_incoming_t *irq, msg_t *); | |||||
5311 | static void incoming_retransmit_reply(nta_incoming_t *irq, tport_t *tport); | |||||
5312 | ||||||
5313 | /** Create a default server transaction. | |||||
5314 | * | |||||
5315 | * The default server transaction is used by a proxy to forward responses | |||||
5316 | * statelessly. | |||||
5317 | * | |||||
5318 | * @param agent pointer to agent object | |||||
5319 | * | |||||
5320 | * @retval pointer to default server transaction object | |||||
5321 | * @retval NULL if failed | |||||
5322 | */ | |||||
5323 | nta_incoming_t *nta_incoming_default(nta_agent_t *agent) | |||||
5324 | { | |||||
5325 | msg_t *msg; | |||||
5326 | su_home_t *home; | |||||
5327 | nta_incoming_t *irq; | |||||
5328 | ||||||
5329 | if (agent == NULL((void*)0)) | |||||
5330 | return su_seterrno(EFAULT14), NULL((void*)0); | |||||
5331 | if (agent->sa_default_incoming) | |||||
5332 | return su_seterrno(EEXIST17), NULL((void*)0); | |||||
5333 | ||||||
5334 | msg = nta_msg_create(agent, 0); | |||||
5335 | if (!msg) | |||||
5336 | return NULL((void*)0); | |||||
5337 | ||||||
5338 | irq = su_zalloc(home = msg_home(msg)((su_home_t*)(msg)), sizeof(*irq)); | |||||
5339 | if (!irq) | |||||
5340 | return (void)msg_destroy(msg), NULL((void*)0); | |||||
5341 | ||||||
5342 | irq->irq_home = home; | |||||
5343 | irq->irq_request = NULL((void*)0); | |||||
5344 | irq->irq_agent = agent; | |||||
5345 | irq->irq_received = agent_now(agent); | |||||
5346 | irq->irq_method = sip_method_invalid; | |||||
5347 | ||||||
5348 | irq->irq_default = 1; | |||||
5349 | agent->sa_default_incoming = irq; | |||||
5350 | ||||||
5351 | return irq; | |||||
5352 | } | |||||
5353 | ||||||
5354 | /** Create a server transaction. | |||||
5355 | * | |||||
5356 | * Create a server transaction for a request message. This function is used | |||||
5357 | * when an element processing requests statelessly wants to process a | |||||
5358 | * particular request statefully. | |||||
5359 | * | |||||
5360 | * @param agent pointer to agent object | |||||
5361 | * @param leg pointer to leg object (either @a agent or @a leg may be NULL) | |||||
5362 | * @param msg pointer to message object | |||||
5363 | * @param sip pointer to SIP structure (may be NULL) | |||||
5364 | * @param tag,value,... optional tagged parameters | |||||
5365 | * | |||||
5366 | * @note | |||||
5367 | * The ownership of @a msg is taken over by the function even if the | |||||
5368 | * function fails. | |||||
5369 | * | |||||
5370 | * @TAGS | |||||
5371 | * @TAG NTATAG_TPORT() specifies the transport used to receive the request | |||||
5372 | * and also default transport for sending the response. | |||||
5373 | * | |||||
5374 | * @retval nta_incoming_t pointer to the newly created server transaction | |||||
5375 | * @retval NULL if failed | |||||
5376 | */ | |||||
5377 | nta_incoming_t *nta_incoming_create(nta_agent_t *agent, | |||||
5378 | nta_leg_t *leg, | |||||
5379 | msg_t *msg, | |||||
5380 | sip_t *sip, | |||||
5381 | tag_type_t tag, tag_value_t value, ...) | |||||
5382 | { | |||||
5383 | char const *to_tag = NULL((void*)0); | |||||
5384 | tport_t *tport = NULL((void*)0); | |||||
5385 | ta_list ta; | |||||
5386 | nta_incoming_t *irq; | |||||
5387 | ||||||
5388 | if (msg == NULL((void*)0)) | |||||
5389 | return NULL((void*)0); | |||||
5390 | ||||||
5391 | if (agent == NULL((void*)0) && leg != NULL((void*)0)) | |||||
5392 | agent = leg->leg_agent; | |||||
5393 | ||||||
5394 | if (sip == NULL((void*)0)) | |||||
5395 | sip = sip_object(msg); | |||||
5396 | ||||||
5397 | if (agent == NULL((void*)0) || sip == NULL((void*)0) || !sip->sip_request || !sip->sip_cseq) | |||||
5398 | return msg_destroy(msg), NULL((void*)0); | |||||
5399 | ||||||
5400 | ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value = (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag ) == tag_next && (ta_start__value) != 0) { ta_start__tag = ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag == tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag == tag_next) { ta_start__value = ((tagi_t *)ta_start__value) ->t_value; } else { ta_start__tag = tag_next; break; } } ( ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value ; if (ta_start__tag != ((void*)0) && ta_start__tag != tag_null && ta_start__tag != tag_next) { va_list ta_start__ap ; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag = tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap ); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value = 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0); | |||||
5401 | ||||||
5402 | tl_gets(ta_args(ta)(ta).tl, | |||||
5403 | NTATAG_TPORT_REF(tport)ntatag_tport_ref, tag_ptr_vr(&(tport), (tport)), | |||||
5404 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
5405 | ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value ))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta) .ap)); | |||||
5406 | ||||||
5407 | if (leg && leg->leg_local) | |||||
5408 | to_tag = leg->leg_local->a_tag; | |||||
5409 | ||||||
5410 | if (tport == NULL((void*)0)) | |||||
5411 | tport = tport_delivered_by(agent->sa_tports, msg); | |||||
5412 | ||||||
5413 | irq = incoming_create(agent, msg, sip, tport, to_tag); | |||||
5414 | ||||||
5415 | if (!irq) | |||||
5416 | msg_destroy(msg); | |||||
5417 | ||||||
5418 | return irq; | |||||
5419 | } | |||||
5420 | ||||||
5421 | /** @internal Create a new incoming transaction object. */ | |||||
5422 | static | |||||
5423 | nta_incoming_t *incoming_create(nta_agent_t *agent, | |||||
5424 | msg_t *msg, | |||||
5425 | sip_t *sip, | |||||
5426 | tport_t *tport, | |||||
5427 | char const *tag) | |||||
5428 | { | |||||
5429 | nta_incoming_t *irq = su_zalloc(msg_home(msg)((su_home_t*)(msg)), sizeof(*irq)); | |||||
5430 | ||||||
5431 | agent->sa_stats->as_server_tr++; | |||||
5432 | ||||||
5433 | if (irq) { | |||||
5434 | su_home_t *home; | |||||
5435 | incoming_queue_t *queue; | |||||
5436 | sip_method_t method = sip->sip_request->rq_method; | |||||
5437 | ||||||
5438 | irq->irq_request = msg; | |||||
5439 | irq->irq_home = home = msg_home(msg_ref_create(msg))((su_home_t*)(msg_ref_create(msg))); | |||||
5440 | irq->irq_agent = agent; | |||||
5441 | ||||||
5442 | irq->irq_received = agent_now(agent); /* Timestamp originally from tport */ | |||||
5443 | ||||||
5444 | irq->irq_method = method; | |||||
5445 | irq->irq_rq = sip_request_copy(home, sip->sip_request); | |||||
5446 | irq->irq_from = sip_from_copy(home, sip->sip_from); | |||||
5447 | irq->irq_to = sip_to_copy(home, sip->sip_to); | |||||
5448 | irq->irq_call_id = sip_call_id_copy(home, sip->sip_call_id); | |||||
5449 | irq->irq_cseq = sip_cseq_copy(home, sip->sip_cseq); | |||||
5450 | irq->irq_via = sip_via_copy(home, sip->sip_via); | |||||
5451 | switch (method) { | |||||
5452 | case sip_method_ack: | |||||
5453 | case sip_method_cancel: | |||||
5454 | case sip_method_bye: | |||||
5455 | case sip_method_options: | |||||
5456 | case sip_method_register: /* Handling Path is up to application */ | |||||
5457 | case sip_method_info: | |||||
5458 | case sip_method_prack: | |||||
5459 | case sip_method_publish: | |||||
5460 | break; | |||||
5461 | default: | |||||
5462 | irq->irq_record_route = | |||||
5463 | sip_record_route_copy(home, sip->sip_record_route); | |||||
5464 | } | |||||
5465 | irq->irq_branch = sip->sip_via->v_branch; | |||||
5466 | irq->irq_reliable_tp = tport_is_reliable(tport); | |||||
5467 | irq->irq_extra_100 = 0; /* Sending extra 100 trying false by default */ | |||||
5468 | ||||||
5469 | if (sip->sip_timestamp) | |||||
5470 | irq->irq_timestamp = sip_timestamp_copy(home, sip->sip_timestamp); | |||||
5471 | ||||||
5472 | /* Tag transaction */ | |||||
5473 | if (tag) | |||||
5474 | sip_to_tag(home, irq->irq_to, tag); | |||||
5475 | irq->irq_tag = irq->irq_to->a_tag; | |||||
5476 | ||||||
5477 | if (method != sip_method_ack) { | |||||
5478 | int *use_rport = NULL((void*)0); | |||||
5479 | int retry_without_rport = 0; | |||||
5480 | ||||||
5481 | if (agent->sa_server_rport) | |||||
5482 | use_rport = &retry_without_rport, retry_without_rport = 1; | |||||
5483 | ||||||
5484 | if (nta_tpn_by_via(irq->irq_tpn, irq->irq_via, use_rport) < 0) | |||||
5485 | SU_DEBUG_1(("%s: bad via\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 5485, "%s: bad via\n", __func__)) : (void)0); | |||||
5486 | } | |||||
5487 | ||||||
5488 | incoming_set_compartment(irq, tport, msg, 0); | |||||
5489 | ||||||
5490 | if (method == sip_method_invite) { | |||||
5491 | irq->irq_must_100rel = | |||||
5492 | sip->sip_require && sip_has_feature(sip->sip_require, "100rel"); | |||||
5493 | ||||||
5494 | if (irq->irq_must_100rel || | |||||
5495 | (sip->sip_supported && | |||||
5496 | sip_has_feature(sip->sip_supported, "100rel"))) { | |||||
5497 | irq->irq_rseq = su_randint(1, 0x7fffffff); /* Initialize rseq */ | |||||
5498 | } | |||||
5499 | ||||||
5500 | queue = agent->sa_in.proceeding; | |||||
5501 | ||||||
5502 | if (irq->irq_reliable_tp) | |||||
5503 | incoming_set_timer(irq, agent->sa_t2 / 2); /* N1 = T2 / 2 */ | |||||
5504 | else | |||||
5505 | incoming_set_timer(irq, 200); /* N1 = 200 ms */ | |||||
5506 | ||||||
5507 | irq->irq_tport = tport_ref(tport); | |||||
5508 | } | |||||
5509 | else if (method == sip_method_ack) { | |||||
5510 | irq->irq_status = 700; /* Never send reply to ACK */ | |||||
5511 | irq->irq_completed = 1; | |||||
5512 | if (irq->irq_reliable_tp || !agent->sa_is_a_uas) { | |||||
5513 | queue = agent->sa_in.terminated; | |||||
5514 | irq->irq_terminated = 1; | |||||
5515 | } | |||||
5516 | else { | |||||
5517 | queue = agent->sa_in.completed; /* Timer J */ | |||||
5518 | } | |||||
5519 | } | |||||
5520 | else { | |||||
5521 | queue = agent->sa_in.proceeding; | |||||
5522 | /* RFC 4320 (nit-actions-03): | |||||
5523 | ||||||
5524 | Blacklisting on a late response occurs even over reliable transports. | |||||
5525 | Thus, if an element processing a request received over a reliable | |||||
5526 | transport is delaying its final response at all, sending a 100 Trying | |||||
5527 | well in advance of the timeout will prevent blacklisting. Sending a | |||||
5528 | 100 Trying immediately will not harm the transaction as it would over | |||||
5529 | UDP, but a policy of always sending such a message results in | |||||
5530 | unneccessary traffic. A policy of sending a 100 Trying after the | |||||
5531 | period of time in which Timer E reaches T2 had this been a UDP hop is | |||||
5532 | one reasonable compromise. | |||||
5533 | ||||||
5534 | */ | |||||
5535 | if (agent->sa_extra_100 && irq->irq_reliable_tp) | |||||
5536 | incoming_set_timer(irq, agent->sa_t2 / 2); /* T2 / 2 */ | |||||
5537 | ||||||
5538 | irq->irq_tport = tport_ref(tport); | |||||
5539 | } | |||||
5540 | ||||||
5541 | irq->irq_hash = NTA_HASH(irq->irq_call_id, irq->irq_cseq->cs_seq)((irq->irq_call_id)->i_hash + 26839U * (uint32_t)(irq-> irq_cseq->cs_seq)); | |||||
5542 | ||||||
5543 | incoming_insert(agent, queue, irq); | |||||
5544 | } | |||||
5545 | ||||||
5546 | return irq; | |||||
5547 | } | |||||
5548 | ||||||
5549 | /** @internal | |||||
5550 | * Insert incoming transaction to hash table. | |||||
5551 | */ | |||||
5552 | static void | |||||
5553 | incoming_insert(nta_agent_t *agent, | |||||
5554 | incoming_queue_t *queue, | |||||
5555 | nta_incoming_t *irq) | |||||
5556 | { | |||||
5557 | incoming_queue(queue, irq); | |||||
5558 | ||||||
5559 | if (incoming_htable_is_full(agent->sa_incoming)) | |||||
5560 | incoming_htable_resize(agent->sa_home, agent->sa_incoming, 0); | |||||
5561 | ||||||
5562 | if (irq->irq_method != sip_method_ack) | |||||
5563 | incoming_htable_insert(agent->sa_incoming, irq); | |||||
5564 | else | |||||
5565 | /* ACK is appended - final response with tags match with it, | |||||
5566 | * not with the original INVITE transaction */ | |||||
5567 | /* XXX - what about rfc2543 servers, which do not add tag? */ | |||||
5568 | incoming_htable_append(agent->sa_incoming, irq); | |||||
5569 | } | |||||
5570 | ||||||
5571 | /** Call callback for incoming request */ | |||||
5572 | static | |||||
5573 | int incoming_callback(nta_leg_t *leg, nta_incoming_t *irq, sip_t *sip) | |||||
5574 | { | |||||
5575 | sip_method_t method = sip->sip_request->rq_method; | |||||
5576 | char const *method_name = sip->sip_request->rq_method_name; | |||||
5577 | ||||||
5578 | /* RFC-3261 section 12.2.2 (page 76) */ | |||||
5579 | if (leg->leg_dialog && | |||||
5580 | irq->irq_agent->sa_is_a_uas && | |||||
5581 | method != sip_method_ack) { | |||||
5582 | uint32_t seq = sip->sip_cseq->cs_seq; | |||||
5583 | ||||||
5584 | if (leg->leg_rseq > sip->sip_cseq->cs_seq) { | |||||
5585 | SU_DEBUG_3(("nta_leg(%p): out-of-order %s (%u < %u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 5586, "nta_leg(%p): out-of-order %s (%u < %u)\n", (void * )leg, method_name, seq, leg->leg_rseq)) : (void)0) | |||||
5586 | (void *)leg, method_name, seq, leg->leg_rseq))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 5586, "nta_leg(%p): out-of-order %s (%u < %u)\n", (void * )leg, method_name, seq, leg->leg_rseq)) : (void)0); | |||||
5587 | return 500; | |||||
5588 | } | |||||
5589 | ||||||
5590 | leg->leg_rseq = seq; | |||||
5591 | } | |||||
5592 | ||||||
5593 | return leg->leg_callback(leg->leg_magic, leg, irq, sip); | |||||
5594 | } | |||||
5595 | ||||||
5596 | /** | |||||
5597 | * Destroy an incoming transaction. | |||||
5598 | * | |||||
5599 | * This function does not actually free transaction object, but marks it as | |||||
5600 | * disposable. The object is freed after a timeout. | |||||
5601 | * | |||||
5602 | * @param irq incoming request object to be destroyed | |||||
5603 | */ | |||||
5604 | void nta_incoming_destroy(nta_incoming_t *irq) | |||||
5605 | { | |||||
5606 | if (irq) { | |||||
5607 | irq->irq_callback = NULL((void*)0); | |||||
5608 | irq->irq_magic = NULL((void*)0); | |||||
5609 | irq->irq_destroyed = 1; | |||||
5610 | if (!irq->irq_in_callback) { | |||||
5611 | if (irq->irq_terminated || irq->irq_default) | |||||
5612 | incoming_free(irq); | |||||
5613 | else if (irq->irq_status < 200) | |||||
5614 | nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error, TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
5615 | } | |||||
5616 | } | |||||
5617 | } | |||||
5618 | ||||||
5619 | /** @internal | |||||
5620 | * Initialize a queue for incoming transactions. | |||||
5621 | */ | |||||
5622 | static void | |||||
5623 | incoming_queue_init(incoming_queue_t *queue, unsigned timeout) | |||||
5624 | { | |||||
5625 | memset(queue, 0, sizeof *queue); | |||||
5626 | queue->q_tail = &queue->q_head; | |||||
5627 | queue->q_timeout = timeout; | |||||
5628 | } | |||||
5629 | ||||||
5630 | /** Change the timeout value of a queue */ | |||||
5631 | static void | |||||
5632 | incoming_queue_adjust(nta_agent_t *sa, | |||||
5633 | incoming_queue_t *queue, | |||||
5634 | uint32_t timeout) | |||||
5635 | { | |||||
5636 | nta_incoming_t *irq; | |||||
5637 | uint32_t latest; | |||||
5638 | ||||||
5639 | if (timeout >= queue->q_timeout || !queue->q_head) { | |||||
5640 | queue->q_timeout = timeout; | |||||
5641 | return; | |||||
5642 | } | |||||
5643 | ||||||
5644 | latest = set_timeout(sa, queue->q_timeout = timeout); | |||||
5645 | ||||||
5646 | for (irq = queue->q_head; irq; irq = irq->irq_next) { | |||||
5647 | if ((int32_t)(irq->irq_timeout - latest) > 0) | |||||
5648 | irq->irq_timeout = latest; | |||||
5649 | } | |||||
5650 | } | |||||
5651 | ||||||
5652 | /** @internal | |||||
5653 | * Test if an incoming transaction is in a queue. | |||||
5654 | */ | |||||
5655 | su_inlinestatic inline | |||||
5656 | int incoming_is_queued(nta_incoming_t const *irq) | |||||
5657 | { | |||||
5658 | return irq && irq->irq_queue; | |||||
5659 | } | |||||
5660 | ||||||
5661 | /** @internal | |||||
5662 | * Insert an incoming transaction into a queue. | |||||
5663 | * | |||||
5664 | * Insert a server transaction into a queue, and sets the corresponding | |||||
5665 | * timeout at the same time. | |||||
5666 | */ | |||||
5667 | su_inlinestatic inline | |||||
5668 | void incoming_queue(incoming_queue_t *queue, | |||||
5669 | nta_incoming_t *irq) | |||||
5670 | { | |||||
5671 | if (irq->irq_queue == queue) { | |||||
5672 | assert(queue->q_timeout == 0)((void) sizeof ((queue->q_timeout == 0) ? 1 : 0), __extension__ ({ if (queue->q_timeout == 0) ; else __assert_fail ("queue->q_timeout == 0" , "nta.c", 5672, __extension__ __PRETTY_FUNCTION__); })); | |||||
5673 | return; | |||||
5674 | } | |||||
5675 | ||||||
5676 | if (incoming_is_queued(irq)) | |||||
5677 | incoming_remove(irq); | |||||
5678 | ||||||
5679 | assert(*queue->q_tail == NULL)((void) sizeof ((*queue->q_tail == ((void*)0)) ? 1 : 0), __extension__ ({ if (*queue->q_tail == ((void*)0)) ; else __assert_fail ("*queue->q_tail == NULL", "nta.c", 5679, __extension__ __PRETTY_FUNCTION__ ); })); | |||||
5680 | ||||||
5681 | irq->irq_timeout = set_timeout(irq->irq_agent, queue->q_timeout); | |||||
5682 | ||||||
5683 | irq->irq_queue = queue; | |||||
5684 | irq->irq_prev = queue->q_tail; | |||||
5685 | *queue->q_tail = irq; | |||||
5686 | queue->q_tail = &irq->irq_next; | |||||
5687 | queue->q_length++; | |||||
5688 | } | |||||
5689 | ||||||
5690 | /** @internal | |||||
5691 | * Remove an incoming transaction from a queue. | |||||
5692 | */ | |||||
5693 | su_inlinestatic inline | |||||
5694 | void incoming_remove(nta_incoming_t *irq) | |||||
5695 | { | |||||
5696 | assert(incoming_is_queued(irq))((void) sizeof ((incoming_is_queued(irq)) ? 1 : 0), __extension__ ({ if (incoming_is_queued(irq)) ; else __assert_fail ("incoming_is_queued(irq)" , "nta.c", 5696, __extension__ __PRETTY_FUNCTION__); })); | |||||
5697 | assert(irq->irq_queue->q_length > 0)((void) sizeof ((irq->irq_queue->q_length > 0) ? 1 : 0), __extension__ ({ if (irq->irq_queue->q_length > 0) ; else __assert_fail ("irq->irq_queue->q_length > 0" , "nta.c", 5697, __extension__ __PRETTY_FUNCTION__); })); | |||||
5698 | ||||||
5699 | if ((*irq->irq_prev = irq->irq_next)) | |||||
5700 | irq->irq_next->irq_prev = irq->irq_prev; | |||||
5701 | else | |||||
5702 | irq->irq_queue->q_tail = irq->irq_prev, assert(!*irq->irq_queue->q_tail)((void) sizeof ((!*irq->irq_queue->q_tail) ? 1 : 0), __extension__ ({ if (!*irq->irq_queue->q_tail) ; else __assert_fail ( "!*irq->irq_queue->q_tail", "nta.c", 5702, __extension__ __PRETTY_FUNCTION__); })); | |||||
5703 | ||||||
5704 | irq->irq_queue->q_length--; | |||||
5705 | irq->irq_next = NULL((void*)0); | |||||
5706 | irq->irq_prev = NULL((void*)0); | |||||
5707 | irq->irq_queue = NULL((void*)0); | |||||
5708 | irq->irq_timeout = 0; | |||||
5709 | } | |||||
5710 | ||||||
5711 | su_inlinestatic inline | |||||
5712 | void incoming_set_timer(nta_incoming_t *irq, uint32_t interval) | |||||
5713 | { | |||||
5714 | nta_incoming_t **rq; | |||||
5715 | ||||||
5716 | assert(irq)((void) sizeof ((irq) ? 1 : 0), __extension__ ({ if (irq) ; else __assert_fail ("irq", "nta.c", 5716, __extension__ __PRETTY_FUNCTION__ ); })); | |||||
5717 | ||||||
5718 | if (interval == 0) { | |||||
5719 | incoming_reset_timer(irq); | |||||
5720 | return; | |||||
5721 | } | |||||
5722 | ||||||
5723 | if (irq->irq_rprev) { | |||||
5724 | if ((*irq->irq_rprev = irq->irq_rnext)) | |||||
5725 | irq->irq_rnext->irq_rprev = irq->irq_rprev; | |||||
5726 | if (irq->irq_agent->sa_in.re_t1 == &irq->irq_rnext) | |||||
5727 | irq->irq_agent->sa_in.re_t1 = irq->irq_rprev; | |||||
5728 | } else { | |||||
5729 | irq->irq_agent->sa_in.re_length++; | |||||
5730 | } | |||||
5731 | ||||||
5732 | irq->irq_retry = set_timeout(irq->irq_agent, irq->irq_interval = interval); | |||||
5733 | ||||||
5734 | rq = irq->irq_agent->sa_in.re_t1; | |||||
5735 | ||||||
5736 | if (!(*rq) || (int32_t)((*rq)->irq_retry - irq->irq_retry) > 0) | |||||
5737 | rq = &irq->irq_agent->sa_in.re_list; | |||||
5738 | ||||||
5739 | while (*rq && (int32_t)((*rq)->irq_retry - irq->irq_retry) <= 0) | |||||
5740 | rq = &(*rq)->irq_rnext; | |||||
5741 | ||||||
5742 | if ((irq->irq_rnext = *rq)) | |||||
5743 | irq->irq_rnext->irq_rprev = &irq->irq_rnext; | |||||
5744 | *rq = irq; | |||||
5745 | irq->irq_rprev = rq; | |||||
5746 | ||||||
5747 | /* Optimization: keep special place for transactions with T1 interval */ | |||||
5748 | if (interval == irq->irq_agent->sa_t1) | |||||
5749 | irq->irq_agent->sa_in.re_t1 = rq; | |||||
5750 | } | |||||
5751 | ||||||
5752 | su_inlinestatic inline | |||||
5753 | void incoming_reset_timer(nta_incoming_t *irq) | |||||
5754 | { | |||||
5755 | if (irq->irq_rprev) { | |||||
5756 | if ((*irq->irq_rprev = irq->irq_rnext)) | |||||
5757 | irq->irq_rnext->irq_rprev = irq->irq_rprev; | |||||
5758 | if (irq->irq_agent->sa_in.re_t1 == &irq->irq_rnext) | |||||
5759 | irq->irq_agent->sa_in.re_t1 = irq->irq_rprev; | |||||
5760 | irq->irq_agent->sa_in.re_length--; | |||||
5761 | } | |||||
5762 | ||||||
5763 | irq->irq_interval = 0, irq->irq_retry = 0; | |||||
5764 | irq->irq_rnext = NULL((void*)0), irq->irq_rprev = NULL((void*)0); | |||||
5765 | } | |||||
5766 | ||||||
5767 | /** @internal | |||||
5768 | * Free an incoming transaction. | |||||
5769 | */ | |||||
5770 | static | |||||
5771 | void incoming_free(nta_incoming_t *irq) | |||||
5772 | { | |||||
5773 | SU_DEBUG_9(("nta: incoming_free(%p)\n", (void *)irq))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 5773, "nta: incoming_free(%p)\n", (void *)irq)) : (void)0); | |||||
5774 | ||||||
5775 | incoming_cut_off(irq); | |||||
5776 | incoming_reclaim(irq); | |||||
5777 | } | |||||
5778 | ||||||
5779 | /** Remove references to the irq */ | |||||
5780 | su_inlinestatic inline | |||||
5781 | void incoming_cut_off(nta_incoming_t *irq) | |||||
5782 | { | |||||
5783 | nta_agent_t *agent = irq->irq_agent; | |||||
5784 | ||||||
5785 | assert(agent)((void) sizeof ((agent) ? 1 : 0), __extension__ ({ if (agent) ; else __assert_fail ("agent", "nta.c", 5785, __extension__ __PRETTY_FUNCTION__ ); })); | |||||
5786 | ||||||
5787 | if (irq->irq_default) { | |||||
5788 | if (irq == agent->sa_default_incoming) | |||||
5789 | agent->sa_default_incoming = NULL((void*)0); | |||||
5790 | irq->irq_default = 0; | |||||
5791 | return; | |||||
5792 | } | |||||
5793 | ||||||
5794 | if (incoming_is_queued(irq)) | |||||
5795 | incoming_remove(irq); | |||||
5796 | ||||||
5797 | incoming_reset_timer(irq); | |||||
5798 | ||||||
5799 | incoming_htable_remove(agent->sa_incoming, irq); | |||||
5800 | ||||||
5801 | if (irq->irq_cc) | |||||
5802 | nta_compartment_decref(&irq->irq_cc); | |||||
5803 | ||||||
5804 | if (irq->irq_tport) | |||||
5805 | tport_decref(&irq->irq_tport); | |||||
5806 | } | |||||
5807 | ||||||
5808 | /** Reclaim the memory used by irq */ | |||||
5809 | su_inlinestatic inline | |||||
5810 | void incoming_reclaim(nta_incoming_t *irq) | |||||
5811 | { | |||||
5812 | su_home_t *home = irq->irq_home; | |||||
5813 | nta_reliable_t *rel, *rel_next; | |||||
5814 | ||||||
5815 | if (irq->irq_request) | |||||
5816 | msg_destroy(irq->irq_request), irq->irq_request = NULL((void*)0); | |||||
5817 | if (irq->irq_request2) | |||||
5818 | msg_destroy(irq->irq_request2), irq->irq_request2 = NULL((void*)0); | |||||
5819 | if (irq->irq_response) | |||||
5820 | msg_destroy(irq->irq_response), irq->irq_response = NULL((void*)0); | |||||
5821 | ||||||
5822 | for (rel = irq->irq_reliable; rel; rel = rel_next) { | |||||
5823 | rel_next = rel->rel_next; | |||||
5824 | if (rel->rel_unsent) | |||||
5825 | msg_destroy(rel->rel_unsent); | |||||
5826 | su_free(irq->irq_agent->sa_home, rel); | |||||
5827 | } | |||||
5828 | ||||||
5829 | irq->irq_home = NULL((void*)0); | |||||
5830 | ||||||
5831 | su_free(home, irq); | |||||
5832 | ||||||
5833 | msg_destroy((msg_t *)home); | |||||
5834 | } | |||||
5835 | ||||||
5836 | /** Queue request to be freed */ | |||||
5837 | su_inlinestatic inline | |||||
5838 | void incoming_free_queue(incoming_queue_t *q, nta_incoming_t *irq) | |||||
5839 | { | |||||
5840 | incoming_cut_off(irq); | |||||
5841 | incoming_queue(q, irq); | |||||
5842 | } | |||||
5843 | ||||||
5844 | /** Reclaim memory used by queue of requests */ | |||||
5845 | static | |||||
5846 | void incoming_reclaim_queued(su_root_magic_t *rm, | |||||
5847 | su_msg_r msg, | |||||
5848 | union sm_arg_u *u) | |||||
5849 | { | |||||
5850 | incoming_queue_t *q = u->a_incoming_queue; | |||||
5851 | nta_incoming_t *irq, *irq_next; | |||||
5852 | ||||||
5853 | SU_DEBUG_9(("incoming_reclaim_all(%p, %p, %p)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 5854, "incoming_reclaim_all(%p, %p, %p)\n", (void *)rm, (void *)msg, (void *)u)) : (void)0) | |||||
5854 | (void *)rm, (void *)msg, (void *)u))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 5854, "incoming_reclaim_all(%p, %p, %p)\n", (void *)rm, (void *)msg, (void *)u)) : (void)0); | |||||
5855 | ||||||
5856 | for (irq = q->q_head; irq; irq = irq_next) { | |||||
5857 | irq_next = irq->irq_next; | |||||
5858 | incoming_reclaim(irq); | |||||
5859 | } | |||||
5860 | } | |||||
5861 | ||||||
5862 | /**Bind a callback and context to an incoming transaction object | |||||
5863 | * | |||||
5864 | * Set the callback function and context pointer attached to an incoming | |||||
5865 | * request object. The callback function will be invoked if the incoming | |||||
5866 | * request is cancelled, or if the final response to an incoming @b INVITE | |||||
5867 | * request has been acknowledged. | |||||
5868 | * | |||||
5869 | * If the callback is NULL, or no callback has been bound, NTA invokes the | |||||
5870 | * request callback of the call leg. | |||||
5871 | * | |||||
5872 | * @param irq incoming transaction | |||||
5873 | * @param callback callback function | |||||
5874 | * @param magic application context | |||||
5875 | */ | |||||
5876 | void nta_incoming_bind(nta_incoming_t *irq, | |||||
5877 | nta_ack_cancel_f *callback, | |||||
5878 | nta_incoming_magic_t *magic) | |||||
5879 | { | |||||
5880 | if (irq) { | |||||
5881 | irq->irq_callback = callback; | |||||
5882 | irq->irq_magic = magic; | |||||
5883 | } | |||||
5884 | } | |||||
5885 | ||||||
5886 | /** Add a @To tag to incoming request if needed. | |||||
5887 | * | |||||
5888 | * If @a tag is NULL, a new tag is generated. | |||||
5889 | */ | |||||
5890 | char const *nta_incoming_tag(nta_incoming_t *irq, char const *tag) | |||||
5891 | { | |||||
5892 | if (!irq) | |||||
5893 | return su_seterrno(EFAULT14), NULL((void*)0); | |||||
5894 | ||||||
5895 | if (irq->irq_default) | |||||
5896 | return su_seterrno(EINVAL22), NULL((void*)0); | |||||
5897 | ||||||
5898 | if (tag && strchr(tag, '=')) | |||||
5899 | tag = strchr(tag, '=') + 1; | |||||
5900 | ||||||
5901 | if (tag && irq->irq_tag && !su_casematch(tag, irq->irq_tag)) | |||||
5902 | return NULL((void*)0); | |||||
5903 | ||||||
5904 | if (!irq->irq_tag) { | |||||
5905 | if (tag) | |||||
5906 | tag = su_strdup(irq->irq_home, tag); | |||||
5907 | else | |||||
5908 | tag = nta_agent_newtag(irq->irq_home, NULL((void*)0), irq->irq_agent); | |||||
5909 | ||||||
5910 | if (!tag) | |||||
5911 | return tag; | |||||
5912 | ||||||
5913 | irq->irq_tag = tag; | |||||
5914 | irq->irq_tag_set = 1; | |||||
5915 | } | |||||
5916 | ||||||
5917 | return irq->irq_tag; | |||||
5918 | } | |||||
5919 | ||||||
5920 | ||||||
5921 | /**Get request message. | |||||
5922 | * | |||||
5923 | * Retrieve the incoming request message of the incoming transaction. Note | |||||
5924 | * that the message is not copied, but a new reference to it is created. | |||||
5925 | * | |||||
5926 | * @param irq incoming transaction handle | |||||
5927 | * | |||||
5928 | * @retval | |||||
5929 | * A pointer to request message is returned. | |||||
5930 | */ | |||||
5931 | msg_t *nta_incoming_getrequest(nta_incoming_t *irq) | |||||
5932 | { | |||||
5933 | msg_t *msg = NULL((void*)0); | |||||
5934 | ||||||
5935 | if (irq && !irq->irq_default) | |||||
5936 | msg = msg_ref_create(irq->irq_request); | |||||
5937 | ||||||
5938 | return msg; | |||||
5939 | } | |||||
5940 | ||||||
5941 | /**Get ACK or CANCEL message. | |||||
5942 | * | |||||
5943 | * Retrieve the incoming ACK or CANCEL request message of the incoming | |||||
5944 | * transaction. Note that the ACK or CANCEL message is not copied, but a new | |||||
5945 | * reference to it is created. | |||||
5946 | * | |||||
5947 | * @param irq incoming transaction handle | |||||
5948 | * | |||||
5949 | * @retval A pointer to request message is returned, or NULL if there is no | |||||
5950 | * CANCEL or ACK received. | |||||
5951 | */ | |||||
5952 | msg_t *nta_incoming_getrequest_ackcancel(nta_incoming_t *irq) | |||||
5953 | { | |||||
5954 | msg_t *msg = NULL((void*)0); | |||||
5955 | ||||||
5956 | if (irq && irq->irq_request2) | |||||
5957 | msg = msg_ref_create(irq->irq_request2); | |||||
5958 | ||||||
5959 | return msg; | |||||
5960 | } | |||||
5961 | ||||||
5962 | /**Get response message. | |||||
5963 | * | |||||
5964 | * Retrieve the response message latest sent by the server transaction. Note | |||||
5965 | * that the message is not copied, but a new reference to it is created. Use | |||||
5966 | * msg_dup() or msg_copy() to make a copy of it. | |||||
5967 | * | |||||
5968 | * @param irq incoming transaction handle | |||||
5969 | * | |||||
5970 | * @retval | |||||
5971 | * A pointer to a response message is returned. | |||||
5972 | */ | |||||
5973 | msg_t *nta_incoming_getresponse(nta_incoming_t *irq) | |||||
5974 | { | |||||
5975 | msg_t *msg = NULL((void*)0); | |||||
5976 | ||||||
5977 | if (irq && irq->irq_response) | |||||
5978 | msg = msg_ref_create(irq->irq_response); | |||||
5979 | ||||||
5980 | return msg; | |||||
5981 | } | |||||
5982 | ||||||
5983 | /** Get method of a server transaction. */ | |||||
5984 | sip_method_t nta_incoming_method(nta_incoming_t const *irq) | |||||
5985 | { | |||||
5986 | return irq ? irq->irq_method : sip_method_invalid; | |||||
5987 | } | |||||
5988 | ||||||
5989 | /** Get method name of a server transaction. */ | |||||
5990 | char const *nta_incoming_method_name(nta_incoming_t const *irq) | |||||
5991 | { | |||||
5992 | if (irq == NULL((void*)0)) | |||||
5993 | return NULL((void*)0); | |||||
5994 | else if (irq->irq_rq) | |||||
5995 | return irq->irq_rq->rq_method_name; | |||||
5996 | else | |||||
5997 | return "*"; | |||||
5998 | } | |||||
5999 | ||||||
6000 | /** Get Request-URI of a server transaction */ | |||||
6001 | url_t const *nta_incoming_url(nta_incoming_t const *irq) | |||||
6002 | { | |||||
6003 | return irq && irq->irq_rq ? irq->irq_rq->rq_url : NULL((void*)0); | |||||
6004 | } | |||||
6005 | ||||||
6006 | /** Get sequence number of a server transaction. | |||||
6007 | */ | |||||
6008 | uint32_t nta_incoming_cseq(nta_incoming_t const *irq) | |||||
6009 | { | |||||
6010 | return irq && irq->irq_cseq ? irq->irq_cseq->cs_seq : 0; | |||||
6011 | } | |||||
6012 | ||||||
6013 | /** Get local tag for incoming request */ | |||||
6014 | char const *nta_incoming_gettag(nta_incoming_t const *irq) | |||||
6015 | { | |||||
6016 | return irq ? irq->irq_tag : 0; | |||||
6017 | } | |||||
6018 | ||||||
6019 | /** | |||||
6020 | * Get status code of a server transaction. | |||||
6021 | */ | |||||
6022 | int nta_incoming_status(nta_incoming_t const *irq) | |||||
6023 | { | |||||
6024 | return irq ? irq->irq_status : 400; | |||||
6025 | } | |||||
6026 | ||||||
6027 | /** Get application context for a server transaction. | |||||
6028 | * | |||||
6029 | * @param irq server transaction | |||||
6030 | * @param callback callback pointer | |||||
6031 | * | |||||
6032 | * Return the application context bound to the server transaction. If the @a | |||||
6033 | * callback function pointer is given, return application context only if | |||||
6034 | * the callback matches with the callback bound to the server transaction. | |||||
6035 | * | |||||
6036 | */ | |||||
6037 | nta_incoming_magic_t *nta_incoming_magic(nta_incoming_t *irq, | |||||
6038 | nta_ack_cancel_f *callback) | |||||
6039 | { | |||||
6040 | return irq && (callback == NULL((void*)0) || irq->irq_callback == callback) | |||||
6041 | ? irq->irq_magic : NULL((void*)0); | |||||
6042 | } | |||||
6043 | ||||||
6044 | /** When received. | |||||
6045 | * | |||||
6046 | * Return timestamp from the reception of the initial request. | |||||
6047 | * | |||||
6048 | * @NEW_1_12_7. | |||||
6049 | */ | |||||
6050 | sip_time_t nta_incoming_received(nta_incoming_t *irq, | |||||
6051 | su_nanotime_t *return_nano) | |||||
6052 | { | |||||
6053 | su_time_t tv = { 0, 0 }; | |||||
6054 | ||||||
6055 | if (irq) | |||||
6056 | tv = irq->irq_received; | |||||
6057 | ||||||
6058 | if (return_nano) | |||||
6059 | *return_nano = (su_nanotime_t)tv.tv_sec * 1000000000 + tv.tv_usec * 1000; | |||||
6060 | ||||||
6061 | return tv.tv_sec; | |||||
6062 | } | |||||
6063 | ||||||
6064 | /** Find incoming transaction. */ | |||||
6065 | nta_incoming_t *nta_incoming_find(nta_agent_t const *agent, | |||||
6066 | sip_t const *sip, | |||||
6067 | sip_via_t const *v) | |||||
6068 | { | |||||
6069 | if (agent && sip && v) | |||||
6070 | return incoming_find(agent, sip, v, NULL((void*)0), NULL((void*)0), NULL((void*)0)); | |||||
6071 | else | |||||
6072 | return NULL((void*)0); | |||||
6073 | } | |||||
6074 | ||||||
6075 | /** Find a matching server transaction object. | |||||
6076 | * | |||||
6077 | * Check also for requests to merge, to ACK, or to CANCEL. | |||||
6078 | */ | |||||
6079 | static nta_incoming_t *incoming_find(nta_agent_t const *agent, | |||||
6080 | sip_t const *sip, | |||||
6081 | sip_via_t const *v, | |||||
6082 | nta_incoming_t **return_merge, | |||||
6083 | nta_incoming_t **return_ack, | |||||
6084 | nta_incoming_t **return_cancel) | |||||
6085 | { | |||||
6086 | sip_cseq_t const *cseq = sip->sip_cseq; | |||||
6087 | sip_call_id_t const *i = sip->sip_call_id; | |||||
6088 | sip_to_t const *to = sip->sip_to; | |||||
6089 | sip_from_t const *from = sip->sip_from; | |||||
6090 | sip_request_t *rq = sip->sip_request; | |||||
6091 | incoming_htable_t const *iht = agent->sa_incoming; | |||||
6092 | hash_value_t hash = NTA_HASH(i, cseq->cs_seq)((i)->i_hash + 26839U * (uint32_t)(cseq->cs_seq)); | |||||
6093 | char const *magic_branch; | |||||
6094 | ||||||
6095 | nta_incoming_t **ii, *irq; | |||||
6096 | ||||||
6097 | int is_uas_ack = return_ack && agent->sa_is_a_uas; | |||||
6098 | ||||||
6099 | if (v->v_branch && su_casenmatch(v->v_branch, "z9hG4bK", 7)) | |||||
6100 | magic_branch = v->v_branch + 7; | |||||
6101 | else | |||||
6102 | magic_branch = NULL((void*)0); | |||||
6103 | ||||||
6104 | for (ii = incoming_htable_hash(iht, hash); | |||||
6105 | (irq = *ii); | |||||
6106 | ii = incoming_htable_next(iht, ii)) { | |||||
6107 | if (hash != irq->irq_hash || | |||||
6108 | irq->irq_call_id->i_hash != i->i_hash || | |||||
6109 | strcmp(irq->irq_call_id->i_id, i->i_id)) | |||||
6110 | continue; | |||||
6111 | if (irq->irq_cseq->cs_seq != cseq->cs_seq) | |||||
6112 | continue; | |||||
6113 | if (su_strcasecmp(irq->irq_from->a_tag, from->a_tag)) | |||||
6114 | continue; | |||||
6115 | ||||||
6116 | if (is_uas_ack && | |||||
6117 | irq->irq_method == sip_method_invite && | |||||
6118 | 200 <= irq->irq_status && irq->irq_status < 300 && | |||||
6119 | su_casematch(irq->irq_tag, to->a_tag)) { | |||||
6120 | *return_ack = irq; | |||||
6121 | return NULL((void*)0); | |||||
6122 | } | |||||
6123 | ||||||
6124 | if (magic_branch) { | |||||
6125 | /* RFC3261 17.2.3: | |||||
6126 | * | |||||
6127 | * The request matches a transaction if branch and sent-by in topmost | |||||
6128 | * the method of the request matches the one that created the | |||||
6129 | * transaction, except for ACK, where the method of the request | |||||
6130 | * that created the transaction is INVITE. | |||||
6131 | */ | |||||
6132 | if (irq->irq_via->v_branch && | |||||
6133 | su_casematch(irq->irq_via->v_branch + 7, magic_branch) && | |||||
6134 | su_casematch(irq->irq_via->v_host, v->v_host) && | |||||
6135 | su_strmatch(irq->irq_via->v_port, v->v_port)) { | |||||
6136 | if (irq->irq_method == cseq->cs_method && | |||||
6137 | strcmp(irq->irq_cseq->cs_method_name, | |||||
6138 | cseq->cs_method_name) == 0) | |||||
6139 | return irq; | |||||
6140 | if (return_ack && irq->irq_method == sip_method_invite) | |||||
6141 | return *return_ack = irq, NULL((void*)0); | |||||
6142 | if (return_cancel && irq->irq_method != sip_method_ack) | |||||
6143 | return *return_cancel = irq, NULL((void*)0); | |||||
6144 | } | |||||
6145 | } | |||||
6146 | else { | |||||
6147 | /* No magic branch */ | |||||
6148 | ||||||
6149 | /* INVITE request matches a transaction if | |||||
6150 | the Request-URI, To tag, From tag, Call-ID, CSeq, and | |||||
6151 | top Via header match */ | |||||
6152 | ||||||
6153 | /* From tag, Call-ID, and CSeq number has been matched above */ | |||||
6154 | ||||||
6155 | /* Match top Via header field */ | |||||
6156 | if (!su_casematch(irq->irq_via->v_branch, v->v_branch) || | |||||
6157 | !su_casematch(irq->irq_via->v_host, v->v_host) || | |||||
6158 | !su_strmatch(irq->irq_via->v_port, v->v_port)) | |||||
6159 | ; | |||||
6160 | /* Match Request-URI */ | |||||
6161 | else if (url_cmp(irq->irq_rq->rq_url, rq->rq_url)) | |||||
6162 | ; | |||||
6163 | else { | |||||
6164 | /* Match CSeq */ | |||||
6165 | if (irq->irq_method == cseq->cs_method && | |||||
6166 | su_strmatch(irq->irq_cseq->cs_method_name, cseq->cs_method_name)) { | |||||
6167 | /* Match To tag */ | |||||
6168 | if (!su_strcasecmp(irq->irq_to->a_tag, to->a_tag)) | |||||
6169 | return irq; /* found */ | |||||
6170 | } | |||||
6171 | else if ( | |||||
6172 | /* Tag set by UAS */ | |||||
6173 | su_strcasecmp(irq->irq_tag, to->a_tag) && | |||||
6174 | /* Original tag */ | |||||
6175 | su_strcasecmp(irq->irq_to->a_tag, to->a_tag)) | |||||
6176 | ; | |||||
6177 | else if (return_ack && irq->irq_method == sip_method_invite) | |||||
6178 | return *return_ack = irq, NULL((void*)0); | |||||
6179 | else if (return_cancel && irq->irq_method != sip_method_ack) | |||||
6180 | return *return_cancel = irq, NULL((void*)0); | |||||
6181 | } | |||||
6182 | } | |||||
6183 | ||||||
6184 | /* RFC3261 - section 8.2.2.2 Merged Requests */ | |||||
6185 | if (return_merge) { | |||||
6186 | if (irq->irq_cseq->cs_method == cseq->cs_method && | |||||
6187 | strcmp(irq->irq_cseq->cs_method_name, | |||||
6188 | cseq->cs_method_name) == 0) | |||||
6189 | *return_merge = irq, return_merge = NULL((void*)0); | |||||
6190 | } | |||||
6191 | } | |||||
6192 | ||||||
6193 | return NULL((void*)0); | |||||
6194 | } | |||||
6195 | ||||||
6196 | /** Process retransmitted requests. */ | |||||
6197 | su_inlinestatic inline | |||||
6198 | int | |||||
6199 | incoming_recv(nta_incoming_t *irq, msg_t *msg, sip_t *sip, tport_t *tport) | |||||
6200 | { | |||||
6201 | nta_agent_t *agent = irq->irq_agent; | |||||
6202 | ||||||
6203 | agent->sa_stats->as_recv_retry++; | |||||
6204 | ||||||
6205 | if (irq->irq_status >= 100) { | |||||
6206 | SU_DEBUG_5(("nta: re-received %s request, retransmitting %u reply\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 6207, "nta: re-received %s request, retransmitting %u reply\n" , sip->sip_request->rq_method_name, irq->irq_status) ) : (void)0) | |||||
6207 | sip->sip_request->rq_method_name, irq->irq_status))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 6207, "nta: re-received %s request, retransmitting %u reply\n" , sip->sip_request->rq_method_name, irq->irq_status) ) : (void)0); | |||||
6208 | incoming_retransmit_reply(irq, tport); | |||||
6209 | } | |||||
6210 | else if (irq->irq_agent->sa_extra_100 && | |||||
6211 | irq->irq_extra_100) { | |||||
6212 | /* Agent and Irq configured to answer automatically with 100 Trying */ | |||||
6213 | if (irq->irq_method == sip_method_invite || | |||||
6214 | /* | |||||
6215 | * Send 100 trying to non-invite if at least half of T2 has expired | |||||
6216 | * since the transaction was created. | |||||
6217 | */ | |||||
6218 | su_duration(agent_now(irq->irq_agent), irq->irq_received) * 2U > | |||||
6219 | irq->irq_agent->sa_t2) { | |||||
6220 | SU_DEBUG_5(("nta: re-received %s request, sending 100 Trying\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 6221, "nta: re-received %s request, sending 100 Trying\n", sip ->sip_request->rq_method_name)) : (void)0) | |||||
6221 | sip->sip_request->rq_method_name))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 6221, "nta: re-received %s request, sending 100 Trying\n", sip ->sip_request->rq_method_name)) : (void)0); | |||||
6222 | nta_incoming_treply(irq, SIP_100_TRYING100, sip_100_Trying, NTATAG_TPORT(tport)ntatag_tport, tag_ptr_v((tport)), TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
6223 | } | |||||
6224 | } | |||||
6225 | ||||||
6226 | msg_destroy(msg); | |||||
6227 | ||||||
6228 | return 0; | |||||
6229 | } | |||||
6230 | ||||||
6231 | su_inlinestatic inline | |||||
6232 | int incoming_ack(nta_incoming_t *irq, msg_t *msg, sip_t *sip, tport_t *tport) | |||||
6233 | { | |||||
6234 | nta_agent_t *agent = irq->irq_agent; | |||||
6235 | ||||||
6236 | /* Process ACK separately? */ | |||||
6237 | if (irq->irq_status >= 200 && irq->irq_status < 300 && !agent->sa_is_a_uas) | |||||
6238 | return -1; | |||||
6239 | ||||||
6240 | if (irq->irq_queue == agent->sa_in.inv_completed) { | |||||
6241 | if (!irq->irq_confirmed) | |||||
6242 | agent->sa_stats->as_acked_tr++; | |||||
6243 | ||||||
6244 | irq->irq_confirmed = 1; | |||||
6245 | incoming_reset_timer(irq); /* Reset timer G */ | |||||
6246 | ||||||
6247 | if (!irq->irq_reliable_tp) { | |||||
6248 | incoming_queue(agent->sa_in.inv_confirmed, irq); /* Timer I */ | |||||
6249 | } | |||||
6250 | else { | |||||
6251 | irq->irq_terminated = 1; | |||||
6252 | incoming_queue(agent->sa_in.terminated, irq); | |||||
6253 | } | |||||
6254 | ||||||
6255 | if (!irq->irq_destroyed) { | |||||
6256 | if (!irq->irq_callback) /* Process ACK normally */ | |||||
6257 | return -1; | |||||
6258 | ||||||
6259 | incoming_call_callback(irq, msg, sip); /* ACK callback */ | |||||
6260 | } | |||||
6261 | } else if (irq->irq_queue == agent->sa_in.proceeding || | |||||
6262 | irq->irq_queue == agent->sa_in.preliminary) | |||||
6263 | return -1; | |||||
6264 | else | |||||
6265 | assert(irq->irq_queue == agent->sa_in.inv_confirmed ||((void) sizeof ((irq->irq_queue == agent->sa_in.inv_confirmed || irq->irq_queue == agent->sa_in.terminated) ? 1 : 0) , __extension__ ({ if (irq->irq_queue == agent->sa_in.inv_confirmed || irq->irq_queue == agent->sa_in.terminated) ; else __assert_fail ("irq->irq_queue == agent->sa_in.inv_confirmed || irq->irq_queue == agent->sa_in.terminated" , "nta.c", 6266, __extension__ __PRETTY_FUNCTION__); })) | |||||
6266 | irq->irq_queue == agent->sa_in.terminated)((void) sizeof ((irq->irq_queue == agent->sa_in.inv_confirmed || irq->irq_queue == agent->sa_in.terminated) ? 1 : 0) , __extension__ ({ if (irq->irq_queue == agent->sa_in.inv_confirmed || irq->irq_queue == agent->sa_in.terminated) ; else __assert_fail ("irq->irq_queue == agent->sa_in.inv_confirmed || irq->irq_queue == agent->sa_in.terminated" , "nta.c", 6266, __extension__ __PRETTY_FUNCTION__); })); | |||||
6267 | ||||||
6268 | msg_destroy(msg); | |||||
6269 | ||||||
6270 | return 0; | |||||
6271 | } | |||||
6272 | ||||||
6273 | /** Respond to the CANCEL. */ | |||||
6274 | su_inlinestatic inline | |||||
6275 | int incoming_cancel(nta_incoming_t *irq, msg_t *msg, sip_t *sip, | |||||
6276 | tport_t *tport) | |||||
6277 | { | |||||
6278 | nta_agent_t *agent = irq->irq_agent; | |||||
6279 | ||||||
6280 | /* According to the RFC 3261, this INVITE has been destroyed */ | |||||
6281 | if (irq->irq_method == sip_method_invite && | |||||
6282 | 200 <= irq->irq_status && irq->irq_status < 300) { | |||||
6283 | mreply(agent, NULL((void*)0), SIP_481_NO_TRANSACTION481, sip_481_No_transaction, msg, | |||||
6284 | tport, 0, 0, NULL((void*)0), | |||||
6285 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
6286 | return 0; | |||||
6287 | } | |||||
6288 | ||||||
6289 | /* UAS MUST use same tag in final response to CANCEL and INVITE */ | |||||
6290 | if (agent->sa_is_a_uas && irq->irq_tag == NULL((void*)0)) { | |||||
6291 | nta_incoming_tag(irq, NULL((void*)0)); | |||||
6292 | } | |||||
6293 | ||||||
6294 | mreply(agent, NULL((void*)0), SIP_200_OK200, sip_200_OK, msg_ref_create(msg), | |||||
6295 | tport, 0, 0, irq->irq_tag, | |||||
6296 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
6297 | ||||||
6298 | /* We have already sent final response */ | |||||
6299 | if (irq->irq_completed || irq->irq_method != sip_method_invite) { | |||||
6300 | msg_destroy(msg); | |||||
6301 | return 0; | |||||
6302 | } | |||||
6303 | ||||||
6304 | if (!irq->irq_canceled) { | |||||
6305 | irq->irq_canceled = 1; | |||||
6306 | agent->sa_stats->as_canceled_tr++; | |||||
6307 | irq = incoming_call_callback(irq, msg, sip); | |||||
6308 | } | |||||
6309 | ||||||
6310 | if (irq && !irq->irq_completed && agent->sa_cancel_487) | |||||
6311 | /* Respond to the cancelled request */ | |||||
6312 | nta_incoming_treply(irq, SIP_487_REQUEST_CANCELLED487, sip_487_Request_terminated, TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
6313 | ||||||
6314 | msg_destroy(msg); | |||||
6315 | ||||||
6316 | return 0; | |||||
6317 | } | |||||
6318 | ||||||
6319 | /** Merge request */ | |||||
6320 | static | |||||
6321 | void request_merge(nta_agent_t *agent, | |||||
6322 | msg_t *msg, sip_t *sip, tport_t *tport, | |||||
6323 | char const *to_tag) | |||||
6324 | { | |||||
6325 | nta_incoming_t *irq; | |||||
6326 | ||||||
6327 | agent->sa_stats->as_merged_request++; | |||||
6328 | ||||||
6329 | irq = incoming_create(agent, msg, sip, tport, to_tag); | |||||
6330 | ||||||
6331 | if (irq) { | |||||
6332 | nta_incoming_treply(irq, 482, "Request merged", TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
6333 | nta_incoming_destroy(irq); | |||||
6334 | } else { | |||||
6335 | SU_DEBUG_3(("nta: request_merge(): cannot create transaction for %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 6336, "nta: request_merge(): cannot create transaction for %s\n" , sip->sip_request->rq_method_name)) : (void)0) | |||||
6336 | sip->sip_request->rq_method_name))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 6336, "nta: request_merge(): cannot create transaction for %s\n" , sip->sip_request->rq_method_name)) : (void)0); | |||||
6337 | mreply(agent, NULL((void*)0), 482, "Request merged", msg, | |||||
6338 | tport, 0, 0, NULL((void*)0), | |||||
6339 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
6340 | } | |||||
6341 | } | |||||
6342 | ||||||
6343 | /**@typedef nta_ack_cancel_f | |||||
6344 | * | |||||
6345 | * Callback function prototype for CANCELed/ACKed requests | |||||
6346 | * | |||||
6347 | * This is a callback function is invoked by NTA when an incoming request | |||||
6348 | * has been cancelled or an response to an incoming INVITE request has been | |||||
6349 | * acknowledged. | |||||
6350 | * | |||||
6351 | * @param magic incoming request context | |||||
6352 | * @param ireq incoming request | |||||
6353 | * @param sip ACK/CANCEL message | |||||
6354 | * | |||||
6355 | * @retval 0 | |||||
6356 | * This callback function should return always 0. | |||||
6357 | */ | |||||
6358 | ||||||
6359 | /** Call callback of incoming transaction */ | |||||
6360 | su_inlinestatic inline | |||||
6361 | nta_incoming_t * | |||||
6362 | incoming_call_callback(nta_incoming_t *irq, msg_t *msg, sip_t *sip) | |||||
6363 | { | |||||
6364 | if (irq->irq_callback) { | |||||
6365 | irq->irq_in_callback = 1; | |||||
6366 | irq->irq_request2 = msg; | |||||
6367 | irq->irq_callback(irq->irq_magic, irq, sip); | |||||
6368 | irq->irq_request2 = NULL((void*)0); | |||||
6369 | irq->irq_in_callback = 0; | |||||
6370 | ||||||
6371 | if (irq->irq_terminated && irq->irq_destroyed) | |||||
6372 | incoming_free(irq), irq = NULL((void*)0); | |||||
6373 | } | |||||
6374 | return irq; | |||||
6375 | } | |||||
6376 | ||||||
6377 | /**Set server transaction parameters. | |||||
6378 | * | |||||
6379 | * Sets the server transaction parameters. Among others, parameters determine the way | |||||
6380 | * the SigComp compression is handled. | |||||
6381 | * | |||||
6382 | * @TAGS | |||||
6383 | * NTATAG_COMP(), NTATAG_SIGCOMP_CLOSE() and NTATAG_EXTRA_100(). | |||||
6384 | * | |||||
6385 | * @retval number of set parameters when succesful | |||||
6386 | * @retval -1 upon an error | |||||
6387 | */ | |||||
6388 | int nta_incoming_set_params(nta_incoming_t *irq, | |||||
6389 | tag_type_t tag, tag_value_t value, ...) | |||||
6390 | { | |||||
6391 | int retval = -1; | |||||
6392 | ||||||
6393 | if (irq) { | |||||
6394 | ta_list ta; | |||||
6395 | ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value = (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag ) == tag_next && (ta_start__value) != 0) { ta_start__tag = ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag == tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag == tag_next) { ta_start__value = ((tagi_t *)ta_start__value) ->t_value; } else { ta_start__tag = tag_next; break; } } ( ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value ; if (ta_start__tag != ((void*)0) && ta_start__tag != tag_null && ta_start__tag != tag_next) { va_list ta_start__ap ; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag = tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap ); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value = 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0); | |||||
6396 | retval = incoming_set_params(irq, ta_args(ta)(ta).tl); | |||||
6397 | ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value ))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta) .ap)); | |||||
6398 | } | |||||
6399 | else { | |||||
6400 | su_seterrno(EINVAL22); | |||||
6401 | } | |||||
6402 | ||||||
6403 | return retval; | |||||
6404 | } | |||||
6405 | ||||||
6406 | static | |||||
6407 | int incoming_set_params(nta_incoming_t *irq, tagi_t const *tags) | |||||
6408 | { | |||||
6409 | int retval = 0; | |||||
6410 | ||||||
6411 | tagi_t const *t; | |||||
6412 | char const *comp = NONE((void *)-1); | |||||
6413 | struct sigcomp_compartment *cc = NONE((void *)-1); | |||||
6414 | ||||||
6415 | if (irq->irq_default) | |||||
6416 | return retval; | |||||
6417 | ||||||
6418 | for (t = tags; t; t = tl_next(t)) { | |||||
6419 | tag_type_t tt = t->t_tag; | |||||
6420 | ||||||
6421 | if (ntatag_comp == tt) | |||||
6422 | comp = (char const *)t->t_value, retval++; | |||||
6423 | ||||||
6424 | else if (ntatag_sigcomp_close == tt) | |||||
6425 | irq->irq_sigcomp_zap = t->t_value != 0, retval++; | |||||
6426 | ||||||
6427 | else if (tptag_compartment == tt) | |||||
6428 | cc = (void *)t->t_value, retval++; | |||||
6429 | ||||||
6430 | else if (ntatag_extra_100 == tt) | |||||
6431 | irq->irq_extra_100 = t->t_value != 0, retval++; | |||||
6432 | } | |||||
6433 | ||||||
6434 | if (cc != NONE((void *)-1)) { | |||||
6435 | if (cc) | |||||
6436 | agent_accept_compressed(irq->irq_agent, irq->irq_request, cc); | |||||
6437 | if (irq->irq_cc) | |||||
6438 | nta_compartment_decref(&irq->irq_cc); | |||||
6439 | irq->irq_cc = nta_compartment_ref(cc); | |||||
6440 | } | |||||
6441 | else if (comp != NULL((void*)0) && comp != NONE((void *)-1) && irq->irq_cc == NULL((void*)0)) { | |||||
6442 | incoming_set_compartment(irq, irq->irq_tport, irq->irq_request, 1); | |||||
6443 | } | |||||
6444 | ||||||
6445 | else if (comp == NULL((void*)0)) { | |||||
6446 | irq->irq_tpn->tpn_comp = NULL((void*)0); | |||||
6447 | } | |||||
6448 | ||||||
6449 | return retval; | |||||
6450 | } | |||||
6451 | ||||||
6452 | su_inlinestatic inline | |||||
6453 | int incoming_set_compartment(nta_incoming_t *irq, tport_t *tport, msg_t *msg, | |||||
6454 | int create_if_needed) | |||||
6455 | { | |||||
6456 | if (!nta_compressor_vtable) | |||||
6457 | return 0; | |||||
6458 | ||||||
6459 | if (irq->irq_cc == NULL((void*)0) | |||||
6460 | || irq->irq_tpn->tpn_comp | |||||
6461 | || tport_delivered_with_comp(tport, msg, NULL((void*)0)) != -1) { | |||||
6462 | struct sigcomp_compartment *cc; | |||||
6463 | ||||||
6464 | cc = agent_compression_compartment(irq->irq_agent, tport, irq->irq_tpn, | |||||
6465 | create_if_needed); | |||||
6466 | ||||||
6467 | if (cc) | |||||
6468 | agent_accept_compressed(irq->irq_agent, msg, cc); | |||||
6469 | ||||||
6470 | irq->irq_cc = cc; | |||||
6471 | } | |||||
6472 | ||||||
6473 | return 0; | |||||
6474 | } | |||||
6475 | ||||||
6476 | /** Add essential headers to the response message */ | |||||
6477 | static int nta_incoming_response_headers(nta_incoming_t *irq, | |||||
6478 | msg_t *msg, | |||||
6479 | sip_t *sip) | |||||
6480 | { | |||||
6481 | int clone = 0; | |||||
6482 | su_home_t *home = msg_home(msg)((su_home_t*)(msg)); | |||||
6483 | ||||||
6484 | if (!sip->sip_from) | |||||
6485 | clone = 1, sip->sip_from = sip_from_copy(home, irq->irq_from); | |||||
6486 | if (!sip->sip_to) | |||||
6487 | clone = 1, sip->sip_to = sip_to_copy(home, irq->irq_to); | |||||
6488 | if (!sip->sip_call_id) | |||||
6489 | clone = 1, sip->sip_call_id = sip_call_id_copy(home, irq->irq_call_id); | |||||
6490 | if (!sip->sip_cseq) | |||||
6491 | clone = 1, sip->sip_cseq = sip_cseq_copy(home, irq->irq_cseq); | |||||
6492 | if (!sip->sip_via) { | |||||
6493 | clone = 1; | |||||
6494 | /* 100 responses are not forwarded by proxies, so only include the topmost Via header */ | |||||
6495 | if (sip->sip_status && sip->sip_status->st_status == 100) | |||||
6496 | sip->sip_via = (sip_via_t *)msg_header_copy_one(home, (msg_header_t const *)irq->irq_via); | |||||
6497 | else | |||||
6498 | sip->sip_via = sip_via_copy(home, irq->irq_via); | |||||
6499 | } | |||||
6500 | ||||||
6501 | if (clone) | |||||
6502 | msg_set_parent(msg, (msg_t *)irq->irq_home); | |||||
6503 | ||||||
6504 | if (!sip->sip_from || !sip->sip_to || !sip->sip_call_id || !sip->sip_cseq || !sip->sip_via) | |||||
6505 | return -1; | |||||
6506 | ||||||
6507 | return 0; | |||||
6508 | } | |||||
6509 | ||||||
6510 | /** Complete a response message. | |||||
6511 | * | |||||
6512 | * @param irq server transaction object | |||||
6513 | * @param msg response message to be completed | |||||
6514 | * @param status status code (in range 100 - 699) | |||||
6515 | * @param phrase status phrase (may be NULL) | |||||
6516 | * @param tag,value,... taged argument list | |||||
6517 | * | |||||
6518 | * Generate status structure based on @a status and @a phrase. | |||||
6519 | * Add essential headers to the response message: | |||||
6520 | * @From, @To, @CallID, @CSeq, @Via, and optionally | |||||
6521 | * @RecordRoute. | |||||
6522 | */ | |||||
6523 | int nta_incoming_complete_response(nta_incoming_t *irq, | |||||
6524 | msg_t *msg, | |||||
6525 | int status, | |||||
6526 | char const *phrase, | |||||
6527 | tag_type_t tag, tag_value_t value, ...) | |||||
6528 | { | |||||
6529 | su_home_t *home = msg_home(msg)((su_home_t*)(msg)); | |||||
6530 | sip_t *sip = sip_object(msg); | |||||
6531 | int retval; | |||||
6532 | ta_list ta; | |||||
6533 | ||||||
6534 | if (irq == NULL((void*)0) || sip == NULL((void*)0)) | |||||
6535 | return su_seterrno(EFAULT14), -1; | |||||
6536 | ||||||
6537 | if (status != 0 && (status < 100 || status > 699)) | |||||
6538 | return su_seterrno(EINVAL22), -1; | |||||
6539 | ||||||
6540 | if (status != 0 && !sip->sip_status) | |||||
6541 | sip->sip_status = sip_status_create(home, status, phrase, NULL((void*)0)); | |||||
6542 | ||||||
6543 | ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value = (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag ) == tag_next && (ta_start__value) != 0) { ta_start__tag = ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag == tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag == tag_next) { ta_start__value = ((tagi_t *)ta_start__value) ->t_value; } else { ta_start__tag = tag_next; break; } } ( ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value ; if (ta_start__tag != ((void*)0) && ta_start__tag != tag_null && ta_start__tag != tag_next) { va_list ta_start__ap ; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag = tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap ); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value = 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0); | |||||
6544 | retval = sip_add_tl(msg, sip, ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta). tl[1].t_value); | |||||
6545 | ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value ))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta) .ap)); | |||||
6546 | ||||||
6547 | if (retval < 0) | |||||
6548 | return -1; | |||||
6549 | ||||||
6550 | if (irq->irq_default) | |||||
6551 | return sip_complete_message(msg); | |||||
6552 | ||||||
6553 | if (status > 100 && !irq->irq_tag) { | |||||
6554 | if (sip->sip_to) | |||||
6555 | nta_incoming_tag(irq, sip->sip_to->a_tag); | |||||
6556 | else | |||||
6557 | nta_incoming_tag(irq, NULL((void*)0)); | |||||
6558 | } | |||||
6559 | ||||||
6560 | if (nta_incoming_response_headers(irq, msg, sip) < 0) | |||||
6561 | return -1; | |||||
6562 | ||||||
6563 | if (sip->sip_status && sip->sip_status->st_status > 100 && | |||||
6564 | irq->irq_tag && sip->sip_to && !sip->sip_to->a_tag) | |||||
6565 | if (sip_to_tag(home, sip->sip_to, irq->irq_tag) < 0) | |||||
6566 | return -1; | |||||
6567 | ||||||
6568 | if (status > 100 && status < 300 && !sip->sip_record_route && irq->irq_record_route) | |||||
6569 | if (sip_add_dup(msg, sip, (sip_header_t *)irq->irq_record_route) < 0) | |||||
6570 | return -1; | |||||
6571 | ||||||
6572 | return sip_complete_message(msg); | |||||
6573 | } | |||||
6574 | ||||||
6575 | ||||||
6576 | /** Create a response message for request. | |||||
6577 | * | |||||
6578 | * @NEW_1_12_5. | |||||
6579 | */ | |||||
6580 | msg_t *nta_incoming_create_response(nta_incoming_t *irq, | |||||
6581 | int status, char const *phrase) | |||||
6582 | { | |||||
6583 | msg_t *msg = NULL((void*)0); | |||||
6584 | sip_t *sip; | |||||
6585 | ||||||
6586 | if (irq) { | |||||
6587 | msg = nta_msg_create(irq->irq_agent, 0); | |||||
6588 | sip = sip_object(msg); | |||||
6589 | ||||||
6590 | if (sip) { | |||||
6591 | if (status != 0) | |||||
6592 | sip->sip_status = sip_status_create(msg_home(msg)((su_home_t*)(msg)), status, phrase, NULL((void*)0)); | |||||
6593 | ||||||
6594 | if (nta_incoming_response_headers(irq, msg, sip) < 0) | |||||
6595 | msg_destroy(msg), msg = NULL((void*)0); | |||||
6596 | } | |||||
6597 | } | |||||
6598 | ||||||
6599 | return msg; | |||||
6600 | } | |||||
6601 | ||||||
6602 | ||||||
6603 | /**Reply to an incoming transaction request. | |||||
6604 | * | |||||
6605 | * This function creates a response message to an incoming request and sends | |||||
6606 | * it to the client. | |||||
6607 | * | |||||
6608 | * @note | |||||
6609 | * It is possible to send several non-final (1xx) responses, but only one | |||||
6610 | * final response. | |||||
6611 | * | |||||
6612 | * @param irq incoming request | |||||
6613 | * @param status status code | |||||
6614 | * @param phrase status phrase (may be NULL if status code is well-known) | |||||
6615 | * @param tag,value,... optional additional headers terminated by TAG_END() | |||||
6616 | * | |||||
6617 | * @retval 0 when succesful | |||||
6618 | * @retval -1 upon an error | |||||
6619 | */ | |||||
6620 | int nta_incoming_treply(nta_incoming_t *irq, | |||||
6621 | int status, | |||||
6622 | char const *phrase, | |||||
6623 | tag_type_t tag, tag_value_t value, ...) | |||||
6624 | { | |||||
6625 | int retval = -1; | |||||
6626 | ||||||
6627 | if (irq && | |||||
6628 | (irq->irq_status < 200 || status < 200 || | |||||
6629 | (irq->irq_method == sip_method_invite && status < 300))) { | |||||
6630 | ta_list ta; | |||||
6631 | msg_t *msg = nta_msg_create(irq->irq_agent, 0); | |||||
6632 | ||||||
6633 | ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value = (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag ) == tag_next && (ta_start__value) != 0) { ta_start__tag = ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag == tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag == tag_next) { ta_start__value = ((tagi_t *)ta_start__value) ->t_value; } else { ta_start__tag = tag_next; break; } } ( ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value ; if (ta_start__tag != ((void*)0) && ta_start__tag != tag_null && ta_start__tag != tag_next) { va_list ta_start__ap ; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag = tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap ); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value = 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0); | |||||
6634 | ||||||
6635 | if (!msg) | |||||
6636 | ; | |||||
6637 | else if (nta_incoming_complete_response(irq, msg, status, phrase, | |||||
6638 | ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta). tl[1].t_value) < 0) | |||||
6639 | msg_destroy(msg); | |||||
6640 | else if (incoming_set_params(irq, ta_args(ta)(ta).tl) < 0) | |||||
6641 | msg_destroy(msg); | |||||
6642 | else | |||||
6643 | retval = nta_incoming_mreply(irq, msg); | |||||
6644 | ||||||
6645 | ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value ))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta) .ap)); | |||||
6646 | ||||||
6647 | if (retval < 0 && status >= 200) | |||||
6648 | incoming_final_failed(irq, NULL((void*)0)); | |||||
6649 | } | |||||
6650 | ||||||
6651 | return retval; | |||||
6652 | } | |||||
6653 | ||||||
6654 | /** | |||||
6655 | * Return a response message to client. | |||||
6656 | * | |||||
6657 | * @note | |||||
6658 | * The ownership of @a msg is taken over by the function even if the | |||||
6659 | * function fails. | |||||
6660 | * | |||||
6661 | * @retval 0 when succesful | |||||
6662 | * @retval -1 upon an error | |||||
6663 | */ | |||||
6664 | int nta_incoming_mreply(nta_incoming_t *irq, msg_t *msg) | |||||
6665 | { | |||||
6666 | sip_t *sip = sip_object(msg); | |||||
6667 | ||||||
6668 | int status; | |||||
6669 | ||||||
6670 | if (irq == NULL((void*)0)) { | |||||
6671 | msg_destroy(msg); | |||||
6672 | return -1; | |||||
6673 | } | |||||
6674 | ||||||
6675 | if (msg == NULL((void*)0) || sip == NULL((void*)0)) | |||||
6676 | return -1; | |||||
6677 | ||||||
6678 | if (msg == irq->irq_response) | |||||
6679 | return 0; | |||||
6680 | ||||||
6681 | if (!sip->sip_status || !sip->sip_via || !sip->sip_cseq) | |||||
6682 | return incoming_final_failed(irq, msg); | |||||
6683 | ||||||
6684 | assert (sip->sip_cseq->cs_method == irq->irq_method || irq->irq_default)((void) sizeof ((sip->sip_cseq->cs_method == irq->irq_method || irq->irq_default) ? 1 : 0), __extension__ ({ if (sip-> sip_cseq->cs_method == irq->irq_method || irq->irq_default ) ; else __assert_fail ("sip->sip_cseq->cs_method == irq->irq_method || irq->irq_default" , "nta.c", 6684, __extension__ __PRETTY_FUNCTION__); })); | |||||
6685 | ||||||
6686 | status = sip->sip_status->st_status; | |||||
6687 | ||||||
6688 | if (!irq->irq_tag && status > 100 && !irq->irq_default) | |||||
6689 | nta_incoming_tag(irq, NULL((void*)0)); | |||||
6690 | ||||||
6691 | if (/* (irq->irq_confirmed && status >= 200) || */ | |||||
6692 | (irq->irq_completed && status >= 300)) { | |||||
6693 | SU_DEBUG_3(("%s: already %s transaction\n", __func__,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 6694, "%s: already %s transaction\n", __func__, irq->irq_confirmed ? "confirmed" : "completed")) : (void)0) | |||||
6694 | irq->irq_confirmed ? "confirmed" : "completed"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 6694, "%s: already %s transaction\n", __func__, irq->irq_confirmed ? "confirmed" : "completed")) : (void)0); | |||||
6695 | msg_destroy(msg); | |||||
6696 | return -1; | |||||
6697 | } | |||||
6698 | ||||||
6699 | #ifdef HAVE_ZLIB_COMPRESS1 | |||||
6700 | if (irq->irq_compressed) { | |||||
6701 | sip_content_encoding_Xflate(msg, sip, 0, 0); | |||||
6702 | } | |||||
6703 | #endif | |||||
6704 | ||||||
6705 | if (irq->irq_must_100rel && !sip->sip_rseq && status > 100 && status < 200) { | |||||
6706 | /* This nta_reliable_t object will be destroyed by PRACK or timeout */ | |||||
6707 | if (nta_reliable_mreply(irq, NULL((void*)0), NULL((void*)0), msg)) | |||||
6708 | return 0; | |||||
6709 | ||||||
6710 | return -1; | |||||
6711 | } | |||||
6712 | ||||||
6713 | if (status >= 200 && irq->irq_reliable && irq->irq_reliable->rel_unsent) { | |||||
6714 | if (reliable_final(irq, msg, sip) == 0) | |||||
6715 | return 0; | |||||
6716 | } | |||||
6717 | ||||||
6718 | return incoming_reply(irq, msg, sip); | |||||
6719 | } | |||||
6720 | ||||||
6721 | ||||||
6722 | ||||||
6723 | /** Send the response message. | |||||
6724 | * | |||||
6725 | * @note The ownership of msg is handled to incoming_reply(). | |||||
6726 | */ | |||||
6727 | int incoming_reply(nta_incoming_t *irq, msg_t *msg, sip_t *sip) | |||||
6728 | { | |||||
6729 | nta_agent_t *agent = irq->irq_agent; | |||||
6730 | int status = sip->sip_status->st_status; | |||||
6731 | int sending = 1; | |||||
6732 | int *use_rport = NULL((void*)0); | |||||
6733 | int retry_without_rport = 0; | |||||
6734 | tp_name_t *tpn, default_tpn[1]; | |||||
6735 | ||||||
6736 | if (status == 408 && | |||||
6737 | irq->irq_method != sip_method_invite && | |||||
6738 | !agent->sa_pass_408 && | |||||
6739 | !irq->irq_default) { | |||||
6740 | /* RFC 4320 nit-actions-03 Action 2: | |||||
6741 | ||||||
6742 | A transaction-stateful SIP element MUST NOT send a response with | |||||
6743 | Status-Code of 408 to a non-INVITE request. As a consequence, an | |||||
6744 | element that can not respond before the transaction expires will not | |||||
6745 | send a final response at all. | |||||
6746 | */ | |||||
6747 | sending = 0; | |||||
6748 | } | |||||
6749 | ||||||
6750 | if (irq->irq_status == 0 && irq->irq_timestamp && !sip->sip_timestamp) | |||||
6751 | incoming_timestamp(irq, msg, sip); | |||||
6752 | ||||||
6753 | if (irq->irq_default) { | |||||
6754 | if (agent->sa_server_rport) | |||||
6755 | use_rport = &retry_without_rport, retry_without_rport = 1; | |||||
6756 | tpn = default_tpn; | |||||
6757 | if (nta_tpn_by_via(tpn, sip->sip_via, use_rport) < 0) | |||||
6758 | tpn = NULL((void*)0); | |||||
6759 | } | |||||
6760 | else { | |||||
6761 | tpn = irq->irq_tpn; | |||||
6762 | } | |||||
6763 | ||||||
6764 | if (sip_complete_message(msg) < 0) | |||||
6765 | SU_DEBUG_1(("%s: sip_complete_message() failed\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 6765, "%s: sip_complete_message() failed\n", __func__)) : ( void)0); | |||||
6766 | else if (msg_serialize(msg, (msg_pub_t *)sip) < 0) | |||||
6767 | SU_DEBUG_1(("%s: sip_serialize() failed\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 6767, "%s: sip_serialize() failed\n", __func__)) : (void)0); | |||||
6768 | else if (!(irq->irq_tport) && | |||||
6769 | !(tport_decref(&irq->irq_tport), | |||||
6770 | irq->irq_tport = tpn ? tport_by_name(agent->sa_tports, tpn) : 0)) | |||||
6771 | SU_DEBUG_1(("%s: no tport\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 6771, "%s: no tport\n", __func__)) : (void)0); | |||||
6772 | else { | |||||
6773 | int i, err = 0; | |||||
6774 | tport_t *tp = NULL((void*)0); | |||||
6775 | incoming_queue_t *queue; | |||||
6776 | ||||||
6777 | char const *method_name; | |||||
6778 | uint32_t cseq; | |||||
6779 | ||||||
6780 | if (irq->irq_default) { | |||||
6781 | assert(sip->sip_cseq)((void) sizeof ((sip->sip_cseq) ? 1 : 0), __extension__ ({ if (sip->sip_cseq) ; else __assert_fail ("sip->sip_cseq" , "nta.c", 6781, __extension__ __PRETTY_FUNCTION__); })); | |||||
6782 | method_name = sip->sip_cseq->cs_method_name, cseq = sip->sip_cseq->cs_seq; | |||||
6783 | } | |||||
6784 | else { | |||||
6785 | method_name = irq->irq_rq->rq_method_name, cseq = irq->irq_cseq->cs_seq; | |||||
6786 | } | |||||
6787 | ||||||
6788 | if (sending) { | |||||
6789 | for (i = 0; i < 3; i++) { | |||||
6790 | tp = tport_tsend(irq->irq_tport, msg, tpn, | |||||
6791 | IF_SIGCOMP_TPTAG_COMPARTMENT(irq->irq_cc)!(irq->irq_cc && irq->irq_cc != ((void *)-1)) ? tag_skip : tptag_compartment, tag_ptr_v((irq->irq_cc)), | |||||
6792 | TPTAG_MTU(INT_MAX)tptag_mtu, tag_usize_v((2147483647)), | |||||
6793 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
6794 | if (tp) | |||||
6795 | break; | |||||
6796 | ||||||
6797 | err = msg_errno(msg); | |||||
6798 | SU_DEBUG_5(("%s: tport_tsend: %s%s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 6800, "%s: tport_tsend: %s%s\n", __func__, su_strerror(err) , err == 32 ? "(retrying)" : "")) : (void)0) | |||||
6799 | __func__, su_strerror(err),(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 6800, "%s: tport_tsend: %s%s\n", __func__, su_strerror(err) , err == 32 ? "(retrying)" : "")) : (void)0) | |||||
6800 | err == EPIPE ? "(retrying)" : ""))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 6800, "%s: tport_tsend: %s%s\n", __func__, su_strerror(err) , err == 32 ? "(retrying)" : "")) : (void)0); | |||||
6801 | ||||||
6802 | if (err != EPIPE32 && err != ECONNREFUSED111) | |||||
6803 | break; | |||||
6804 | tport_decref(&irq->irq_tport); | |||||
6805 | irq->irq_tport = tport_ref(tport_by_name(agent->sa_tports, tpn)); | |||||
6806 | } | |||||
6807 | ||||||
6808 | if (!tp) { | |||||
6809 | SU_DEBUG_3(("%s: tport_tsend: "(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 6812, "%s: tport_tsend: " "error (%s) while sending %u %s for %s (%u)\n" , __func__, su_strerror(err), status, sip->sip_status-> st_phrase, method_name, cseq)) : (void)0) | |||||
6810 | "error (%s) while sending %u %s for %s (%u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 6812, "%s: tport_tsend: " "error (%s) while sending %u %s for %s (%u)\n" , __func__, su_strerror(err), status, sip->sip_status-> st_phrase, method_name, cseq)) : (void)0) | |||||
6811 | __func__, su_strerror(err),(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 6812, "%s: tport_tsend: " "error (%s) while sending %u %s for %s (%u)\n" , __func__, su_strerror(err), status, sip->sip_status-> st_phrase, method_name, cseq)) : (void)0) | |||||
6812 | status, sip->sip_status->st_phrase, method_name, cseq))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 6812, "%s: tport_tsend: " "error (%s) while sending %u %s for %s (%u)\n" , __func__, su_strerror(err), status, sip->sip_status-> st_phrase, method_name, cseq)) : (void)0); | |||||
6813 | if (status < 200) | |||||
6814 | msg_destroy(msg); | |||||
6815 | else | |||||
6816 | incoming_final_failed(irq, msg); | |||||
6817 | return 0; | |||||
6818 | } | |||||
6819 | ||||||
6820 | agent->sa_stats->as_sent_msg++; | |||||
6821 | agent->sa_stats->as_sent_response++; | |||||
6822 | } | |||||
6823 | ||||||
6824 | SU_DEBUG_5(("nta: %s %u %s for %s (%u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 6826, "nta: %s %u %s for %s (%u)\n", sending ? "sent" : "not sending" , status, sip->sip_status->st_phrase, method_name, cseq )) : (void)0) | |||||
6825 | sending ? "sent" : "not sending",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 6826, "nta: %s %u %s for %s (%u)\n", sending ? "sent" : "not sending" , status, sip->sip_status->st_phrase, method_name, cseq )) : (void)0) | |||||
6826 | status, sip->sip_status->st_phrase, method_name, cseq))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 6826, "nta: %s %u %s for %s (%u)\n", sending ? "sent" : "not sending" , status, sip->sip_status->st_phrase, method_name, cseq )) : (void)0); | |||||
6827 | ||||||
6828 | if (irq->irq_default) { | |||||
6829 | msg_destroy(msg); | |||||
6830 | return 0; | |||||
6831 | } | |||||
6832 | ||||||
6833 | incoming_reset_timer(irq); | |||||
6834 | ||||||
6835 | if (status < 200) { | |||||
6836 | queue = agent->sa_in.proceeding; | |||||
6837 | ||||||
6838 | if (irq->irq_method == sip_method_invite && status > 100 && | |||||
6839 | agent->sa_progress != UINT_MAX(2147483647 *2U +1U) && agent->sa_is_a_uas) { | |||||
6840 | /* Retransmit preliminary responses in regular intervals */ | |||||
6841 | incoming_set_timer(irq, agent->sa_progress); /* N2 */ | |||||
6842 | } | |||||
6843 | } | |||||
6844 | else { | |||||
6845 | irq->irq_completed = 1; | |||||
6846 | ||||||
6847 | /* XXX - we should do this only after message has actually been sent! */ | |||||
6848 | if (irq->irq_sigcomp_zap && irq->irq_cc) | |||||
6849 | agent_close_compressor(irq->irq_agent, irq->irq_cc); | |||||
6850 | ||||||
6851 | if (irq->irq_method != sip_method_invite) { | |||||
6852 | irq->irq_confirmed = 1; | |||||
6853 | ||||||
6854 | if (irq->irq_reliable_tp) { | |||||
6855 | irq->irq_terminated = 1; | |||||
6856 | queue = agent->sa_in.terminated ; /* J - set for 0 seconds */ | |||||
6857 | } else { | |||||
6858 | queue = agent->sa_in.completed; /* J */ | |||||
6859 | } | |||||
6860 | ||||||
6861 | tport_decref(&irq->irq_tport); | |||||
6862 | } | |||||
6863 | else if (status >= 300 || agent->sa_is_a_uas) { | |||||
6864 | if (status < 300 || !irq->irq_reliable_tp) | |||||
6865 | incoming_set_timer(irq, agent->sa_t1); /* G */ | |||||
6866 | queue = agent->sa_in.inv_completed; /* H */ | |||||
6867 | } | |||||
6868 | else { | |||||
6869 | #if 1 | |||||
6870 | /* Avoid bug in @RFC3261: | |||||
6871 | Keep INVITE transaction around in order to catch | |||||
6872 | retransmitted INVITEs | |||||
6873 | */ | |||||
6874 | irq->irq_confirmed = 1; | |||||
6875 | queue = agent->sa_in.inv_confirmed; /* H */ | |||||
6876 | #else | |||||
6877 | irq->irq_terminated = 1; | |||||
6878 | queue = agent->sa_in.terminated; | |||||
6879 | #endif | |||||
6880 | } | |||||
6881 | } | |||||
6882 | ||||||
6883 | if (irq->irq_queue != queue) | |||||
6884 | incoming_queue(queue, irq); | |||||
6885 | ||||||
6886 | if (status >= 200 || irq->irq_status < 200) { | |||||
6887 | if (irq->irq_response) | |||||
6888 | msg_destroy(irq->irq_response); | |||||
6889 | assert(msg_home(msg) != irq->irq_home)((void) sizeof ((((su_home_t*)(msg)) != irq->irq_home) ? 1 : 0), __extension__ ({ if (((su_home_t*)(msg)) != irq->irq_home ) ; else __assert_fail ("msg_home(msg) != irq->irq_home", "nta.c" , 6889, __extension__ __PRETTY_FUNCTION__); })); | |||||
6890 | irq->irq_response = msg; | |||||
6891 | } | |||||
6892 | else { | |||||
6893 | msg_destroy(msg); | |||||
6894 | } | |||||
6895 | ||||||
6896 | if (sip->sip_cseq->cs_method == irq->irq_method && | |||||
6897 | irq->irq_status < 200 && status > irq->irq_status) | |||||
6898 | irq->irq_status = status; | |||||
6899 | ||||||
6900 | return 0; | |||||
6901 | } | |||||
6902 | ||||||
6903 | /* | |||||
6904 | * XXX - handling error is very problematic. | |||||
6905 | * Nobody checks return code from nta_incoming_*reply() | |||||
6906 | */ | |||||
6907 | if (status < 200) { | |||||
6908 | msg_destroy(msg); | |||||
6909 | return -1; | |||||
6910 | } | |||||
6911 | ||||||
6912 | /* We could not send final response. */ | |||||
6913 | return incoming_final_failed(irq, msg); | |||||
6914 | } | |||||
6915 | ||||||
6916 | ||||||
6917 | /** @internal Sending final response has failed. | |||||
6918 | * | |||||
6919 | * Put transaction into its own queue, try later to send the response. | |||||
6920 | */ | |||||
6921 | su_inlinestatic inline | |||||
6922 | int incoming_final_failed(nta_incoming_t *irq, msg_t *msg) | |||||
6923 | { | |||||
6924 | msg_destroy(msg); | |||||
6925 | ||||||
6926 | if (!irq->irq_default) { | |||||
6927 | irq->irq_final_failed = 1; | |||||
6928 | incoming_queue(irq->irq_agent->sa_in.final_failed, irq); | |||||
6929 | } | |||||
6930 | ||||||
6931 | return -1; | |||||
6932 | } | |||||
6933 | ||||||
6934 | /** @internal Retransmit the reply */ | |||||
6935 | static | |||||
6936 | void incoming_retransmit_reply(nta_incoming_t *irq, tport_t *tport) | |||||
6937 | { | |||||
6938 | msg_t *msg = NULL((void*)0); | |||||
6939 | ||||||
6940 | if (irq->irq_final_failed) | |||||
6941 | return; | |||||
6942 | ||||||
6943 | if (tport == NULL((void*)0)) | |||||
6944 | tport = irq->irq_tport; | |||||
6945 | ||||||
6946 | /* Answer with existing reply */ | |||||
6947 | if (irq->irq_reliable && !irq->irq_reliable->rel_pracked) | |||||
6948 | msg = reliable_response(irq); | |||||
6949 | else | |||||
6950 | msg = irq->irq_response; | |||||
6951 | ||||||
6952 | if (msg && tport) { | |||||
6953 | irq->irq_retries++; | |||||
6954 | ||||||
6955 | if (irq->irq_retries == 2 && irq->irq_tpn->tpn_comp) { | |||||
6956 | irq->irq_tpn->tpn_comp = NULL((void*)0); | |||||
6957 | ||||||
6958 | if (irq->irq_cc) { | |||||
6959 | agent_close_compressor(irq->irq_agent, irq->irq_cc); | |||||
6960 | nta_compartment_decref(&irq->irq_cc); | |||||
6961 | } | |||||
6962 | } | |||||
6963 | ||||||
6964 | tport_tsend(tport, msg, irq->irq_tpn, | |||||
6965 | IF_SIGCOMP_TPTAG_COMPARTMENT(irq->irq_cc)!(irq->irq_cc && irq->irq_cc != ((void *)-1)) ? tag_skip : tptag_compartment, tag_ptr_v((irq->irq_cc)), | |||||
6966 | TPTAG_MTU(INT_MAX)tptag_mtu, tag_usize_v((2147483647)), TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
6967 | irq->irq_agent->sa_stats->as_sent_msg++; | |||||
6968 | irq->irq_agent->sa_stats->as_sent_response++; | |||||
6969 | } | |||||
6970 | } | |||||
6971 | ||||||
6972 | /** @internal Create timestamp header for response */ | |||||
6973 | static | |||||
6974 | int incoming_timestamp(nta_incoming_t *irq, msg_t *msg, sip_t *sip) | |||||
6975 | { | |||||
6976 | sip_timestamp_t ts[1]; | |||||
6977 | su_time_t now = su_now(); | |||||
6978 | char delay[32]; | |||||
6979 | double diff = su_time_diff(now, irq->irq_received); | |||||
6980 | ||||||
6981 | snprintf(delay, sizeof delay, "%.06f", diff); | |||||
6982 | ||||||
6983 | *ts = *irq->irq_timestamp; | |||||
6984 | ts->ts_delay = delay; | |||||
6985 | ||||||
6986 | return sip_add_dup(msg, sip, (sip_header_t *)ts); | |||||
6987 | } | |||||
6988 | ||||||
6989 | enum { | |||||
6990 | timer_max_retransmit = 30, | |||||
6991 | timer_max_terminate = 100000, | |||||
6992 | timer_max_timeout = 100 | |||||
6993 | }; | |||||
6994 | ||||||
6995 | /** @internal Timer routine for the incoming request. */ | |||||
6996 | static void | |||||
6997 | _nta_incoming_timer(nta_agent_t *sa) | |||||
6998 | { | |||||
6999 | uint32_t now; | |||||
7000 | nta_incoming_t *irq, *irq_next; | |||||
7001 | size_t retransmitted = 0, timeout = 0, terminated = 0, destroyed = 0; | |||||
7002 | size_t unconfirmed = | |||||
7003 | sa->sa_in.inv_completed->q_length + | |||||
7004 | sa->sa_in.preliminary->q_length; | |||||
7005 | size_t unterminated = | |||||
7006 | sa->sa_in.inv_confirmed->q_length + | |||||
7007 | sa->sa_in.completed->q_length; | |||||
7008 | size_t total = sa->sa_incoming->iht_used; | |||||
7009 | ||||||
7010 | incoming_queue_t rq[1]; | |||||
7011 | ||||||
7012 | incoming_queue_init(rq, 0); | |||||
7013 | ||||||
7014 | /* Handle retry queue */ | |||||
7015 | while ((irq = sa->sa_in.re_list)) { | |||||
7016 | ||||||
7017 | now = su_time_ms(su_now()); | |||||
7018 | ||||||
7019 | if ((int32_t)(irq->irq_retry - now) > 0) | |||||
7020 | break; | |||||
7021 | if (retransmitted >= timer_max_retransmit) | |||||
7022 | break; | |||||
7023 | ||||||
7024 | if (irq->irq_method == sip_method_invite && irq->irq_status >= 200) { | |||||
7025 | /* Timer G */ | |||||
7026 | assert(irq->irq_queue == sa->sa_in.inv_completed)((void) sizeof ((irq->irq_queue == sa->sa_in.inv_completed ) ? 1 : 0), __extension__ ({ if (irq->irq_queue == sa-> sa_in.inv_completed) ; else __assert_fail ("irq->irq_queue == sa->sa_in.inv_completed" , "nta.c", 7026, __extension__ __PRETTY_FUNCTION__); })); | |||||
7027 | ||||||
7028 | retransmitted++; | |||||
7029 | ||||||
7030 | SU_DEBUG_5(("nta: timer %s fired, retransmitting %u reply\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 7031, "nta: timer %s fired, retransmitting %u reply\n", "G" , irq->irq_status)) : (void)0) | |||||
7031 | "G", irq->irq_status))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 7031, "nta: timer %s fired, retransmitting %u reply\n", "G" , irq->irq_status)) : (void)0); | |||||
7032 | ||||||
7033 | incoming_retransmit_reply(irq, irq->irq_tport); | |||||
7034 | ||||||
7035 | if (2U * irq->irq_interval < sa->sa_t2) | |||||
7036 | incoming_set_timer(irq, 2U * irq->irq_interval); /* G */ | |||||
7037 | else | |||||
7038 | incoming_set_timer(irq, sa->sa_t2); /* G */ | |||||
7039 | } | |||||
7040 | else if (irq->irq_method == sip_method_invite && irq->irq_status >= 100) { | |||||
7041 | if (irq->irq_queue == sa->sa_in.preliminary) { | |||||
7042 | /* Timer P1 - PRACK timer */ | |||||
7043 | retransmitted++; | |||||
7044 | SU_DEBUG_5(("nta: timer %s fired, retransmitting %u reply\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 7045, "nta: timer %s fired, retransmitting %u reply\n", "P1" , irq->irq_status)) : (void)0) | |||||
7045 | "P1", irq->irq_status))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 7045, "nta: timer %s fired, retransmitting %u reply\n", "P1" , irq->irq_status)) : (void)0); | |||||
7046 | ||||||
7047 | incoming_retransmit_reply(irq, irq->irq_tport); | |||||
7048 | ||||||
7049 | incoming_set_timer(irq, 2 * irq->irq_interval); /* P1 */ | |||||
7050 | } | |||||
7051 | else { | |||||
7052 | /* Retransmitting provisional responses */ | |||||
7053 | SU_DEBUG_5(("nta: timer %s fired, retransmitting %u reply\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 7054, "nta: timer %s fired, retransmitting %u reply\n", "N2" , irq->irq_status)) : (void)0) | |||||
7054 | "N2", irq->irq_status))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 7054, "nta: timer %s fired, retransmitting %u reply\n", "N2" , irq->irq_status)) : (void)0); | |||||
7055 | incoming_set_timer(irq, sa->sa_progress); | |||||
7056 | retransmitted++; | |||||
7057 | incoming_retransmit_reply(irq, irq->irq_tport); | |||||
7058 | } | |||||
7059 | } | |||||
7060 | else { | |||||
7061 | /* Timer N1 */ | |||||
7062 | incoming_reset_timer(irq); | |||||
7063 | ||||||
7064 | if(irq->irq_extra_100) { | |||||
7065 | SU_DEBUG_5(("nta: timer N1 fired, sending %u %s\n", SIP_100_TRYING))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 7065, "nta: timer N1 fired, sending %u %s\n", 100, sip_100_Trying )) : (void)0); | |||||
7066 | nta_incoming_treply(irq, SIP_100_TRYING100, sip_100_Trying, TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
7067 | } | |||||
7068 | else { | |||||
7069 | SU_DEBUG_5(("nta: timer N1 fired, but avoided sending %u %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 7070, "nta: timer N1 fired, but avoided sending %u %s\n", 100 , sip_100_Trying)) : (void)0) | |||||
7070 | SIP_100_TRYING))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 7070, "nta: timer N1 fired, but avoided sending %u %s\n", 100 , sip_100_Trying)) : (void)0); | |||||
7071 | } | |||||
7072 | } | |||||
7073 | } | |||||
7074 | ||||||
7075 | while ((irq = sa->sa_in.final_failed->q_head)) { | |||||
7076 | ||||||
7077 | ||||||
7078 | incoming_remove(irq); | |||||
7079 | irq->irq_final_failed = 0; | |||||
7080 | ||||||
7081 | /* Report error to application */ | |||||
7082 | SU_DEBUG_5(("nta: sending final response failed, timeout %u response\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 7083, "nta: sending final response failed, timeout %u response\n" , irq->irq_status)) : (void)0) | |||||
7083 | irq->irq_status))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 7083, "nta: sending final response failed, timeout %u response\n" , irq->irq_status)) : (void)0); | |||||
7084 | reliable_timeout(irq, 0); | |||||
7085 | ||||||
7086 | nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error, TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
7087 | ||||||
7088 | if (!irq->irq_final_failed) /* We have taken care of the error... */ | |||||
7089 | continue; | |||||
7090 | ||||||
7091 | if (irq->irq_destroyed) { | |||||
7092 | incoming_free_queue(rq, irq); | |||||
7093 | continue; | |||||
7094 | } | |||||
7095 | ||||||
7096 | incoming_reset_timer(irq); | |||||
7097 | irq->irq_confirmed = 1; | |||||
7098 | irq->irq_terminated = 1; | |||||
7099 | incoming_queue(sa->sa_in.terminated, irq); | |||||
7100 | } | |||||
7101 | ||||||
7102 | /* Timeouts. | |||||
7103 | * For each state the request is in, there is always a queue of its own | |||||
7104 | */ | |||||
7105 | while ((irq = sa->sa_in.preliminary->q_head)) { | |||||
7106 | assert(irq->irq_status < 200)((void) sizeof ((irq->irq_status < 200) ? 1 : 0), __extension__ ({ if (irq->irq_status < 200) ; else __assert_fail ("irq->irq_status < 200" , "nta.c", 7106, __extension__ __PRETTY_FUNCTION__); })); | |||||
7107 | assert(irq->irq_timeout)((void) sizeof ((irq->irq_timeout) ? 1 : 0), __extension__ ({ if (irq->irq_timeout) ; else __assert_fail ("irq->irq_timeout" , "nta.c", 7107, __extension__ __PRETTY_FUNCTION__); })); | |||||
7108 | ||||||
7109 | now = su_time_ms(su_now()); | |||||
7110 | ||||||
7111 | if ((int32_t)(irq->irq_timeout - now) > 0) | |||||
7112 | break; | |||||
7113 | if (timeout >= timer_max_timeout) | |||||
7114 | break; | |||||
7115 | ||||||
7116 | timeout++; | |||||
7117 | ||||||
7118 | /* Timer P2 - PRACK timer */ | |||||
7119 | SU_DEBUG_5(("nta: timer %s fired, %s %u response\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 7120, "nta: timer %s fired, %s %u response\n", "P2", "timeout" , irq->irq_status)) : (void)0) | |||||
7120 | "P2", "timeout", irq->irq_status))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 7120, "nta: timer %s fired, %s %u response\n", "P2", "timeout" , irq->irq_status)) : (void)0); | |||||
7121 | incoming_reset_timer(irq); | |||||
7122 | irq->irq_timeout = 0; | |||||
7123 | reliable_timeout(irq, 1); | |||||
7124 | } | |||||
7125 | ||||||
7126 | while ((irq = sa->sa_in.inv_completed->q_head)) { | |||||
7127 | assert(irq->irq_status >= 200)((void) sizeof ((irq->irq_status >= 200) ? 1 : 0), __extension__ ({ if (irq->irq_status >= 200) ; else __assert_fail ("irq->irq_status >= 200" , "nta.c", 7127, __extension__ __PRETTY_FUNCTION__); })); | |||||
7128 | assert(irq->irq_timeout)((void) sizeof ((irq->irq_timeout) ? 1 : 0), __extension__ ({ if (irq->irq_timeout) ; else __assert_fail ("irq->irq_timeout" , "nta.c", 7128, __extension__ __PRETTY_FUNCTION__); })); | |||||
7129 | assert(irq->irq_method == sip_method_invite)((void) sizeof ((irq->irq_method == sip_method_invite) ? 1 : 0), __extension__ ({ if (irq->irq_method == sip_method_invite ) ; else __assert_fail ("irq->irq_method == sip_method_invite" , "nta.c", 7129, __extension__ __PRETTY_FUNCTION__); })); | |||||
7130 | ||||||
7131 | now = su_time_ms(su_now()); | |||||
7132 | ||||||
7133 | if ((int32_t)(irq->irq_timeout - now) > 0 || | |||||
7134 | timeout >= timer_max_timeout || | |||||
7135 | terminated >= timer_max_terminate) | |||||
7136 | break; | |||||
7137 | ||||||
7138 | /* Timer H */ | |||||
7139 | SU_DEBUG_5(("nta: timer %s fired, %s %u response\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 7140, "nta: timer %s fired, %s %u response\n", "H", "timeout and terminate" , irq->irq_status)) : (void)0) | |||||
7140 | "H", "timeout and terminate", irq->irq_status))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 7140, "nta: timer %s fired, %s %u response\n", "H", "timeout and terminate" , irq->irq_status)) : (void)0); | |||||
7141 | irq->irq_confirmed = 1; | |||||
7142 | irq->irq_terminated = 1; | |||||
7143 | incoming_reset_timer(irq); | |||||
7144 | if (!irq->irq_destroyed) { | |||||
7145 | timeout++; | |||||
7146 | incoming_queue(sa->sa_in.terminated, irq); | |||||
7147 | /* report timeout error to user */ | |||||
7148 | incoming_call_callback(irq, NULL((void*)0), NULL((void*)0)); | |||||
7149 | } else { | |||||
7150 | timeout++; | |||||
7151 | terminated++; | |||||
7152 | incoming_free_queue(rq, irq); | |||||
7153 | } | |||||
7154 | } | |||||
7155 | ||||||
7156 | while ((irq = sa->sa_in.inv_confirmed->q_head)) { | |||||
7157 | assert(irq->irq_timeout)((void) sizeof ((irq->irq_timeout) ? 1 : 0), __extension__ ({ if (irq->irq_timeout) ; else __assert_fail ("irq->irq_timeout" , "nta.c", 7157, __extension__ __PRETTY_FUNCTION__); })); | |||||
7158 | assert(irq->irq_status >= 200)((void) sizeof ((irq->irq_status >= 200) ? 1 : 0), __extension__ ({ if (irq->irq_status >= 200) ; else __assert_fail ("irq->irq_status >= 200" , "nta.c", 7158, __extension__ __PRETTY_FUNCTION__); })); | |||||
7159 | assert(irq->irq_method == sip_method_invite)((void) sizeof ((irq->irq_method == sip_method_invite) ? 1 : 0), __extension__ ({ if (irq->irq_method == sip_method_invite ) ; else __assert_fail ("irq->irq_method == sip_method_invite" , "nta.c", 7159, __extension__ __PRETTY_FUNCTION__); })); | |||||
7160 | ||||||
7161 | now = su_time_ms(su_now()); | |||||
7162 | ||||||
7163 | if ((int32_t)(irq->irq_timeout - now) > 0 || | |||||
7164 | terminated >= timer_max_terminate) | |||||
7165 | break; | |||||
7166 | ||||||
7167 | /* Timer I */ | |||||
7168 | SU_DEBUG_5(("nta: timer %s fired, %s %u response\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 7169, "nta: timer %s fired, %s %u response\n", "I", "terminate" , irq->irq_status)) : (void)0) | |||||
7169 | "I", "terminate", irq->irq_status))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 7169, "nta: timer %s fired, %s %u response\n", "I", "terminate" , irq->irq_status)) : (void)0); | |||||
7170 | ||||||
7171 | terminated++; | |||||
7172 | irq->irq_terminated = 1; | |||||
7173 | ||||||
7174 | if (!irq->irq_destroyed) | |||||
7175 | incoming_queue(sa->sa_in.terminated, irq); | |||||
7176 | else | |||||
7177 | incoming_free_queue(rq, irq); | |||||
7178 | } | |||||
7179 | ||||||
7180 | while ((irq = sa->sa_in.completed->q_head)) { | |||||
7181 | assert(irq->irq_status >= 200)((void) sizeof ((irq->irq_status >= 200) ? 1 : 0), __extension__ ({ if (irq->irq_status >= 200) ; else __assert_fail ("irq->irq_status >= 200" , "nta.c", 7181, __extension__ __PRETTY_FUNCTION__); })); | |||||
7182 | assert(irq->irq_timeout)((void) sizeof ((irq->irq_timeout) ? 1 : 0), __extension__ ({ if (irq->irq_timeout) ; else __assert_fail ("irq->irq_timeout" , "nta.c", 7182, __extension__ __PRETTY_FUNCTION__); })); | |||||
7183 | assert(irq->irq_method != sip_method_invite)((void) sizeof ((irq->irq_method != sip_method_invite) ? 1 : 0), __extension__ ({ if (irq->irq_method != sip_method_invite ) ; else __assert_fail ("irq->irq_method != sip_method_invite" , "nta.c", 7183, __extension__ __PRETTY_FUNCTION__); })); | |||||
7184 | ||||||
7185 | now = su_time_ms(su_now()); | |||||
7186 | ||||||
7187 | if ((int32_t)(irq->irq_timeout - now) > 0 || | |||||
7188 | terminated >= timer_max_terminate) | |||||
7189 | break; | |||||
7190 | ||||||
7191 | /* Timer J */ | |||||
7192 | ||||||
7193 | SU_DEBUG_5(("nta: timer %s fired, %s %u response\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 7194, "nta: timer %s fired, %s %u response\n", "J", "terminate" , irq->irq_status)) : (void)0) | |||||
7194 | "J", "terminate", irq->irq_status))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 7194, "nta: timer %s fired, %s %u response\n", "J", "terminate" , irq->irq_status)) : (void)0); | |||||
7195 | ||||||
7196 | terminated++; | |||||
7197 | irq->irq_terminated = 1; | |||||
7198 | ||||||
7199 | if (!irq->irq_destroyed) | |||||
7200 | incoming_queue(sa->sa_in.terminated, irq); | |||||
7201 | else | |||||
7202 | incoming_free_queue(rq, irq); | |||||
7203 | } | |||||
7204 | ||||||
7205 | for (irq = sa->sa_in.terminated->q_head; irq; irq = irq_next) { | |||||
7206 | ||||||
7207 | irq_next = irq->irq_next; | |||||
7208 | if (irq->irq_destroyed) | |||||
7209 | incoming_free_queue(rq, irq); | |||||
7210 | } | |||||
7211 | ||||||
7212 | destroyed = incoming_mass_destroy(sa, rq); | |||||
7213 | ||||||
7214 | if (retransmitted || timeout || terminated || destroyed) | |||||
7215 | SU_DEBUG_5(("nta_incoming_timer: "(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 7223, "nta_incoming_timer: " "%zu""/""%zu"" resent, " "%zu" "/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n" , retransmitted, unconfirmed, timeout, unconfirmed, terminated , unterminated, destroyed, total)) : (void)0) | |||||
7216 | MOD_ZU"/"MOD_ZU" resent, "(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 7223, "nta_incoming_timer: " "%zu""/""%zu"" resent, " "%zu" "/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n" , retransmitted, unconfirmed, timeout, unconfirmed, terminated , unterminated, destroyed, total)) : (void)0) | |||||
7217 | MOD_ZU"/"MOD_ZU" tout, "(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 7223, "nta_incoming_timer: " "%zu""/""%zu"" resent, " "%zu" "/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n" , retransmitted, unconfirmed, timeout, unconfirmed, terminated , unterminated, destroyed, total)) : (void)0) | |||||
7218 | MOD_ZU"/"MOD_ZU" term, "(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 7223, "nta_incoming_timer: " "%zu""/""%zu"" resent, " "%zu" "/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n" , retransmitted, unconfirmed, timeout, unconfirmed, terminated , unterminated, destroyed, total)) : (void)0) | |||||
7219 | MOD_ZU"/"MOD_ZU" free\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 7223, "nta_incoming_timer: " "%zu""/""%zu"" resent, " "%zu" "/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n" , retransmitted, unconfirmed, timeout, unconfirmed, terminated , unterminated, destroyed, total)) : (void)0) | |||||
7220 | retransmitted, unconfirmed,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 7223, "nta_incoming_timer: " "%zu""/""%zu"" resent, " "%zu" "/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n" , retransmitted, unconfirmed, timeout, unconfirmed, terminated , unterminated, destroyed, total)) : (void)0) | |||||
7221 | timeout, unconfirmed,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 7223, "nta_incoming_timer: " "%zu""/""%zu"" resent, " "%zu" "/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n" , retransmitted, unconfirmed, timeout, unconfirmed, terminated , unterminated, destroyed, total)) : (void)0) | |||||
7222 | terminated, unterminated,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 7223, "nta_incoming_timer: " "%zu""/""%zu"" resent, " "%zu" "/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n" , retransmitted, unconfirmed, timeout, unconfirmed, terminated , unterminated, destroyed, total)) : (void)0) | |||||
7223 | destroyed, total))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 7223, "nta_incoming_timer: " "%zu""/""%zu"" resent, " "%zu" "/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n" , retransmitted, unconfirmed, timeout, unconfirmed, terminated , unterminated, destroyed, total)) : (void)0); | |||||
7224 | } | |||||
7225 | ||||||
7226 | /** Mass destroy server transactions */ | |||||
7227 | su_inlinestatic inline | |||||
7228 | size_t incoming_mass_destroy(nta_agent_t *sa, incoming_queue_t *q) | |||||
7229 | { | |||||
7230 | size_t destroyed = q->q_length; | |||||
7231 | ||||||
7232 | if (destroyed > 2 && *sa->sa_terminator) { | |||||
7233 | su_msg_r m = SU_MSG_R_INIT{ ((void*)0) }; | |||||
7234 | ||||||
7235 | if (su_msg_create(m, | |||||
7236 | su_clone_task(sa->sa_terminator), | |||||
7237 | su_root_task(sa->sa_root), | |||||
7238 | incoming_reclaim_queued, | |||||
7239 | sizeof(incoming_queue_t)) == SU_SUCCESSsu_success) { | |||||
7240 | incoming_queue_t *mq = su_msg_data(m)->a_incoming_queue; | |||||
7241 | ||||||
7242 | *mq = *q; | |||||
7243 | ||||||
7244 | if (su_msg_send(m) == SU_SUCCESSsu_success) | |||||
7245 | q->q_length = 0; | |||||
7246 | } | |||||
7247 | } | |||||
7248 | ||||||
7249 | if (q->q_length > 0) | |||||
7250 | incoming_reclaim_queued(NULL((void*)0), NULL((void*)0), (void *)q); | |||||
7251 | ||||||
7252 | return destroyed; | |||||
7253 | } | |||||
7254 | ||||||
7255 | /* ====================================================================== */ | |||||
7256 | /* 8) Client-side (outgoing) transactions */ | |||||
7257 | ||||||
7258 | #define HTABLE_HASH_ORQ(orq)((orq)->orq_hash) ((orq)->orq_hash) | |||||
7259 | ||||||
7260 | #ifdef __clang__1 | |||||
7261 | #pragma clang diagnostic push | |||||
7262 | #pragma clang diagnostic ignored "-Wunused-function" | |||||
7263 | #endif | |||||
7264 | ||||||
7265 | 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, collisions = 0; if (new_size == 0) new_size = 2 * oht->oht_size + 1; if (new_size < 31) new_size = 31; if (new_size < 5 * oht->oht_used / 4) new_size = 5 * oht->oht_used / 4; if (!(new_hash = su_zalloc (home, sizeof(*new_hash) * new_size))) return -1; old_size = oht ->oht_size; do for (j = 0; j < old_size; j++) { if (!old_hash [j]) continue; if (again < 2 && ((old_hash[j])-> orq_hash) % old_size > j) { again = 1; continue; } i0 = (( old_hash[j])->orq_hash) % new_size; for (i = i0; new_hash[ i]; i = (i + 1) % new_size, ((void) sizeof ((i != i0) ? 1 : 0 ), __extension__ ({ if (i != i0) ; else __assert_fail ("i != i0" , "nta.c", 7266, __extension__ __PRETTY_FUNCTION__); }))) collisions ++; new_hash[i] = old_hash[j], old_hash[j] = ((void*)0); used ++; } while (again++ == 1); oht->oht_table = new_hash, oht ->oht_size = new_size; ((void) sizeof ((oht->oht_used == used) ? 1 : 0), __extension__ ({ if (oht->oht_used == used ) ; else __assert_fail ("oht->oht_used == used", "nta.c", 7266 , __extension__ __PRETTY_FUNCTION__); })); su_free(home, old_hash ); return 0; } static inline int outgoing_htable_is_full(outgoing_htable_t const *oht) { return oht->oht_table == ((void*)0) || 3 * oht ->oht_used > 2 * oht->oht_size; } static inline nta_outgoing_t **outgoing_htable_hash(outgoing_htable_t const *oht, hash_value_t hv) { return oht->oht_table + hv % oht->oht_size; } static inline nta_outgoing_t **outgoing_htable_next(outgoing_htable_t const *oht, nta_outgoing_t * const *ee) { if (++ee < oht-> oht_table + oht->oht_size && ee >= oht->oht_table ) return (nta_outgoing_t **)ee; else return oht->oht_table ; } static inline void outgoing_htable_append(outgoing_htable_t *oht, nta_outgoing_t const *e) { nta_outgoing_t **ee; oht-> oht_used++; for (ee = outgoing_htable_hash(oht, ((e)->orq_hash )); *ee; ee = outgoing_htable_next(oht, ee)) ; *ee = (nta_outgoing_t *)e; } static inline void outgoing_htable_insert(outgoing_htable_t *oht, nta_outgoing_t const *e) { nta_outgoing_t *e0, **ee; oht ->oht_used++; for (ee = outgoing_htable_hash(oht, ((e)-> orq_hash)); (e0 = *ee); ee = outgoing_htable_next(oht, ee)) * ee = (nta_outgoing_t *)e, e = e0; *ee = (nta_outgoing_t *)e; } static inline int outgoing_htable_remove(outgoing_htable_t * oht, nta_outgoing_t const *e) { size_t i, j, k; size_t size = oht->oht_size; nta_outgoing_t **htable = oht->oht_table ; if (!e) return -1; for (i = ((e)->orq_hash) % size; htable [i]; i = (i + 1) % size) if (e == htable[i]) break; if (!htable [i]) return -1; for (j = (i + 1) % size; htable[j]; j = (j + 1 ) % size) { k = ((htable[j])->orq_hash) % size; if (k == j ) continue; if (j > i ? (i < k && k < j) : ( i < k || k < j)) continue; htable[i] = htable[j], i = j ; } oht->oht_used--; htable[i] = ((void*)0); return 0; } extern int outgoing_htable_dummy | |||||
7266 | size_t, hash_value_t)static inline int outgoing_htable_resize(su_home_t *home, outgoing_htable_t oht[], size_t new_size) { nta_outgoing_t **new_hash; nta_outgoing_t **old_hash = oht->oht_table; size_t old_size; size_t i, j , i0; unsigned again = 0; size_t used = 0, collisions = 0; if (new_size == 0) new_size = 2 * oht->oht_size + 1; if (new_size < 31) new_size = 31; if (new_size < 5 * oht->oht_used / 4) new_size = 5 * oht->oht_used / 4; if (!(new_hash = su_zalloc (home, sizeof(*new_hash) * new_size))) return -1; old_size = oht ->oht_size; do for (j = 0; j < old_size; j++) { if (!old_hash [j]) continue; if (again < 2 && ((old_hash[j])-> orq_hash) % old_size > j) { again = 1; continue; } i0 = (( old_hash[j])->orq_hash) % new_size; for (i = i0; new_hash[ i]; i = (i + 1) % new_size, ((void) sizeof ((i != i0) ? 1 : 0 ), __extension__ ({ if (i != i0) ; else __assert_fail ("i != i0" , "nta.c", 7266, __extension__ __PRETTY_FUNCTION__); }))) collisions ++; new_hash[i] = old_hash[j], old_hash[j] = ((void*)0); used ++; } while (again++ == 1); oht->oht_table = new_hash, oht ->oht_size = new_size; ((void) sizeof ((oht->oht_used == used) ? 1 : 0), __extension__ ({ if (oht->oht_used == used ) ; else __assert_fail ("oht->oht_used == used", "nta.c", 7266 , __extension__ __PRETTY_FUNCTION__); })); su_free(home, old_hash ); return 0; } static inline int outgoing_htable_is_full(outgoing_htable_t const *oht) { return oht->oht_table == ((void*)0) || 3 * oht ->oht_used > 2 * oht->oht_size; } static inline nta_outgoing_t **outgoing_htable_hash(outgoing_htable_t const *oht, hash_value_t hv) { return oht->oht_table + hv % oht->oht_size; } static inline nta_outgoing_t **outgoing_htable_next(outgoing_htable_t const *oht, nta_outgoing_t * const *ee) { if (++ee < oht-> oht_table + oht->oht_size && ee >= oht->oht_table ) return (nta_outgoing_t **)ee; else return oht->oht_table ; } static inline void outgoing_htable_append(outgoing_htable_t *oht, nta_outgoing_t const *e) { nta_outgoing_t **ee; oht-> oht_used++; for (ee = outgoing_htable_hash(oht, ((e)->orq_hash )); *ee; ee = outgoing_htable_next(oht, ee)) ; *ee = (nta_outgoing_t *)e; } static inline void outgoing_htable_insert(outgoing_htable_t *oht, nta_outgoing_t const *e) { nta_outgoing_t *e0, **ee; oht ->oht_used++; for (ee = outgoing_htable_hash(oht, ((e)-> orq_hash)); (e0 = *ee); ee = outgoing_htable_next(oht, ee)) * ee = (nta_outgoing_t *)e, e = e0; *ee = (nta_outgoing_t *)e; } static inline int outgoing_htable_remove(outgoing_htable_t * oht, nta_outgoing_t const *e) { size_t i, j, k; size_t size = oht->oht_size; nta_outgoing_t **htable = oht->oht_table ; if (!e) return -1; for (i = ((e)->orq_hash) % size; htable [i]; i = (i + 1) % size) if (e == htable[i]) break; if (!htable [i]) return -1; for (j = (i + 1) % size; htable[j]; j = (j + 1 ) % size) { k = ((htable[j])->orq_hash) % size; if (k == j ) continue; if (j > i ? (i < k && k < j) : ( i < k || k < j)) continue; htable[i] = htable[j], i = j ; } oht->oht_used--; htable[i] = ((void*)0); return 0; } extern int outgoing_htable_dummy; | |||||
7267 | ||||||
7268 | #ifdef __clang__1 | |||||
7269 | #pragma clang diagnostic pop | |||||
7270 | #endif | |||||
7271 | ||||||
7272 | static int outgoing_features(nta_agent_t *agent, nta_outgoing_t *orq, | |||||
7273 | msg_t *msg, sip_t *sip, | |||||
7274 | tagi_t *tags); | |||||
7275 | static void outgoing_prepare_send(nta_outgoing_t *orq); | |||||
7276 | static void outgoing_send_via(nta_outgoing_t *orq, tport_t *tp); | |||||
7277 | static void outgoing_send(nta_outgoing_t *orq, int retransmit); | |||||
7278 | static void outgoing_try_tcp_instead(nta_outgoing_t *orq); | |||||
7279 | static void outgoing_try_udp_instead(nta_outgoing_t *orq, int timeout); | |||||
7280 | static void outgoing_tport_error(nta_agent_t *agent, nta_outgoing_t *orq, | |||||
7281 | tport_t *tp, msg_t *msg, int error); | |||||
7282 | static void outgoing_print_tport_error(nta_outgoing_t *orq, | |||||
7283 | int level, char *todo, | |||||
7284 | tp_name_t const *, msg_t *, int error); | |||||
7285 | static void outgoing_insert(nta_agent_t *sa, nta_outgoing_t *orq); | |||||
7286 | static void outgoing_destroy(nta_outgoing_t *orq); | |||||
7287 | su_inlinestatic inline int outgoing_is_queued(nta_outgoing_t const *orq); | |||||
7288 | su_inlinestatic inline void outgoing_queue(outgoing_queue_t *queue, | |||||
7289 | nta_outgoing_t *orq); | |||||
7290 | su_inlinestatic inline void outgoing_remove(nta_outgoing_t *orq); | |||||
7291 | su_inlinestatic inline void outgoing_set_timer(nta_outgoing_t *orq, uint32_t interval); | |||||
7292 | static void outgoing_reset_timer(nta_outgoing_t *orq); | |||||
7293 | static size_t outgoing_timer_dk(outgoing_queue_t *q, | |||||
7294 | char const *timer, | |||||
7295 | uint32_t now); | |||||
7296 | static size_t outgoing_timer_bf(outgoing_queue_t *q, | |||||
7297 | char const *timer, | |||||
7298 | uint32_t now); | |||||
7299 | static size_t outgoing_timer_c(outgoing_queue_t *q, | |||||
7300 | char const *timer, | |||||
7301 | uint32_t now); | |||||
7302 | ||||||
7303 | static void outgoing_ack(nta_outgoing_t *orq, sip_t *sip); | |||||
7304 | static msg_t *outgoing_ackmsg(nta_outgoing_t *, sip_method_t, char const *, | |||||
7305 | tag_type_t tag, tag_value_t value, ...); | |||||
7306 | static void outgoing_retransmit(nta_outgoing_t *orq); | |||||
7307 | static void outgoing_trying(nta_outgoing_t *orq); | |||||
7308 | static void outgoing_timeout(nta_outgoing_t *orq, uint32_t now); | |||||
7309 | static int outgoing_complete(nta_outgoing_t *orq); | |||||
7310 | static void outgoing_terminate_invite(nta_outgoing_t *); | |||||
7311 | static void outgoing_remove_fork(nta_outgoing_t *orq); | |||||
7312 | static int outgoing_terminate(nta_outgoing_t *orq); | |||||
7313 | static size_t outgoing_mass_destroy(nta_agent_t *sa, outgoing_queue_t *q); | |||||
7314 | static void outgoing_estimate_delay(nta_outgoing_t *orq, sip_t *sip); | |||||
7315 | static int outgoing_duplicate(nta_outgoing_t *orq, | |||||
7316 | msg_t *msg, | |||||
7317 | sip_t *sip); | |||||
7318 | static int outgoing_reply(nta_outgoing_t *orq, | |||||
7319 | int status, char const *phrase, | |||||
7320 | int delayed); | |||||
7321 | ||||||
7322 | static int outgoing_default_cb(nta_outgoing_magic_t *magic, | |||||
7323 | nta_outgoing_t *request, | |||||
7324 | sip_t const *sip); | |||||
7325 | ||||||
7326 | ||||||
7327 | /** Create a default outgoing transaction. | |||||
7328 | * | |||||
7329 | * The default outgoing transaction is used when agent receives responses | |||||
7330 | * not belonging to any transaction. | |||||
7331 | * | |||||
7332 | * @sa nta_leg_default(), nta_incoming_default(). | |||||
7333 | */ | |||||
7334 | nta_outgoing_t *nta_outgoing_default(nta_agent_t *agent, | |||||
7335 | nta_response_f *callback, | |||||
7336 | nta_outgoing_magic_t *magic) | |||||
7337 | { | |||||
7338 | nta_outgoing_t *orq; | |||||
7339 | ||||||
7340 | if (agent == NULL((void*)0)) | |||||
7341 | return NULL((void*)0); | |||||
7342 | ||||||
7343 | if (agent->sa_default_outgoing) | |||||
7344 | return NULL((void*)0); | |||||
7345 | ||||||
7346 | orq = su_zalloc(agent->sa_home, sizeof *orq); | |||||
7347 | if (!orq) | |||||
7348 | return NULL((void*)0); | |||||
7349 | ||||||
7350 | orq->orq_agent = agent; | |||||
7351 | orq->orq_callback = callback; | |||||
7352 | orq->orq_magic = magic; | |||||
7353 | orq->orq_method = sip_method_invalid; | |||||
7354 | orq->orq_method_name = "*"; | |||||
7355 | orq->orq_default = 1; | |||||
7356 | orq->orq_stateless = 1; | |||||
7357 | orq->orq_delay = UINT_MAX(2147483647 *2U +1U); | |||||
7358 | ||||||
7359 | return agent->sa_default_outgoing = orq; | |||||
7360 | } | |||||
7361 | ||||||
7362 | /**Create an outgoing request and client transaction belonging to the leg. | |||||
7363 | * | |||||
7364 | * Create a request message and pass the request message to an outgoing | |||||
7365 | * client transaction object. The request is sent to the @a route_url (if | |||||
7366 | * non-NULL), default proxy (if defined by NTATAG_DEFAULT_PROXY()), or to | |||||
7367 | * the address specified by @a request_uri. If no @a request_uri is | |||||
7368 | * specified, it is taken from route-set target or from the @To header. | |||||
7369 | * | |||||
7370 | * When NTA receives response to the request, it invokes the @a callback | |||||
7371 | * function. | |||||
7372 | * | |||||
7373 | * @param leg call leg object | |||||
7374 | * @param callback callback function (may be @c NULL) | |||||
7375 | * @param magic application context pointer | |||||
7376 | * @param route_url optional URL used to route transaction requests | |||||
7377 | * @param method method type | |||||
7378 | * @param name method name | |||||
7379 | * @param request_uri Request-URI | |||||
7380 | * @param tag, value, ... list of tagged arguments | |||||
7381 | * | |||||
7382 | * @return | |||||
7383 | * A pointer to a newly created outgoing transaction object if successful, | |||||
7384 | * and NULL otherwise. | |||||
7385 | * | |||||
7386 | * @note If NTATAG_STATELESS(1) tag is given and the @a callback is NULL, | |||||
7387 | * the transaction object is marked as destroyed from the beginning. In that | |||||
7388 | * case, the function may return @code (nta_outgoing_t *)-1 @endcode if the | |||||
7389 | * transaction is freed before returning from the function. | |||||
7390 | * | |||||
7391 | * @sa | |||||
7392 | * nta_outgoing_mcreate(), nta_outgoing_tcancel(), nta_outgoing_destroy(). | |||||
7393 | * | |||||
7394 | * @TAGS | |||||
7395 | * NTATAG_STATELESS(), NTATAG_DELAY_SENDING(), NTATAG_BRANCH_KEY(), | |||||
7396 | * NTATAG_ACK_BRANCH(), NTATAG_DEFAULT_PROXY(), NTATAG_PASS_100(), | |||||
7397 | * NTATAG_USE_TIMESTAMP(), NTATAG_USER_VIA(), TPTAG_IDENT(), NTATAG_TPORT(). All | |||||
7398 | * SIP tags from <sofia-sip/sip_tag.h> can be used to manipulate the request message. | |||||
7399 | * SIP tags after SIPTAG_END() are ignored, however. | |||||
7400 | */ | |||||
7401 | nta_outgoing_t *nta_outgoing_tcreate(nta_leg_t *leg, | |||||
7402 | nta_response_f *callback, | |||||
7403 | nta_outgoing_magic_t *magic, | |||||
7404 | url_string_t const *route_url, | |||||
7405 | sip_method_t method, | |||||
7406 | char const *name, | |||||
7407 | url_string_t const *request_uri, | |||||
7408 | tag_type_t tag, tag_value_t value, ...) | |||||
7409 | { | |||||
7410 | nta_agent_t *agent; | |||||
7411 | msg_t *msg; | |||||
7412 | sip_t *sip; | |||||
7413 | nta_outgoing_t *orq = NULL((void*)0); | |||||
7414 | ta_list ta; | |||||
7415 | tagi_t const *tagi; | |||||
7416 | ||||||
7417 | if (leg == NULL((void*)0)) | |||||
7418 | return NULL((void*)0); | |||||
7419 | ||||||
7420 | agent = leg->leg_agent; | |||||
7421 | msg = nta_msg_create(agent, 0); | |||||
7422 | sip = sip_object(msg); | |||||
7423 | ||||||
7424 | if (route_url == NULL((void*)0)) | |||||
7425 | route_url = (url_string_t *)agent->sa_default_proxy; | |||||
7426 | ||||||
7427 | ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value = (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag ) == tag_next && (ta_start__value) != 0) { ta_start__tag = ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag == tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag == tag_next) { ta_start__value = ((tagi_t *)ta_start__value) ->t_value; } else { ta_start__tag = tag_next; break; } } ( ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value ; if (ta_start__tag != ((void*)0) && ta_start__tag != tag_null && ta_start__tag != tag_next) { va_list ta_start__ap ; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag = tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap ); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value = 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0); | |||||
7428 | ||||||
7429 | tagi = ta_args(ta)(ta).tl; | |||||
7430 | ||||||
7431 | if (sip_add_tagis(msg, sip, &tagi) < 0) { | |||||
7432 | if (tagi && tagi->t_tag) { | |||||
7433 | tag_type_t t = tagi->t_tag; | |||||
7434 | SU_DEBUG_5(("%s(): bad tag %s::%s\n", __func__,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 7435, "%s(): bad tag %s::%s\n", __func__, t->tt_ns ? t-> tt_ns : "", t->tt_name ? t->tt_name : "")) : (void)0) | |||||
7435 | t->tt_ns ? t->tt_ns : "", t->tt_name ? t->tt_name : ""))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 7435, "%s(): bad tag %s::%s\n", __func__, t->tt_ns ? t-> tt_ns : "", t->tt_name ? t->tt_name : "")) : (void)0); | |||||
7436 | } | |||||
7437 | } | |||||
7438 | else if (route_url == NULL((void*)0) && leg->leg_route && | |||||
7439 | leg->leg_loose_route && | |||||
7440 | !(route_url = (url_string_t *)leg->leg_route->r_url)) | |||||
7441 | ; | |||||
7442 | else if (nta_msg_request_complete(msg, leg, method, name, request_uri) < 0) | |||||
7443 | ; | |||||
7444 | else | |||||
7445 | orq = outgoing_create(agent, callback, magic, route_url, NULL((void*)0), msg, | |||||
7446 | ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta). tl[1].t_value); | |||||
7447 | ||||||
7448 | ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value ))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta) .ap)); | |||||
7449 | ||||||
7450 | if (!orq) | |||||
7451 | msg_destroy(msg); | |||||
7452 | ||||||
7453 | return orq; | |||||
7454 | } | |||||
7455 | ||||||
7456 | /**Create an outgoing client transaction. | |||||
7457 | * | |||||
7458 | * Create an outgoing transaction object. The request message is passed to | |||||
7459 | * the transaction object, which sends the request to the network. The | |||||
7460 | * request is sent to the @a route_url (if non-NULL), default proxy (if | |||||
7461 | * defined by NTATAG_DEFAULT_PROXY()), or to the address specified by @a | |||||
7462 | * request_uri. If no @a request_uri is specified, it is taken from | |||||
7463 | * route-set target or from the @To header. | |||||
7464 | * | |||||
7465 | * When NTA receives response to the request, it invokes the @a callback | |||||
7466 | * function. | |||||
7467 | * | |||||
7468 | * @param agent NTA agent object | |||||
7469 | * @param callback callback function (may be @c NULL) | |||||
7470 | * @param magic application context pointer | |||||
7471 | * @param route_url optional URL used to route transaction requests | |||||
7472 | * @param msg request message | |||||
7473 | * @param tag, value, ... tagged parameter list | |||||
7474 | * | |||||
7475 | * @return | |||||
7476 | * Returns a pointer to newly created outgoing transaction object if | |||||
7477 | * successful, and NULL otherwise. | |||||
7478 | * | |||||
7479 | * @note The caller is responsible for destroying the request message @a msg | |||||
7480 | * upon failure. | |||||
7481 | * | |||||
7482 | * @note If NTATAG_STATELESS(1) tag is given and the @a callback is NULL, | |||||
7483 | * the transaction object is marked as destroyed from the beginning. In that | |||||
7484 | * case, the function may return @code (nta_outgoing_t *)-1 @endcode if the | |||||
7485 | * transaction is freed before returning from the function. | |||||
7486 | * | |||||
7487 | * @sa | |||||
7488 | * nta_outgoing_tcreate(), nta_outgoing_tcancel(), nta_outgoing_destroy(). | |||||
7489 | * | |||||
7490 | * @TAGS | |||||
7491 | * NTATAG_STATELESS(), NTATAG_DELAY_SENDING(), NTATAG_BRANCH_KEY(), | |||||
7492 | * NTATAG_ACK_BRANCH(), NTATAG_DEFAULT_PROXY(), NTATAG_PASS_100(), | |||||
7493 | * NTATAG_USE_TIMESTAMP(), NTATAG_USER_VIA(), TPTAG_IDENT(), NTATAG_TPORT(). All | |||||
7494 | * SIP tags from <sofia-sip/sip_tag.h> can be used to manipulate the request message. | |||||
7495 | * SIP tags after SIPTAG_END() are ignored, however. | |||||
7496 | */ | |||||
7497 | nta_outgoing_t *nta_outgoing_mcreate(nta_agent_t *agent, | |||||
7498 | nta_response_f *callback, | |||||
7499 | nta_outgoing_magic_t *magic, | |||||
7500 | url_string_t const *route_url, | |||||
7501 | msg_t *msg, | |||||
7502 | tag_type_t tag, tag_value_t value, ...) | |||||
7503 | { | |||||
7504 | nta_outgoing_t *orq = NULL((void*)0); | |||||
7505 | int cleanup = 0; | |||||
7506 | ||||||
7507 | if (msg == NONE((void *)-1)) | |||||
7508 | msg = nta_msg_create(agent, 0), cleanup = 1; | |||||
7509 | ||||||
7510 | if (msg && agent) { | |||||
7511 | ta_list ta; | |||||
7512 | ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value = (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag ) == tag_next && (ta_start__value) != 0) { ta_start__tag = ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag == tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag == tag_next) { ta_start__value = ((tagi_t *)ta_start__value) ->t_value; } else { ta_start__tag = tag_next; break; } } ( ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value ; if (ta_start__tag != ((void*)0) && ta_start__tag != tag_null && ta_start__tag != tag_next) { va_list ta_start__ap ; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag = tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap ); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value = 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0); | |||||
7513 | if (sip_add_tl(msg, sip_object(msg), ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta). tl[1].t_value) >= 0) | |||||
7514 | orq = outgoing_create(agent, callback, magic, route_url, NULL((void*)0), msg, | |||||
7515 | ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta). tl[1].t_value); | |||||
7516 | ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value ))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta) .ap)); | |||||
7517 | } | |||||
7518 | ||||||
7519 | if (!orq && cleanup) | |||||
7520 | msg_destroy(msg); | |||||
7521 | ||||||
7522 | return orq; | |||||
7523 | } | |||||
7524 | ||||||
7525 | /** Cancel the request. */ | |||||
7526 | int nta_outgoing_cancel(nta_outgoing_t *orq) | |||||
7527 | { | |||||
7528 | nta_outgoing_t *cancel = | |||||
7529 | nta_outgoing_tcancel(orq, NULL((void*)0), NULL((void*)0), TAG_NULL()(tag_type_t)0, (tag_value_t)0); | |||||
7530 | ||||||
7531 | return (cancel != NULL((void*)0)) - 1; | |||||
7532 | } | |||||
7533 | ||||||
7534 | /** Cancel the request. | |||||
7535 | * | |||||
7536 | * Initiate a cancel transaction for client transaction @a orq. | |||||
7537 | * | |||||
7538 | * @param orq client transaction to cancel | |||||
7539 | * @param callback callback function (may be @c NULL) | |||||
7540 | * @param magic application context pointer | |||||
7541 | * @param tag, value, ... list of extra arguments | |||||
7542 | * | |||||
7543 | * @note The function may return @code (nta_outgoing_t *)-1 @endcode (NONE) | |||||
7544 | * if callback is NULL. | |||||
7545 | * | |||||
7546 | * @TAGS | |||||
7547 | * NTATAG_CANCEL_2534(), NTATAG_CANCEL_408() and all the tags that are | |||||
7548 | * accepted by nta_outgoing_tcreate(). | |||||
7549 | * | |||||
7550 | * If NTATAG_CANCEL_408(1) or NTATAG_CANCEL_2543(1) is given, the stack | |||||
7551 | * generates a 487 response to the request internally. If | |||||
7552 | * NTATAG_CANCEL_408(1) is given, no CANCEL request is actually sent. | |||||
7553 | * | |||||
7554 | * @note | |||||
7555 | * nta_outgoing_tcancel() refuses to send a CANCEL request for non-INVITE | |||||
7556 | * requests. | |||||
7557 | */ | |||||
7558 | nta_outgoing_t *nta_outgoing_tcancel(nta_outgoing_t *orq, | |||||
7559 | nta_response_f *callback, | |||||
7560 | nta_outgoing_magic_t *magic, | |||||
7561 | tag_type_t tag, tag_value_t value, ...) | |||||
7562 | { | |||||
7563 | msg_t *msg; | |||||
7564 | int cancel_2543, cancel_408; | |||||
7565 | ta_list ta; | |||||
7566 | int delay_sending; | |||||
7567 | ||||||
7568 | if (orq == NULL((void*)0) || orq == NONE((void *)-1)) | |||||
7569 | return NULL((void*)0); | |||||
7570 | ||||||
7571 | if (orq->orq_destroyed) { | |||||
7572 | SU_DEBUG_3(("%s: trying to cancel destroyed request\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 7572, "%s: trying to cancel destroyed request\n", __func__) ) : (void)0); | |||||
7573 | return NULL((void*)0); | |||||
7574 | } | |||||
7575 | if (orq->orq_method != sip_method_invite) { | |||||
7576 | SU_DEBUG_3(("%s: trying to cancel non-INVITE request\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 7576, "%s: trying to cancel non-INVITE request\n", __func__ )) : (void)0); | |||||
7577 | return NULL((void*)0); | |||||
7578 | } | |||||
7579 | ||||||
7580 | if (orq->orq_forking) | |||||
7581 | orq = orq->orq_forking; | |||||
7582 | ||||||
7583 | if (orq->orq_status >= 200 | |||||
7584 | /* && orq->orq_method != sip_method_invite ... !multicast */) { | |||||
7585 | SU_DEBUG_3(("%s: trying to cancel completed request\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 7585, "%s: trying to cancel completed request\n", __func__) ) : (void)0); | |||||
7586 | return NULL((void*)0); | |||||
7587 | } | |||||
7588 | if (orq->orq_canceled) { | |||||
7589 | SU_DEBUG_3(("%s: trying to cancel cancelled request\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 7589, "%s: trying to cancel cancelled request\n", __func__) ) : (void)0); | |||||
7590 | return NULL((void*)0); | |||||
7591 | } | |||||
7592 | orq->orq_canceled = 1; | |||||
7593 | ||||||
7594 | #if HAVE_SOFIA_SRESOLV1 | |||||
7595 | if (!orq->orq_resolved) { | |||||
7596 | outgoing_destroy_resolver(orq); | |||||
7597 | outgoing_reply(orq, SIP_487_REQUEST_CANCELLED487, sip_487_Request_terminated, 1); | |||||
7598 | return NULL((void*)0); /* XXX - Does anyone care about reply? */ | |||||
7599 | } | |||||
7600 | #endif | |||||
7601 | ||||||
7602 | cancel_408 = 0; /* Don't really CANCEL, this is timeout. */ | |||||
7603 | cancel_2543 = orq->orq_agent->sa_cancel_2543; | |||||
7604 | /* CANCEL may be sent only after a provisional response has been received. */ | |||||
7605 | delay_sending = orq->orq_status < 100; | |||||
7606 | ||||||
7607 | ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value = (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag ) == tag_next && (ta_start__value) != 0) { ta_start__tag = ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag == tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag == tag_next) { ta_start__value = ((tagi_t *)ta_start__value) ->t_value; } else { ta_start__tag = tag_next; break; } } ( ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value ; if (ta_start__tag != ((void*)0) && ta_start__tag != tag_null && ta_start__tag != tag_next) { va_list ta_start__ap ; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag = tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap ); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value = 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0); | |||||
7608 | ||||||
7609 | tl_gets(ta_args(ta)(ta).tl, | |||||
7610 | NTATAG_CANCEL_408_REF(cancel_408)ntatag_cancel_408_ref, tag_bool_vr(&(cancel_408)), | |||||
7611 | NTATAG_CANCEL_2543_REF(cancel_2543)ntatag_cancel_2543_ref, tag_bool_vr(&(cancel_2543)), | |||||
7612 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
7613 | ||||||
7614 | if (!cancel_408) | |||||
7615 | msg = outgoing_ackmsg(orq, SIP_METHOD_CANCELsip_method_cancel, "CANCEL", ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta). tl[1].t_value); | |||||
7616 | else | |||||
7617 | msg = NULL((void*)0); | |||||
7618 | ||||||
7619 | ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value ))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta) .ap)); | |||||
7620 | ||||||
7621 | if ((cancel_2543 || cancel_408) && !orq->orq_stateless) | |||||
7622 | outgoing_reply(orq, SIP_487_REQUEST_CANCELLED487, sip_487_Request_terminated, 1); | |||||
7623 | ||||||
7624 | if (msg) { | |||||
7625 | nta_outgoing_t *cancel; | |||||
7626 | if (cancel_2543) /* Follow RFC 2543 semantics for CANCEL */ | |||||
7627 | delay_sending = 0; | |||||
7628 | ||||||
7629 | cancel = outgoing_create(orq->orq_agent, callback, magic, | |||||
7630 | NULL((void*)0), orq->orq_tpn, msg, | |||||
7631 | NTATAG_BRANCH_KEY(orq->orq_branch)ntatag_branch_key, tag_str_v((orq->orq_branch)), | |||||
7632 | NTATAG_DELAY_SENDING(delay_sending)ntatag_delay_sending, tag_bool_v((delay_sending)), | |||||
7633 | NTATAG_USER_VIA(1)ntatag_user_via, tag_bool_v((1)), | |||||
7634 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
7635 | ||||||
7636 | if (delay_sending) | |||||
7637 | orq->orq_cancel = cancel; | |||||
7638 | ||||||
7639 | if (cancel) { | |||||
7640 | if (!delay_sending) | |||||
7641 | outgoing_complete(orq); | |||||
7642 | return cancel; | |||||
7643 | } | |||||
7644 | ||||||
7645 | msg_destroy(msg); | |||||
7646 | } | |||||
7647 | ||||||
7648 | return NULL((void*)0); | |||||
7649 | } | |||||
7650 | ||||||
7651 | /**Bind callback and application context to a client transaction. | |||||
7652 | * | |||||
7653 | * @param orq outgoing client transaction | |||||
7654 | * @param callback callback function (may be NULL) | |||||
7655 | * @param magic application context pointer | |||||
7656 | * (given as argument to @a callback) | |||||
7657 | * | |||||
7658 | * @NEW_1_12_9 | |||||
7659 | */ | |||||
7660 | int | |||||
7661 | nta_outgoing_bind(nta_outgoing_t *orq, | |||||
7662 | nta_response_f *callback, | |||||
7663 | nta_outgoing_magic_t *magic) | |||||
7664 | { | |||||
7665 | if (orq && !orq->orq_destroyed) { | |||||
7666 | if (callback == NULL((void*)0)) | |||||
7667 | callback = outgoing_default_cb; | |||||
7668 | orq->orq_callback = callback; | |||||
7669 | orq->orq_magic = magic; | |||||
7670 | return 0; | |||||
7671 | } | |||||
7672 | return -1; | |||||
7673 | } | |||||
7674 | ||||||
7675 | /**Get application context bound to a client transaction. | |||||
7676 | * | |||||
7677 | * @param orq outgoing client transaction | |||||
7678 | * @param callback callback function (may be NULL) | |||||
7679 | * | |||||
7680 | * Return the application context bound to a client transaction. If the @a | |||||
7681 | * callback function pointer is given, return application context only if | |||||
7682 | * the callback matches with the callback bound to the client transaction. | |||||
7683 | * | |||||
7684 | * @NEW_1_12_11 | |||||
7685 | */ | |||||
7686 | nta_outgoing_magic_t * | |||||
7687 | nta_outgoing_magic(nta_outgoing_t const *orq, | |||||
7688 | nta_response_f *callback) | |||||
7689 | { | |||||
7690 | if (orq && (callback == NULL((void*)0) || callback == orq->orq_callback)) | |||||
7691 | return orq->orq_magic; | |||||
7692 | else | |||||
7693 | return NULL((void*)0); | |||||
7694 | } | |||||
7695 | ||||||
7696 | ||||||
7697 | /** | |||||
7698 | * Destroy a request object. | |||||
7699 | * | |||||
7700 | * @note | |||||
7701 | * This function does not actually free the object, but marks it as | |||||
7702 | * disposable. The object is freed after a timeout. | |||||
7703 | */ | |||||
7704 | void nta_outgoing_destroy(nta_outgoing_t *orq) | |||||
7705 | { | |||||
7706 | if (orq == NULL((void*)0) || orq == NONE((void *)-1)) | |||||
7707 | return; | |||||
7708 | ||||||
7709 | if (orq->orq_destroyed) { | |||||
7710 | SU_DEBUG_1(("%s(%p): %s\n", "nta_outgoing_destroy", (void *)orq,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 7711, "%s(%p): %s\n", "nta_outgoing_destroy", (void *)orq, "already destroyed" )) : (void)0) | |||||
7711 | "already destroyed"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 7711, "%s(%p): %s\n", "nta_outgoing_destroy", (void *)orq, "already destroyed" )) : (void)0); | |||||
7712 | return; | |||||
7713 | } | |||||
7714 | ||||||
7715 | outgoing_destroy(orq); | |||||
7716 | } | |||||
7717 | ||||||
7718 | /** Return the request URI */ | |||||
7719 | url_t const *nta_outgoing_request_uri(nta_outgoing_t const *orq) | |||||
7720 | { | |||||
7721 | return orq != NULL((void*)0) && orq != NONE((void *)-1) ? orq->orq_url : NULL((void*)0); | |||||
7722 | } | |||||
7723 | ||||||
7724 | /** Return the URI used to route the request */ | |||||
7725 | url_t const *nta_outgoing_route_uri(nta_outgoing_t const *orq) | |||||
7726 | { | |||||
7727 | return orq != NULL((void*)0) && orq != NONE((void *)-1) ? orq->orq_route : NULL((void*)0); | |||||
7728 | } | |||||
7729 | ||||||
7730 | /** Return method of the client transaction */ | |||||
7731 | sip_method_t nta_outgoing_method(nta_outgoing_t const *orq) | |||||
7732 | { | |||||
7733 | return orq != NULL((void*)0) && orq != NONE((void *)-1) ? orq->orq_method : sip_method_invalid; | |||||
7734 | } | |||||
7735 | ||||||
7736 | /** Return method name of the client transaction */ | |||||
7737 | char const *nta_outgoing_method_name(nta_outgoing_t const *orq) | |||||
7738 | { | |||||
7739 | return orq != NULL((void*)0) && orq != NONE((void *)-1) ? orq->orq_method_name : NULL((void*)0); | |||||
7740 | } | |||||
7741 | ||||||
7742 | /** Get sequence number of a client transaction. | |||||
7743 | */ | |||||
7744 | uint32_t nta_outgoing_cseq(nta_outgoing_t const *orq) | |||||
7745 | { | |||||
7746 | return orq != NULL((void*)0) && orq != NONE((void *)-1) && orq->orq_cseq | |||||
7747 | ? orq->orq_cseq->cs_seq : 0; | |||||
7748 | } | |||||
7749 | ||||||
7750 | /** | |||||
7751 | * Get the status code of a client transaction. | |||||
7752 | */ | |||||
7753 | int nta_outgoing_status(nta_outgoing_t const *orq) | |||||
7754 | { | |||||
7755 | /* Return 500 Internal server error for invalid handles. */ | |||||
7756 | return orq != NULL((void*)0) && orq != NONE((void *)-1) ? orq->orq_status : 500; | |||||
7757 | } | |||||
7758 | ||||||
7759 | /** Get the RTT delay measured using @Timestamp header. */ | |||||
7760 | unsigned nta_outgoing_delay(nta_outgoing_t const *orq) | |||||
7761 | { | |||||
7762 | return orq != NULL((void*)0) && orq != NONE((void *)-1) ? orq->orq_delay : UINT_MAX(2147483647 *2U +1U); | |||||
7763 | } | |||||
7764 | ||||||
7765 | /** Get the branch parameter. @NEW_1_12_7. */ | |||||
7766 | char const *nta_outgoing_branch(nta_outgoing_t const *orq) | |||||
7767 | { | |||||
7768 | return orq != NULL((void*)0) && orq != NONE((void *)-1) && orq->orq_branch | |||||
7769 | ? orq->orq_branch + strlen("branch=") | |||||
7770 | : NULL((void*)0); | |||||
7771 | } | |||||
7772 | ||||||
7773 | /**Get reference to response message. | |||||
7774 | * | |||||
7775 | * Retrieve the latest incoming response message to the outgoing | |||||
7776 | * transaction. Note that the message is not copied, but a new reference to | |||||
7777 | * it is created instead. | |||||
7778 | * | |||||
7779 | * @param orq outgoing transaction handle | |||||
7780 | * | |||||
7781 | * @retval | |||||
7782 | * A pointer to response message is returned, or NULL if no response message | |||||
7783 | * has been received. | |||||
7784 | */ | |||||
7785 | msg_t *nta_outgoing_getresponse(nta_outgoing_t *orq) | |||||
7786 | { | |||||
7787 | if (orq != NULL((void*)0) && orq != NONE((void *)-1)) | |||||
7788 | return msg_ref_create(orq->orq_response); | |||||
7789 | else | |||||
7790 | return NULL((void*)0); | |||||
7791 | } | |||||
7792 | ||||||
7793 | /**Get request message. | |||||
7794 | * | |||||
7795 | * Retrieves the request message sent to the network. Note that the request | |||||
7796 | * message is @b not copied, but a new reference to it is created. | |||||
7797 | * | |||||
7798 | * @retval | |||||
7799 | * A pointer to the request message is returned, or NULL if an error | |||||
7800 | * occurred. | |||||
7801 | */ | |||||
7802 | msg_t *nta_outgoing_getrequest(nta_outgoing_t *orq) | |||||
7803 | { | |||||
7804 | if (orq != NULL((void*)0) && orq != NONE((void *)-1)) | |||||
7805 | return msg_ref_create(orq->orq_request); | |||||
7806 | else | |||||
7807 | return NULL((void*)0); | |||||
7808 | } | |||||
7809 | ||||||
7810 | /**Create an outgoing request. | |||||
7811 | * | |||||
7812 | * Create an outgoing transaction object and send the request to the | |||||
7813 | * network. The request is sent to the @a route_url (if non-NULL), default | |||||
7814 | * proxy (if defined by NTATAG_DEFAULT_PROXY()), or to the address specified | |||||
7815 | * by @a sip->sip_request->rq_url. | |||||
7816 | * | |||||
7817 | * When NTA receives response to the request, it invokes the @a callback | |||||
7818 | * function. | |||||
7819 | * | |||||
7820 | * @param agent nta agent object | |||||
7821 | * @param callback callback function (may be @c NULL) | |||||
7822 | * @param magic application context pointer | |||||
7823 | * @param route_url optional URL used to route transaction requests | |||||
7824 | * @param msg request message | |||||
7825 | * @param tpn (optional) transport name | |||||
7826 | * @param msg request message to | |||||
7827 | * @param tag, value, ... tagged arguments | |||||
7828 | * | |||||
7829 | * @return | |||||
7830 | * Returns a pointer to newly created outgoing transaction object if | |||||
7831 | * successful, and NULL otherwise. | |||||
7832 | * | |||||
7833 | * @note If NTATAG_STATELESS(1) tag is given and the @a callback is NULL, | |||||
7834 | * the transaction object is marked as destroyed from the beginning. In that | |||||
7835 | * case, the function may return @code (nta_outgoing_t *)-1 @endcode if the | |||||
7836 | * transaction is freed before returning from the function. | |||||
7837 | * | |||||
7838 | * @TAG NTATAG_TPORT must point to an existing transport object for | |||||
7839 | * 'agent' (the passed tport is otherwise ignored). | |||||
7840 | * | |||||
7841 | * @sa | |||||
7842 | * nta_outgoing_tcreate(), nta_outgoing_tcancel(), nta_outgoing_destroy(). | |||||
7843 | */ | |||||
7844 | nta_outgoing_t *outgoing_create(nta_agent_t *agent, | |||||
7845 | nta_response_f *callback, | |||||
7846 | nta_outgoing_magic_t *magic, | |||||
7847 | url_string_t const *route_url, | |||||
7848 | tp_name_t const *tpn, | |||||
7849 | msg_t *msg, | |||||
7850 | tag_type_t tag, tag_value_t value, ...) | |||||
7851 | { | |||||
7852 | nta_outgoing_t *orq; | |||||
7853 | sip_t *sip; | |||||
7854 | su_home_t *home; | |||||
7855 | char const *comp = NONE((void *)-1); | |||||
7856 | char const *branch = NONE((void *)-1); | |||||
7857 | char const *ack_branch = NONE((void *)-1); | |||||
7858 | char const *tp_ident; | |||||
7859 | int delay_sending = 0, sigcomp_zap = 0; | |||||
7860 | int pass_100 = agent->sa_pass_100, use_timestamp = agent->sa_timestamp; | |||||
7861 | enum nta_res_order_e res_order = agent->sa_res_order; | |||||
7862 | struct sigcomp_compartment *cc = NULL((void*)0); | |||||
7863 | ta_list ta; | |||||
7864 | char const *scheme = NULL((void*)0); | |||||
7865 | char const *port = NULL((void*)0); | |||||
7866 | int invalid, resolved = 0, stateless = 0, user_via = agent->sa_user_via; | |||||
7867 | int invite_100rel = agent->sa_invite_100rel; | |||||
7868 | int explicit_transport = 1; | |||||
7869 | int call_tls_orq_connect_timeout_is_set = 0; | |||||
7870 | int call_tls_orq_connect_timeout = 0; | |||||
7871 | ||||||
7872 | tagi_t const *t; | |||||
7873 | tport_t *override_tport = NULL((void*)0); | |||||
7874 | ||||||
7875 | if (!agent->sa_tport_ip6) | |||||
7876 | res_order = nta_res_ip4_only; | |||||
7877 | else if (!agent->sa_tport_ip4) | |||||
7878 | res_order = nta_res_ip6_only; | |||||
7879 | ||||||
7880 | if (!callback) | |||||
7881 | callback = outgoing_default_cb; | |||||
7882 | if (!route_url) | |||||
7883 | route_url = (url_string_t *)agent->sa_default_proxy; | |||||
7884 | ||||||
7885 | sip = sip_object(msg); | |||||
7886 | home = msg_home(msg)((su_home_t*)(msg)); | |||||
7887 | ||||||
7888 | #ifdef HAVE_ZLIB_COMPRESS1 | |||||
7889 | sip_content_encoding_Xflate(msg, sip_object(msg), 0, 1); | |||||
7890 | #endif | |||||
7891 | ||||||
7892 | if (!sip->sip_request || sip_complete_message(msg) < 0) { | |||||
7893 | SU_DEBUG_3(("nta: outgoing_create: incomplete request\n" VA_NONE))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 7893, "nta: outgoing_create: incomplete request\n" "%s", "" )) : (void)0); | |||||
7894 | return NULL((void*)0); | |||||
7895 | } | |||||
7896 | ||||||
7897 | if (!route_url && !tpn && sip->sip_route && | |||||
7898 | sip->sip_route->r_url->url_params && | |||||
7899 | url_param(sip->sip_route->r_url->url_params, "lr", NULL((void*)0), 0)) | |||||
7900 | route_url = (url_string_t *)sip->sip_route->r_url; | |||||
7901 | ||||||
7902 | if (!(orq = su_zalloc(agent->sa_home, sizeof(*orq)))) | |||||
7903 | return NULL((void*)0); | |||||
7904 | ||||||
7905 | tp_ident = tpn ? tpn->tpn_ident : NULL((void*)0); | |||||
7906 | ||||||
7907 | ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value = (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag ) == tag_next && (ta_start__value) != 0) { ta_start__tag = ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag == tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag == tag_next) { ta_start__value = ((tagi_t *)ta_start__value) ->t_value; } else { ta_start__tag = tag_next; break; } } ( ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value ; if (ta_start__tag != ((void*)0) && ta_start__tag != tag_null && ta_start__tag != tag_next) { va_list ta_start__ap ; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag = tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap ); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value = 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0); | |||||
7908 | ||||||
7909 | /* tl_gets() is a bit too slow here... */ | |||||
7910 | for (t = ta_args(ta)(ta).tl; t; t = tl_next(t)) { | |||||
7911 | tag_type_t tt = t->t_tag; | |||||
7912 | ||||||
7913 | if (ntatag_stateless == tt) | |||||
7914 | stateless = t->t_value != 0; | |||||
7915 | else if (ntatag_delay_sending == tt) | |||||
7916 | delay_sending = t->t_value != 0; | |||||
7917 | else if (ntatag_branch_key == tt) | |||||
7918 | branch = (void *)t->t_value; | |||||
7919 | else if (ntatag_pass_100 == tt) | |||||
7920 | pass_100 = t->t_value != 0; | |||||
7921 | else if (ntatag_use_timestamp == tt) | |||||
7922 | use_timestamp = t->t_value != 0; | |||||
7923 | else if (ntatag_user_via == tt) | |||||
7924 | user_via = t->t_value != 0; | |||||
7925 | else if (ntatag_ack_branch == tt) | |||||
7926 | ack_branch = (void *)t->t_value; | |||||
7927 | else if (ntatag_default_proxy == tt) | |||||
7928 | route_url = (void *)t->t_value; | |||||
7929 | else if (tptag_ident == tt) | |||||
7930 | tp_ident = (void *)t->t_value; | |||||
7931 | else if (ntatag_comp == tt) | |||||
7932 | comp = (char const *)t->t_value; | |||||
7933 | else if (ntatag_sigcomp_close == tt) | |||||
7934 | sigcomp_zap = t->t_value != 0; | |||||
7935 | else if (tptag_compartment == tt) | |||||
7936 | cc = (void *)t->t_value; | |||||
7937 | else if (ntatag_tport == tt) { | |||||
7938 | override_tport = (tport_t *)t->t_value; | |||||
7939 | } | |||||
7940 | else if (ntatag_rel100 == tt) { | |||||
7941 | invite_100rel = t->t_value != 0; | |||||
7942 | } | |||||
7943 | else if (ntatag_tls_orq_connect_timeout == tt) { | |||||
7944 | call_tls_orq_connect_timeout_is_set = 1; | |||||
7945 | call_tls_orq_connect_timeout = t->t_value; | |||||
7946 | if (call_tls_orq_connect_timeout > NTA_TIME_MAX) call_tls_orq_connect_timeout = NTA_TIME_MAX; | |||||
7947 | } | |||||
7948 | } | |||||
7949 | ||||||
7950 | orq->orq_agent = agent; | |||||
7951 | orq->orq_callback = callback; | |||||
7952 | orq->orq_magic = magic; | |||||
7953 | orq->orq_method = sip->sip_request->rq_method; | |||||
7954 | orq->orq_method_name = sip->sip_request->rq_method_name; | |||||
7955 | orq->orq_cseq = sip->sip_cseq; | |||||
7956 | orq->orq_to = sip->sip_to; | |||||
7957 | orq->orq_from = sip->sip_from; | |||||
7958 | orq->orq_call_id = sip->sip_call_id; | |||||
7959 | orq->orq_tags = tl_afilter(home, tport_tags, ta_args(ta)(ta).tl); | |||||
7960 | orq->orq_delayed = delay_sending != 0; | |||||
7961 | orq->orq_pass_100 = pass_100 != 0; | |||||
7962 | orq->orq_sigcomp_zap = sigcomp_zap; | |||||
7963 | orq->orq_sigcomp_new = comp != NONE((void *)-1) && comp != NULL((void*)0); | |||||
7964 | orq->orq_timestamp = use_timestamp; | |||||
7965 | orq->orq_delay = UINT_MAX(2147483647 *2U +1U); | |||||
7966 | orq->orq_stateless = stateless != 0; | |||||
7967 | orq->orq_user_via = user_via != 0 && sip->sip_via; | |||||
7968 | orq->orq_100rel = invite_100rel; | |||||
7969 | orq->orq_uas = !stateless && agent->sa_is_a_uas; | |||||
7970 | orq->orq_call_tls_connect_timeout_is_set = call_tls_orq_connect_timeout_is_set; | |||||
7971 | orq->orq_call_tls_connect_timeout = (call_tls_orq_connect_timeout > 0) ? call_tls_orq_connect_timeout : 0; | |||||
7972 | ||||||
7973 | if (cc) | |||||
7974 | orq->orq_cc = nta_compartment_ref(cc); | |||||
7975 | ||||||
7976 | /* Add supported features */ | |||||
7977 | outgoing_features(agent, orq, msg, sip, ta_args(ta)(ta).tl); | |||||
7978 | ||||||
7979 | ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value ))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta) .ap)); | |||||
7980 | ||||||
7981 | /* select the tport to use for the outgoing message */ | |||||
7982 | if (override_tport) { | |||||
7983 | /* note: no ref taken to the tport as its only used once here */ | |||||
7984 | if (tport_is_secondary(override_tport)) { | |||||
7985 | tpn = tport_name(override_tport); | |||||
7986 | orq->orq_user_tport = 1; | |||||
7987 | } | |||||
7988 | } | |||||
7989 | ||||||
7990 | if (tpn) { | |||||
7991 | /* CANCEL or ACK to [3456]XX */ | |||||
7992 | invalid = tport_name_dup(home, orq->orq_tpn, tpn); | |||||
7993 | #if 0 //HAVE_SOFIA_SRESOLV | |||||
7994 | /* We send ACK or CANCEL only if original request was really sent */ | |||||
7995 | assert(tport_name_is_resolved(orq->orq_tpn))((void) sizeof ((tport_name_is_resolved(orq->orq_tpn)) ? 1 : 0), __extension__ ({ if (tport_name_is_resolved(orq->orq_tpn )) ; else __assert_fail ("tport_name_is_resolved(orq->orq_tpn)" , "nta.c", 7995, __extension__ __PRETTY_FUNCTION__); })); | |||||
7996 | #endif | |||||
7997 | resolved = tport_name_is_resolved(orq->orq_tpn); | |||||
7998 | orq->orq_url = url_hdup(home, sip->sip_request->rq_url); | |||||
7999 | } | |||||
8000 | else if (route_url && !orq->orq_user_tport) { | |||||
8001 | invalid = nta_tpn_by_url(home, orq->orq_tpn, &scheme, &port, route_url); | |||||
8002 | if (invalid >= 0) { | |||||
8003 | explicit_transport = invalid > 0; | |||||
8004 | if (override_tport) { /* Use transport protocol name from transport */ | |||||
8005 | if (strcmp(orq->orq_tpn->tpn_proto, "*") == 0) | |||||
8006 | orq->orq_tpn->tpn_proto = tport_name(override_tport)->tpn_proto; | |||||
8007 | } | |||||
8008 | ||||||
8009 | resolved = tport_name_is_resolved(orq->orq_tpn); | |||||
8010 | orq->orq_url = url_hdup(home, sip->sip_request->rq_url); | |||||
8011 | if (route_url != (url_string_t *)agent->sa_default_proxy) | |||||
8012 | orq->orq_route = url_hdup(home, route_url->us_url); | |||||
8013 | } | |||||
8014 | } | |||||
8015 | else { | |||||
8016 | invalid = nta_tpn_by_url(home, orq->orq_tpn, &scheme, &port, | |||||
8017 | (url_string_t *)sip->sip_request->rq_url); | |||||
8018 | if (invalid >= 0) { | |||||
8019 | explicit_transport = invalid > 0; | |||||
8020 | resolved = tport_name_is_resolved(orq->orq_tpn); | |||||
8021 | sip_fragment_clear(sip->sip_request->rq_common)((sip->sip_request->rq_common)->h_data = ((void*)0), (sip->sip_request->rq_common)->h_len = 0); | |||||
8022 | } | |||||
8023 | orq->orq_url = url_hdup(home, sip->sip_request->rq_url); | |||||
8024 | } | |||||
8025 | ||||||
8026 | if (!override_tport) | |||||
8027 | orq->orq_tpn->tpn_ident = tp_ident; | |||||
8028 | else | |||||
8029 | orq->orq_tpn->tpn_ident = tport_name(override_tport)->tpn_ident; | |||||
8030 | ||||||
8031 | if (comp == NULL((void*)0)) | |||||
8032 | orq->orq_tpn->tpn_comp = comp; | |||||
8033 | ||||||
8034 | if (orq->orq_user_via && su_strmatch(orq->orq_tpn->tpn_proto, "*")) { | |||||
8035 | char const *proto = sip_via_transport(sip->sip_via); | |||||
8036 | if (proto) orq->orq_tpn->tpn_proto = proto; | |||||
8037 | } | |||||
8038 | ||||||
8039 | if (branch && branch != NONE((void *)-1)) { | |||||
8040 | if (su_casenmatch(branch, "branch=", 7)) | |||||
8041 | branch = su_strdup(home, branch); | |||||
8042 | else | |||||
8043 | branch = su_sprintf(home, "branch=%s", branch); | |||||
8044 | } | |||||
8045 | else if (orq->orq_user_via && sip->sip_via->v_branch && orq->orq_method != sip_method_invite ) | |||||
8046 | branch = su_sprintf(home, "branch=%s", sip->sip_via->v_branch); | |||||
8047 | else if (stateless) | |||||
8048 | branch = stateless_branch(agent, msg, sip, orq->orq_tpn); | |||||
8049 | else | |||||
8050 | branch = stateful_branch(home, agent); | |||||
8051 | ||||||
8052 | orq->orq_branch = branch; | |||||
8053 | orq->orq_via_branch = branch; | |||||
8054 | ||||||
8055 | if (orq->orq_method == sip_method_ack) { | |||||
8056 | /* Find the original INVITE which we are ACKing */ | |||||
8057 | if (ack_branch != NULL((void*)0) && ack_branch != NONE((void *)-1)) { | |||||
8058 | if (su_casenmatch(ack_branch, "branch=", 7)) | |||||
8059 | orq->orq_branch = su_strdup(home, ack_branch); | |||||
8060 | else | |||||
8061 | orq->orq_branch = su_sprintf(home, "branch=%s", ack_branch); | |||||
8062 | } | |||||
8063 | else if (orq->orq_uas) { | |||||
8064 | /* | |||||
8065 | * ACK redirects further 2XX messages to it. | |||||
8066 | * | |||||
8067 | * Use orq_branch from INVITE, but put a different branch in topmost Via. | |||||
8068 | */ | |||||
8069 | nta_outgoing_t *invite = outgoing_find(agent, msg, sip, NULL((void*)0)); | |||||
8070 | ||||||
8071 | if (invite) { | |||||
8072 | sip_t const *inv = sip_object(invite->orq_request); | |||||
8073 | ||||||
8074 | orq->orq_branch = su_strdup(home, invite->orq_branch); | |||||
8075 | ||||||
8076 | /* @RFC3261 section 13.2.2.4 - | |||||
8077 | * The ACK MUST contain the same credentials as the INVITE. | |||||
8078 | */ | |||||
8079 | if (!sip->sip_proxy_authorization && !sip->sip_authorization) { | |||||
8080 | if (inv->sip_proxy_authorization) | |||||
8081 | sip_add_dup(msg, sip, (void *)inv->sip_proxy_authorization); | |||||
8082 | if (inv->sip_authorization) | |||||
8083 | sip_add_dup(msg, sip, (void *)inv->sip_authorization); | |||||
8084 | } | |||||
8085 | } | |||||
8086 | else { | |||||
8087 | SU_DEBUG_1(("outgoing_create: ACK without INVITE\n" VA_NONE))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 8087, "outgoing_create: ACK without INVITE\n" "%s", "")) : ( void)0); | |||||
8088 | assert(!"INVITE found for ACK")((void) sizeof ((!"INVITE found for ACK") ? 1 : 0), __extension__ ({ if (!"INVITE found for ACK") ; else __assert_fail ("!\"INVITE found for ACK\"" , "nta.c", 8088, __extension__ __PRETTY_FUNCTION__); })); | |||||
8089 | } | |||||
8090 | } | |||||
8091 | } | |||||
8092 | ||||||
8093 | #if HAVE_SOFIA_SRESOLV1 | |||||
8094 | if (!resolved) | |||||
8095 | orq->orq_tpn->tpn_port = port; | |||||
8096 | orq->orq_resolved = resolved; | |||||
8097 | #else | |||||
8098 | orq->orq_resolved = resolved = 1; | |||||
8099 | #endif | |||||
8100 | orq->orq_sips = su_casematch(scheme, "sips"); | |||||
8101 | ||||||
8102 | if (invalid < 0 || !orq->orq_branch || msg_serialize(msg, (void *)sip) < 0) { | |||||
8103 | SU_DEBUG_3(("nta outgoing create: %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 8105, "nta outgoing create: %s\n", invalid < 0 ? "invalid URI" : !orq->orq_branch ? "no branch" : "invalid message")) : ( void)0) | |||||
8104 | invalid < 0 ? "invalid URI" :(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 8105, "nta outgoing create: %s\n", invalid < 0 ? "invalid URI" : !orq->orq_branch ? "no branch" : "invalid message")) : ( void)0) | |||||
8105 | !orq->orq_branch ? "no branch" : "invalid message"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 8105, "nta outgoing create: %s\n", invalid < 0 ? "invalid URI" : !orq->orq_branch ? "no branch" : "invalid message")) : ( void)0); | |||||
8106 | outgoing_free(orq); | |||||
8107 | return NULL((void*)0); | |||||
8108 | } | |||||
8109 | ||||||
8110 | /* Now we are committed in sending the transaction */ | |||||
8111 | orq->orq_request = msg; | |||||
8112 | agent->sa_stats->as_client_tr++; | |||||
8113 | orq->orq_hash = NTA_HASH(sip->sip_call_id, sip->sip_cseq->cs_seq)((sip->sip_call_id)->i_hash + 26839U * (uint32_t)(sip-> sip_cseq->cs_seq)); | |||||
8114 | ||||||
8115 | if (orq->orq_user_tport) | |||||
8116 | outgoing_send_via(orq, override_tport); | |||||
8117 | else if (resolved) | |||||
8118 | outgoing_prepare_send(orq); | |||||
8119 | #if HAVE_SOFIA_SRESOLV1 | |||||
8120 | else | |||||
8121 | outgoing_resolve(orq, explicit_transport, res_order); | |||||
8122 | #endif | |||||
8123 | ||||||
8124 | if (stateless && | |||||
8125 | orq->orq_status >= 200 && | |||||
8126 | callback == outgoing_default_cb) { | |||||
8127 | void *retval; | |||||
8128 | ||||||
8129 | if (orq->orq_status < 300) | |||||
8130 | retval = (void *)-1; /* NONE */ | |||||
8131 | else | |||||
8132 | retval = NULL((void*)0), orq->orq_request = NULL((void*)0); | |||||
8133 | ||||||
8134 | outgoing_free(orq); | |||||
8135 | ||||||
8136 | return retval; | |||||
8137 | } | |||||
8138 | ||||||
8139 | assert(orq->orq_queue)((void) sizeof ((orq->orq_queue) ? 1 : 0), __extension__ ( { if (orq->orq_queue) ; else __assert_fail ("orq->orq_queue" , "nta.c", 8139, __extension__ __PRETTY_FUNCTION__); })); | |||||
8140 | ||||||
8141 | outgoing_insert(agent, orq); | |||||
8142 | ||||||
8143 | return orq; | |||||
8144 | } | |||||
8145 | ||||||
8146 | /** Prepare sending a request */ | |||||
8147 | static void | |||||
8148 | outgoing_prepare_send(nta_outgoing_t *orq) | |||||
8149 | { | |||||
8150 | nta_agent_t *sa = orq->orq_agent; | |||||
8151 | tport_t *tp; | |||||
8152 | tp_name_t *tpn = orq->orq_tpn; | |||||
8153 | ||||||
8154 | /* Select transport by scheme */ | |||||
8155 | if (orq->orq_sips && strcmp(tpn->tpn_proto, "*") == 0) | |||||
8156 | tpn->tpn_proto = "tls"; | |||||
8157 | ||||||
8158 | if (!tpn->tpn_port) | |||||
8159 | tpn->tpn_port = ""; | |||||
8160 | ||||||
8161 | tp = tport_by_name(sa->sa_tports, tpn); | |||||
8162 | ||||||
8163 | if (tpn->tpn_port[0] == '\0') { | |||||
8164 | if (orq->orq_sips || tport_has_tls(tp)) | |||||
8165 | tpn->tpn_port = "5061"; | |||||
8166 | else | |||||
8167 | tpn->tpn_port = "5060"; | |||||
8168 | } | |||||
8169 | ||||||
8170 | if (tp) { | |||||
8171 | outgoing_send_via(orq, tp); | |||||
8172 | } | |||||
8173 | else if (orq->orq_sips) { | |||||
8174 | SU_DEBUG_3(("nta outgoing create: no secure transport\n" VA_NONE))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 8174, "nta outgoing create: no secure transport\n" "%s", "" )) : (void)0); | |||||
8175 | outgoing_reply(orq, SIP_416_UNSUPPORTED_URI416, sip_416_Unsupported_uri, 1); | |||||
8176 | } | |||||
8177 | else { | |||||
8178 | SU_DEBUG_3(("nta outgoing create: no transport protocol\n" VA_NONE))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 8178, "nta outgoing create: no transport protocol\n" "%s", "" )) : (void)0); | |||||
8179 | outgoing_reply(orq, 503, "No transport", 1); | |||||
8180 | } | |||||
8181 | } | |||||
8182 | ||||||
8183 | /** Send request using given transport */ | |||||
8184 | static void | |||||
8185 | outgoing_send_via(nta_outgoing_t *orq, tport_t *tp) | |||||
8186 | { | |||||
8187 | tport_t *old_tp = orq->orq_tport; | |||||
8188 | ||||||
8189 | orq->orq_tport = tport_ref(tp); | |||||
8190 | ||||||
8191 | if (orq->orq_pending && tp != old_tp) { | |||||
8192 | tport_release(old_tp, orq->orq_pending, | |||||
8193 | orq->orq_request, NULL((void*)0), orq, 0); | |||||
8194 | orq->orq_pending = 0; | |||||
8195 | } | |||||
8196 | ||||||
8197 | if (old_tp) tport_unref(old_tp); | |||||
8198 | ||||||
8199 | if (outgoing_insert_via(orq, agent_tport_via(tp)) < 0) { | |||||
8200 | SU_DEBUG_3(("nta outgoing create: cannot insert Via line\n" VA_NONE))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 8200, "nta outgoing create: cannot insert Via line\n" "%s", "")) : (void)0); | |||||
8201 | outgoing_reply(orq, 503, "Cannot insert Via", 1); | |||||
8202 | return; | |||||
8203 | } | |||||
8204 | ||||||
8205 | #if HAVE_SOFIA_SMIME0 | |||||
8206 | { | |||||
8207 | sm_object_t *smime = sa->sa_smime; | |||||
8208 | sip_t *sip = sip_object(orq->orq_request); | |||||
8209 | ||||||
8210 | if (sa->sa_smime && | |||||
8211 | (sip->sip_request->rq_method == sip_method_invite || | |||||
8212 | sip->sip_request->rq_method == sip_method_message)) { | |||||
8213 | msg_prepare(orq->orq_request); | |||||
8214 | if (sm_encode_message(smime, msg, sip, SM_ID_NULL) < 0) { | |||||
8215 | outgoing_tport_error(sa, orq, NULL((void*)0), | |||||
8216 | orq->orq_request, su_errno()); | |||||
8217 | return; | |||||
8218 | } | |||||
8219 | } | |||||
8220 | } | |||||
8221 | #endif | |||||
8222 | ||||||
8223 | orq->orq_prepared = 1; | |||||
8224 | ||||||
8225 | if (orq->orq_delayed) { | |||||
8226 | SU_DEBUG_5(("nta: delayed sending %s (%u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8227, "nta: delayed sending %s (%u)\n", orq->orq_method_name , orq->orq_cseq->cs_seq)) : (void)0) | |||||
8227 | orq->orq_method_name, orq->orq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8227, "nta: delayed sending %s (%u)\n", orq->orq_method_name , orq->orq_cseq->cs_seq)) : (void)0); | |||||
8228 | outgoing_queue(orq->orq_agent->sa_out.delayed, orq); | |||||
8229 | return; | |||||
8230 | } | |||||
8231 | ||||||
8232 | outgoing_send(orq, 0); | |||||
8233 | } | |||||
8234 | ||||||
8235 | ||||||
8236 | /** Send a request */ | |||||
8237 | static void | |||||
8238 | outgoing_send(nta_outgoing_t *orq, int retransmit) | |||||
8239 | { | |||||
8240 | int err; | |||||
8241 | tp_name_t const *tpn = orq->orq_tpn; | |||||
8242 | msg_t *msg = orq->orq_request; | |||||
8243 | nta_agent_t *agent = orq->orq_agent; | |||||
8244 | tport_t *tp; | |||||
8245 | int once = 0; | |||||
8246 | su_time_t now = su_now(); | |||||
8247 | tag_type_t tag = tag_skip; | |||||
8248 | tag_value_t value = 0; | |||||
8249 | struct sigcomp_compartment *cc; cc = NULL((void*)0); | |||||
8250 | ||||||
8251 | /* tport can be NULL if we are just switching network */ | |||||
8252 | if (orq->orq_tport == NULL((void*)0)) { | |||||
8253 | outgoing_tport_error(agent, orq, NULL((void*)0), orq->orq_request, ENETRESET102); | |||||
8254 | return; | |||||
8255 | } | |||||
8256 | ||||||
8257 | if (orq->orq_user_tport && !tport_is_clear_to_send(orq->orq_tport)) { | |||||
8258 | outgoing_tport_error(agent, orq, NULL((void*)0), orq->orq_request, EPIPE32); | |||||
8259 | return; | |||||
8260 | } | |||||
8261 | ||||||
8262 | if (!retransmit) | |||||
8263 | orq->orq_sent = now; | |||||
8264 | ||||||
8265 | if (orq->orq_timestamp) { | |||||
8266 | sip_t *sip = sip_object(msg); | |||||
8267 | sip_timestamp_t *ts = | |||||
8268 | sip_timestamp_format(msg_home(msg)((su_home_t*)(msg)), "%lu.%06lu", | |||||
8269 | now.tv_sec, now.tv_usec); | |||||
8270 | ||||||
8271 | if (ts) { | |||||
8272 | if (sip->sip_timestamp) | |||||
8273 | msg_header_remove(msg, (msg_pub_t *)sip, (msg_header_t *)sip->sip_timestamp); | |||||
8274 | msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)ts); | |||||
8275 | } | |||||
8276 | } | |||||
8277 | ||||||
8278 | for (;;) { | |||||
8279 | if (tpn->tpn_comp == NULL((void*)0)) { | |||||
8280 | /* xyzzy */ | |||||
8281 | } | |||||
8282 | else if (orq->orq_cc) { | |||||
8283 | cc = orq->orq_cc, orq->orq_cc = NULL((void*)0); | |||||
8284 | } | |||||
8285 | else { | |||||
8286 | cc = agent_compression_compartment(agent, orq->orq_tport, tpn, | |||||
8287 | orq->orq_sigcomp_new); | |||||
8288 | } | |||||
8289 | ||||||
8290 | if (orq->orq_try_udp_instead) | |||||
8291 | tag = tptag_mtu, value = 65535; | |||||
8292 | ||||||
8293 | if (orq->orq_pending) { | |||||
8294 | tport_release(orq->orq_tport, orq->orq_pending, | |||||
8295 | orq->orq_request, NULL((void*)0), orq, 0); | |||||
8296 | orq->orq_pending = 0; | |||||
8297 | } | |||||
8298 | ||||||
8299 | tp = tport_tsend(orq->orq_tport, msg, tpn, | |||||
8300 | tag, value, | |||||
8301 | IF_SIGCOMP_TPTAG_COMPARTMENT(cc)!(cc && cc != ((void *)-1)) ? tag_skip : tptag_compartment , tag_ptr_v((cc)), | |||||
8302 | TAG_NEXT(orq->orq_tags)tag_next, (tag_value_t)(orq->orq_tags)); | |||||
8303 | if (tp) | |||||
8304 | break; | |||||
8305 | ||||||
8306 | err = msg_errno(orq->orq_request); | |||||
8307 | ||||||
8308 | if (cc) | |||||
8309 | nta_compartment_decref(&cc); | |||||
8310 | ||||||
8311 | if (orq->orq_user_tport) | |||||
8312 | /* No retries */; | |||||
8313 | /* RFC3261, 18.1.1 */ | |||||
8314 | else if (err == EMSGSIZE90 && !orq->orq_try_tcp_instead) { | |||||
8315 | if (su_casematch(tpn->tpn_proto, "udp") || | |||||
8316 | su_casematch(tpn->tpn_proto, "*")) { | |||||
8317 | outgoing_try_tcp_instead(orq); | |||||
8318 | continue; | |||||
8319 | } | |||||
8320 | } | |||||
8321 | else if (err == ECONNREFUSED111 && orq->orq_try_tcp_instead) { | |||||
8322 | if (su_casematch(tpn->tpn_proto, "tcp") && msg_size(msg) <= 65535) { | |||||
8323 | outgoing_try_udp_instead(orq, 0); | |||||
8324 | continue; | |||||
8325 | } | |||||
8326 | } | |||||
8327 | else if (err == EPIPE32) { | |||||
8328 | /* Connection was closed */ | |||||
8329 | if (!once++) { | |||||
8330 | orq->orq_retries++; | |||||
8331 | continue; | |||||
8332 | } | |||||
8333 | } | |||||
8334 | ||||||
8335 | outgoing_tport_error(agent, orq, NULL((void*)0), orq->orq_request, err); | |||||
8336 | ||||||
8337 | return; | |||||
8338 | } | |||||
8339 | ||||||
8340 | agent->sa_stats->as_sent_msg++; | |||||
8341 | agent->sa_stats->as_sent_request++; | |||||
8342 | if (retransmit) | |||||
8343 | agent->sa_stats->as_retry_request++; | |||||
8344 | ||||||
8345 | SU_DEBUG_5(("nta: %ssent %s (%u) to " TPN_FORMAT "\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8348, "nta: %ssent %s (%u) to " "%s/%s:%s%s%s%s%s" "\n", retransmit ? "re" : "", orq->orq_method_name, orq->orq_cseq->cs_seq , (tpn)->tpn_proto, (tpn)->tpn_host, (tpn)->tpn_port , (tpn)->tpn_comp ? ";comp=" : "", (tpn)->tpn_comp ? (tpn )->tpn_comp : "", (tpn)->tpn_ident ? "/" : "", (tpn)-> tpn_ident ? (tpn)->tpn_ident : "")) : (void)0) | |||||
8346 | retransmit ? "re" : "",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8348, "nta: %ssent %s (%u) to " "%s/%s:%s%s%s%s%s" "\n", retransmit ? "re" : "", orq->orq_method_name, orq->orq_cseq->cs_seq , (tpn)->tpn_proto, (tpn)->tpn_host, (tpn)->tpn_port , (tpn)->tpn_comp ? ";comp=" : "", (tpn)->tpn_comp ? (tpn )->tpn_comp : "", (tpn)->tpn_ident ? "/" : "", (tpn)-> tpn_ident ? (tpn)->tpn_ident : "")) : (void)0) | |||||
8347 | orq->orq_method_name, orq->orq_cseq->cs_seq,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8348, "nta: %ssent %s (%u) to " "%s/%s:%s%s%s%s%s" "\n", retransmit ? "re" : "", orq->orq_method_name, orq->orq_cseq->cs_seq , (tpn)->tpn_proto, (tpn)->tpn_host, (tpn)->tpn_port , (tpn)->tpn_comp ? ";comp=" : "", (tpn)->tpn_comp ? (tpn )->tpn_comp : "", (tpn)->tpn_ident ? "/" : "", (tpn)-> tpn_ident ? (tpn)->tpn_ident : "")) : (void)0) | |||||
8348 | TPN_ARGS(tpn)))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8348, "nta: %ssent %s (%u) to " "%s/%s:%s%s%s%s%s" "\n", retransmit ? "re" : "", orq->orq_method_name, orq->orq_cseq->cs_seq , (tpn)->tpn_proto, (tpn)->tpn_host, (tpn)->tpn_port , (tpn)->tpn_comp ? ";comp=" : "", (tpn)->tpn_comp ? (tpn )->tpn_comp : "", (tpn)->tpn_ident ? "/" : "", (tpn)-> tpn_ident ? (tpn)->tpn_ident : "")) : (void)0); | |||||
8349 | ||||||
8350 | if (cc) { | |||||
8351 | if (orq->orq_cc) | |||||
8352 | nta_compartment_decref(&orq->orq_cc); | |||||
8353 | } | |||||
8354 | ||||||
8355 | if (orq->orq_pending) { | |||||
8356 | assert(orq->orq_tport)((void) sizeof ((orq->orq_tport) ? 1 : 0), __extension__ ( { if (orq->orq_tport) ; else __assert_fail ("orq->orq_tport" , "nta.c", 8356, __extension__ __PRETTY_FUNCTION__); })); | |||||
8357 | tport_release(orq->orq_tport, orq->orq_pending, | |||||
8358 | orq->orq_request, NULL((void*)0), orq, 0); | |||||
8359 | orq->orq_pending = 0; | |||||
8360 | } | |||||
8361 | ||||||
8362 | if (orq->orq_stateless) { | |||||
8363 | outgoing_reply(orq, 202, NULL((void*)0), 202); | |||||
8364 | return; | |||||
8365 | } | |||||
8366 | ||||||
8367 | if (orq->orq_method != sip_method_ack) { | |||||
8368 | orq->orq_pending = tport_pend(tp, orq->orq_request, | |||||
8369 | outgoing_tport_error, orq); | |||||
8370 | if (orq->orq_pending < 0) | |||||
8371 | orq->orq_pending = 0; | |||||
8372 | } | |||||
8373 | ||||||
8374 | if (tp != orq->orq_tport) { | |||||
8375 | tport_decref(&orq->orq_tport); | |||||
8376 | orq->orq_tport = tport_ref(tp); | |||||
8377 | } | |||||
8378 | ||||||
8379 | orq->orq_reliable = tport_is_reliable(tp); | |||||
8380 | ||||||
8381 | if (retransmit) | |||||
8382 | return; | |||||
8383 | ||||||
8384 | outgoing_trying(orq); /* Timer B / F */ | |||||
8385 | ||||||
8386 | if (orq->orq_method == sip_method_ack) | |||||
8387 | ; | |||||
8388 | else if (!orq->orq_reliable) { | |||||
8389 | /* race condition on initial t1 timer timeout, set minimum initial timeout to 1000ms */ | |||||
8390 | unsigned t1_timer = agent->sa_t1; | |||||
8391 | if (t1_timer < 1000) t1_timer = 1000; | |||||
8392 | outgoing_set_timer(orq, t1_timer); /* Timer A/E */ | |||||
8393 | } else if (orq->orq_try_tcp_instead && !tport_is_connected(tp)) { | |||||
8394 | outgoing_set_timer(orq, agent->sa_t4); /* Timer N3 */ | |||||
8395 | } else if (su_casenmatch(orq->orq_tpn->tpn_proto, "tls", 3) && !tport_is_connected(tp)) { | |||||
8396 | unsigned tls_reconect_interval = (orq->orq_call_tls_connect_timeout_is_set) ? | |||||
8397 | orq->orq_call_tls_connect_timeout : agent->sa_tls_orq_connect_timeout; | |||||
8398 | if (tls_reconect_interval) { | |||||
8399 | if (tls_reconect_interval < 1000) tls_reconect_interval = 1000; | |||||
8400 | outgoing_set_timer(orq, tls_reconect_interval); /* Timer N3 set to (min 1000 ms if set) */ | |||||
8401 | } | |||||
8402 | } | |||||
8403 | } | |||||
8404 | ||||||
8405 | static void | |||||
8406 | outgoing_try_tcp_instead(nta_outgoing_t *orq) | |||||
8407 | { | |||||
8408 | tport_t *tp; | |||||
8409 | tp_name_t tpn[1]; | |||||
8410 | ||||||
8411 | assert(orq->orq_pending == 0)((void) sizeof ((orq->orq_pending == 0) ? 1 : 0), __extension__ ({ if (orq->orq_pending == 0) ; else __assert_fail ("orq->orq_pending == 0" , "nta.c", 8411, __extension__ __PRETTY_FUNCTION__); })); | |||||
8412 | ||||||
8413 | *tpn = *orq->orq_tpn; | |||||
8414 | tpn->tpn_proto = "tcp"; | |||||
8415 | orq->orq_try_tcp_instead = 1; | |||||
8416 | ||||||
8417 | tp = tport_by_name(orq->orq_agent->sa_tports, tpn); | |||||
8418 | if (tp && tp != orq->orq_tport) { | |||||
8419 | sip_t *sip = sip_object(orq->orq_request); | |||||
8420 | sip_fragment_clear(sip->sip_via->v_common)((sip->sip_via->v_common)->h_data = ((void*)0), (sip ->sip_via->v_common)->h_len = 0); | |||||
8421 | sip->sip_via->v_protocol = sip_transport_tcp; | |||||
8422 | ||||||
8423 | SU_DEBUG_5(("nta: %s (%u) too large for UDP, trying TCP\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8424, "nta: %s (%u) too large for UDP, trying TCP\n", orq-> orq_method_name, orq->orq_cseq->cs_seq)) : (void)0) | |||||
8424 | orq->orq_method_name, orq->orq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8424, "nta: %s (%u) too large for UDP, trying TCP\n", orq-> orq_method_name, orq->orq_cseq->cs_seq)) : (void)0); | |||||
8425 | ||||||
8426 | orq->orq_tpn->tpn_proto = "tcp"; | |||||
8427 | tport_decref(&orq->orq_tport); | |||||
8428 | orq->orq_tport = tport_ref(tp); | |||||
8429 | ||||||
8430 | return; | |||||
8431 | } | |||||
8432 | ||||||
8433 | /* No TCP - try again with UDP without SIP MTU limit */ | |||||
8434 | tpn->tpn_proto = "udp"; | |||||
8435 | orq->orq_try_udp_instead = 1; | |||||
8436 | ||||||
8437 | tp = tport_by_name(orq->orq_agent->sa_tports, tpn); | |||||
8438 | if (tp && tp != orq->orq_tport) { | |||||
8439 | SU_DEBUG_5(("nta: %s (%u) exceed normal UDP size limit\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8440, "nta: %s (%u) exceed normal UDP size limit\n", orq-> orq_method_name, orq->orq_cseq->cs_seq)) : (void)0) | |||||
8440 | orq->orq_method_name, orq->orq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8440, "nta: %s (%u) exceed normal UDP size limit\n", orq-> orq_method_name, orq->orq_cseq->cs_seq)) : (void)0); | |||||
8441 | ||||||
8442 | tport_decref(&orq->orq_tport); | |||||
8443 | orq->orq_tport = tport_ref(tp); | |||||
8444 | } | |||||
8445 | } | |||||
8446 | ||||||
8447 | static void | |||||
8448 | outgoing_try_udp_instead(nta_outgoing_t *orq, int timeout) | |||||
8449 | { | |||||
8450 | tport_t *tp; | |||||
8451 | tp_name_t tpn[1]; | |||||
8452 | ||||||
8453 | if (orq->orq_pending) { | |||||
8454 | tport_release(orq->orq_tport, orq->orq_pending, | |||||
8455 | orq->orq_request, NULL((void*)0), orq, 0); | |||||
8456 | orq->orq_pending = 0; | |||||
8457 | } | |||||
8458 | ||||||
8459 | *tpn = *orq->orq_tpn; | |||||
8460 | tpn->tpn_proto = "udp"; | |||||
8461 | orq->orq_try_udp_instead = 1; | |||||
8462 | ||||||
8463 | tp = tport_by_name(orq->orq_agent->sa_tports, tpn); | |||||
8464 | if (tp && tp != orq->orq_tport) { | |||||
8465 | sip_t *sip = sip_object(orq->orq_request); | |||||
8466 | ||||||
8467 | sip_fragment_clear(sip->sip_via->v_common)((sip->sip_via->v_common)->h_data = ((void*)0), (sip ->sip_via->v_common)->h_len = 0); | |||||
8468 | sip->sip_via->v_protocol = sip_transport_udp; | |||||
8469 | ||||||
8470 | SU_DEBUG_5(("nta: %s (%u) TCP %s, trying UDP\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8472, "nta: %s (%u) TCP %s, trying UDP\n", orq->orq_method_name , orq->orq_cseq->cs_seq, timeout ? "times out" : "refused" )) : (void)0) | |||||
8471 | orq->orq_method_name, orq->orq_cseq->cs_seq,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8472, "nta: %s (%u) TCP %s, trying UDP\n", orq->orq_method_name , orq->orq_cseq->cs_seq, timeout ? "times out" : "refused" )) : (void)0) | |||||
8472 | timeout ? "times out" : "refused"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8472, "nta: %s (%u) TCP %s, trying UDP\n", orq->orq_method_name , orq->orq_cseq->cs_seq, timeout ? "times out" : "refused" )) : (void)0); | |||||
8473 | ||||||
8474 | orq->orq_tpn->tpn_proto = "udp"; | |||||
8475 | tport_decref(&orq->orq_tport); | |||||
8476 | orq->orq_tport = tport_ref(tp); | |||||
8477 | } | |||||
8478 | } | |||||
8479 | ||||||
8480 | ||||||
8481 | /** @internal Report transport errors. */ | |||||
8482 | void | |||||
8483 | outgoing_tport_error(nta_agent_t *agent, nta_outgoing_t *orq, | |||||
8484 | tport_t *tp, msg_t *msg, int error) | |||||
8485 | { | |||||
8486 | tp_name_t const *tpn = tp ? tport_name(tp) : orq->orq_tpn; | |||||
8487 | ||||||
8488 | if (orq->orq_pending) { | |||||
8489 | assert(orq->orq_tport)((void) sizeof ((orq->orq_tport) ? 1 : 0), __extension__ ( { if (orq->orq_tport) ; else __assert_fail ("orq->orq_tport" , "nta.c", 8489, __extension__ __PRETTY_FUNCTION__); })); | |||||
8490 | tport_release(orq->orq_tport, orq->orq_pending, orq->orq_request, | |||||
8491 | NULL((void*)0), orq, 0); | |||||
8492 | orq->orq_pending = 0; | |||||
8493 | } | |||||
8494 | ||||||
8495 | if (error == EPIPE32 && orq->orq_retries++ == 0) { | |||||
8496 | /* XXX - we should retry only if the transport is not newly created */ | |||||
8497 | outgoing_print_tport_error(orq, 5, "retrying once after ", | |||||
8498 | tpn, msg, error); | |||||
8499 | outgoing_send(orq, 1); | |||||
8500 | return; | |||||
8501 | } | |||||
8502 | else if (error == ECONNREFUSED111 && orq->orq_try_tcp_instead) { | |||||
8503 | /* RFC3261, 18.1.1 */ | |||||
8504 | if (su_casematch(tpn->tpn_proto, "tcp") && msg_size(msg) <= 65535) { | |||||
8505 | outgoing_print_tport_error(orq, 5, "retrying with UDP after ", | |||||
8506 | tpn, msg, error); | |||||
8507 | outgoing_try_udp_instead(orq, 0); | |||||
8508 | outgoing_remove(orq); /* Reset state - this is no resend! */ | |||||
8509 | outgoing_send(orq, 0); /* Send */ | |||||
8510 | return; | |||||
8511 | } | |||||
8512 | } | |||||
8513 | else if (error == 0) { | |||||
8514 | /* | |||||
8515 | * Server closed connection. RFC3261: | |||||
8516 | * "there is no coupling between TCP connection state and SIP | |||||
8517 | * processing." | |||||
8518 | */ | |||||
8519 | return; | |||||
8520 | } | |||||
8521 | ||||||
8522 | if (outgoing_other_destinations(orq)) { | |||||
8523 | outgoing_print_tport_error(orq, 5, "trying alternative server after ", | |||||
8524 | tpn, msg, error); | |||||
8525 | outgoing_try_another(orq); | |||||
8526 | return; | |||||
8527 | } | |||||
8528 | ||||||
8529 | outgoing_print_tport_error(orq, 3, "", tpn, msg, error); | |||||
8530 | ||||||
8531 | outgoing_reply(orq, SIP_503_SERVICE_UNAVAILABLE503, sip_503_Service_unavailable, 0); | |||||
8532 | } | |||||
8533 | ||||||
8534 | static | |||||
8535 | void | |||||
8536 | outgoing_print_tport_error(nta_outgoing_t *orq, int level, char *todo, | |||||
8537 | tp_name_t const *tpn, msg_t *msg, int error) | |||||
8538 | { | |||||
8539 | su_sockaddr_t const *su = msg_addr(msg); | |||||
8540 | char addr[SU_ADDRSIZE(48)]; | |||||
8541 | ||||||
8542 | su_llog(nta_log, level,_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8548 , "nta: %s (%u): %s%s (%u) with %s/[%s]:%u\n", orq->orq_method_name , orq->orq_cseq->cs_seq, todo, su_strerror(error), error , tpn->tpn_proto, inet_ntop(su->su_sa.sa_family, ((su)-> su_sa.sa_family == 2 ? (void *)&(su)->su_sin.sin_addr : ((su)->su_sa.sa_family == 10 ? (void *)&(su)->su_sin6 .sin6_addr : (void *)&(su)->su_sa.sa_data)), addr, sizeof (addr)), htons(su->su_sin.sin_port)) | |||||
8543 | "nta: %s (%u): %s%s (%u) with %s/[%s]:%u\n",_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8548 , "nta: %s (%u): %s%s (%u) with %s/[%s]:%u\n", orq->orq_method_name , orq->orq_cseq->cs_seq, todo, su_strerror(error), error , tpn->tpn_proto, inet_ntop(su->su_sa.sa_family, ((su)-> su_sa.sa_family == 2 ? (void *)&(su)->su_sin.sin_addr : ((su)->su_sa.sa_family == 10 ? (void *)&(su)->su_sin6 .sin6_addr : (void *)&(su)->su_sa.sa_data)), addr, sizeof (addr)), htons(su->su_sin.sin_port)) | |||||
8544 | orq->orq_method_name, orq->orq_cseq->cs_seq,_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8548 , "nta: %s (%u): %s%s (%u) with %s/[%s]:%u\n", orq->orq_method_name , orq->orq_cseq->cs_seq, todo, su_strerror(error), error , tpn->tpn_proto, inet_ntop(su->su_sa.sa_family, ((su)-> su_sa.sa_family == 2 ? (void *)&(su)->su_sin.sin_addr : ((su)->su_sa.sa_family == 10 ? (void *)&(su)->su_sin6 .sin6_addr : (void *)&(su)->su_sa.sa_data)), addr, sizeof (addr)), htons(su->su_sin.sin_port)) | |||||
8545 | todo, su_strerror(error), error,_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8548 , "nta: %s (%u): %s%s (%u) with %s/[%s]:%u\n", orq->orq_method_name , orq->orq_cseq->cs_seq, todo, su_strerror(error), error , tpn->tpn_proto, inet_ntop(su->su_sa.sa_family, ((su)-> su_sa.sa_family == 2 ? (void *)&(su)->su_sin.sin_addr : ((su)->su_sa.sa_family == 10 ? (void *)&(su)->su_sin6 .sin6_addr : (void *)&(su)->su_sa.sa_data)), addr, sizeof (addr)), htons(su->su_sin.sin_port)) | |||||
8546 | tpn->tpn_proto,_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8548 , "nta: %s (%u): %s%s (%u) with %s/[%s]:%u\n", orq->orq_method_name , orq->orq_cseq->cs_seq, todo, su_strerror(error), error , tpn->tpn_proto, inet_ntop(su->su_sa.sa_family, ((su)-> su_sa.sa_family == 2 ? (void *)&(su)->su_sin.sin_addr : ((su)->su_sa.sa_family == 10 ? (void *)&(su)->su_sin6 .sin6_addr : (void *)&(su)->su_sa.sa_data)), addr, sizeof (addr)), htons(su->su_sin.sin_port)) | |||||
8547 | su_inet_ntop(su->su_family, SU_ADDR(su), addr, sizeof(addr)),_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8548 , "nta: %s (%u): %s%s (%u) with %s/[%s]:%u\n", orq->orq_method_name , orq->orq_cseq->cs_seq, todo, su_strerror(error), error , tpn->tpn_proto, inet_ntop(su->su_sa.sa_family, ((su)-> su_sa.sa_family == 2 ? (void *)&(su)->su_sin.sin_addr : ((su)->su_sa.sa_family == 10 ? (void *)&(su)->su_sin6 .sin6_addr : (void *)&(su)->su_sa.sa_data)), addr, sizeof (addr)), htons(su->su_sin.sin_port)) | |||||
8548 | htons(su->su_port))_su_llog(nta_log, level, "nta.c", (const char *)__func__, 8548 , "nta: %s (%u): %s%s (%u) with %s/[%s]:%u\n", orq->orq_method_name , orq->orq_cseq->cs_seq, todo, su_strerror(error), error , tpn->tpn_proto, inet_ntop(su->su_sa.sa_family, ((su)-> su_sa.sa_family == 2 ? (void *)&(su)->su_sin.sin_addr : ((su)->su_sa.sa_family == 10 ? (void *)&(su)->su_sin6 .sin6_addr : (void *)&(su)->su_sa.sa_data)), addr, sizeof (addr)), htons(su->su_sin.sin_port)); | |||||
8549 | } | |||||
8550 | ||||||
8551 | /**@internal | |||||
8552 | * Add features supported. | |||||
8553 | */ | |||||
8554 | static | |||||
8555 | int outgoing_features(nta_agent_t *agent, nta_outgoing_t *orq, | |||||
8556 | msg_t *msg, sip_t *sip, | |||||
8557 | tagi_t *tags) | |||||
8558 | { | |||||
8559 | char const *supported[8]; | |||||
8560 | int i; | |||||
8561 | ||||||
8562 | if (orq->orq_method != sip_method_invite) /* fast path for now */ | |||||
8563 | return 0; | |||||
8564 | ||||||
8565 | supported[i = 0] = NULL((void*)0); | |||||
8566 | ||||||
8567 | if (orq->orq_method == sip_method_invite) { | |||||
8568 | int require_100rel = sip_has_feature(sip->sip_require, "100rel"); | |||||
8569 | ||||||
8570 | if (require_100rel) { | |||||
8571 | orq->orq_must_100rel = 1; | |||||
8572 | orq->orq_100rel = 1; | |||||
8573 | } | |||||
8574 | else if (sip_has_feature(sip->sip_supported, "100rel")) { | |||||
8575 | orq->orq_100rel = 1; | |||||
8576 | } | |||||
8577 | else if (orq->orq_100rel) { | |||||
8578 | supported[i++] = "100rel"; | |||||
8579 | } | |||||
8580 | } | |||||
8581 | ||||||
8582 | if (i) { | |||||
8583 | supported[i] = NULL((void*)0); | |||||
8584 | ||||||
8585 | if (sip->sip_supported) { | |||||
8586 | su_home_t *home = msg_home(msg)((su_home_t*)(msg)); | |||||
8587 | return msg_list_append_items(home, sip->sip_supported, supported); | |||||
8588 | } | |||||
8589 | else { | |||||
8590 | sip_supported_t s[1]; | |||||
8591 | sip_supported_init(s); | |||||
8592 | s->k_items = supported; | |||||
8593 | return sip_add_dup(msg, sip, (sip_header_t *)s); | |||||
8594 | } | |||||
8595 | } | |||||
8596 | ||||||
8597 | return 0; | |||||
8598 | } | |||||
8599 | ||||||
8600 | ||||||
8601 | /**@internal | |||||
8602 | * Insert outgoing request to agent hash table | |||||
8603 | */ | |||||
8604 | static | |||||
8605 | void outgoing_insert(nta_agent_t *agent, nta_outgoing_t *orq) | |||||
8606 | { | |||||
8607 | if (outgoing_htable_is_full(agent->sa_outgoing)) | |||||
8608 | outgoing_htable_resize(agent->sa_home, agent->sa_outgoing, 0); | |||||
8609 | outgoing_htable_insert(agent->sa_outgoing, orq); | |||||
8610 | orq->orq_inserted = 1; | |||||
8611 | } | |||||
8612 | ||||||
8613 | /** @internal | |||||
8614 | * Initialize a queue for outgoing transactions. | |||||
8615 | */ | |||||
8616 | static void | |||||
8617 | outgoing_queue_init(outgoing_queue_t *queue, unsigned timeout) | |||||
8618 | { | |||||
8619 | memset(queue, 0, sizeof *queue); | |||||
8620 | queue->q_tail = &queue->q_head; | |||||
8621 | queue->q_timeout = timeout; | |||||
8622 | } | |||||
8623 | ||||||
8624 | /** Change the timeout value of a queue */ | |||||
8625 | static void | |||||
8626 | outgoing_queue_adjust(nta_agent_t *sa, | |||||
8627 | outgoing_queue_t *queue, | |||||
8628 | unsigned timeout) | |||||
8629 | { | |||||
8630 | nta_outgoing_t *orq; | |||||
8631 | uint32_t latest; | |||||
8632 | ||||||
8633 | if (timeout >= queue->q_timeout || !queue->q_head) { | |||||
8634 | queue->q_timeout = timeout; | |||||
8635 | return; | |||||
8636 | } | |||||
8637 | ||||||
8638 | latest = set_timeout(sa, queue->q_timeout = timeout); | |||||
8639 | ||||||
8640 | for (orq = queue->q_head; orq; orq = orq->orq_next) { | |||||
8641 | if (orq->orq_timeout == 0 || | |||||
8642 | (int32_t)(orq->orq_timeout - latest) > 0) | |||||
8643 | orq->orq_timeout = latest; | |||||
8644 | } | |||||
8645 | } | |||||
8646 | ||||||
8647 | /** @internal | |||||
8648 | * Test if an outgoing transaction is in a queue. | |||||
8649 | */ | |||||
8650 | su_inlinestatic inline int | |||||
8651 | outgoing_is_queued(nta_outgoing_t const *orq) | |||||
8652 | { | |||||
8653 | return orq && orq->orq_queue; | |||||
8654 | } | |||||
8655 | ||||||
8656 | /** @internal | |||||
8657 | * Insert an outgoing transaction into a queue. | |||||
8658 | * | |||||
8659 | * Insert a client transaction into a queue and set the corresponding | |||||
8660 | * timeout at the same time. | |||||
8661 | */ | |||||
8662 | static void | |||||
8663 | outgoing_queue(outgoing_queue_t *queue, | |||||
8664 | nta_outgoing_t *orq) | |||||
8665 | { | |||||
8666 | if (orq->orq_queue == queue) { | |||||
8667 | //assert(queue->q_timeout == 0); | |||||
8668 | return; | |||||
8669 | } | |||||
8670 | ||||||
8671 | assert(!orq->orq_forked)((void) sizeof ((!orq->orq_forked) ? 1 : 0), __extension__ ({ if (!orq->orq_forked) ; else __assert_fail ("!orq->orq_forked" , "nta.c", 8671, __extension__ __PRETTY_FUNCTION__); })); | |||||
8672 | ||||||
8673 | if (outgoing_is_queued(orq)) | |||||
8674 | outgoing_remove(orq); | |||||
8675 | ||||||
8676 | orq->orq_timeout = set_timeout(orq->orq_agent, queue->q_timeout); | |||||
8677 | ||||||
8678 | orq->orq_queue = queue; | |||||
8679 | orq->orq_prev = queue->q_tail; | |||||
8680 | *queue->q_tail = orq; | |||||
8681 | queue->q_tail = &orq->orq_next; | |||||
8682 | queue->q_length++; | |||||
8683 | } | |||||
8684 | ||||||
8685 | /** @internal | |||||
8686 | * Remove an outgoing transaction from a queue. | |||||
8687 | */ | |||||
8688 | su_inlinestatic inline | |||||
8689 | void outgoing_remove(nta_outgoing_t *orq) | |||||
8690 | { | |||||
8691 | assert(outgoing_is_queued(orq))((void) sizeof ((outgoing_is_queued(orq)) ? 1 : 0), __extension__ ({ if (outgoing_is_queued(orq)) ; else __assert_fail ("outgoing_is_queued(orq)" , "nta.c", 8691, __extension__ __PRETTY_FUNCTION__); })); | |||||
8692 | assert(orq->orq_queue->q_length > 0)((void) sizeof ((orq->orq_queue->q_length > 0) ? 1 : 0), __extension__ ({ if (orq->orq_queue->q_length > 0) ; else __assert_fail ("orq->orq_queue->q_length > 0" , "nta.c", 8692, __extension__ __PRETTY_FUNCTION__); })); | |||||
8693 | ||||||
8694 | if ((*orq->orq_prev = orq->orq_next)) | |||||
8695 | orq->orq_next->orq_prev = orq->orq_prev; | |||||
8696 | else | |||||
8697 | orq->orq_queue->q_tail = orq->orq_prev; | |||||
8698 | ||||||
8699 | orq->orq_queue->q_length--; | |||||
8700 | orq->orq_next = NULL((void*)0); | |||||
8701 | orq->orq_prev = NULL((void*)0); | |||||
8702 | orq->orq_queue = NULL((void*)0); | |||||
8703 | orq->orq_timeout = 0; | |||||
8704 | } | |||||
8705 | ||||||
8706 | /** Set retransmit timer (orq_retry). | |||||
8707 | * | |||||
8708 | * Set the retry timer (B/D) on the outgoing request (client transaction). | |||||
8709 | */ | |||||
8710 | su_inlinestatic inline | |||||
8711 | void outgoing_set_timer(nta_outgoing_t *orq, uint32_t interval) | |||||
8712 | { | |||||
8713 | nta_outgoing_t **rq; | |||||
8714 | ||||||
8715 | assert(orq)((void) sizeof ((orq) ? 1 : 0), __extension__ ({ if (orq) ; else __assert_fail ("orq", "nta.c", 8715, __extension__ __PRETTY_FUNCTION__ ); })); | |||||
8716 | ||||||
8717 | if (interval == 0) { | |||||
8718 | outgoing_reset_timer(orq); | |||||
8719 | return; | |||||
8720 | } | |||||
8721 | ||||||
8722 | if (orq->orq_rprev) { | |||||
8723 | /* Remove transaction from retry dequeue, re-insert it later. */ | |||||
8724 | if ((*orq->orq_rprev = orq->orq_rnext)) | |||||
8725 | orq->orq_rnext->orq_rprev = orq->orq_rprev; | |||||
8726 | if (orq->orq_agent->sa_out.re_t1 == &orq->orq_rnext) | |||||
8727 | orq->orq_agent->sa_out.re_t1 = orq->orq_rprev; | |||||
8728 | } | |||||
8729 | else { | |||||
8730 | orq->orq_agent->sa_out.re_length++; | |||||
8731 | } | |||||
8732 | ||||||
8733 | orq->orq_retry = set_timeout(orq->orq_agent, orq->orq_interval = interval); | |||||
8734 | ||||||
8735 | /* Shortcut into queue at SIP T1 */ | |||||
8736 | rq = orq->orq_agent->sa_out.re_t1; | |||||
8737 | ||||||
8738 | if (!(*rq) || (int32_t)((*rq)->orq_retry - orq->orq_retry) > 0) | |||||
8739 | rq = &orq->orq_agent->sa_out.re_list; | |||||
8740 | ||||||
8741 | while (*rq && (int32_t)((*rq)->orq_retry - orq->orq_retry) <= 0) | |||||
8742 | rq = &(*rq)->orq_rnext; | |||||
8743 | ||||||
8744 | if ((orq->orq_rnext = *rq)) | |||||
8745 | orq->orq_rnext->orq_rprev = &orq->orq_rnext; | |||||
8746 | *rq = orq; | |||||
8747 | orq->orq_rprev = rq; | |||||
8748 | ||||||
8749 | if (interval == orq->orq_agent->sa_t1) | |||||
8750 | orq->orq_agent->sa_out.re_t1 = rq; | |||||
8751 | } | |||||
8752 | ||||||
8753 | static | |||||
8754 | void outgoing_reset_timer(nta_outgoing_t *orq) | |||||
8755 | { | |||||
8756 | if (orq->orq_rprev) { | |||||
8757 | if ((*orq->orq_rprev = orq->orq_rnext)) | |||||
8758 | orq->orq_rnext->orq_rprev = orq->orq_rprev; | |||||
8759 | if (orq->orq_agent->sa_out.re_t1 == &orq->orq_rnext) | |||||
8760 | orq->orq_agent->sa_out.re_t1 = orq->orq_rprev; | |||||
8761 | orq->orq_agent->sa_out.re_length--; | |||||
8762 | } | |||||
8763 | ||||||
8764 | orq->orq_interval = 0, orq->orq_retry = 0; | |||||
8765 | orq->orq_rnext = NULL((void*)0), orq->orq_rprev = NULL((void*)0); | |||||
8766 | } | |||||
8767 | ||||||
8768 | /** @internal | |||||
8769 | * Free resources associated with the request. | |||||
8770 | */ | |||||
8771 | static | |||||
8772 | void outgoing_free(nta_outgoing_t *orq) | |||||
8773 | { | |||||
8774 | SU_DEBUG_9(("nta: outgoing_free(%p)\n", (void *)orq))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 8774, "nta: outgoing_free(%p)\n", (void *)orq)) : (void)0); | |||||
8775 | assert(orq->orq_forks == NULL && orq->orq_forking == NULL)((void) sizeof ((orq->orq_forks == ((void*)0) && orq ->orq_forking == ((void*)0)) ? 1 : 0), __extension__ ({ if (orq->orq_forks == ((void*)0) && orq->orq_forking == ((void*)0)) ; else __assert_fail ("orq->orq_forks == NULL && orq->orq_forking == NULL" , "nta.c", 8775, __extension__ __PRETTY_FUNCTION__); })); | |||||
8776 | outgoing_cut_off(orq); | |||||
8777 | outgoing_reclaim(orq); | |||||
8778 | } | |||||
8779 | ||||||
8780 | /** Remove outgoing request from hash tables */ | |||||
8781 | su_inlinestatic inline void | |||||
8782 | outgoing_cut_off(nta_outgoing_t *orq) | |||||
8783 | { | |||||
8784 | nta_agent_t *agent = orq->orq_agent; | |||||
8785 | ||||||
8786 | if (orq->orq_default) | |||||
8787 | agent->sa_default_outgoing = NULL((void*)0); | |||||
8788 | ||||||
8789 | if (orq->orq_inserted) | |||||
8790 | outgoing_htable_remove(agent->sa_outgoing, orq), orq->orq_inserted = 0; | |||||
8791 | ||||||
8792 | if (outgoing_is_queued(orq)) | |||||
8793 | outgoing_remove(orq); | |||||
8794 | ||||||
8795 | #if 0 | |||||
8796 | if (orq->orq_forked) | |||||
8797 | outgoing_remove_fork(orq); | |||||
8798 | #endif | |||||
8799 | ||||||
8800 | outgoing_reset_timer(orq); | |||||
8801 | ||||||
8802 | if (orq->orq_pending) { | |||||
8803 | tport_release(orq->orq_tport, orq->orq_pending, | |||||
8804 | orq->orq_request, NULL((void*)0), orq, 0); | |||||
8805 | } | |||||
8806 | orq->orq_pending = 0; | |||||
8807 | ||||||
8808 | if (orq->orq_cc) | |||||
8809 | nta_compartment_decref(&orq->orq_cc); | |||||
8810 | ||||||
8811 | if (orq->orq_tport) | |||||
8812 | tport_decref(&orq->orq_tport); | |||||
8813 | } | |||||
8814 | ||||||
8815 | /** Reclaim outgoing request */ | |||||
8816 | su_inlinestatic inline | |||||
8817 | void outgoing_reclaim(nta_outgoing_t *orq) | |||||
8818 | { | |||||
8819 | if (orq->orq_status2b) | |||||
8820 | *orq->orq_status2b = -1; | |||||
8821 | ||||||
8822 | if (orq->orq_request) | |||||
8823 | msg_destroy(orq->orq_request), orq->orq_request = NULL((void*)0); | |||||
8824 | if (orq->orq_response) | |||||
8825 | msg_destroy(orq->orq_response), orq->orq_response = NULL((void*)0); | |||||
8826 | #if HAVE_SOFIA_SRESOLV1 | |||||
8827 | if (orq->orq_resolver) | |||||
8828 | outgoing_destroy_resolver(orq); | |||||
8829 | #endif | |||||
8830 | su_free(orq->orq_agent->sa_home, orq); | |||||
8831 | } | |||||
8832 | ||||||
8833 | /** Queue request to be freed */ | |||||
8834 | su_inlinestatic inline | |||||
8835 | void outgoing_free_queue(outgoing_queue_t *q, nta_outgoing_t *orq) | |||||
8836 | { | |||||
8837 | outgoing_cut_off(orq); | |||||
8838 | outgoing_queue(q, orq); | |||||
8839 | } | |||||
8840 | ||||||
8841 | /** Reclaim memory used by queue of requests */ | |||||
8842 | static | |||||
8843 | void outgoing_reclaim_queued(su_root_magic_t *rm, | |||||
8844 | su_msg_r msg, | |||||
8845 | union sm_arg_u *u) | |||||
8846 | { | |||||
8847 | outgoing_queue_t *q = u->a_outgoing_queue; | |||||
8848 | nta_outgoing_t *orq, *orq_next; | |||||
8849 | ||||||
8850 | SU_DEBUG_9(("outgoing_reclaim_all(%p, %p, %p)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 8851, "outgoing_reclaim_all(%p, %p, %p)\n", (void *)rm, (void *)msg, (void *)u)) : (void)0) | |||||
8851 | (void *)rm, (void *)msg, (void *)u))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 9 ? (_su_llog(nta_log, 9, "nta.c", (const char *)__func__ , 8851, "outgoing_reclaim_all(%p, %p, %p)\n", (void *)rm, (void *)msg, (void *)u)) : (void)0); | |||||
8852 | ||||||
8853 | for (orq = q->q_head; orq; orq = orq_next) { | |||||
8854 | orq_next = orq->orq_next; | |||||
8855 | outgoing_reclaim(orq); | |||||
8856 | } | |||||
8857 | } | |||||
8858 | ||||||
8859 | /** @internal Default callback for request */ | |||||
8860 | int outgoing_default_cb(nta_outgoing_magic_t *magic, | |||||
8861 | nta_outgoing_t *orq, | |||||
8862 | sip_t const *sip) | |||||
8863 | { | |||||
8864 | if (sip == NULL((void*)0) || sip->sip_status->st_status >= 200) | |||||
8865 | outgoing_destroy(orq); | |||||
8866 | return 0; | |||||
8867 | } | |||||
8868 | ||||||
8869 | /** @internal Destroy an outgoing transaction */ | |||||
8870 | void outgoing_destroy(nta_outgoing_t *orq) | |||||
8871 | { | |||||
8872 | if (orq->orq_terminated || orq->orq_default) { | |||||
8873 | if (!orq->orq_forking && !orq->orq_forks) { | |||||
8874 | outgoing_free(orq); | |||||
8875 | return; | |||||
8876 | } | |||||
8877 | } | |||||
8878 | /* Application is expected to handle 200 OK statelessly | |||||
8879 | => kill transaction immediately */ | |||||
8880 | else if (orq->orq_method == sip_method_invite && !orq->orq_completed | |||||
8881 | /* (unless transaction has been canceled) */ | |||||
8882 | && !orq->orq_canceled | |||||
8883 | /* or it has been forked */ | |||||
8884 | && !orq->orq_forking && !orq->orq_forks) { | |||||
8885 | orq->orq_destroyed = 1; | |||||
8886 | outgoing_terminate(orq); | |||||
8887 | return; | |||||
8888 | } | |||||
8889 | ||||||
8890 | orq->orq_destroyed = 1; | |||||
8891 | orq->orq_callback = outgoing_default_cb; | |||||
8892 | orq->orq_magic = NULL((void*)0); | |||||
8893 | } | |||||
8894 | ||||||
8895 | /** @internal Outgoing transaction timer routine. | |||||
8896 | * | |||||
8897 | */ | |||||
8898 | static void | |||||
8899 | _nta_outgoing_timer(nta_agent_t *sa) | |||||
8900 | { | |||||
8901 | uint32_t now = su_time_ms(su_now()); | |||||
8902 | nta_outgoing_t *orq; | |||||
8903 | outgoing_queue_t rq[1]; | |||||
8904 | size_t retransmitted = 0, terminated = 0, timeout = 0, destroyed; | |||||
8905 | size_t total = sa->sa_outgoing->oht_used; | |||||
8906 | size_t trying = sa->sa_out.re_length; | |||||
8907 | size_t pending = sa->sa_out.trying->q_length + | |||||
8908 | sa->sa_out.inv_calling->q_length; | |||||
8909 | size_t completed = sa->sa_out.completed->q_length + | |||||
8910 | sa->sa_out.inv_completed->q_length; | |||||
8911 | ||||||
8912 | outgoing_queue_init(sa->sa_out.free = rq, 0); | |||||
8913 | ||||||
8914 | while ((orq = sa->sa_out.re_list)) { | |||||
8915 | ||||||
8916 | now = su_time_ms(su_now()); | |||||
8917 | ||||||
8918 | if ((int32_t)(orq->orq_retry - now) > 0) | |||||
8919 | break; | |||||
8920 | if (retransmitted >= timer_max_retransmit) | |||||
8921 | break; | |||||
8922 | ||||||
8923 | if (orq->orq_reliable) { | |||||
8924 | outgoing_reset_timer(orq); | |||||
8925 | ||||||
8926 | if (!tport_is_connected(orq->orq_tport)) { | |||||
8927 | uint32_t tls_connect_timeout = (orq->orq_call_tls_connect_timeout_is_set) ? | |||||
8928 | orq->orq_call_tls_connect_timeout : sa->sa_tls_orq_connect_timeout; | |||||
8929 | if (su_casenmatch(orq->orq_tpn->tpn_proto, "tls", 3) && tls_connect_timeout) { | |||||
8930 | outgoing_remove(orq); /* Reset state - this is no resend! */ | |||||
8931 | if (outgoing_other_destinations(orq)) { | |||||
8932 | SU_DEBUG_5(("nta: timer %s fired (proto: %s), %s %s (%u)\n", "N3",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8934, "nta: timer %s fired (proto: %s), %s %s (%u)\n", "N3" , orq->orq_tpn->tpn_proto, "trying alternative server for" , orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void )0) | |||||
8933 | orq->orq_tpn->tpn_proto, "trying alternative server for",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8934, "nta: timer %s fired (proto: %s), %s %s (%u)\n", "N3" , orq->orq_tpn->tpn_proto, "trying alternative server for" , orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void )0) | |||||
8934 | orq->orq_method_name, orq->orq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8934, "nta: timer %s fired (proto: %s), %s %s (%u)\n", "N3" , orq->orq_tpn->tpn_proto, "trying alternative server for" , orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void )0); | |||||
8935 | outgoing_try_another(orq); | |||||
8936 | } else { | |||||
8937 | SU_DEBUG_5(("nta: timer %s fired (proto: %s), %s %s (%u)\n", "N3",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8939, "nta: timer %s fired (proto: %s), %s %s (%u)\n", "N3" , orq->orq_tpn->tpn_proto, "retrying for", orq->orq_method_name , orq->orq_cseq->cs_seq)) : (void)0) | |||||
8938 | orq->orq_tpn->tpn_proto, "retrying for",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8939, "nta: timer %s fired (proto: %s), %s %s (%u)\n", "N3" , orq->orq_tpn->tpn_proto, "retrying for", orq->orq_method_name , orq->orq_cseq->cs_seq)) : (void)0) | |||||
8939 | orq->orq_method_name, orq->orq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8939, "nta: timer %s fired (proto: %s), %s %s (%u)\n", "N3" , orq->orq_tpn->tpn_proto, "retrying for", orq->orq_method_name , orq->orq_cseq->cs_seq)) : (void)0); | |||||
8940 | outgoing_send(orq, 0); /* Send */ | |||||
8941 | } | |||||
8942 | } else { | |||||
8943 | /* | |||||
8944 | * Timer N3: try to use UDP if trying to send via TCP | |||||
8945 | * but no connection is established within SIP T4 | |||||
8946 | */ | |||||
8947 | SU_DEBUG_5(("nta: timer %s fired, %s %s (%u)\n", "N3",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8949, "nta: timer %s fired, %s %s (%u)\n", "N3", "try UDP instead for" , orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void )0) | |||||
8948 | "try UDP instead for",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8949, "nta: timer %s fired, %s %s (%u)\n", "N3", "try UDP instead for" , orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void )0) | |||||
8949 | orq->orq_method_name, orq->orq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8949, "nta: timer %s fired, %s %s (%u)\n", "N3", "try UDP instead for" , orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void )0); | |||||
8950 | outgoing_try_udp_instead(orq, 1); | |||||
8951 | outgoing_remove(orq); /* Reset state - this is no resend! */ | |||||
8952 | outgoing_send(orq, 0); /* Send */ | |||||
8953 | } | |||||
8954 | } | |||||
8955 | continue; | |||||
8956 | } | |||||
8957 | ||||||
8958 | assert(!orq->orq_reliable && orq->orq_interval != 0)((void) sizeof ((!orq->orq_reliable && orq->orq_interval != 0) ? 1 : 0), __extension__ ({ if (!orq->orq_reliable && orq->orq_interval != 0) ; else __assert_fail ("!orq->orq_reliable && orq->orq_interval != 0" , "nta.c", 8958, __extension__ __PRETTY_FUNCTION__); })); | |||||
8959 | ||||||
8960 | SU_DEBUG_5(("nta: timer %s fired, %s %s (%u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8962, "nta: timer %s fired, %s %s (%u)\n", orq->orq_method == sip_method_invite ? "A" : "E", "retransmit", orq->orq_method_name , orq->orq_cseq->cs_seq)) : (void)0) | |||||
8961 | orq->orq_method == sip_method_invite ? "A" : "E",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8962, "nta: timer %s fired, %s %s (%u)\n", orq->orq_method == sip_method_invite ? "A" : "E", "retransmit", orq->orq_method_name , orq->orq_cseq->cs_seq)) : (void)0) | |||||
8962 | "retransmit", orq->orq_method_name, orq->orq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8962, "nta: timer %s fired, %s %s (%u)\n", orq->orq_method == sip_method_invite ? "A" : "E", "retransmit", orq->orq_method_name , orq->orq_cseq->cs_seq)) : (void)0); | |||||
8963 | ||||||
8964 | outgoing_retransmit(orq); | |||||
8965 | ||||||
8966 | if (orq->orq_method == sip_method_invite || | |||||
8967 | 2U * orq->orq_interval < sa->sa_t2) | |||||
8968 | outgoing_set_timer(orq, 2U * orq->orq_interval); | |||||
8969 | else | |||||
8970 | outgoing_set_timer(orq, sa->sa_t2); | |||||
8971 | ||||||
8972 | if (++retransmitted % 5 == 0) | |||||
8973 | su_root_yield(sa->sa_root); /* Handle received packets */ | |||||
8974 | } | |||||
8975 | ||||||
8976 | terminated | |||||
8977 | = outgoing_timer_dk(sa->sa_out.inv_completed, "D", now) | |||||
8978 | + outgoing_timer_dk(sa->sa_out.completed, "K", now); | |||||
8979 | ||||||
8980 | timeout | |||||
8981 | = outgoing_timer_bf(sa->sa_out.inv_calling, "B", now) | |||||
8982 | + outgoing_timer_c(sa->sa_out.inv_proceeding, "C", now) | |||||
8983 | + outgoing_timer_bf(sa->sa_out.trying, "F", now); | |||||
8984 | ||||||
8985 | destroyed = outgoing_mass_destroy(sa, rq); | |||||
8986 | ||||||
8987 | sa->sa_out.free = NULL((void*)0); | |||||
8988 | ||||||
8989 | if (retransmitted || timeout || terminated || destroyed) { | |||||
8990 | SU_DEBUG_5(("nta_outgoing_timer: "(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8998, "nta_outgoing_timer: " "%zu""/""%zu"" resent, " "%zu" "/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n" , retransmitted, trying, timeout, pending, terminated, completed , destroyed, total)) : (void)0) | |||||
8991 | MOD_ZU"/"MOD_ZU" resent, "(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8998, "nta_outgoing_timer: " "%zu""/""%zu"" resent, " "%zu" "/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n" , retransmitted, trying, timeout, pending, terminated, completed , destroyed, total)) : (void)0) | |||||
8992 | MOD_ZU"/"MOD_ZU" tout, "(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8998, "nta_outgoing_timer: " "%zu""/""%zu"" resent, " "%zu" "/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n" , retransmitted, trying, timeout, pending, terminated, completed , destroyed, total)) : (void)0) | |||||
8993 | MOD_ZU"/"MOD_ZU" term, "(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8998, "nta_outgoing_timer: " "%zu""/""%zu"" resent, " "%zu" "/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n" , retransmitted, trying, timeout, pending, terminated, completed , destroyed, total)) : (void)0) | |||||
8994 | MOD_ZU"/"MOD_ZU" free\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8998, "nta_outgoing_timer: " "%zu""/""%zu"" resent, " "%zu" "/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n" , retransmitted, trying, timeout, pending, terminated, completed , destroyed, total)) : (void)0) | |||||
8995 | retransmitted, trying,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8998, "nta_outgoing_timer: " "%zu""/""%zu"" resent, " "%zu" "/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n" , retransmitted, trying, timeout, pending, terminated, completed , destroyed, total)) : (void)0) | |||||
8996 | timeout, pending,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8998, "nta_outgoing_timer: " "%zu""/""%zu"" resent, " "%zu" "/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n" , retransmitted, trying, timeout, pending, terminated, completed , destroyed, total)) : (void)0) | |||||
8997 | terminated, completed,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8998, "nta_outgoing_timer: " "%zu""/""%zu"" resent, " "%zu" "/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n" , retransmitted, trying, timeout, pending, terminated, completed , destroyed, total)) : (void)0) | |||||
8998 | destroyed, total))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 8998, "nta_outgoing_timer: " "%zu""/""%zu"" resent, " "%zu" "/""%zu"" tout, " "%zu""/""%zu"" term, " "%zu""/""%zu"" free\n" , retransmitted, trying, timeout, pending, terminated, completed , destroyed, total)) : (void)0); | |||||
8999 | } | |||||
9000 | } | |||||
9001 | ||||||
9002 | /** @internal Retransmit the outgoing request. */ | |||||
9003 | void outgoing_retransmit(nta_outgoing_t *orq) | |||||
9004 | { | |||||
9005 | if (orq->orq_prepared && !orq->orq_delayed) { | |||||
9006 | orq->orq_retries++; | |||||
9007 | ||||||
9008 | if (orq->orq_retries >= 4 && orq->orq_cc) { | |||||
9009 | orq->orq_tpn->tpn_comp = NULL((void*)0); | |||||
9010 | if (orq->orq_retries == 4) { | |||||
9011 | agent_close_compressor(orq->orq_agent, orq->orq_cc); | |||||
9012 | nta_compartment_decref(&orq->orq_cc); | |||||
9013 | } | |||||
9014 | } | |||||
9015 | ||||||
9016 | outgoing_send(orq, 1); | |||||
9017 | } | |||||
9018 | } | |||||
9019 | ||||||
9020 | /** Trying a client transaction. */ | |||||
9021 | static | |||||
9022 | void outgoing_trying(nta_outgoing_t *orq) | |||||
9023 | { | |||||
9024 | if (orq->orq_forked) | |||||
9025 | ; | |||||
9026 | else if (orq->orq_method == sip_method_invite) { | |||||
9027 | if (!orq->orq_completed) { | |||||
9028 | outgoing_queue(orq->orq_agent->sa_out.inv_calling, orq); | |||||
9029 | } else { | |||||
9030 | SU_DEBUG_5(("nta(%p): completed request can not be put into inv_calling queue (%u)\n", (void *)orq, orq->orq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 9030, "nta(%p): completed request can not be put into inv_calling queue (%u)\n" , (void *)orq, orq->orq_cseq->cs_seq)) : (void)0); | |||||
9031 | if (orq->orq_queue != orq->orq_agent->sa_out.inv_completed) { | |||||
9032 | /* Put back into inv_completed if it's not there by any reason */ | |||||
9033 | outgoing_queue(orq->orq_agent->sa_out.inv_completed, orq); /* Timer D */ | |||||
9034 | } | |||||
9035 | } | |||||
9036 | } | |||||
9037 | else | |||||
9038 | outgoing_queue(orq->orq_agent->sa_out.trying, orq); | |||||
9039 | } | |||||
9040 | ||||||
9041 | /** Handle timers B and F */ | |||||
9042 | static | |||||
9043 | size_t outgoing_timer_bf(outgoing_queue_t *q, | |||||
9044 | char const *timer, | |||||
9045 | uint32_t now) | |||||
9046 | { | |||||
9047 | nta_outgoing_t *orq; | |||||
9048 | size_t timeout = 0; | |||||
9049 | ||||||
9050 | while ((orq = q->q_head)) { | |||||
9051 | if ((int32_t)(orq->orq_timeout - now) > 0 || | |||||
9052 | timeout >= timer_max_timeout) | |||||
9053 | break; | |||||
9054 | ||||||
9055 | timeout++; | |||||
9056 | ||||||
9057 | SU_DEBUG_5(("nta: timer %s fired, %s %s (%u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 9060, "nta: timer %s fired, %s %s (%u)\n", timer, orq->orq_method != sip_method_ack ? "timeout" : "terminating", orq->orq_method_name , orq->orq_cseq->cs_seq)) : (void)0) | |||||
9058 | timer,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 9060, "nta: timer %s fired, %s %s (%u)\n", timer, orq->orq_method != sip_method_ack ? "timeout" : "terminating", orq->orq_method_name , orq->orq_cseq->cs_seq)) : (void)0) | |||||
9059 | orq->orq_method != sip_method_ack ? "timeout" : "terminating",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 9060, "nta: timer %s fired, %s %s (%u)\n", timer, orq->orq_method != sip_method_ack ? "timeout" : "terminating", orq->orq_method_name , orq->orq_cseq->cs_seq)) : (void)0) | |||||
9060 | orq->orq_method_name, orq->orq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 9060, "nta: timer %s fired, %s %s (%u)\n", timer, orq->orq_method != sip_method_ack ? "timeout" : "terminating", orq->orq_method_name , orq->orq_cseq->cs_seq)) : (void)0); | |||||
9061 | ||||||
9062 | if (orq->orq_method != sip_method_ack) | |||||
9063 | outgoing_timeout(orq, now); | |||||
9064 | else | |||||
9065 | outgoing_terminate(orq); | |||||
9066 | ||||||
9067 | assert(q->q_head != orq || (int32_t)(orq->orq_timeout - now) > 0)((void) sizeof ((q->q_head != orq || (int32_t)(orq->orq_timeout - now) > 0) ? 1 : 0), __extension__ ({ if (q->q_head != orq || (int32_t)(orq->orq_timeout - now) > 0) ; else __assert_fail ("q->q_head != orq || (int32_t)(orq->orq_timeout - now) > 0" , "nta.c", 9067, __extension__ __PRETTY_FUNCTION__); })); | |||||
9068 | } | |||||
9069 | ||||||
9070 | return timeout; | |||||
9071 | } | |||||
9072 | ||||||
9073 | /** Handle timer C */ | |||||
9074 | static | |||||
9075 | size_t outgoing_timer_c(outgoing_queue_t *q, | |||||
9076 | char const *timer, | |||||
9077 | uint32_t now) | |||||
9078 | { | |||||
9079 | nta_outgoing_t *orq; | |||||
9080 | size_t timeout = 0; | |||||
9081 | ||||||
9082 | if (q->q_timeout == 0) | |||||
9083 | return 0; | |||||
9084 | ||||||
9085 | while ((orq = q->q_head)) { | |||||
9086 | if ((int32_t)(orq->orq_timeout - now) > 0 || timeout >= timer_max_timeout) | |||||
9087 | break; | |||||
9088 | ||||||
9089 | timeout++; | |||||
9090 | ||||||
9091 | SU_DEBUG_5(("nta: timer %s fired, %s %s (%u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 9093, "nta: timer %s fired, %s %s (%u)\n", timer, "CANCEL and timeout" , orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void )0) | |||||
9092 | timer, "CANCEL and timeout",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 9093, "nta: timer %s fired, %s %s (%u)\n", timer, "CANCEL and timeout" , orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void )0) | |||||
9093 | orq->orq_method_name, orq->orq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 9093, "nta: timer %s fired, %s %s (%u)\n", timer, "CANCEL and timeout" , orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void )0); | |||||
9094 | /* | |||||
9095 | * If the client transaction has received a provisional response, the | |||||
9096 | * proxy MUST generate a CANCEL request matching that transaction. | |||||
9097 | */ | |||||
9098 | nta_outgoing_tcancel(orq, NULL((void*)0), NULL((void*)0), TAG_NULL()(tag_type_t)0, (tag_value_t)0); | |||||
9099 | } | |||||
9100 | ||||||
9101 | return timeout; | |||||
9102 | } | |||||
9103 | ||||||
9104 | /** @internal Signal transaction timeout to the application. */ | |||||
9105 | void outgoing_timeout(nta_outgoing_t *orq, uint32_t now) | |||||
9106 | { | |||||
9107 | nta_outgoing_t *cancel = NULL((void*)0); | |||||
9108 | ||||||
9109 | if (orq->orq_status || orq->orq_canceled) | |||||
9110 | ; | |||||
9111 | else if (outgoing_other_destinations(orq)) { | |||||
9112 | SU_DEBUG_5(("%s(%p): %s\n", "nta", (void *)orq,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 9113, "%s(%p): %s\n", "nta", (void *)orq, "try next after timeout" )) : (void)0) | |||||
9113 | "try next after timeout"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 9113, "%s(%p): %s\n", "nta", (void *)orq, "try next after timeout" )) : (void)0); | |||||
9114 | outgoing_try_another(orq); | |||||
9115 | return; | |||||
9116 | } | |||||
9117 | ||||||
9118 | cancel = orq->orq_cancel, orq->orq_cancel = NULL((void*)0); | |||||
9119 | orq->orq_agent->sa_stats->as_tout_request++; | |||||
9120 | ||||||
9121 | outgoing_reply(orq, SIP_408_REQUEST_TIMEOUT408, sip_408_Request_timeout, 0); | |||||
9122 | ||||||
9123 | if (cancel) | |||||
9124 | outgoing_timeout(cancel, now); | |||||
9125 | } | |||||
9126 | ||||||
9127 | /** Complete a client transaction. | |||||
9128 | * | |||||
9129 | * @return True if transaction was free()d. | |||||
9130 | */ | |||||
9131 | static int | |||||
9132 | outgoing_complete(nta_outgoing_t *orq) | |||||
9133 | { | |||||
9134 | orq->orq_completed = 1; | |||||
9135 | ||||||
9136 | outgoing_reset_timer(orq); /* Timer A / Timer E */ | |||||
9137 | ||||||
9138 | if (orq->orq_stateless) | |||||
9139 | return outgoing_terminate(orq); | |||||
9140 | ||||||
9141 | if (orq->orq_forked) { | |||||
9142 | outgoing_remove_fork(orq); | |||||
9143 | return outgoing_terminate(orq); | |||||
9144 | } | |||||
9145 | ||||||
9146 | if (orq->orq_reliable) { | |||||
9147 | if (orq->orq_method != sip_method_invite || !orq->orq_uas) | |||||
9148 | return outgoing_terminate(orq); | |||||
9149 | } | |||||
9150 | ||||||
9151 | if (orq->orq_method == sip_method_invite) { | |||||
9152 | if (orq->orq_queue != orq->orq_agent->sa_out.inv_completed) | |||||
9153 | outgoing_queue(orq->orq_agent->sa_out.inv_completed, orq); /* Timer D */ | |||||
9154 | } | |||||
9155 | else { | |||||
9156 | outgoing_queue(orq->orq_agent->sa_out.completed, orq); /* Timer K */ | |||||
9157 | } | |||||
9158 | ||||||
9159 | return 0; | |||||
9160 | } | |||||
9161 | ||||||
9162 | /** Handle timers D and K */ | |||||
9163 | static | |||||
9164 | size_t outgoing_timer_dk(outgoing_queue_t *q, | |||||
9165 | char const *timer, | |||||
9166 | uint32_t now) | |||||
9167 | { | |||||
9168 | nta_outgoing_t *orq; | |||||
9169 | size_t terminated = 0; | |||||
9170 | ||||||
9171 | while ((orq = q->q_head)) { | |||||
9172 | if ((int32_t)(orq->orq_timeout - now) > 0 || | |||||
9173 | terminated >= timer_max_terminate) | |||||
9174 | break; | |||||
9175 | ||||||
9176 | terminated++; | |||||
9177 | ||||||
9178 | SU_DEBUG_5(("nta: timer %s fired, %s %s (%u)\n", timer,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 9179, "nta: timer %s fired, %s %s (%u)\n", timer, "terminate" , orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void )0) | |||||
9179 | "terminate", orq->orq_method_name, orq->orq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 9179, "nta: timer %s fired, %s %s (%u)\n", timer, "terminate" , orq->orq_method_name, orq->orq_cseq->cs_seq)) : (void )0); | |||||
9180 | ||||||
9181 | if (orq->orq_method == sip_method_invite) | |||||
9182 | outgoing_terminate_invite(orq); | |||||
9183 | else | |||||
9184 | outgoing_terminate(orq); | |||||
9185 | } | |||||
9186 | ||||||
9187 | return terminated; | |||||
9188 | } | |||||
9189 | ||||||
9190 | ||||||
9191 | /** Terminate an INVITE client transaction. */ | |||||
9192 | static void | |||||
9193 | outgoing_terminate_invite(nta_outgoing_t *original) | |||||
9194 | { | |||||
9195 | nta_outgoing_t *orq = original; | |||||
9196 | ||||||
9197 | while (original->orq_forks) { | |||||
9198 | orq = original->orq_forks; | |||||
9199 | original->orq_forks = orq->orq_forks; | |||||
9200 | ||||||
9201 | assert(orq->orq_forking == original)((void) sizeof ((orq->orq_forking == original) ? 1 : 0), __extension__ ({ if (orq->orq_forking == original) ; else __assert_fail ("orq->orq_forking == original", "nta.c", 9201, __extension__ __PRETTY_FUNCTION__); })); | |||||
9202 | ||||||
9203 | SU_DEBUG_5(("nta: timer %s fired, %s %s (%u);tag=%s\n", "D",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 9205, "nta: timer %s fired, %s %s (%u);tag=%s\n", "D", "terminate" , orq->orq_method_name, orq->orq_cseq->cs_seq, orq-> orq_tag)) : (void)0) | |||||
9204 | "terminate", orq->orq_method_name, orq->orq_cseq->cs_seq,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 9205, "nta: timer %s fired, %s %s (%u);tag=%s\n", "D", "terminate" , orq->orq_method_name, orq->orq_cseq->cs_seq, orq-> orq_tag)) : (void)0) | |||||
9205 | orq->orq_tag))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 9205, "nta: timer %s fired, %s %s (%u);tag=%s\n", "D", "terminate" , orq->orq_method_name, orq->orq_cseq->cs_seq, orq-> orq_tag)) : (void)0); | |||||
9206 | ||||||
9207 | orq->orq_forking = NULL((void*)0), orq->orq_forks = NULL((void*)0), orq->orq_forked = 0; | |||||
9208 | ||||||
9209 | if (outgoing_terminate(orq)) | |||||
9210 | continue; | |||||
9211 | ||||||
9212 | if (orq->orq_status < 200) { | |||||
9213 | /* Fork has timed out */ | |||||
9214 | orq->orq_agent->sa_stats->as_tout_request++; | |||||
9215 | outgoing_reply(orq, SIP_408_REQUEST_TIMEOUT408, sip_408_Request_timeout, 0); | |||||
9216 | } | |||||
9217 | } | |||||
9218 | ||||||
9219 | if (outgoing_terminate(orq = original)) | |||||
9220 | return; | |||||
9221 | ||||||
9222 | if (orq->orq_status < 200) { | |||||
9223 | /* Original INVITE has timed out */ | |||||
9224 | orq->orq_agent->sa_stats->as_tout_request++; | |||||
9225 | outgoing_reply(orq, SIP_408_REQUEST_TIMEOUT408, sip_408_Request_timeout, 0); | |||||
9226 | } | |||||
9227 | } | |||||
9228 | ||||||
9229 | static void | |||||
9230 | outgoing_remove_fork(nta_outgoing_t *orq) | |||||
9231 | { | |||||
9232 | nta_outgoing_t **slot; | |||||
9233 | ||||||
9234 | for (slot = &orq->orq_forking->orq_forks; | |||||
9235 | slot && *slot; | |||||
9236 | slot = &(*slot)->orq_forks) { | |||||
9237 | if (orq == *slot) { | |||||
9238 | *slot = orq->orq_forks; | |||||
9239 | orq->orq_forks = NULL((void*)0); | |||||
9240 | orq->orq_forking = NULL((void*)0); | |||||
9241 | orq->orq_forked = 0; | |||||
9242 | } | |||||
9243 | } | |||||
9244 | ||||||
9245 | assert(orq == NULL)((void) sizeof ((orq == ((void*)0)) ? 1 : 0), __extension__ ( { if (orq == ((void*)0)) ; else __assert_fail ("orq == NULL", "nta.c", 9245, __extension__ __PRETTY_FUNCTION__); })); | |||||
9246 | } | |||||
9247 | ||||||
9248 | /** Terminate a client transaction. */ | |||||
9249 | static | |||||
9250 | int outgoing_terminate(nta_outgoing_t *orq) | |||||
9251 | { | |||||
9252 | orq->orq_terminated = 1; | |||||
9253 | ||||||
9254 | if (!orq->orq_destroyed) { | |||||
9255 | outgoing_queue(orq->orq_agent->sa_out.terminated, orq); | |||||
9256 | return 0; | |||||
9257 | } | |||||
9258 | else if (orq->orq_agent->sa_out.free) { | |||||
9259 | outgoing_free_queue(orq->orq_agent->sa_out.free, orq); | |||||
9260 | return 1; | |||||
9261 | } | |||||
9262 | else { | |||||
9263 | outgoing_free(orq); | |||||
9264 | return 1; | |||||
9265 | } | |||||
9266 | } | |||||
9267 | ||||||
9268 | /** Mass destroy client transactions */ | |||||
9269 | static | |||||
9270 | size_t outgoing_mass_destroy(nta_agent_t *sa, outgoing_queue_t *q) | |||||
9271 | { | |||||
9272 | size_t destroyed = q->q_length; | |||||
9273 | ||||||
9274 | if (destroyed > 2 && *sa->sa_terminator) { | |||||
9275 | su_msg_r m = SU_MSG_R_INIT{ ((void*)0) }; | |||||
9276 | ||||||
9277 | if (su_msg_create(m, | |||||
9278 | su_clone_task(sa->sa_terminator), | |||||
9279 | su_root_task(sa->sa_root), | |||||
9280 | outgoing_reclaim_queued, | |||||
9281 | sizeof(outgoing_queue_t)) == SU_SUCCESSsu_success) { | |||||
9282 | outgoing_queue_t *mq = su_msg_data(m)->a_outgoing_queue; | |||||
9283 | ||||||
9284 | *mq = *q; | |||||
9285 | ||||||
9286 | if (su_msg_send(m) == SU_SUCCESSsu_success) | |||||
9287 | q->q_length = 0; | |||||
9288 | } | |||||
9289 | } | |||||
9290 | ||||||
9291 | if (q->q_length) | |||||
9292 | outgoing_reclaim_queued(NULL((void*)0), NULL((void*)0), (void*)q); | |||||
9293 | ||||||
9294 | return destroyed; | |||||
9295 | } | |||||
9296 | ||||||
9297 | /** Find an outgoing request corresponging to a message and @Via line. | |||||
9298 | * | |||||
9299 | * Return an outgoing request object based on a message and the @Via line | |||||
9300 | * given as argument. This function is used when doing loop checking: if we | |||||
9301 | * have sent the request and it has been routed back to us. | |||||
9302 | * | |||||
9303 | * @param agent | |||||
9304 | * @param msg | |||||
9305 | * @param sip | |||||
9306 | * @param v | |||||
9307 | */ | |||||
9308 | nta_outgoing_t *nta_outgoing_find(nta_agent_t const *agent, | |||||
9309 | msg_t const *msg, | |||||
9310 | sip_t const *sip, | |||||
9311 | sip_via_t const *v) | |||||
9312 | { | |||||
9313 | if (agent == NULL((void*)0) || msg == NULL((void*)0) || sip == NULL((void*)0) || v == NULL((void*)0)) { | |||||
9314 | su_seterrno(EFAULT14); | |||||
9315 | return NULL((void*)0); | |||||
9316 | } | |||||
9317 | ||||||
9318 | return outgoing_find(agent, msg, sip, v); | |||||
9319 | } | |||||
9320 | ||||||
9321 | /**@internal | |||||
9322 | * | |||||
9323 | * Find an outgoing request corresponging to a message and @Via line. | |||||
9324 | * | |||||
9325 | */ | |||||
9326 | nta_outgoing_t *outgoing_find(nta_agent_t const *sa, | |||||
9327 | msg_t const *msg, | |||||
9328 | sip_t const *sip, | |||||
9329 | sip_via_t const *v) | |||||
9330 | { | |||||
9331 | nta_outgoing_t **oo, *orq; | |||||
9332 | outgoing_htable_t const *oht = sa->sa_outgoing; | |||||
9333 | sip_cseq_t const *cseq = sip->sip_cseq; | |||||
9334 | sip_call_id_t const *i = sip->sip_call_id; | |||||
9335 | hash_value_t hash; | |||||
9336 | sip_method_t method, method2; | |||||
9337 | unsigned short status = sip->sip_status ? sip->sip_status->st_status : 0; | |||||
9338 | ||||||
9339 | if (cseq == NULL((void*)0)) | |||||
9340 | return NULL((void*)0); | |||||
9341 | ||||||
9342 | hash = NTA_HASH(i, cseq->cs_seq)((i)->i_hash + 26839U * (uint32_t)(cseq->cs_seq)); | |||||
9343 | ||||||
9344 | method = cseq->cs_method; | |||||
9345 | ||||||
9346 | /* Get original invite when ACKing */ | |||||
9347 | if (sip->sip_request && method == sip_method_ack && v == NULL((void*)0)) | |||||
9348 | method = sip_method_invite, method2 = sip_method_invalid; | |||||
9349 | else if (sa->sa_is_a_uas && 200 <= status && status < 300 && method == sip_method_invite) | |||||
9350 | method2 = sip_method_ack; | |||||
9351 | else | |||||
9352 | method2 = method; | |||||
9353 | ||||||
9354 | for (oo = outgoing_htable_hash(oht, hash); | |||||
9355 | (orq = *oo); | |||||
9356 | oo = outgoing_htable_next(oht, oo)) { | |||||
9357 | if (orq->orq_stateless) | |||||
9358 | continue; | |||||
9359 | /* Accept terminated transactions when looking for original INVITE */ | |||||
9360 | if (orq->orq_terminated && method2 != sip_method_invalid) | |||||
9361 | continue; | |||||
9362 | if (hash != orq->orq_hash) | |||||
9363 | continue; | |||||
9364 | if (orq->orq_call_id->i_hash != i->i_hash || | |||||
9365 | strcmp(orq->orq_call_id->i_id, i->i_id)) | |||||
9366 | continue; | |||||
9367 | if (orq->orq_cseq->cs_seq != cseq->cs_seq) | |||||
9368 | continue; | |||||
9369 | if (method == sip_method_unknown && | |||||
9370 | strcmp(orq->orq_cseq->cs_method_name, cseq->cs_method_name)) | |||||
9371 | continue; | |||||
9372 | if (orq->orq_method != method && orq->orq_method != method2) | |||||
9373 | continue; | |||||
9374 | if (su_strcasecmp(orq->orq_from->a_tag, sip->sip_from->a_tag)) | |||||
9375 | continue; | |||||
9376 | if (orq->orq_to->a_tag && | |||||
9377 | su_strcasecmp(orq->orq_to->a_tag, sip->sip_to->a_tag)) | |||||
9378 | continue; | |||||
9379 | ||||||
9380 | if (orq->orq_method == sip_method_ack && 300 <= status) | |||||
9381 | continue; | |||||
9382 | ||||||
9383 | if (v && !su_casematch(orq->orq_branch + strlen("branch="), v->v_branch)) | |||||
9384 | continue; | |||||
9385 | ||||||
9386 | break; /* match */ | |||||
9387 | } | |||||
9388 | ||||||
9389 | return orq; | |||||
9390 | } | |||||
9391 | ||||||
9392 | /** Process a response message. */ | |||||
9393 | int outgoing_recv(nta_outgoing_t *_orq, | |||||
9394 | int status, | |||||
9395 | msg_t *msg, | |||||
9396 | sip_t *sip) | |||||
9397 | { | |||||
9398 | nta_outgoing_t *orq = _orq->orq_forking ? _orq->orq_forking : _orq; | |||||
9399 | nta_agent_t *sa = orq->orq_agent; | |||||
9400 | int internal = sip == NULL((void*)0) || (sip->sip_flags & NTA_INTERNAL_MSG(1<<15)) != 0; | |||||
9401 | ||||||
9402 | assert(!internal || status >= 300)((void) sizeof ((!internal || status >= 300) ? 1 : 0), __extension__ ({ if (!internal || status >= 300) ; else __assert_fail ( "!internal || status >= 300", "nta.c", 9402, __extension__ __PRETTY_FUNCTION__); })); | |||||
9403 | assert(orq == _orq || orq->orq_method == sip_method_invite)((void) sizeof ((orq == _orq || orq->orq_method == sip_method_invite ) ? 1 : 0), __extension__ ({ if (orq == _orq || orq->orq_method == sip_method_invite) ; else __assert_fail ("orq == _orq || orq->orq_method == sip_method_invite" , "nta.c", 9403, __extension__ __PRETTY_FUNCTION__); })); | |||||
9404 | ||||||
9405 | if (status < 100) status = 100; | |||||
9406 | ||||||
9407 | if (!internal && orq->orq_delay == UINT_MAX(2147483647 *2U +1U)) | |||||
9408 | outgoing_estimate_delay(orq, sip); | |||||
9409 | ||||||
9410 | if (orq->orq_cc) | |||||
9411 | agent_accept_compressed(orq->orq_agent, msg, orq->orq_cc); | |||||
9412 | ||||||
9413 | if (orq->orq_cancel) { | |||||
9414 | nta_outgoing_t *cancel; | |||||
9415 | cancel = orq->orq_cancel; orq->orq_cancel = NULL((void*)0); | |||||
9416 | cancel->orq_delayed = 0; | |||||
9417 | ||||||
9418 | if (status < 200) { | |||||
9419 | outgoing_send(cancel, 0); | |||||
9420 | outgoing_complete(orq); | |||||
9421 | } | |||||
9422 | else { | |||||
9423 | outgoing_reply(cancel, SIP_481_NO_TRANSACTION481, sip_481_No_transaction, 0); | |||||
9424 | } | |||||
9425 | } | |||||
9426 | ||||||
9427 | if (orq->orq_pending) { | |||||
9428 | tport_release(orq->orq_tport, orq->orq_pending, orq->orq_request, | |||||
9429 | msg, orq, status < 200); | |||||
9430 | if (status >= 200) | |||||
9431 | orq->orq_pending = 0; | |||||
9432 | } | |||||
9433 | ||||||
9434 | /* The state machines */ | |||||
9435 | if (orq->orq_method == sip_method_invite) { | |||||
9436 | nta_outgoing_t *original = orq; | |||||
9437 | ||||||
9438 | orq = _orq; | |||||
9439 | ||||||
9440 | if (orq->orq_destroyed && 200 <= status && status < 300) { | |||||
9441 | if (orq->orq_uas && su_strcasecmp(sip->sip_to->a_tag, orq->orq_tag) != 0) { | |||||
9442 | /* Orphan 200 Ok to INVITE. ACK and BYE it */ | |||||
9443 | SU_DEBUG_5(("nta: Orphan 200 Ok send ACK&BYE %p\n", (void *)orq))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 9443, "nta: Orphan 200 Ok send ACK&BYE %p\n", (void *)orq )) : (void)0); | |||||
9444 | return nta_msg_ackbye(sa, msg); | |||||
9445 | } | |||||
9446 | return -1; /* Proxy statelessly (RFC3261 section 16.11) */ | |||||
9447 | } | |||||
9448 | ||||||
9449 | outgoing_reset_timer(original); /* Retransmission */ | |||||
9450 | ||||||
9451 | if (status < 200) { | |||||
9452 | if (original->orq_status < 200) | |||||
9453 | original->orq_status = status; | |||||
9454 | if (orq->orq_status < 200) | |||||
9455 | orq->orq_status = status; | |||||
9456 | ||||||
9457 | if (original->orq_queue == sa->sa_out.inv_calling) { | |||||
9458 | outgoing_queue(sa->sa_out.inv_proceeding, original); | |||||
9459 | } | |||||
9460 | else if (original->orq_queue == sa->sa_out.inv_proceeding) { | |||||
9461 | if (sa->sa_out.inv_proceeding->q_timeout) { | |||||
9462 | outgoing_remove(original); | |||||
9463 | outgoing_queue(sa->sa_out.inv_proceeding, original); | |||||
9464 | } | |||||
9465 | } | |||||
9466 | ||||||
9467 | /* Handle 100rel */ | |||||
9468 | if (sip && sip->sip_rseq) { | |||||
9469 | if (outgoing_recv_reliable(orq, msg, sip) < 0) { | |||||
9470 | msg_destroy(msg); | |||||
9471 | return 0; | |||||
9472 | } | |||||
9473 | } | |||||
9474 | } | |||||
9475 | else { | |||||
9476 | /* Final response */ | |||||
9477 | if (status >= 300 && !internal) | |||||
9478 | outgoing_ack(original, sip); | |||||
9479 | ||||||
9480 | if (!original->orq_completed) { | |||||
9481 | if (outgoing_complete(original)) | |||||
9482 | return 0; | |||||
9483 | ||||||
9484 | if (orq->orq_uas && sip && orq == original) { | |||||
9485 | /* | |||||
9486 | * We silently discard duplicate final responses to INVITE below | |||||
9487 | * with outgoing_duplicate() | |||||
9488 | */ | |||||
9489 | su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request)); | |||||
9490 | orq->orq_tag = su_strdup(home, sip->sip_to->a_tag); | |||||
9491 | } | |||||
9492 | } | |||||
9493 | /* Retransmission or response from another fork */ | |||||
9494 | else if (orq->orq_status >= 200) { | |||||
9495 | /* Once 2xx has been received, non-2xx will not be forwarded */ | |||||
9496 | if (status >= 300) | |||||
9497 | return outgoing_duplicate(orq, msg, sip); | |||||
9498 | ||||||
9499 | if (orq->orq_uas) { | |||||
9500 | if (su_strcasecmp(sip->sip_to->a_tag, orq->orq_tag) == 0) | |||||
9501 | /* Catch retransmission */ | |||||
9502 | return outgoing_duplicate(orq, msg, sip); | |||||
9503 | ||||||
9504 | /* Orphan 200 Ok to INVITE. ACK and BYE it */ | |||||
9505 | SU_DEBUG_5(("nta: Orphan 200 Ok send ACK&BYE" VA_NONE))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 9505, "nta: Orphan 200 Ok send ACK&BYE" "%s", "")) : (void )0); | |||||
9506 | return nta_msg_ackbye(sa, msg); | |||||
9507 | } | |||||
9508 | } | |||||
9509 | ||||||
9510 | orq->orq_status = status; | |||||
9511 | } | |||||
9512 | } | |||||
9513 | else if (orq->orq_method != sip_method_ack) { | |||||
9514 | /* Non-INVITE */ | |||||
9515 | if (orq->orq_queue == sa->sa_out.trying || | |||||
9516 | orq->orq_queue == sa->sa_out.resolving) { | |||||
9517 | /* hacked by freeswitch, this is being hit by options 404 status with 404 orq->orq_status and orq_destroyed = 1, orq_completed = 1 */ | |||||
9518 | /* assert(orq->orq_status < 200); */ | |||||
9519 | if (orq->orq_status >= 200) {msg_destroy(msg); return 0;} | |||||
9520 | ||||||
9521 | if (status < 200) { | |||||
9522 | /* @RFC3261 17.1.2.1: | |||||
9523 | * retransmissions continue for unreliable transports, | |||||
9524 | * but at an interval of T2. | |||||
9525 | * | |||||
9526 | * @RFC4321 1.2: | |||||
9527 | * Note that Timer E is not altered during the transition | |||||
9528 | * to Proceeding. | |||||
9529 | */ | |||||
9530 | if (!orq->orq_reliable) | |||||
9531 | orq->orq_interval = sa->sa_t2; | |||||
9532 | } | |||||
9533 | else if (!outgoing_complete(orq)) { | |||||
9534 | if (orq->orq_sigcomp_zap && orq->orq_tport && orq->orq_cc) | |||||
9535 | agent_zap_compressor(orq->orq_agent, orq->orq_cc); | |||||
9536 | } | |||||
9537 | else /* outgoing_complete */ { | |||||
9538 | msg_destroy(msg); | |||||
9539 | return 0; | |||||
9540 | } | |||||
9541 | } | |||||
9542 | else { | |||||
9543 | /* Already completed or terminated */ | |||||
9544 | assert(orq->orq_queue == sa->sa_out.completed ||((void) sizeof ((orq->orq_queue == sa->sa_out.completed || orq->orq_queue == sa->sa_out.terminated) ? 1 : 0), __extension__ ({ if (orq->orq_queue == sa->sa_out.completed || orq-> orq_queue == sa->sa_out.terminated) ; else __assert_fail ( "orq->orq_queue == sa->sa_out.completed || orq->orq_queue == sa->sa_out.terminated" , "nta.c", 9545, __extension__ __PRETTY_FUNCTION__); })) | |||||
9545 | orq->orq_queue == sa->sa_out.terminated)((void) sizeof ((orq->orq_queue == sa->sa_out.completed || orq->orq_queue == sa->sa_out.terminated) ? 1 : 0), __extension__ ({ if (orq->orq_queue == sa->sa_out.completed || orq-> orq_queue == sa->sa_out.terminated) ; else __assert_fail ( "orq->orq_queue == sa->sa_out.completed || orq->orq_queue == sa->sa_out.terminated" , "nta.c", 9545, __extension__ __PRETTY_FUNCTION__); })); | |||||
9546 | assert(orq->orq_status >= 200)((void) sizeof ((orq->orq_status >= 200) ? 1 : 0), __extension__ ({ if (orq->orq_status >= 200) ; else __assert_fail ("orq->orq_status >= 200" , "nta.c", 9546, __extension__ __PRETTY_FUNCTION__); })); | |||||
9547 | return outgoing_duplicate(orq, msg, sip); | |||||
9548 | } | |||||
9549 | ||||||
9550 | orq->orq_status = status; | |||||
9551 | } | |||||
9552 | else { | |||||
9553 | /* ACK */ | |||||
9554 | if (sip && (sip->sip_flags & NTA_INTERNAL_MSG(1<<15)) == 0) | |||||
9555 | /* Received re-transmitted final reply to INVITE, retransmit ACK */ | |||||
9556 | outgoing_retransmit(orq); | |||||
9557 | msg_destroy(msg); | |||||
9558 | return 0; | |||||
9559 | } | |||||
9560 | ||||||
9561 | if (100 >= status + orq->orq_pass_100) { | |||||
9562 | msg_destroy(msg); | |||||
9563 | return 0; | |||||
9564 | } | |||||
9565 | ||||||
9566 | if (orq->orq_destroyed) { | |||||
9567 | msg_destroy(msg); | |||||
9568 | return 0; | |||||
9569 | } | |||||
9570 | ||||||
9571 | if (orq->orq_response) | |||||
9572 | msg_destroy(orq->orq_response); | |||||
9573 | orq->orq_response = msg; | |||||
9574 | /* Call callback */ | |||||
9575 | orq->orq_callback(orq->orq_magic, orq, sip); | |||||
9576 | return 0; | |||||
9577 | } | |||||
9578 | ||||||
9579 | static void outgoing_default_recv(nta_outgoing_t *orq, | |||||
9580 | int status, | |||||
9581 | msg_t *msg, | |||||
9582 | sip_t *sip) | |||||
9583 | { | |||||
9584 | assert(sip->sip_cseq)((void) sizeof ((sip->sip_cseq) ? 1 : 0), __extension__ ({ if (sip->sip_cseq) ; else __assert_fail ("sip->sip_cseq" , "nta.c", 9584, __extension__ __PRETTY_FUNCTION__); })); | |||||
9585 | ||||||
9586 | orq->orq_status = status; | |||||
9587 | orq->orq_response = msg; | |||||
9588 | orq->orq_callback(orq->orq_magic, orq, sip); | |||||
9589 | orq->orq_response = NULL((void*)0); | |||||
9590 | orq->orq_status = 0; | |||||
9591 | msg_destroy(msg); | |||||
9592 | } | |||||
9593 | ||||||
9594 | static void outgoing_estimate_delay(nta_outgoing_t *orq, sip_t *sip) | |||||
9595 | { | |||||
9596 | su_time_t now = su_now(); | |||||
9597 | double diff = 1000 * su_time_diff(now, orq->orq_sent); | |||||
9598 | ||||||
9599 | if (orq->orq_timestamp && sip->sip_timestamp) { | |||||
9600 | double diff2, delay = 0.0; | |||||
9601 | su_time_t timestamp = { 0, 0 }; | |||||
9602 | char const *bad; | |||||
9603 | ||||||
9604 | sscanf(sip->sip_timestamp->ts_stamp, "%lu.%lu", | |||||
9605 | ×tamp.tv_sec, ×tamp.tv_usec); | |||||
9606 | ||||||
9607 | diff2 = 1000 * su_time_diff(now, timestamp); | |||||
9608 | ||||||
9609 | if (diff2 < 0) | |||||
9610 | bad = "negative"; | |||||
9611 | else if (diff2 > diff + 1e-3) | |||||
9612 | bad = "too large"; | |||||
9613 | else { | |||||
9614 | if (sip->sip_timestamp->ts_delay) | |||||
9615 | sscanf(sip->sip_timestamp->ts_delay, "%lg", &delay); | |||||
9616 | ||||||
9617 | if (1000 * delay <= diff2) { | |||||
9618 | diff = diff2 - 1000 * delay; | |||||
9619 | orq->orq_delay = (unsigned)diff; | |||||
9620 | SU_DEBUG_7(("nta_outgoing: RTT is %g ms, now is %lu.%06lu, "(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__ , 9625, "nta_outgoing: RTT is %g ms, now is %lu.%06lu, " "Timestamp was %s %s\n" , diff, now.tv_sec, now.tv_usec, sip->sip_timestamp->ts_stamp , sip->sip_timestamp->ts_delay ? sip->sip_timestamp-> ts_delay : "")) : (void)0) | |||||
9621 | "Timestamp was %s %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__ , 9625, "nta_outgoing: RTT is %g ms, now is %lu.%06lu, " "Timestamp was %s %s\n" , diff, now.tv_sec, now.tv_usec, sip->sip_timestamp->ts_stamp , sip->sip_timestamp->ts_delay ? sip->sip_timestamp-> ts_delay : "")) : (void)0) | |||||
9622 | diff, now.tv_sec, now.tv_usec,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__ , 9625, "nta_outgoing: RTT is %g ms, now is %lu.%06lu, " "Timestamp was %s %s\n" , diff, now.tv_sec, now.tv_usec, sip->sip_timestamp->ts_stamp , sip->sip_timestamp->ts_delay ? sip->sip_timestamp-> ts_delay : "")) : (void)0) | |||||
9623 | sip->sip_timestamp->ts_stamp,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__ , 9625, "nta_outgoing: RTT is %g ms, now is %lu.%06lu, " "Timestamp was %s %s\n" , diff, now.tv_sec, now.tv_usec, sip->sip_timestamp->ts_stamp , sip->sip_timestamp->ts_delay ? sip->sip_timestamp-> ts_delay : "")) : (void)0) | |||||
9624 | sip->sip_timestamp->ts_delay ?(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__ , 9625, "nta_outgoing: RTT is %g ms, now is %lu.%06lu, " "Timestamp was %s %s\n" , diff, now.tv_sec, now.tv_usec, sip->sip_timestamp->ts_stamp , sip->sip_timestamp->ts_delay ? sip->sip_timestamp-> ts_delay : "")) : (void)0) | |||||
9625 | sip->sip_timestamp->ts_delay : ""))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__ , 9625, "nta_outgoing: RTT is %g ms, now is %lu.%06lu, " "Timestamp was %s %s\n" , diff, now.tv_sec, now.tv_usec, sip->sip_timestamp->ts_stamp , sip->sip_timestamp->ts_delay ? sip->sip_timestamp-> ts_delay : "")) : (void)0); | |||||
9626 | return; | |||||
9627 | } | |||||
9628 | bad = "delay"; | |||||
9629 | } | |||||
9630 | ||||||
9631 | SU_DEBUG_3(("nta_outgoing: %s Timestamp %lu.%06lu %g "(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 9637, "nta_outgoing: %s Timestamp %lu.%06lu %g " "(sent %lu.%06lu, now is %lu.%06lu)\n" , bad, timestamp.tv_sec, timestamp.tv_usec, delay, orq->orq_sent .tv_sec, orq->orq_sent.tv_usec, now.tv_sec, now.tv_usec)) : (void)0) | |||||
9632 | "(sent %lu.%06lu, now is %lu.%06lu)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 9637, "nta_outgoing: %s Timestamp %lu.%06lu %g " "(sent %lu.%06lu, now is %lu.%06lu)\n" , bad, timestamp.tv_sec, timestamp.tv_usec, delay, orq->orq_sent .tv_sec, orq->orq_sent.tv_usec, now.tv_sec, now.tv_usec)) : (void)0) | |||||
9633 | bad,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 9637, "nta_outgoing: %s Timestamp %lu.%06lu %g " "(sent %lu.%06lu, now is %lu.%06lu)\n" , bad, timestamp.tv_sec, timestamp.tv_usec, delay, orq->orq_sent .tv_sec, orq->orq_sent.tv_usec, now.tv_sec, now.tv_usec)) : (void)0) | |||||
9634 | timestamp.tv_sec, timestamp.tv_usec,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 9637, "nta_outgoing: %s Timestamp %lu.%06lu %g " "(sent %lu.%06lu, now is %lu.%06lu)\n" , bad, timestamp.tv_sec, timestamp.tv_usec, delay, orq->orq_sent .tv_sec, orq->orq_sent.tv_usec, now.tv_sec, now.tv_usec)) : (void)0) | |||||
9635 | delay,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 9637, "nta_outgoing: %s Timestamp %lu.%06lu %g " "(sent %lu.%06lu, now is %lu.%06lu)\n" , bad, timestamp.tv_sec, timestamp.tv_usec, delay, orq->orq_sent .tv_sec, orq->orq_sent.tv_usec, now.tv_sec, now.tv_usec)) : (void)0) | |||||
9636 | orq->orq_sent.tv_sec, orq->orq_sent.tv_usec,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 9637, "nta_outgoing: %s Timestamp %lu.%06lu %g " "(sent %lu.%06lu, now is %lu.%06lu)\n" , bad, timestamp.tv_sec, timestamp.tv_usec, delay, orq->orq_sent .tv_sec, orq->orq_sent.tv_usec, now.tv_sec, now.tv_usec)) : (void)0) | |||||
9637 | now.tv_sec, now.tv_usec))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 9637, "nta_outgoing: %s Timestamp %lu.%06lu %g " "(sent %lu.%06lu, now is %lu.%06lu)\n" , bad, timestamp.tv_sec, timestamp.tv_usec, delay, orq->orq_sent .tv_sec, orq->orq_sent.tv_usec, now.tv_sec, now.tv_usec)) : (void)0); | |||||
9638 | } | |||||
9639 | ||||||
9640 | if (diff >= 0 && diff < (double)UINT_MAX(2147483647 *2U +1U)) { | |||||
9641 | orq->orq_delay = (unsigned)diff; | |||||
9642 | SU_DEBUG_7(("nta_outgoing: RTT is %g ms\n", diff))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__ , 9642, "nta_outgoing: RTT is %g ms\n", diff)) : (void)0); | |||||
9643 | } | |||||
9644 | } | |||||
9645 | ||||||
9646 | /**@typedef nta_response_f | |||||
9647 | * | |||||
9648 | * Callback for replies to outgoing requests. | |||||
9649 | * | |||||
9650 | * This is a callback function invoked by NTA when it has received a new | |||||
9651 | * reply to an outgoing request. | |||||
9652 | * | |||||
9653 | * @param magic request context | |||||
9654 | * @param request request handle | |||||
9655 | * @param sip received status message | |||||
9656 | * | |||||
9657 | * @return | |||||
9658 | * This callback function should return always 0. | |||||
9659 | * | |||||
9660 | */ | |||||
9661 | ||||||
9662 | /** Process duplicate responses */ | |||||
9663 | static int outgoing_duplicate(nta_outgoing_t *orq, | |||||
9664 | msg_t *msg, | |||||
9665 | sip_t *sip) | |||||
9666 | { | |||||
9667 | sip_via_t *v; | |||||
9668 | ||||||
9669 | if (sip && (sip->sip_flags & NTA_INTERNAL_MSG(1<<15)) == 0) { | |||||
9670 | v = sip->sip_via; | |||||
9671 | ||||||
9672 | SU_DEBUG_5(("nta: %u %s is duplicate response to %d %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 9674, "nta: %u %s is duplicate response to %d %s\n", sip-> sip_status->st_status, sip->sip_status->st_phrase, orq ->orq_cseq->cs_seq, orq->orq_cseq->cs_method_name )) : (void)0) | |||||
9673 | sip->sip_status->st_status, sip->sip_status->st_phrase,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 9674, "nta: %u %s is duplicate response to %d %s\n", sip-> sip_status->st_status, sip->sip_status->st_phrase, orq ->orq_cseq->cs_seq, orq->orq_cseq->cs_method_name )) : (void)0) | |||||
9674 | orq->orq_cseq->cs_seq, orq->orq_cseq->cs_method_name))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 9674, "nta: %u %s is duplicate response to %d %s\n", sip-> sip_status->st_status, sip->sip_status->st_phrase, orq ->orq_cseq->cs_seq, orq->orq_cseq->cs_method_name )) : (void)0); | |||||
9675 | if (v) | |||||
9676 | SU_DEBUG_5(("\tVia: %s %s%s%s%s%s%s%s%s%s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 9681, "\tVia: %s %s%s%s%s%s%s%s%s%s\n", v->v_protocol, v ->v_host, ((v->v_port) ? (":") : ""), ((v->v_port) ? (v->v_port) : ""), ((v->v_received) ? (" ;received=") : ""), ((v->v_received) ? (v->v_received) : ""), ((v-> v_maddr) ? (" ;maddr=") : ""), ((v->v_maddr) ? (v->v_maddr ) : ""), ((v->v_branch) ? (" ;branch=") : ""), ((v->v_branch ) ? (v->v_branch) : ""))) : (void)0) | |||||
9677 | v->v_protocol, v->v_host,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 9681, "\tVia: %s %s%s%s%s%s%s%s%s%s\n", v->v_protocol, v ->v_host, ((v->v_port) ? (":") : ""), ((v->v_port) ? (v->v_port) : ""), ((v->v_received) ? (" ;received=") : ""), ((v->v_received) ? (v->v_received) : ""), ((v-> v_maddr) ? (" ;maddr=") : ""), ((v->v_maddr) ? (v->v_maddr ) : ""), ((v->v_branch) ? (" ;branch=") : ""), ((v->v_branch ) ? (v->v_branch) : ""))) : (void)0) | |||||
9678 | SIP_STRLOG(":", v->v_port),(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 9681, "\tVia: %s %s%s%s%s%s%s%s%s%s\n", v->v_protocol, v ->v_host, ((v->v_port) ? (":") : ""), ((v->v_port) ? (v->v_port) : ""), ((v->v_received) ? (" ;received=") : ""), ((v->v_received) ? (v->v_received) : ""), ((v-> v_maddr) ? (" ;maddr=") : ""), ((v->v_maddr) ? (v->v_maddr ) : ""), ((v->v_branch) ? (" ;branch=") : ""), ((v->v_branch ) ? (v->v_branch) : ""))) : (void)0) | |||||
9679 | SIP_STRLOG(" ;received=", v->v_received),(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 9681, "\tVia: %s %s%s%s%s%s%s%s%s%s\n", v->v_protocol, v ->v_host, ((v->v_port) ? (":") : ""), ((v->v_port) ? (v->v_port) : ""), ((v->v_received) ? (" ;received=") : ""), ((v->v_received) ? (v->v_received) : ""), ((v-> v_maddr) ? (" ;maddr=") : ""), ((v->v_maddr) ? (v->v_maddr ) : ""), ((v->v_branch) ? (" ;branch=") : ""), ((v->v_branch ) ? (v->v_branch) : ""))) : (void)0) | |||||
9680 | SIP_STRLOG(" ;maddr=", v->v_maddr),(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 9681, "\tVia: %s %s%s%s%s%s%s%s%s%s\n", v->v_protocol, v ->v_host, ((v->v_port) ? (":") : ""), ((v->v_port) ? (v->v_port) : ""), ((v->v_received) ? (" ;received=") : ""), ((v->v_received) ? (v->v_received) : ""), ((v-> v_maddr) ? (" ;maddr=") : ""), ((v->v_maddr) ? (v->v_maddr ) : ""), ((v->v_branch) ? (" ;branch=") : ""), ((v->v_branch ) ? (v->v_branch) : ""))) : (void)0) | |||||
9681 | SIP_STRLOG(" ;branch=", v->v_branch)))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 9681, "\tVia: %s %s%s%s%s%s%s%s%s%s\n", v->v_protocol, v ->v_host, ((v->v_port) ? (":") : ""), ((v->v_port) ? (v->v_port) : ""), ((v->v_received) ? (" ;received=") : ""), ((v->v_received) ? (v->v_received) : ""), ((v-> v_maddr) ? (" ;maddr=") : ""), ((v->v_maddr) ? (v->v_maddr ) : ""), ((v->v_branch) ? (" ;branch=") : ""), ((v->v_branch ) ? (v->v_branch) : ""))) : (void)0); | |||||
9682 | } | |||||
9683 | ||||||
9684 | msg_destroy(msg); | |||||
9685 | return 0; | |||||
9686 | } | |||||
9687 | ||||||
9688 | /** @internal ACK to a final response (300..699). | |||||
9689 | * These messages are ACK'ed via the original URL (and tport) | |||||
9690 | */ | |||||
9691 | void outgoing_ack(nta_outgoing_t *orq, sip_t *sip) | |||||
9692 | { | |||||
9693 | msg_t *ackmsg; | |||||
9694 | ||||||
9695 | assert(orq)((void) sizeof ((orq) ? 1 : 0), __extension__ ({ if (orq) ; else __assert_fail ("orq", "nta.c", 9695, __extension__ __PRETTY_FUNCTION__ ); })); | |||||
9696 | ||||||
9697 | /* Do not ack internally generated messages... */ | |||||
9698 | if (sip == NULL((void*)0) || sip->sip_flags & NTA_INTERNAL_MSG(1<<15)) | |||||
9699 | return; | |||||
9700 | ||||||
9701 | assert(sip)((void) sizeof ((sip) ? 1 : 0), __extension__ ({ if (sip) ; else __assert_fail ("sip", "nta.c", 9701, __extension__ __PRETTY_FUNCTION__ ); })); assert(sip->sip_status)((void) sizeof ((sip->sip_status) ? 1 : 0), __extension__ ( { if (sip->sip_status) ; else __assert_fail ("sip->sip_status" , "nta.c", 9701, __extension__ __PRETTY_FUNCTION__); })); | |||||
9702 | assert(sip->sip_status->st_status >= 300)((void) sizeof ((sip->sip_status->st_status >= 300) ? 1 : 0), __extension__ ({ if (sip->sip_status->st_status >= 300) ; else __assert_fail ("sip->sip_status->st_status >= 300" , "nta.c", 9702, __extension__ __PRETTY_FUNCTION__); })); | |||||
9703 | assert(orq->orq_tport)((void) sizeof ((orq->orq_tport) ? 1 : 0), __extension__ ( { if (orq->orq_tport) ; else __assert_fail ("orq->orq_tport" , "nta.c", 9703, __extension__ __PRETTY_FUNCTION__); })); | |||||
9704 | ||||||
9705 | ackmsg = outgoing_ackmsg(orq, SIP_METHOD_ACKsip_method_ack, "ACK", SIPTAG_TO(sip->sip_to)siptag_to, siptag_to_v(sip->sip_to), TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
9706 | if (!ackmsg) | |||||
9707 | return; | |||||
9708 | ||||||
9709 | if (!outgoing_create(orq->orq_agent, NULL((void*)0), NULL((void*)0), | |||||
9710 | NULL((void*)0), orq->orq_tpn, ackmsg, | |||||
9711 | NTATAG_BRANCH_KEY(sip->sip_via->v_branch)ntatag_branch_key, tag_str_v((sip->sip_via->v_branch)), | |||||
9712 | NTATAG_USER_VIA(1)ntatag_user_via, tag_bool_v((1)), | |||||
9713 | NTATAG_STATELESS(1)ntatag_stateless, tag_bool_v((1)), | |||||
9714 | TAG_END()(tag_type_t)0, (tag_value_t)0)) | |||||
9715 | msg_destroy(ackmsg); | |||||
9716 | } | |||||
9717 | ||||||
9718 | /** Generate messages for hop-by-hop ACK or CANCEL. | |||||
9719 | */ | |||||
9720 | msg_t *outgoing_ackmsg(nta_outgoing_t *orq, sip_method_t m, char const *mname, | |||||
9721 | tag_type_t tag, tag_value_t value, ...) | |||||
9722 | { | |||||
9723 | msg_t *msg = nta_msg_create(orq->orq_agent, 0); | |||||
9724 | su_home_t *home = msg_home(msg)((su_home_t*)(msg)); | |||||
9725 | sip_t *sip = sip_object(msg); | |||||
9726 | sip_t *old = sip_object(orq->orq_request); | |||||
9727 | sip_via_t via[1]; | |||||
9728 | ||||||
9729 | if (!sip) | |||||
9730 | return NULL((void*)0); | |||||
9731 | ||||||
9732 | if (tag) { | |||||
9733 | ta_list ta; | |||||
9734 | ||||||
9735 | ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value = (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag ) == tag_next && (ta_start__value) != 0) { ta_start__tag = ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag == tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag == tag_next) { ta_start__value = ((tagi_t *)ta_start__value) ->t_value; } else { ta_start__tag = tag_next; break; } } ( ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value ; if (ta_start__tag != ((void*)0) && ta_start__tag != tag_null && ta_start__tag != tag_next) { va_list ta_start__ap ; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag = tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap ); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value = 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0); | |||||
9736 | ||||||
9737 | sip_add_tl(msg, sip, ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta). tl[1].t_value); | |||||
9738 | /* Bug sf.net # 173323: | |||||
9739 | * Ensure that request-URI, topmost Via, From, To, Call-ID, CSeq, | |||||
9740 | * Max-Forward, Route, Accept-Contact, Reject-Contact and | |||||
9741 | * Request-Disposition are copied from original request | |||||
9742 | */ | |||||
9743 | if (sip->sip_from) | |||||
9744 | sip_header_remove(msg, sip, (void *)sip->sip_from); | |||||
9745 | if (sip->sip_to && m != sip_method_ack) | |||||
9746 | sip_header_remove(msg, sip, (void *)sip->sip_to); | |||||
9747 | if (sip->sip_call_id) | |||||
9748 | sip_header_remove(msg, sip, (void *)sip->sip_call_id); | |||||
9749 | while (sip->sip_route) | |||||
9750 | sip_header_remove(msg, sip, (void *)sip->sip_route); | |||||
9751 | while (sip->sip_accept_contact) | |||||
9752 | sip_header_remove(msg, sip, (void *)sip->sip_accept_contact); | |||||
9753 | while (sip->sip_reject_contact) | |||||
9754 | sip_header_remove(msg, sip, (void *)sip->sip_reject_contact); | |||||
9755 | if (sip->sip_request_disposition) | |||||
9756 | sip_header_remove(msg, sip, (void *)sip->sip_request_disposition); | |||||
9757 | while (sip->sip_via) | |||||
9758 | sip_header_remove(msg, sip, (void *)sip->sip_via); | |||||
9759 | if (sip->sip_max_forwards) | |||||
9760 | sip_header_remove(msg, sip, (void *)sip->sip_max_forwards); | |||||
9761 | ||||||
9762 | ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value ))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta) .ap)); | |||||
9763 | } | |||||
9764 | ||||||
9765 | sip->sip_request = | |||||
9766 | sip_request_create(home, m, mname, (url_string_t *)orq->orq_url, NULL((void*)0)); | |||||
9767 | ||||||
9768 | if (sip->sip_to == NULL((void*)0)) | |||||
9769 | sip_add_dup(msg, sip, (sip_header_t *)old->sip_to); | |||||
9770 | sip_add_dup(msg, sip, (sip_header_t *)old->sip_from); | |||||
9771 | sip_add_dup(msg, sip, (sip_header_t *)old->sip_call_id); | |||||
9772 | sip_add_dup(msg, sip, (sip_header_t *)old->sip_route); | |||||
9773 | /* @RFC3841. Bug #1326727. */ | |||||
9774 | sip_add_dup(msg, sip, (sip_header_t *)old->sip_accept_contact); | |||||
9775 | sip_add_dup(msg, sip, (sip_header_t *)old->sip_reject_contact); | |||||
9776 | sip_add_dup(msg, sip, (sip_header_t *)old->sip_request_disposition); | |||||
9777 | sip_add_dup(msg, sip, (sip_header_t *)old->sip_max_forwards); | |||||
9778 | ||||||
9779 | if (old->sip_via) { | |||||
9780 | /* Add only the topmost Via header */ | |||||
9781 | *via = *old->sip_via; via->v_next = NULL((void*)0); | |||||
9782 | sip_add_dup(msg, sip, (sip_header_t *)via); | |||||
9783 | } | |||||
9784 | ||||||
9785 | sip->sip_cseq = sip_cseq_create(home, old->sip_cseq->cs_seq, m, mname); | |||||
9786 | ||||||
9787 | if (sip->sip_request && | |||||
9788 | sip->sip_to && | |||||
9789 | sip->sip_from && | |||||
9790 | sip->sip_call_id && | |||||
9791 | (!old->sip_route || sip->sip_route) && | |||||
9792 | sip->sip_cseq) | |||||
9793 | return msg; | |||||
9794 | ||||||
9795 | msg_destroy(msg); | |||||
9796 | ||||||
9797 | return NULL((void*)0); | |||||
9798 | } | |||||
9799 | ||||||
9800 | static | |||||
9801 | void outgoing_delayed_recv(su_root_magic_t *rm, | |||||
9802 | su_msg_r msg, | |||||
9803 | union sm_arg_u *u); | |||||
9804 | ||||||
9805 | /** Respond internally to a transaction. */ | |||||
9806 | int outgoing_reply(nta_outgoing_t *orq, int status, char const *phrase, | |||||
9807 | int delayed) | |||||
9808 | { | |||||
9809 | nta_agent_t *agent = orq->orq_agent; | |||||
9810 | msg_t *msg = NULL((void*)0); | |||||
9811 | sip_t *sip = NULL((void*)0); | |||||
9812 | ||||||
9813 | assert(status == 202 || status >= 400)((void) sizeof ((status == 202 || status >= 400) ? 1 : 0), __extension__ ({ if (status == 202 || status >= 400) ; else __assert_fail ("status == 202 || status >= 400", "nta.c", 9813, __extension__ __PRETTY_FUNCTION__); })); | |||||
9814 | ||||||
9815 | if (orq->orq_pending) | |||||
9816 | tport_release(orq->orq_tport, orq->orq_pending, | |||||
9817 | orq->orq_request, NULL((void*)0), orq, 0); | |||||
9818 | orq->orq_pending = 0; | |||||
9819 | ||||||
9820 | orq->orq_delayed = 0; | |||||
9821 | ||||||
9822 | if (orq->orq_method == sip_method_ack) { | |||||
9823 | if (status != delayed) | |||||
9824 | SU_DEBUG_3(("nta(%p): responding %u %s to ACK!\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 9825, "nta(%p): responding %u %s to ACK!\n", (void *)orq, status , phrase)) : (void)0) | |||||
9825 | (void *)orq, status, phrase))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 9825, "nta(%p): responding %u %s to ACK!\n", (void *)orq, status , phrase)) : (void)0); | |||||
9826 | orq->orq_status = status; | |||||
9827 | if (orq->orq_queue == NULL((void*)0)) | |||||
9828 | outgoing_trying(orq); /* Timer F */ | |||||
9829 | return 0; | |||||
9830 | } | |||||
9831 | ||||||
9832 | if (orq->orq_destroyed) { | |||||
9833 | if (orq->orq_status < 200) | |||||
9834 | orq->orq_status = status; | |||||
9835 | outgoing_complete(orq); /* Timer D / Timer K */ | |||||
9836 | return 0; | |||||
9837 | } | |||||
9838 | ||||||
9839 | if (orq->orq_stateless) | |||||
9840 | ; | |||||
9841 | else if (orq->orq_queue == NULL((void*)0) || | |||||
9842 | orq->orq_queue == orq->orq_agent->sa_out.resolving || | |||||
9843 | orq->orq_queue == orq->orq_agent->sa_out.delayed) | |||||
9844 | outgoing_trying(orq); | |||||
9845 | ||||||
9846 | /** Insert a dummy Via header */ | |||||
9847 | if (!orq->orq_prepared) { | |||||
9848 | tport_t *tp = tport_primaries(orq->orq_agent->sa_tports); | |||||
9849 | outgoing_insert_via(orq, agent_tport_via(tp)); | |||||
9850 | } | |||||
9851 | ||||||
9852 | /* Create response message, if needed */ | |||||
9853 | if (!orq->orq_stateless && | |||||
9854 | !(orq->orq_callback == outgoing_default_cb) && | |||||
9855 | !(status == 408 && | |||||
9856 | orq->orq_method != sip_method_invite && | |||||
9857 | !orq->orq_agent->sa_timeout_408)) { | |||||
9858 | char const *to_tag; | |||||
9859 | ||||||
9860 | msg = nta_msg_create(agent, NTA_INTERNAL_MSG(1<<15)); | |||||
9861 | ||||||
9862 | if (complete_response(msg, status, phrase, orq->orq_request) < 0) { | |||||
9863 | assert(!"complete message")((void) sizeof ((!"complete message") ? 1 : 0), __extension__ ({ if (!"complete message") ; else __assert_fail ("!\"complete message\"" , "nta.c", 9863, __extension__ __PRETTY_FUNCTION__); })); | |||||
9864 | return -1; | |||||
9865 | } | |||||
9866 | ||||||
9867 | sip = sip_object(msg); assert(sip->sip_flags & NTA_INTERNAL_MSG)((void) sizeof ((sip->sip_flags & (1<<15)) ? 1 : 0), __extension__ ({ if (sip->sip_flags & (1<<15 )) ; else __assert_fail ("sip->sip_flags & NTA_INTERNAL_MSG" , "nta.c", 9867, __extension__ __PRETTY_FUNCTION__); })); | |||||
9868 | to_tag = nta_agent_newtag(msg_home(msg)((su_home_t*)(msg)), "tag=%s", agent); | |||||
9869 | ||||||
9870 | if (status > 100 && | |||||
9871 | sip->sip_to && !sip->sip_to->a_tag && | |||||
9872 | sip->sip_cseq->cs_method != sip_method_cancel && | |||||
9873 | sip_to_tag(msg_home(msg)((su_home_t*)(msg)), sip->sip_to, to_tag) < 0) { | |||||
9874 | assert(!"adding tag")((void) sizeof ((!"adding tag") ? 1 : 0), __extension__ ({ if (!"adding tag") ; else __assert_fail ("!\"adding tag\"", "nta.c" , 9874, __extension__ __PRETTY_FUNCTION__); })); | |||||
9875 | return -1; | |||||
9876 | } | |||||
9877 | ||||||
9878 | if (status > 400 && agent->sa_blacklist) { | |||||
9879 | sip_retry_after_t af[1]; | |||||
9880 | sip_retry_after_init(af)->af_delta = agent->sa_blacklist; | |||||
9881 | ||||||
9882 | sip_add_dup(msg, sip, (sip_header_t *)af); | |||||
9883 | } | |||||
9884 | } | |||||
9885 | ||||||
9886 | if (orq->orq_inserted && !delayed) { | |||||
9887 | outgoing_recv(orq, status, msg, sip); | |||||
9888 | return 0; | |||||
9889 | } | |||||
9890 | else if (orq->orq_stateless && orq->orq_callback == outgoing_default_cb) { | |||||
9891 | /* Xyzzy */ | |||||
9892 | orq->orq_status = status; | |||||
9893 | outgoing_complete(orq); | |||||
9894 | } | |||||
9895 | else { | |||||
9896 | /* | |||||
9897 | * The thread creating outgoing transaction must return to application | |||||
9898 | * before transaction callback can be invoked. Therefore processing an | |||||
9899 | * internally generated response message must be delayed until | |||||
9900 | * transaction creation is completed. | |||||
9901 | * | |||||
9902 | * The internally generated message is transmitted using su_msg_send() | |||||
9903 | * and it is delivered back to NTA when the application next time | |||||
9904 | * executes the su_root_t event loop. | |||||
9905 | */ | |||||
9906 | nta_agent_t *agent = orq->orq_agent; | |||||
9907 | su_root_t *root = agent->sa_root; | |||||
9908 | su_msg_r su_msg = SU_MSG_R_INIT{ ((void*)0) }; | |||||
9909 | ||||||
9910 | if (su_msg_create(su_msg, | |||||
9911 | su_root_task(root), | |||||
9912 | su_root_task(root), | |||||
9913 | outgoing_delayed_recv, | |||||
9914 | sizeof(struct outgoing_recv_s)) == SU_SUCCESSsu_success) { | |||||
9915 | struct outgoing_recv_s *a = su_msg_data(su_msg)->a_outgoing_recv; | |||||
9916 | ||||||
9917 | a->orq = orq; | |||||
9918 | a->msg = msg; | |||||
9919 | a->sip = sip; | |||||
9920 | a->status = status; | |||||
9921 | ||||||
9922 | orq->orq_status2b = &a->status; | |||||
9923 | ||||||
9924 | if (su_msg_send(su_msg) == SU_SUCCESSsu_success) { | |||||
9925 | return 0; | |||||
9926 | } | |||||
9927 | } | |||||
9928 | } | |||||
9929 | ||||||
9930 | if (msg) | |||||
9931 | msg_destroy(msg); | |||||
9932 | ||||||
9933 | return -1; | |||||
9934 | } | |||||
9935 | ||||||
9936 | static | |||||
9937 | void outgoing_delayed_recv(su_root_magic_t *rm, | |||||
9938 | su_msg_r msg, | |||||
9939 | union sm_arg_u *u) | |||||
9940 | { | |||||
9941 | struct outgoing_recv_s *a = u->a_outgoing_recv; | |||||
9942 | ||||||
9943 | if (a->status > 0) { | |||||
9944 | a->orq->orq_status2b = 0; | |||||
9945 | if (outgoing_recv(a->orq, a->status, a->msg, a->sip) >= 0) | |||||
9946 | return; | |||||
9947 | } | |||||
9948 | ||||||
9949 | msg_destroy(a->msg); | |||||
9950 | } | |||||
9951 | ||||||
9952 | ||||||
9953 | /* ====================================================================== */ | |||||
9954 | /* 9) Resolving (SIP) URL */ | |||||
9955 | ||||||
9956 | #if HAVE_SOFIA_SRESOLV1 | |||||
9957 | ||||||
9958 | struct sipdns_query; | |||||
9959 | ||||||
9960 | /** DNS resolving for (SIP) URLs */ | |||||
9961 | struct sipdns_resolver | |||||
9962 | { | |||||
9963 | tp_name_t sr_tpn[1]; /**< Copy of original transport name */ | |||||
9964 | sres_query_t *sr_query; /**< Current DNS Query */ | |||||
9965 | char const *sr_target; /**< Target for current query */ | |||||
9966 | ||||||
9967 | struct sipdns_query *sr_current; /**< Current query (with results) */ | |||||
9968 | char **sr_results; /**< A/AAAA results to be used */ | |||||
9969 | ||||||
9970 | struct sipdns_query *sr_head; /**< List of intermediate results */ | |||||
9971 | struct sipdns_query **sr_tail; /**< End of intermediate result list */ | |||||
9972 | ||||||
9973 | struct sipdns_query *sr_done; /**< Completed intermediate results */ | |||||
9974 | ||||||
9975 | struct sipdns_tport const *sr_tport; /**< Selected transport */ | |||||
9976 | ||||||
9977 | /** Transports to consider for this request */ | |||||
9978 | struct sipdns_tport const *sr_tports[SIPDNS_TRANSPORTS(6) + 1]; | |||||
9979 | ||||||
9980 | uint16_t sr_a_aaaa1, sr_a_aaaa2; /**< Order of A and/or AAAA queries. */ | |||||
9981 | ||||||
9982 | unsigned | |||||
9983 | sr_use_naptr:1, | |||||
9984 | sr_use_srv:1, | |||||
9985 | sr_use_a_aaaa:1; | |||||
9986 | }; | |||||
9987 | ||||||
9988 | /** Intermediate queries */ | |||||
9989 | struct sipdns_query | |||||
9990 | { | |||||
9991 | struct sipdns_query *sq_next; | |||||
9992 | ||||||
9993 | char const *sq_proto; | |||||
9994 | char const *sq_domain; | |||||
9995 | char sq_port[6]; /* port number */ | |||||
9996 | uint16_t sq_otype; /* origin type of query data (0 means request) */ | |||||
9997 | uint16_t sq_type; /* query type */ | |||||
9998 | uint16_t sq_priority; /* priority or preference */ | |||||
9999 | uint16_t sq_weight; /* preference or weight */ | |||||
10000 | uint16_t sq_grayish; /* candidate for graylisting */ | |||||
10001 | }; | |||||
10002 | ||||||
10003 | static int outgoing_resolve_next(nta_outgoing_t *orq); | |||||
10004 | static int outgoing_resolving(nta_outgoing_t *orq); | |||||
10005 | static int outgoing_resolving_error(nta_outgoing_t *, | |||||
10006 | int status, char const *phrase); | |||||
10007 | static void outgoing_graylist(nta_outgoing_t *orq, struct sipdns_query *sq); | |||||
10008 | static int outgoing_query_naptr(nta_outgoing_t *orq, char const *domain); | |||||
10009 | static void outgoing_answer_naptr(sres_context_t *orq, sres_query_t *q, | |||||
10010 | sres_record_t *answers[]); | |||||
10011 | struct sipdns_tport const *outgoing_naptr_tport(nta_outgoing_t *orq, | |||||
10012 | sres_record_t *answers[]); | |||||
10013 | ||||||
10014 | static int outgoing_make_srv_query(nta_outgoing_t *orq); | |||||
10015 | static int outgoing_make_a_aaaa_query(nta_outgoing_t *orq); | |||||
10016 | ||||||
10017 | static void outgoing_query_all(nta_outgoing_t *orq); | |||||
10018 | ||||||
10019 | static int outgoing_query_srv(nta_outgoing_t *orq, struct sipdns_query *); | |||||
10020 | static void outgoing_answer_srv(sres_context_t *orq, sres_query_t *q, | |||||
10021 | sres_record_t *answers[]); | |||||
10022 | ||||||
10023 | #if SU_HAVE_IN61 | |||||
10024 | static int outgoing_query_aaaa(nta_outgoing_t *orq, struct sipdns_query *); | |||||
10025 | static void outgoing_answer_aaaa(sres_context_t *orq, sres_query_t *q, | |||||
10026 | sres_record_t *answers[]); | |||||
10027 | #endif | |||||
10028 | ||||||
10029 | static int outgoing_query_a(nta_outgoing_t *orq, struct sipdns_query *); | |||||
10030 | static void outgoing_answer_a(sres_context_t *orq, sres_query_t *q, | |||||
10031 | sres_record_t *answers[]); | |||||
10032 | ||||||
10033 | #ifdef __clang_analyzer__1 | |||||
10034 | #define FUNC_ATTR_NONNULL(...)__attribute__((nonnull(...))) __attribute__((nonnull(__VA_ARGS__))) | |||||
10035 | #else | |||||
10036 | #define FUNC_ATTR_NONNULL(...)__attribute__((nonnull(...))) | |||||
10037 | #endif | |||||
10038 | ||||||
10039 | static void outgoing_query_results(nta_outgoing_t *orq, | |||||
10040 | struct sipdns_query *sq, | |||||
10041 | char *results[], | |||||
10042 | size_t rlen) FUNC_ATTR_NONNULL(3)__attribute__((nonnull(3))); | |||||
10043 | ||||||
10044 | ||||||
10045 | #define SIPDNS_503_ERROR503, "DNS Error" 503, "DNS Error" | |||||
10046 | ||||||
10047 | /** Resolve a request destination */ | |||||
10048 | static void | |||||
10049 | outgoing_resolve(nta_outgoing_t *orq, | |||||
10050 | int explicit_transport, | |||||
10051 | enum nta_res_order_e res_order) | |||||
10052 | { | |||||
10053 | struct sipdns_resolver *sr = NULL((void*)0); | |||||
10054 | char const *tpname = orq->orq_tpn->tpn_proto; | |||||
10055 | int tport_known = strcmp(tpname, "*") != 0; | |||||
10056 | ||||||
10057 | if (orq->orq_agent->sa_resolver) | |||||
10058 | orq->orq_resolver = sr = su_zalloc(orq->orq_agent->sa_home, (sizeof *sr)); | |||||
10059 | ||||||
10060 | if (!sr) { | |||||
10061 | outgoing_resolving_error(orq, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error); | |||||
10062 | return; | |||||
10063 | } | |||||
10064 | ||||||
10065 | *sr->sr_tpn = *orq->orq_tpn; | |||||
10066 | sr->sr_use_srv = orq->orq_agent->sa_use_srv; | |||||
10067 | sr->sr_use_naptr = orq->orq_agent->sa_use_naptr && sr->sr_use_srv; | |||||
10068 | sr->sr_use_a_aaaa = 1; | |||||
10069 | sr->sr_tail = &sr->sr_head; | |||||
10070 | ||||||
10071 | /* RFC 3263: | |||||
10072 | If the TARGET was not a numeric IP address, but a port is present in | |||||
10073 | the URI, the client performs an A or AAAA record lookup of the domain | |||||
10074 | name. The result will be a list of IP addresses, each of which can | |||||
10075 | be contacted at the specific port from the URI and transport protocol | |||||
10076 | determined previously. The client SHOULD try the first record. If | |||||
10077 | an attempt should fail, based on the definition of failure in Section | |||||
10078 | 4.3, the next SHOULD be tried, and if that should fail, the next | |||||
10079 | SHOULD be tried, and so on. | |||||
10080 | ||||||
10081 | This is a change from RFC 2543. Previously, if the port was | |||||
10082 | explicit, but with a value of 5060, SRV records were used. Now, A | |||||
10083 | or AAAA records will be used. | |||||
10084 | */ | |||||
10085 | if (sr->sr_tpn->tpn_port) | |||||
10086 | sr->sr_use_naptr = 0, sr->sr_use_srv = 0; | |||||
10087 | ||||||
10088 | /* RFC3263: | |||||
10089 | If [...] a transport was specified explicitly, the client performs an | |||||
10090 | SRV query for that specific transport, | |||||
10091 | */ | |||||
10092 | if (explicit_transport) | |||||
10093 | sr->sr_use_naptr = 0; | |||||
10094 | ||||||
10095 | { | |||||
10096 | /* Initialize sr_tports */ | |||||
10097 | tport_t *tport; | |||||
10098 | char const *ident = sr->sr_tpn->tpn_ident; | |||||
10099 | int i, j; | |||||
10100 | ||||||
10101 | for (tport = tport_primary_by_name(orq->orq_agent->sa_tports, orq->orq_tpn); | |||||
10102 | tport; | |||||
10103 | tport = tport_next(tport)) { | |||||
10104 | tp_name_t const *tpn = tport_name(tport); | |||||
10105 | if (tport_known && !su_casematch(tpn->tpn_proto, tpname)) | |||||
10106 | continue; | |||||
10107 | if (ident && (tpn->tpn_ident == NULL((void*)0) || strcmp(ident, tpn->tpn_ident))) | |||||
10108 | continue; | |||||
10109 | ||||||
10110 | for (j = 0; j < SIPDNS_TRANSPORTS(6); j++) | |||||
10111 | if (su_casematch(tpn->tpn_proto, sipdns_tports[j].name)) | |||||
10112 | break; | |||||
10113 | ||||||
10114 | assert(j < SIPDNS_TRANSPORTS)((void) sizeof ((j < (6)) ? 1 : 0), __extension__ ({ if (j < (6)) ; else __assert_fail ("j < SIPDNS_TRANSPORTS", "nta.c" , 10114, __extension__ __PRETTY_FUNCTION__); })); | |||||
10115 | if (j == SIPDNS_TRANSPORTS(6)) | |||||
10116 | /* Someone added transport but did not update sipdns_tports */ | |||||
10117 | continue; | |||||
10118 | ||||||
10119 | for (i = 0; i < SIPDNS_TRANSPORTS(6); i++) { | |||||
10120 | if (sipdns_tports + j == sr->sr_tports[i] || sr->sr_tports[i] == NULL((void*)0)) | |||||
10121 | break; | |||||
10122 | } | |||||
10123 | sr->sr_tports[i] = sipdns_tports + j; | |||||
10124 | ||||||
10125 | if (tport_known) /* Looking for only one transport */ { | |||||
10126 | sr->sr_tport = sipdns_tports + j; | |||||
10127 | break; | |||||
10128 | } | |||||
10129 | } | |||||
10130 | ||||||
10131 | /* Nothing found */ | |||||
10132 | if (!sr->sr_tports[0]) { | |||||
10133 | SU_DEBUG_3(("nta(%p): transport %s is not supported%s%s\n", (void *)orq,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 10134, "nta(%p): transport %s is not supported%s%s\n", (void *)orq, tpname, ident ? " by interface " : "", ident ? ident : "")) : (void)0) | |||||
10134 | tpname, ident ? " by interface " : "", ident ? ident : ""))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 10134, "nta(%p): transport %s is not supported%s%s\n", (void *)orq, tpname, ident ? " by interface " : "", ident ? ident : "")) : (void)0); | |||||
10135 | outgoing_resolving_error(orq, SIPDNS_503_ERROR503, "DNS Error"); | |||||
10136 | return; | |||||
10137 | } | |||||
10138 | } | |||||
10139 | ||||||
10140 | switch (res_order) { | |||||
10141 | default: | |||||
10142 | case nta_res_ip6_ip4: | |||||
10143 | sr->sr_a_aaaa1 = sres_type_aaaa, sr->sr_a_aaaa2 = sres_type_a; | |||||
10144 | break; | |||||
10145 | case nta_res_ip4_ip6: | |||||
10146 | sr->sr_a_aaaa1 = sres_type_a, sr->sr_a_aaaa2 = sres_type_aaaa; | |||||
10147 | break; | |||||
10148 | case nta_res_ip6_only: | |||||
10149 | sr->sr_a_aaaa1 = sres_type_aaaa, sr->sr_a_aaaa2 = sres_type_aaaa; | |||||
10150 | break; | |||||
10151 | case nta_res_ip4_only: | |||||
10152 | sr->sr_a_aaaa1 = sres_type_a, sr->sr_a_aaaa2 = sres_type_a; | |||||
10153 | break; | |||||
10154 | } | |||||
10155 | ||||||
10156 | outgoing_resolve_next(orq); | |||||
10157 | } | |||||
10158 | ||||||
10159 | /** Resolve next destination. */ | |||||
10160 | static int | |||||
10161 | outgoing_resolve_next(nta_outgoing_t *orq) | |||||
10162 | { | |||||
10163 | struct sipdns_resolver *sr = orq->orq_resolver; | |||||
10164 | ||||||
10165 | if (sr == NULL((void*)0)) { | |||||
10166 | outgoing_resolving_error(orq, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error); | |||||
10167 | return 0; | |||||
10168 | } | |||||
10169 | ||||||
10170 | if (sr->sr_results) { | |||||
10171 | /* Use existing A/AAAA results */ | |||||
10172 | su_free(msg_home(orq->orq_request)((su_home_t*)(orq->orq_request)), sr->sr_results[0]); | |||||
10173 | sr->sr_results++; | |||||
10174 | if (sr->sr_results[0]) { | |||||
10175 | struct sipdns_query *sq = sr->sr_current; assert(sq)((void) sizeof ((sq) ? 1 : 0), __extension__ ({ if (sq) ; else __assert_fail ("sq", "nta.c", 10175, __extension__ __PRETTY_FUNCTION__ ); })); | |||||
10176 | ||||||
10177 | if (sq->sq_proto) | |||||
10178 | orq->orq_tpn->tpn_proto = sq->sq_proto; | |||||
10179 | if (sq->sq_port[0]) | |||||
10180 | orq->orq_tpn->tpn_port = sq->sq_port; | |||||
10181 | ||||||
10182 | orq->orq_tpn->tpn_host = sr->sr_results[0]; | |||||
10183 | ||||||
10184 | outgoing_reset_timer(orq); | |||||
10185 | outgoing_queue(orq->orq_agent->sa_out.resolving, orq); | |||||
10186 | outgoing_prepare_send(orq); | |||||
10187 | return 1; | |||||
10188 | } | |||||
10189 | else { | |||||
10190 | sr->sr_current = NULL((void*)0); | |||||
10191 | sr->sr_results = NULL((void*)0); | |||||
10192 | } | |||||
10193 | } | |||||
10194 | ||||||
10195 | if (sr->sr_head) | |||||
10196 | outgoing_query_all(orq); | |||||
10197 | else if (sr->sr_use_naptr) | |||||
10198 | outgoing_query_naptr(orq, sr->sr_tpn->tpn_host); /* NAPTR */ | |||||
10199 | else if (sr->sr_use_srv) | |||||
10200 | outgoing_make_srv_query(orq); /* SRV */ | |||||
10201 | else if (sr->sr_use_a_aaaa) | |||||
10202 | outgoing_make_a_aaaa_query(orq); /* A/AAAA */ | |||||
10203 | else | |||||
10204 | return outgoing_resolving_error(orq, SIPDNS_503_ERROR503, "DNS Error"); | |||||
10205 | ||||||
10206 | return 1; | |||||
10207 | } | |||||
10208 | ||||||
10209 | /** Check if can we retry other destinations? */ | |||||
10210 | static int | |||||
10211 | outgoing_other_destinations(nta_outgoing_t const *orq) | |||||
10212 | { | |||||
10213 | struct sipdns_resolver *sr = orq->orq_resolver; | |||||
10214 | ||||||
10215 | if (!sr) | |||||
10216 | return 0; | |||||
10217 | ||||||
10218 | if (sr->sr_use_a_aaaa || sr->sr_use_srv || sr->sr_use_naptr) | |||||
10219 | return 1; | |||||
10220 | ||||||
10221 | if (sr->sr_results && sr->sr_results[1]) | |||||
10222 | return 1; | |||||
10223 | ||||||
10224 | if (sr->sr_head) | |||||
10225 | return 1; | |||||
10226 | ||||||
10227 | return 0; | |||||
10228 | } | |||||
10229 | ||||||
10230 | /** Resolve a request destination */ | |||||
10231 | static int | |||||
10232 | outgoing_try_another(nta_outgoing_t *orq) | |||||
10233 | { | |||||
10234 | struct sipdns_resolver *sr = orq->orq_resolver; | |||||
10235 | ||||||
10236 | if (sr == NULL((void*)0)) | |||||
10237 | return 0; | |||||
10238 | ||||||
10239 | *orq->orq_tpn = *sr->sr_tpn; | |||||
10240 | orq->orq_try_tcp_instead = 0, orq->orq_try_udp_instead = 0; | |||||
10241 | outgoing_reset_timer(orq); | |||||
10242 | outgoing_queue(orq->orq_agent->sa_out.resolving, orq); | |||||
10243 | ||||||
10244 | if (orq->orq_status > 0) | |||||
10245 | /* PP: don't hack priority if a preliminary response has been received */ | |||||
10246 | ; | |||||
10247 | else if (orq->orq_agent->sa_graylist == 0) | |||||
10248 | /* PP: priority hacking disabled */ | |||||
10249 | ; | |||||
10250 | /* NetModule hack: | |||||
10251 | * Move server that did not work to end of queue in sres cache | |||||
10252 | * | |||||
10253 | * the next request does not try to use the server that is currently down | |||||
10254 | * | |||||
10255 | * @TODO: fix cases with only A or AAAA answering, or all servers down. | |||||
10256 | */ | |||||
10257 | else if (sr && sr->sr_target) { | |||||
10258 | struct sipdns_query *sq; | |||||
10259 | ||||||
10260 | /* find latest A/AAAA record */ | |||||
10261 | sq = sr->sr_head; | |||||
10262 | if (sq && sq->sq_type == sr->sr_a_aaaa2 && sr->sr_a_aaaa1 != sr->sr_a_aaaa2) { | |||||
10263 | sq->sq_grayish = 1; | |||||
10264 | } | |||||
10265 | else { | |||||
10266 | outgoing_graylist(orq, sr->sr_done); | |||||
10267 | } | |||||
10268 | } | |||||
10269 | ||||||
10270 | return outgoing_resolve_next(orq); | |||||
10271 | } | |||||
10272 | ||||||
10273 | /** Graylist SRV records */ | |||||
10274 | static void outgoing_graylist(nta_outgoing_t *orq, struct sipdns_query *sq) | |||||
10275 | { | |||||
10276 | struct sipdns_resolver *sr = orq->orq_resolver; | |||||
10277 | char const *target = sq->sq_domain, *proto = sq->sq_proto; | |||||
10278 | unsigned prio = sq->sq_priority, maxprio = prio; | |||||
10279 | ||||||
10280 | /* Don't know how to graylist but SRV records */ | |||||
10281 | if (sq->sq_otype != sres_type_srv) | |||||
10282 | return; | |||||
10283 | ||||||
10284 | SU_DEBUG_5(("nta: graylisting %s:%s;transport=%s\n", target, sq->sq_port, proto))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 10284, "nta: graylisting %s:%s;transport=%s\n", target, sq-> sq_port, proto)) : (void)0); | |||||
10285 | ||||||
10286 | for (sq = sr->sr_head; sq; sq = sq->sq_next) | |||||
10287 | if (sq->sq_otype == sres_type_srv && sq->sq_priority > maxprio) | |||||
10288 | maxprio = sq->sq_priority; | |||||
10289 | ||||||
10290 | for (sq = sr->sr_done; sq; sq = sq->sq_next) | |||||
10291 | if (sq->sq_otype == sres_type_srv && sq->sq_priority > maxprio) | |||||
10292 | maxprio = sq->sq_priority; | |||||
10293 | ||||||
10294 | for (sq = sr->sr_done; sq; sq = sq->sq_next) { | |||||
10295 | int modified; | |||||
10296 | ||||||
10297 | if (sq->sq_type != sres_type_srv || strcmp(proto, sq->sq_proto)) | |||||
10298 | continue; | |||||
10299 | ||||||
10300 | /* modify the SRV record(s) corresponding to the latest A/AAAA record */ | |||||
10301 | modified = sres_set_cached_srv_priority( | |||||
10302 | orq->orq_agent->sa_resolver, | |||||
10303 | sq->sq_domain, | |||||
10304 | target, | |||||
10305 | sq->sq_port[0] ? (uint16_t)strtoul(sq->sq_port, NULL((void*)0), 10) : 0, | |||||
10306 | orq->orq_agent->sa_graylist, | |||||
10307 | maxprio + 1); | |||||
10308 | ||||||
10309 | if (modified >= 0) | |||||
10310 | SU_DEBUG_3(("nta: reduced priority of %d %s SRV records (increase value to %u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 10311, "nta: reduced priority of %d %s SRV records (increase value to %u)\n" , modified, sq->sq_domain, maxprio + 1)) : (void)0) | |||||
10311 | modified, sq->sq_domain, maxprio + 1))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 10311, "nta: reduced priority of %d %s SRV records (increase value to %u)\n" , modified, sq->sq_domain, maxprio + 1)) : (void)0); | |||||
10312 | else | |||||
10313 | SU_DEBUG_3(("nta: failed to reduce %s SRV priority\n", sq->sq_domain))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 10313, "nta: failed to reduce %s SRV priority\n", sq->sq_domain )) : (void)0); | |||||
10314 | } | |||||
10315 | } | |||||
10316 | ||||||
10317 | /** Cancel resolver query */ | |||||
10318 | su_inlinestatic inline void outgoing_cancel_resolver(nta_outgoing_t *orq) | |||||
10319 | { | |||||
10320 | struct sipdns_resolver *sr = orq->orq_resolver; | |||||
10321 | ||||||
10322 | assert(orq->orq_resolver)((void) sizeof ((orq->orq_resolver) ? 1 : 0), __extension__ ({ if (orq->orq_resolver) ; else __assert_fail ("orq->orq_resolver" , "nta.c", 10322, __extension__ __PRETTY_FUNCTION__); })); | |||||
10323 | ||||||
10324 | if (sr->sr_query) /* Cancel resolver query */ | |||||
10325 | sres_query_bind(sr->sr_query, NULL((void*)0), NULL((void*)0)), sr->sr_query = NULL((void*)0); | |||||
10326 | } | |||||
10327 | ||||||
10328 | /** Destroy resolver */ | |||||
10329 | su_inlinestatic inline void outgoing_destroy_resolver(nta_outgoing_t *orq) | |||||
10330 | { | |||||
10331 | struct sipdns_resolver *sr = orq->orq_resolver; | |||||
10332 | ||||||
10333 | assert(orq->orq_resolver)((void) sizeof ((orq->orq_resolver) ? 1 : 0), __extension__ ({ if (orq->orq_resolver) ; else __assert_fail ("orq->orq_resolver" , "nta.c", 10333, __extension__ __PRETTY_FUNCTION__); })); | |||||
10334 | ||||||
10335 | outgoing_cancel_resolver(orq); | |||||
10336 | ||||||
10337 | su_free(orq->orq_agent->sa_home, sr); | |||||
10338 | ||||||
10339 | orq->orq_resolver = NULL((void*)0); | |||||
10340 | } | |||||
10341 | ||||||
10342 | /** Check if we are resolving. If not, return 503 response. */ | |||||
10343 | static | |||||
10344 | int outgoing_resolving(nta_outgoing_t *orq) | |||||
10345 | { | |||||
10346 | struct sipdns_resolver *sr = orq->orq_resolver; | |||||
10347 | ||||||
10348 | assert(orq->orq_resolver)((void) sizeof ((orq->orq_resolver) ? 1 : 0), __extension__ ({ if (orq->orq_resolver) ; else __assert_fail ("orq->orq_resolver" , "nta.c", 10348, __extension__ __PRETTY_FUNCTION__); })); | |||||
10349 | ||||||
10350 | if (!sr->sr_query) { | |||||
10351 | return outgoing_resolving_error(orq, SIPDNS_503_ERROR503, "DNS Error"); | |||||
10352 | } | |||||
10353 | else { | |||||
10354 | outgoing_queue(orq->orq_agent->sa_out.resolving, orq); | |||||
10355 | return 0; | |||||
10356 | } | |||||
10357 | } | |||||
10358 | ||||||
10359 | /** Return 503 response */ | |||||
10360 | static | |||||
10361 | int outgoing_resolving_error(nta_outgoing_t *orq, int status, char const *phrase) | |||||
10362 | { | |||||
10363 | orq->orq_resolved = 1; | |||||
10364 | outgoing_reply(orq, status, phrase, 0); | |||||
10365 | return -1; | |||||
10366 | } | |||||
10367 | ||||||
10368 | /* Query SRV records (with the given tport). */ | |||||
10369 | static | |||||
10370 | int outgoing_make_srv_query(nta_outgoing_t *orq) | |||||
10371 | { | |||||
10372 | struct sipdns_resolver *sr = orq->orq_resolver; | |||||
10373 | su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request)); | |||||
10374 | struct sipdns_query *sq; | |||||
10375 | char const *host, *prefix; | |||||
10376 | int i; | |||||
10377 | size_t hlen, plen; | |||||
10378 | ||||||
10379 | sr->sr_use_srv = 0; | |||||
10380 | ||||||
10381 | host = sr->sr_tpn->tpn_host; | |||||
10382 | hlen = strlen(host) + 1; | |||||
10383 | ||||||
10384 | for (i = 0; sr->sr_tports[i]; i++) { | |||||
10385 | if (sr->sr_tport && sr->sr_tports[i] != sr->sr_tport) | |||||
10386 | continue; | |||||
10387 | ||||||
10388 | prefix = sr->sr_tports[i]->prefix; | |||||
10389 | plen = strlen(prefix); | |||||
10390 | ||||||
10391 | sq = su_zalloc(home, (sizeof *sq) + plen + hlen); | |||||
10392 | if (sq) { | |||||
10393 | *sr->sr_tail = sq, sr->sr_tail = &sq->sq_next; | |||||
10394 | sq->sq_domain = memcpy(sq + 1, prefix, plen); | |||||
10395 | memcpy((char *)sq->sq_domain + plen, host, hlen); | |||||
10396 | sq->sq_proto = sr->sr_tports[i]->name; | |||||
10397 | sq->sq_type = sres_type_srv; | |||||
10398 | sq->sq_priority = 1; | |||||
10399 | sq->sq_weight = 1; | |||||
10400 | } | |||||
10401 | } | |||||
10402 | ||||||
10403 | outgoing_query_all(orq); | |||||
10404 | ||||||
10405 | return 0; | |||||
10406 | } | |||||
10407 | ||||||
10408 | /* Query A/AAAA records. */ | |||||
10409 | static | |||||
10410 | int outgoing_make_a_aaaa_query(nta_outgoing_t *orq) | |||||
10411 | { | |||||
10412 | struct sipdns_resolver *sr = orq->orq_resolver; | |||||
10413 | su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request)); | |||||
10414 | tp_name_t *tpn = orq->orq_tpn; | |||||
10415 | struct sipdns_query *sq; | |||||
10416 | ||||||
10417 | assert(sr)((void) sizeof ((sr) ? 1 : 0), __extension__ ({ if (sr) ; else __assert_fail ("sr", "nta.c", 10417, __extension__ __PRETTY_FUNCTION__ ); })); | |||||
10418 | ||||||
10419 | sr->sr_use_a_aaaa = 0; | |||||
10420 | ||||||
10421 | sq = su_zalloc(home, 2 * (sizeof *sq)); | |||||
10422 | if (!sq) | |||||
10423 | return outgoing_resolving(orq); | |||||
10424 | ||||||
10425 | sq->sq_type = sr->sr_a_aaaa1; | |||||
10426 | sq->sq_domain = tpn->tpn_host; | |||||
10427 | sq->sq_priority = 1; | |||||
10428 | ||||||
10429 | /* Append */ | |||||
10430 | *sr->sr_tail = sq, sr->sr_tail = &sq->sq_next; | |||||
10431 | ||||||
10432 | outgoing_query_all(orq); | |||||
10433 | ||||||
10434 | return 0; | |||||
10435 | } | |||||
10436 | ||||||
10437 | ||||||
10438 | /** Start SRV/A/AAAA queries */ | |||||
10439 | static | |||||
10440 | void outgoing_query_all(nta_outgoing_t *orq) | |||||
10441 | { | |||||
10442 | struct sipdns_resolver *sr = orq->orq_resolver; | |||||
10443 | struct sipdns_query *sq = sr->sr_head; | |||||
10444 | ||||||
10445 | if (sq == NULL((void*)0)) { | |||||
10446 | outgoing_resolving_error(orq, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error); | |||||
10447 | return; | |||||
10448 | } | |||||
10449 | ||||||
10450 | /* Remove from intermediate list */ | |||||
10451 | if (!(sr->sr_head = sq->sq_next)) | |||||
10452 | sr->sr_tail = &sr->sr_head; | |||||
10453 | ||||||
10454 | if (sq->sq_type == sres_type_srv) | |||||
10455 | outgoing_query_srv(orq, sq); | |||||
10456 | #if SU_HAVE_IN61 | |||||
10457 | else if (sq->sq_type == sres_type_aaaa) | |||||
10458 | outgoing_query_aaaa(orq, sq); | |||||
10459 | #endif | |||||
10460 | else if (sq->sq_type == sres_type_a) | |||||
10461 | outgoing_query_a(orq, sq); | |||||
10462 | else | |||||
10463 | outgoing_resolving_error(orq, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error); | |||||
10464 | } | |||||
10465 | ||||||
10466 | /** Query NAPTR record. */ | |||||
10467 | static | |||||
10468 | int outgoing_query_naptr(nta_outgoing_t *orq, char const *domain) | |||||
10469 | { | |||||
10470 | struct sipdns_resolver *sr = orq->orq_resolver; | |||||
10471 | sres_record_t **answers; | |||||
10472 | ||||||
10473 | sr->sr_use_naptr = 0; | |||||
10474 | ||||||
10475 | sr->sr_target = domain; | |||||
10476 | ||||||
10477 | answers = sres_cached_answers(orq->orq_agent->sa_resolver, | |||||
10478 | sres_type_naptr, domain); | |||||
10479 | ||||||
10480 | SU_DEBUG_5(("nta: for \"%s\" query \"%s\" %s%s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 10482, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn ->tpn_host, domain, "NAPTR", answers ? " (cached)" : "")) : (void)0) | |||||
10481 | orq->orq_tpn->tpn_host, domain, "NAPTR",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 10482, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn ->tpn_host, domain, "NAPTR", answers ? " (cached)" : "")) : (void)0) | |||||
10482 | answers ? " (cached)" : ""))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 10482, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn ->tpn_host, domain, "NAPTR", answers ? " (cached)" : "")) : (void)0); | |||||
10483 | ||||||
10484 | if (answers) { | |||||
10485 | outgoing_answer_naptr(orq, NULL((void*)0), answers); | |||||
10486 | return 0; | |||||
10487 | } | |||||
10488 | else { | |||||
10489 | sr->sr_query = sres_query(orq->orq_agent->sa_resolver, | |||||
10490 | outgoing_answer_naptr, orq, | |||||
10491 | sres_type_naptr, domain); | |||||
10492 | return outgoing_resolving(orq); | |||||
10493 | } | |||||
10494 | } | |||||
10495 | ||||||
10496 | /* Process NAPTR records */ | |||||
10497 | static | |||||
10498 | void outgoing_answer_naptr(sres_context_t *orq, | |||||
10499 | sres_query_t *q, | |||||
10500 | sres_record_t *answers[]) | |||||
10501 | { | |||||
10502 | int i, order = -1; | |||||
10503 | size_t rlen; | |||||
10504 | su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request)); | |||||
10505 | struct sipdns_resolver *sr = orq->orq_resolver; | |||||
10506 | tp_name_t tpn[1]; | |||||
10507 | struct sipdns_query *sq, *selected = NULL((void*)0), **tail = &selected, **at; | |||||
10508 | ||||||
10509 | assert(sr)((void) sizeof ((sr) ? 1 : 0), __extension__ ({ if (sr) ; else __assert_fail ("sr", "nta.c", 10509, __extension__ __PRETTY_FUNCTION__ ); })); | |||||
10510 | ||||||
10511 | sr->sr_query = NULL((void*)0); | |||||
10512 | ||||||
10513 | *tpn = *sr->sr_tpn; | |||||
10514 | ||||||
10515 | /* The NAPTR results are sorted first by Order then by Preference */ | |||||
10516 | sres_sort_answers(orq->orq_agent->sa_resolver, answers); | |||||
10517 | ||||||
10518 | if (sr->sr_tport == NULL((void*)0)) | |||||
10519 | sr->sr_tport = outgoing_naptr_tport(orq, answers); | |||||
10520 | ||||||
10521 | for (i = 0; answers && answers[i]; i++) { | |||||
10522 | sres_naptr_record_t const *na = answers[i]->sr_naptr; | |||||
10523 | uint16_t type; | |||||
10524 | int valid_tport; | |||||
10525 | ||||||
10526 | if (na->na_record->r_status) | |||||
10527 | continue; | |||||
10528 | if (na->na_record->r_type != sres_type_naptr) | |||||
10529 | continue; | |||||
10530 | ||||||
10531 | /* Check if NAPTR matches our target */ | |||||
10532 | if (!su_casenmatch(na->na_services, "SIP+", 4) && | |||||
10533 | !su_casenmatch(na->na_services, "SIPS+", 5)) | |||||
10534 | /* Not a SIP/SIPS service */ | |||||
10535 | continue; | |||||
10536 | ||||||
10537 | /* Use NAPTR results, don't try extra SRV/A/AAAA records */ | |||||
10538 | sr->sr_use_srv = 0, sr->sr_use_a_aaaa = 0; | |||||
10539 | ||||||
10540 | valid_tport = sr->sr_tport && | |||||
10541 | su_casematch(na->na_services, sr->sr_tport->service); | |||||
10542 | ||||||
10543 | SU_DEBUG_5(("nta: %s IN NAPTR %u %u \"%s\" \"%s\" \"%s\" %s%s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 10549, "nta: %s IN NAPTR %u %u \"%s\" \"%s\" \"%s\" %s%s\n" , na->na_record->r_name, na->na_order, na->na_prefer , na->na_flags, na->na_services, na->na_regexp, na-> na_replace, order >= 0 && order != na->na_order ? " (out of order)" : valid_tport ? "" : " (tport not used)" )) : (void)0) | |||||
10544 | na->na_record->r_name,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 10549, "nta: %s IN NAPTR %u %u \"%s\" \"%s\" \"%s\" %s%s\n" , na->na_record->r_name, na->na_order, na->na_prefer , na->na_flags, na->na_services, na->na_regexp, na-> na_replace, order >= 0 && order != na->na_order ? " (out of order)" : valid_tport ? "" : " (tport not used)" )) : (void)0) | |||||
10545 | na->na_order, na->na_prefer,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 10549, "nta: %s IN NAPTR %u %u \"%s\" \"%s\" \"%s\" %s%s\n" , na->na_record->r_name, na->na_order, na->na_prefer , na->na_flags, na->na_services, na->na_regexp, na-> na_replace, order >= 0 && order != na->na_order ? " (out of order)" : valid_tport ? "" : " (tport not used)" )) : (void)0) | |||||
10546 | na->na_flags, na->na_services,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 10549, "nta: %s IN NAPTR %u %u \"%s\" \"%s\" \"%s\" %s%s\n" , na->na_record->r_name, na->na_order, na->na_prefer , na->na_flags, na->na_services, na->na_regexp, na-> na_replace, order >= 0 && order != na->na_order ? " (out of order)" : valid_tport ? "" : " (tport not used)" )) : (void)0) | |||||
10547 | na->na_regexp, na->na_replace,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 10549, "nta: %s IN NAPTR %u %u \"%s\" \"%s\" \"%s\" %s%s\n" , na->na_record->r_name, na->na_order, na->na_prefer , na->na_flags, na->na_services, na->na_regexp, na-> na_replace, order >= 0 && order != na->na_order ? " (out of order)" : valid_tport ? "" : " (tport not used)" )) : (void)0) | |||||
10548 | order >= 0 && order != na->na_order ? " (out of order)" :(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 10549, "nta: %s IN NAPTR %u %u \"%s\" \"%s\" \"%s\" %s%s\n" , na->na_record->r_name, na->na_order, na->na_prefer , na->na_flags, na->na_services, na->na_regexp, na-> na_replace, order >= 0 && order != na->na_order ? " (out of order)" : valid_tport ? "" : " (tport not used)" )) : (void)0) | |||||
10549 | valid_tport ? "" : " (tport not used)"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 10549, "nta: %s IN NAPTR %u %u \"%s\" \"%s\" \"%s\" %s%s\n" , na->na_record->r_name, na->na_order, na->na_prefer , na->na_flags, na->na_services, na->na_regexp, na-> na_replace, order >= 0 && order != na->na_order ? " (out of order)" : valid_tport ? "" : " (tport not used)" )) : (void)0); | |||||
10550 | ||||||
10551 | /* RFC 2915 p 4: | |||||
10552 | * Order | |||||
10553 | * A 16-bit unsigned integer specifying the order in which the | |||||
10554 | * NAPTR records MUST be processed to ensure the correct ordering | |||||
10555 | * of rules. Low numbers are processed before high numbers, and | |||||
10556 | * once a NAPTR is found whose rule "matches" the target, the | |||||
10557 | * client MUST NOT consider any NAPTRs with a higher value for | |||||
10558 | * order (except as noted below for the Flags field). | |||||
10559 | */ | |||||
10560 | if (order >= 0 && order != na->na_order) | |||||
10561 | continue; | |||||
10562 | if (!valid_tport) | |||||
10563 | continue; | |||||
10564 | ||||||
10565 | /* OK, we found matching NAPTR */ | |||||
10566 | order = na->na_order; | |||||
10567 | ||||||
10568 | /* | |||||
10569 | * The "S" flag means that the next lookup should be for SRV records | |||||
10570 | * ... "A" means that the next lookup should be for either an A, AAAA, | |||||
10571 | * or A6 record. | |||||
10572 | */ | |||||
10573 | if (na->na_flags[0] == 's' || na->na_flags[0] == 'S') | |||||
10574 | type = sres_type_srv; /* SRV */ | |||||
10575 | else if (na->na_flags[0] == 'a' || na->na_flags[0] == 'A') | |||||
10576 | type = sr->sr_a_aaaa1; /* A / AAAA */ | |||||
10577 | else | |||||
10578 | continue; | |||||
10579 | ||||||
10580 | rlen = strlen(na->na_replace) + 1; | |||||
10581 | sq = su_zalloc(home, (sizeof *sq) + rlen); | |||||
10582 | ||||||
10583 | if (sq == NULL((void*)0)) | |||||
10584 | continue; | |||||
10585 | ||||||
10586 | *tail = sq, tail = &sq->sq_next; | |||||
10587 | sq->sq_otype = sres_type_naptr; | |||||
10588 | sq->sq_priority = na->na_prefer; | |||||
10589 | sq->sq_weight = 1; | |||||
10590 | sq->sq_type = type; | |||||
10591 | sq->sq_domain = memcpy(sq + 1, na->na_replace, rlen); | |||||
10592 | sq->sq_proto = sr->sr_tport->name; | |||||
10593 | } | |||||
10594 | ||||||
10595 | sres_free_answers(orq->orq_agent->sa_resolver, answers); | |||||
10596 | ||||||
10597 | /* RFC2915: | |||||
10598 | Preference [...] specifies the order in which NAPTR | |||||
10599 | records with equal "order" values SHOULD be processed, low | |||||
10600 | numbers being processed before high numbers. */ | |||||
10601 | at = sr->sr_tail; | |||||
10602 | while (selected) { | |||||
10603 | sq = selected, selected = sq->sq_next; | |||||
10604 | ||||||
10605 | for (tail = at; *tail; tail = &(*tail)->sq_next) { | |||||
10606 | if (sq->sq_priority < (*tail)->sq_priority) | |||||
10607 | break; | |||||
10608 | if (sq->sq_priority == (*tail)->sq_priority && | |||||
10609 | sq->sq_weight < (*tail)->sq_weight) | |||||
10610 | break; | |||||
10611 | } | |||||
10612 | /* Insert */ | |||||
10613 | sq->sq_next = *tail, *tail = sq; | |||||
10614 | ||||||
10615 | if (!sq->sq_next) /* Last one */ | |||||
10616 | sr->sr_tail = &sq->sq_next; | |||||
10617 | } | |||||
10618 | ||||||
10619 | outgoing_resolve_next(orq); | |||||
10620 | } | |||||
10621 | ||||||
10622 | /* Find first supported protocol in order and preference */ | |||||
10623 | struct sipdns_tport const * | |||||
10624 | outgoing_naptr_tport(nta_outgoing_t *orq, sres_record_t *answers[]) | |||||
10625 | { | |||||
10626 | int i, j, order, pref; | |||||
10627 | int orders[SIPDNS_TRANSPORTS(6)] = {0}, prefs[SIPDNS_TRANSPORTS(6)] = {0}; | |||||
10628 | struct sipdns_tport const *tport; | |||||
10629 | ||||||
10630 | struct sipdns_resolver *sr = orq->orq_resolver; | |||||
10631 | ||||||
10632 | prefs[0] = 0; | |||||
10633 | for (j = 0; sr->sr_tports[j]; j++) { | |||||
10634 | tport = sr->sr_tports[j]; | |||||
10635 | ||||||
10636 | orders[j] = 65536, prefs[j] = 65536; | |||||
10637 | ||||||
10638 | /* Find transport order */ | |||||
10639 | for (i = 0; answers && answers[i]; i++) { | |||||
10640 | sres_naptr_record_t const *na = answers[i]->sr_naptr; | |||||
10641 | if (na->na_record->r_status) | |||||
10642 | continue; | |||||
10643 | if (na->na_record->r_type != sres_type_naptr) | |||||
10644 | continue; | |||||
10645 | /* Check if NAPTR matches transport */ | |||||
10646 | if (!su_casematch(na->na_services, tport->service)) | |||||
10647 | continue; | |||||
10648 | orders[j] = na->na_order; | |||||
10649 | prefs[j] = na->na_prefer; | |||||
10650 | break; | |||||
10651 | } | |||||
10652 | } | |||||
10653 | ||||||
10654 | tport = sr->sr_tports[0], order = orders[0], pref = prefs[0]; | |||||
10655 | ||||||
10656 | for (j = 1; sr->sr_tports[j]; j++) { | |||||
10657 | if (orders[j] <= order && prefs[j] < pref) { | |||||
10658 | tport = sr->sr_tports[j], order = orders[j], pref = prefs[j]; | |||||
10659 | } | |||||
10660 | } | |||||
10661 | ||||||
10662 | return tport; | |||||
10663 | } | |||||
10664 | ||||||
10665 | ||||||
10666 | /* Query SRV records */ | |||||
10667 | static | |||||
10668 | int outgoing_query_srv(nta_outgoing_t *orq, | |||||
10669 | struct sipdns_query *sq) | |||||
10670 | { | |||||
10671 | struct sipdns_resolver *sr = orq->orq_resolver; | |||||
10672 | ||||||
10673 | sres_record_t **answers; | |||||
10674 | ||||||
10675 | sr->sr_target = sq->sq_domain; | |||||
10676 | sr->sr_current = sq; | |||||
10677 | ||||||
10678 | answers = sres_cached_answers(orq->orq_agent->sa_resolver, | |||||
10679 | sres_type_srv, sq->sq_domain); | |||||
10680 | ||||||
10681 | SU_DEBUG_5(("nta: for \"%s\" query \"%s\" %s%s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 10683, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn ->tpn_host, sq->sq_domain, "SRV", answers ? " (cached)" : "")) : (void)0) | |||||
10682 | orq->orq_tpn->tpn_host, sq->sq_domain, "SRV",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 10683, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn ->tpn_host, sq->sq_domain, "SRV", answers ? " (cached)" : "")) : (void)0) | |||||
10683 | answers ? " (cached)" : ""))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 10683, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn ->tpn_host, sq->sq_domain, "SRV", answers ? " (cached)" : "")) : (void)0); | |||||
10684 | ||||||
10685 | if (answers) { | |||||
10686 | outgoing_answer_srv(orq, NULL((void*)0), answers); | |||||
10687 | return 0; | |||||
10688 | } | |||||
10689 | else { | |||||
10690 | sr->sr_query = sres_query(orq->orq_agent->sa_resolver, | |||||
10691 | outgoing_answer_srv, orq, | |||||
10692 | sres_type_srv, sq->sq_domain); | |||||
10693 | return outgoing_resolving(orq); | |||||
10694 | } | |||||
10695 | } | |||||
10696 | ||||||
10697 | /* Process SRV records */ | |||||
10698 | static | |||||
10699 | void | |||||
10700 | outgoing_answer_srv(sres_context_t *orq, sres_query_t *q, | |||||
10701 | sres_record_t *answers[]) | |||||
10702 | { | |||||
10703 | struct sipdns_resolver *sr = orq->orq_resolver; | |||||
10704 | su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request)); | |||||
10705 | struct sipdns_query *sq0, *sq, *selected = NULL((void*)0), **tail = &selected, **at; | |||||
10706 | int i; | |||||
10707 | size_t tlen; | |||||
10708 | ||||||
10709 | sr->sr_query = NULL((void*)0); | |||||
10710 | ||||||
10711 | sq0 = sr->sr_current; | |||||
10712 | assert(sq0 && sq0->sq_type == sres_type_srv)((void) sizeof ((sq0 && sq0->sq_type == sres_type_srv ) ? 1 : 0), __extension__ ({ if (sq0 && sq0->sq_type == sres_type_srv) ; else __assert_fail ("sq0 && sq0->sq_type == sres_type_srv" , "nta.c", 10712, __extension__ __PRETTY_FUNCTION__); })); | |||||
10713 | assert(sq0->sq_domain)((void) sizeof ((sq0->sq_domain) ? 1 : 0), __extension__ ( { if (sq0->sq_domain) ; else __assert_fail ("sq0->sq_domain" , "nta.c", 10713, __extension__ __PRETTY_FUNCTION__); })); assert(sq0->sq_proto)((void) sizeof ((sq0->sq_proto) ? 1 : 0), __extension__ ({ if (sq0->sq_proto) ; else __assert_fail ("sq0->sq_proto" , "nta.c", 10713, __extension__ __PRETTY_FUNCTION__); })); | |||||
10714 | ||||||
10715 | /* Sort by priority, weight? */ | |||||
10716 | sres_sort_answers(orq->orq_agent->sa_resolver, answers); | |||||
10717 | ||||||
10718 | for (i = 0; answers && answers[i]; i++) { | |||||
10719 | sres_srv_record_t const *srv = answers[i]->sr_srv; | |||||
10720 | ||||||
10721 | if (srv->srv_record->r_status /* There was an error */ || | |||||
10722 | srv->srv_record->r_type != sres_type_srv) | |||||
10723 | continue; | |||||
10724 | ||||||
10725 | tlen = strlen(srv->srv_target) + 1; | |||||
10726 | ||||||
10727 | sq = su_zalloc(home, (sizeof *sq) + tlen); | |||||
10728 | ||||||
10729 | if (sq) { | |||||
10730 | *tail = sq, tail = &sq->sq_next; | |||||
10731 | ||||||
10732 | sq->sq_otype = sres_type_srv; | |||||
10733 | sq->sq_type = sr->sr_a_aaaa1; | |||||
10734 | sq->sq_proto = sq0->sq_proto; | |||||
10735 | sq->sq_domain = memcpy(sq + 1, srv->srv_target, tlen); | |||||
10736 | snprintf(sq->sq_port, sizeof(sq->sq_port), "%u", srv->srv_port); | |||||
10737 | sq->sq_priority = srv->srv_priority; | |||||
10738 | sq->sq_weight = srv->srv_weight; | |||||
10739 | } | |||||
10740 | } | |||||
10741 | ||||||
10742 | sres_free_answers(orq->orq_agent->sa_resolver, answers); | |||||
10743 | ||||||
10744 | at = &sr->sr_head; | |||||
10745 | ||||||
10746 | /* Insert sorted by priority, randomly select by weigth */ | |||||
10747 | while (selected) { | |||||
10748 | unsigned long weight = 0; | |||||
10749 | unsigned N = 0; | |||||
10750 | uint16_t priority = selected->sq_priority; | |||||
10751 | ||||||
10752 | /* Total weight of entries with same priority */ | |||||
10753 | for (sq = selected; sq && priority == sq->sq_priority; sq = sq->sq_next) { | |||||
10754 | weight += sq->sq_weight; | |||||
10755 | N ++; | |||||
10756 | } | |||||
10757 | ||||||
10758 | tail = &selected; | |||||
10759 | ||||||
10760 | /* Select by weighted random. Entries with weight 0 are kept in order */ | |||||
10761 | if (N > 1 && weight > 0) { | |||||
10762 | unsigned rand = su_randint(0, weight - 1); | |||||
10763 | ||||||
10764 | while (*tail && rand >= (*tail)->sq_weight) { | |||||
10765 | rand -= (*tail)->sq_weight; | |||||
10766 | tail = &(*tail)->sq_next; | |||||
10767 | } | |||||
10768 | } | |||||
10769 | ||||||
10770 | /* Remove selected */ | |||||
10771 | if (*tail) { | |||||
10772 | sq = *tail; *tail = sq->sq_next; assert(sq->sq_priority == priority)((void) sizeof ((sq->sq_priority == priority) ? 1 : 0), __extension__ ({ if (sq->sq_priority == priority) ; else __assert_fail ( "sq->sq_priority == priority", "nta.c", 10772, __extension__ __PRETTY_FUNCTION__); })); | |||||
10773 | ||||||
10774 | /* Append at *at */ | |||||
10775 | sq->sq_next = *at; *at = sq; at = &sq->sq_next; if (!*at) sr->sr_tail = at; | |||||
10776 | ||||||
10777 | SU_DEBUG_5(("nta: %s IN SRV %u %u %s %s (%s)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 10780, "nta: %s IN SRV %u %u %s %s (%s)\n", sq0->sq_domain , (unsigned)sq->sq_priority, (unsigned)sq->sq_weight, sq ->sq_port, sq->sq_domain, sq->sq_proto)) : (void)0) | |||||
10778 | sq0->sq_domain,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 10780, "nta: %s IN SRV %u %u %s %s (%s)\n", sq0->sq_domain , (unsigned)sq->sq_priority, (unsigned)sq->sq_weight, sq ->sq_port, sq->sq_domain, sq->sq_proto)) : (void)0) | |||||
10779 | (unsigned)sq->sq_priority, (unsigned)sq->sq_weight,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 10780, "nta: %s IN SRV %u %u %s %s (%s)\n", sq0->sq_domain , (unsigned)sq->sq_priority, (unsigned)sq->sq_weight, sq ->sq_port, sq->sq_domain, sq->sq_proto)) : (void)0) | |||||
10780 | sq->sq_port, sq->sq_domain, sq->sq_proto))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 10780, "nta: %s IN SRV %u %u %s %s (%s)\n", sq0->sq_domain , (unsigned)sq->sq_priority, (unsigned)sq->sq_weight, sq ->sq_port, sq->sq_domain, sq->sq_proto)) : (void)0); | |||||
10781 | } | |||||
10782 | } | |||||
10783 | ||||||
10784 | /* This is not needed anymore (?) */ | |||||
10785 | sr->sr_current = NULL((void*)0); | |||||
10786 | sq0->sq_next = sr->sr_done; sr->sr_done = sq0; | |||||
10787 | ||||||
10788 | outgoing_resolve_next(orq); | |||||
10789 | } | |||||
10790 | ||||||
10791 | #if SU_HAVE_IN61 | |||||
10792 | /* Query AAAA records */ | |||||
10793 | static | |||||
10794 | int outgoing_query_aaaa(nta_outgoing_t *orq, struct sipdns_query *sq) | |||||
10795 | { | |||||
10796 | struct sipdns_resolver *sr = orq->orq_resolver; | |||||
10797 | sres_record_t **answers; | |||||
10798 | ||||||
10799 | sr->sr_target = sq->sq_domain; | |||||
10800 | sr->sr_current = sq; | |||||
10801 | ||||||
10802 | answers = sres_cached_answers(orq->orq_agent->sa_resolver, | |||||
10803 | sres_type_aaaa, sq->sq_domain); | |||||
10804 | ||||||
10805 | SU_DEBUG_5(("nta: for \"%s\" query \"%s\" %s%s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 10807, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn ->tpn_host, sq->sq_domain, "AAAA", answers ? " (cached)" : "")) : (void)0) | |||||
10806 | orq->orq_tpn->tpn_host, sq->sq_domain, "AAAA",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 10807, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn ->tpn_host, sq->sq_domain, "AAAA", answers ? " (cached)" : "")) : (void)0) | |||||
10807 | answers ? " (cached)" : ""))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 10807, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn ->tpn_host, sq->sq_domain, "AAAA", answers ? " (cached)" : "")) : (void)0); | |||||
10808 | ||||||
10809 | if (answers) { | |||||
10810 | outgoing_answer_aaaa(orq, NULL((void*)0), answers); | |||||
10811 | return 0; | |||||
10812 | } | |||||
10813 | ||||||
10814 | sr->sr_query = sres_query(orq->orq_agent->sa_resolver, | |||||
10815 | outgoing_answer_aaaa, orq, | |||||
10816 | sres_type_aaaa, sq->sq_domain); | |||||
10817 | ||||||
10818 | return outgoing_resolving(orq); | |||||
10819 | } | |||||
10820 | ||||||
10821 | /* Process AAAA records */ | |||||
10822 | static | |||||
10823 | void outgoing_answer_aaaa(sres_context_t *orq, sres_query_t *q, | |||||
10824 | sres_record_t *answers[]) | |||||
10825 | { | |||||
10826 | struct sipdns_resolver *sr = orq->orq_resolver; | |||||
10827 | su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request)); | |||||
10828 | struct sipdns_query *sq = sr->sr_current; | |||||
10829 | ||||||
10830 | size_t i, j, found; | |||||
10831 | char *result, **results = NULL((void*)0); | |||||
10832 | ||||||
10833 | assert(sq)((void) sizeof ((sq) ? 1 : 0), __extension__ ({ if (sq) ; else __assert_fail ("sq", "nta.c", 10833, __extension__ __PRETTY_FUNCTION__ ); })); assert(sq->sq_type == sres_type_aaaa)((void) sizeof ((sq->sq_type == sres_type_aaaa) ? 1 : 0), __extension__ ({ if (sq->sq_type == sres_type_aaaa) ; else __assert_fail ("sq->sq_type == sres_type_aaaa", "nta.c", 10833, __extension__ __PRETTY_FUNCTION__); })); | |||||
10834 | ||||||
10835 | sr->sr_query = NULL((void*)0); | |||||
10836 | ||||||
10837 | for (i = 0, found = 0; answers && answers[i]; i++) { | |||||
10838 | sres_aaaa_record_t const *aaaa = answers[i]->sr_aaaa; | |||||
10839 | if (aaaa->aaaa_record->r_status == 0 && | |||||
10840 | aaaa->aaaa_record->r_type == sres_type_aaaa) | |||||
10841 | found++; | |||||
10842 | } | |||||
10843 | ||||||
10844 | if (found > 1) | |||||
10845 | results = su_zalloc(home, (found + 1) * (sizeof *results)); | |||||
10846 | else if (found) | |||||
10847 | results = &result; | |||||
10848 | ||||||
10849 | for (i = j = 0; results && answers && answers[i]; i++) { | |||||
10850 | char addr[SU_ADDRSIZE(48)]; | |||||
10851 | sres_aaaa_record_t const *aaaa = answers[i]->sr_aaaa; | |||||
10852 | ||||||
10853 | if (aaaa->aaaa_record->r_status || | |||||
10854 | aaaa->aaaa_record->r_type != sres_type_aaaa) | |||||
10855 | continue; /* There was an error */ | |||||
10856 | ||||||
10857 | su_inet_ntopinet_ntop(AF_INET610, &aaaa->aaaa_addr, addr, sizeof(addr)); | |||||
10858 | ||||||
10859 | if (j == 0) | |||||
10860 | SU_DEBUG_5(("nta(%p): %s IN AAAA %s\n", (void *)orq,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 10861, "nta(%p): %s IN AAAA %s\n", (void *)orq, aaaa->aaaa_record ->r_name, addr)) : (void)0) | |||||
10861 | aaaa->aaaa_record->r_name, addr))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 10861, "nta(%p): %s IN AAAA %s\n", (void *)orq, aaaa->aaaa_record ->r_name, addr)) : (void)0); | |||||
10862 | else | |||||
10863 | SU_DEBUG_5(("nta(%p): AAAA %s\n", (void *)orq, addr))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 10863, "nta(%p): AAAA %s\n", (void *)orq, addr)) : (void)0 ); | |||||
10864 | ||||||
10865 | assert(j < found)((void) sizeof ((j < found) ? 1 : 0), __extension__ ({ if ( j < found) ; else __assert_fail ("j < found", "nta.c", 10865 , __extension__ __PRETTY_FUNCTION__); })); | |||||
10866 | results[j++] = su_strdup(home, addr); | |||||
10867 | } | |||||
10868 | ||||||
10869 | sres_free_answers(orq->orq_agent->sa_resolver, answers); | |||||
10870 | ||||||
10871 | if (results) | |||||
10872 | outgoing_query_results(orq, sq, results, found); | |||||
10873 | } | |||||
10874 | #endif /* SU_HAVE_IN6 */ | |||||
10875 | ||||||
10876 | /* Query A records */ | |||||
10877 | static | |||||
10878 | int outgoing_query_a(nta_outgoing_t *orq, struct sipdns_query *sq) | |||||
10879 | { | |||||
10880 | struct sipdns_resolver *sr = orq->orq_resolver; | |||||
10881 | sres_record_t **answers; | |||||
10882 | ||||||
10883 | sr->sr_target = sq->sq_domain; | |||||
10884 | sr->sr_current = sq; | |||||
10885 | ||||||
10886 | answers = sres_cached_answers(orq->orq_agent->sa_resolver, | |||||
10887 | sres_type_a, sq->sq_domain); | |||||
10888 | ||||||
10889 | SU_DEBUG_5(("nta: for \"%s\" query \"%s\" %s%s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 10891, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn ->tpn_host, sq->sq_domain, "A", answers ? " (cached)" : "")) : (void)0) | |||||
10890 | orq->orq_tpn->tpn_host, sq->sq_domain, "A",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 10891, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn ->tpn_host, sq->sq_domain, "A", answers ? " (cached)" : "")) : (void)0) | |||||
10891 | answers ? " (cached)" : ""))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 10891, "nta: for \"%s\" query \"%s\" %s%s\n", orq->orq_tpn ->tpn_host, sq->sq_domain, "A", answers ? " (cached)" : "")) : (void)0); | |||||
10892 | ||||||
10893 | if (answers) { | |||||
10894 | outgoing_answer_a(orq, NULL((void*)0), answers); | |||||
10895 | return 0; | |||||
10896 | } | |||||
10897 | ||||||
10898 | sr->sr_query = sres_query(orq->orq_agent->sa_resolver, | |||||
10899 | outgoing_answer_a, orq, | |||||
10900 | sres_type_a, sq->sq_domain); | |||||
10901 | ||||||
10902 | return outgoing_resolving(orq); | |||||
10903 | } | |||||
10904 | ||||||
10905 | /* Process A records */ | |||||
10906 | static | |||||
10907 | void outgoing_answer_a(sres_context_t *orq, sres_query_t *q, | |||||
10908 | sres_record_t *answers[]) | |||||
10909 | { | |||||
10910 | struct sipdns_resolver *sr = orq->orq_resolver; | |||||
10911 | su_home_t *home = msg_home(orq->orq_request)((su_home_t*)(orq->orq_request)); | |||||
10912 | struct sipdns_query *sq = sr->sr_current; | |||||
10913 | ||||||
10914 | int i, j, found; | |||||
10915 | char *result, **results = NULL((void*)0); | |||||
10916 | ||||||
10917 | assert(sq)((void) sizeof ((sq) ? 1 : 0), __extension__ ({ if (sq) ; else __assert_fail ("sq", "nta.c", 10917, __extension__ __PRETTY_FUNCTION__ ); })); assert(sq->sq_type == sres_type_a)((void) sizeof ((sq->sq_type == sres_type_a) ? 1 : 0), __extension__ ({ if (sq->sq_type == sres_type_a) ; else __assert_fail ( "sq->sq_type == sres_type_a", "nta.c", 10917, __extension__ __PRETTY_FUNCTION__); })); | |||||
10918 | ||||||
10919 | sr->sr_query = NULL((void*)0); | |||||
10920 | ||||||
10921 | for (i = 0, found = 0; answers && answers[i]; i++) { | |||||
10922 | sres_a_record_t const *a = answers[i]->sr_a; | |||||
10923 | if (a->a_record->r_status == 0 && | |||||
10924 | a->a_record->r_type == sres_type_a) | |||||
10925 | found++; | |||||
10926 | } | |||||
10927 | ||||||
10928 | if (found > 1) | |||||
10929 | results = su_zalloc(home, (found + 1) * (sizeof *results)); | |||||
10930 | else if (found) | |||||
10931 | results = &result; | |||||
10932 | ||||||
10933 | for (i = j = 0; answers && answers[i]; i++) { | |||||
10934 | char addr[SU_ADDRSIZE(48)]; | |||||
10935 | sres_a_record_t const *a = answers[i]->sr_a; | |||||
10936 | ||||||
10937 | if (a->a_record->r_status || | |||||
10938 | a->a_record->r_type != sres_type_a) | |||||
10939 | continue; /* There was an error */ | |||||
10940 | ||||||
10941 | su_inet_ntopinet_ntop(AF_INET2, &a->a_addr, addr, sizeof(addr)); | |||||
10942 | ||||||
10943 | if (j == 0) | |||||
10944 | SU_DEBUG_5(("nta: %s IN A %s\n", a->a_record->r_name, addr))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 10944, "nta: %s IN A %s\n", a->a_record->r_name, addr )) : (void)0); | |||||
10945 | else | |||||
10946 | SU_DEBUG_5(("nta(%p): A %s\n", (void *)orq, addr))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 10946, "nta(%p): A %s\n", (void *)orq, addr)) : (void)0); | |||||
10947 | ||||||
10948 | assert(j < found)((void) sizeof ((j < found) ? 1 : 0), __extension__ ({ if ( j < found) ; else __assert_fail ("j < found", "nta.c", 10948 , __extension__ __PRETTY_FUNCTION__); })); | |||||
10949 | results[j++] = su_strdup(home, addr); | |||||
10950 | } | |||||
10951 | ||||||
10952 | sres_free_answers(orq->orq_agent->sa_resolver, answers); | |||||
10953 | ||||||
10954 | if (results) | |||||
10955 | outgoing_query_results(orq, sq, results, found); | |||||
10956 | else if (!q) | |||||
10957 | outgoing_resolving_error(orq, SIPDNS_503_ERROR503, "DNS Error"); | |||||
10958 | } | |||||
10959 | ||||||
10960 | /** Store A/AAAA query results */ | |||||
10961 | static void | |||||
10962 | outgoing_query_results(nta_outgoing_t *orq, | |||||
10963 | struct sipdns_query *sq, | |||||
10964 | char *results[], | |||||
10965 | size_t rlen) | |||||
10966 | { | |||||
10967 | struct sipdns_resolver *sr = orq->orq_resolver; | |||||
10968 | ||||||
10969 | if (sq->sq_type == sr->sr_a_aaaa1 && | |||||
10970 | sq->sq_type != sr->sr_a_aaaa2) { | |||||
10971 | sq->sq_type = sr->sr_a_aaaa2; | |||||
10972 | ||||||
10973 | SU_DEBUG_7(("nta(%p): %s %s record still unresolved\n", (void *)orq,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__ , 10974, "nta(%p): %s %s record still unresolved\n", (void *) orq, sq->sq_domain, sq->sq_type == sres_type_a ? "A" : "AAAA" )) : (void)0) | |||||
10974 | sq->sq_domain, sq->sq_type == sres_type_a ? "A" : "AAAA"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__ , 10974, "nta(%p): %s %s record still unresolved\n", (void *) orq, sq->sq_domain, sq->sq_type == sres_type_a ? "A" : "AAAA" )) : (void)0); | |||||
10975 | ||||||
10976 | /* | |||||
10977 | * Three possible policies: | |||||
10978 | * 1) try each host for AAAA/A, then A/AAAA | |||||
10979 | * 2) try everything first for AAAA/A, then everything for A/AAAA | |||||
10980 | * 3) try one SRV record results for AAAA/A, then for A/AAAA, | |||||
10981 | * then next SRV record | |||||
10982 | */ | |||||
10983 | ||||||
10984 | /* We use now policy #1 */ | |||||
10985 | if (!(sq->sq_next = sr->sr_head)) | |||||
10986 | sr->sr_tail = &sq->sq_next; | |||||
10987 | sr->sr_head = sq; | |||||
10988 | } | |||||
10989 | else { | |||||
10990 | sq->sq_next = sr->sr_done, sr->sr_done = sq; | |||||
10991 | ||||||
10992 | if (rlen == 0 && sq->sq_grayish) | |||||
10993 | outgoing_graylist(orq, sq); | |||||
10994 | } | |||||
10995 | ||||||
10996 | if (rlen > 1) | |||||
10997 | sr->sr_results = results; | |||||
10998 | else | |||||
10999 | sr->sr_current = NULL((void*)0); | |||||
11000 | ||||||
11001 | if (rlen > 0) { | |||||
11002 | orq->orq_resolved = 1; | |||||
11003 | orq->orq_tpn->tpn_host = results[0]; | |||||
11004 | if (sq->sq_proto) orq->orq_tpn->tpn_proto = sq->sq_proto; | |||||
11005 | if (sq->sq_port[0]) orq->orq_tpn->tpn_port = sq->sq_port; | |||||
11006 | outgoing_prepare_send(orq); | |||||
11007 | } else { | |||||
11008 | outgoing_resolve_next(orq); | |||||
11009 | } | |||||
11010 | } | |||||
11011 | ||||||
11012 | ||||||
11013 | #endif | |||||
11014 | ||||||
11015 | /* ====================================================================== */ | |||||
11016 | /* 10) Reliable responses */ | |||||
11017 | ||||||
11018 | static nta_prack_f nta_reliable_destroyed; | |||||
11019 | ||||||
11020 | /** | |||||
11021 | * Check that server transaction can be used to send reliable provisional | |||||
11022 | * responses. | |||||
11023 | */ | |||||
11024 | su_inlinestatic inline | |||||
11025 | int reliable_check(nta_incoming_t *irq) | |||||
11026 | { | |||||
11027 | if (irq == NULL((void*)0) || irq->irq_status >= 200 || !irq->irq_agent) | |||||
11028 | return 0; | |||||
11029 | ||||||
11030 | if (irq->irq_reliable && irq->irq_reliable->rel_status >= 200) | |||||
11031 | return 0; | |||||
11032 | ||||||
11033 | /* @RSeq is initialized to nonzero when request requires/supports 100rel */ | |||||
11034 | if (irq->irq_rseq == 0) | |||||
11035 | return 0; | |||||
11036 | ||||||
11037 | if (irq->irq_rseq == 0xffffffffU) /* already sent >> 2**31 responses */ | |||||
11038 | return 0; | |||||
11039 | ||||||
11040 | return 1; | |||||
11041 | } | |||||
11042 | ||||||
11043 | /** Respond reliably. | |||||
11044 | * | |||||
11045 | * @param irq | |||||
11046 | * @param callback | |||||
11047 | * @param rmagic | |||||
11048 | * @param status | |||||
11049 | * @param phrase | |||||
11050 | * @param tag, value, .. | |||||
11051 | */ | |||||
11052 | nta_reliable_t *nta_reliable_treply(nta_incoming_t *irq, | |||||
11053 | nta_prack_f *callback, | |||||
11054 | nta_reliable_magic_t *rmagic, | |||||
11055 | int status, char const *phrase, | |||||
11056 | tag_type_t tag, | |||||
11057 | tag_value_t value, ...) | |||||
11058 | { | |||||
11059 | ta_list ta; | |||||
11060 | msg_t *msg; | |||||
11061 | sip_t *sip; | |||||
11062 | nta_reliable_t *retval = NULL((void*)0); | |||||
11063 | ||||||
11064 | if (!reliable_check(irq) || (status <= 100 || status >= 200)) | |||||
11065 | return NULL((void*)0); | |||||
11066 | ||||||
11067 | msg = nta_msg_create(irq->irq_agent, 0); | |||||
11068 | sip = sip_object(msg); | |||||
11069 | ||||||
11070 | if (!sip) | |||||
11071 | return NULL((void*)0); | |||||
11072 | ||||||
11073 | ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value = (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag ) == tag_next && (ta_start__value) != 0) { ta_start__tag = ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag == tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag == tag_next) { ta_start__value = ((tagi_t *)ta_start__value) ->t_value; } else { ta_start__tag = tag_next; break; } } ( ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value ; if (ta_start__tag != ((void*)0) && ta_start__tag != tag_null && ta_start__tag != tag_next) { va_list ta_start__ap ; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag = tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap ); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value = 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0); | |||||
11074 | ||||||
11075 | if (0 > nta_incoming_complete_response(irq, msg, status, phrase, | |||||
11076 | ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta). tl[1].t_value)) | |||||
11077 | msg_destroy(msg); | |||||
11078 | else if (!(retval = reliable_mreply(irq, callback, rmagic, msg, sip))) | |||||
11079 | msg_destroy(msg); | |||||
11080 | ||||||
11081 | ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value ))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta) .ap)); | |||||
11082 | ||||||
11083 | return retval; | |||||
11084 | } | |||||
11085 | ||||||
11086 | /** Respond reliably with @a msg. | |||||
11087 | * | |||||
11088 | * @note | |||||
11089 | * The stack takes over the ownership of @a msg. (It is destroyed even if | |||||
11090 | * sending the response fails.) | |||||
11091 | * | |||||
11092 | * @param irq | |||||
11093 | * @param callback | |||||
11094 | * @param rmagic | |||||
11095 | * @param msg | |||||
11096 | */ | |||||
11097 | nta_reliable_t *nta_reliable_mreply(nta_incoming_t *irq, | |||||
11098 | nta_prack_f *callback, | |||||
11099 | nta_reliable_magic_t *rmagic, | |||||
11100 | msg_t *msg) | |||||
11101 | { | |||||
11102 | sip_t *sip = sip_object(msg); | |||||
11103 | ||||||
11104 | if (!reliable_check(irq)) { | |||||
11105 | msg_destroy(msg); | |||||
11106 | return NULL((void*)0); | |||||
11107 | } | |||||
11108 | ||||||
11109 | if (sip == NULL((void*)0) || !sip->sip_status || sip->sip_status->st_status <= 100) { | |||||
11110 | msg_destroy(msg); | |||||
11111 | return NULL((void*)0); | |||||
11112 | } | |||||
11113 | ||||||
11114 | if (sip->sip_status->st_status >= 200) { | |||||
11115 | incoming_final_failed(irq, msg); | |||||
11116 | return NULL((void*)0); | |||||
11117 | } | |||||
11118 | ||||||
11119 | return reliable_mreply(irq, callback, rmagic, msg, sip); | |||||
11120 | } | |||||
11121 | ||||||
11122 | static | |||||
11123 | nta_reliable_t *reliable_mreply(nta_incoming_t *irq, | |||||
11124 | nta_prack_f *callback, | |||||
11125 | nta_reliable_magic_t *rmagic, | |||||
11126 | msg_t *msg, | |||||
11127 | sip_t *sip) | |||||
11128 | { | |||||
11129 | nta_reliable_t *rel; | |||||
11130 | nta_agent_t *agent; | |||||
11131 | ||||||
11132 | agent = irq->irq_agent; | |||||
11133 | ||||||
11134 | if (callback == NULL((void*)0)) | |||||
11135 | callback = nta_reliable_destroyed; | |||||
11136 | ||||||
11137 | rel = su_zalloc(agent->sa_home, sizeof(*rel)); | |||||
11138 | if (rel) { | |||||
11139 | rel->rel_irq = irq; | |||||
11140 | rel->rel_callback = callback; | |||||
11141 | rel->rel_magic = rmagic; | |||||
11142 | rel->rel_unsent = msg; | |||||
11143 | rel->rel_status = sip->sip_status->st_status; | |||||
11144 | rel->rel_precious = sip->sip_payload != NULL((void*)0); | |||||
11145 | rel->rel_next = irq->irq_reliable; | |||||
11146 | ||||||
11147 | /* | |||||
11148 | * If there already is a un-pr-acknowledged response, queue this one | |||||
11149 | * until at least one response is pr-acknowledged. | |||||
11150 | */ | |||||
11151 | if (irq->irq_reliable && | |||||
11152 | (irq->irq_reliable->rel_next == NULL((void*)0) || | |||||
11153 | irq->irq_reliable->rel_rseq == 0)) { | |||||
11154 | return irq->irq_reliable = rel; | |||||
11155 | } | |||||
11156 | ||||||
11157 | if (reliable_send(irq, rel, msg_ref_create(msg), sip) < 0) { | |||||
11158 | msg_destroy(msg); | |||||
11159 | su_free(agent->sa_home, rel); | |||||
11160 | return NULL((void*)0); | |||||
11161 | } | |||||
11162 | ||||||
11163 | irq->irq_reliable = rel; | |||||
11164 | ||||||
11165 | return callback ? rel : (nta_reliable_t *)-1; | |||||
11166 | } | |||||
11167 | ||||||
11168 | msg_destroy(msg); | |||||
11169 | return NULL((void*)0); | |||||
11170 | } | |||||
11171 | ||||||
11172 | static | |||||
11173 | int reliable_send(nta_incoming_t *irq, | |||||
11174 | nta_reliable_t *rel, | |||||
11175 | msg_t *msg, | |||||
11176 | sip_t *sip) | |||||
11177 | { | |||||
11178 | nta_agent_t *sa = irq->irq_agent; | |||||
11179 | su_home_t *home = msg_home(msg)((su_home_t*)(msg)); | |||||
11180 | sip_rseq_t rseq[1]; | |||||
11181 | sip_rseq_init(rseq); | |||||
11182 | ||||||
11183 | if (sip->sip_require) | |||||
11184 | msg_header_replace_param(home, sip->sip_require->k_common, "100rel"); | |||||
11185 | else | |||||
11186 | sip_add_make(msg, sip, sip_require_class, "100rel"); | |||||
11187 | ||||||
11188 | rel->rel_rseq = rseq->rs_response = irq->irq_rseq; | |||||
11189 | sip_add_dup(msg, sip, (sip_header_t *)rseq); | |||||
11190 | ||||||
11191 | if (!sip->sip_rseq || incoming_reply(irq, msg, sip) < 0) { | |||||
11192 | msg_destroy(msg); | |||||
11193 | return -1; | |||||
11194 | } | |||||
11195 | ||||||
11196 | irq->irq_rseq++; | |||||
11197 | ||||||
11198 | if (irq->irq_queue == sa->sa_in.preliminary) | |||||
11199 | /* Make sure we are moved to the tail */ | |||||
11200 | incoming_remove(irq); | |||||
11201 | ||||||
11202 | incoming_queue(sa->sa_in.preliminary, irq); /* P1 */ | |||||
11203 | incoming_set_timer(irq, sa->sa_t1); /* P2 */ | |||||
11204 | ||||||
11205 | return 0; | |||||
11206 | } | |||||
11207 | ||||||
11208 | /** Queue final response when there are unsent precious preliminary responses */ | |||||
11209 | static | |||||
11210 | int reliable_final(nta_incoming_t *irq, msg_t *msg, sip_t *sip) | |||||
11211 | { | |||||
11212 | nta_reliable_t *r; | |||||
11213 | unsigned already_in_callback; | |||||
11214 | /* | |||||
11215 | * We delay sending final response if it's 2XX and | |||||
11216 | * an unpracked reliable response contains session description | |||||
11217 | */ | |||||
11218 | /* Get last unpracked response from queue */ | |||||
11219 | if (sip->sip_status->st_status < 300) | |||||
11220 | for (r = irq->irq_reliable; r; r = r->rel_next) | |||||
11221 | if (r->rel_unsent && r->rel_precious) { | |||||
11222 | /* Delay sending 2XX */ | |||||
11223 | reliable_mreply(irq, NULL((void*)0), NULL((void*)0), msg, sip); | |||||
11224 | return 0; | |||||
11225 | } | |||||
11226 | ||||||
11227 | /* Flush unsent responses. */ | |||||
11228 | already_in_callback = irq->irq_in_callback; | |||||
11229 | irq->irq_in_callback = 1; | |||||
11230 | reliable_flush(irq); | |||||
11231 | irq->irq_in_callback = already_in_callback; | |||||
11232 | ||||||
11233 | if (!already_in_callback && irq->irq_terminated && irq->irq_destroyed) { | |||||
11234 | incoming_free(irq); | |||||
11235 | msg_destroy(msg); | |||||
11236 | return 0; | |||||
11237 | } | |||||
11238 | ||||||
11239 | return 1; | |||||
11240 | } | |||||
11241 | ||||||
11242 | /** Get latest reliably sent response */ | |||||
11243 | static | |||||
11244 | msg_t *reliable_response(nta_incoming_t *irq) | |||||
11245 | { | |||||
11246 | nta_reliable_t *r, *rel; | |||||
11247 | ||||||
11248 | /* Get last unpracked response from queue */ | |||||
11249 | for (rel = NULL((void*)0), r = irq->irq_reliable; r; r = r->rel_next) | |||||
11250 | if (!r->rel_pracked) | |||||
11251 | rel = r; | |||||
11252 | ||||||
11253 | assert(rel)((void) sizeof ((rel) ? 1 : 0), __extension__ ({ if (rel) ; else __assert_fail ("rel", "nta.c", 11253, __extension__ __PRETTY_FUNCTION__ ); })); | |||||
11254 | ||||||
11255 | return rel->rel_unsent; | |||||
11256 | } | |||||
11257 | ||||||
11258 | /* Find un-PRACKed responses */ | |||||
11259 | static | |||||
11260 | nta_reliable_t *reliable_find(nta_agent_t const *agent, | |||||
11261 | sip_t const *sip) | |||||
11262 | { | |||||
11263 | incoming_htable_t const *iht = agent->sa_incoming; | |||||
11264 | nta_incoming_t *irq, **ii; | |||||
11265 | sip_call_id_t const *i = sip->sip_call_id; | |||||
11266 | sip_rack_t const *rack = sip->sip_rack; | |||||
11267 | hash_value_t hash = NTA_HASH(i, rack->ra_cseq)((i)->i_hash + 26839U * (uint32_t)(rack->ra_cseq)); | |||||
11268 | ||||||
11269 | /* XXX - add own hash table for 100rel */ | |||||
11270 | ||||||
11271 | for (ii = incoming_htable_hash(iht, hash); | |||||
11272 | (irq = *ii); | |||||
11273 | ii = incoming_htable_next(iht, ii)) { | |||||
11274 | ||||||
11275 | if (hash == irq->irq_hash && | |||||
11276 | irq->irq_call_id->i_hash == i->i_hash && | |||||
11277 | irq->irq_cseq->cs_seq == rack->ra_cseq && | |||||
11278 | irq->irq_method == sip_method_invite && | |||||
11279 | strcmp(irq->irq_call_id->i_id, i->i_id) == 0 && | |||||
11280 | (irq->irq_to->a_tag == NULL((void*)0) || | |||||
11281 | su_casematch(irq->irq_to->a_tag, sip->sip_to->a_tag)) && | |||||
11282 | su_casematch(irq->irq_from->a_tag, sip->sip_from->a_tag)) { | |||||
11283 | ||||||
11284 | nta_reliable_t const *rel; | |||||
11285 | ||||||
11286 | /* Found matching INVITE */ | |||||
11287 | for (rel = irq->irq_reliable; rel; rel = rel->rel_next) | |||||
11288 | if (rel->rel_rseq == rack->ra_response) | |||||
11289 | return (nta_reliable_t *)rel; | |||||
11290 | ||||||
11291 | } | |||||
11292 | } | |||||
11293 | ||||||
11294 | return NULL((void*)0); | |||||
11295 | } | |||||
11296 | ||||||
11297 | /** Process incoming PRACK with matching @RAck field */ | |||||
11298 | static | |||||
11299 | int reliable_recv(nta_reliable_t *rel, msg_t *msg, sip_t *sip, tport_t *tp) | |||||
11300 | { | |||||
11301 | nta_incoming_t *irq = rel->rel_irq; | |||||
11302 | nta_incoming_t *pr_irq; | |||||
11303 | int status; | |||||
11304 | ||||||
11305 | rel->rel_pracked = 1; | |||||
11306 | msg_ref_destroy(rel->rel_unsent), rel->rel_unsent = NULL((void*)0); | |||||
11307 | ||||||
11308 | pr_irq = incoming_create(irq->irq_agent, msg, sip, tp, irq->irq_tag); | |||||
11309 | if (!pr_irq) { | |||||
11310 | mreply(irq->irq_agent, NULL((void*)0), | |||||
11311 | SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error, msg, | |||||
11312 | tp, 0, 0, NULL((void*)0), | |||||
11313 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
11314 | return 0; | |||||
11315 | } | |||||
11316 | ||||||
11317 | if (irq->irq_status < 200) { | |||||
11318 | incoming_queue(irq->irq_agent->sa_in.proceeding, irq); /* Reset P1 */ | |||||
11319 | incoming_reset_timer(irq); /* Reset P2 */ | |||||
11320 | } | |||||
11321 | ||||||
11322 | irq->irq_in_callback = pr_irq->irq_in_callback = 1; | |||||
11323 | status = rel->rel_callback(rel->rel_magic, rel, pr_irq, sip); rel = NULL((void*)0); | |||||
11324 | irq->irq_in_callback = pr_irq->irq_in_callback = 0; | |||||
11325 | ||||||
11326 | if (pr_irq->irq_completed) { /* Already sent final response */ | |||||
11327 | if (pr_irq->irq_terminated && pr_irq->irq_destroyed) | |||||
11328 | incoming_free(pr_irq); | |||||
11329 | } | |||||
11330 | else if (status != 0) { | |||||
11331 | if (status < 200 || status > 299) { | |||||
11332 | SU_DEBUG_3(("nta_reliable(): invalid status %03d from callback\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 11333, "nta_reliable(): invalid status %03d from callback\n" , status)) : (void)0) | |||||
11333 | status))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 11333, "nta_reliable(): invalid status %03d from callback\n" , status)) : (void)0); | |||||
11334 | status = 200; | |||||
11335 | } | |||||
11336 | nta_incoming_treply(pr_irq, status, "OK", TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
11337 | nta_incoming_destroy(pr_irq); | |||||
11338 | } | |||||
11339 | ||||||
11340 | /* If there are queued unsent reliable responses, send them all. */ | |||||
11341 | while (irq->irq_reliable && irq->irq_reliable->rel_rseq == 0) { | |||||
11342 | nta_reliable_t *r; | |||||
11343 | ||||||
11344 | for (r = irq->irq_reliable; r; r = r->rel_next) | |||||
11345 | if (r->rel_rseq == 0) | |||||
11346 | rel = r; | |||||
11347 | ||||||
11348 | msg = rel->rel_unsent, sip = sip_object(msg); | |||||
11349 | ||||||
11350 | if (sip->sip_status->st_status < 200) { | |||||
11351 | if (reliable_send(irq, rel, msg_ref_create(msg), sip) < 0) { | |||||
11352 | assert(!"send reliable response")((void) sizeof ((!"send reliable response") ? 1 : 0), __extension__ ({ if (!"send reliable response") ; else __assert_fail ("!\"send reliable response\"" , "nta.c", 11352, __extension__ __PRETTY_FUNCTION__); })); | |||||
11353 | } | |||||
11354 | } | |||||
11355 | else { | |||||
11356 | /* | |||||
11357 | * XXX | |||||
11358 | * Final response should be delayed until a reliable provisional | |||||
11359 | * response has been pracked | |||||
11360 | */ | |||||
11361 | rel->rel_unsent = NULL((void*)0), rel->rel_rseq = (uint32_t)-1; | |||||
11362 | if (incoming_reply(irq, msg, sip) < 0) { | |||||
11363 | assert(!"send delayed final response")((void) sizeof ((!"send delayed final response") ? 1 : 0), __extension__ ({ if (!"send delayed final response") ; else __assert_fail ( "!\"send delayed final response\"", "nta.c", 11363, __extension__ __PRETTY_FUNCTION__); })); | |||||
11364 | } | |||||
11365 | } | |||||
11366 | } | |||||
11367 | ||||||
11368 | return 0; | |||||
11369 | } | |||||
11370 | ||||||
11371 | /** Flush unacknowledged and unsent reliable responses */ | |||||
11372 | void reliable_flush(nta_incoming_t *irq) | |||||
11373 | { | |||||
11374 | nta_reliable_t *r, *rel; | |||||
11375 | ||||||
11376 | do { | |||||
11377 | for (r = irq->irq_reliable, rel = NULL((void*)0); r; r = r->rel_next) | |||||
11378 | if (r->rel_unsent) | |||||
11379 | rel = r; | |||||
11380 | ||||||
11381 | if (rel) { | |||||
11382 | rel->rel_pracked = 1; | |||||
11383 | msg_ref_destroy(rel->rel_unsent), rel->rel_unsent = NULL((void*)0); | |||||
11384 | rel->rel_callback(rel->rel_magic, rel, NULL((void*)0), NULL((void*)0)); | |||||
11385 | } | |||||
11386 | } while (rel); | |||||
11387 | } | |||||
11388 | ||||||
11389 | void reliable_timeout(nta_incoming_t *irq, int timeout) | |||||
11390 | { | |||||
11391 | if (timeout) | |||||
11392 | SU_DEBUG_5(("nta: response timeout with %u\n", irq->irq_status))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 11392, "nta: response timeout with %u\n", irq->irq_status )) : (void)0); | |||||
11393 | ||||||
11394 | irq->irq_in_callback = 1; | |||||
11395 | ||||||
11396 | reliable_flush(irq); | |||||
11397 | ||||||
11398 | if (irq->irq_callback) | |||||
11399 | irq->irq_callback(irq->irq_magic, irq, NULL((void*)0)); | |||||
11400 | ||||||
11401 | irq->irq_in_callback = 0; | |||||
11402 | ||||||
11403 | if (!timeout) | |||||
11404 | return; | |||||
11405 | ||||||
11406 | if (irq->irq_completed && irq->irq_destroyed) | |||||
11407 | incoming_free(irq), irq = NULL((void*)0); | |||||
11408 | else if (irq->irq_status < 200) | |||||
11409 | nta_incoming_treply(irq, 503, "Reliable Response Time-Out", TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
11410 | } | |||||
11411 | ||||||
11412 | #if 0 /* Not needed, yet. */ | |||||
11413 | /** Use this callback when normal leg callback is supposed to | |||||
11414 | * process incoming PRACK requests | |||||
11415 | */ | |||||
11416 | int nta_reliable_leg_prack(nta_reliable_magic_t *magic, | |||||
11417 | nta_reliable_t *rel, | |||||
11418 | nta_incoming_t *irq, | |||||
11419 | sip_t const *sip) | |||||
11420 | { | |||||
11421 | nta_agent_t *agent; | |||||
11422 | nta_leg_t *leg; | |||||
11423 | char const *method_name; | |||||
11424 | url_t url[1]; | |||||
11425 | int retval; | |||||
11426 | ||||||
11427 | if (irq == NULL((void*)0) || sip == NULL((void*)0) || rel == NULL((void*)0) || | |||||
11428 | sip_object(irq->irq_request) != sip) | |||||
11429 | return 500; | |||||
11430 | ||||||
11431 | agent = irq->irq_agent; | |||||
11432 | method_name = sip->sip_request->rq_method_name; | |||||
11433 | *url = *sip->sip_request->rq_url; url->url_params = NULL((void*)0); | |||||
11434 | agent_aliases(agent, url, irq->irq_tport); /* canonize urls */ | |||||
11435 | ||||||
11436 | if ((leg = leg_find(irq->irq_agent, | |||||
11437 | method_name, url, | |||||
11438 | sip->sip_call_id, | |||||
11439 | sip->sip_from->a_tag, | |||||
11440 | sip->sip_to->a_tag))) { | |||||
11441 | /* Use existing dialog */ | |||||
11442 | SU_DEBUG_5(("nta: %s (%u) %s\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 11444, "nta: %s (%u) %s\n", method_name, sip->sip_cseq-> cs_seq, "PRACK processed by default callback, too")) : (void) 0) | |||||
11443 | method_name, sip->sip_cseq->cs_seq,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 11444, "nta: %s (%u) %s\n", method_name, sip->sip_cseq-> cs_seq, "PRACK processed by default callback, too")) : (void) 0) | |||||
11444 | "PRACK processed by default callback, too"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 11444, "nta: %s (%u) %s\n", method_name, sip->sip_cseq-> cs_seq, "PRACK processed by default callback, too")) : (void) 0); | |||||
11445 | retval = leg->leg_callback(leg->leg_magic, leg, irq, sip); | |||||
11446 | } | |||||
11447 | else { | |||||
11448 | retval = 500; | |||||
11449 | } | |||||
11450 | ||||||
11451 | nta_reliable_destroy(rel); | |||||
11452 | ||||||
11453 | return retval; | |||||
11454 | } | |||||
11455 | #endif | |||||
11456 | ||||||
11457 | /** Destroy a reliable response. | |||||
11458 | * | |||||
11459 | * Mark a reliable response object for destroyal and free it if possible. | |||||
11460 | */ | |||||
11461 | void nta_reliable_destroy(nta_reliable_t *rel) | |||||
11462 | { | |||||
11463 | if (rel == NULL((void*)0) || rel == NONE((void *)-1)) | |||||
11464 | return; | |||||
11465 | ||||||
11466 | if (rel->rel_callback == nta_reliable_destroyed) | |||||
11467 | SU_DEBUG_1(("%s(%p): %s\n", __func__, (void *)rel, "already destroyed"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 11467, "%s(%p): %s\n", __func__, (void *)rel, "already destroyed" )) : (void)0); | |||||
11468 | ||||||
11469 | rel->rel_callback = nta_reliable_destroyed; | |||||
11470 | ||||||
11471 | if (rel->rel_response) | |||||
11472 | return; | |||||
11473 | ||||||
11474 | nta_reliable_destroyed(NULL((void*)0), rel, NULL((void*)0), NULL((void*)0)); | |||||
11475 | } | |||||
11476 | ||||||
11477 | /** Free and unallocate the nta_reliable_t structure. */ | |||||
11478 | static | |||||
11479 | int nta_reliable_destroyed(nta_reliable_magic_t *rmagic, | |||||
11480 | nta_reliable_t *rel, | |||||
11481 | nta_incoming_t *prack, | |||||
11482 | sip_t const *sip) | |||||
11483 | { | |||||
11484 | nta_reliable_t **prev; | |||||
11485 | ||||||
11486 | assert(rel)((void) sizeof ((rel) ? 1 : 0), __extension__ ({ if (rel) ; else __assert_fail ("rel", "nta.c", 11486, __extension__ __PRETTY_FUNCTION__ ); })); assert(rel->rel_irq)((void) sizeof ((rel->rel_irq) ? 1 : 0), __extension__ ({ if (rel->rel_irq) ; else __assert_fail ("rel->rel_irq", "nta.c" , 11486, __extension__ __PRETTY_FUNCTION__); })); | |||||
11487 | ||||||
11488 | for (prev = &rel->rel_irq->irq_reliable; *prev; prev = &(*prev)->rel_next) | |||||
11489 | if (*prev == rel) | |||||
11490 | break; | |||||
11491 | ||||||
11492 | if (!*prev) { | |||||
11493 | assert(*prev)((void) sizeof ((*prev) ? 1 : 0), __extension__ ({ if (*prev) ; else __assert_fail ("*prev", "nta.c", 11493, __extension__ __PRETTY_FUNCTION__); })); | |||||
11494 | SU_DEBUG_1(("%s(%p): %s\n", __func__, (void *)rel, "not linked"))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 11494, "%s(%p): %s\n", __func__, (void *)rel, "not linked") ) : (void)0); | |||||
11495 | return 200; | |||||
11496 | } | |||||
11497 | ||||||
11498 | *prev = rel->rel_next; | |||||
11499 | ||||||
11500 | if (rel->rel_unsent) | |||||
11501 | msg_destroy(rel->rel_unsent), rel->rel_unsent = NULL((void*)0); | |||||
11502 | ||||||
11503 | su_free(rel->rel_irq->irq_agent->sa_home, rel); | |||||
11504 | ||||||
11505 | return 200; | |||||
11506 | } | |||||
11507 | ||||||
11508 | /** Validate a reliable response. */ | |||||
11509 | int outgoing_recv_reliable(nta_outgoing_t *orq, | |||||
11510 | msg_t *msg, | |||||
11511 | sip_t *sip) | |||||
11512 | { | |||||
11513 | short status = sip->sip_status->st_status; | |||||
11514 | char const *phrase = sip->sip_status->st_phrase; | |||||
11515 | uint32_t rseq = sip->sip_rseq->rs_response; | |||||
11516 | ||||||
11517 | SU_DEBUG_7(("nta: %03u %s is reliably received with RSeq: %u\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__ , 11518, "nta: %03u %s is reliably received with RSeq: %u\n", status, phrase, rseq)) : (void)0) | |||||
11518 | status, phrase, rseq))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 7 ? (_su_llog(nta_log, 7, "nta.c", (const char *)__func__ , 11518, "nta: %03u %s is reliably received with RSeq: %u\n", status, phrase, rseq)) : (void)0); | |||||
11519 | ||||||
11520 | /* Cannot handle reliable responses unless we have a full dialog */ | |||||
11521 | if (orq->orq_rseq == 0 && !orq->orq_to->a_tag) { | |||||
11522 | SU_DEBUG_5(("nta: %03u %s with initial RSeq: %u outside dialog\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 11523, "nta: %03u %s with initial RSeq: %u outside dialog\n" , status, phrase, rseq)) : (void)0) | |||||
11523 | status, phrase, rseq))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 5 ? (_su_llog(nta_log, 5, "nta.c", (const char *)__func__ , 11523, "nta: %03u %s with initial RSeq: %u outside dialog\n" , status, phrase, rseq)) : (void)0); | |||||
11524 | return 0; | |||||
11525 | } | |||||
11526 | ||||||
11527 | if (rseq <= orq->orq_rseq) { | |||||
11528 | SU_DEBUG_3(("nta: %03u %s already received (RSeq: %u, expecting %u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 11529, "nta: %03u %s already received (RSeq: %u, expecting %u)\n" , status, phrase, rseq, orq->orq_rseq + 1)) : (void)0) | |||||
11529 | status, phrase, rseq, orq->orq_rseq + 1))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 11529, "nta: %03u %s already received (RSeq: %u, expecting %u)\n" , status, phrase, rseq, orq->orq_rseq + 1)) : (void)0); | |||||
11530 | return -1; | |||||
11531 | } | |||||
11532 | ||||||
11533 | if (orq->orq_rseq && orq->orq_rseq + 1 != rseq) { | |||||
11534 | SU_DEBUG_3(("nta: %03d %s is not expected (RSeq: %u, expecting %u)\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 11536, "nta: %03d %s is not expected (RSeq: %u, expecting %u)\n" , status, sip->sip_status->st_phrase, rseq, orq->orq_rseq + 1)) : (void)0) | |||||
11535 | status, sip->sip_status->st_phrase,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 11536, "nta: %03d %s is not expected (RSeq: %u, expecting %u)\n" , status, sip->sip_status->st_phrase, rseq, orq->orq_rseq + 1)) : (void)0) | |||||
11536 | rseq, orq->orq_rseq + 1))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 3 ? (_su_llog(nta_log, 3, "nta.c", (const char *)__func__ , 11536, "nta: %03d %s is not expected (RSeq: %u, expecting %u)\n" , status, sip->sip_status->st_phrase, rseq, orq->orq_rseq + 1)) : (void)0); | |||||
11537 | return -1; | |||||
11538 | } | |||||
11539 | ||||||
11540 | return 0; | |||||
11541 | } | |||||
11542 | ||||||
11543 | /** Create a tagged fork of outgoing request. | |||||
11544 | * | |||||
11545 | * When a dialog-creating INVITE request is forked, each response from | |||||
11546 | * diffent fork will create an early dialog with a distinct tag in @To | |||||
11547 | * header. When each fork should be handled separately, a tagged INVITE | |||||
11548 | * request can be used. It will only receive responses from the specified | |||||
11549 | * fork. Please note that the tagged transaction should be terminated with | |||||
11550 | * the final response from another fork, too. | |||||
11551 | * | |||||
11552 | * @param orq | |||||
11553 | * @param callback | |||||
11554 | * @param magic | |||||
11555 | * @param to_tag | |||||
11556 | * @param rseq | |||||
11557 | * | |||||
11558 | * @bug Fix the memory leak - either one of the requests is left unreleased | |||||
11559 | * for ever. | |||||
11560 | */ | |||||
11561 | nta_outgoing_t *nta_outgoing_tagged(nta_outgoing_t *orq, | |||||
11562 | nta_response_f *callback, | |||||
11563 | nta_outgoing_magic_t *magic, | |||||
11564 | char const *to_tag, | |||||
11565 | sip_rseq_t const *rseq) | |||||
11566 | { | |||||
11567 | nta_agent_t *agent; | |||||
11568 | su_home_t *home; | |||||
11569 | nta_outgoing_t *tagged; | |||||
11570 | sip_to_t *to; | |||||
11571 | ||||||
11572 | if (orq == NULL((void*)0) || to_tag == NULL((void*)0)) | |||||
11573 | return NULL((void*)0); | |||||
11574 | ||||||
11575 | if (orq->orq_to->a_tag) { | |||||
11576 | SU_DEBUG_1(("%s: transaction %p (CSeq: %s %u) already in dialog\n", __func__,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 11577, "%s: transaction %p (CSeq: %s %u) already in dialog\n" , __func__, (void *)orq, orq->orq_cseq->cs_method_name, orq->orq_cseq->cs_seq)) : (void)0) | |||||
11577 | (void *)orq, orq->orq_cseq->cs_method_name, orq->orq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 11577, "%s: transaction %p (CSeq: %s %u) already in dialog\n" , __func__, (void *)orq, orq->orq_cseq->cs_method_name, orq->orq_cseq->cs_seq)) : (void)0); | |||||
11578 | return NULL((void*)0); | |||||
11579 | } | |||||
11580 | if (orq->orq_method != sip_method_invite) { | |||||
11581 | SU_DEBUG_1(("%s: transaction %p (CSeq: %s %u) cannot be tagged\n", __func__,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 11582, "%s: transaction %p (CSeq: %s %u) cannot be tagged\n" , __func__, (void *)orq, orq->orq_cseq->cs_method_name, orq->orq_cseq->cs_seq)) : (void)0) | |||||
11582 | (void *)orq, orq->orq_cseq->cs_method_name, orq->orq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 11582, "%s: transaction %p (CSeq: %s %u) cannot be tagged\n" , __func__, (void *)orq, orq->orq_cseq->cs_method_name, orq->orq_cseq->cs_seq)) : (void)0); | |||||
11583 | return NULL((void*)0); | |||||
11584 | } | |||||
11585 | if (orq->orq_status < 100) { | |||||
11586 | SU_DEBUG_1(("%s: transaction %p (CSeq: %s %u) still calling\n", __func__,(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 11587, "%s: transaction %p (CSeq: %s %u) still calling\n", __func__ , (void *)orq, orq->orq_cseq->cs_method_name, orq->orq_cseq ->cs_seq)) : (void)0) | |||||
11587 | (void *)orq, orq->orq_cseq->cs_method_name, orq->orq_cseq->cs_seq))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 11587, "%s: transaction %p (CSeq: %s %u) still calling\n", __func__ , (void *)orq, orq->orq_cseq->cs_method_name, orq->orq_cseq ->cs_seq)) : (void)0); | |||||
11588 | return NULL((void*)0); | |||||
11589 | } | |||||
11590 | ||||||
11591 | assert(orq->orq_agent)((void) sizeof ((orq->orq_agent) ? 1 : 0), __extension__ ( { if (orq->orq_agent) ; else __assert_fail ("orq->orq_agent" , "nta.c", 11591, __extension__ __PRETTY_FUNCTION__); })); assert(orq->orq_request)((void) sizeof ((orq->orq_request) ? 1 : 0), __extension__ ({ if (orq->orq_request) ; else __assert_fail ("orq->orq_request" , "nta.c", 11591, __extension__ __PRETTY_FUNCTION__); })); | |||||
11592 | ||||||
11593 | agent = orq->orq_agent; | |||||
11594 | tagged = su_zalloc(agent->sa_home, sizeof(*tagged)); | |||||
11595 | ||||||
11596 | home = msg_home((msg_t *)orq->orq_request)((su_home_t*)((msg_t *)orq->orq_request)); | |||||
11597 | ||||||
11598 | tagged->orq_hash = orq->orq_hash; | |||||
11599 | tagged->orq_agent = orq->orq_agent; | |||||
11600 | tagged->orq_callback = callback; | |||||
11601 | tagged->orq_magic = magic; | |||||
11602 | ||||||
11603 | tagged->orq_method = orq->orq_method; | |||||
11604 | tagged->orq_method_name = orq->orq_method_name; | |||||
11605 | tagged->orq_url = orq->orq_url; | |||||
11606 | tagged->orq_from = orq->orq_from; | |||||
11607 | ||||||
11608 | sip_to_tag(home, to = sip_to_copy(home, orq->orq_to), to_tag); | |||||
11609 | ||||||
11610 | tagged->orq_to = to; | |||||
11611 | tagged->orq_tag = to->a_tag; | |||||
11612 | tagged->orq_cseq = orq->orq_cseq; | |||||
11613 | tagged->orq_call_id = orq->orq_call_id; | |||||
11614 | ||||||
11615 | tagged->orq_request = msg_ref_create(orq->orq_request); | |||||
11616 | tagged->orq_response = msg_ref_create(orq->orq_response); | |||||
11617 | ||||||
11618 | tagged->orq_status = orq->orq_status; | |||||
11619 | tagged->orq_via_added = orq->orq_via_added; | |||||
11620 | tagged->orq_prepared = orq->orq_prepared; | |||||
11621 | tagged->orq_reliable = orq->orq_reliable; | |||||
11622 | tagged->orq_sips = orq->orq_sips; | |||||
11623 | tagged->orq_uas = orq->orq_uas; | |||||
11624 | tagged->orq_pass_100 = orq->orq_pass_100; | |||||
11625 | tagged->orq_must_100rel = orq->orq_must_100rel; | |||||
11626 | tagged->orq_100rel = orq->orq_100rel; | |||||
11627 | tagged->orq_route = orq->orq_route; | |||||
11628 | *tagged->orq_tpn = *orq->orq_tpn; | |||||
11629 | tagged->orq_tport = tport_ref(orq->orq_tport); | |||||
11630 | if (orq->orq_cc) | |||||
11631 | tagged->orq_cc = nta_compartment_ref(orq->orq_cc); | |||||
11632 | tagged->orq_branch = orq->orq_branch; | |||||
11633 | tagged->orq_via_branch = orq->orq_via_branch; | |||||
11634 | ||||||
11635 | if (tagged->orq_uas) { | |||||
11636 | tagged->orq_forking = orq; | |||||
11637 | tagged->orq_forks = orq->orq_forks; | |||||
11638 | tagged->orq_forked = 1; | |||||
11639 | orq->orq_forks = tagged; | |||||
11640 | } | |||||
11641 | ||||||
11642 | outgoing_insert(agent, tagged); | |||||
11643 | ||||||
11644 | return tagged; | |||||
11645 | } | |||||
11646 | ||||||
11647 | /**PRACK a provisional response. | |||||
11648 | * | |||||
11649 | * Create and send a PRACK request used to acknowledge a provisional | |||||
11650 | * response. | |||||
11651 | * | |||||
11652 | * The request is sent using the route of the original request @a oorq. | |||||
11653 | * | |||||
11654 | * When NTA receives response to the prack request, it invokes the @a | |||||
11655 | * callback function. | |||||
11656 | * | |||||
11657 | * @param leg dialog object | |||||
11658 | * @param oorq original transaction request | |||||
11659 | * @param callback callback function (may be @c NULL) | |||||
11660 | * @param magic application context pointer | |||||
11661 | * @param route_url optional URL used to route transaction requests | |||||
11662 | * @param resp (optional) response message to be acknowledged | |||||
11663 | * @param tag,value,... optional | |||||
11664 | * | |||||
11665 | * @return | |||||
11666 | * If successful, return a pointer to newly created client transaction | |||||
11667 | * object for PRACK request, NULL otherwise. | |||||
11668 | * | |||||
11669 | * @sa | |||||
11670 | * nta_outgoing_tcreate(), nta_outgoing_tcancel(), nta_outgoing_destroy(). | |||||
11671 | */ | |||||
11672 | nta_outgoing_t *nta_outgoing_prack(nta_leg_t *leg, | |||||
11673 | nta_outgoing_t *oorq, | |||||
11674 | nta_response_f *callback, | |||||
11675 | nta_outgoing_magic_t *magic, | |||||
11676 | url_string_t const *route_url, | |||||
11677 | sip_t const *resp, | |||||
11678 | tag_type_t tag, tag_value_t value, ...) | |||||
11679 | { | |||||
11680 | ta_list ta; | |||||
11681 | msg_t *msg; | |||||
11682 | su_home_t *home; | |||||
11683 | sip_t *sip; | |||||
11684 | sip_to_t const *to = NULL((void*)0); | |||||
11685 | sip_route_t *route = NULL((void*)0), r0[1]; | |||||
11686 | nta_outgoing_t *orq = NULL((void*)0); | |||||
11687 | sip_rack_t *rack = NULL((void*)0), rack0[1]; | |||||
11688 | ||||||
11689 | if (!leg || !oorq) { | |||||
11690 | SU_DEBUG_1(("%s: invalid arguments\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 11690, "%s: invalid arguments\n", __func__)) : (void)0); | |||||
11691 | return NULL((void*)0); | |||||
11692 | } | |||||
11693 | ||||||
11694 | sip_rack_init(rack0); | |||||
11695 | ||||||
11696 | if (resp) { | |||||
11697 | if (!resp->sip_status) { | |||||
11698 | SU_DEBUG_1(("%s: invalid arguments\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 11698, "%s: invalid arguments\n", __func__)) : (void)0); | |||||
11699 | return NULL((void*)0); | |||||
11700 | } | |||||
11701 | ||||||
11702 | if (resp->sip_status->st_status <= 100 || | |||||
11703 | resp->sip_status->st_status >= 200) { | |||||
11704 | SU_DEBUG_1(("%s: %u response cannot be PRACKed\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 11705, "%s: %u response cannot be PRACKed\n", __func__, resp ->sip_status->st_status)) : (void)0) | |||||
11705 | __func__, resp->sip_status->st_status))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 11705, "%s: %u response cannot be PRACKed\n", __func__, resp ->sip_status->st_status)) : (void)0); | |||||
11706 | return NULL((void*)0); | |||||
11707 | } | |||||
11708 | ||||||
11709 | if (!resp->sip_rseq) { | |||||
11710 | SU_DEBUG_1(("%s: %u response missing RSeq\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 11711, "%s: %u response missing RSeq\n", __func__, resp-> sip_status->st_status)) : (void)0) | |||||
11711 | __func__, resp->sip_status->st_status))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 11711, "%s: %u response missing RSeq\n", __func__, resp-> sip_status->st_status)) : (void)0); | |||||
11712 | return NULL((void*)0); | |||||
11713 | } | |||||
11714 | ||||||
11715 | if (resp->sip_rseq->rs_response <= oorq->orq_rseq) { | |||||
11716 | SU_DEBUG_1(("%s: %u response RSeq does not match received RSeq\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 11717, "%s: %u response RSeq does not match received RSeq\n" , __func__, resp->sip_status->st_status)) : (void)0) | |||||
11717 | __func__, resp->sip_status->st_status))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 11717, "%s: %u response RSeq does not match received RSeq\n" , __func__, resp->sip_status->st_status)) : (void)0); | |||||
11718 | return NULL((void*)0); | |||||
11719 | } | |||||
11720 | if (!oorq->orq_must_100rel && | |||||
11721 | !sip_has_feature(resp->sip_require, "100rel")) { | |||||
11722 | SU_DEBUG_1(("%s: %u response does not require 100rel\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 11723, "%s: %u response does not require 100rel\n", __func__ , resp->sip_status->st_status)) : (void)0) | |||||
11723 | __func__, resp->sip_status->st_status))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 11723, "%s: %u response does not require 100rel\n", __func__ , resp->sip_status->st_status)) : (void)0); | |||||
11724 | return NULL((void*)0); | |||||
11725 | } | |||||
11726 | ||||||
11727 | if (!resp->sip_to->a_tag) { | |||||
11728 | SU_DEBUG_1(("%s: %u response has no To tag\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 11729, "%s: %u response has no To tag\n", __func__, resp-> sip_status->st_status)) : (void)0) | |||||
11729 | __func__, resp->sip_status->st_status))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 11729, "%s: %u response has no To tag\n", __func__, resp-> sip_status->st_status)) : (void)0); | |||||
11730 | return NULL((void*)0); | |||||
11731 | } | |||||
11732 | if (su_strcasecmp(resp->sip_to->a_tag, leg->leg_remote->a_tag) || | |||||
11733 | su_strcasecmp(resp->sip_to->a_tag, oorq->orq_to->a_tag)) { | |||||
11734 | SU_DEBUG_1(("%s: %u response To tag does not agree with dialog tag\n",(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 11735, "%s: %u response To tag does not agree with dialog tag\n" , __func__, resp->sip_status->st_status)) : (void)0) | |||||
11735 | __func__, resp->sip_status->st_status))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 11735, "%s: %u response To tag does not agree with dialog tag\n" , __func__, resp->sip_status->st_status)) : (void)0); | |||||
11736 | return NULL((void*)0); | |||||
11737 | } | |||||
11738 | ||||||
11739 | to = resp->sip_to; | |||||
11740 | rack = rack0; | |||||
11741 | ||||||
11742 | rack->ra_response = resp->sip_rseq->rs_response; | |||||
11743 | rack->ra_cseq = resp->sip_cseq->cs_seq; | |||||
11744 | rack->ra_method = resp->sip_cseq->cs_method; | |||||
11745 | rack->ra_method_name = resp->sip_cseq->cs_method_name; | |||||
11746 | } | |||||
11747 | ||||||
11748 | msg = nta_msg_create(leg->leg_agent, 0); | |||||
11749 | sip = sip_object(msg); home = msg_home(msg)((su_home_t*)(msg)); | |||||
11750 | ||||||
11751 | if (!sip) | |||||
11752 | return NULL((void*)0); | |||||
11753 | ||||||
11754 | if (!leg->leg_route && resp) { | |||||
11755 | /* Insert contact into route */ | |||||
11756 | if (resp->sip_contact) { | |||||
11757 | sip_route_init(r0)->r_url[0] = resp->sip_contact->m_url[0]; | |||||
11758 | route = sip_route_dup(home, r0); | |||||
11759 | } | |||||
11760 | ||||||
11761 | /* Reverse record route */ | |||||
11762 | if (resp->sip_record_route) { | |||||
11763 | sip_route_t *r, *r_next; | |||||
11764 | for (r = sip_route_dup(home, resp->sip_record_route); r; r = r_next) { | |||||
11765 | r_next = r->r_next, r->r_next = route, route = r; | |||||
11766 | } | |||||
11767 | } | |||||
11768 | } | |||||
11769 | ||||||
11770 | ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value = (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag ) == tag_next && (ta_start__value) != 0) { ta_start__tag = ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag == tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag == tag_next) { ta_start__value = ((tagi_t *)ta_start__value) ->t_value; } else { ta_start__tag = tag_next; break; } } ( ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value ; if (ta_start__tag != ((void*)0) && ta_start__tag != tag_null && ta_start__tag != tag_next) { va_list ta_start__ap ; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag = tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap ); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value = 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0); | |||||
11771 | ||||||
11772 | if (!resp) { | |||||
11773 | tagi_t const *t; | |||||
11774 | ||||||
11775 | if ((t = tl_find(ta_args(ta)(ta).tl, ntatag_rseq)) && t->t_value) { | |||||
11776 | rack = rack0; | |||||
11777 | rack->ra_response = (uint32_t)t->t_value; | |||||
11778 | } | |||||
11779 | ||||||
11780 | if (rack) { | |||||
11781 | rack->ra_cseq = oorq->orq_cseq->cs_seq; | |||||
11782 | rack->ra_method = oorq->orq_cseq->cs_method; | |||||
11783 | rack->ra_method_name = oorq->orq_cseq->cs_method_name; | |||||
11784 | } | |||||
11785 | } | |||||
11786 | ||||||
11787 | if (sip_add_tl(msg, sip, | |||||
11788 | TAG_IF(rack, SIPTAG_RACK(rack))!(rack) ? tag_skip : siptag_rack, siptag_rack_v(rack), | |||||
11789 | TAG_IF(to, SIPTAG_TO(to))!(to) ? tag_skip : siptag_to, siptag_to_v(to), | |||||
11790 | ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta). tl[1].t_value) < 0) | |||||
11791 | ; | |||||
11792 | else if (route && sip_add_dup(msg, sip, (sip_header_t *)route) < 0) | |||||
11793 | ; | |||||
11794 | else if (!sip->sip_rack) | |||||
11795 | SU_DEBUG_1(("%s: RAck header missing\n", __func__))(((nta_log != ((void*)0) && nta_log->log_init) == 0 ? 9 : ((nta_log != ((void*)0) && nta_log->log_init > 1) ? nta_log->log_level : su_log_default->log_level )) >= 1 ? (_su_llog(nta_log, 1, "nta.c", (const char *)__func__ , 11795, "%s: RAck header missing\n", __func__)) : (void)0); | |||||
11796 | else if (nta_msg_request_complete(msg, leg, | |||||
11797 | SIP_METHOD_PRACKsip_method_prack, "PRACK", | |||||
11798 | (url_string_t *)oorq->orq_url) < 0) | |||||
11799 | ; | |||||
11800 | else | |||||
11801 | orq = outgoing_create(leg->leg_agent, callback, magic, | |||||
11802 | route_url, NULL((void*)0), msg, ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta). tl[1].t_value); | |||||
11803 | ||||||
11804 | ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value ))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta) .ap)); | |||||
11805 | ||||||
11806 | if (!orq) | |||||
11807 | msg_destroy(msg); | |||||
11808 | else if (rack) | |||||
11809 | oorq->orq_rseq = rack->ra_response; | |||||
11810 | else if (sip->sip_rack) | |||||
11811 | oorq->orq_rseq = sip->sip_rack->ra_response; | |||||
11812 | ||||||
11813 | return orq; | |||||
11814 | } | |||||
11815 | ||||||
11816 | /** Get @RSeq value stored with client transaction. */ | |||||
11817 | uint32_t nta_outgoing_rseq(nta_outgoing_t const *orq) | |||||
11818 | { | |||||
11819 | return orq ? orq->orq_rseq : 0; | |||||
11820 | } | |||||
11821 | ||||||
11822 | /** Set @RSeq value stored with client transaction. | |||||
11823 | * | |||||
11824 | * @return 0 if rseq was set successfully | |||||
11825 | * @return -1 if rseq is invalid or orq is NULL. | |||||
11826 | */ | |||||
11827 | int nta_outgoing_setrseq(nta_outgoing_t *orq, uint32_t rseq) | |||||
11828 | { | |||||
11829 | if (orq && orq->orq_rseq <= rseq) { | |||||
11830 | orq->orq_rseq = rseq; | |||||
11831 | return 0; | |||||
11832 | } | |||||
11833 | ||||||
11834 | return -1; | |||||
11835 | } | |||||
11836 | ||||||
11837 | /* ------------------------------------------------------------------------ */ | |||||
11838 | /* 11) SigComp handling and public transport interface */ | |||||
11839 | ||||||
11840 | #include <sofia-sip/nta_tport.h> | |||||
11841 | ||||||
11842 | /** Return the master transport for the agent. | |||||
11843 | * | |||||
11844 | * @NEW_1_12_11 | |||||
11845 | */ | |||||
11846 | tport_t * | |||||
11847 | nta_agent_tports(nta_agent_t *agent) | |||||
11848 | { | |||||
11849 | return agent ? agent->sa_tports : NULL((void*)0); | |||||
11850 | } | |||||
11851 | ||||||
11852 | su_inlinestatic inline tport_t * | |||||
11853 | nta_transport_(nta_agent_t *agent, | |||||
11854 | nta_incoming_t *irq, | |||||
11855 | msg_t *msg) | |||||
11856 | { | |||||
11857 | if (irq) | |||||
11858 | return irq->irq_tport; | |||||
11859 | else if (agent && msg) | |||||
11860 | return tport_delivered_by(agent->sa_tports, msg); | |||||
11861 | ||||||
11862 | errno(*__errno_location ()) = EINVAL22; | |||||
11863 | return NULL((void*)0); | |||||
11864 | } | |||||
11865 | ||||||
11866 | ||||||
11867 | /** Return a new reference to the transaction transport. | |||||
11868 | * | |||||
11869 | * @note The referenced transport must be unreferenced with tport_unref() | |||||
11870 | */ | |||||
11871 | tport_t * | |||||
11872 | nta_incoming_transport(nta_agent_t *agent, | |||||
11873 | nta_incoming_t *irq, | |||||
11874 | msg_t *msg) | |||||
11875 | { | |||||
11876 | return tport_ref(nta_transport_(agent, irq, msg)); | |||||
11877 | } | |||||
11878 | ||||||
11879 | nta_compressor_t *nta_agent_init_sigcomp(nta_agent_t *sa) | |||||
11880 | { | |||||
11881 | if (!nta_compressor_vtable || !sa) | |||||
11882 | return NULL((void*)0); | |||||
11883 | ||||||
11884 | if (sa->sa_compressor == NULL((void*)0)) { | |||||
11885 | char const * const *l = sa->sa_sigcomp_option_list; | |||||
11886 | nta_compressor_t *comp; | |||||
11887 | comp = nta_compressor_vtable->ncv_init_agent(sa, l); | |||||
11888 | sa->sa_compressor = comp; | |||||
11889 | } | |||||
11890 | ||||||
11891 | return sa->sa_compressor; | |||||
11892 | } | |||||
11893 | ||||||
11894 | void nta_agent_deinit_sigcomp(nta_agent_t *sa) | |||||
11895 | { | |||||
11896 | if (nta_compressor_vtable && sa && sa->sa_compressor) { | |||||
11897 | nta_compressor_vtable->ncv_deinit_agent(sa, sa->sa_compressor); | |||||
11898 | sa->sa_compressor = NULL((void*)0); | |||||
11899 | } | |||||
11900 | } | |||||
11901 | ||||||
11902 | struct sigcomp_compartment * | |||||
11903 | nta_incoming_compartment(nta_incoming_t *irq) | |||||
11904 | { | |||||
11905 | if (nta_compressor_vtable && irq && irq->irq_cc) | |||||
11906 | return nta_compressor_vtable->ncv_compartment_ref(irq->irq_cc); | |||||
11907 | else | |||||
11908 | return NULL((void*)0); | |||||
11909 | } | |||||
11910 | ||||||
11911 | tport_t * | |||||
11912 | nta_outgoing_transport(nta_outgoing_t *orq) | |||||
11913 | { | |||||
11914 | if (orq) | |||||
11915 | return tport_ref(orq->orq_tport); | |||||
11916 | else | |||||
11917 | return NULL((void*)0); | |||||
11918 | } | |||||
11919 | ||||||
11920 | ||||||
11921 | struct sigcomp_compartment * | |||||
11922 | nta_outgoing_compartment(nta_outgoing_t *orq) | |||||
11923 | { | |||||
11924 | if (nta_compressor_vtable && orq && orq->orq_cc) | |||||
11925 | return nta_compressor_vtable->ncv_compartment_ref(orq->orq_cc); | |||||
11926 | else | |||||
11927 | return NULL((void*)0); | |||||
11928 | } | |||||
11929 | ||||||
11930 | ||||||
11931 | struct sigcomp_compartment * | |||||
11932 | nta_compartment_ref(struct sigcomp_compartment *cc) | |||||
11933 | { | |||||
11934 | if (nta_compressor_vtable) | |||||
11935 | return nta_compressor_vtable->ncv_compartment_ref(cc); | |||||
11936 | else | |||||
11937 | return NULL((void*)0); | |||||
11938 | } | |||||
11939 | ||||||
11940 | void | |||||
11941 | nta_compartment_decref(struct sigcomp_compartment **pcc) | |||||
11942 | { | |||||
11943 | if (nta_compressor_vtable && pcc && *pcc) | |||||
11944 | nta_compressor_vtable->ncv_compartment_unref(*pcc), *pcc = NULL((void*)0); | |||||
11945 | } | |||||
11946 | ||||||
11947 | ||||||
11948 | /** Get compartment for connection, create it when needed. */ | |||||
11949 | static | |||||
11950 | struct sigcomp_compartment * | |||||
11951 | agent_compression_compartment(nta_agent_t *sa, | |||||
11952 | tport_t *tp, | |||||
11953 | tp_name_t const *tpn, | |||||
11954 | int new_if_needed) | |||||
11955 | { | |||||
11956 | if (nta_compressor_vtable) { | |||||
11957 | char const * const *l = sa->sa_sigcomp_option_list; | |||||
11958 | return nta_compressor_vtable-> | |||||
11959 | ncv_compartment(sa, tp, sa->sa_compressor, tpn, l, new_if_needed); | |||||
11960 | } | |||||
11961 | else | |||||
11962 | return NULL((void*)0); | |||||
11963 | } | |||||
11964 | ||||||
11965 | static | |||||
11966 | int agent_accept_compressed(nta_agent_t *sa, msg_t *msg, | |||||
11967 | struct sigcomp_compartment *cc) | |||||
11968 | { | |||||
11969 | if (nta_compressor_vtable) { | |||||
11970 | nta_compressor_t *msc = sa->sa_compressor; | |||||
11971 | tport_compressor_t *sc = NULL((void*)0); | |||||
11972 | if (tport_delivered_with_comp(sa->sa_tports, msg, &sc) < 0) | |||||
11973 | return 0; | |||||
11974 | return nta_compressor_vtable->ncv_accept_compressed(sa, msc, sc, msg, cc); | |||||
11975 | } | |||||
11976 | else | |||||
11977 | return 0; | |||||
11978 | } | |||||
11979 | ||||||
11980 | /** Close compressor (lose its state). */ | |||||
11981 | static | |||||
11982 | int agent_close_compressor(nta_agent_t *sa, | |||||
11983 | struct sigcomp_compartment *cc) | |||||
11984 | { | |||||
11985 | if (nta_compressor_vtable) | |||||
11986 | return nta_compressor_vtable->ncv_close_compressor(sa, cc); | |||||
11987 | return 0; | |||||
11988 | } | |||||
11989 | ||||||
11990 | /** Close both compressor and decompressor */ | |||||
11991 | static | |||||
11992 | int agent_zap_compressor(nta_agent_t *sa, | |||||
11993 | struct sigcomp_compartment *cc) | |||||
11994 | { | |||||
11995 | if (nta_compressor_vtable) | |||||
11996 | return nta_compressor_vtable->ncv_zap_compressor(sa, cc); | |||||
11997 | return 0; | |||||
11998 | } | |||||
11999 | ||||||
12000 | /** Bind transport update callback */ | |||||
12001 | int nta_agent_bind_tport_update(nta_agent_t *agent, | |||||
12002 | nta_update_magic_t *magic, | |||||
12003 | nta_update_tport_f *callback) | |||||
12004 | { | |||||
12005 | if (!agent) | |||||
12006 | return su_seterrno(EFAULT14), -1; | |||||
12007 | agent->sa_update_magic = magic; | |||||
12008 | agent->sa_update_tport = callback; | |||||
12009 | return 0; | |||||
12010 | } | |||||
12011 | ||||||
12012 | /** Bind transport error callback */ | |||||
12013 | int nta_agent_bind_tport_error(nta_agent_t *agent, | |||||
12014 | nta_error_magic_t *magic, | |||||
12015 | nta_error_tport_f *callback) | |||||
12016 | { | |||||
12017 | if (!agent) | |||||
12018 | return su_seterrno(EFAULT14), -1; | |||||
12019 | agent->sa_error_magic = magic; | |||||
12020 | agent->sa_error_tport = callback; | |||||
12021 | return 0; | |||||
12022 | } | |||||
12023 | ||||||
12024 | /** Check if public transport binding is in progress */ | |||||
12025 | int nta_agent_tport_is_updating(nta_agent_t *agent) | |||||
12026 | { | |||||
12027 | return agent && tport_is_updating(agent->sa_tports); | |||||
12028 | } | |||||
12029 | ||||||
12030 | /** Initiate STUN keepalive controller to TPORT */ | |||||
12031 | int nta_tport_keepalive(nta_outgoing_t *orq) | |||||
12032 | { | |||||
12033 | assert(orq)((void) sizeof ((orq) ? 1 : 0), __extension__ ({ if (orq) ; else __assert_fail ("orq", "nta.c", 12033, __extension__ __PRETTY_FUNCTION__ ); })); | |||||
12034 | ||||||
12035 | #if HAVE_SOFIA_STUN | |||||
12036 | return tport_keepalive(orq->orq_tport, msg_addrinfo(orq->orq_request), | |||||
12037 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||||
12038 | #else | |||||
12039 | return -1; | |||||
12040 | #endif | |||||
12041 | } | |||||
12042 | ||||||
12043 | /** Close all transports. @since Experimental in @VERSION_1_12_2. */ | |||||
12044 | int nta_agent_close_tports(nta_agent_t *agent) | |||||
12045 | { | |||||
12046 | size_t i; | |||||
12047 | outgoing_htable_t *oht = agent->sa_outgoing; | |||||
12048 | incoming_htable_t *iht = agent->sa_incoming; | |||||
12049 | ||||||
12050 | for (i = oht->oht_size; i-- > 0;) | |||||
12051 | /* while */ if (oht->oht_table[i]) { | |||||
12052 | nta_outgoing_t *orq = oht->oht_table[i]; | |||||
12053 | ||||||
12054 | if (orq->orq_pending && orq->orq_tport) | |||||
12055 | tport_release(orq->orq_tport, orq->orq_pending, orq->orq_request, | |||||
12056 | NULL((void*)0), orq, 0); | |||||
12057 | ||||||
12058 | orq->orq_pending = 0; | |||||
12059 | tport_unref(orq->orq_tport), orq->orq_tport = NULL((void*)0); | |||||
12060 | } | |||||
12061 | ||||||
12062 | ||||||
12063 | for (i = iht->iht_size; i-- > 0;) | |||||
12064 | /* while */ if (iht->iht_table[i]) { | |||||
12065 | nta_incoming_t *irq = iht->iht_table[i]; | |||||
12066 | tport_unref(irq->irq_tport), irq->irq_tport = NULL((void*)0); | |||||
12067 | } | |||||
12068 | ||||||
12069 | tport_destroy(agent->sa_tports), agent->sa_tports = NULL((void*)0); | |||||
12070 | ||||||
12071 | msg_header_free(agent->sa_home, (void *)agent->sa_vias); | |||||
12072 | agent->sa_vias = NULL((void*)0); | |||||
12073 | msg_header_free(agent->sa_home, (void *)agent->sa_public_vias); | |||||
12074 | agent->sa_public_vias = NULL((void*)0); | |||||
12075 | ||||||
12076 | return 0; | |||||
12077 | } |
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) */ |