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_T   struct nua_ee_data
51 #define SU_TIMER_ARG_T struct nua_client_request
52 
53 #define NUA_SAVED_EVENT_T su_msg_t *
54 #define NUA_SAVED_SIGNAL_T su_msg_t *
55 
56 #define NTA_AGENT_MAGIC_T    struct nua_s
57 #define NTA_LEG_MAGIC_T      struct nua_handle_s
58 #define NTA_OUTGOING_MAGIC_T 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
67 su_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  */
123 static void nua_client_request_destroy(nua_client_request_t *cr);
124 static int nua_client_init_request0(nua_client_request_t *cr);
125 static int nua_client_request_try(nua_client_request_t *cr);
126 static int nua_client_request_sendmsg(nua_client_request_t *cr);
127 static 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  */
nua_client_create(nua_handle_t * nh,int event,nua_client_methods_t const * methods,tagi_t const * const tags)137 int 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,
158 			   (enum nua_event_e)event,
159 			   NUA_ERROR_AT(__FILE__, __LINE__),
160 			   NULL);
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;
182 	  cr->cr_tags = tags;
183 	}
184       }
185     }
186   }
187 
188   if (cr->cr_owner == NULL)
189     cr->cr_owner = nua_handle_ref(nh);
190 
191   if (tags && cr->cr_tags == NULL)
192     cr->cr_tags = tl_tlist(nh->nh_home, TAG_NEXT(tags));
193 
194 #if HAVE_MEMLEAK_LOG
195   SU_DEBUG_0(("%p %s() for %s\n", cr, __func__, cr->cr_methods->crm_method_name));
196 #endif
197 
198   if (nua_client_request_queue(cr))
199     return 0;
200 
201   return nua_client_init_request(cr);
202 }
203 
nua_client_tcreate(nua_handle_t * nh,int event,nua_client_methods_t const * methods,tag_type_t tag,tag_value_t value,...)204 int 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);
212   retval = nua_client_create(nh, event, methods, ta_args(ta));
213   ta_end(ta);
214   return retval;
215 }
216 
217 #if HAVE_MEMLEAK_LOG
218 nua_client_request_t *
nua_client_request_ref_by(nua_client_request_t * cr,char const * where,unsigned line,char const * who)219 nua_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",
223 	      cr, cr->cr_methods->crm_method_name,
224 	      ++(cr->cr_refs), where, line, who));
225   return cr;
226 }
227 
nua_client_request_unref_by(nua_client_request_t * cr,char const * where,unsigned line,char const * who)228 int 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",
232 	      cr, cr->cr_methods->crm_method_name,
233 	      cr->cr_refs - 1, where, line, who));
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
nua_client_request_ref(nua_client_request_t * cr)246 nua_client_request_t *nua_client_request_ref(nua_client_request_t *cr)
247 {
248   cr->cr_refs++;
249   return cr;
250 }
251 
nua_client_request_unref(nua_client_request_t * cr)252 int 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 
nua_client_request_queue(nua_client_request_t * cr)266 int 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);
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 
303 int
nua_client_request_remove(nua_client_request_t * cr)304 nua_client_request_remove(nua_client_request_t *cr)
305 {
306   int retval = 0;
307   int in_queue = cr->cr_prev != NULL;
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, cr->cr_next = NULL;
314 
315   if (cr->cr_timer) {
316     su_timer_destroy(cr->cr_timer), cr->cr_timer = NULL;
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 
326 int
nua_client_request_clean(nua_client_request_t * cr)327 nua_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, cr->cr_acked = 0;
331     return nua_client_request_unref(cr);
332   }
333   return 0;
334 }
335 
336 int
nua_client_request_complete(nua_client_request_t * cr)337 nua_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 
352 static void
nua_client_request_destroy(nua_client_request_t * cr)353 nua_client_request_destroy(nua_client_request_t *cr)
354 {
355   nua_handle_t *nh;
356 
357   if (cr == NULL)
358     return;
359 
360   /* Possible references: */
361   assert(cr->cr_prev == NULL);	/* queue */
362   assert(cr->cr_orq == NULL);	/* transaction callback */
363   assert(cr->cr_timer == NULL);	/* timer callback */
364 
365   nh = cr->cr_owner;
366 
367   nua_destroy_signal(cr->cr_signal);
368 
369   nua_client_bind(cr, NULL);
370 
371 #if HAVE_MEMLEAK_LOG
372   SU_DEBUG_0(("%p %s for %s\n", cr, __func__, cr->cr_methods->crm_method_name));
373 #endif
374 
375   if (cr->cr_msg)
376     msg_destroy(cr->cr_msg);
377   cr->cr_msg = NULL, cr->cr_sip = NULL;
378 
379   if (cr->cr_orq)
380     nta_outgoing_destroy(cr->cr_orq), cr->cr_orq = NULL;
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 */
nua_client_bind(nua_client_request_t * cr,nua_dialog_usage_t * du)391 int nua_client_bind(nua_client_request_t *cr, nua_dialog_usage_t *du)
392 {
393   assert(cr);
394   if (cr == NULL)
395     return -1;
396 
397   if (du == NULL) {
398     du = cr->cr_usage;
399     cr->cr_usage = NULL;
400     if (du && du->du_cr == cr) {
401       du->du_cr = NULL;
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);
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  */
426 int
nua_client_request_in_progress(nua_client_request_t const * cr)427 nua_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  */
nua_client_init_request(nua_client_request_t * cr)440 int 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  */
456 static
nua_client_init_request0(nua_client_request_t * cr)457 int 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;
463   sip_t *sip;
464   url_string_t const *url = NULL;
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__), NULL);
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, NULL, 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, NULL, cr->cr_tags);
490     else
491       return nua_base_client_request(cr, NULL, NULL, 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__), 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)
548     url = (url_string_t const *)NH_PGET(nh, 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__), 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__), msg);
573 
574     if (sip->sip_from == NULL &&
575 	sip_add_dup(msg, sip, (sip_header_t *)nua->nua_from) < 0)
576       return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__), msg);
577 
578     if (sip->sip_to == NULL && 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__), msg);
582     }
583   }
584   else {
585     if (ds->ds_route)
586       url = NULL;
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__), 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;
598     if (error < 0)
599       return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__), 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 
nua_client_request_template(nua_client_request_t * cr)610 msg_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;
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  */
nua_client_restart_request(nua_client_request_t * cr,int terminating,tagi_t const * tags)646 int 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));
652 
653     if (tags && cr->cr_msg)
654       if (sip_add_tagis(cr->cr_msg, NULL, &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  */
nua_client_resend_request(nua_client_request_t * cr,int terminating)672 int 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  */
707 static
nua_client_request_try(nua_client_request_t * cr)708 int 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__), NULL);
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  */
724 static
nua_client_request_sendmsg(nua_client_request_t * cr)725 int 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);
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),
746 				 SIPTAG_FROM(cr->cr_sip->sip_from),
747 				 SIPTAG_TO(cr->cr_sip->sip_to),
748 				 SIPTAG_CSEQ(cr->cr_sip->sip_cseq),
749 				 TAG_END());
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) {
756       if (sip_from_tag(msg_home(cr->cr_msg), cr->cr_sip->sip_from,
757 		       nta_leg_tag(ds->ds_leg, NULL)) < 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_dhandle->nh_ds->ds_leg; /* Default leg */
769 
770   msg = msg_copy(cr->cr_msg), sip = sip_object(msg);
771 
772   if (msg == NULL)
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);
781 
782     if (initial_route) {
783       initial_route = sip_route_dup(msg_home(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)),
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));
827 
828   if (!sip->sip_supported && NH_PGET(nh, supported))
829     sip_add_dup(msg, sip, (sip_header_t *)NH_PGET(nh, supported));
830 
831   if (method == sip_method_register && NH_PGET(nh, 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))
837     sip_add_make(msg, sip, sip_organization_class, NH_PGET(nh, organization));
838 
839   if (!sip->sip_user_agent && NH_PGET(nh, user_agent))
840     sip_add_make(msg, sip, sip_user_agent_class, NH_PGET(nh, user_agent));
841 
842   if (!sip->sip_via && NH_PGET(nh, via))
843     sip_add_make(msg, sip, sip_via_class, NH_PGET(nh, 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) &&
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));
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);
904   else
905     error = nua_base_client_request(cr, msg, sip, NULL);
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  */
nua_base_client_trequest(nua_client_request_t * cr,msg_t * msg,sip_t * sip,tag_type_t tag,tag_value_t value,...)921 int 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);
928   retval = nua_base_client_request(cr, msg, sip, ta_args(ta));
929   ta_end(ta);
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  */
nua_base_client_request(nua_client_request_t * cr,msg_t * msg,sip_t * sip,tagi_t const * tags)941 int 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);
946   url_string_t * proxy = NH_PGET(nh, proxy);
947 
948   if (nh->nh_auth) {
949     if (cr->cr_challenged ||
950 	NH_PGET(nh, auth_cache) == nua_auth_cache_dialog) {
951       if (auc_authorize(&nh->nh_auth, msg, sip) < 0)
952 	return nua_client_return(cr, 900, "Cannot add credentials", msg);
953     }
954   }
955 
956   cr->cr_seq = sip->sip_cseq->cs_seq; /* Save last sequence number */
957 
958   assert(cr->cr_orq == NULL);
959 
960   cr->cr_orq = nta_outgoing_mcreate(nh->nh_nua->nua_nta,
961 				    nua_client_orq_response,
962 				    nua_client_request_ref(cr),
963 				    NULL,
964 				    msg,
965 				    TAG_IF(proxy_is_set,
966 					   NTATAG_DEFAULT_PROXY(proxy)),
967 				    TAG_NEXT(tags));
968 
969   if (cr->cr_orq == NULL) {
970     nua_client_request_unref(cr);
971     return -1;
972   }
973 
974   return 0;
975 }
976 
977 /** Callback for nta client transaction */
978 int
nua_client_orq_response(nua_client_request_t * cr,nta_outgoing_t * orq,sip_t const * sip)979 nua_client_orq_response(nua_client_request_t *cr,
980 			nta_outgoing_t *orq,
981 			sip_t const *sip)
982 {
983   int status;
984   char const *phrase;
985 
986   if (sip && sip->sip_status) {
987     status = sip->sip_status->st_status;
988     phrase = sip->sip_status->st_phrase;
989   }
990   else {
991     status = nta_outgoing_status(orq);
992     phrase = "";
993   }
994 
995   nua_client_response(cr, status, phrase, sip);
996 
997   return 0;
998 }
999 
1000 /**Return response to the client request.
1001  *
1002  * Return a response generated by the stack. This function is used to return
1003  * a error response within @a nua_client_methods_t#crm_init or @a
1004  * nua_client_methods_t#crm_send functions. It takes care of disposing the @a
1005  * to_be_destroyed that cannot be sent.
1006  *
1007  * @retval 0 if response event was preliminary
1008  * @retval 1 if response event was final
1009  * @retval 2 if response event destroyed the handle, too.
1010  */
nua_client_return(nua_client_request_t * cr,int status,char const * phrase,msg_t * to_be_destroyed)1011 int nua_client_return(nua_client_request_t *cr,
1012 		      int status,
1013 		      char const *phrase,
1014 		      msg_t *to_be_destroyed)
1015 {
1016   if (to_be_destroyed)
1017     msg_destroy(to_be_destroyed);
1018   nua_client_response(cr, status, phrase, NULL);
1019   return 1;
1020 }
1021 
1022 /** Process response to the client request.
1023  *
1024  * The response can be generated by the stack (@a sip is NULL) or
1025  * returned by the remote server.
1026  *
1027  * @retval 0 if response event was preliminary
1028  * @retval 1 if response event was final
1029  * @retval 2 if response event destroyed the handle, too.
1030  */
nua_client_response(nua_client_request_t * cr,int status,char const * phrase,sip_t const * sip)1031 int nua_client_response(nua_client_request_t *cr,
1032 			int status,
1033 			char const *phrase,
1034 			sip_t const *sip)
1035 {
1036   nua_handle_t *nh = cr->cr_owner;
1037   nua_dialog_usage_t *du = cr->cr_usage;
1038   int retval = 0;
1039 
1040   if (cr->cr_restarting)
1041     return 0;
1042 
1043   if (cr->cr_status == 200 && status < 200) { // ignore 183 follows 200
1044     return 0;
1045   }
1046 
1047   nua_client_request_ref(cr);
1048 
1049   cr->cr_status = status;
1050   cr->cr_phrase = phrase;
1051 
1052   if (status < 200) {
1053     /* Xyzzy */
1054   }
1055   else if (sip && nua_client_check_restart(cr, status, phrase, sip)) {
1056     nua_client_request_unref(cr);
1057     return 0;
1058   }
1059   else if (status < 300) {
1060     if (cr->cr_terminating) {
1061       cr->cr_terminated = 1;
1062     }
1063     else {
1064       if (sip) {
1065 	if (cr->cr_contactize)
1066 	  nua_dialog_uac_route(nh, nh->nh_ds, sip, 1, cr->cr_initial);
1067 	nua_dialog_store_peer_info(nh, nh->nh_ds, sip);
1068       }
1069 
1070       if (du && du->du_cr == cr)
1071 	du->du_ready = 1;
1072     }
1073   }
1074   else {
1075     sip_method_t method = cr->cr_method;
1076     int terminated, graceful = 1;
1077 
1078     if (status < 700) {
1079 		terminated = sip_response_terminates_dialog(status, method, &graceful);
1080 		if (terminated && !cr->cr_initial) {
1081 			terminated = 0, graceful = 1;
1082 		}
1083 	} else {
1084 		/* XXX - terminate usage by all internal error responses */
1085 		terminated = 0, graceful = 1;
1086 	}
1087 
1088     if (terminated < 0)
1089       cr->cr_terminated = terminated;
1090     else if (cr->cr_terminating || terminated)
1091       cr->cr_terminated = 1;
1092     else if (graceful)
1093       cr->cr_graceful = 1;
1094   }
1095 
1096   if (status < 200) {
1097     if (cr->cr_methods->crm_preliminary)
1098       cr->cr_methods->crm_preliminary(cr, status, phrase, sip);
1099     else
1100       nua_base_client_response(cr, status, phrase, sip, NULL);
1101     cr->cr_phrase = NULL;
1102   }
1103   else {
1104     if (cr->cr_methods->crm_recv)
1105       retval = cr->cr_methods->crm_recv(cr, status, phrase, sip);
1106     else
1107       retval = nua_base_client_response(cr, status, phrase, sip, NULL);
1108   }
1109 
1110   nua_client_request_unref(cr);
1111 
1112   return retval;
1113 }
1114 
1115 /** Check if request should be restarted.
1116  *
1117  * @retval 1 if restarted or waiting for restart
1118  * @retval 0 otherwise
1119  */
nua_client_check_restart(nua_client_request_t * cr,int status,char const * phrase,sip_t const * sip)1120 int nua_client_check_restart(nua_client_request_t *cr,
1121 			     int status,
1122 			     char const *phrase,
1123 			     sip_t const *sip)
1124 {
1125   nua_handle_t *nh;
1126 
1127   assert(cr && status >= 200 && phrase && sip);
1128 
1129   nh = cr->cr_owner;
1130 
1131   if (cr->cr_retry_count > NH_PGET(nh, retry_count))
1132     return 0;
1133 
1134   if (cr->cr_methods->crm_check_restart)
1135     return cr->cr_methods->crm_check_restart(cr, status, phrase, sip);
1136   else
1137     return nua_base_client_check_restart(cr, status, phrase, sip);
1138 }
1139 
nua_base_client_check_restart(nua_client_request_t * cr,int status,char const * phrase,sip_t const * sip)1140 int nua_base_client_check_restart(nua_client_request_t *cr,
1141 				  int status,
1142 				  char const *phrase,
1143 				  sip_t const *sip)
1144 {
1145   nua_handle_t *nh = cr->cr_owner;
1146   nta_outgoing_t *orq;
1147 #if 0
1148   if (status == 302 || status == 305) {
1149     sip_route_t r[1];
1150 
1151     if (!can_redirect(sip->sip_contact, cr->cr_method))
1152       return 0;
1153 
1154     switch (status) {
1155     case 302:
1156       if (nua_dialog_zap(nh, nh->nh_ds) == 0 &&
1157 	  nua_client_set_target(cr, sip->sip_contact->m_url) >= 0)
1158 	return nua_client_restart(cr, 100, "Redirected");
1159       break;
1160 
1161     case 305:
1162       sip_route_init(r);
1163       *r->r_url = *sip->sip_contact->m_url;
1164       if (nua_dialog_zap(nh, nh->nh_ds) == 0 &&
1165 	  sip_add_dup(cr->cr_msg, cr->cr_sip, (sip_header_t *)r) >= 0)
1166 	return nua_client_restart(cr, 100, "Redirected via a proxy");
1167       break;
1168 
1169     default:
1170       break;
1171     }
1172   }
1173 #endif
1174 
1175   if (status == 423) {
1176     unsigned my_expires = 0;
1177 
1178     if (cr->cr_sip->sip_expires)
1179       my_expires = cr->cr_sip->sip_expires->ex_delta;
1180 
1181     if (sip->sip_min_expires &&
1182 	sip->sip_min_expires->me_delta > my_expires) {
1183       sip_expires_t ex[1];
1184       sip_expires_init(ex);
1185       ex->ex_delta = sip->sip_min_expires->me_delta;
1186 
1187       if (sip_add_dup(cr->cr_msg, NULL, (sip_header_t *)ex) < 0)
1188 	return 0;
1189 
1190       return nua_client_restart(cr, 100, "Re-Negotiating Expiration");
1191     }
1192   }
1193 
1194   if (status == 403) {
1195 	  if (nh->nh_auth) {
1196 		  /* Bad username/password */
1197 		  SU_DEBUG_7(("nua(%p): bad credentials, clearing them\n", (void *)nh));
1198 		  auc_clear_credentials(&nh->nh_auth, NULL, NULL);
1199 	  }
1200   }
1201 
1202   if ((status == 401 && sip->sip_www_authenticate) ||
1203       (status == 407 && sip->sip_proxy_authenticate)) {
1204     int server = 0, proxy = 0;
1205 
1206     if (sip->sip_www_authenticate)
1207       server = auc_challenge(&nh->nh_auth, nh->nh_home,
1208 			     sip->sip_www_authenticate,
1209 			     sip_authorization_class);
1210 
1211     if (sip->sip_proxy_authenticate)
1212       proxy = auc_challenge(&nh->nh_auth, nh->nh_home,
1213 			    sip->sip_proxy_authenticate,
1214 			    sip_proxy_authorization_class);
1215 
1216     if (server >= 0 && proxy >= 0) {
1217       int invalid = cr->cr_challenged && server + proxy == 0;
1218 
1219       cr->cr_challenged = 1;
1220 
1221       if (invalid) {
1222 		  /* Bad username/password */
1223 		  SU_DEBUG_7(("nua(%p): bad credentials, clearing them\n", (void *)nh));
1224 		  auc_clear_credentials(&nh->nh_auth, NULL, NULL);
1225       } else if (auc_has_authorization(&nh->nh_auth)) {
1226 		  return nua_client_restart(cr, 100, "Request Authorized by Cache");
1227 	  }
1228 
1229       orq = cr->cr_orq, cr->cr_orq = NULL;
1230 
1231       cr->cr_waiting = cr->cr_wait_for_cred = 1;
1232       nua_client_report(cr, status, phrase, NULL, orq, NULL);
1233       nta_outgoing_destroy(orq);
1234       cr->cr_status = 0, cr->cr_phrase = NULL;
1235       nua_client_request_unref(cr);
1236 
1237       return 1;
1238     }
1239   }
1240   /* GriGiu : RFC-3261 status supported Retry-After */
1241   if ( (status == 404 || status == 413 || status == 480 || status == 486 ||
1242 	   status == 500 || status == 503 ||
1243 	   status == 600 || status == 603) &&
1244       sip->sip_retry_after &&
1245 	  NH_PGET(nh, retry_after_enable) &&
1246       sip->sip_retry_after->af_delta < 3200) {
1247     su_timer_t *timer;
1248     char phrase[18];		/* Retry After XXXX\0 */
1249 
1250     timer = su_timer_create(su_root_task(nh->nh_nua->nua_root), 0);
1251 
1252     if (su_timer_set_interval(timer, nua_client_restart_after, cr,
1253 			      sip->sip_retry_after->af_delta * 1000) < 0) {
1254       su_timer_destroy(timer);
1255       return 0; /* Too bad */
1256     }
1257 
1258     cr->cr_timer = timer;	/* This takes over cr reference from orq */
1259 
1260     snprintf(phrase, sizeof phrase, "Retry After %u",
1261 	     (unsigned)sip->sip_retry_after->af_delta);
1262 
1263     orq = cr->cr_orq, cr->cr_orq = NULL;
1264     cr->cr_waiting = 1;
1265     nua_client_report(cr, 100, phrase, NULL, orq, NULL);
1266     nta_outgoing_destroy(orq);
1267     cr->cr_status = 0, cr->cr_phrase = NULL;
1268 
1269     return 1;
1270   }
1271 
1272   return 0;  /* This was a final response that cannot be restarted. */
1273 }
1274 
1275 #if 0
1276 su_inline
1277 int can_redirect(sip_contact_t const *m, sip_method_t method)
1278 {
1279   if (m && m->m_url->url_host) {
1280     enum url_type_e type = (enum url_type_e)m->m_url->url_type;
1281     return
1282       type == url_sip ||
1283       type == url_sips ||
1284       (type == url_tel &&
1285        (method == sip_method_invite || method == sip_method_message)) ||
1286       (type == url_im && method == sip_method_message) ||
1287       (type == url_pres && method == sip_method_subscribe);
1288   }
1289   return 0;
1290 }
1291 #endif
1292 
1293 /** @internal Add authorization data */
nh_authorize(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)1294 static int nh_authorize(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
1295 {
1296   int retval = 0;
1297   tagi_t const *ti;
1298   ta_list ta;
1299 
1300   ta_start(ta, tag, value);
1301 
1302   for (ti = ta_args(ta); ti; ti = tl_next(ti)) {
1303     if (ti->t_tag == nutag_auth && ti->t_value) {
1304       char *data = (char *)ti->t_value;
1305       int rv = auc_credentials(&nh->nh_auth, nh->nh_home, data);
1306 
1307       if (rv > 0) {
1308 	retval = 1;
1309       }
1310       else if (rv < 0) {
1311 	retval = -1;
1312 	break;
1313       }
1314     }
1315   }
1316 
1317   ta_end(ta);
1318 
1319   return retval;
1320 }
1321 
1322 /** @NUA_EVENT nua_r_authenticate
1323  *
1324  * Response to nua_authenticate(). Under normal operation, this event is
1325  * never sent but rather the unauthenticated operation is completed.
1326  * However, if there is no operation to authentication or if there is an
1327  * authentication error the #nua_r_authenticate event is sent to the
1328  * application with the status code as follows:
1329  * - <i>202 No operation to restart</i>:\n
1330  *   The authenticator associated with the handle was updated, but there was
1331  *   no operation to retry with the new credentials.
1332  * - <i>900 Cannot add credentials</i>:\n
1333  *   There was internal problem updating authenticator.
1334  * - <i>904 No matching challenge</i>:\n
1335  *   There was no challenge matching with the credentials provided by
1336  *   nua_authenticate(), e.g., their realm did not match with the one
1337  *   received with the challenge.
1338  *
1339  * @param status status code from authentication
1340  * @param phrase a short textual description of @a status code
1341  * @param nh     operation handle authenticated
1342  * @param hmagic application context associated with the handle
1343  * @param sip    NULL
1344  * @param tags   empty
1345  *
1346  * @sa nua_terminate(), nua_handle_destroy()
1347  *
1348  * @END_NUA_EVENT
1349  */
1350 
1351 void
nua_stack_authenticate(nua_t * nua,nua_handle_t * nh,nua_event_t e,tagi_t const * tags)1352 nua_stack_authenticate(nua_t *nua, nua_handle_t *nh, nua_event_t e,
1353 		       tagi_t const *tags)
1354 {
1355   nua_client_request_t *cr = nh->nh_ds->ds_cr;
1356   int status = nh_authorize(nh, TAG_NEXT(tags));
1357 
1358   if (status > 0) {
1359     if (cr && cr->cr_wait_for_cred) {
1360       cr->cr_waiting = cr->cr_wait_for_cred = 0;
1361       nua_client_restart_request(cr, cr->cr_terminating, tags);
1362     }
1363     else {
1364       nua_stack_event(nua, nh, NULL, e,
1365 		      202, "No operation to restart",
1366 		      NULL);
1367     }
1368   }
1369   else if (cr && cr->cr_wait_for_cred) {
1370     cr->cr_waiting = cr->cr_wait_for_cred = 0;
1371 
1372     if (status < 0)
1373       nua_client_response(cr, 900, "Operation cannot add credentials", NULL);
1374     else
1375       nua_client_response(cr, 904, "Operation has no matching challenge ", NULL);
1376   }
1377   else if (status < 0) {
1378     nua_stack_event(nua, nh, NULL, e, 900, "Cannot add credentials", NULL);
1379   }
1380   else {
1381     nua_stack_event(nua, nh, NULL, e, 904, "No matching challenge", NULL);
1382   }
1383 }
1384 
1385 /** Request restarted by timer */
1386 static void
nua_client_restart_after(su_root_magic_t * magic,su_timer_t * timer,nua_client_request_t * cr)1387 nua_client_restart_after(su_root_magic_t *magic,
1388 			 su_timer_t *timer,
1389 			 nua_client_request_t *cr)
1390 {
1391   cr->cr_waiting = 0;
1392   su_timer_destroy(cr->cr_timer), cr->cr_timer = NULL;
1393   nua_client_restart_request(cr, cr->cr_terminating, NULL);
1394   nua_client_request_unref(cr);
1395 }
1396 
1397 /** Restart request.
1398  *
1399  * @retval 1 if restarted
1400  * @retval 0 otherwise
1401  */
nua_client_restart(nua_client_request_t * cr,int status,char const * phrase)1402 int nua_client_restart(nua_client_request_t *cr,
1403 		       int status, char const *phrase)
1404 {
1405   nua_handle_t *nh = cr->cr_owner;
1406   nta_outgoing_t *orq;
1407   int error = -1, terminated, graceful;
1408 
1409   if (cr->cr_retry_count > NH_PGET(nh, retry_count))
1410     return 0;
1411 
1412   orq = cr->cr_orq, cr->cr_orq = NULL;  assert(orq);
1413   terminated = cr->cr_terminated, cr->cr_terminated = 0;
1414   graceful = cr->cr_graceful, cr->cr_graceful = 0;
1415 
1416   cr->cr_restarting = 1;
1417   error = nua_client_request_sendmsg(cr);
1418   cr->cr_restarting = 0;
1419 
1420   if (error) {
1421     cr->cr_graceful = graceful;
1422     cr->cr_terminated = terminated;
1423     assert(cr->cr_orq == NULL);
1424     cr->cr_orq = orq;
1425     return 0;
1426   }
1427 
1428   nua_client_report(cr, status, phrase, NULL, orq, NULL);
1429 
1430   nta_outgoing_destroy(orq);
1431   nua_client_request_unref(cr);	/* ... reference used by old orq */
1432 
1433   return 1;
1434 }
1435 
nua_client_set_target(nua_client_request_t * cr,url_t const * target)1436 int nua_client_set_target(nua_client_request_t *cr, url_t const *target)
1437 {
1438   url_t *new_target, *old_target = cr->cr_target;
1439 
1440   if (!target || target == old_target)
1441     return 0;
1442 
1443   new_target = url_hdup(cr->cr_owner->nh_home, (url_t *)target);
1444   if (!new_target)
1445     return -1;
1446   cr->cr_target = new_target;
1447   if (old_target)
1448     su_free(cr->cr_owner->nh_home, old_target);
1449 
1450   return 0;
1451 }
1452 
1453 /**@internal
1454  * Relay response event to the application.
1455  *
1456  * @todo
1457  * If handle has already been marked as destroyed by nua_handle_destroy(),
1458  * release the handle with nh_destroy().
1459  *
1460  * @retval 0 if event was preliminary
1461  * @retval 1 if event was final
1462  * @retval 2 if event destroyed the handle, too.
1463  */
nua_base_client_tresponse(nua_client_request_t * cr,int status,char const * phrase,sip_t const * sip,tag_type_t tag,tag_value_t value,...)1464 int nua_base_client_tresponse(nua_client_request_t *cr,
1465 			      int status, char const *phrase,
1466 			      sip_t const *sip,
1467 			      tag_type_t tag, tag_value_t value, ...)
1468 {
1469   ta_list ta;
1470   int retval;
1471 
1472   if (cr->cr_event == nua_r_destroy)
1473     return nua_base_client_response(cr, status, phrase, sip, NULL);
1474 
1475   ta_start(ta, tag, value);
1476   retval = nua_base_client_response(cr, status, phrase, sip, ta_args(ta));
1477   ta_end(ta);
1478 
1479   return retval;
1480 }
1481 
1482 /**@internal
1483  * Relay response event to the application.
1484  *
1485  * @todo
1486  * If handle has already been marked as destroyed by nua_handle_destroy(),
1487  * release the handle with nh_destroy().
1488  *
1489  * @retval 0 if event was preliminary
1490  * @retval 1 if event was final
1491  * @retval 2 if event destroyed the handle, too.
1492  */
nua_base_client_response(nua_client_request_t * cr,int status,char const * phrase,sip_t const * sip,tagi_t const * tags)1493 int nua_base_client_response(nua_client_request_t *cr,
1494 			     int status, char const *phrase,
1495 			     sip_t const *sip,
1496 			     tagi_t const *tags)
1497 {
1498   nua_handle_t *nh = cr->cr_owner;
1499   sip_method_t method = cr->cr_method;
1500   nua_dialog_usage_t *du;
1501 
1502   cr->cr_reporting = 1, nh->nh_ds->ds_reporting = 1;
1503 
1504   if (nh->nh_auth && sip &&
1505       (sip->sip_authentication_info || sip->sip_proxy_authentication_info)) {
1506     /* Collect nextnonce */
1507     if (sip->sip_authentication_info)
1508       auc_info(&nh->nh_auth,
1509 	       sip->sip_authentication_info,
1510 	       sip_authorization_class);
1511     if (sip->sip_proxy_authentication_info)
1512       auc_info(&nh->nh_auth,
1513 	       sip->sip_proxy_authentication_info,
1514 	       sip_proxy_authorization_class);
1515   }
1516 
1517   if ((method != sip_method_invite && status >= 200) || status >= 300)
1518     nua_client_request_remove(cr);
1519 
1520   nua_client_report(cr, status, phrase, sip, cr->cr_orq, tags);
1521 
1522   if (status < 200 ||
1523       /* Un-ACKed 2XX response to INVITE */
1524       (method == sip_method_invite && status < 300 && !cr->cr_acked)) {
1525     cr->cr_reporting = 0, nh->nh_ds->ds_reporting = 0;
1526     return 1;
1527   }
1528 
1529   nua_client_request_clean(cr);
1530 
1531   du = cr->cr_usage;
1532 
1533   if (cr->cr_terminated < 0) {
1534     /* XXX - dialog has been terminated */;
1535     nua_dialog_deinit(nh, nh->nh_ds), cr->cr_usage = NULL;
1536   }
1537   else if (du) {
1538     if (cr->cr_terminated ||
1539 	(!du->du_ready && status >= 300 && nua_client_is_bound(cr))) {
1540       /* Usage has been destroyed */
1541       nua_dialog_usage_remove(nh, nh->nh_ds, du, cr, NULL), cr->cr_usage = NULL;
1542     }
1543     else if (cr->cr_graceful) {
1544       /* Terminate usage gracefully */
1545       if (nua_dialog_usage_shutdown(nh, nh->nh_ds, du) > 0)
1546 	cr->cr_usage = NULL;
1547     }
1548   }
1549   else if (cr->cr_terminated) {
1550     if (nh->nh_ds->ds_usage == NULL)
1551       nua_dialog_remove(nh, nh->nh_ds, NULL), cr->cr_usage = NULL;
1552   }
1553 
1554   cr->cr_phrase = NULL;
1555   cr->cr_reporting = 0, nh->nh_ds->ds_reporting = 0;
1556 
1557   if (method == sip_method_cancel)
1558     return 1;
1559 
1560   return nua_client_next_request(nh->nh_ds->ds_cr, method == sip_method_invite);
1561 }
1562 
1563 /** Send event, zap transaction but leave cr in list */
nua_client_report(nua_client_request_t * cr,int status,char const * phrase,sip_t const * sip,nta_outgoing_t * orq,tagi_t const * tags)1564 int nua_client_report(nua_client_request_t *cr,
1565 		      int status, char const *phrase,
1566 		      sip_t const *sip,
1567 		      nta_outgoing_t *orq,
1568 		      tagi_t const *tags)
1569 {
1570   nua_handle_t *nh;
1571 
1572   if (cr->cr_event == nua_r_destroy)
1573     return 1;
1574 
1575   if (cr->cr_methods->crm_report)
1576     return cr->cr_methods->crm_report(cr, status, phrase, sip, orq, tags);
1577 
1578   nh = cr->cr_owner;
1579 
1580   nua_stack_event(nh->nh_nua, nh,
1581 		  nta_outgoing_getresponse(orq),
1582 		  (enum nua_event_e)cr->cr_event,
1583 		  status, phrase,
1584 		  tags);
1585   return 1;
1586 }
1587 
nua_client_treport(nua_client_request_t * cr,int status,char const * phrase,sip_t const * sip,nta_outgoing_t * orq,tag_type_t tag,tag_value_t value,...)1588 int nua_client_treport(nua_client_request_t *cr,
1589 		       int status, char const *phrase,
1590 		       sip_t const *sip,
1591 		       nta_outgoing_t *orq,
1592 		       tag_type_t tag, tag_value_t value, ...)
1593 {
1594   int retval;
1595   ta_list ta;
1596   ta_start(ta, tag, value);
1597   retval = nua_client_report(cr, status, phrase, sip, orq, ta_args(ta));
1598   ta_end(ta);
1599   return retval;
1600 }
1601 
nua_client_next_request(nua_client_request_t * cr,int invite)1602 int nua_client_next_request(nua_client_request_t *cr, int invite)
1603 {
1604   for (; cr; cr = cr->cr_next) {
1605     if (cr->cr_method == sip_method_cancel)
1606       continue;
1607     break;
1608   }
1609 
1610   if (cr && !nua_client_request_in_progress(cr)) {
1611     nua_client_init_request(cr);
1612   }
1613 
1614   return 1;
1615 }
1616 
1617 nua_client_request_t *
nua_client_request_pending(nua_client_request_t const * cr)1618 nua_client_request_pending(nua_client_request_t const *cr)
1619 {
1620   for (;cr;cr = cr->cr_next)
1621     if (cr->cr_orq)
1622       return (nua_client_request_t *)cr;
1623 
1624   return NULL;
1625 }
1626 
1627 /**@internal
1628  * Save handle parameters and initial authentication info.
1629  *
1630  * @retval -1 upon an error
1631  * @retval 0 when successful
1632  */
nua_stack_init_handle(nua_t * nua,nua_handle_t * nh,tagi_t const * tags)1633 int nua_stack_init_handle(nua_t *nua, nua_handle_t *nh, tagi_t const *tags)
1634 {
1635   int retval = 0;
1636 
1637   if (nh == NULL)
1638     return -1;
1639 
1640   assert(nh != nua->nua_dhandle);
1641 
1642   if (nua_stack_set_params(nua, nh, nua_i_error, tags) < 0)
1643     retval = -1;
1644 
1645   if (retval || nh->nh_init) /* Already initialized? */
1646     return retval;
1647 
1648   if (nh->nh_tags)
1649     nh_authorize(nh, TAG_NEXT(nh->nh_tags));
1650 
1651   nh->nh_init = 1;
1652 
1653   return 0;
1654 }
1655