Bug Summary

File:libsofia-sip-ua/nua/nua_client.c
Warning:line 1544, column 31
Access to field 'sip_to' results in a dereference of a null pointer (loaded from variable 'sip')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name nua_client.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib/llvm-11/lib/clang/11.0.1 -D HAVE_CONFIG_H -I . -I ../.. -I ../../libsofia-sip-ua/su/sofia-sip -I ../../libsofia-sip-ua/features -I ../../libsofia-sip-ua/features -I ../../libsofia-sip-ua/ipt -I ../../libsofia-sip-ua/ipt -I ../../libsofia-sip-ua/iptsec -I ../../libsofia-sip-ua/iptsec -I ../../libsofia-sip-ua/bnf -I ../../libsofia-sip-ua/bnf -I ../../libsofia-sip-ua/http -I ../../libsofia-sip-ua/http -I ../../libsofia-sip-ua/msg -I ../../libsofia-sip-ua/msg -I ../../libsofia-sip-ua/nth -I ../../libsofia-sip-ua/nth -I ../../libsofia-sip-ua/nta -I ../../libsofia-sip-ua/nta -I ../../libsofia-sip-ua/nea -I ../../libsofia-sip-ua/nea -I ../../libsofia-sip-ua/nua -I ../../libsofia-sip-ua/nua -I ../../libsofia-sip-ua/soa -I ../../libsofia-sip-ua/soa -I ../../libsofia-sip-ua/sdp -I ../../libsofia-sip-ua/sdp -I ../../libsofia-sip-ua/sip -I ../../libsofia-sip-ua/sip -I ../../libsofia-sip-ua/soa -I ../../libsofia-sip-ua/soa -I ../../libsofia-sip-ua/sresolv -I ../../libsofia-sip-ua/sresolv -I ../../libsofia-sip-ua/tport -I ../../libsofia-sip-ua/tport -I ../../libsofia-sip-ua/stun -I ../../libsofia-sip-ua/stun -I ../../libsofia-sip-ua/url -I ../../libsofia-sip-ua/url -I ../../libsofia-sip-ua/su -I ../../libsofia-sip-ua/su -I ../../s2check -D SU_DEBUG=0 -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-11/lib/clang/11.0.1/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir /drone/src/libsofia-sip-ua/nua -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-output=html -faddrsig -o /drone/src/scan-build/2022-06-23-181620-12-1 -x c nua_client.c
1/*
2 * This file is part of the Sofia-SIP package
3 *
4 * Copyright (C) 2006 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 nua_client.c
26 * @brief Client transaction handling
27 *
28 * @author Pekka Pessi <Pekka.Pessi@nokia.com>
29 *
30 * @date Created: Tue Feb 3 16:10:45 EET 2009
31 */
32
33#include "config.h"
34
35#include <stddef.h>
36#include <stdlib.h>
37#include <string.h>
38#include <limits.h>
39
40#include <assert.h>
41
42#include <sofia-sip/su_string.h>
43#include <sofia-sip/su_tagarg.h>
44#include <sofia-sip/su_tag_inline.h>
45
46#include <sofia-sip/sip_util.h>
47#include <sofia-sip/sip_protos.h>
48#include <sofia-sip/sip_status.h>
49
50#define SU_MSG_ARG_Tstruct nua_ee_data struct nua_ee_data
51#define SU_TIMER_ARG_Tstruct nua_client_request struct nua_client_request
52
53#define NUA_SAVED_EVENT_Tsu_msg_t * su_msg_t *
54#define NUA_SAVED_SIGNAL_Tsu_msg_t * su_msg_t *
55
56#define NTA_AGENT_MAGIC_Tstruct nua_s struct nua_s
57#define NTA_LEG_MAGIC_Tstruct nua_handle_s struct nua_handle_s
58#define NTA_OUTGOING_MAGIC_Tstruct nua_client_request struct nua_client_request
59
60#include "nua_stack.h"
61#include "nua_dialog.h"
62#include "nua_client.h"
63
64#include <sofia-sip/su_wait.h>
65
66#if 0
67su_inlinestatic inline int can_redirect(sip_contact_t const *m, sip_method_t method);
68#endif
69
70/**@internal
71 *
72 * @class nua_client_request
73 *
74 * Each handle has a queue of client-side requests; if a request is pending,
75 * a new request from API is added to the queue. After the request is
76 * complete, it is removed from the queue and destroyed by the default. The
77 * exception is the client requests bound to a dialog usage: they are saved
78 * and re-used when the dialog usage is refreshed (and sometimes when the
79 * usage is terminated).
80 *
81 * The client request is subclassed and its behaviour modified using virtual
82 * function table in #nua_client_methods_t.
83 *
84 * The first three methods (crm_template(), crm_init(), crm_send()) are
85 * called when the request is sent first time.
86 *
87 * The crm_template() is called if a template request message is needed (for
88 * example, in case of unregister, unsubscribe and unpublish, the template
89 * message is taken from the request establishing the usage).
90 *
91 * The crm_init() is called when the template message and dialog leg has
92 * been created and populated by the tags procided by the application. Its
93 * parameters msg and sip are pointer to the template request message that
94 * is saved in the nua_client_request::cr_msg field.
95 *
96 * The crm_send() is called with a copy of the template message that has
97 * been populated with all the fields included in the request, including
98 * @CSeq and @MaxForwards. The crm_send() function, such as
99 * nua_publish_client_request(), usually calls nua_base_client_trequest() that
100 * then creates the nta-level transaction.
101 *
102 * The response to the request is processed by crm_check_restart(), which
103 * modifies and restarts the request when needed (e.g., when negotiating
104 * expiration time). After the request has been suitably modified, e.g., the
105 * expiration time has been increased, the restart function calls
106 * nua_client_restart(), which restarts the request and relays the
107 * intermediate response to the application with nua_client_restart() and
108 * crm_report().
109 *
110 * The final responses are processed by crm_recv() and and preliminary ones
111 * by crm_preliminary(). All virtual functions should call
112 * nua_base_client_response() beside method-specific processing.
113 *
114 * The nua_base_client_response() relays the response to the application with
115 * nua_client_restart() and crm_report().
116 *
117 * @par Terminating Dialog Usages and Dialogs
118 *
119 * The response is marked as terminating with nua_client_set_terminating().
120 * When a terminating request completes the dialog usage is removed and the
121 * dialog is destroyed (unless there is an another active usage).
122 */
123static void nua_client_request_destroy(nua_client_request_t *cr);
124static int nua_client_init_request0(nua_client_request_t *cr);
125static int nua_client_request_try(nua_client_request_t *cr);
126static int nua_client_request_sendmsg(nua_client_request_t *cr);
127static void nua_client_restart_after(su_root_magic_t *magic,
128 su_timer_t *timer,
129 nua_client_request_t *cr);
130
131/**Create a client request.
132 *
133 * @retval 0 if request is pending
134 * @retval > 0 if error event has been sent
135 * @retval < 0 upon an error
136 */
137int nua_client_create(nua_handle_t *nh,
138 int event,
139 nua_client_methods_t const *methods,
140 tagi_t const * const tags)
141{
142 su_home_t *home = nh->nh_home;
143 nua_client_request_t *cr;
144 sip_method_t method;
145 char const *name;
146
147 method = methods->crm_method, name = methods->crm_method_name;
148 if (!name) {
149 tagi_t const *t = tl_find_last(tags, nutag_method);
150 if (t)
151 name = (char const *)t->t_value;
152 }
153
154 cr = su_zalloc(home, sizeof *cr + methods->crm_extra);
155 if (!cr) {
156 return nua_stack_event(nh->nh_nua, nh,
157 NULL((void*)0),
158 (enum nua_event_e)event,
159 NUA_ERROR_AT(__FILE__, __LINE__)900, "Internal error at " "nua_client.c" ":" "159",
160 NULL((void*)0));
161 }
162
163 cr->cr_methods = methods;
164 cr->cr_event = event;
165 cr->cr_method = method;
166 cr->cr_method_name = name;
167 cr->cr_contactize = methods->crm_flags.target_refresh;
168 cr->cr_dialog = methods->crm_flags.create_dialog;
169 cr->cr_auto = 1;
170
171 if (su_msg_is_non_null(nh->nh_nua->nua_signal)) {
172 nua_event_data_t *e = su_msg_data(nh->nh_nua->nua_signal)->ee_data;
173
174 if (tags == e->e_tags && event == e->e_event) {
175 cr->cr_auto = 0;
176
177 if (tags) {
178 nua_move_signal(cr->cr_signal, nh->nh_nua->nua_signal);
179 if (cr->cr_signal[0]) {
180 /* Steal reference from signal */
181 cr->cr_owner = e->e_nh, e->e_nh = NULL((void*)0);
182 cr->cr_tags = tags;
183 }
184 }
185 }
186 }
187
188 if (cr->cr_owner == NULL((void*)0))
189 cr->cr_owner = nua_handle_ref(nh);
190
191 if (tags && cr->cr_tags == NULL((void*)0))
192 cr->cr_tags = tl_tlist(nh->nh_home, TAG_NEXT(tags)tag_next, (tag_value_t)(tags));
193
194#if HAVE_MEMLEAK_LOG
195 SU_DEBUG_0(("%p %s() for %s\n", cr, __func__, cr->cr_methods->crm_method_name))((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 0 ? (_su_llog((nua_log), 0, "nua_client.c",
(const char *)__func__, 195, "%p %s() for %s\n", cr, __func__
, cr->cr_methods->crm_method_name)) : (void)0)
;
196#endif
197
198 if (nua_client_request_queue(cr))
199 return 0;
200
201 return nua_client_init_request(cr);
202}
203
204int nua_client_tcreate(nua_handle_t *nh,
205 int event,
206 nua_client_methods_t const *methods,
207 tag_type_t tag, tag_value_t value, ...)
208{
209 int retval;
210 ta_list ta;
211 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)
;
212 retval = nua_client_create(nh, event, methods, ta_args(ta)(ta).tl);
213 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))
;
214 return retval;
215}
216
217#if HAVE_MEMLEAK_LOG
218nua_client_request_t *
219nua_client_request_ref_by(nua_client_request_t *cr,
220 char const *where, unsigned line, char const *who)
221{
222 SU_DEBUG_0(("%p ref %s to %u by %s:%u: %s()\n",((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 0 ? (_su_llog((nua_log), 0, "nua_client.c",
(const char *)__func__, 224, "%p ref %s to %u by %s:%u: %s()\n"
, cr, cr->cr_methods->crm_method_name, ++(cr->cr_refs
), where, line, who)) : (void)0)
223 cr, cr->cr_methods->crm_method_name,((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 0 ? (_su_llog((nua_log), 0, "nua_client.c",
(const char *)__func__, 224, "%p ref %s to %u by %s:%u: %s()\n"
, cr, cr->cr_methods->crm_method_name, ++(cr->cr_refs
), where, line, who)) : (void)0)
224 ++(cr->cr_refs), where, line, who))((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 0 ? (_su_llog((nua_log), 0, "nua_client.c",
(const char *)__func__, 224, "%p ref %s to %u by %s:%u: %s()\n"
, cr, cr->cr_methods->crm_method_name, ++(cr->cr_refs
), where, line, who)) : (void)0)
;
225 return cr;
226}
227
228int nua_client_request_unref_by(nua_client_request_t *cr,
229 char const *where, unsigned line, char const *who)
230{
231 SU_DEBUG_0(("%p unref %s to %u by %s:%u: %s()\n",((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 0 ? (_su_llog((nua_log), 0, "nua_client.c",
(const char *)__func__, 233, "%p unref %s to %u by %s:%u: %s()\n"
, cr, cr->cr_methods->crm_method_name, cr->cr_refs -
1, where, line, who)) : (void)0)
232 cr, cr->cr_methods->crm_method_name,((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 0 ? (_su_llog((nua_log), 0, "nua_client.c",
(const char *)__func__, 233, "%p unref %s to %u by %s:%u: %s()\n"
, cr, cr->cr_methods->crm_method_name, cr->cr_refs -
1, where, line, who)) : (void)0)
233 cr->cr_refs - 1, where, line, who))((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 0 ? (_su_llog((nua_log), 0, "nua_client.c",
(const char *)__func__, 233, "%p unref %s to %u by %s:%u: %s()\n"
, cr, cr->cr_methods->crm_method_name, cr->cr_refs -
1, where, line, who)) : (void)0)
;
234
235 if (cr->cr_refs > 1) {
236 cr->cr_refs--;
237 return 0;
238 }
239 else {
240 cr->cr_refs = 0;
241 nua_client_request_destroy(cr);
242 return 1;
243 }
244}
245#else
246nua_client_request_t *nua_client_request_ref(nua_client_request_t *cr)
247{
248 cr->cr_refs++;
249 return cr;
250}
251
252int nua_client_request_unref(nua_client_request_t *cr)
253{
254 if (cr->cr_refs > 1) {
255 cr->cr_refs--;
256 return 0;
257 }
258 else {
259 cr->cr_refs = 0;
260 nua_client_request_destroy(cr);
261 return 1;
262 }
263}
264#endif
265
266int nua_client_request_queue(nua_client_request_t *cr)
267{
268 int queued = 0;
269 nua_client_request_t **queue = &cr->cr_owner->nh_ds->ds_cr;
270
271 assert(cr->cr_prev == NULL && cr->cr_next == NULL)((void) sizeof ((cr->cr_prev == ((void*)0) && cr->
cr_next == ((void*)0)) ? 1 : 0), __extension__ ({ if (cr->
cr_prev == ((void*)0) && cr->cr_next == ((void*)0)
) ; else __assert_fail ("cr->cr_prev == NULL && cr->cr_next == NULL"
, "nua_client.c", 271, __extension__ __PRETTY_FUNCTION__); })
)
;
272
273 cr->cr_status = 0;
274
275 nua_client_request_ref(cr);
276
277 if (cr->cr_method != sip_method_invite &&
278 cr->cr_method != sip_method_cancel) {
279 while (*queue) {
280 if ((*queue)->cr_method == sip_method_invite ||
281 (*queue)->cr_method == sip_method_cancel)
282 break;
283 queue = &(*queue)->cr_next;
284 queued = 1;
285 }
286 }
287 else {
288 while (*queue) {
289 queue = &(*queue)->cr_next;
290 if (cr->cr_method == sip_method_invite)
291 queued = 1;
292 }
293 }
294
295 if ((cr->cr_next = *queue))
296 cr->cr_next->cr_prev = &cr->cr_next;
297
298 cr->cr_prev = queue, *queue = cr;
299
300 return queued;
301}
302
303int
304nua_client_request_remove(nua_client_request_t *cr)
305{
306 int retval = 0;
307 int in_queue = cr->cr_prev != NULL((void*)0);
308
309 if (in_queue) {
310 if ((*cr->cr_prev = cr->cr_next))
311 cr->cr_next->cr_prev = cr->cr_prev;
312 }
313 cr->cr_prev = NULL((void*)0), cr->cr_next = NULL((void*)0);
314
315 if (cr->cr_timer) {
316 su_timer_destroy(cr->cr_timer), cr->cr_timer = NULL((void*)0);
317 retval = nua_client_request_unref(cr);
318 }
319
320 if (!in_queue)
321 return retval;
322
323 return nua_client_request_unref(cr);
324}
325
326int
327nua_client_request_clean(nua_client_request_t *cr)
328{
329 if (cr->cr_orq) {
330 nta_outgoing_destroy(cr->cr_orq), cr->cr_orq = NULL((void*)0), cr->cr_acked = 0;
331 return nua_client_request_unref(cr);
332 }
333 return 0;
334}
335
336int
337nua_client_request_complete(nua_client_request_t *cr)
338{
339 if (cr->cr_orq) {
340 nua_client_request_ref(cr);
341 if (cr->cr_methods->crm_complete)
342 /* Calls nua_invite_client_complete() */
343 cr->cr_methods->crm_complete(cr);
344 nua_client_request_clean(cr);
345 if (nua_client_request_unref(cr))
346 return 1;
347 }
348
349 return nua_client_request_remove(cr);
350}
351
352static void
353nua_client_request_destroy(nua_client_request_t *cr)
354{
355 nua_handle_t *nh;
356
357 if (cr == NULL((void*)0))
358 return;
359
360 /* Possible references: */
361 assert(cr->cr_prev == NULL)((void) sizeof ((cr->cr_prev == ((void*)0)) ? 1 : 0), __extension__
({ if (cr->cr_prev == ((void*)0)) ; else __assert_fail ("cr->cr_prev == NULL"
, "nua_client.c", 361, __extension__ __PRETTY_FUNCTION__); })
)
; /* queue */
362 assert(cr->cr_orq == NULL)((void) sizeof ((cr->cr_orq == ((void*)0)) ? 1 : 0), __extension__
({ if (cr->cr_orq == ((void*)0)) ; else __assert_fail ("cr->cr_orq == NULL"
, "nua_client.c", 362, __extension__ __PRETTY_FUNCTION__); })
)
; /* transaction callback */
363 assert(cr->cr_timer == NULL)((void) sizeof ((cr->cr_timer == ((void*)0)) ? 1 : 0), __extension__
({ if (cr->cr_timer == ((void*)0)) ; else __assert_fail (
"cr->cr_timer == NULL", "nua_client.c", 363, __extension__
__PRETTY_FUNCTION__); }))
; /* timer callback */
364
365 nh = cr->cr_owner;
366
367 nua_destroy_signal(cr->cr_signal);
368
369 nua_client_bind(cr, NULL((void*)0));
370
371#if HAVE_MEMLEAK_LOG
372 SU_DEBUG_0(("%p %s for %s\n", cr, __func__, cr->cr_methods->crm_method_name))((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 0 ? (_su_llog((nua_log), 0, "nua_client.c",
(const char *)__func__, 372, "%p %s for %s\n", cr, __func__,
cr->cr_methods->crm_method_name)) : (void)0)
;
373#endif
374
375 if (cr->cr_msg)
376 msg_destroy(cr->cr_msg);
377 cr->cr_msg = NULL((void*)0), cr->cr_sip = NULL((void*)0);
378
379 if (cr->cr_orq)
380 nta_outgoing_destroy(cr->cr_orq), cr->cr_orq = NULL((void*)0);
381
382 if (cr->cr_target)
383 su_free(nh->nh_home, cr->cr_target);
384
385 su_free(nh->nh_home, cr);
386
387 nua_handle_unref(nh);
388}
389
390/** Bind client request to a dialog usage */
391int nua_client_bind(nua_client_request_t *cr, nua_dialog_usage_t *du)
392{
393 assert(cr)((void) sizeof ((cr) ? 1 : 0), __extension__ ({ if (cr) ; else
__assert_fail ("cr", "nua_client.c", 393, __extension__ __PRETTY_FUNCTION__
); }))
;
394 if (cr == NULL((void*)0))
395 return -1;
396
397 if (du == NULL((void*)0)) {
398 du = cr->cr_usage;
399 cr->cr_usage = NULL((void*)0);
400 if (du && du->du_cr == cr) {
401 du->du_cr = NULL((void*)0);
402 nua_client_request_unref(cr);
403 }
404 return 0;
405 }
406
407 if (du->du_cr && cr == du->du_cr)
408 return 0;
409
410 if (du->du_cr) {
411 nua_client_bind(du->du_cr, NULL((void*)0));
412 }
413
414 du->du_cr = nua_client_request_ref(cr), cr->cr_usage = du;
415
416 return 0;
417}
418
419/** Check if client request is in progress.
420 *
421 * A client request is in progress, if
422 * 1) it has actual transaction going on
423 * 2) it is waiting credentials from application
424 * 3) it is waiting for Retry-After timer
425 */
426int
427nua_client_request_in_progress(nua_client_request_t const *cr)
428{
429 return cr &&
430 (cr->cr_orq || cr->cr_wait_for_cred || cr->cr_timer);
431}
432
433/**Initialize client request for sending.
434 *
435 * This function is called when the request is taken from queue and sent.
436 *
437 * @retval 0 if request is pending
438 * @retval >=1 if error event has been sent
439 */
440int nua_client_init_request(nua_client_request_t *cr)
441{
442 int retval;
443 nua_client_request_ref(cr);
444 retval = nua_client_init_request0(cr);
445 nua_client_request_unref(cr);
446 return retval;
447}
448
449/**Initialize client request for sending.
450 *
451 * This function is called when the request is taken from queue and sent.
452 *
453 * @retval 0 if request is pending
454 * @retval >=1 if error event has been sent
455 */
456static
457int nua_client_init_request0(nua_client_request_t *cr)
458{
459 nua_handle_t *nh = cr->cr_owner;
460 nua_t *nua = nh->nh_nua;
461 nua_dialog_state_t *ds = nh->nh_ds;
462 msg_t *msg = NULL((void*)0);
463 sip_t *sip;
464 url_string_t const *url = NULL((void*)0);
465 tagi_t const *t;
466 int has_contact = 0;
467 int error = 0;
468
469 if (!cr->cr_method_name)
470 return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__)900, "Internal error at " "nua_client.c" ":" "470", NULL((void*)0));
471
472 if (cr->cr_msg)
473 return nua_client_request_try(cr);
474
475 cr->cr_answer_recv = 0, cr->cr_offer_sent = 0;
476 cr->cr_offer_recv = 0, cr->cr_answer_sent = 0;
477 cr->cr_terminated = 0, cr->cr_graceful = 0;
478
479 nua_stack_init_handle(nua, nh, cr->cr_tags);
480
481 if (cr->cr_method == sip_method_cancel) {
482 if (cr->cr_methods->crm_init) {
483 error = cr->cr_methods->crm_init(cr, NULL((void*)0), NULL((void*)0), cr->cr_tags);
484 if (error)
485 return error;
486 }
487
488 if (cr->cr_methods->crm_send)
489 return cr->cr_methods->crm_send(cr, NULL((void*)0), NULL((void*)0), cr->cr_tags);
490 else
491 return nua_base_client_request(cr, NULL((void*)0), NULL((void*)0), cr->cr_tags);
492 }
493
494 if (!cr->cr_methods->crm_template ||
495 cr->cr_methods->crm_template(cr, &msg, cr->cr_tags) == 0)
496 msg = nua_client_request_template(cr);
497
498 sip = sip_object(msg);
499 if (!sip)
500 return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__)900, "Internal error at " "nua_client.c" ":" "500", msg);
501
502 if (nh->nh_tags) {
503 for (t = nh->nh_tags; t; t = t_next(t)) {
504 if (t->t_tag == siptag_contact ||
505 t->t_tag == siptag_contact_str)
506 has_contact = 1;
507 else if (t->t_tag == nutag_url)
508 url = (url_string_t const *)t->t_value;
509 }
510 }
511
512 /**@par Populating SIP Request Message with Tagged Arguments
513 *
514 * The tagged arguments can be used to pass values for any SIP headers
515 * to the stack. When the INVITE message (or any other SIP message) is
516 * created, the tagged values saved with nua_handle() are used first,
517 * next the tagged values given with the operation (nua_invite()) are
518 * added.
519 *
520 * When multiple tags for the same header are specified, the behaviour
521 * depends on the header type. If only a single header field can be
522 * included in a SIP message, the latest non-NULL value is used, e.g.,
523 * @Subject. However, if the SIP header can consist of multiple lines or
524 * header fields separated by comma, e.g., @Accept, all the tagged
525 * values are concatenated.
526 *
527 * However, if a tag value is #SIP_NONE (-1 casted as a void pointer),
528 * the values from previous tags are ignored.
529 */
530 for (t = cr->cr_tags; t; t = t_next(t)) {
531 if (t->t_tag == siptag_contact ||
532 t->t_tag == siptag_contact_str)
533 has_contact = 1;
534 else if (t->t_tag == nutag_url)
535 url = (url_string_t const *)t->t_value;
536 else if (t->t_tag == nutag_dialog) {
537 cr->cr_dialog = t->t_value > 1;
538 cr->cr_contactize = t->t_value >= 1;
539 }
540 else if (t->t_tag == nutag_auth && t->t_value) {
541 /* XXX ignoring errors */
542 if (nh->nh_auth)
543 auc_credentials(&nh->nh_auth, nh->nh_home, (char *)t->t_value);
544 }
545 }
546
547 if (cr->cr_method == sip_method_register && url == NULL((void*)0))
548 url = (url_string_t const *)NH_PGET(nh, registrar)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_registrar ? ((
nh)->nh_prefs)->nhp_registrar : ((nh)->nh_nua->nua_handles
->nh_prefs)->nhp_registrar)
;
549
550 if ((t = cr->cr_tags)) {
551 if (sip_add_tagis(msg, sip, &t) < 0)
552 return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__)900, "Internal error at " "nua_client.c" ":" "552", msg);
553 }
554
555 /**
556 * Now, the target URI for the request needs to be determined.
557 *
558 * For initial requests, values from tags are used. If NUTAG_URL() is
559 * given, it is used as target URI. Otherwise, if SIPTAG_TO() is given,
560 * it is used as target URI. If neither is given, the complete request
561 * line already specified using SIPTAG_REQUEST() or SIPTAG_REQUEST_STR()
562 * is used. At this point, the target URI is stored in the request line,
563 * together with method name and protocol version ("SIP/2.0"). The
564 * initial dialog information is also created: @CallID, @CSeq headers
565 * are generated, if they do not exist, and a tag is added to the @From
566 * header.
567 */
568
569 if (!ds->ds_leg) {
570 if (ds->ds_remote_tag && ds->ds_remote_tag[0] &&
571 sip_to_tag(nh->nh_home, sip->sip_to, ds->ds_remote_tag) < 0)
572 return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__)900, "Internal error at " "nua_client.c" ":" "572", msg);
573
574 if (sip->sip_from == NULL((void*)0) &&
575 sip_add_dup(msg, sip, (sip_header_t *)nua->nua_from) < 0)
576 return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__)900, "Internal error at " "nua_client.c" ":" "576", msg);
577
578 if (sip->sip_to == NULL((void*)0) && cr->cr_method == sip_method_register &&
579 sip_add_dup_as(msg, sip, sip_to_class,
580 (sip_header_t *)sip->sip_from) < 0) {
581 return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__)900, "Internal error at " "nua_client.c" ":" "581", msg);
582 }
583 }
584 else {
585 if (ds->ds_route)
586 url = NULL((void*)0);
587 }
588
589 if (url && nua_client_set_target(cr, (url_t *)url) < 0)
590 return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__)900, "Internal error at " "nua_client.c" ":" "590", msg);
591
592 cr->cr_has_contact = has_contact;
593
594 if (cr->cr_methods->crm_init) {
595 error = cr->cr_methods->crm_init(cr, msg, sip, cr->cr_tags);
596 if (error < -1)
597 msg = NULL((void*)0);
598 if (error < 0)
599 return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__)900, "Internal error at " "nua_client.c" ":" "599", msg);
600 if (error != 0)
601 return error;
602 }
603
604 cr->cr_msg = msg;
605 cr->cr_sip = sip;
606
607 return nua_client_request_try(cr);
608}
609
610msg_t *nua_client_request_template(nua_client_request_t *cr)
611{
612 nua_handle_t *nh = cr->cr_owner;
613 nua_t *nua = nh->nh_nua;
614 nua_dialog_state_t *ds = nh->nh_ds;
615
616 msg_t *msg = nta_msg_create(nua->nua_nta, 0);
617 sip_t *sip = sip_object(msg);
618
619 if (!sip)
620 return NULL((void*)0);
621
622 if (nh->nh_tags) {
623 tagi_t const *t = nh->nh_tags;
624
625 /* Use the From header from the dialog.
626 If From is set, it is always first tag in the handle */
627 if (ds->ds_leg && t->t_tag == siptag_from)
628 t++;
629
630 /* When the INVITE message (or any other SIP message) is
631 * created, the tagged values saved with nua_handle() are used first. */
632 sip_add_tagis(msg, sip, &t);
633 }
634
635 return msg;
636}
637
638
639/** Restart the request message.
640 *
641 * A restarted request has not been completed successfully.
642 *
643 * @retval 0 if request is pending
644 * @retval >=1 if error event has been sent
645 */
646int nua_client_restart_request(nua_client_request_t *cr,
647 int terminating,
648 tagi_t const *tags)
649{
650 if (cr) {
651 assert(nua_client_is_queued(cr))((void) sizeof ((nua_client_is_queued(cr)) ? 1 : 0), __extension__
({ if (nua_client_is_queued(cr)) ; else __assert_fail ("nua_client_is_queued(cr)"
, "nua_client.c", 651, __extension__ __PRETTY_FUNCTION__); })
)
;
652
653 if (tags && cr->cr_msg)
654 if (sip_add_tagis(cr->cr_msg, NULL((void*)0), &tags) < 0)
655 /* XXX */;
656
657 nua_client_set_terminating(cr, terminating);
658
659 return nua_client_request_try(cr);
660 }
661
662 return 0;
663}
664
665/** Resend the request message.
666 *
667 * A resent request has completed once successfully - restarted has not.
668 *
669 * @retval 0 if request is pending
670 * @retval >=1 if error event has been sent
671 */
672int nua_client_resend_request(nua_client_request_t *cr,
673 int terminating)
674{
675 if (cr) {
676 cr->cr_retry_count = 0;
677 cr->cr_challenged = 0;
678
679 if (nua_client_is_queued(cr)) {
680 if (terminating)
681 cr->cr_graceful = 1;
682 return 0;
683 }
684
685 if (terminating)
686 nua_client_set_terminating(cr, terminating);
687
688 if (nua_client_request_queue(cr))
689 return 0;
690
691 if (nua_dialog_is_reporting(cr->cr_owner->nh_ds))
692 return 0;
693
694 return nua_client_request_try(cr);
695 }
696 return 0;
697}
698
699
700/** Send a request message.
701 *
702 * If an error occurs, send error event to the application.
703 *
704 * @retval 0 if request is pending
705 * @retval >=1 if error event has been sent
706 */
707static
708int nua_client_request_try(nua_client_request_t *cr)
709{
710 int error = nua_client_request_sendmsg(cr);
711
712 if (error < 0)
713 error = nua_client_response(cr, NUA_ERROR_AT(__FILE__, __LINE__)900, "Internal error at " "nua_client.c" ":" "713", NULL((void*)0));
714
715 return error;
716}
717
718/**Send a request message.
719 *
720 * @retval 0 if request is pending
721 * @retval >=1 if error event has been sent
722 * @retval < 0 if no error event has been sent
723 */
724static
725int nua_client_request_sendmsg(nua_client_request_t *cr)
726{
727 nua_handle_t *nh = cr->cr_owner;
728 nua_dialog_state_t *ds = nh->nh_ds;
729 sip_method_t method = cr->cr_method;
730 char const *name = cr->cr_method_name;
731 url_string_t const *url = (url_string_t *)cr->cr_target;
732 nta_leg_t *leg;
733 msg_t *msg;
734 sip_t *sip;
735 int error;
736
737 assert(cr->cr_orq == NULL)((void) sizeof ((cr->cr_orq == ((void*)0)) ? 1 : 0), __extension__
({ if (cr->cr_orq == ((void*)0)) ; else __assert_fail ("cr->cr_orq == NULL"
, "nua_client.c", 737, __extension__ __PRETTY_FUNCTION__); })
)
;
738
739 cr->cr_offer_sent = cr->cr_answer_recv = 0;
740 cr->cr_offer_recv = cr->cr_answer_sent = 0;
741
742 if (!ds->ds_leg && cr->cr_dialog) {
743 ds->ds_leg = nta_leg_tcreate(nh->nh_nua->nua_nta,
744 nua_stack_process_request, nh,
745 SIPTAG_CALL_ID(cr->cr_sip->sip_call_id)siptag_call_id, siptag_call_id_v(cr->cr_sip->sip_call_id
)
,
746 SIPTAG_FROM(cr->cr_sip->sip_from)siptag_from, siptag_from_v(cr->cr_sip->sip_from),
747 SIPTAG_TO(cr->cr_sip->sip_to)siptag_to, siptag_to_v(cr->cr_sip->sip_to),
748 SIPTAG_CSEQ(cr->cr_sip->sip_cseq)siptag_cseq, siptag_cseq_v(cr->cr_sip->sip_cseq),
749 TAG_END()(tag_type_t)0, (tag_value_t)0);
750 if (!ds->ds_leg)
751 return -1;
752 }
753
754 if (cr->cr_sip->sip_from && ds->ds_leg) {
755 if (cr->cr_sip->sip_from->a_tag == NULL((void*)0)) {
756 if (sip_from_tag(msg_home(cr->cr_msg)((su_home_t*)(cr->cr_msg)), cr->cr_sip->sip_from,
757 nta_leg_tag(ds->ds_leg, NULL((void*)0))) < 0) {
758 return -1;
759 }
760 }
761 }
762
763 cr->cr_retry_count++;
764
765 if (ds->ds_leg)
766 leg = ds->ds_leg;
767 else
768 leg = nh->nh_nua->nua_dhandlenua_handles->nh_ds->ds_leg; /* Default leg */
769
770 msg = msg_copy(cr->cr_msg), sip = sip_object(msg);
771
772 if (msg == NULL((void*)0))
773 return -1;
774
775 if (nua_dialog_is_established(ds)) {
776 while (sip->sip_route)
777 sip_route_remove(msg, sip);
778 }
779 else if (!ds->ds_route) {
780 sip_route_t *initial_route = NH_PGET(nh, initial_route)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_initial_route ?
((nh)->nh_prefs)->nhp_initial_route : ((nh)->nh_nua
->nua_handles->nh_prefs)->nhp_initial_route)
;
781
782 if (initial_route) {
783 initial_route = sip_route_dup(msg_home(msg)((su_home_t*)(msg)), initial_route);
784 if (!initial_route) return -1;
785 msg_header_prepend(msg, (msg_pub_t*)sip,
786 /* This should be
787 (msg_header_t **)&sip->sip_route
788 * but directly casting pointer &sip->sip_route gives
789 * spurious type-punning warning */
790 (msg_header_t **)((char *)sip + offsetof(sip_t, sip_route)__builtin_offsetof(sip_t, sip_route)),
791 (msg_header_t *)initial_route);
792 }
793 }
794
795
796 /**
797 * For in-dialog requests, the request URI is taken from the @Contact
798 * header received from the remote party during dialog establishment,
799 * and the NUTAG_URL() is ignored.
800 *
801 * Also, the @CallID and @CSeq headers and @From and @To tags are
802 * generated based on the dialog information and added to the request.
803 * If the dialog has a route, it is added to the request, too.
804 */
805 if (nta_msg_request_complete(msg, leg, method, name, url) < 0) {
806 msg_destroy(msg);
807 return -1;
808 }
809
810 /**@MaxForwards header (with default value set by NTATAG_MAX_FORWARDS()) is
811 * also added now, if it does not exist.
812 */
813
814 if (!ds->ds_remote)
815 ds->ds_remote = sip_to_dup(nh->nh_home, sip->sip_to);
816 if (!ds->ds_local)
817 ds->ds_local = sip_from_dup(nh->nh_home, sip->sip_from);
818
819 /**
820 * Next, values previously set with nua_set_params() or nua_set_hparams()
821 * are used: @Allow, @Supported, @Organization, @UserAgent and
822 * @AllowEvents headers are added to the request if they are not already
823 * set.
824 */
825 if (!sip->sip_allow)
826 sip_add_dup(msg, sip, (sip_header_t*)NH_PGET(nh, allow)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_allow ? ((nh)->
nh_prefs)->nhp_allow : ((nh)->nh_nua->nua_handles->
nh_prefs)->nhp_allow)
);
827
828 if (!sip->sip_supported && NH_PGET(nh, supported)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_supported ? ((
nh)->nh_prefs)->nhp_supported : ((nh)->nh_nua->nua_handles
->nh_prefs)->nhp_supported)
)
829 sip_add_dup(msg, sip, (sip_header_t *)NH_PGET(nh, supported)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_supported ? ((
nh)->nh_prefs)->nhp_supported : ((nh)->nh_nua->nua_handles
->nh_prefs)->nhp_supported)
);
830
831 if (method == sip_method_register && NH_PGET(nh, path_enable)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_path_enable ? (
(nh)->nh_prefs)->nhp_path_enable : ((nh)->nh_nua->
nua_handles->nh_prefs)->nhp_path_enable)
&&
832 !sip_has_feature(sip->sip_supported, "path") &&
833 !sip_has_feature(sip->sip_require, "path"))
834 sip_add_make(msg, sip, sip_supported_class, "path");
835
836 if (!sip->sip_organization && NH_PGET(nh, organization)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_organization ?
((nh)->nh_prefs)->nhp_organization : ((nh)->nh_nua->
nua_handles->nh_prefs)->nhp_organization)
)
837 sip_add_make(msg, sip, sip_organization_class, NH_PGET(nh, organization)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_organization ?
((nh)->nh_prefs)->nhp_organization : ((nh)->nh_nua->
nua_handles->nh_prefs)->nhp_organization)
);
838
839 if (!sip->sip_user_agent && NH_PGET(nh, user_agent)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_user_agent ? (
(nh)->nh_prefs)->nhp_user_agent : ((nh)->nh_nua->
nua_handles->nh_prefs)->nhp_user_agent)
)
840 sip_add_make(msg, sip, sip_user_agent_class, NH_PGET(nh, user_agent)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_user_agent ? (
(nh)->nh_prefs)->nhp_user_agent : ((nh)->nh_nua->
nua_handles->nh_prefs)->nhp_user_agent)
);
841
842 if (!sip->sip_via && NH_PGET(nh, via)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_via ? ((nh)->
nh_prefs)->nhp_via : ((nh)->nh_nua->nua_handles->
nh_prefs)->nhp_via)
)
843 sip_add_make(msg, sip, sip_via_class, NH_PGET(nh, via)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_via ? ((nh)->
nh_prefs)->nhp_via : ((nh)->nh_nua->nua_handles->
nh_prefs)->nhp_via)
);
844
845 /** Any node implementing one or more event packages SHOULD include an
846 * appropriate @AllowEvents header indicating all supported events in
847 * all methods which initiate dialogs and their responses (such as
848 * INVITE) and OPTIONS responses.
849 */
850 if (!sip->sip_allow_events &&
851 NH_PGET(nh, allow_events)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_allow_events ?
((nh)->nh_prefs)->nhp_allow_events : ((nh)->nh_nua->
nua_handles->nh_prefs)->nhp_allow_events)
&&
852 (method == sip_method_notify || /* Always in NOTIFY */
853 (!ds->ds_remote_tag && /* And in initial requests */
854 (method == sip_method_subscribe || method == sip_method_refer ||
855 method == sip_method_options ||
856 method == sip_method_invite))))
857 sip_add_dup(msg, sip, (void *)NH_PGET(nh, allow_events)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_allow_events ?
((nh)->nh_prefs)->nhp_allow_events : ((nh)->nh_nua->
nua_handles->nh_prefs)->nhp_allow_events)
);
858
859 /**
860 * Next, the stack generates a @Contact header for the request (unless
861 * the application already gave a @Contact header or it does not want to
862 * use @Contact and indicates that by including SIPTAG_CONTACT(NULL) or
863 * SIPTAG_CONTACT(SIP_NONE) in the tagged parameters.) If the
864 * application has registered the URI in @From header, the @Contact
865 * header used with registration is used. Otherwise, the @Contact header
866 * is generated from the local IP address and port number.
867 */
868
869 /**For the initial requests, @ServiceRoute set that was received from the
870 * registrar is also added to the request message.
871 */
872 if (cr->cr_method != sip_method_register) {
873 if (cr->cr_contactize && cr->cr_has_contact) {
874 sip_contact_t *ltarget = sip_contact_dup(nh->nh_home, sip->sip_contact);
875 if (ds->ds_ltarget)
876 msg_header_free(nh->nh_home, (msg_header_t *)ds->ds_ltarget);
877 ds->ds_ltarget = ltarget;
878 }
879
880 if (ds->ds_ltarget && !cr->cr_has_contact)
881 sip_add_dup(msg, sip, (sip_header_t *)ds->ds_ltarget);
882
883 /*
884 FS-4102
885 It was decided to comment out this code because it does not appear to make sense
886 Dec 22, 2016
887
888 if (nua_registration_add_contact_to_request(nh, msg, sip,
889 cr->cr_contactize &&
890 !cr->cr_has_contact &&
891 !ds->ds_ltarget,
892 !ds->ds_route) < 0) {
893 msg_destroy(msg);
894 return -1;
895 }
896 */
897
898 }
899
900 cr->cr_wait_for_cred = 0;
901
902 if (cr->cr_methods->crm_send)
903 error = cr->cr_methods->crm_send(cr, msg, sip, NULL((void*)0));
904 else
905 error = nua_base_client_request(cr, msg, sip, NULL((void*)0));
906
907 if (error == -1)
908 msg_destroy(msg);
909
910 return error;
911}
912
913/**Add tags to request message and send it,
914 *
915 * @retval 0 success
916 * @retval -1 if error occurred, but event has not been sent
917 * @retval -2 if error occurred, event has not been sent,
918 * and @a msg has been destroyed
919 * @retval >=1 if error event has been sent
920 */
921int nua_base_client_trequest(nua_client_request_t *cr,
922 msg_t *msg, sip_t *sip,
923 tag_type_t tag, tag_value_t value, ...)
924{
925 int retval;
926 ta_list ta;
927 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)
;
928 retval = nua_base_client_request(cr, msg, sip, ta_args(ta)(ta).tl);
929 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))
;
930 return retval;
931}
932
933/** Send request.
934 *
935 * @retval 0 success
936 * @retval -1 if error occurred, but event has not been sent,
937 * and caller has to destroy request message @ msg
938 * @retval -2 if error occurred, event has not been sent
939 * @retval >=1 if error event has been sent
940 */
941int nua_base_client_request(nua_client_request_t *cr, msg_t *msg, sip_t *sip,
942 tagi_t const *tags)
943{
944 nua_handle_t *nh = cr->cr_owner;
945 int proxy_is_set = NH_PISSET(nh, proxy)((((nh)->nh_prefs)->nhp_set_.set_bits.nhb_proxy) &&
(nh)->nh_nua->nua_handles->nh_prefs != (nh)->nh_prefs
)
;
946 url_string_t * proxy = NH_PGET(nh, proxy)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_proxy ? ((nh)->
nh_prefs)->nhp_proxy : ((nh)->nh_nua->nua_handles->
nh_prefs)->nhp_proxy)
;
947 int call_tls_orq_connect_timeout_is_set = NH_PISSET(nh, call_tls_orq_connect_timeout)((((nh)->nh_prefs)->nhp_set_.set_bits.nhb_call_tls_orq_connect_timeout
) && (nh)->nh_nua->nua_handles->nh_prefs != (
nh)->nh_prefs)
;
948 uint32_t call_tls_orq_connect_timeout = NH_PGET(nh, call_tls_orq_connect_timeout)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_call_tls_orq_connect_timeout
? ((nh)->nh_prefs)->nhp_call_tls_orq_connect_timeout :
((nh)->nh_nua->nua_handles->nh_prefs)->nhp_call_tls_orq_connect_timeout
)
;
949
950 if (nh->nh_auth) {
951 if (cr->cr_challenged ||
952 NH_PGET(nh, auth_cache)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_auth_cache ? (
(nh)->nh_prefs)->nhp_auth_cache : ((nh)->nh_nua->
nua_handles->nh_prefs)->nhp_auth_cache)
== nua_auth_cache_dialog) {
953 if (auc_authorize(&nh->nh_auth, msg, sip) < 0)
954 return nua_client_return(cr, 900, "Cannot add credentials", msg);
955 }
956 }
957
958 cr->cr_seq = sip->sip_cseq->cs_seq; /* Save last sequence number */
959
960 assert(cr->cr_orq == NULL)((void) sizeof ((cr->cr_orq == ((void*)0)) ? 1 : 0), __extension__
({ if (cr->cr_orq == ((void*)0)) ; else __assert_fail ("cr->cr_orq == NULL"
, "nua_client.c", 960, __extension__ __PRETTY_FUNCTION__); })
)
;
961
962 cr->cr_orq = nta_outgoing_mcreate(nh->nh_nua->nua_nta,
963 nua_client_orq_response,
964 nua_client_request_ref(cr),
965 NULL((void*)0),
966 msg,
967 TAG_IF(proxy_is_set,!(proxy_is_set) ? tag_skip : ntatag_default_proxy, urltag_url_v
((proxy))
968 NTATAG_DEFAULT_PROXY(proxy))!(proxy_is_set) ? tag_skip : ntatag_default_proxy, urltag_url_v
((proxy))
,
969 TAG_IF(call_tls_orq_connect_timeout_is_set,!(call_tls_orq_connect_timeout_is_set) ? tag_skip : ntatag_tls_orq_connect_timeout
, tag_uint_v((call_tls_orq_connect_timeout))
970 NTATAG_TLS_ORQ_CONNECT_TIMEOUT(call_tls_orq_connect_timeout))!(call_tls_orq_connect_timeout_is_set) ? tag_skip : ntatag_tls_orq_connect_timeout
, tag_uint_v((call_tls_orq_connect_timeout))
,
971 TAG_NEXT(tags)tag_next, (tag_value_t)(tags));
972
973 if (cr->cr_orq == NULL((void*)0)) {
974 nua_client_request_unref(cr);
975 return -1;
976 }
977
978 return 0;
979}
980
981/** Callback for nta client transaction */
982int
983nua_client_orq_response(nua_client_request_t *cr,
984 nta_outgoing_t *orq,
985 sip_t const *sip)
986{
987 int status;
988 char const *phrase;
989
990 if (sip && sip->sip_status) {
991 status = sip->sip_status->st_status;
992 phrase = sip->sip_status->st_phrase;
993 }
994 else {
995 status = nta_outgoing_status(orq);
996 phrase = "";
997 }
998
999 nua_client_response(cr, status, phrase, sip);
1000
1001 return 0;
1002}
1003
1004/**Return response to the client request.
1005 *
1006 * Return a response generated by the stack. This function is used to return
1007 * a error response within @a nua_client_methods_t#crm_init or @a
1008 * nua_client_methods_t#crm_send functions. It takes care of disposing the @a
1009 * to_be_destroyed that cannot be sent.
1010 *
1011 * @retval 0 if response event was preliminary
1012 * @retval 1 if response event was final
1013 * @retval 2 if response event destroyed the handle, too.
1014 */
1015int nua_client_return(nua_client_request_t *cr,
1016 int status,
1017 char const *phrase,
1018 msg_t *to_be_destroyed)
1019{
1020 if (to_be_destroyed)
1021 msg_destroy(to_be_destroyed);
1022 nua_client_response(cr, status, phrase, NULL((void*)0));
1023 return 1;
1024}
1025
1026/** Process response to the client request.
1027 *
1028 * The response can be generated by the stack (@a sip is NULL) or
1029 * returned by the remote server.
1030 *
1031 * @retval 0 if response event was preliminary
1032 * @retval 1 if response event was final
1033 * @retval 2 if response event destroyed the handle, too.
1034 */
1035int nua_client_response(nua_client_request_t *cr,
1036 int status,
1037 char const *phrase,
1038 sip_t const *sip)
1039{
1040 nua_handle_t *nh = cr->cr_owner;
1041 nua_dialog_usage_t *du = cr->cr_usage;
1042 int retval = 0;
1043
1044 if (cr->cr_restarting)
1045 return 0;
1046
1047 if (cr->cr_status == 200 && status < 200) { // ignore 183 follows 200
1048 return 0;
1049 }
1050
1051 nua_client_request_ref(cr);
1052
1053 cr->cr_status = status;
1054 cr->cr_phrase = phrase;
1055
1056 if (status == 183) {
1057 /**
1058 * Save the new remote tag on To header during Session Progress
1059 * to allow sending INFO messages to remote peer before 200 OK
1060 */
1061 if (sip) {
1062 if (cr->cr_contactize)
1063 nua_dialog_uac_route(nh, nh->nh_ds, sip, 1, cr->cr_initial);
1064 }
1065 }
1066 else if (status < 200) {
1067 /* Xyzzy */
1068 }
1069 else if (sip && nua_client_check_restart(cr, status, phrase, sip)) {
1070 nua_client_request_unref(cr);
1071 return 0;
1072 }
1073 else if (status < 300) {
1074 if (cr->cr_terminating) {
1075 cr->cr_terminated = 1;
1076 }
1077 else {
1078 if (sip) {
1079 if (cr->cr_contactize)
1080 nua_dialog_uac_route(nh, nh->nh_ds, sip, 1, cr->cr_initial);
1081 nua_dialog_store_peer_info(nh, nh->nh_ds, sip);
1082 }
1083
1084 if (du && du->du_cr == cr)
1085 du->du_ready = 1;
1086 }
1087 }
1088 else {
1089 sip_method_t method = cr->cr_method;
1090 int terminated, graceful = 1;
1091
1092 if (status < 700) {
1093 terminated = sip_response_terminates_dialog(status, method, &graceful);
1094 if (terminated && !cr->cr_initial) {
1095 terminated = 0, graceful = 1;
1096 }
1097 } else {
1098 /* XXX - terminate usage by all internal error responses */
1099 terminated = 0, graceful = 1;
1100 }
1101
1102 if (terminated < 0)
1103 cr->cr_terminated = terminated;
1104 else if (cr->cr_terminating || terminated)
1105 cr->cr_terminated = 1;
1106 else if (graceful)
1107 cr->cr_graceful = 1;
1108 }
1109
1110 if (status < 200) {
1111 if (cr->cr_methods->crm_preliminary)
1112 cr->cr_methods->crm_preliminary(cr, status, phrase, sip);
1113 else
1114 nua_base_client_response(cr, status, phrase, sip, NULL((void*)0));
1115 cr->cr_phrase = NULL((void*)0);
1116 }
1117 else {
1118 if (cr->cr_methods->crm_recv)
1119 retval = cr->cr_methods->crm_recv(cr, status, phrase, sip);
1120 else
1121 retval = nua_base_client_response(cr, status, phrase, sip, NULL((void*)0));
1122 }
1123
1124 nua_client_request_unref(cr);
1125
1126 return retval;
1127}
1128
1129/** Check if request should be restarted.
1130 *
1131 * @retval 1 if restarted or waiting for restart
1132 * @retval 0 otherwise
1133 */
1134int nua_client_check_restart(nua_client_request_t *cr,
1135 int status,
1136 char const *phrase,
1137 sip_t const *sip)
1138{
1139 nua_handle_t *nh;
1140
1141 assert(cr && status >= 200 && phrase && sip)((void) sizeof ((cr && status >= 200 && phrase
&& sip) ? 1 : 0), __extension__ ({ if (cr &&
status >= 200 && phrase && sip) ; else __assert_fail
("cr && status >= 200 && phrase && sip"
, "nua_client.c", 1141, __extension__ __PRETTY_FUNCTION__); }
))
;
1142
1143 nh = cr->cr_owner;
1144
1145 if (cr->cr_retry_count > NH_PGET(nh, retry_count)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_retry_count ? (
(nh)->nh_prefs)->nhp_retry_count : ((nh)->nh_nua->
nua_handles->nh_prefs)->nhp_retry_count)
)
1146 return 0;
1147
1148 if (cr->cr_methods->crm_check_restart)
1149 return cr->cr_methods->crm_check_restart(cr, status, phrase, sip);
1150 else
1151 return nua_base_client_check_restart(cr, status, phrase, sip);
1152}
1153
1154int nua_base_client_check_restart(nua_client_request_t *cr,
1155 int status,
1156 char const *phrase,
1157 sip_t const *sip)
1158{
1159 nua_handle_t *nh = cr->cr_owner;
1160 nta_outgoing_t *orq;
1161#if 0
1162 if (status == 302 || status == 305) {
1163 sip_route_t r[1];
1164
1165 if (!can_redirect(sip->sip_contact, cr->cr_method))
1166 return 0;
1167
1168 switch (status) {
1169 case 302:
1170 if (nua_dialog_zap(nh, nh->nh_ds) == 0 &&
1171 nua_client_set_target(cr, sip->sip_contact->m_url) >= 0)
1172 return nua_client_restart(cr, 100, "Redirected");
1173 break;
1174
1175 case 305:
1176 sip_route_init(r);
1177 *r->r_url = *sip->sip_contact->m_url;
1178 if (nua_dialog_zap(nh, nh->nh_ds) == 0 &&
1179 sip_add_dup(cr->cr_msg, cr->cr_sip, (sip_header_t *)r) >= 0)
1180 return nua_client_restart(cr, 100, "Redirected via a proxy");
1181 break;
1182
1183 default:
1184 break;
1185 }
1186 }
1187#endif
1188
1189 if (status == 423) {
1190 unsigned my_expires = 0;
1191
1192 if (cr->cr_sip->sip_expires)
1193 my_expires = cr->cr_sip->sip_expires->ex_delta;
1194
1195 if (sip->sip_min_expires &&
1196 sip->sip_min_expires->me_delta > my_expires) {
1197 sip_expires_t ex[1];
1198 sip_expires_init(ex);
1199 ex->ex_delta = sip->sip_min_expires->me_delta;
1200
1201 if (sip_add_dup(cr->cr_msg, NULL((void*)0), (sip_header_t *)ex) < 0)
1202 return 0;
1203
1204 return nua_client_restart(cr, 100, "Re-Negotiating Expiration");
1205 }
1206 }
1207
1208 if (status == 403) {
1209 if (nh->nh_auth) {
1210 /* Bad username/password */
1211 SU_DEBUG_7(("nua(%p): bad credentials, clearing them\n", (void *)nh))((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 7 ? (_su_llog((nua_log), 7, "nua_client.c",
(const char *)__func__, 1211, "nua(%p): bad credentials, clearing them\n"
, (void *)nh)) : (void)0)
;
1212 auc_clear_credentials(&nh->nh_auth, NULL((void*)0), NULL((void*)0));
1213 }
1214 }
1215
1216 if ((status == 401 && sip->sip_www_authenticate) ||
1217 (status == 407 && sip->sip_proxy_authenticate)) {
1218 int server = 0, proxy = 0;
1219
1220 if (sip->sip_www_authenticate)
1221 server = auc_challenge(&nh->nh_auth, nh->nh_home,
1222 sip->sip_www_authenticate,
1223 sip_authorization_class);
1224
1225 if (sip->sip_proxy_authenticate)
1226 proxy = auc_challenge(&nh->nh_auth, nh->nh_home,
1227 sip->sip_proxy_authenticate,
1228 sip_proxy_authorization_class);
1229
1230 if (server >= 0 && proxy >= 0) {
1231 int invalid = cr->cr_challenged && server + proxy == 0;
1232
1233 cr->cr_challenged = 1;
1234
1235 if (invalid) {
1236 /* Bad username/password */
1237 SU_DEBUG_7(("nua(%p): bad credentials, clearing them\n", (void *)nh))((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 7 ? (_su_llog((nua_log), 7, "nua_client.c",
(const char *)__func__, 1237, "nua(%p): bad credentials, clearing them\n"
, (void *)nh)) : (void)0)
;
1238 auc_clear_credentials(&nh->nh_auth, NULL((void*)0), NULL((void*)0));
1239 } else if (auc_has_authorization(&nh->nh_auth)) {
1240 return nua_client_restart(cr, 100, "Request Authorized by Cache");
1241 }
1242
1243 orq = cr->cr_orq, cr->cr_orq = NULL((void*)0);
1244
1245 cr->cr_waiting = cr->cr_wait_for_cred = 1;
1246 nua_client_report(cr, status, phrase, NULL((void*)0), orq, NULL((void*)0));
1247 nta_outgoing_destroy(orq);
1248 cr->cr_status = 0, cr->cr_phrase = NULL((void*)0);
1249 nua_client_request_unref(cr);
1250
1251 return 1;
1252 }
1253 }
1254 /* GriGiu : RFC-3261 status supported Retry-After */
1255 if ( (status == 404 || status == 413 || status == 480 || status == 486 ||
1256 status == 500 || status == 503 ||
1257 status == 600 || status == 603) &&
1258 sip->sip_retry_after &&
1259 NH_PGET(nh, retry_after_enable)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_retry_after_enable
? ((nh)->nh_prefs)->nhp_retry_after_enable : ((nh)->
nh_nua->nua_handles->nh_prefs)->nhp_retry_after_enable
)
&&
1260 sip->sip_retry_after->af_delta < 3200) {
1261 su_timer_t *timer;
1262 char phrase[18]; /* Retry After XXXX\0 */
1263
1264 timer = su_timer_create(su_root_task(nh->nh_nua->nua_root), 0);
1265
1266 if (su_timer_set_interval(timer, nua_client_restart_after, cr,
1267 sip->sip_retry_after->af_delta * 1000) < 0) {
1268 su_timer_destroy(timer);
1269 return 0; /* Too bad */
1270 }
1271
1272 cr->cr_timer = timer; /* This takes over cr reference from orq */
1273
1274 snprintf(phrase, sizeof phrase, "Retry After %u",
1275 (unsigned)sip->sip_retry_after->af_delta);
1276
1277 orq = cr->cr_orq, cr->cr_orq = NULL((void*)0);
1278 cr->cr_waiting = 1;
1279 nua_client_report(cr, 100, phrase, NULL((void*)0), orq, NULL((void*)0));
1280 nta_outgoing_destroy(orq);
1281 cr->cr_status = 0, cr->cr_phrase = NULL((void*)0);
1282
1283 return 1;
1284 }
1285
1286 return 0; /* This was a final response that cannot be restarted. */
1287}
1288
1289#if 0
1290su_inlinestatic inline
1291int can_redirect(sip_contact_t const *m, sip_method_t method)
1292{
1293 if (m && m->m_url->url_host) {
1294 enum url_type_e type = (enum url_type_e)m->m_url->url_type;
1295 return
1296 type == url_sip ||
1297 type == url_urn ||
1298 type == url_sips ||
1299 (type == url_tel &&
1300 (method == sip_method_invite || method == sip_method_message)) ||
1301 (type == url_im && method == sip_method_message) ||
1302 (type == url_pres && method == sip_method_subscribe);
1303 }
1304 return 0;
1305}
1306#endif
1307
1308/** @internal Add authorization data */
1309static int nh_authorize(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
1310{
1311 int retval = 0;
1312 tagi_t const *ti;
1313 ta_list ta;
1314
1315 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)
;
1316
1317 for (ti = ta_args(ta)(ta).tl; ti; ti = tl_next(ti)) {
1318 if (ti->t_tag == nutag_auth && ti->t_value) {
1319 char *data = (char *)ti->t_value;
1320 int rv = auc_credentials(&nh->nh_auth, nh->nh_home, data);
1321
1322 if (rv > 0) {
1323 retval = 1;
1324 }
1325 else if (rv < 0) {
1326 retval = -1;
1327 break;
1328 }
1329 }
1330 }
1331
1332 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))
;
1333
1334 return retval;
1335}
1336
1337/** @NUA_EVENT nua_r_authenticate
1338 *
1339 * Response to nua_authenticate(). Under normal operation, this event is
1340 * never sent but rather the unauthenticated operation is completed.
1341 * However, if there is no operation to authentication or if there is an
1342 * authentication error the #nua_r_authenticate event is sent to the
1343 * application with the status code as follows:
1344 * - <i>202 No operation to restart</i>:\n
1345 * The authenticator associated with the handle was updated, but there was
1346 * no operation to retry with the new credentials.
1347 * - <i>900 Cannot add credentials</i>:\n
1348 * There was internal problem updating authenticator.
1349 * - <i>904 No matching challenge</i>:\n
1350 * There was no challenge matching with the credentials provided by
1351 * nua_authenticate(), e.g., their realm did not match with the one
1352 * received with the challenge.
1353 *
1354 * @param status status code from authentication
1355 * @param phrase a short textual description of @a status code
1356 * @param nh operation handle authenticated
1357 * @param hmagic application context associated with the handle
1358 * @param sip NULL
1359 * @param tags empty
1360 *
1361 * @sa nua_terminate(), nua_handle_destroy()
1362 *
1363 * @END_NUA_EVENT
1364 */
1365
1366void
1367nua_stack_authenticate(nua_t *nua, nua_handle_t *nh, nua_event_t e,
1368 tagi_t const *tags)
1369{
1370 nua_client_request_t *cr = nh->nh_ds->ds_cr;
1371 int status = nh_authorize(nh, TAG_NEXT(tags)tag_next, (tag_value_t)(tags));
1372
1373 if (status > 0) {
1374 if (cr && cr->cr_wait_for_cred) {
1375 cr->cr_waiting = cr->cr_wait_for_cred = 0;
1376 nua_client_restart_request(cr, cr->cr_terminating, tags);
1377 }
1378 else {
1379 nua_stack_event(nua, nh, NULL((void*)0), e,
1380 202, "No operation to restart",
1381 NULL((void*)0));
1382 }
1383 }
1384 else if (cr && cr->cr_wait_for_cred) {
1385 cr->cr_waiting = cr->cr_wait_for_cred = 0;
1386
1387 if (status < 0)
1388 nua_client_response(cr, 900, "Operation cannot add credentials", NULL((void*)0));
1389 else
1390 nua_client_response(cr, 904, "Operation has no matching challenge ", NULL((void*)0));
1391 }
1392 else if (status < 0) {
1393 nua_stack_event(nua, nh, NULL((void*)0), e, 900, "Cannot add credentials", NULL((void*)0));
1394 }
1395 else {
1396 nua_stack_event(nua, nh, NULL((void*)0), e, 904, "No matching challenge", NULL((void*)0));
1397 }
1398}
1399
1400/** Request restarted by timer */
1401static void
1402nua_client_restart_after(su_root_magic_t *magic,
1403 su_timer_t *timer,
1404 nua_client_request_t *cr)
1405{
1406 cr->cr_waiting = 0;
1407 su_timer_destroy(cr->cr_timer), cr->cr_timer = NULL((void*)0);
1408 nua_client_restart_request(cr, cr->cr_terminating, NULL((void*)0));
1409 nua_client_request_unref(cr);
1410}
1411
1412/** Restart request.
1413 *
1414 * @retval 1 if restarted
1415 * @retval 0 otherwise
1416 */
1417int nua_client_restart(nua_client_request_t *cr,
1418 int status, char const *phrase)
1419{
1420 nua_handle_t *nh = cr->cr_owner;
1421 nta_outgoing_t *orq;
1422 int error = -1, terminated, graceful;
1423
1424 if (cr->cr_retry_count > NH_PGET(nh, retry_count)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_retry_count ? (
(nh)->nh_prefs)->nhp_retry_count : ((nh)->nh_nua->
nua_handles->nh_prefs)->nhp_retry_count)
)
1425 return 0;
1426
1427 orq = cr->cr_orq, cr->cr_orq = NULL((void*)0); assert(orq)((void) sizeof ((orq) ? 1 : 0), __extension__ ({ if (orq) ; else
__assert_fail ("orq", "nua_client.c", 1427, __extension__ __PRETTY_FUNCTION__
); }))
;
1428 terminated = cr->cr_terminated, cr->cr_terminated = 0;
1429 graceful = cr->cr_graceful, cr->cr_graceful = 0;
1430
1431 cr->cr_restarting = 1;
1432 error = nua_client_request_sendmsg(cr);
1433 cr->cr_restarting = 0;
1434
1435 if (error) {
1436 cr->cr_graceful = graceful;
1437 cr->cr_terminated = terminated;
1438 assert(cr->cr_orq == NULL)((void) sizeof ((cr->cr_orq == ((void*)0)) ? 1 : 0), __extension__
({ if (cr->cr_orq == ((void*)0)) ; else __assert_fail ("cr->cr_orq == NULL"
, "nua_client.c", 1438, __extension__ __PRETTY_FUNCTION__); }
))
;
1439 cr->cr_orq = orq;
1440 return 0;
1441 }
1442
1443 nua_client_report(cr, status, phrase, NULL((void*)0), orq, NULL((void*)0));
1444
1445 nta_outgoing_destroy(orq);
1446 nua_client_request_unref(cr); /* ... reference used by old orq */
1447
1448 return 1;
1449}
1450
1451int nua_client_set_target(nua_client_request_t *cr, url_t const *target)
1452{
1453 url_t *new_target, *old_target = cr->cr_target;
1454
1455 if (!target || target == old_target)
1456 return 0;
1457
1458 new_target = url_hdup(cr->cr_owner->nh_home, (url_t *)target);
1459 if (!new_target)
1460 return -1;
1461 cr->cr_target = new_target;
1462 if (old_target)
1463 su_free(cr->cr_owner->nh_home, old_target);
1464
1465 return 0;
1466}
1467
1468/**@internal
1469 * Relay response event to the application.
1470 *
1471 * @todo
1472 * If handle has already been marked as destroyed by nua_handle_destroy(),
1473 * release the handle with nh_destroy().
1474 *
1475 * @retval 0 if event was preliminary
1476 * @retval 1 if event was final
1477 * @retval 2 if event destroyed the handle, too.
1478 */
1479int nua_base_client_tresponse(nua_client_request_t *cr,
1480 int status, char const *phrase,
1481 sip_t const *sip,
1482 tag_type_t tag, tag_value_t value, ...)
1483{
1484 ta_list ta;
1485 int retval;
1486
1487 if (cr->cr_event == nua_r_destroy)
1
Assuming field 'cr_event' is equal to nua_r_destroy
2
Taking true branch
1488 return nua_base_client_response(cr, status, phrase, sip, NULL((void*)0));
3
Passing value via 4th parameter 'sip'
4
Calling 'nua_base_client_response'
1489
1490 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)
;
1491 retval = nua_base_client_response(cr, status, phrase, sip, ta_args(ta)(ta).tl);
1492 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))
;
1493
1494 return retval;
1495}
1496
1497/**@internal
1498 * Relay response event to the application.
1499 *
1500 * @todo
1501 * If handle has already been marked as destroyed by nua_handle_destroy(),
1502 * release the handle with nh_destroy().
1503 *
1504 * @retval 0 if event was preliminary
1505 * @retval 1 if event was final
1506 * @retval 2 if event destroyed the handle, too.
1507 */
1508int nua_base_client_response(nua_client_request_t *cr,
1509 int status, char const *phrase,
1510 sip_t const *sip,
1511 tagi_t const *tags)
1512{
1513 nua_handle_t *nh = cr->cr_owner;
1514 sip_method_t method = cr->cr_method;
1515 nua_dialog_usage_t *du;
1516
1517 cr->cr_reporting = 1, nh->nh_ds->ds_reporting = 1;
1518
1519 if (nh->nh_auth && sip &&
5
Assuming field 'nh_auth' is non-null
6
Assuming 'sip' is null
7
Assuming pointer value is null
1520 (sip->sip_authentication_info || sip->sip_proxy_authentication_info)) {
1521 /* Collect nextnonce */
1522 if (sip->sip_authentication_info)
1523 auc_info(&nh->nh_auth,
1524 sip->sip_authentication_info,
1525 sip_authorization_class);
1526 if (sip->sip_proxy_authentication_info)
1527 auc_info(&nh->nh_auth,
1528 sip->sip_proxy_authentication_info,
1529 sip_proxy_authorization_class);
1530 }
1531
1532 if ((method != sip_method_invite && status >= 200) || status >= 300)
8
Assuming 'method' is equal to sip_method_invite
9
Assuming 'status' is < 300
10
Taking false branch
1533 nua_client_request_remove(cr);
1534
1535 nua_client_report(cr, status, phrase, sip, cr->cr_orq, tags);
11
Calling 'nua_client_report'
14
Returning from 'nua_client_report'
1536
1537 /**
1538 * In Session Progress we need to update our sip_to tag to allow correct
1539 * INFO messages to be sent before a 200 OK is received
1540 */
1541 if (status == 183 && method
15.1
'method' is equal to sip_method_invite
== sip_method_invite && !cr->cr_acked) {
15
Assuming 'status' is equal to 183
16
Assuming field 'cr_acked' is 0
17
Taking true branch
1542 nua_dialog_state_t *ds = nh->nh_ds;
1543 if (ds
17.1
'ds' is non-null
&& ds->ds_remote_tag && ds->ds_remote_tag[0] &&
18
Assuming field 'ds_remote_tag' is non-null
19
Assuming the condition is true
1544 sip_to_tag(nh->nh_home, sip->sip_to, ds->ds_remote_tag) < 0)
20
Access to field 'sip_to' results in a dereference of a null pointer (loaded from variable 'sip')
1545 SU_DEBUG_3(("%s Cannot store remote tag in sip_to header\n", __func__))((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 3 ? (_su_llog((nua_log), 3, "nua_client.c",
(const char *)__func__, 1545, "%s Cannot store remote tag in sip_to header\n"
, __func__)) : (void)0)
;
1546 }
1547
1548 if (status < 200 ||
1549 /* Un-ACKed 2XX response to INVITE */
1550 (method == sip_method_invite && status < 300 && !cr->cr_acked)) {
1551 cr->cr_reporting = 0, nh->nh_ds->ds_reporting = 0;
1552 return 1;
1553 }
1554
1555 nua_client_request_clean(cr);
1556
1557 du = cr->cr_usage;
1558
1559 if (cr->cr_terminated < 0) {
1560 /* XXX - dialog has been terminated */;
1561 nua_dialog_deinit(nh, nh->nh_ds), cr->cr_usage = NULL((void*)0);
1562 }
1563 else if (du) {
1564 if (cr->cr_terminated ||
1565 (!du->du_ready && status >= 300 && nua_client_is_bound(cr))) {
1566 /* Usage has been destroyed */
1567 nua_dialog_usage_remove(nh, nh->nh_ds, du, cr, NULL((void*)0)), cr->cr_usage = NULL((void*)0);
1568 }
1569 else if (cr->cr_graceful) {
1570 /* Terminate usage gracefully */
1571 if (nua_dialog_usage_shutdown(nh, nh->nh_ds, du) > 0)
1572 cr->cr_usage = NULL((void*)0);
1573 }
1574 }
1575 else if (cr->cr_terminated) {
1576 if (nh->nh_ds->ds_usage == NULL((void*)0))
1577 nua_dialog_remove(nh, nh->nh_ds, NULL((void*)0)), cr->cr_usage = NULL((void*)0);
1578 }
1579
1580 cr->cr_phrase = NULL((void*)0);
1581 cr->cr_reporting = 0, nh->nh_ds->ds_reporting = 0;
1582
1583 if (method == sip_method_cancel)
1584 return 1;
1585
1586 return nua_client_next_request(nh->nh_ds->ds_cr, method == sip_method_invite);
1587}
1588
1589/** Send event, zap transaction but leave cr in list */
1590int nua_client_report(nua_client_request_t *cr,
1591 int status, char const *phrase,
1592 sip_t const *sip,
1593 nta_outgoing_t *orq,
1594 tagi_t const *tags)
1595{
1596 nua_handle_t *nh;
1597
1598 if (cr->cr_event
11.1
Field 'cr_event' is equal to nua_r_destroy
== nua_r_destroy)
12
Taking true branch
1599 return 1;
13
Returning without writing to 'cr->cr_acked', which participates in a condition later
1600
1601 if (cr->cr_methods->crm_report)
1602 return cr->cr_methods->crm_report(cr, status, phrase, sip, orq, tags);
1603
1604 nh = cr->cr_owner;
1605
1606 nua_stack_event(nh->nh_nua, nh,
1607 nta_outgoing_getresponse(orq),
1608 (enum nua_event_e)cr->cr_event,
1609 status, phrase,
1610 tags);
1611 return 1;
1612}
1613
1614int nua_client_treport(nua_client_request_t *cr,
1615 int status, char const *phrase,
1616 sip_t const *sip,
1617 nta_outgoing_t *orq,
1618 tag_type_t tag, tag_value_t value, ...)
1619{
1620 int retval;
1621 ta_list ta;
1622 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)
;
1623 retval = nua_client_report(cr, status, phrase, sip, orq, ta_args(ta)(ta).tl);
1624 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))
;
1625 return retval;
1626}
1627
1628int nua_client_next_request(nua_client_request_t *cr, int invite)
1629{
1630 for (; cr; cr = cr->cr_next) {
1631 if (cr->cr_method == sip_method_cancel)
1632 continue;
1633 break;
1634 }
1635
1636 if (cr && !nua_client_request_in_progress(cr)) {
1637 nua_client_init_request(cr);
1638 }
1639
1640 return 1;
1641}
1642
1643nua_client_request_t *
1644nua_client_request_pending(nua_client_request_t const *cr)
1645{
1646 for (;cr;cr = cr->cr_next)
1647 if (cr->cr_orq)
1648 return (nua_client_request_t *)cr;
1649
1650 return NULL((void*)0);
1651}
1652
1653/**@internal
1654 * Save handle parameters and initial authentication info.
1655 *
1656 * @retval -1 upon an error
1657 * @retval 0 when successful
1658 */
1659int nua_stack_init_handle(nua_t *nua, nua_handle_t *nh, tagi_t const *tags)
1660{
1661 int retval = 0;
1662
1663 if (nh == NULL((void*)0))
1664 return -1;
1665
1666 assert(nh != nua->nua_dhandle)((void) sizeof ((nh != nua->nua_handles) ? 1 : 0), __extension__
({ if (nh != nua->nua_handles) ; else __assert_fail ("nh != nua->nua_dhandle"
, "nua_client.c", 1666, __extension__ __PRETTY_FUNCTION__); }
))
;
1667
1668 if (nua_stack_set_params(nua, nh, nua_i_error, tags) < 0)
1669 retval = -1;
1670
1671 if (retval || nh->nh_init) /* Already initialized? */
1672 return retval;
1673
1674 if (nh->nh_tags)
1675 nh_authorize(nh, TAG_NEXT(nh->nh_tags)tag_next, (tag_value_t)(nh->nh_tags));
1676
1677 nh->nh_init = 1;
1678
1679 return 0;
1680}