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