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