a bunch of small refactorings in the dialog module
[sip-router] / modules_k / dialog / dlg_transfer.c
1 /**
2  * $Id$
3  *
4  * Copyright (C) 2009 Daniel-Constantin Mierla (asipto.com)
5  *
6  * This file is part of kamailio, a free SIP server.
7  *
8  * kamailio is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version
12  *
13  * kamailio is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include "../../dprint.h"
27 #include "../../ut.h"
28 #include "../../trim.h"
29 #include "../../mem/mem.h"
30 #include "../../mem/shm_mem.h"
31 #include "../../parser/parse_from.h"
32 #include "../../parser/msg_parser.h"
33
34 #include "../../modules/tm/tm_load.h"
35
36 #include "dlg_req_within.h"
37 #include "dlg_handlers.h"
38 #include "dlg_transfer.h"
39
40 #define DLG_HOLD_SDP "v=0\r\no=kamailio-bridge 0 0 IN IP4 0.0.0.0\r\ns=kamailio\r\nc=IN IP4 0.0.0.0\r\nt=0 0\r\nm=audio 9 RTP/AVP 8 0\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:0 PCMU/8000\r\n"
41 #define DLG_HOLD_SDP_LEN        (sizeof(DLG_HOLD_SDP)-1)
42
43 #define DLG_HOLD_CT_HDR "Contact: <sip:kamailio.org:5060>\r\nContent-Type: application/sdp\r\n"
44 #define DLG_HOLD_CT_HDR_LEN     (sizeof(DLG_HOLD_CT_HDR)-1)
45
46 extern str dlg_bridge_controller;
47
48 void dlg_transfer_ctx_free(dlg_transfer_ctx_t *dtc)
49 {
50         struct dlg_cell *dlg;
51
52         if(dtc==NULL)
53                 return;
54         if(dtc->from.s!=NULL)
55                 shm_free(dtc->from.s);
56         if(dtc->to.s!=NULL)
57                 shm_free(dtc->to.s);
58
59         dlg = dtc->dlg;
60         if(dlg!=NULL)
61         {
62                 if (dlg->tag[DLG_CALLER_LEG].s)
63                         shm_free(dlg->tag[DLG_CALLER_LEG].s);
64
65                 if (dlg->tag[DLG_CALLEE_LEG].s)
66                         shm_free(dlg->tag[DLG_CALLEE_LEG].s);
67
68                 if (dlg->cseq[DLG_CALLER_LEG].s)
69                         shm_free(dlg->cseq[DLG_CALLER_LEG].s);
70
71                 if (dlg->cseq[DLG_CALLEE_LEG].s)
72                         shm_free(dlg->cseq[DLG_CALLEE_LEG].s);
73
74                 shm_free(dlg);
75         }
76
77         shm_free(dtc);
78 }
79
80 void dlg_refer_tm_callback(struct cell *t, int type, struct tmcb_params *ps)
81 {
82         dlg_transfer_ctx_t *dtc = NULL;
83         dlg_t* dialog_info = NULL;
84         str met = {"BYE", 3};
85         int result;
86         struct dlg_cell *dlg;
87         uac_req_t uac_r;
88
89         if(ps->param==NULL || *ps->param==0)
90         {
91                 LM_DBG("message id not received\n");
92                 return;
93         }
94         dtc = *((dlg_transfer_ctx_t**)ps->param);
95         if(dtc==NULL)
96                 return;
97         LM_DBG("REFER completed with status %d\n", ps->code);
98
99         /* we send the BYE anyhow */
100         dlg = dtc->dlg;
101         if ((dialog_info = build_dlg_t(dlg, DLG_CALLEE_LEG)) == 0){
102                 LM_ERR("failed to create dlg_t\n");
103                 goto error;
104         }
105
106         memset(&uac_r, '\0', sizeof(uac_req_t));
107         set_uac_req(&uac_r, &met, NULL, NULL, dialog_info, 0, NULL, NULL);
108         result = d_tmb.t_request_within(&uac_r);
109
110         if(result < 0) {
111                 LM_ERR("failed to send the REFER request\n");
112                 /* todo: clean-up dtc */
113                 goto error;
114         }
115
116         free_tm_dlg(dialog_info);
117         dlg_transfer_ctx_free(dtc);
118
119         LM_DBG("BYE sent\n");
120         return;
121
122 error:
123         dlg_transfer_ctx_free(dtc);
124         if(dialog_info)
125                 free_tm_dlg(dialog_info);
126         return;
127
128 }
129
130 static int dlg_refer_callee(dlg_transfer_ctx_t *dtc)
131 {
132         /*verify direction*/
133         dlg_t* dialog_info = NULL;
134         str met = {"REFER", 5};
135         int result;
136         str hdrs;
137         struct dlg_cell *dlg;
138         uac_req_t uac_r;
139
140         dlg = dtc->dlg;
141
142         if ((dialog_info = build_dlg_t(dlg, DLG_CALLEE_LEG)) == 0){
143                 LM_ERR("failed to create dlg_t\n");
144                 goto error;
145         }
146
147         hdrs.len = 23 + 2*CRLF_LEN + dlg_bridge_controller.len
148                 + dtc->to.len;
149         LM_DBG("sending REFER [%d] <%.*s>\n", hdrs.len, dtc->to.len, dtc->to.s);
150         hdrs.s = (char*)pkg_malloc(hdrs.len*sizeof(char));
151         if(hdrs.s == NULL)
152                 goto error;
153         memcpy(hdrs.s, "Referred-By: ", 13);
154         memcpy(hdrs.s+13, dlg_bridge_controller.s, dlg_bridge_controller.len);
155         memcpy(hdrs.s+13+dlg_bridge_controller.len, CRLF, CRLF_LEN);
156         memcpy(hdrs.s+13+dlg_bridge_controller.len+CRLF_LEN, "Refer-To: ", 10);
157         memcpy(hdrs.s+23+dlg_bridge_controller.len+CRLF_LEN, dtc->to.s,
158                         dtc->to.len);
159         memcpy(hdrs.s+23+dlg_bridge_controller.len+CRLF_LEN+dtc->to.len,
160                         CRLF, CRLF_LEN);
161
162         memset(&uac_r, '\0', sizeof(uac_req_t));
163         set_uac_req(&uac_r, &met, &hdrs, NULL, dialog_info, 0,
164                                 dlg_refer_tm_callback, (void*)dtc);
165         result = d_tmb.t_request_within(&uac_r);
166
167         pkg_free(hdrs.s);
168         if(result < 0) {
169                 LM_ERR("failed to send the REFER request\n");
170                 /* todo: clean-up dtc */
171                 goto error;
172         }
173
174         free_tm_dlg(dialog_info);
175
176         LM_DBG("REFER sent\n");
177         return 0;
178
179 error:
180         if(dialog_info)
181                 free_tm_dlg(dialog_info);
182         return -1;
183 }
184
185
186 void dlg_bridge_tm_callback(struct cell *t, int type, struct tmcb_params *ps)
187 {
188         struct sip_msg *msg = NULL;
189         dlg_transfer_ctx_t *dtc = NULL;
190         struct dlg_cell *dlg = NULL;
191         str s;
192         str cseq;
193         str empty = {"", 0};
194
195         if(ps->param==NULL || *ps->param==0)
196         {
197                 LM_DBG("message id not received\n");
198                 return;
199         }
200         dtc = *((dlg_transfer_ctx_t**)ps->param);
201         if(dtc==NULL)
202                 return;
203         LM_DBG("completed with status %d\n", ps->code);
204         if(ps->code>=300)
205                 goto error;
206
207         /* 2xx - build dialog/send refer */
208         msg = ps->rpl;
209         if((msg->cseq==NULL || parse_headers(msg,HDR_CSEQ_F,0)<0)
210                         || msg->cseq==NULL || msg->cseq->parsed==NULL)
211         {
212                         LM_ERR("bad sip message or missing CSeq hdr :-/\n");
213                         goto error;
214         }
215         cseq = (get_cseq(msg))->number;
216
217         if((msg->to==NULL && parse_headers(msg, HDR_TO_F,0)<0) || msg->to==NULL)
218         {
219                 LM_ERR("bad request or missing TO hdr\n");
220                 goto error;
221         }
222         if(parse_from_header(msg))
223         {
224                 LM_ERR("bad request or missing FROM hdr\n");
225                 goto error;
226         }
227         if((msg->callid==NULL && parse_headers(msg,HDR_CALLID_F,0)<0)
228                         || msg->callid==NULL){
229                 LM_ERR("bad request or missing CALLID hdr\n");
230                 goto error;
231         }
232         s = msg->callid->body;
233         trim(&s);
234
235         /* some sanity checks */
236         if (s.len==0 || get_from(msg)->tag_value.len==0) {
237                 LM_ERR("invalid request -> callid (%d) or from TAG (%d) empty\n",
238                         s.len, get_from(msg)->tag_value.len);
239                 goto error;
240         }
241
242         dlg = build_new_dlg(&s /*callid*/, &(get_from(msg)->uri) /*from uri*/,
243                 &(get_to(msg)->uri) /*to uri*/,
244                 &(get_from(msg)->tag_value)/*from_tag*/ );
245         if (dlg==0) {
246                 LM_ERR("failed to create new dialog\n");
247                 goto error;
248         }
249         dtc->dlg = dlg;
250         if (dlg_set_leg_info(dlg, &(get_from(msg)->tag_value),
251                                 &empty, &dlg_bridge_controller, &cseq, DLG_CALLER_LEG)!=0) {
252                 LM_ERR("dlg_set_leg_info failed\n");
253                 goto error;
254         }
255
256         if (populate_leg_info(dlg, msg, t, DLG_CALLEE_LEG,
257                         &(get_to(msg)->tag_value)) !=0)
258         {
259                 LM_ERR("could not add further info to the dialog\n");
260                 shm_free(dlg);
261                 goto error;
262         }
263
264         if(dlg_refer_callee(dtc)!=0)
265                 goto error;
266         return;
267
268 error:
269         dlg_transfer_ctx_free(dtc);
270         return;
271 }
272
273
274 int dlg_bridge(str *from, str *to, str *op)
275 {
276         dlg_transfer_ctx_t *dtc;
277         int ret;
278         str s_method = {"INVITE", 6};
279         str s_body;
280         str s_hdrs;
281         uac_req_t uac_r;
282
283         dtc = (dlg_transfer_ctx_t*)shm_malloc(sizeof(dlg_transfer_ctx_t));
284         if(dtc==NULL)
285         {
286                 LM_ERR("no shm\n");
287                 return -1;
288         }
289         memset(dtc, 0, sizeof(dlg_transfer_ctx_t));
290         dtc->from.s = (char*)shm_malloc((from->len+1)*sizeof(char));
291         if(dtc->from.s==NULL)
292         {
293                 LM_ERR("no shm\n");
294                 shm_free(dtc);
295                 return -1;
296         }
297         dtc->to.s = (char*)shm_malloc((to->len+1)*sizeof(char));
298         if(dtc->to.s==NULL)
299         {
300                 LM_ERR("no shm\n");
301                 shm_free(dtc->from.s);
302                 shm_free(dtc);
303                 return -1;
304         }
305         memcpy(dtc->from.s, from->s, from->len);
306         dtc->from.len = from->len;
307         dtc->from.s[dtc->from.len] = '\0';
308         memcpy(dtc->to.s, to->s, to->len);
309         dtc->to.len = to->len;
310         dtc->to.s[dtc->to.len] = '\0';
311
312         LM_DBG("bridge <%.*s> to <%.*s>\n", dtc->from.len, dtc->from.s,
313                         dtc->to.len, dtc->to.s);
314         s_body.s   = DLG_HOLD_SDP;
315         s_body.len = DLG_HOLD_SDP_LEN;
316         s_hdrs.s   = DLG_HOLD_CT_HDR;
317         s_hdrs.len = DLG_HOLD_CT_HDR_LEN;
318
319         memset(&uac_r, '\0', sizeof(uac_req_t));
320         uac_r.method = &s_method;
321         uac_r.headers = &s_hdrs;
322         uac_r.body = &s_body;
323         uac_r.cb = dlg_bridge_tm_callback;
324         uac_r.cbp = (void*)(long)dtc;
325         ret = d_tmb.t_request(&uac_r, /* UAC Req */
326                                                   &dtc->from, /* Request-URI (To) */
327                                                   &dtc->from, /* To */
328                                                   &dlg_bridge_controller, /* From */
329                                                   (op != NULL && op->len>0)?op:NULL /* Outbound-URI */
330                 );
331
332         if(ret<0)
333         {
334                 dlg_transfer_ctx_free(dtc);
335                 return -1;
336         }
337         return 0;
338 }
339
340 int dlg_transfer(struct dlg_cell *dlg, str *to, int side)
341 {
342         dlg_transfer_ctx_t *dtc = NULL;
343         struct dlg_cell *ndlg = NULL;
344         str from;
345         str empty = {"", 0};
346
347         dtc = (dlg_transfer_ctx_t*)shm_malloc(sizeof(dlg_transfer_ctx_t));
348         if(dtc==NULL)
349         {
350                 LM_ERR("no shm\n");
351                 return -1;
352         }
353         if(side==DLG_CALLEE_LEG)
354         {
355                 from = dlg->from_uri;
356         } else {
357                 from = dlg->to_uri;
358         }
359         memset(dtc, 0, sizeof(dlg_transfer_ctx_t));
360         dtc->from.s = (char*)shm_malloc((from.len+1)*sizeof(char));
361         if(dtc->from.s==NULL)
362         {
363                 LM_ERR("no shm\n");
364                 shm_free(dtc);
365                 return -1;
366         }
367         dtc->to.s = (char*)shm_malloc((to->len+1)*sizeof(char));
368         if(dtc->to.s==NULL)
369         {
370                 LM_ERR("no shm\n");
371                 shm_free(dtc->from.s);
372                 shm_free(dtc);
373                 return -1;
374         }
375         memcpy(dtc->from.s, from.s, from.len);
376         dtc->from.len = from.len;
377         dtc->from.s[dtc->from.len] = '\0';
378         memcpy(dtc->to.s, to->s, to->len);
379         dtc->to.len = to->len;
380         dtc->to.s[dtc->to.len] = '\0';
381         
382         if(side==DLG_CALLER_LEG)
383                 ndlg = build_new_dlg(&dlg->callid /*callid*/,
384                                 &dlg->to_uri /*from uri*/, &dlg->from_uri /*to uri*/,
385                                 &dlg->tag[side]/*from_tag*/ );
386         else
387                 ndlg = build_new_dlg(&dlg->callid /*callid*/,
388                                 &dlg->from_uri /*from uri*/, &dlg->to_uri /*to uri*/,
389                                 &dlg->tag[side]/*from_tag*/ );
390         if (ndlg==0) {
391                 LM_ERR("failed to create new dialog\n");
392                 goto error;
393         }
394         dtc->dlg = ndlg;
395         if (dlg_set_leg_info(ndlg, &dlg->tag[side], &empty,
396                         &dlg->contact[side], &dlg->cseq[side], DLG_CALLER_LEG)!=0)
397         {
398                 LM_ERR("dlg_set_leg_info failed for caller\n");
399                 goto error;
400         }
401         if(side==DLG_CALLEE_LEG)
402                 side = DLG_CALLER_LEG;
403         else
404                 side = DLG_CALLEE_LEG;
405         if (dlg_set_leg_info(ndlg, &dlg->tag[side], &dlg->route_set[side],
406                         &dlg->contact[side], &dlg->cseq[side], DLG_CALLEE_LEG)!=0)
407         {
408                 LM_ERR("dlg_set_leg_info failed for caller\n");
409                 goto error;
410         }
411
412         if(dlg_refer_callee(dtc)!=0)
413                 goto error;
414         return 0;
415
416 error:
417         dlg_transfer_ctx_free(dtc);
418         return -1;
419 }
420