changed c<'9' to c<='9' in cseq parsing.
[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                                 DBG("found non-numerical in CSeq: <%i>='%c'\n",(unsigned int)c,c);
404                                 fifo_uac_error(resp, 400, "non-nummerical CSeq");
405                                 return -6;
406                         }
407                 }
408                 
409                 if (parsed_cseq->method.len != method->len 
410                     || memcmp(parsed_cseq->method.s, method->s, method->len) !=0 ) {
411                         fifo_uac_error(resp, 400, "CSeq method mismatch");
412                         return -7;
413                 }
414         } else {
415                 *cseq_is = 0;
416         }
417
418         if (msg->callid) {
419                 callid->s = msg->callid->body.s;
420                 callid->len = msg->callid->body.len;
421         } else {
422                 callid->s = 0;
423                 callid->len = 0;
424         }
425
426         return 0;
427 }
428
429
430 #define FIFO_ROUTE_PREFIX "Route: "
431 #define FIFO_ROUTE_SEPARATOR ", "
432
433 static inline void print_routes(FILE* out, dlg_t* _d)
434 {
435         rr_t* ptr;
436
437         ptr = _d->hooks.first_route;
438
439         if (ptr) {
440                 fprintf(out, FIFO_ROUTE_PREFIX);
441         } else {
442                 fprintf(out, ".\n");
443                 return;
444         }
445
446         while(ptr) {
447                 fprintf(out, "%.*s", ptr->len, ptr->nameaddr.name.s);
448
449                 ptr = ptr->next;
450                 if (ptr) {
451                         fprintf(out, FIFO_ROUTE_SEPARATOR);
452                 }
453         } 
454
455         if (_d->hooks.last_route) {
456                 fprintf(out, FIFO_ROUTE_SEPARATOR "<");
457                 fprintf(out, "%.*s", _d->hooks.last_route->len, _d->hooks.last_route->s);
458                 fprintf(out, ">");
459         }
460
461         if (_d->hooks.first_route) {
462                 fprintf(out, CRLF);
463         }
464 }
465
466
467 static inline int print_uris(FILE* out, struct sip_msg* reply)
468 {
469         dlg_t* dlg;
470         
471         dlg = (dlg_t*)shm_malloc(sizeof(dlg_t));
472         if (!dlg) {
473                 LOG(L_ERR, "print_routes(): No memory left\n");
474                 return -1;
475         }
476
477         memset(dlg, 0, sizeof(dlg_t));
478         if (dlg_response_uac(dlg, reply) < 0) {
479                 LOG(L_ERR, "print_routes(): Error while creating dialog structure\n");
480                 return -2;
481         }
482
483         if (dlg->state != DLG_CONFIRMED) {
484                 fprintf(out, ".\n.\n.\n");
485                 free_dlg(dlg);
486                 return 0;
487         }
488
489         if (dlg->hooks.request_uri->s) {        
490                 fprintf(out, "%.*s\n", dlg->hooks.request_uri->len, dlg->hooks.request_uri->s);
491         } else {
492                 fprintf(out, ".\n");
493         }
494         if (dlg->hooks.next_hop->s) {
495                 fprintf(out, "%.*s\n", dlg->hooks.next_hop->len, dlg->hooks.next_hop->s);
496         } else {
497                 fprintf(out, ".\n");
498         }
499         print_routes(out, dlg);
500         free_dlg(dlg);
501         return 0;
502 }
503
504
505 static void fifo_callback(struct cell *t, struct sip_msg *reply,
506                           int code, void *param)
507 {
508         
509         char *filename;
510         FILE* f;
511         str text;
512
513         DBG("!!!!! ref_counter: %d\n", t->ref_count);
514
515         DBG("DEBUG: fifo UAC completed with status %d\n", code);
516         if (!t->cbp) {
517                 LOG(L_INFO, "INFO: fifo UAC completed with status %d\n", code);
518                 return;
519         }
520
521         filename=(char *)(t->cbp);
522         if (reply==FAKED_REPLY) {
523                 get_reply_status(&text,reply,code);
524                 if (text.s==0) {
525                         LOG(L_ERR, "ERROR: fifo_callback: get_reply_status failed\n");
526                         fifo_reply(filename, "500 fifo_callback: get_reply_status failed\n");
527                         return;
528                 }
529                 fifo_reply(filename, "%.*s\n", text.len, text.s );
530                 pkg_free(text.s);
531         } else {
532                 text.s=reply->first_line.u.reply.reason.s;
533                 text.len=reply->first_line.u.reply.reason.len;
534
535                 f = fopen(filename, "wt");
536                 if (!f) return;
537                 fprintf(f, "%d %.*s\n", reply->first_line.u.reply.statuscode, text.len, text.s);
538                 print_uris(f, reply);
539                 fprintf(f, "%s\n", reply->headers->name.s);
540                 fclose(f);
541         }
542         DBG("DEBUG: fifo_callback sucesssfuly completed\n");
543 }       
544
545
546 int fifo_uac(FILE *stream, char *response_file)
547 {
548         str method, ruri, nexthop, headers, body, hfb, callid;
549         struct sip_uri puri, pnexthop;
550         struct sip_msg faked_msg;
551         int ret, sip_error, err_ret;
552         int fromtag, cseq_is, cseq;
553         struct cb_data;
554         char err_buf[MAX_REASON_LEN];
555         char* shm_file;
556         dlg_t dlg;
557
558         if (fifo_get_method(stream, response_file, &method) < 0) return 1;
559         if (fifo_get_ruri(stream, response_file, &ruri, &puri) < 0) return 1;
560         if (fifo_get_nexthop(stream, response_file, &nexthop, &pnexthop) < 0) return 1;
561         if (fifo_get_headers(stream, response_file, &headers) < 0) return 1;
562
563         /* use SIP parser to look at what is in the FIFO request */
564         memset(&faked_msg, 0, sizeof(struct sip_msg));
565         faked_msg.len = headers.len; 
566         faked_msg.buf = faked_msg.unparsed = headers.s;
567         if (parse_headers(&faked_msg, HDR_EOH, 0) == -1 ) {
568                 DBG("DEBUG: fifo_uac: parse_headers failed\n");
569                 fifo_uac_error(response_file, 400, "HFs unparseable");
570                 goto error;
571         }
572         DBG("DEBUG: fifo_uac: parse_headers succeeded\n");
573
574         if (fifo_get_body(stream, response_file, &body) < 0) goto error;
575         
576              /* at this moment, we collected all the things we got, let's
577               * verify user has not forgotten something */
578         if (fifo_check_msg(&faked_msg, &method, response_file, &body, &fromtag, 
579                            &cseq_is, &cseq, &callid) < 0) goto error;
580
581         hfb.s = get_hfblock(nexthop.len ? &nexthop : &ruri, 
582                             faked_msg.headers, &hfb.len, PROTO_UDP);
583         if (!hfb.s) {
584                 fifo_uac_error(response_file, 500, "no mem for hf block");
585                 goto error;
586         }
587
588         DBG("DEBUG: fifo_uac: EoL -- proceeding to transaction creation\n");
589
590         memset(&dlg, 0, sizeof(dlg_t));
591              /* Fill in Call-ID, use given Call-ID if
592               * present and generate it if not present
593               */
594         if (callid.s && callid.len) dlg.id.call_id = callid;
595         else generate_callid(&dlg.id.call_id);
596         
597              /* We will not fill in dlg->id.rem_tag because
598               * if present it will be printed within To HF
599               */
600         
601              /* Generate fromtag if not present */
602         if (!fromtag) {
603                 generate_fromtag(&dlg.id.loc_tag, &dlg.id.call_id);
604         }
605
606              /* Fill in CSeq */
607         if (cseq_is) dlg.loc_seq.value = cseq;
608         else dlg.loc_seq.value = DEFAULT_CSEQ;
609         dlg.loc_seq.is_set = 1;
610
611         dlg.loc_uri = faked_msg.from->body;
612         dlg.rem_uri = faked_msg.to->body;
613         dlg.hooks.request_uri = &ruri;
614         dlg.hooks.next_hop = (nexthop.len ? &nexthop : &ruri);
615
616         print_dlg(stderr, &dlg);
617
618         /* we got it all, initiate transaction now! */
619         if (fifo_cbp(&shm_file, response_file) < 0) goto error01;
620
621         ret = t_uac(&method, &hfb, &body, &dlg, fifo_callback, shm_file);
622
623         if (ret <= 0) {
624                 err_ret = err2reason_phrase(ret, &sip_error, err_buf,
625                                             sizeof(err_buf), "FIFO/UAC") ;
626                 if (err_ret > 0 )
627                 {
628                         fifo_uac_error(response_file, sip_error, err_buf);
629                 } else {
630                         fifo_uac_error(response_file, 500, "FIFO/UAC error");
631                 }
632         }
633         
634  error01:
635         pkg_free(hfb.s);
636         
637  error:
638              /* free_sip_msg(&faked_msg); */
639         if (faked_msg.headers) free_hdr_field_lst(faked_msg.headers);
640         return 1;
641 }