f1db1677d1797a856684c6128125039544b80eb4
[sip-router] / modules / tm / uac_fifo.c
1 /*
2  * $Id$
3  *
4  * Copyright (C) 2001-2003 Fhg Fokus
5  *
6  * This file is part of ser, a free SIP server.
7  *
8  * ser 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  * For a license to use the ser software under conditions
14  * other than those described here, or to purchase support for this
15  * software, please contact iptel.org by e-mail at the following addresses:
16  *    info@iptel.org
17  *
18  * ser is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License 
24  * along with this program; if not, write to the Free Software 
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26  *
27  * History:
28  * --------
29  *  2003-12-03 : fifo_callback() updated for changes in tm callbacks (bogdan)
30  *  2004-02-11: fix: TM callback writes to fifo changed to non-blocking (jiri)
31  */
32
33 #include <string.h>
34 #include "../../mem/shm_mem.h"
35 #include "../../mem/mem.h"
36 #include "../../dprint.h"
37 #include "../../fifo_server.h"
38 #include "../../str.h"
39 #include "../../parser/msg_parser.h"
40 #include "../../parser/parse_from.h"
41 #include "../../parser/parse_uri.h"
42 #include "../../ip_addr.h"
43 #include "config.h"
44 #include "ut.h"
45 #include "uac.h"
46 #include "dlg.h"
47 #include "callid.h"
48 #include "h_table.h"
49 #include "uac_fifo.h"
50
51
52 /*
53  * Callback data structure
54  */
55 struct cb_data {
56         dlg_t* dialog;
57         char filename[1];
58 };
59
60
61 struct str_list {
62         str s;
63         struct str_list *next;
64 };
65
66
67 #define skip_hf(_hf) (             \
68     ((_hf)->type == HDR_FROM)   || \
69     ((_hf)->type == HDR_TO)     || \
70     ((_hf)->type == HDR_CALLID) || \
71     ((_hf)->type == HDR_CSEQ)      \
72 )
73
74
75 /*
76  * Report an error to syslog and FIFO output file
77  */
78 static inline void fifo_uac_error(char *reply_fifo, int code, char *msg)
79 {
80         LOG(L_ERR, "ERROR: fifo_uac: %s\n", msg ); 
81         fifo_reply(reply_fifo, "%d fifo_uac: %s", code, msg);
82 }
83
84
85 /*
86  * Get the Request URI from the FIFO stream and parse it
87  */
88 static inline int fifo_get_ruri(FILE* stream, char* response_file, str* ruri, struct sip_uri* puri)
89 {
90         static char ruri_buf[MAX_URI_SIZE];
91
92         if (!read_line(ruri_buf, MAX_URI_SIZE, stream, &ruri->len) || !ruri->len) {
93                 fifo_uac_error(response_file, 400, "ruri expected");
94                 return -1;
95         }
96         
97         if (parse_uri(ruri_buf, ruri->len, puri) < 0 ) {
98                 fifo_uac_error(response_file, 400, "ruri invalid\n");
99                 return -2;
100         }
101         ruri->s = ruri_buf;
102         DBG("DEBUG: fifo_get_ruri: '%.*s'\n", ruri->len, ruri->s);
103         return 0;
104 }
105
106
107 /*
108  * Get and parse next hop URI
109  */
110 static inline int fifo_get_nexthop(FILE* stream, char* response_file, str* nexthop, struct sip_uri* pnexthop)
111 {
112         static char nexthop_buf[MAX_URI_SIZE];
113
114         if (!read_line(nexthop_buf, MAX_URI_SIZE, stream, &nexthop->len) || !nexthop->len) {
115                 fifo_uac_error(response_file, 400, "next hop address expected\n");
116                 return -1;
117         }
118
119         if (nexthop->len == 1 && nexthop_buf[0] == '.' ) {
120                 DBG("DEBUG: fifo_get_nexthop: next hop empty\n");
121                 nexthop->s = 0; 
122                 nexthop->len = 0;
123         } else if (parse_uri(nexthop_buf, nexthop->len, pnexthop) < 0 ) {
124                 fifo_uac_error(response_file, 400, "next hop uri invalid\n");
125                 return -2;
126         } else {
127                 nexthop->s = nexthop_buf;
128                 DBG("DEBUG: fifo_get_nexthop: hop: '%.*s'\n", nexthop->len, nexthop->s);
129         }
130
131         return 0;
132 }
133
134
135 /*
136  * Get method name from FIFO stream
137  */
138 static inline int fifo_get_method(FILE* stream, char* response_file, str* method)
139 {
140         static char method_buf[MAX_METHOD];
141
142         if (!read_line(method_buf, MAX_METHOD, stream, &method->len) || !method->len) {
143                      /* line breaking must have failed -- consume the rest
144                         and proceed to a new request
145                      */
146                 fifo_uac_error(response_file, 400, "method expected");
147                 return -1;
148         }
149         method->s = method_buf;
150         DBG("fifo_get_method: method: '%.*s'\n", method->len, method->s);
151         return 0;
152 }
153
154
155 /*
156  * Get message body from FIFO stream
157  */
158 static inline int fifo_get_body(FILE* stream, char* response_file, str* body)
159 {
160         static char body_buf[MAX_BODY];
161
162         if (!read_body(body_buf, MAX_BODY, stream, &body->len)) {
163                 fifo_uac_error(response_file, 400, "body expected");
164                 return -1;
165         }
166         body->s = body_buf;
167         DBG("fifo_get_body: body: %.*s\n", body->len,  body->s);
168         return 0;
169 }
170
171
172 /*
173  * Get message headers from FIFO stream
174  */
175 static inline int fifo_get_headers(FILE* stream, char* response_file, str* headers)
176 {
177         static char headers_buf[MAX_HEADER];
178
179              /* now read and parse header fields */
180         if (!read_line_set(headers_buf, MAX_HEADER, stream, &headers->len) || !headers->len) {
181                 fifo_uac_error(response_file, 400, "HFs expected");
182                 return -1;
183         }
184         headers->s = headers_buf;
185         DBG("fifo_get_headers: headers: %.*s\n", headers->len, headers->s);
186         return 0;
187 }
188
189
190 /*
191  * Create shm_copy of filename
192  */
193 static inline int fifo_cbp(char** shm_file, char* response_file)
194 {
195         int fn_len;
196
197         if (response_file) {
198                 fn_len = strlen(response_file) + 1;
199                 *shm_file = shm_malloc(fn_len);
200                 if (!*shm_file) {
201                         fifo_uac_error(response_file, 500, "no shmem");
202                         return -1;
203                 }
204                 memcpy(*shm_file, response_file, fn_len);
205         } else {
206                 *shm_file = 0;
207         }
208         return 0;
209 }
210
211
212 static inline struct str_list *new_str(char *s, int len, struct str_list **last, int *total)
213 {
214         struct str_list *new;
215         new=pkg_malloc(sizeof(struct str_list));
216         if (!new) {
217                 LOG(L_ERR, "ERROR: get_hfblock: not enough mem\n");
218                 return 0;
219         }
220         new->s.s=s;
221         new->s.len=len;
222         new->next=0;
223
224         (*last)->next=new;
225         *last=new;
226         *total+=len;
227
228         return new;
229 }
230
231
232 static char *get_hfblock(str *uri, struct hdr_field *hf, int *l, int proto) 
233 {
234         struct str_list sl, *last, *new, *i, *foo;
235         int hf_avail, frag_len, total_len;
236         char *begin, *needle, *dst, *ret, *d;
237         str *sock_name, *portname;
238         union sockaddr_union to_su;
239         struct socket_info* send_sock;
240
241         ret=0; /* pesimist: assume failure */
242         total_len=0;
243         last=&sl;
244         last->next=0;
245         portname=sock_name=0;
246
247         for (; hf; hf=hf->next) {
248                 if (skip_hf(hf)) continue;
249
250                 begin=needle=hf->name.s; 
251                 hf_avail=hf->len;
252
253                 /* substitution loop */
254                 while(hf_avail) {
255                         d=memchr(needle, SUBST_CHAR, hf_avail);
256                         if (!d || d+1>=needle+hf_avail) { /* nothing to substitute */
257                                 new=new_str(begin, hf_avail, &last, &total_len); 
258                                 if (!new) goto error;
259                                 break;
260                         } else {
261                                 frag_len=d-begin;
262                                 d++; /* d not at the second substitution char */
263                                 switch(*d) {
264                                         case SUBST_CHAR:        /* double SUBST_CHAR: IP */
265                                                 /* string before substitute */
266                                                 new=new_str(begin, frag_len, &last, &total_len); 
267                                                 if (!new) goto error;
268                                                 /* substitute */
269                                                 if (!sock_name) {
270                                                         send_sock=uri2sock( uri, &to_su, proto );
271                                                         if (!send_sock) {
272                                                                 LOG(L_ERR, "ERROR: get_hf_block: send_sock failed\n");
273                                                                 goto error;
274                                                         }
275                                                         sock_name=&send_sock->address_str;
276                                                         portname=&send_sock->port_no_str;
277                                                 }
278                                                 new=new_str(sock_name->s, sock_name->len,
279                                                                 &last, &total_len );
280                                                 if (!new) goto error;
281                                                 /* inefficient - FIXME --andrei*/
282                                                 new=new_str(":", 1, &last, &total_len);
283                                                 if (!new) goto error;
284                                                 new=new_str(portname->s, portname->len,
285                                                                 &last, &total_len );
286                                                 if (!new) goto error;
287                                                 /* keep going ... */
288                                                 begin=needle=d+1;hf_avail-=frag_len+2;
289                                                 continue;
290                                         default:
291                                                 /* no valid substitution char -- keep going */
292                                                 hf_avail-=frag_len+1;
293                                                 needle=d;
294                                 }
295                         } /* possible substitute */
296                 } /* substitution loop */
297                 /* proceed to next header */
298                 /* new=new_str(CRLF, CRLF_LEN, &last, &total_len );
299                 if (!new) goto error; */
300                 DBG("DEBUG: get_hf_block: one more hf processed\n");
301         } /* header loop */
302
303
304         /* construct a single header block now */
305         ret=pkg_malloc(total_len);
306         if (!ret) {
307                 LOG(L_ERR, "ERROR: get_hf_block no pkg mem for hf block\n");
308                 goto error;
309         }
310         i=sl.next;
311         dst=ret;
312         while(i) {
313                 foo=i;
314                 i=i->next;
315                 memcpy(dst, foo->s.s, foo->s.len);
316                 dst+=foo->s.len;
317                 pkg_free(foo);
318         }
319         *l=total_len;
320         return ret;
321
322 error:
323         i=sl.next;
324         while(i) {
325                 foo=i;
326                 i=i->next;
327                 pkg_free(foo);
328         }
329         *l=0;
330         return 0;
331 }
332
333
334 /* syntax:
335
336         :t_uac:[file] EOL
337         method EOL
338         r-uri EOL 
339         dst EOL                                 // ("." if no outbound server used)
340                                                         // must be used with dialogs/lr
341         <EOL separated HFs>+    // From and To must be present at least;
342                                                         // dialog-apps must include tag in From
343                                                         // (an ephemeral is appended otherwise)
344                                                         // and supply CSeq/CallId
345         .[EOL]
346         [body] 
347         .EOL
348
349
350         there is also the possibility to have server placed its
351     hostname:portnumber in header fields -- just put double
352         exclamation mark in any of the optional header fields
353         (i.e., any but From/To/CallID,CSeq), they will be 
354         substituted hn:pn
355
356 Example:
357
358 sc fifo t_uac_dlg MESSAGE sip:joe@192.168.2.1 \
359         . \ # no outbound proxy
360         'From:sender@iptel.org;tagd=123'  \ # no to-tag -> ephemeral
361         'To:sender@iptel.org' \
362         'Foo: sip:user@!! '  \ # expansion here
363         'CSEQ: 11 MESSAGE   ' \
364         . \ # EoH
365         .       # empty body
366 ---
367 U 192.168.2.16:5060 -> 192.168.2.1:5060
368 MESSAGE sip:joe@192.168.2.1 SIP/2.0..
369 Via: SIP/2.0/UDP 192.168.2.16;branch=z9hG4bK760c.922ea6a1.0..
370 To: sender@iptel.org..
371 From: sender@iptel.org;tagd=123;tag=5405e669bc2980663aed2624dc31396f-fa77..
372 CSeq: 11 MESSAGE..
373 Call-ID: e863bf56-22255@192.168.2.16..
374 Content-Length: 0..
375 User-Agent: Sip EXpress router (0.8.11pre4-tcp1-locking (i386/linux))..
376 Foo: sip:user@192.168.2.16:5060..
377 ..
378
379
380 */
381
382
383 /*
384  * Make sure that the FIFO user created the message
385  * correctly
386  */
387 static inline int fifo_check_msg(struct sip_msg* msg, str* method, char* resp, str* body, 
388                                  int* fromtag, int *cseq_is, int* cseq, str* callid)
389 {
390         struct to_body* parsed_from;
391         struct cseq_body *parsed_cseq;
392         int i;
393         char c;
394
395         if (body->len && !msg->content_type) {
396                 fifo_uac_error(resp, 400, "Content-Type missing");
397                 return -1;
398         }
399
400         if (body->len && msg->content_length) {
401                 fifo_uac_error(resp, 400, "Content-Length disallowed");
402                 return -2;
403         }
404
405         if (!msg->to) {
406                 fifo_uac_error(resp, 400, "To missing");
407                 return -3;
408         }
409
410         if (!msg->from) {
411                 fifo_uac_error(resp, 400, "From missing");
412                 return -4;
413         }
414
415              /* we also need to know if there is from-tag and add it otherwise */
416         if (parse_from_header(msg) < 0) {
417                 fifo_uac_error(resp, 400, "Error in From");
418                 return -5;
419         }
420
421         parsed_from = (struct to_body*)msg->from->parsed;
422         *fromtag = parsed_from->tag_value.s && parsed_from->tag_value.len;
423
424         *cseq = 0;
425         if (msg->cseq && (parsed_cseq = get_cseq(msg))) {
426                 *cseq_is = 1;
427                 for (i = 0; i < parsed_cseq->number.len; i++) {
428                         c = parsed_cseq->number.s[i];
429                         if (c >= '0' && c <= '9' ) *cseq = (*cseq) * 10 + c - '0';
430                         else {
431                                 DBG("found non-numerical in CSeq: <%i>='%c'\n",(unsigned int)c,c);
432                                 fifo_uac_error(resp, 400, "non-nummerical CSeq");
433                                 return -6;
434                         }
435                 }
436                 
437                 if (parsed_cseq->method.len != method->len 
438                     || memcmp(parsed_cseq->method.s, method->s, method->len) !=0 ) {
439                         fifo_uac_error(resp, 400, "CSeq method mismatch");
440                         return -7;
441                 }
442         } else {
443                 *cseq_is = 0;
444         }
445
446         if (msg->callid) {
447                 callid->s = msg->callid->body.s;
448                 callid->len = msg->callid->body.len;
449         } else {
450                 callid->s = 0;
451                 callid->len = 0;
452         }
453
454         return 0;
455 }
456
457
458 #define FIFO_ROUTE_PREFIX "Route: "
459 #define FIFO_ROUTE_SEPARATOR ", "
460
461 static inline void print_routes(FILE* out, dlg_t* _d)
462 {
463         rr_t* ptr;
464
465         ptr = _d->hooks.first_route;
466
467         if (ptr) {
468                 fprintf(out, FIFO_ROUTE_PREFIX);
469         } else {
470                 fprintf(out, ".\n");
471                 return;
472         }
473
474         while(ptr) {
475                 fprintf(out, "%.*s", ptr->len, ptr->nameaddr.name.s);
476
477                 ptr = ptr->next;
478                 if (ptr) {
479                         fprintf(out, FIFO_ROUTE_SEPARATOR);
480                 }
481         } 
482
483         if (_d->hooks.last_route) {
484                 fprintf(out, FIFO_ROUTE_SEPARATOR "<");
485                 fprintf(out, "%.*s", _d->hooks.last_route->len, _d->hooks.last_route->s);
486                 fprintf(out, ">");
487         }
488
489         if (_d->hooks.first_route) {
490                 fprintf(out, CRLF);
491         }
492 }
493
494
495 static inline int print_uris(FILE* out, struct sip_msg* reply)
496 {
497         dlg_t* dlg;
498         
499         dlg = (dlg_t*)shm_malloc(sizeof(dlg_t));
500         if (!dlg) {
501                 LOG(L_ERR, "print_routes(): No memory left\n");
502                 return -1;
503         }
504
505         memset(dlg, 0, sizeof(dlg_t));
506         if (dlg_response_uac(dlg, reply) < 0) {
507                 LOG(L_ERR, "print_routes(): Error while creating dialog structure\n");
508                 free_dlg(dlg);
509                 return -2;
510         }
511
512         if (dlg->state != DLG_CONFIRMED) {
513                 fprintf(out, ".\n.\n.\n");
514                 free_dlg(dlg);
515                 return 0;
516         }
517
518         if (dlg->hooks.request_uri->s) {        
519                 fprintf(out, "%.*s\n", dlg->hooks.request_uri->len, dlg->hooks.request_uri->s);
520         } else {
521                 fprintf(out, ".\n");
522         }
523         if (dlg->hooks.next_hop->s) {
524                 fprintf(out, "%.*s\n", dlg->hooks.next_hop->len, dlg->hooks.next_hop->s);
525         } else {
526                 fprintf(out, ".\n");
527         }
528         print_routes(out, dlg);
529         free_dlg(dlg);
530         return 0;
531 }
532
533
534 static void fifo_callback( struct cell *t, int type, struct tmcb_params *ps )
535 {
536         
537         char *filename;
538         FILE* f;
539         str text;
540
541         DBG("!!!!! ref_counter: %d\n", t->ref_count);
542
543         DBG("DEBUG: fifo UAC completed with status %d\n", ps->code);
544         if (!*ps->param) {
545                 LOG(L_INFO, "INFO: fifo UAC completed with status %d\n", ps->code);
546                 return;
547         }
548
549         filename=(char *)(*ps->param);
550         if (ps->rpl==FAKED_REPLY) {
551                 get_reply_status( &text, ps->rpl, ps->code);
552                 if (text.s==0) {
553                         LOG(L_ERR, "ERROR: fifo_callback: get_reply_status failed\n");
554                         fifo_reply( filename,
555                                 "500 fifo_callback: get_reply_status failed\n");
556                         goto done;
557                 }
558                 fifo_reply(filename, "%.*s\n", text.len, text.s );
559                 pkg_free(text.s);
560         } else {
561                 text.s = ps->rpl->first_line.u.reply.reason.s;
562                 text.len = ps->rpl->first_line.u.reply.reason.len;
563
564                 f = open_reply_pipe(filename);
565                 if (!f) return;
566                 fprintf(f, "%d %.*s\n", ps->rpl->first_line.u.reply.statuscode, text.len, text.s);
567                 print_uris(f, ps->rpl);
568                 fprintf(f, "%s\n", ps->rpl->headers->name.s);
569                 fclose(f);
570         }
571         DBG("DEBUG: fifo_callback sucesssfuly completed\n");
572 done:
573         shm_free(filename);
574 }
575
576
577 int fifo_uac(FILE *stream, char *response_file)
578 {
579         str method, ruri, nexthop, headers, body, hfb, callid;
580         struct sip_uri puri, pnexthop;
581         struct sip_msg faked_msg;
582         int ret, sip_error, err_ret;
583         int fromtag, cseq_is, cseq;
584         struct cb_data;
585         char err_buf[MAX_REASON_LEN];
586         char* shm_file;
587         dlg_t dlg;
588
589         if (fifo_get_method(stream, response_file, &method) < 0) return 1;
590         if (fifo_get_ruri(stream, response_file, &ruri, &puri) < 0) return 1;
591         if (fifo_get_nexthop(stream, response_file, &nexthop, &pnexthop) < 0) return 1;
592         if (fifo_get_headers(stream, response_file, &headers) < 0) return 1;
593
594         /* use SIP parser to look at what is in the FIFO request */
595         memset(&faked_msg, 0, sizeof(struct sip_msg));
596         faked_msg.len = headers.len; 
597         faked_msg.buf = faked_msg.unparsed = headers.s;
598         if (parse_headers(&faked_msg, HDR_EOH, 0) == -1 ) {
599                 DBG("DEBUG: fifo_uac: parse_headers failed\n");
600                 fifo_uac_error(response_file, 400, "HFs unparseable");
601                 goto error;
602         }
603         DBG("DEBUG: fifo_uac: parse_headers succeeded\n");
604
605         if (fifo_get_body(stream, response_file, &body) < 0) goto error;
606         
607              /* at this moment, we collected all the things we got, let's
608               * verify user has not forgotten something */
609         if (fifo_check_msg(&faked_msg, &method, response_file, &body, &fromtag, 
610                            &cseq_is, &cseq, &callid) < 0) goto error;
611
612         hfb.s = get_hfblock(nexthop.len ? &nexthop : &ruri, 
613                             faked_msg.headers, &hfb.len, PROTO_UDP);
614         if (!hfb.s) {
615                 fifo_uac_error(response_file, 500, "no mem for hf block");
616                 goto error;
617         }
618
619         DBG("DEBUG: fifo_uac: EoL -- proceeding to transaction creation\n");
620
621         memset(&dlg, 0, sizeof(dlg_t));
622              /* Fill in Call-ID, use given Call-ID if
623               * present and generate it if not present
624               */
625         if (callid.s && callid.len) dlg.id.call_id = callid;
626         else generate_callid(&dlg.id.call_id);
627         
628              /* We will not fill in dlg->id.rem_tag because
629               * if present it will be printed within To HF
630               */
631         
632              /* Generate fromtag if not present */
633         if (!fromtag) {
634                 generate_fromtag(&dlg.id.loc_tag, &dlg.id.call_id);
635         }
636
637              /* Fill in CSeq */
638         if (cseq_is) dlg.loc_seq.value = cseq;
639         else dlg.loc_seq.value = DEFAULT_CSEQ;
640         dlg.loc_seq.is_set = 1;
641
642         dlg.loc_uri = faked_msg.from->body;
643         dlg.rem_uri = faked_msg.to->body;
644         dlg.hooks.request_uri = &ruri;
645         dlg.hooks.next_hop = (nexthop.len ? &nexthop : &ruri);
646
647 #ifdef XL_DEBUG
648         print_dlg(stderr, &dlg);
649 #endif
650
651         /* we got it all, initiate transaction now! */
652         if (fifo_cbp(&shm_file, response_file) < 0) goto error01;
653
654         ret = t_uac(&method, &hfb, &body, &dlg, fifo_callback, shm_file);
655
656         if (ret <= 0) {
657                 err_ret = err2reason_phrase(ret, &sip_error, err_buf,
658                         sizeof(err_buf), "FIFO/UAC") ;
659                 if (err_ret > 0 )
660                 {
661                         fifo_uac_error(response_file, sip_error, err_buf);
662                 } else {
663                         fifo_uac_error(response_file, 500, "FIFO/UAC error");
664                 }
665         }
666         
667  error01:
668         pkg_free(hfb.s);
669         
670  error:
671              /* free_sip_msg(&faked_msg); */
672         if (faked_msg.headers) free_hdr_field_lst(faked_msg.headers);
673         return 1;
674 }