f81de9ff6a8cdb329f1646ff3cceceaa822eed9d
[sip-router] / modules / tm / uac.c
1 /*
2  * $Id$
3  *
4  * simple UAC for things such as SUBSCRIBE or SMS gateway;
5  * no authentication and other UAC features -- just send
6  * a message, retransmit and await a reply; forking is not
7  * supported during client generation, in all other places
8  * it is -- adding it should be simple
9  *
10  * Copyright (C) 2001-2003 FhG Fokus
11  *
12  * This file is part of ser, a free SIP server.
13  *
14  * ser is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version
18  *
19  * For a license to use the ser software under conditions
20  * other than those described here, or to purchase support for this
21  * software, please contact iptel.org by e-mail at the following addresses:
22  *    info@iptel.org
23  *
24  * ser is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27  * GNU General Public License for more details.
28  *
29  * You should have received a copy of the GNU General Public License 
30  * along with this program; if not, write to the Free Software 
31  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
32  *
33  * History:
34  * --------
35  *  2003-01-23  t_uac_dlg now uses get_out_socket (jiri)
36  *  2003-01-27  fifo:t_uac_dlg completed (jiri)
37  *  2003-01-29  scratchpad removed (jiri)
38  *  2003-02-13  t_uac, t _uac_dlg, gethfblock, uri2proxy changed to use 
39  *               proto & rb->dst (andrei)
40  *  2003-02-27  FIFO/UAC now dumps reply -- good for CTD (jiri)
41  *  2003-02-28  scratchpad compatibility abandoned (jiri)
42  *  2003-03-01  kr set through a function now (jiri)
43  *  2003-03-19  replaced all mallocs/frees w/ pkg_malloc/pkg_free (andrei)
44  *  2003-04-02  port_no_str does not contain a leading ':' anymore (andrei)
45  *  2003-07-08  appropriate log messages in check_params(...), 
46  *               call calculate_hooks if next_hop==NULL in t_uac (dcm) 
47  *  2003-10-24  updated to the new socket_info lists (andrei)
48  *  2003-12-03  completion filed removed from transaction and uac callbacks
49  *              merged in transaction callbacks as LOCAL_COMPLETED (bogdan)
50  *  2004-02-11  FIFO/CANCEL + alignments (hash=f(callid,cseq)) (uli+jiri)
51  *  2004-02-13  t->is_invite, t->local, t->noisy_ctimer replaced (bogdan)
52  *  2004-08-23  avp support in t_uac (bogdan)
53  *  2005-12-16  t_uac will set the new_cell timers to the default values,
54  *               fixes 0 fr_timer bug (andrei)
55  *  2006-08-11  t_uac uses dns failover until it finds a send socket (andrei)
56  */
57
58 #include <string.h>
59 #include "../../mem/shm_mem.h"
60 #include "../../dprint.h"
61 #include "../../globals.h"
62 #include "../../md5.h"
63 #include "../../crc.h"
64 #include "../../ip_addr.h"
65 #include "../../socket_info.h"
66 #include "ut.h"
67 #include "h_table.h"
68 #include "t_hooks.h"
69 #include "t_funcs.h"
70 #include "t_msgbuilder.h"
71 #include "callid.h"
72 #include "uac.h"
73
74
75 #define FROM_TAG_LEN (MD5_LEN + 1 /* - */ + CRC16_LEN) /* length of FROM tags */
76
77 static char from_tag[FROM_TAG_LEN + 1];
78
79 char* uac_from = "sip:foo@foo.bar"; /* Module parameter */
80
81 /* Enable/disable passing of provisional replies to FIFO applications */
82 int pass_provisional_replies = 0;
83
84 /*
85  * Initialize UAC
86  */
87 int uac_init(void) 
88 {
89         str src[3];
90         struct socket_info *si;
91
92         if (RAND_MAX < TABLE_ENTRIES) {
93                 LOG(L_WARN, "Warning: uac does not spread "
94                     "across the whole hash table\n");
95         }
96         /* on tcp/tls bind_address is 0 so try to get the first address we listen
97          * on no matter the protocol */
98         si=bind_address?bind_address:get_first_socket();
99         if (si==0){
100                 LOG(L_CRIT, "BUG: uac_init: null socket list\n");
101                 return -1;
102         }
103
104         /* calculate the initial From tag */
105         src[0].s = "Long live SER server";
106         src[0].len = strlen(src[0].s);
107         src[1].s = si->address_str.s;
108         src[1].len = strlen(src[1].s);
109         src[2].s = si->port_no_str.s;
110         src[2].len = strlen(src[2].s);
111
112         MDStringArray(from_tag, src, 3);
113         from_tag[MD5_LEN] = '-';
114         return 1;
115 }
116
117
118 /*
119  * Generate a From tag
120  */
121 void generate_fromtag(str* tag, str* callid)
122 {
123              /* calculate from tag from callid */
124         crcitt_string_array(&from_tag[MD5_LEN + 1], callid, 1);
125         tag->s = from_tag; 
126         tag->len = FROM_TAG_LEN;
127 }
128
129
130 /*
131  * Check value of parameters
132  */
133 static inline int check_params(str* method, str* to, str* from, dlg_t** dialog)
134 {
135         if (!method || !to || !from || !dialog) {
136                 LOG(L_ERR, "check_params(): Invalid parameter value\n");
137                 return -1;
138         }
139
140         if (!method->s || !method->len) {
141                 LOG(L_ERR, "check_params(): Invalid request method\n");
142                 return -2;
143         }
144
145         if (!to->s || !to->len) {
146                 LOG(L_ERR, "check_params(): Invalid To URI\n");
147                 return -4;
148         }
149
150         if (!from->s || !from->len) {
151                 LOG(L_ERR, "check_params(): Invalid From URI\n");
152                 return -5;
153         }
154         return 0;
155 }
156
157 static inline unsigned int dlg2hash( dlg_t* dlg )
158 {
159         str cseq_nr;
160         unsigned int hashid;
161
162         cseq_nr.s=int2str(dlg->loc_seq.value, &cseq_nr.len);
163         hashid=hash(dlg->id.call_id, cseq_nr);
164         DBG("DEBUG: dlg2hash: %d\n", hashid);
165         return hashid;
166 }
167
168 static inline int t_uac_prepare(str* method, str* headers, str* body, dlg_t* dialog,
169           transaction_cb cb, void* cbp, struct retr_buf **dst_req)
170 {
171         struct dest_info dst;
172         struct cell *new_cell;
173         struct retr_buf *request;
174         char* buf;
175         int buf_len, ret, flags;
176         unsigned int hi;
177 #ifdef USE_DNS_FAILOVER
178         struct dns_srv_handle dns_h;
179 #endif
180
181         ret=-1;
182         /*if (dst_req) *dst_req = NULL;*/
183         
184         /*** added by dcm 
185          * - needed by external ua to send a request within a dlg
186          */
187         if(!dialog->hooks.next_hop && w_calculate_hooks(dialog)<0)
188                 goto error2;
189
190         DBG("DEBUG:tm:t_uac: next_hop=<%.*s>\n",dialog->hooks.next_hop->len,
191                         dialog->hooks.next_hop->s);
192         /* it's a new message, so we will take the default socket */
193 #ifdef USE_DNS_FAILOVER
194         if (use_dns_failover){
195                 dns_srv_handle_init(&dns_h);
196                 if ((uri2dst(&dns_h, &dst, 0, dialog->hooks.next_hop, PROTO_NONE)==0)
197                                 || (dst.send_sock==0)){
198                         dns_srv_handle_put(&dns_h);
199                         ser_error = E_NO_SOCKET;
200                         ret=ser_error;
201                         LOG(L_ERR, "t_uac: no socket found\n");
202                         goto error2;
203                 }
204                 dns_srv_handle_put(&dns_h); /* not needed anymore */
205         }else{
206                 if ((uri2dst(0, &dst, 0, dialog->hooks.next_hop, PROTO_NONE)==0) ||
207                                 (dst.send_sock==0)){
208                         ser_error = E_NO_SOCKET;
209                         ret=ser_error;
210                         LOG(L_ERR, "t_uac: no socket found\n");
211                         goto error2;
212                 }
213         }
214 #else
215         if ((uri2dst(&dst, 0, dialog->hooks.next_hop, PROTO_NONE)==0) ||
216                         (dst.send_sock==0)){
217                 ser_error = E_NO_SOCKET;
218                 ret=ser_error;
219                 LOG(L_ERR, "t_uac: no socket found\n");
220                 goto error2;
221         }
222 #endif
223
224         new_cell = build_cell(0); 
225         if (!new_cell) {
226                 ret=E_OUT_OF_MEM;
227                 LOG(L_ERR, "t_uac: short of cell shmem\n");
228                 goto error2;
229         }
230         /* init timers hack, new_cell->fr_timer and new_cell->fr_inv_timer
231          * must be set, or else the fr will happen immediately
232          * we can't call init_new_t() because we don't have a sip msg
233          * => we'll ignore t_set_fr() or avp timer value and will use directly the
234          * module params fr_inv_timer and fr_timer -- andrei */
235         new_cell->fr_timeout=fr_timeout;
236         new_cell->fr_inv_timeout=fr_inv_timeout;
237
238         /* better reset avp list now - anyhow, it's useless from
239          * this point (bogdan) */
240         reset_avps();
241
242         /* add the callback the the transaction for LOCAL_COMPLETED event */
243  
244         flags = TMCB_LOCAL_COMPLETED;
245         /* Add also TMCB_LOCAL_REPLY_OUT if provisional replies are desired */
246         if (pass_provisional_replies) flags |= TMCB_LOCAL_RESPONSE_OUT;
247
248         if(cb && insert_tmcb(&(new_cell->tmcb_hl), flags, cb, cbp)!=1){
249                 ret=E_OUT_OF_MEM; 
250                 LOG(L_ERR, "t_uac: short of tmcb shmem\n");
251                 goto error2;
252         }
253
254         if (method->len==INVITE_LEN && memcmp(method->s, INVITE, INVITE_LEN)==0)
255                 new_cell->flags |= T_IS_INVITE_FLAG;
256         new_cell->flags |= T_IS_LOCAL_FLAG;
257         set_kr(REQ_FWDED);
258
259         request = &new_cell->uac[0].request;
260         
261         request->dst = dst;
262
263         hi=dlg2hash(dialog);
264         LOCK_HASH(hi);
265         insert_into_hash_table_unsafe(new_cell, hi);
266         UNLOCK_HASH(hi);
267
268         buf = build_uac_req(method, headers, body, dialog, 0, new_cell,
269                 &buf_len, &dst);
270         if (!buf) {
271                 LOG(L_ERR, "t_uac: Error while building message\n");
272                 ret=E_OUT_OF_MEM;
273                 goto error1;
274         }
275
276         new_cell->method.s = buf;
277         new_cell->method.len = method->len;
278
279         request->buffer = buf;
280         request->buffer_len = buf_len;
281         new_cell->nr_of_outgoings++;
282         
283         if (dst_req) *dst_req = request;
284         
285         return 1;
286
287  error1:
288         LOCK_HASH(hi);
289         remove_from_hash_table_unsafe(new_cell);
290         UNLOCK_HASH(hi);
291         free_cell(new_cell);
292 error2:
293         return ret;
294 }
295
296 /*
297  * Prepare a message within a dialog
298  */
299 int prepare_req_within(str* method, str* headers, 
300                 str* body, dlg_t* dialog, transaction_cb completion_cb, 
301                 void* cbp, struct retr_buf **dst_req)
302 {
303         if (!method || !dialog) {
304                 LOG(L_ERR, "req_within: Invalid parameter value\n");
305                 goto err;
306         }
307
308         if (dialog->state != DLG_CONFIRMED) {
309                 LOG(L_ERR, "req_within: Dialog is not confirmed yet\n");
310                 goto err;
311         }
312
313         if ((method->len == 3) && (!memcmp("ACK", method->s, 3))) goto send;
314         if ((method->len == 6) && (!memcmp("CANCEL", method->s, 6))) goto send;
315         dialog->loc_seq.value++; /* Increment CSeq */
316  send:
317         return t_uac_prepare(method, headers, body, dialog, completion_cb, cbp, dst_req);
318
319  err:
320         /* if (cbp) shm_free(cbp); */
321         /* !! never free cbp here because if t_uac_prepare fails, cbp is not freed
322          * and thus caller has no chance to discover if it is freed or not !! */
323         return -1;
324 }
325
326 static inline void send_prepared_request_impl(struct retr_buf *request)
327 {
328         if (SEND_BUFFER(request) == -1) {
329                 LOG(L_ERR, "t_uac: Attempt to send to precreated request failed\n");
330         }
331         
332         if (start_retr(request)!=0)
333                 LOG(L_CRIT, "BUG: t_uac: failed to start retr. for %p\n", request);
334 }
335
336 void send_prepared_request(struct retr_buf *request)
337 {
338         send_prepared_request_impl(request);
339 }
340
341 /*
342  * Send a request using data from the dialog structure
343  */
344 int t_uac(str* method, str* headers, str* body, dlg_t* dialog,
345           transaction_cb cb, void* cbp)
346 {
347         struct retr_buf *request;
348         int ret;
349
350         ret = t_uac_prepare(method, headers, body, dialog, cb, cbp, &request);
351         if (ret < 0) return ret;
352         send_prepared_request_impl(request);
353         return ret;
354 }
355
356
357 /*
358  * Send a message within a dialog
359  */
360 int req_within(str* method, str* headers, str* body, dlg_t* dialog, transaction_cb completion_cb, void* cbp)
361 {
362         if (!method || !dialog) {
363                 LOG(L_ERR, "req_within: Invalid parameter value\n");
364                 goto err;
365         }
366
367         if (dialog->state != DLG_CONFIRMED) {
368                 LOG(L_ERR, "req_within: Dialog is not confirmed yet\n");
369                 goto err;
370         }
371
372         if ((method->len == 3) && (!memcmp("ACK", method->s, 3))) goto send;
373         if ((method->len == 6) && (!memcmp("CANCEL", method->s, 6))) goto send;
374         dialog->loc_seq.value++; /* Increment CSeq */
375  send:
376         return t_uac(method, headers, body, dialog, completion_cb, cbp);
377
378  err:
379         if (cbp) shm_free(cbp);
380         return -1;
381 }
382
383
384 /*
385  * Send an initial request that will start a dialog
386  */
387 int req_outside(str* method, str* to, str* from, str* headers, str* body, dlg_t** dialog, transaction_cb cb, void* cbp)
388 {
389         str callid, fromtag;
390
391         if (check_params(method, to, from, dialog) < 0) goto err;
392         
393         generate_callid(&callid);
394         generate_fromtag(&fromtag, &callid);
395
396         if (new_dlg_uac(&callid, &fromtag, DEFAULT_CSEQ, from, to, dialog) < 0) {
397                 LOG(L_ERR, "req_outside(): Error while creating new dialog\n");
398                 goto err;
399         }
400
401         return t_uac(method, headers, body, *dialog, cb, cbp);
402
403  err:
404         if (cbp) shm_free(cbp);
405         return -1;
406 }
407
408
409 /*
410  * Send a transactional request, no dialogs involved
411  */
412 int request(str* m, str* ruri, str* to, str* from, str* h, str* b, str *next_hop, transaction_cb c, void* cp)
413 {
414         str callid, fromtag;
415         dlg_t* dialog;
416         int res;
417
418         if (check_params(m, to, from, &dialog) < 0) goto err;
419
420         generate_callid(&callid);
421         generate_fromtag(&fromtag, &callid);
422
423         if (new_dlg_uac(&callid, &fromtag, DEFAULT_CSEQ, from, to, &dialog) < 0) {
424                 LOG(L_ERR, "request(): Error while creating temporary dialog\n");
425                 goto err;
426         }
427
428         if (ruri) {
429                 dialog->rem_target.s = ruri->s;
430                 dialog->rem_target.len = ruri->len;
431                 dialog->hooks.request_uri = &dialog->rem_target;
432         }
433         w_calculate_hooks(dialog);
434
435         if (next_hop) 
436                 if ((next_hop->len > 0) && next_hop->s) dialog->hooks.next_hop = next_hop;
437
438         res = t_uac(m, h, b, dialog, c, cp);
439         dialog->rem_target.s = 0;
440         free_dlg(dialog);
441         return res;
442
443  err:
444         if (cp) shm_free(cp);
445         return -1;
446 }