f1458a18195a9113f84b77d50e1982e6fee7f076
[sip-router] / modules / tm / rpc_uac.c
1 /* 
2  * $Id$
3  * 
4  * Copyright (C) 2009 iptelorg GmbH
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 /*
19  * modules/tm/rpc_uac.c
20  */
21 /*
22  * History:
23  * --------
24  *  2009-07-20  initial version (andrei)
25 */
26
27 #include "rpc_uac.h"
28 #include "../../rpc.h"
29 #include "../../socket_info.h"
30 #include "../../ut.h"
31 #include "../../parser/parse_from.h"
32 #include "../../str_list.h"
33 #include "ut.h"
34 #include "dlg.h"
35 #include "uac.h"
36 #include "callid.h"
37
38
39
40 /* RPC substitution char (used in rpc_t_uac headers) */
41 #define SUBST_CHAR '!'
42
43
44
45 #define skip_hf(_hf) (             \
46     ((_hf)->type == HDR_FROM_T)   || \
47     ((_hf)->type == HDR_TO_T)     || \
48     ((_hf)->type == HDR_CALLID_T) || \
49     ((_hf)->type == HDR_CSEQ_T)      \
50 )
51
52
53
54 /** make sure the rpc user created the msg properly.
55  * Make sure that the FIFO user created the message
56  * correctly and fill some extra parameters in function
57  * of the message contents.
58  * @param rpc - rpc handle
59  * @param  c  - rpc context handle
60  * @param msg - faked sip msg
61  * @param method 
62  * @param body
63  * @param fromtag - filled on success (1 if fromtag present, 0 if not)
64  * @param cseq_is - filled on success (1 if cseq present, 0 if not)
65  * @param cseq    - filled on success with the cseq number
66  * @callid        - filled on success with a pointer to the callid in the msg.
67  * @return -1 on error (and sends the rpc reply), 0 on success
68  */
69 static int rpc_uac_check_msg(rpc_t *rpc, void* c,
70                                                                 struct sip_msg* msg,
71                                                                 str* method, str* body, 
72                                                                 int* fromtag, int *cseq_is, int* cseq,
73                                                                 str* callid)
74 {
75         struct to_body* parsed_from;
76         struct cseq_body *parsed_cseq;
77         int i;
78         char ch;
79
80         if (body->len && !msg->content_type) {
81                 rpc->fault(c, 400, "Content-Type missing");
82                 goto err;
83         }
84
85         if (body->len && msg->content_length) {
86                 rpc->fault(c, 400, "Content-Length disallowed");
87                 goto err;
88         }
89
90         if (!msg->to) {
91                 rpc->fault(c, 400,  "To missing");
92                 goto err;
93         }
94
95         if (!msg->from) {
96                 rpc->fault(c, 400, "From missing");
97                 goto err;
98         }
99
100         /* we also need to know if there is from-tag and add it otherwise */
101         if (parse_from_header(msg) < 0) {
102                 rpc->fault(c, 400, "Error in From");
103                 goto err;
104         }
105
106         parsed_from = (struct to_body*)msg->from->parsed;
107         *fromtag = parsed_from->tag_value.s && parsed_from->tag_value.len;
108
109         *cseq = 0;
110         if (msg->cseq && (parsed_cseq = get_cseq(msg))) {
111                 *cseq_is = 1;
112                 for (i = 0; i < parsed_cseq->number.len; i++) {
113                         ch = parsed_cseq->number.s[i];
114                         if (ch >= '0' && ch <= '9' ) {
115                                 *cseq = (*cseq) * 10 + ch - '0';
116                         } else {
117                                 DBG("check_msg: Found non-numerical in CSeq: <%i>='%c'\n",
118                                                         (unsigned int)ch, ch);
119                                 rpc->fault(c, 400,  "Non-numerical CSeq");
120                                 goto err;
121                         }
122                 }
123                 
124                 if (parsed_cseq->method.len != method->len || 
125                                 memcmp(parsed_cseq->method.s, method->s, method->len) !=0 ) {
126                         rpc->fault(c, 400, "CSeq method mismatch");
127                         goto err;
128                 }
129         } else {
130                 *cseq_is = 0;
131         }
132
133         if (msg->callid) {
134                 callid->s = msg->callid->body.s;
135                 callid->len = msg->callid->body.len;
136         } else {
137                 callid->s = 0;
138                 callid->len = 0;
139         }
140         return 0;
141
142 err:
143         return -1;
144 }
145
146
147
148
149
150 /** construct a "header block" from a header list.
151   *
152   * @return pkg_malloc'ed header block on success (with *l set to its length),
153   *         0 on error.
154   */
155 static char *get_hfblock(str *uri, struct hdr_field *hf, int proto,
156                                                         struct socket_info* ssock, int* l)
157 {
158         struct str_list sl, *last, *i, *foo;
159         int p, frag_len, total_len;
160         char *begin, *needle, *dst, *ret, *d;
161         str *sock_name, *portname;
162         struct dest_info di;
163
164         ret = 0; /* pessimist: assume failure */
165         total_len = 0;
166         last = &sl;
167         last->next = 0;
168         if (ssock){
169                 sock_name = &ssock->address_str;
170                 portname = &ssock->port_no_str;
171         }else{
172                 sock_name = 0;
173                 portname = 0;
174         }
175
176         for (; hf; hf = hf->next) {
177                 if (skip_hf(hf)) continue;
178
179                 begin = needle = hf->name.s; 
180                 p = hf->len;
181
182                      /* substitution loop */
183                 while(p) {
184                         d = q_memchr(needle, SUBST_CHAR, p);
185                         if (!d || d + 1 >= needle + p) { /* nothing to substitute */
186                                 if (!append_str_list(begin, p, &last, &total_len)) goto error;
187                                 break;
188                         } else {
189                                 frag_len = d - begin;
190                                 d++; /* d not at the second substitution char */
191                                 switch(*d) {
192                                 case SUBST_CHAR: /* double SUBST_CHAR: IP */
193                                              /* string before substitute */
194                                         if (!append_str_list(begin, frag_len, &last, &total_len))
195                                                 goto error;
196                                              /* substitute */
197                                         if (!sock_name) {
198                                                 if (
199 #ifdef USE_DNS_FAILOVER
200                                                                 uri2dst(0, &di, 0, uri, proto)
201 #else
202                                                                 uri2dst(&di, 0, uri, proto)
203 #endif /* USE_DNS_FAILOVER */
204                                                                         == 0 ){
205                                                         LOG(L_ERR, "ERROR: get_hfblock: send_sock"
206                                                                                 " failed\n");
207                                                         goto error;
208                                                 }
209                                                 sock_name = &di.send_sock->address_str;
210                                                 portname = &di.send_sock->port_no_str;
211                                         }
212                                         if (!append_str_list(sock_name->s, sock_name->len, &last,
213                                                                         &total_len))
214                                                 goto error;
215                                         /* inefficient - FIXME --andrei*/
216                                         if (!append_str_list(":", 1, &last, &total_len)) goto error;
217                                         if (!append_str_list(portname->s, portname->len, &last,
218                                                                 &total_len)) goto error;
219                                         /* keep going ... */
220                                         begin = needle = d + 1;
221                                         p -= frag_len + 2;
222                                         continue;
223                                 default:
224                                         /* no valid substitution char -- keep going */
225                                         p -= frag_len + 1;
226                                         needle = d;
227                                 }
228                         } /* possible substitute */
229                 } /* substitution loop */
230                 DBG("get_hfblock: one more hf processed\n");
231         } /* header loop */
232         
233              /* construct a single header block now */
234         ret = pkg_malloc(total_len);
235         if (!ret) {
236                 LOG(L_ERR, "get_hfblock: no pkg mem for hf block\n");
237                 goto error;
238         }
239         i = sl.next;
240         dst = ret;
241         while(i) {
242                 foo = i;
243                 i = i->next;
244                 memcpy(dst, foo->s.s, foo->s.len);
245                 dst += foo->s.len;
246                 pkg_free(foo);
247         }
248         *l = total_len;
249         return ret;
250         
251  error:
252         i = sl.next;
253         while(i) {
254                 foo = i;
255                 i = i->next;
256                 pkg_free(foo);
257         }
258         *l = 0;
259         return 0;
260 }
261
262
263 #define RPC_ROUTE_PREFIX        "Route: "
264 #define RPC_ROUTE_PREFIX_LEN    (sizeof(RPC_ROUTE_PREFIX)-1)
265 #define RPC_ROUTE_SEPARATOR     ", "
266 #define RPC_ROUTE_SEPARATOR_LEN (sizeof(RPC_ROUTE_SEPARATOR)-1)
267
268
269 /** internal print routes into rpc reply function.
270  *  Prints the dialog routes. It's used internally by
271  *  rpx_print_uris (called from rpc_uac_callback()).
272  *  @param rpc
273  *  @param c - rpc context
274  *  @param reply - sip reply
275  */
276 static void  rpc_print_routes(rpc_t* rpc, void* c,
277                                                                 dlg_t* d)
278 {
279         rr_t* ptr;
280         int size;
281         char* buf;
282         char* p;
283         
284         
285         if (d->hooks.first_route == 0){
286                 rpc->add(c, "s", "");
287                 return;
288         }
289         size=RPC_ROUTE_PREFIX_LEN;
290         for (ptr=d->hooks.first_route; ptr; ptr=ptr->next)
291                 size+=ptr->len+(ptr->next!=0)*RPC_ROUTE_SEPARATOR_LEN;
292         if (d->hooks.last_route)
293                 size+=RPC_ROUTE_SEPARATOR_LEN + 1 /* '<' */ + 
294                                 d->hooks.last_route->len +1 /* '>' */;
295
296         buf=pkg_malloc(size+1);
297         if (buf==0){
298                 ERR("out of memory\n");
299                 rpc->add(c, "s", "");
300                 return;
301         }
302         p=buf;
303         memcpy(p, RPC_ROUTE_PREFIX, RPC_ROUTE_PREFIX_LEN);
304         p+=RPC_ROUTE_PREFIX_LEN;
305         for (ptr=d->hooks.first_route; ptr; ptr=ptr->next){
306                 memcpy(p, ptr->nameaddr.name.s, ptr->len);
307                 p+=ptr->len;
308                 if (ptr->next!=0){
309                         memcpy(p, RPC_ROUTE_SEPARATOR, RPC_ROUTE_SEPARATOR_LEN);
310                         p+=RPC_ROUTE_SEPARATOR_LEN;
311                 }
312         }
313         if (d->hooks.last_route){
314                 memcpy(p, RPC_ROUTE_SEPARATOR, RPC_ROUTE_SEPARATOR_LEN);
315                 p+=RPC_ROUTE_SEPARATOR_LEN;
316                 *p='<';
317                 p++;
318                 memcpy(p, d->hooks.last_route->s, d->hooks.last_route->len);
319                 p+=d->hooks.last_route->len;
320                 *p='>';
321                 p++;
322         }
323         *p=0;
324         rpc->add(c, "s", buf);
325         pkg_free(buf);
326         return;
327 }
328
329
330 /** internal print uri into rpc reply function.
331  *  Prints the uris into rpc reply. It's used internally by
332  *  rpc_uac_callback().
333  *  @param rpc
334  *  @param c - rpc context
335  *  @param reply - sip reply
336  */
337 static void  rpc_print_uris(rpc_t* rpc, void* c, struct sip_msg* reply)
338 {
339         dlg_t* dlg;
340         dlg=shm_malloc(sizeof(dlg_t));
341         if (dlg==0){
342                 ERR("out of memory (shm)\n");
343                 return;
344         }
345         memset(dlg, 0, sizeof(dlg_t));
346         if (dlg_response_uac(dlg, reply, TARGET_REFRESH_UNKNOWN) < 0) {
347                 ERR("failure while filling dialog structure\n");
348                 free_dlg(dlg);
349                 return;
350         }
351         if (dlg->state != DLG_CONFIRMED) {
352                 free_dlg(dlg);
353                 return;
354         }
355         if (dlg->hooks.request_uri->s){
356                 rpc->add(c, "S", dlg->hooks.request_uri);
357         }else{
358                 rpc->add(c, "s", "");
359         }
360         if (dlg->hooks.next_hop->s) {
361                 rpc->add(c, "S", dlg->hooks.next_hop);
362         } else {
363                 rpc->add(c, "s", "");
364         }
365         rpc_print_routes(rpc, c, dlg);
366         free_dlg(dlg);
367         return;
368 }
369
370
371
372 /* t_uac callback */
373 static void rpc_uac_callback(struct cell* t, int type, struct tmcb_params* ps)
374 {
375         rpc_delayed_ctx_t* dctx;
376         str text;
377         rpc_t* rpc;
378         void* c;
379         int code;
380         str* preason;
381         
382         dctx=(rpc_delayed_ctx_t*)*ps->param;
383         *ps->param=0;
384         if (dctx==0){
385                 BUG("null delayed reply ctx\n");
386                 return;
387         }
388         rpc=&dctx->rpc;
389         c=dctx->reply_ctx;
390         if (ps->rpl==FAKED_REPLY) {
391                 text.s=error_text(ps->code);
392                 text.len=strlen(text.s);
393                 code=ps->code;
394                 preason=&text;
395                 rpc->add(c, "dS", code, preason);
396                 rpc->add(c, "s", ""); /* request uri (rpc_print_uris)*/
397                 rpc->add(c, "s", ""); /* next hop (rpc_print_uris) */
398                 rpc->add(c, "s", ""); /* dialog routes (rpc_print_routes) */
399                 rpc->add(c, "s", ""); /* rest of the reply */
400         }else{
401                 code=ps->rpl->first_line.u.reply.statuscode;
402                 preason=&ps->rpl->first_line.u.reply.reason;
403                 rpc->add(c, "dS", code, preason);
404                 rpc_print_uris(rpc, c, ps->rpl);
405                 /* print all the reply (from the first header) */
406                 rpc->add(c, "s", ps->rpl->headers->name.s);
407         }
408         rpc->delayed_ctx_close(dctx);
409         ps->param=0;
410 }
411
412
413
414 /** rpc t_uac version-
415   * It expects the following list of strings as parameters:
416   *  method
417   *  request_uri
418   *  dst_uri (next hop) -- can be empty (either "" or ".", which is still
419   *                        supported for backwards compatibility with fifo)
420   *  send_socket (socket from which the message will be sent)
421   *  headers (message headers separated by CRLF, at least From and To
422   *           must be present)
423   *  body (optional, might be null or completely missing)
424   *
425   * If all the parameters are ok it will call t_uac() using them.
426   * Note: this version will  wait for the transaction final reply
427   * only if reply_wait is set to 1. Otherwise the rpc reply will be sent 
428   * immediately and it will be success if the paremters were ok and t_uac did
429   * not report any error.
430   * Note: reply waiting (reply_wait==1) is not yet supported.
431   * @param rpc - rpc handle
432   * @param  c - rpc current context
433   * @param reply_wait - if 1 do not generate a rpc reply until final response
434   *                     for the transaction arrives, if 0 immediately send
435   *                     an rpc reply (see above).
436   */
437 static void rpc_t_uac(rpc_t* rpc, void* c, int reply_wait)
438 {
439         /* rpc params */
440         str method, ruri, nexthop, send_socket, headers, body;
441         /* other internal vars.*/
442         str hfb, callid;
443         struct sip_uri p_uri, pnexthop;
444         struct sip_msg faked_msg;
445         struct socket_info* ssock;
446         str saddr;
447         int sport, sproto;
448         int ret, sip_error, err_ret, fromtag, cseq_is, cseq;
449         char err_buf[MAX_REASON_LEN];
450         dlg_t dlg;
451         uac_req_t uac_req;
452         rpc_delayed_ctx_t* dctx;
453         
454         body.s=0;
455         body.len=0;
456         dctx=0;
457         if (reply_wait && (rpc->capabilities == 0 ||
458                                                 !(rpc->capabilities(c) & RPC_DELAYED_REPLY))) {
459                 rpc->fault(c, 600, "Reply wait/async mode not supported"
460                                                         " by this rpc transport");
461                 return;
462         }
463         ret=rpc->scan(c, "SSSSS*S",
464                                         &method, &ruri, &nexthop, &send_socket, &headers, &body);
465         if (ret<5 && ! (-ret == 5)){
466                 rpc->fault(c, 400, "too few parameters (%d/5)", ret?ret:-ret);
467                 return;
468         }
469         /* check and parse parameters */
470         if (method.len==0){
471                 rpc->fault(c, 400, "Empty method");
472                 return;
473         }
474         if (parse_uri(ruri.s, ruri.len, &p_uri)<0){
475                 rpc->fault(c, 400, "Invalid request uri \"%s\"", ruri.s);
476                 return;
477         }
478         /* old fifo & unixsock backwards compatibility for nexthop: '.' is still
479            allowed */
480         if (nexthop.len==1 && nexthop.s[0]=='.'){
481                 /* empty nextop */
482                 nexthop.len=0;
483                 nexthop.s=0;
484         }else if (nexthop.len==0){
485                 nexthop.s=0;
486         }else if (parse_uri(nexthop.s, nexthop.len, &pnexthop)<0){
487                 rpc->fault(c, 400, "Invalid next-hop uri \"%s\"", nexthop.s);
488                 return;
489         }
490         /* kamailio backwards compatibility for send_socket: '.' is still
491            allowed for an empty socket */
492         ssock=0;
493         saddr.s=0;
494         saddr.len=0;
495         if (send_socket.len==1 && send_socket.s[0]=='.'){
496                 /* empty send socket */
497                 send_socket.len=0;
498         }else if (send_socket.len &&
499                                 (parse_phostport(send_socket.s, &saddr.s, &saddr.len,
500                                                                 &sport, &sproto)!=0 ||
501                                                                 /* check also if it's not a MH addr. */
502                                                                 saddr.len==0 || saddr.s[0]=='(')
503                                 ){
504                 rpc->fault(c, 400, "Invalid send socket \"%s\"", send_socket.s);
505                 return;
506         }else if (saddr.len && (ssock=grep_sock_info(&saddr, sport, sproto))==0){
507                 rpc->fault(c, 400, "No local socket for \"%s\"", send_socket.s);
508                 return;
509         }
510         /* check headers using the SIP parser to look in the header list */
511         memset(&faked_msg, 0, sizeof(struct sip_msg));
512         faked_msg.len=headers.len;
513         faked_msg.buf=faked_msg.unparsed=headers.s;
514         if (parse_headers(&faked_msg, HDR_EOH_F, 0)==-1){
515                 rpc->fault(c, 400, "Invalid headers");
516                 return;
517         }
518         /* at this moment all the parameters are parsed => more sanity checks */
519         if (rpc_uac_check_msg(rpc, c, &faked_msg, &method, &body, &fromtag,
520                                                         &cseq_is, &cseq, &callid)<0)
521                 goto error;
522         hfb.s=get_hfblock(nexthop.len? &nexthop: &ruri, faked_msg.headers,
523                                                 PROTO_NONE, ssock, &hfb.len);
524         if (hfb.s==0){
525                 rpc->fault(c, 500, "out of memory");
526                 goto error;
527         }
528         /* proceed to transaction creation */
529         memset(&dlg, 0, sizeof(dlg_t));
530         /* fill call-id if call-id present or else generate a callid */
531         if (callid.s && callid.len) dlg.id.call_id=callid;
532         else generate_callid(&dlg.id.call_id);
533         
534         /* We will not fill in dlg->id.rem_tag because
535          * if present it will be printed within To HF
536          */
537         
538         /* Generate fromtag if not present */
539         if (!fromtag) {
540                 generate_fromtag(&dlg.id.loc_tag, &dlg.id.call_id);
541         }
542         
543         /* Fill in CSeq */
544         if (cseq_is) dlg.loc_seq.value = cseq;
545         else dlg.loc_seq.value = DEFAULT_CSEQ;
546         dlg.loc_seq.is_set = 1;
547         
548         dlg.loc_uri = faked_msg.from->body;
549         dlg.rem_uri = faked_msg.to->body;
550         dlg.rem_target = ruri;
551         dlg.dst_uri = nexthop;
552         dlg.send_sock=ssock;
553         
554         memset(&uac_req, 0, sizeof(uac_req));
555         uac_req.method=&method;
556         uac_req.headers=&hfb;
557         uac_req.body=body.len?&body:0;
558         uac_req.dialog=&dlg;
559         if (reply_wait){
560                 dctx=rpc->delayed_ctx_new(c);
561                 if (dctx==0){
562                         rpc->fault(c, 500, "internal error: failed to create context");
563                         return;
564                 }
565                 uac_req.cb=rpc_uac_callback;
566                 uac_req.cbp=dctx;
567                 uac_req.cb_flags=TMCB_LOCAL_COMPLETED;
568                 /* switch to dctx, in case adding the callback fails and we
569                    want to still send a reply */
570                 rpc=&dctx->rpc;
571                 c=dctx->reply_ctx;
572         }
573         ret = t_uac(&uac_req);
574         
575         if (ret <= 0) {
576                 err_ret = err2reason_phrase(ret, &sip_error, err_buf,
577                         sizeof(err_buf), "RPC/UAC") ;
578                 if (err_ret > 0 )
579                 {
580                         rpc->fault(c, sip_error, "%s", err_buf);
581                 } else {
582                         rpc->fault(c, 500, "RPC/UAC error");
583                 }
584                 if (dctx)
585                         rpc->delayed_ctx_close(dctx);
586                 goto error01;
587         }
588 error01:
589         if (hfb.s) pkg_free(hfb.s);
590 error:
591         if (faked_msg.headers) free_hdr_field_lst(faked_msg.headers);
592 }
593
594
595
596 /** t_uac with no reply waiting.
597   * @see rpc_t_uac.
598   */
599 void rpc_t_uac_start(rpc_t* rpc, void* c)
600 {
601         rpc_t_uac(rpc, c, 0);
602 }
603
604 /** t_uac with reply waiting.
605   * @see rpc_t_uac.
606   */
607 void rpc_t_uac_wait(rpc_t* rpc, void* c)
608 {
609         rpc_t_uac(rpc, c, 1);
610 }
611
612 /* vi: set ts=4 sw=4 tw=79:ai:cindent: */