1 /*
2 * Copyright (C) 2009 iptelorg GmbH
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16 /*
17 * modules/tm/rpc_uac.c
18 */
19
20 #include "rpc_uac.h"
21 #include "../../core/rpc.h"
22 #include "../../core/socket_info.h"
23 #include "../../core/ut.h"
24 #include "../../core/parser/parse_from.h"
25 #include "../../core/str_list.h"
26 #include "../../core/timer_proc.h"
27 #include "../../core/utils/sruid.h"
28 #include "ut.h"
29 #include "dlg.h"
30 #include "uac.h"
31 #include "callid.h"
32
33
34 /* RPC substitution char (used in rpc_t_uac headers) */
35 #define SUBST_CHAR '!'
36
37 #define TM_RPC_RESPONSE_LIFETIME 300
38 #define TM_RPC_RESPONSE_TIMERSTEP 10
39
40 void tm_rpc_response_list_clean(unsigned int ticks, void *param);
41
42 typedef struct tm_rpc_response {
43 str ruid;
44 int flags;
45 int rcode;
46 str rtext;
47 time_t rtime;
48 struct tm_rpc_response *next;
49 } tm_rpc_response_t;
50
51 typedef struct tm_rpc_response_list {
52 gen_lock_t rlock;
53 tm_rpc_response_t *rlist;
54 } tm_rpc_response_list_t;
55
56 static tm_rpc_response_list_t *_tm_rpc_response_list = NULL;
57
58 static sruid_t _tm_rpc_sruid;
59
60 /**
61 *
62 */
tm_rpc_response_list_init(void)63 int tm_rpc_response_list_init(void)
64 {
65 if(_tm_rpc_response_list != NULL) {
66 return 0;
67 }
68 if(sruid_init(&_tm_rpc_sruid, '-', "tmrp", SRUID_INC)<0) {
69 LM_ERR("failed to init sruid\n");
70 return -1;
71 }
72 if(sr_wtimer_add(tm_rpc_response_list_clean, 0,
73 TM_RPC_RESPONSE_TIMERSTEP)<0) {
74 LM_ERR("failed to register timer routine\n");
75 return -1;
76 }
77 _tm_rpc_response_list = shm_malloc(sizeof(tm_rpc_response_list_t));
78 if(_tm_rpc_response_list == NULL) {
79 SHM_MEM_ERROR;
80 return -1;
81 }
82
83 memset(_tm_rpc_response_list, 0, sizeof(tm_rpc_response_list_t));
84
85 lock_init(&_tm_rpc_response_list->rlock);
86
87 return 0;
88 }
89
90 /**
91 *
92 */
tm_rpc_response_list_destroy(void)93 int tm_rpc_response_list_destroy(void)
94 {
95 tm_rpc_response_t *rl0 = NULL;
96 tm_rpc_response_t *rl1 = NULL;
97
98 if(_tm_rpc_response_list == NULL) {
99 return 0;
100 }
101
102 rl1 = _tm_rpc_response_list->rlist;
103
104 while(rl1!=NULL) {
105 rl0 = rl1;
106 rl1 = rl1->next;
107 shm_free(rl0);
108 }
109 lock_destroy(&_tm_rpc_response_list->rlock);
110 shm_free(_tm_rpc_response_list);
111 _tm_rpc_response_list = NULL;
112
113 return 0;
114 }
115
116 /**
117 *
118 */
tm_rpc_response_list_add(str * ruid,int rcode,str * rtext)119 int tm_rpc_response_list_add(str *ruid, int rcode, str *rtext)
120 {
121 size_t rsize = 0;
122 tm_rpc_response_t *ri = NULL;
123 if(_tm_rpc_response_list == NULL) {
124 LM_ERR("rpc response list not initialized\n");
125 return -1;
126 }
127
128 rsize = sizeof(tm_rpc_response_t) + ruid->len + 2
129 + ((rtext!=NULL)?rtext->len:0);
130
131 ri = (tm_rpc_response_t*)shm_malloc(rsize);
132 if(ri==NULL) {
133 SHM_MEM_ERROR;
134 return -1;
135 }
136 memset(ri, 0, rsize);
137
138 ri->ruid.s = (char*)ri + sizeof(tm_rpc_response_t);
139 ri->ruid.len = ruid->len;
140 memcpy(ri->ruid.s, ruid->s, ruid->len);
141 ri->rtime = time(NULL);
142 ri->rcode = rcode;
143 if(rtext!=NULL) {
144 ri->rtext.s = ri->ruid.s + ri->ruid.len + 1;
145 ri->rtext.len = rtext->len;
146 memcpy(ri->rtext.s, rtext->s, rtext->len);
147 }
148 lock_get(&_tm_rpc_response_list->rlock);
149 ri->next = _tm_rpc_response_list->rlist;
150 _tm_rpc_response_list->rlist = ri;
151 lock_release(&_tm_rpc_response_list->rlock);
152
153 return 0;
154 }
155
156 /**
157 *
158 */
tm_rpc_response_list_get(str * ruid)159 tm_rpc_response_t *tm_rpc_response_list_get(str *ruid)
160 {
161 tm_rpc_response_t *ri0 = NULL;
162 tm_rpc_response_t *ri1 = NULL;
163
164 if(_tm_rpc_response_list == NULL) {
165 LM_ERR("rpc response list not initialized\n");
166 return NULL;
167 }
168
169 lock_get(&_tm_rpc_response_list->rlock);
170 ri1 = _tm_rpc_response_list->rlist;
171 while(ri1!=NULL) {
172 if(ri1->ruid.len==ruid->len
173 && memcmp(ri1->ruid.s, ruid->s, ruid->len)==0) {
174 if(ri0 == NULL) {
175 _tm_rpc_response_list->rlist = ri1->next;
176 } else {
177 ri0->next = ri1->next;
178 }
179 lock_release(&_tm_rpc_response_list->rlock);
180 return ri1;
181 }
182 ri0 = ri1;
183 ri1 = ri1->next;
184 }
185 lock_release(&_tm_rpc_response_list->rlock);
186 return NULL;
187 }
188
189 /**
190 *
191 */
tm_rpc_response_list_clean(unsigned int ticks,void * param)192 void tm_rpc_response_list_clean(unsigned int ticks, void *param)
193 {
194 tm_rpc_response_t *ri0 = NULL;
195 tm_rpc_response_t *ri1 = NULL;
196 time_t tnow;
197
198 if(_tm_rpc_response_list == NULL) {
199 return;
200 }
201
202 tnow = time(NULL);
203 lock_get(&_tm_rpc_response_list->rlock);
204 ri1 = _tm_rpc_response_list->rlist;
205 while(ri1!=NULL) {
206 if(ri1->rtime < tnow - TM_RPC_RESPONSE_LIFETIME) {
207 LM_DBG("freeing item [%.*s]\n", ri1->ruid.len, ri1->ruid.s);
208 if(ri0 == NULL) {
209 _tm_rpc_response_list->rlist = ri1->next;
210 shm_free(ri1);
211 ri1 = _tm_rpc_response_list->rlist;
212 } else {
213 ri0->next = ri1->next;
214 shm_free(ri1);
215 ri1 = ri0->next;
216 }
217 } else {
218 ri0 = ri1;
219 ri1 = ri1->next;
220 }
221 }
222 lock_release(&_tm_rpc_response_list->rlock);
223 }
224
225 /** make sure the rpc user created the msg properly.
226 * Make sure that the FIFO user created the message
227 * correctly and fill some extra parameters in function
228 * of the message contents.
229 * @param rpc - rpc handle
230 * @param c - rpc context handle
231 * @param msg - faked sip msg
232 * @param method
233 * @param body
234 * @param fromtag - filled on success (1 if fromtag present, 0 if not)
235 * @param cseq_is - filled on success (1 if cseq present, 0 if not)
236 * @param cseq - filled on success with the cseq number
237 * @callid - filled on success with a pointer to the callid in the msg.
238 * @return -1 on error (and sends the rpc reply), 0 on success
239 */
rpc_uac_check_msg(rpc_t * rpc,void * c,struct sip_msg * msg,str * method,str * body,int * fromtag,int * cseq_is,int * cseq,str * callid)240 static int rpc_uac_check_msg(rpc_t *rpc, void* c,
241 struct sip_msg* msg,
242 str* method, str* body,
243 int* fromtag, int *cseq_is, int* cseq,
244 str* callid)
245 {
246 struct to_body* parsed_from;
247 struct cseq_body *parsed_cseq;
248 int i;
249 char ch;
250
251 if (body->len && !msg->content_type) {
252 rpc->fault(c, 400, "Content-Type missing");
253 goto err;
254 }
255
256 if (body->len && msg->content_length) {
257 rpc->fault(c, 400, "Content-Length disallowed");
258 goto err;
259 }
260
261 if (!msg->to) {
262 rpc->fault(c, 400, "To missing");
263 goto err;
264 }
265
266 if (!msg->from) {
267 rpc->fault(c, 400, "From missing");
268 goto err;
269 }
270
271 /* we also need to know if there is from-tag and add it otherwise */
272 if (parse_from_header(msg) < 0) {
273 rpc->fault(c, 400, "Error in From");
274 goto err;
275 }
276
277 parsed_from = (struct to_body*)msg->from->parsed;
278 *fromtag = parsed_from->tag_value.s && parsed_from->tag_value.len;
279
280 *cseq = 0;
281 if (msg->cseq && (parsed_cseq = get_cseq(msg))) {
282 *cseq_is = 1;
283 for (i = 0; i < parsed_cseq->number.len; i++) {
284 ch = parsed_cseq->number.s[i];
285 if (ch >= '0' && ch <= '9' ) {
286 *cseq = (*cseq) * 10 + ch - '0';
287 } else {
288 LM_DBG("Found non-numerical in CSeq: <%i>='%c'\n",
289 (unsigned int)ch, ch);
290 rpc->fault(c, 400, "Non-numerical CSeq");
291 goto err;
292 }
293 }
294
295 if (parsed_cseq->method.len != method->len ||
296 memcmp(parsed_cseq->method.s, method->s, method->len) !=0 ) {
297 rpc->fault(c, 400, "CSeq method mismatch");
298 goto err;
299 }
300 } else {
301 *cseq_is = 0;
302 }
303
304 if (msg->callid) {
305 callid->s = msg->callid->body.s;
306 callid->len = msg->callid->body.len;
307 } else {
308 callid->s = 0;
309 callid->len = 0;
310 }
311 return 0;
312
313 err:
314 return -1;
315 }
316
317
318 /** construct a "header block" from a header list.
319 *
320 * @return pkg_malloc'ed header block on success (with *l set to its length),
321 * 0 on error.
322 */
get_hfblock(str * uri,struct hdr_field * hf,int proto,struct socket_info * ssock,str * hout)323 static int get_hfblock(str *uri, struct hdr_field *hf, int proto,
324 struct socket_info* ssock, str* hout)
325 {
326 struct str_list sl, *last, *i, *foo;
327 int p, frag_len, total_len;
328 char *begin, *needle, *dst, *ret, *d;
329 str *sock_name, *portname;
330 struct dest_info di;
331
332 hout->s = NULL;
333 hout->len = 0;
334 ret = 0; /* pessimist: assume failure */
335 total_len = 0;
336 last = &sl;
337 last->next = 0;
338 sock_name = 0;
339 portname = 0;
340 if (ssock){
341 si_get_signaling_data(ssock, &sock_name, &portname);
342 }
343
344 for (; hf; hf = hf->next) {
345 if (tm_skip_hf(hf)) continue;
346
347 begin = needle = hf->name.s;
348 p = hf->len;
349
350 /* substitution loop */
351 while(p) {
352 d = q_memchr(needle, SUBST_CHAR, p);
353 if (!d || d + 1 >= needle + p) { /* nothing to substitute */
354 if (!append_str_list(begin, p, &last, &total_len)) goto error;
355 break;
356 } else {
357 frag_len = d - begin;
358 d++; /* d not at the second substitution char */
359 switch(*d) {
360 case SUBST_CHAR: /* double SUBST_CHAR: IP */
361 /* string before substitute */
362 if (!append_str_list(begin, frag_len, &last, &total_len))
363 goto error;
364 /* substitute */
365 if (!sock_name) {
366 if (
367 #ifdef USE_DNS_FAILOVER
368 uri2dst(0, &di, 0, uri, proto)
369 #else
370 uri2dst(&di, 0, uri, proto)
371 #endif /* USE_DNS_FAILOVER */
372 == 0 ){
373 LM_ERR("send_sock failed\n");
374 goto error;
375 }
376 si_get_signaling_data(di.send_sock, &sock_name, &portname);
377 }
378 if (!append_str_list(sock_name->s, sock_name->len, &last,
379 &total_len))
380 goto error;
381 /* inefficient - FIXME --andrei*/
382 if (!append_str_list(":", 1, &last, &total_len)) goto error;
383 if (!append_str_list(portname->s, portname->len, &last,
384 &total_len)) goto error;
385 /* keep going ... */
386 begin = needle = d + 1;
387 p -= frag_len + 2;
388 continue;
389 default:
390 /* no valid substitution char -- keep going */
391 p -= frag_len + 1;
392 needle = d;
393 }
394 } /* possible substitute */
395 } /* substitution loop */
396 LM_DBG("one more hf processed\n");
397 } /* header loop */
398
399 if(total_len==0) {
400 LM_DBG("empty result for headers block\n");
401 return 1;;
402 }
403
404 /* construct a single header block now */
405 ret = pkg_malloc(total_len);
406 if (!ret) {
407 PKG_MEM_ERROR;
408 goto error;
409 }
410 i = sl.next;
411 dst = ret;
412 while(i) {
413 foo = i;
414 i = i->next;
415 memcpy(dst, foo->s.s, foo->s.len);
416 dst += foo->s.len;
417 pkg_free(foo);
418 }
419 hout->len = total_len;
420 hout->s = ret;
421 return 0;
422
423 error:
424 i = sl.next;
425 while(i) {
426 foo = i;
427 i = i->next;
428 pkg_free(foo);
429 }
430 return -1;
431 }
432
433
434 #define RPC_ROUTE_PREFIX "Route: "
435 #define RPC_ROUTE_PREFIX_LEN (sizeof(RPC_ROUTE_PREFIX)-1)
436 #define RPC_ROUTE_SEPARATOR ", "
437 #define RPC_ROUTE_SEPARATOR_LEN (sizeof(RPC_ROUTE_SEPARATOR)-1)
438
439
440 /** internal print routes into rpc reply function.
441 * Prints the dialog routes. It's used internally by
442 * rpx_print_uris (called from rpc_uac_callback()).
443 * @param rpc
444 * @param c - rpc context
445 * @param reply - sip reply
446 */
rpc_print_routes(rpc_t * rpc,void * c,dlg_t * d)447 static void rpc_print_routes(rpc_t* rpc, void* c,
448 dlg_t* d)
449 {
450 rr_t* ptr;
451 int size;
452 char* buf;
453 char* p;
454
455 if (d->hooks.first_route == 0){
456 rpc->add(c, "s", "");
457 return;
458 }
459 size=RPC_ROUTE_PREFIX_LEN;
460 for (ptr=d->hooks.first_route; ptr; ptr=ptr->next)
461 size+=ptr->len+(ptr->next!=0)*RPC_ROUTE_SEPARATOR_LEN;
462 if (d->hooks.last_route)
463 size+=RPC_ROUTE_SEPARATOR_LEN + 1 /* '<' */ +
464 d->hooks.last_route->len +1 /* '>' */;
465
466 buf=pkg_malloc(size+1);
467 if (buf==0){
468 PKG_MEM_ERROR;
469 rpc->add(c, "s", "");
470 return;
471 }
472 p=buf;
473 memcpy(p, RPC_ROUTE_PREFIX, RPC_ROUTE_PREFIX_LEN);
474 p+=RPC_ROUTE_PREFIX_LEN;
475 for (ptr=d->hooks.first_route; ptr; ptr=ptr->next){
476 memcpy(p, ptr->nameaddr.name.s, ptr->len);
477 p+=ptr->len;
478 if (ptr->next!=0){
479 memcpy(p, RPC_ROUTE_SEPARATOR, RPC_ROUTE_SEPARATOR_LEN);
480 p+=RPC_ROUTE_SEPARATOR_LEN;
481 }
482 }
483 if (d->hooks.last_route){
484 memcpy(p, RPC_ROUTE_SEPARATOR, RPC_ROUTE_SEPARATOR_LEN);
485 p+=RPC_ROUTE_SEPARATOR_LEN;
486 *p='<';
487 p++;
488 memcpy(p, d->hooks.last_route->s, d->hooks.last_route->len);
489 p+=d->hooks.last_route->len;
490 *p='>';
491 p++;
492 }
493 *p=0;
494 rpc->add(c, "s", buf);
495 pkg_free(buf);
496 return;
497 }
498
499
500 /** internal print uri into rpc reply function.
501 * Prints the uris into rpc reply. It's used internally by
502 * rpc_uac_callback().
503 * @param rpc
504 * @param c - rpc context
505 * @param reply - sip reply
506 */
rpc_print_uris(rpc_t * rpc,void * c,struct sip_msg * reply)507 static void rpc_print_uris(rpc_t* rpc, void* c, struct sip_msg* reply)
508 {
509 dlg_t* dlg;
510 dlg=shm_malloc(sizeof(dlg_t));
511 if (dlg==0){
512 SHM_MEM_ERROR;
513 return;
514 }
515 memset(dlg, 0, sizeof(dlg_t));
516 if (dlg_response_uac(dlg, reply, TARGET_REFRESH_UNKNOWN) < 0) {
517 LM_ERR("failure while filling dialog structure\n");
518 free_dlg(dlg);
519 return;
520 }
521 if (dlg->state != DLG_CONFIRMED) {
522 free_dlg(dlg);
523 return;
524 }
525 if (dlg->hooks.request_uri->s){
526 rpc->add(c, "S", dlg->hooks.request_uri);
527 }else{
528 rpc->add(c, "s", "");
529 }
530 if (dlg->hooks.next_hop->s) {
531 rpc->add(c, "S", dlg->hooks.next_hop);
532 } else {
533 rpc->add(c, "s", "");
534 }
535 rpc_print_routes(rpc, c, dlg);
536 free_dlg(dlg);
537 return;
538 }
539
540
541
542 /* t_uac callback */
rpc_uac_callback(struct cell * t,int type,struct tmcb_params * ps)543 static void rpc_uac_callback(struct cell* t, int type, struct tmcb_params* ps)
544 {
545 rpc_delayed_ctx_t* dctx;
546 str text;
547 rpc_t* rpc;
548 void* c;
549 int code;
550 str* preason;
551
552 dctx=(rpc_delayed_ctx_t*)*ps->param;
553 *ps->param=0;
554 if (dctx==0){
555 BUG("null delayed reply ctx\n");
556 return;
557 }
558 rpc=&dctx->rpc;
559 c=dctx->reply_ctx;
560 if (ps->rpl==FAKED_REPLY) {
561 text.s=error_text(ps->code);
562 text.len=strlen(text.s);
563 code=ps->code;
564 preason=&text;
565 rpc->add(c, "dS", code, preason);
566 rpc->add(c, "s", ""); /* request uri (rpc_print_uris)*/
567 rpc->add(c, "s", ""); /* next hop (rpc_print_uris) */
568 rpc->add(c, "s", ""); /* dialog routes (rpc_print_routes) */
569 rpc->add(c, "s", ""); /* rest of the reply */
570 }else{
571 code=ps->rpl->first_line.u.reply.statuscode;
572 preason=&ps->rpl->first_line.u.reply.reason;
573 rpc->add(c, "dS", code, preason);
574 rpc_print_uris(rpc, c, ps->rpl);
575 /* print all the reply (from the first header) */
576 rpc->add(c, "s", ps->rpl->headers->name.s);
577 }
578 rpc->delayed_ctx_close(dctx);
579 ps->param=0;
580 }
581
582
583 /* t_uac callback */
rpc_uac_block_callback(struct cell * t,int type,struct tmcb_params * ps)584 static void rpc_uac_block_callback(struct cell* t, int type,
585 struct tmcb_params* ps)
586 {
587 str *ruid;
588 str rtext;
589
590 ruid = (str*)(*ps->param);
591 *ps->param=0;
592 if (ps->rpl==FAKED_REPLY) {
593 rtext.s = error_text(ps->code);
594 rtext.len = strlen(rtext.s);
595 } else {
596 rtext = ps->rpl->first_line.u.reply.reason;
597 }
598 tm_rpc_response_list_add(ruid, ps->code, &rtext);
599 shm_free(ruid);
600 }
601
602
603 /** rpc t_uac version-
604 * It expects the following list of strings as parameters:
605 * method
606 * request_uri
607 * dst_uri (next hop) -- can be empty (either "" or ".", which is still
608 * supported for backwards compatibility with fifo)
609 * send_socket (socket from which the message will be sent)
610 * headers (message headers separated by CRLF, at least From and To
611 * must be present)
612 * body (optional, might be null or completely missing)
613 *
614 * If all the parameters are ok it will call t_uac() using them.
615 * Note: this version will wait for the transaction final reply
616 * only if reply_wait is set to 1. Otherwise the rpc reply will be sent
617 * immediately and it will be success if the parameters were ok and t_uac did
618 * not report any error.
619 * Note: reply waiting (reply_wait==1) is not yet supported.
620 * @param rpc - rpc handle
621 * @param c - rpc current context
622 * @param reply_wait - if 1 do not generate a rpc reply until final response
623 * for the transaction arrives, if 0 immediately send
624 * an rpc reply (see above).
625 */
rpc_t_uac(rpc_t * rpc,void * c,int reply_wait)626 static void rpc_t_uac(rpc_t* rpc, void* c, int reply_wait)
627 {
628 /* rpc params */
629 str method, ruri, nexthop, send_socket, headers, body;
630 /* other internal vars.*/
631 str hfb, callid;
632 struct sip_uri p_uri, pnexthop;
633 struct sip_msg faked_msg;
634 struct socket_info* ssock;
635 str saddr;
636 int sport, sproto;
637 int ret, sip_error, err_ret, fromtag, cseq_is, cseq;
638 char err_buf[MAX_REASON_LEN];
639 dlg_t dlg;
640 uac_req_t uac_req;
641 rpc_delayed_ctx_t* dctx;
642 str *ruid = NULL;
643 tm_rpc_response_t *ritem = NULL;
644 int rcount = 0;
645 void* th = NULL;
646
647 body.s=0;
648 body.len=0;
649 dctx=0;
650 if (reply_wait==1 && (rpc->capabilities == 0 ||
651 !(rpc->capabilities(c) & RPC_DELAYED_REPLY))) {
652 rpc->fault(c, 600, "Reply wait/async mode not supported"
653 " by this rpc transport");
654 return;
655 }
656 ret=rpc->scan(c, "SSSSS*S",
657 &method, &ruri, &nexthop, &send_socket, &headers, &body);
658 if (ret<5 && ! (-ret == 5)){
659 rpc->fault(c, 400, "too few parameters (%d/5)", ret?ret:-ret);
660 return;
661 }
662 /* check and parse parameters */
663 if (method.len==0){
664 rpc->fault(c, 400, "Empty method");
665 return;
666 }
667 if (parse_uri(ruri.s, ruri.len, &p_uri)<0){
668 rpc->fault(c, 400, "Invalid request uri \"%s\"", ruri.s);
669 return;
670 }
671 /* old fifo & unixsock backwards compatibility for nexthop: '.' is still
672 allowed */
673 if (nexthop.len==1 && nexthop.s[0]=='.'){
674 /* empty nextop */
675 nexthop.len=0;
676 nexthop.s=0;
677 }else if (nexthop.len==0){
678 nexthop.s=0;
679 }else if (parse_uri(nexthop.s, nexthop.len, &pnexthop)<0){
680 rpc->fault(c, 400, "Invalid next-hop uri \"%s\"", nexthop.s);
681 return;
682 }
683 /* kamailio backwards compatibility for send_socket: '.' is still
684 allowed for an empty socket */
685 ssock=0;
686 saddr.s=0;
687 saddr.len=0;
688 if (send_socket.len==1 && send_socket.s[0]=='.'){
689 /* empty send socket */
690 send_socket.len=0;
691 }else if (send_socket.len &&
692 (parse_phostport(send_socket.s, &saddr.s, &saddr.len,
693 &sport, &sproto)!=0 ||
694 /* check also if it's not a MH addr. */
695 saddr.len==0 || saddr.s[0]=='(')
696 ){
697 rpc->fault(c, 400, "Invalid send socket \"%s\"", send_socket.s);
698 return;
699 }else if (saddr.len && (ssock=grep_sock_info(&saddr, sport, sproto))==0){
700 rpc->fault(c, 400, "No local socket for \"%s\"", send_socket.s);
701 return;
702 }
703 /* check headers using the SIP parser to look in the header list */
704 memset(&faked_msg, 0, sizeof(struct sip_msg));
705 faked_msg.len=headers.len;
706 faked_msg.buf=faked_msg.unparsed=headers.s;
707 if (parse_headers(&faked_msg, HDR_EOH_F, 0)==-1){
708 rpc->fault(c, 400, "Invalid headers");
709 return;
710 }
711 /* at this moment all the parameters are parsed => more sanity checks */
712 if (rpc_uac_check_msg(rpc, c, &faked_msg, &method, &body, &fromtag,
713 &cseq_is, &cseq, &callid)<0)
714 goto error;
715 if(get_hfblock(nexthop.len? &nexthop: &ruri, faked_msg.headers,
716 PROTO_NONE, ssock, &hfb)<0) {
717 rpc->fault(c, 500, "Failed to build headers block");
718 goto error;
719 }
720 /* proceed to transaction creation */
721 memset(&dlg, 0, sizeof(dlg_t));
722 /* fill call-id if call-id present or else generate a callid */
723 if (callid.s && callid.len) dlg.id.call_id=callid;
724 else generate_callid(&dlg.id.call_id);
725
726 /* We will not fill in dlg->id.rem_tag because
727 * if present it will be printed within To HF
728 */
729
730 /* Generate fromtag if not present */
731 if (!fromtag) {
732 generate_fromtag(&dlg.id.loc_tag, &dlg.id.call_id, &ruri);
733 }
734
735 /* Fill in CSeq */
736 if (cseq_is) dlg.loc_seq.value = cseq;
737 else dlg.loc_seq.value = DEFAULT_CSEQ;
738 dlg.loc_seq.is_set = 1;
739
740 dlg.loc_uri = faked_msg.from->body;
741 dlg.rem_uri = faked_msg.to->body;
742 dlg.rem_target = ruri;
743 dlg.dst_uri = nexthop;
744 dlg.send_sock=ssock;
745
746 memset(&uac_req, 0, sizeof(uac_req));
747 uac_req.method=&method;
748 if(hfb.s!=NULL && hfb.len>0) uac_req.headers=&hfb;
749 uac_req.body=body.len?&body:0;
750 uac_req.dialog=&dlg;
751 if (reply_wait==1){
752 dctx=rpc->delayed_ctx_new(c);
753 if (dctx==0){
754 rpc->fault(c, 500, "internal error: failed to create context");
755 return;
756 }
757 uac_req.cb=rpc_uac_callback;
758 uac_req.cbp=dctx;
759 uac_req.cb_flags=TMCB_LOCAL_COMPLETED;
760 /* switch to dctx, in case adding the callback fails and we
761 want to still send a reply */
762 rpc=&dctx->rpc;
763 c=dctx->reply_ctx;
764 } else if (reply_wait==2) {
765 sruid_next(&_tm_rpc_sruid);
766 uac_req.cb = rpc_uac_block_callback;
767 ruid = shm_str_dup_block(&_tm_rpc_sruid.uid);
768 uac_req.cbp = ruid;
769 uac_req.cb_flags = TMCB_LOCAL_COMPLETED;
770 }
771
772 ret = t_uac(&uac_req);
773
774 if (ret <= 0) {
775 err_ret = err2reason_phrase(ret, &sip_error, err_buf,
776 sizeof(err_buf), "RPC/UAC") ;
777 if (err_ret > 0 ) {
778 rpc->fault(c, sip_error, "%s", err_buf);
779 } else {
780 rpc->fault(c, 500, "RPC/UAC error");
781 }
782 if (dctx) {
783 rpc->delayed_ctx_close(dctx);
784 }
785 if(ruid) {
786 shm_free(ruid);
787 }
788 goto error01;
789 }
790
791 if(reply_wait==2) {
792 while(ritem==NULL && rcount<800) {
793 sleep_us(100000);
794 rcount++;
795 ritem = tm_rpc_response_list_get(&_tm_rpc_sruid.uid);
796 }
797 if(ritem == NULL) {
798 rpc->fault(c, 500, "No response");
799 } else {
800 /* add structure node */
801 if (rpc->add(c, "{", &th) < 0) {
802 rpc->fault(c, 500, "Structure error");
803 } else {
804 if(rpc->struct_add(th, "dS",
805 "code", ritem->rcode,
806 "text", &ritem->rtext)<0) {
807 rpc->fault(c, 500, "Fields error");
808 return;
809 }
810 }
811 shm_free(ritem);
812 }
813 }
814
815 error01:
816 if (hfb.s) pkg_free(hfb.s);
817 error:
818 if (faked_msg.headers) free_hdr_field_lst(faked_msg.headers);
819 }
820
821
822 /** t_uac with no reply waiting.
823 * @see rpc_t_uac.
824 */
rpc_t_uac_start(rpc_t * rpc,void * c)825 void rpc_t_uac_start(rpc_t* rpc, void* c)
826 {
827 rpc_t_uac(rpc, c, 0);
828 }
829
830 /** t_uac with reply waiting.
831 * @see rpc_t_uac.
832 */
rpc_t_uac_wait(rpc_t * rpc,void * c)833 void rpc_t_uac_wait(rpc_t* rpc, void* c)
834 {
835 rpc_t_uac(rpc, c, 1);
836 }
837
838 /** t_uac with blocking for reply waiting.
839 * @see rpc_t_uac.
840 */
rpc_t_uac_wait_block(rpc_t * rpc,void * c)841 void rpc_t_uac_wait_block(rpc_t* rpc, void* c)
842 {
843 rpc_t_uac(rpc, c, 2);
844 }
845
846
t_uac_check_msg(struct sip_msg * msg,str * method,str * body,str * fromtag,int * cseq_is,int * cseq,str * callid)847 static int t_uac_check_msg(struct sip_msg* msg,
848 str* method, str* body,
849 str *fromtag, int *cseq_is, int* cseq,
850 str* callid)
851 {
852 struct to_body* parsed_from;
853 struct cseq_body *parsed_cseq;
854 int i;
855 char ch;
856
857 if (body->len && !msg->content_type) {
858 LM_ERR("Content-Type missing\n");
859 goto err;
860 }
861
862 if (body->len && msg->content_length) {
863 LM_ERR("Content-Length disallowed\n");
864 goto err;
865 }
866
867 if (!msg->to) {
868 LM_ERR("To missing\n");
869 goto err;
870 }
871
872 if (!msg->from) {
873 LM_ERR("From missing\n");
874 goto err;
875 }
876
877 /* we also need to know if there is from-tag and add it otherwise */
878 if (parse_from_header(msg) < 0) {
879 LM_ERR("Error in From\n");
880 goto err;
881 }
882
883 parsed_from = (struct to_body*)msg->from->parsed;
884 if(parsed_from->tag_value.s && parsed_from->tag_value.len) {
885 fromtag->s = parsed_from->tag_value.s;
886 fromtag->len = parsed_from->tag_value.len;
887 } else {
888 fromtag->s = NULL;
889 fromtag->len = 0;
890 }
891
892 *cseq = 0;
893 if (msg->cseq && (parsed_cseq = get_cseq(msg))) {
894 *cseq_is = 1;
895 for (i = 0; i < parsed_cseq->number.len; i++) {
896 ch = parsed_cseq->number.s[i];
897 if (ch >= '0' && ch <= '9' ) {
898 *cseq = (*cseq) * 10 + ch - '0';
899 } else {
900 DBG("check_msg: Found non-numerical in CSeq: <%i>='%c'\n",
901 (unsigned int)ch, ch);
902 LM_ERR("Non-numerical CSeq\n");
903 goto err;
904 }
905 }
906
907 if (parsed_cseq->method.len != method->len ||
908 memcmp(parsed_cseq->method.s, method->s, method->len) !=0 ) {
909 LM_ERR("CSeq method mismatch\n");
910 goto err;
911 }
912 } else {
913 *cseq_is = 0;
914 }
915
916 if (msg->callid) {
917 callid->s = msg->callid->body.s;
918 callid->len = msg->callid->body.len;
919 } else {
920 callid->s = 0;
921 callid->len = 0;
922 }
923 return 0;
924
925 err:
926 return -1;
927 }
928
t_uac_send(str * method,str * ruri,str * nexthop,str * send_socket,str * headers,str * body)929 int t_uac_send(str *method, str *ruri, str *nexthop, str *send_socket,
930 str *headers, str *body)
931 {
932 str hfb, callid;
933 struct sip_uri p_uri, pnexthop;
934 struct sip_msg faked_msg;
935 struct socket_info* ssock;
936 str saddr;
937 int sport, sproto;
938 int ret, cseq_is, cseq;
939 str fromtag;
940 dlg_t dlg;
941 uac_req_t uac_req;
942
943 ret = -1;
944
945 /* check and parse parameters */
946 if (method->len<=0){
947 LM_ERR("Empty method\n");
948 return -1;
949 }
950 if (parse_uri(ruri->s, ruri->len, &p_uri)<0){
951 LM_ERR("Invalid request uri \"%s\"", ruri->s);
952 return -1;
953 }
954 if (nexthop->len==1 && nexthop->s[0]=='.'){
955 /* empty nextop */
956 nexthop->len=0;
957 nexthop->s=0;
958 }else if (nexthop->len==0){
959 nexthop->s=0;
960 }else if (parse_uri(nexthop->s, nexthop->len, &pnexthop)<0){
961 LM_ERR("Invalid next-hop uri \"%s\"", nexthop->s);
962 return -1;
963 }
964 ssock=0;
965 saddr.s=0;
966 saddr.len=0;
967 if (send_socket->len==1 && send_socket->s[0]=='.'){
968 /* empty send socket */
969 send_socket->len=0;
970 }else if (send_socket->len &&
971 (parse_phostport(send_socket->s, &saddr.s, &saddr.len,
972 &sport, &sproto)!=0 ||
973 /* check also if it's not a MH addr. */
974 saddr.len==0 || saddr.s[0]=='(')
975 ){
976 LM_ERR("Invalid send socket \"%s\"", send_socket->s);
977 return -1;
978 }else if (saddr.len && (ssock=grep_sock_info(&saddr, sport, sproto))==0){
979 LM_ERR("No local socket for \"%s\"", send_socket->s);
980 return -1;
981 }
982 /* check headers using the SIP parser to look in the header list */
983 memset(&faked_msg, 0, sizeof(struct sip_msg));
984 faked_msg.len=headers->len;
985 faked_msg.buf=faked_msg.unparsed=headers->s;
986 if (parse_headers(&faked_msg, HDR_EOH_F, 0)==-1){
987 LM_ERR("Invalid headers\n");
988 return -1;
989 }
990 /* at this moment all the parameters are parsed => more sanity checks */
991 if (t_uac_check_msg(&faked_msg, method, body, &fromtag,
992 &cseq_is, &cseq, &callid)<0) {
993 LM_ERR("checking values failed\n");
994 goto error;
995 }
996 if(get_hfblock(nexthop->len? nexthop: ruri, faked_msg.headers,
997 PROTO_NONE, ssock, &hfb)<0) {
998 LM_ERR("failed to get the block of headers\n");
999 goto error;
1000 }
1001 /* proceed to transaction creation */
1002 memset(&dlg, 0, sizeof(dlg_t));
1003 /* fill call-id if call-id present or else generate a callid */
1004 if (callid.s && callid.len) dlg.id.call_id=callid;
1005 else generate_callid(&dlg.id.call_id);
1006
1007 /* We will not fill in dlg->id.rem_tag because
1008 * if present it will be printed within To HF
1009 */
1010
1011 /* Generate fromtag if not present */
1012 if (fromtag.s && fromtag.len) {
1013 dlg.id.loc_tag = fromtag;
1014 } else {
1015 generate_fromtag(&dlg.id.loc_tag, &dlg.id.call_id, ruri);
1016 }
1017
1018 /* Fill in CSeq */
1019 if (cseq_is) dlg.loc_seq.value = cseq;
1020 else dlg.loc_seq.value = DEFAULT_CSEQ;
1021 dlg.loc_seq.is_set = 1;
1022
1023 dlg.loc_uri = get_from(&faked_msg)->uri;
1024 dlg.rem_uri = get_to(&faked_msg)->uri;
1025 if(get_to(&faked_msg)->tag_value.len > 0) {
1026 dlg.id.rem_tag = get_to(&faked_msg)->tag_value;
1027 }
1028 dlg.rem_target = *ruri;
1029 dlg.dst_uri = *nexthop;
1030 dlg.send_sock=ssock;
1031
1032 memset(&uac_req, 0, sizeof(uac_req));
1033 uac_req.method=method;
1034 if(hfb.s!=NULL && hfb.len>0) uac_req.headers=&hfb;
1035 uac_req.body=body->len?body:0;
1036 uac_req.dialog=&dlg;
1037
1038 ret = t_uac(&uac_req);
1039
1040 if (ret <= 0) {
1041 LM_ERR("UAC error\n");
1042 goto error01;
1043 }
1044 error01:
1045 if (hfb.s) pkg_free(hfb.s);
1046 error:
1047 if (faked_msg.headers) free_hdr_field_lst(faked_msg.headers);
1048
1049 return ret;
1050 }
1051
1052 /* vi: set ts=4 sw=4 tw=79:ai:cindent: */
1053