1 /*
2  * This file is part of the Sofia-SIP package
3  *
4  * Copyright (C) 2006, 2009 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 #ifndef NUA_CLIENT_H
26 /** Defined when <nua_client.h> has been included. */
27 #define NUA_CLIENT_H
28 
29 /**@IFILE nua_client.h
30  * @brief Client requests
31  *
32  * @author Pekka Pessi <Pekka.Pessi@nokia.com>
33  * @author Kai Vehmanen <Kai.Vehmanen@nokia.com>
34  *
35  * @date Created: Tue Feb  3 15:50:35 EET 2009 ppessi
36  */
37 
38 #include <nua_types.h>
39 
40 /* Methods for client request. @internal */
41 typedef struct {
42   sip_method_t crm_method;
43   char const *crm_method_name;
44   size_t crm_extra;		/**< Size of private data */
45 
46   struct {
47     unsigned create_dialog:1, in_dialog:1, target_refresh:1;
48     unsigned:0;
49   } crm_flags;
50 
51   /** Generate a request message.
52    *
53    * @retval 1 when request message has been created
54    * @retval 0 when request message should be created in normal fashion
55    * @retval -1 upon an error
56    */
57   int (*crm_template)(nua_client_request_t *cr,
58 		      msg_t **return_msg,
59 		      tagi_t const *tags);
60 
61   /**@a crm_init is called when a client request is sent first time.
62    *
63    * @retval 1 when request has been responded
64    * @retval 0 when request should be sent in normal fashion
65    * @retval -1 upon an error
66    */
67   int (*crm_init)(nua_client_request_t *, msg_t *msg, sip_t *sip,
68 		  tagi_t const *tags);
69 
70   /** @a crm_send is called each time when a client request is sent.
71    *
72    * @retval 1 when request has been responded
73    * @retval 0 when request has been sent
74    * @retval -1 upon an error (but request message has not been destroyed)
75    * @retval -2 upon an error
76    */
77   int (*crm_send)(nua_client_request_t *,
78 		  msg_t *msg, sip_t *sip,
79 		  tagi_t const *tags);
80 
81   /** @a crm_check_restart is called each time when a response is received.
82    *
83    * It is used to restart request after responses with method-specific
84    * status code or method-specific way of restarting the request.
85    *
86    * @retval 1 when request has been restarted
87    * @retval 0 when response should be processed normally
88    */
89   int (*crm_check_restart)(nua_client_request_t *,
90 			   int status, char const *phrase,
91 			   sip_t const *sip);
92 
93   /** @a crm_recv is called each time a final response is received.
94    *
95    * A final response is in range 200 .. 699 (or internal response) and it
96    * cannot be restarted.
97    *
98    * crm_recv() should call nua_base_client_response() or
99    * nua_base_client_tresponse(). The return values below are documented with
100    * nua_base_client_response(), too.
101    *
102    * @retval 0 if response was preliminary
103    * @retval 1 if response was final
104    * @retval 2 if response destroyed the handle, too.
105    */
106   int (*crm_recv)(nua_client_request_t *,
107 		  int status, char const *phrase,
108 		  sip_t const *sip);
109 
110   /** @a crm_preliminary is called each time a preliminary response is received.
111    *
112    * A preliminary response is in range 101 .. 199.
113    *
114    * crm_preliminary() should call nua_base_client_response() or
115    * nua_base_client_tresponse().
116    *
117    * @retval 0 if response was preliminary
118    * @retval 1 if response was final
119    * @retval 2 if response destroyed the handle, too.
120    */
121   int (*crm_preliminary)(nua_client_request_t *,
122 			 int status, char const *phrase,
123 			 sip_t const *sip);
124 
125   /** @a crm_report is called each time a response is received and it is
126    * reported to the application.
127    *
128    * The status and phrase may be different from the status and phrase
129    * received from the network, e.g., when the request is restarted.
130    *
131    * @return The return value should be 0. It is currently ignored.
132    */
133   int (*crm_report)(nua_client_request_t *,
134 		    int status, char const *phrase,
135 		    sip_t const *sip,
136 		    nta_outgoing_t *orq,
137 		    tagi_t const *tags);
138 
139   /** @a crm_complete is called when a client-side request is destroyed.
140    *
141    * @return The return value should be 0. It is currently ignored.
142    */
143   int (*crm_complete)(nua_client_request_t *);
144 
145 } nua_client_methods_t;
146 
147 /* Client-side request. Documented by nua_client_create() */
148 struct nua_client_request
149 {
150   nua_client_request_t *cr_next, **cr_prev; /**< Linked list of requests */
151   nua_owner_t        *cr_owner;
152   nua_dialog_usage_t *cr_usage;
153 
154   nua_saved_signal_t cr_signal[1];
155   tagi_t const      *cr_tags;
156 
157   nua_client_methods_t const *cr_methods;
158 
159   msg_t              *cr_msg;
160   sip_t              *cr_sip;
161 
162   nta_outgoing_t     *cr_orq;
163 
164   su_timer_t         *cr_timer;	        /**< Expires or retry timer */
165 
166   /*nua_event_t*/ int cr_event;		/**< Request event */
167   sip_method_t        cr_method;
168   char const         *cr_method_name;
169 
170   url_t              *cr_target;
171 
172   char const         *cr_phrase;        /**< Latest status phrase */
173   unsigned short      cr_status;        /**< Latest status */
174   unsigned short      cr_retry_count;   /**< Retry count for this request */
175 
176   uint32_t            cr_seq;
177 
178   unsigned            cr_refs;	 /**< References to client request */
179 
180   /* Flags used with offer-answer */
181   unsigned short      cr_answer_recv;   /**< Recv answer in response
182 					 *  with this status.
183 					 */
184   unsigned cr_offer_sent:1;	/**< Sent offer in this request */
185 
186   unsigned cr_offer_recv:1;	/**< Recv offer in a response */
187   unsigned cr_answer_sent:1;	/**< Sent answer in (PR)ACK */
188 
189   /* Flags with usage */
190   unsigned cr_neutral:1;	/**< No effect on session or other usage */
191 
192   /* Lifelong flags? */
193   unsigned cr_auto:1;		/**< Request was generated by stack */
194   unsigned cr_has_contact:1;	/**< Request has user Contact */
195   unsigned cr_contactize:1;	/**< Request needs Contact */
196   unsigned cr_dialog:1;		/**< Request can initiate dialog */
197 
198   /* Current state */
199   unsigned cr_initial:1;	/**< Initial request of a dialog */
200   unsigned cr_acked:1;		/**< Final response to the request has been ACKed */
201   unsigned cr_waiting:1;	/**< Request is waiting */
202   unsigned cr_challenged:1;	/**< Request was challenged */
203   unsigned cr_wait_for_cred:1;	/**< Request is pending authentication */
204   unsigned cr_restarting:1;	/**< Request is being restarted */
205   unsigned cr_reporting:1;	/**< Reporting in progress */
206   unsigned cr_terminating:1;	/**< Request terminates the usage */
207   signed int cr_terminated:2;	/**< Response terminated usage (1) or
208 				    whole dialog (-1) */
209   unsigned cr_graceful:1;	/**< Graceful termination required */
210 };
211 
212 int nua_client_create(nua_owner_t *owner,
213 		      int event,
214 		      nua_client_methods_t const *methods,
215 		      tagi_t const *tags);
216 
217 int nua_client_tcreate(nua_owner_t *nh,
218 		       int event,
219 		       nua_client_methods_t const *methods,
220 		       tag_type_t tag, tag_value_t value, ...);
221 
222 su_inline
nua_private_client_request(nua_client_request_t const * cr)223 void *nua_private_client_request(nua_client_request_t const *cr)
224 {
225   return (void *)(cr + 1);
226 }
227 
228 nua_client_request_t *nua_client_request_ref(nua_client_request_t *);
229 int nua_client_request_unref(nua_client_request_t *);
230 
231 #if HAVE_MEMLEAK_LOG
232 
233 #define nua_client_request_ref(cr) \
234   nua_client_request_ref_by((cr), __FILE__, __LINE__, __func__)
235 #define nua_client_request_unref(cr) \
236   nua_client_request_unref_by((cr), __FILE__, __LINE__, __func__)
237 
238 nua_client_request_t *nua_client_request_ref_by(nua_client_request_t *,
239 						char const *file, unsigned line,
240 						char const *who);
241 int nua_client_request_unref_by(nua_client_request_t *,
242 				char const *file, unsigned line, char const *who);
243 
244 #endif
245 
246 int nua_client_request_queue(nua_client_request_t *cr);
247 
nua_client_is_queued(nua_client_request_t const * cr)248 su_inline int nua_client_is_queued(nua_client_request_t const *cr)
249 {
250   return cr && cr->cr_prev;
251 }
252 
253 int nua_client_request_in_progress(nua_client_request_t const *cr);
254 
255 int nua_client_request_complete(nua_client_request_t *cr);
256 int nua_client_request_remove(nua_client_request_t *cr);
257 int nua_client_request_clean(nua_client_request_t *cr);
258 int nua_client_bind(nua_client_request_t *cr, nua_dialog_usage_t *du);
259 
nua_client_is_bound(nua_client_request_t const * cr)260 su_inline int nua_client_is_bound(nua_client_request_t const *cr)
261 {
262   return cr && cr->cr_usage && cr->cr_usage->du_cr == cr;
263 }
264 
nua_client_is_reporting(nua_client_request_t const * cr)265 su_inline int nua_client_is_reporting(nua_client_request_t const *cr)
266 {
267   return cr && cr->cr_reporting;
268 }
269 
270 /** Mark client request as a terminating one */
nua_client_set_terminating(nua_client_request_t * cr,int value)271 su_inline void nua_client_set_terminating(nua_client_request_t *cr, int value)
272 {
273   cr->cr_terminating = value != 0;
274 }
275 
276 int nua_client_init_request(nua_client_request_t *cr);
277 
278 msg_t *nua_client_request_template(nua_client_request_t *cr);
279 
280 int nua_client_restart_request(nua_client_request_t *cr,
281 			       int terminating,
282 			       tagi_t const *tags);
283 
284 int nua_client_resend_request(nua_client_request_t *cr,
285 			      int terminating);
286 
287 int nua_base_client_request(nua_client_request_t *cr,
288 			    msg_t *msg,
289 			    sip_t *sip,
290 			    tagi_t const *tags);
291 
292 int nua_base_client_trequest(nua_client_request_t *cr,
293 			     msg_t *msg,
294 			     sip_t *sip,
295 			     tag_type_t tag, tag_value_t value, ...);
296 
297 extern nta_response_f nua_client_orq_response;
298 
299 int nua_client_return(nua_client_request_t *cr,
300 		      int status,
301 		      char const *phrase,
302 		      msg_t *to_be_destroyed);
303 
304 int nua_client_response(nua_client_request_t *cr,
305 			int status,
306 			char const *phrase,
307 			sip_t const *sip);
308 
309 int nua_client_check_restart(nua_client_request_t *cr,
310 			     int status,
311 			     char const *phrase,
312 			     sip_t const *sip);
313 
314 int nua_base_client_check_restart(nua_client_request_t *cr,
315 				  int status,
316 				  char const *phrase,
317 				  sip_t const *sip);
318 
319 int nua_client_restart(nua_client_request_t *cr,
320 		       int status, char const *phrase);
321 
322 int nua_base_client_response(nua_client_request_t *cr,
323 			     int status, char const *phrase,
324 			     sip_t const *sip,
325 			     tagi_t const *tags);
326 
327 int nua_base_client_tresponse(nua_client_request_t *cr,
328 			      int status, char const *phrase,
329 			      sip_t const *sip,
330 			      tag_type_t tag, tag_value_t value, ...);
331 
332 int nua_client_set_target(nua_client_request_t *cr, url_t const *target);
333 
334 int nua_client_report(nua_client_request_t *cr,
335 		      int status, char const *phrase,
336 		      sip_t const *sip,
337 		      nta_outgoing_t *orq,
338 		      tagi_t const *tags);
339 
340 nua_client_request_t *nua_client_request_pending(nua_client_request_t const *);
341 
342 int nua_client_next_request(nua_client_request_t *cr, int invite);
343 
344 #endif /* NUA_CLIENT_H */
345