e8ba6f1b9c65495c2e68270b04027f8f5b6978af
[sip-router] / modules / tm / t_fifo.c
1 /*
2  * $Id$
3  *
4  * transaction maintenance functions
5  *
6  * Copyright (C) 2001-2003 FhG Fokus
7  *
8  * This file is part of ser, a free SIP server.
9  *
10  * ser is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version
14  *
15  * For a license to use the ser software under conditions
16  * other than those described here, or to purchase support for this
17  * software, please contact iptel.org by e-mail at the following addresses:
18  *    info@iptel.org
19  *
20  * ser is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License 
26  * along with this program; if not, write to the Free Software 
27  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28  *
29  * History:
30  * -------
31  *  2004-02-23  created by splitting it from t_funcs (bogdan)
32  *  2004-11-15  t_write_xxx can print whatever avp/hdr
33  */
34
35
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
39 #include <errno.h>
40 #include <string.h>
41 #include <sys/uio.h>
42 #include <unistd.h>
43 #include <fcntl.h>
44 #include <sys/un.h>
45 #include <ctype.h>
46 #include <string.h>
47
48 #include "../../str.h"
49 #include "../../ut.h"
50 #include "../../dprint.h"
51 #include "../../mem/mem.h"
52 #include "../../usr_avp.h"
53 #include "../../parser/parser_f.h"
54 #include "../../parser/parse_from.h"
55 #include "../../parser/parse_rr.h"
56 #include "../../parser/parse_nameaddr.h"
57 #include "../../parser/parse_hname2.h"
58 #include "../../parser/contact/parse_contact.h"
59 #include "../../tsend.h"
60 #include "t_lookup.h"
61 #include "t_fwd.h"
62 #include "t_fifo.h"
63
64
65 /* AF_LOCAL is not defined on solaris */
66 #if !defined(AF_LOCAL)
67 #define AF_LOCAL AF_UNIX
68 #endif
69 #if !defined(PF_LOCAL)
70 #define PF_LOCAL PF_UNIX
71 #endif
72
73
74 /* solaris doesn't have SUN_LEN */
75 #ifndef SUN_LEN
76 #define SUN_LEN(sa)      ( strlen((sa)->sun_path) + \
77                                          (size_t)(((struct sockaddr_un*)0)->sun_path) )
78 #endif
79
80
81
82
83
84
85 int tm_unix_tx_timeout = 2; /* Default is 2 seconds */
86
87 #define TWRITE_PARAMS          20
88 #define TWRITE_VERSION_S       "0.3"
89 #define TWRITE_VERSION_LEN     (sizeof(TWRITE_VERSION_S)-1)
90
91 #define eol_line_s(_i_)        ( iov_lines_eol[2*(_i_)].iov_base )
92 #define eol_line_len(_i_)      ( iov_lines_eol[2*(_i_)].iov_len )
93
94 #define eol_line(_i_,_s_)      { eol_line_s(_i_) = (_s_).s; \
95                                  eol_line_len(_i_) = (_s_).len; }
96
97 #define IDBUF_LEN              128
98 #define ROUTE_BUFFER_MAX       512
99 #define APPEND_BUFFER_MAX      4096
100 #define CMD_BUFFER_MAX         128
101
102 #define append_str(_dest,_src,_len) \
103         do{ \
104                 memcpy( (_dest) , (_src) , (_len) );\
105                 (_dest) += (_len) ;\
106         }while(0);
107
108 #define append_chr(_dest,_c) \
109         *((_dest)++) = _c;
110
111 #define copy_route(s,len,rs,rlen) \
112         do {\
113                 if(rlen+len+3 >= ROUTE_BUFFER_MAX){\
114                         LOG(L_ERR,"vm: buffer overflow while copying new route\n");\
115                         goto error;\
116                 }\
117                 if(len){\
118                         append_chr(s,','); len++;\
119                 }\
120                 append_chr(s,'<');len++;\
121                 append_str(s,rs,rlen);\
122                 len += rlen; \
123                 append_chr(s,'>');len++;\
124         } while(0)
125
126 static struct iovec iov_lines_eol[2*TWRITE_PARAMS];
127 static struct iovec eol={"\n",1};
128
129 static int sock;
130
131 struct hdr_avp {
132         str title;
133         int type;
134         str sval;
135         int ival;
136         struct hdr_avp *next;
137 };
138
139 struct tw_append {
140         str name;
141         int add_body;
142         struct hdr_avp *elems;
143         struct tw_append *next;
144 };
145
146 struct tw_info {
147         str action;
148         struct tw_append *append;
149 };
150
151 #define ELEM_TYPE_AVP      "avp"
152 #define ELEM_TYPE_AVP_LEN  (sizeof(ELEM_TYPE_AVP)-1)
153 #define ELEM_TYPE_HDR      "hdr"
154 #define ELEM_TYPE_HDR_LEN  (sizeof(ELEM_TYPE_HDR)-1)
155 #define ELEM_TYPE_MSG      "msg"
156 #define ELEM_TYPE_MSG_LEN  (sizeof(ELEM_TYPE_MSG)-1)
157 #define ELEM_IS_AVP        (1<<0)
158 #define ELEM_IS_HDR        (1<<1)
159 #define ELEM_IS_MSG        (1<<2)
160
161 #define ELEM_VAL_BODY      "body"
162 #define ELEM_VAL_BODY_LEN  (sizeof(ELEM_VAL_BODY)-1)
163
164
165 static struct tw_append *tw_appends;
166
167
168 static void print_tw_append( struct tw_append *append)
169 {
170         struct hdr_avp *ha;
171
172         if (!append)
173                 return;
174
175         DBG("DEBUG:tm:print_tw_append: tw_append name=<%.*s>\n",
176                 append->name.len,append->name.s);
177         for( ha=append->elems ; ha ; ha=ha->next ) {
178                 DBG("\ttitle=<%.*s>\n",ha->title.len,ha->title.s);
179                 DBG("\t\tttype=<%d>\n",ha->type);
180                 DBG("\t\tsval=<%.*s>\n",ha->sval.len,ha->sval.s);
181                 DBG("\t\tival=<%d>\n",ha->ival);
182         }
183 }
184
185
186 /* tw_append syntax:
187  * tw_append = name:element[;element]
188  * element   = [title=]value 
189  * value     = avp[avp_spec] | hdr[hdr_name] | msg[body] */
190 int parse_tw_append( modparam_t type, void* val)
191 {
192         struct hdr_field hdr;
193         struct hdr_avp *last;
194         struct hdr_avp *ha;
195         struct tw_append *app;
196         int_str avp_name;
197         char *s;
198         char bar;
199         str foo;
200         int n;
201         
202         if (val==0 || ((char*)val)[0]==0)
203                 return 0;
204         s = (char*)val;
205
206         /* start parsing - first the name */
207         while( *s && isspace((int)*s) )  s++;
208         if ( !*s || *s==':')
209                 goto parse_error;
210         foo.s = s;
211         while ( *s && *s!=':' && !isspace((int)*s) ) s++;
212         if ( !*s || foo.s==s )
213                 goto parse_error;
214         foo.len = s - foo.s;
215         /* parse separator */
216         while( *s && isspace((int)*s) )  s++;
217         if ( !*s || *s!=':')
218                 goto parse_error;
219         s++;
220         while( *s && isspace((int)*s) )  s++;
221         if ( !*s )
222                 goto parse_error;
223
224         /* check for name duplication */
225         for(app=tw_appends;app;app=app->next)
226                 if (app->name.len==foo.len && !strncasecmp(app->name.s,foo.s,foo.len)){
227                         LOG(L_ERR,"ERROR:tm:parse_tw_append: duplicated tw_append name "
228                                 "<%.*s>\n",foo.len,foo.s);
229                         goto error;
230                 }
231
232         /* new tw_append structure */
233         app = (struct tw_append*)pkg_malloc( sizeof(struct tw_append) );
234         if (app==0) {
235                 LOG(L_ERR,"ERROR:tm:parse_tw_append: no more pkg memory\n");
236                 goto error;
237         }
238         app->name.s = (char*)pkg_malloc( foo.len+1 );
239         if (app->name.s==0) {
240                 LOG(L_ERR,"ERROR:tm:parse_tw_append: no more pkg memory\n");
241                 goto error;
242         }
243         memcpy( app->name.s, foo.s, foo.len);
244         app->name.len = foo.len;
245         app->name.s[app->name.len] = 0;
246         last = app->elems = 0;
247         app->next = tw_appends;
248         tw_appends = app;
249
250         /* parse the elements */
251         while (*s) {
252                 /* parse element title or element type */
253                 foo.s = s;
254                 while( *s && *s!='[' && *s!='=' && *s!=';' && !isspace((int)*s) ) s++;
255                 if ( !*s || foo.s==s)
256                         goto parse_error;
257                 foo.len = s - foo.s;
258                 /* new hdr_avp structure */
259                 ha = (struct hdr_avp*)pkg_malloc( sizeof(struct hdr_avp) );
260                 if (ha==0) {
261                         LOG(L_ERR,"ERROR:tm:parse_tw_append: no more pkg memory\n");
262                         goto error;
263                 }
264                 memset( ha, 0, sizeof(struct hdr_avp));
265                 if (*s!='[') {
266                         /* foo must by title or some error -> parse separator */
267                         while( *s && isspace((int)*s) )  s++;
268                         if ( !*s || *s!='=')
269                                 goto parse_error;
270                         s++;
271                         while( *s && isspace((int)*s) )  s++;
272                         if ( !*s )
273                                 goto parse_error;
274                         /* set the title */
275                         ha->title.s = (char*)pkg_malloc( foo.len+1 );
276                         if (ha->title.s==0) {
277                                 LOG(L_ERR,"ERROR:tm:parse_tw_append: no more pkg memory\n");
278                                 goto error;
279                         }
280                         memcpy( ha->title.s, foo.s, foo.len);
281                         ha->title.len = foo.len;
282                         ha->title.s[ha->title.len] = 0;
283                         /* parse the type now */
284                         foo.s = s;
285                         while( *s && *s!='[' && *s!=']' && *s!=';' && !isspace((int)*s) )
286                                 s++;
287                         if ( *s!='[' || foo.s==s)
288                                 goto parse_error;
289                         foo.len = s - foo.s;
290                 }
291                 /* foo containes the elemet type */
292                 if ( foo.len==ELEM_TYPE_AVP_LEN &&
293                 !strncasecmp( foo.s, ELEM_TYPE_AVP, foo.len) ) {
294                         ha->type = ELEM_IS_AVP;
295                 } else if ( foo.len==ELEM_TYPE_HDR_LEN &&
296                 !strncasecmp( foo.s, ELEM_TYPE_HDR, foo.len) ) {
297                         ha->type = ELEM_IS_HDR;
298                 } else if ( foo.len==ELEM_TYPE_MSG_LEN &&
299                 !strncasecmp( foo.s, ELEM_TYPE_MSG, foo.len) ) {
300                         ha->type = ELEM_IS_MSG;
301                 } else {
302                         LOG(L_ERR,"ERROR:tm:parse_tw_append: unknown type <%.*s>\n",
303                                 foo.len, foo.s);
304                         goto error;
305                 }
306                 /* parse the element name */
307                 s++;
308                 foo.s = s;
309                 while( *s && *s!=']' && *s!=';' && !isspace((int)*s) ) s++;
310                 if ( *s!=']' || foo.s==s )
311                         goto parse_error;
312                 foo.len = s - foo.s;
313                 s++;
314                 /* process and optimize the element name */
315                 if (ha->type==ELEM_IS_AVP) {
316                         /* element is AVP */
317                         if ( parse_avp_spec( &foo, &n, &avp_name)!=0 ) {
318                                 LOG(L_ERR,"ERROR:tm:parse_tw_append: bad alias spec "
319                                         "<%.*s>\n",foo.len, foo.s);
320                                 goto error;
321                         }
322                         if (n&AVP_NAME_STR) {
323                                 /* string name */
324                                 ha->sval.s = (char*)pkg_malloc(avp_name.s->len+1);
325                                 if (ha->sval.s==0) {
326                                         LOG(L_ERR,"ERROR:tm:parse_tw_append: no more pkg mem\n");
327                                         goto error;
328                                 }
329                                 memcpy( ha->sval.s, avp_name.s->s, avp_name.s->len);
330                                 ha->sval.len = avp_name.s->len;
331                                 ha->sval.s[ha->sval.len] = 0;
332                                 if (ha->title.s==0)
333                                         ha->title = ha->sval;
334                         } else {
335                                 /* ID name - if title is missing, convert the ID to
336                                  * string and us it a title */
337                                 ha->ival = avp_name.n;
338                                 if (ha->title.s==0) {
339                                         foo.s=int2str((unsigned long)ha->ival, &foo.len);
340                                         ha->title.s = (char*)pkg_malloc( n+1 );
341                                         if (ha->title.s==0) {
342                                                 LOG(L_ERR,"ERROR:tm:parse_tw_append: no more pkg "
343                                                         "memory\n");
344                                                 goto error;
345                                         }
346                                         memcpy( ha->title.s, foo.s, foo.len);
347                                         ha->title.len = foo.len;
348                                         ha->title.s[ha->title.len] = 0;
349                                 }
350                         }
351                 } else if (ha->type==ELEM_IS_HDR) {
352                         /* element is HDR -  try to get it's coded type if defined */
353                         bar = foo.s[foo.len];
354                         foo.s[foo.len] = ':';
355                         /* parse header name */
356                         if (parse_hname2( foo.s, foo.s+foo.len+1, &hdr)==0) {
357                                 LOG(L_ERR,"BUG:tm_parse_tw_append: parse header failed\n");
358                                 goto error;
359                         }
360                         foo.s[foo.len] = bar;
361                         ha->ival = hdr.type;
362                         if (hdr.type==HDR_OTHER_T || ha->title.s==0) {
363                                 /* duplicate hdr name */
364                                 ha->sval.s = (char*)pkg_malloc(foo.len+1);
365                                 if (ha->sval.s==0) {
366                                         LOG(L_ERR,"ERROR:tm:parse_tw_append: no more pkg mem\n");
367                                         goto error;
368                                 }
369                                 memcpy( ha->sval.s, foo.s, foo.len);
370                                 ha->sval.len = foo.len;
371                                 ha->sval.s[ha->sval.len] = 0;
372                                 if (ha->title.s==0)
373                                         ha->title = ha->sval;
374                         }
375                 } else {
376                         /* element is MSG */
377                         if ( !(foo.len==ELEM_VAL_BODY_LEN &&
378                         !strncasecmp(ELEM_VAL_BODY,foo.s,foo.len)) ) {
379                                 LOG(L_ERR,"ERROR:tm:parse_tw_append: unsupported value <%.*s>"
380                                         " for msg type\n",foo.len,foo.s);
381                                 goto error;
382                         }
383                         app->add_body = 1;
384                         pkg_free( ha );
385                         ha = 0;
386                 }
387
388                 /* parse the element separator, if present */
389                 while( *s && isspace((int)*s) )  s++;
390                 if ( *s && *s!=';')
391                         goto parse_error;
392                 if (*s==';') {
393                         s++;
394                         while( *s && isspace((int)*s) )  s++;
395                         if (!*s)
396                                 goto parse_error;
397                 }
398
399                 /* link the element to tw_append structure */
400                 if (ha) {
401                         if (last==0) {
402                                 last = app->elems = ha;
403                         } else {
404                                 last->next = ha;
405                                 last = ha;
406                         }
407                 }
408
409         } /* end while */
410
411         print_tw_append( app );
412         /* free the old string */
413         pkg_free(val);
414         return 0;
415 parse_error:
416         LOG(L_ERR,"ERROR:tm:parse_tw_append: parse error in <%s> around "
417                 "position %ld\n", (char*)val, (long)(s-(char*)val));
418 error:
419         return -1;
420 }
421
422
423 static struct tw_append *search_tw_append(char *name, int len)
424 {
425         struct tw_append * app;
426
427         for( app=tw_appends ; app ; app=app->next )
428                 if (app->name.len==len && !strncasecmp(app->name.s,name,len) )
429                         return app;
430         return 0;
431 }
432
433
434 int fixup_t_write( void** param, int param_no)
435 {
436         struct tw_info *twi;
437         char *s;
438
439         if (param_no==2) {
440                 twi = (struct tw_info*)pkg_malloc( sizeof(struct tw_info) );
441                 if (twi==0) {
442                         LOG(L_ERR,"ERROR:tm:fixup_t_write: no more pkg memory\n");
443                         return E_OUT_OF_MEM;
444                 }
445                 memset( twi, 0 , sizeof(struct tw_info));
446                 s = (char*)*param;
447                 twi->action.s = s;
448                 if ( (s=strchr(s,'/'))!=0) {
449                         twi->action.len = s - twi->action.s;
450                         if (twi->action.len==0) {
451                                 LOG(L_ERR,"ERROR:tm:fixup_t_write: empty action name\n");
452                                 return E_CFG;
453                         }
454                         s++;
455                         if (*s==0) {
456                                 LOG(L_ERR,"ERROR:tm:fixup_t_write: empty append name\n");
457                                 return E_CFG;
458                         }
459                         twi->append = search_tw_append( s, strlen(s));
460                         if (twi->append==0) {
461                                 LOG(L_ERR,"ERROR:tm:fixup_t_write: unknown append name "
462                                         "<%s>\n",s);
463                                 return E_CFG;
464                         }
465                 } else {
466                         twi->action.len = strlen(twi->action.s);
467                 }
468                 *param=(void*)twi;
469         }
470
471         return 0;
472 }
473
474
475
476
477
478
479 int init_twrite_sock(void)
480 {
481         int flags;
482
483         sock = socket(PF_LOCAL, SOCK_DGRAM, 0);
484         if (sock == -1) {
485                 LOG(L_ERR, "init_twrite_sock: Unable to create socket: %s\n", strerror(errno));
486                 return -1;
487         }
488
489              /* Turn non-blocking mode on */
490         flags = fcntl(sock, F_GETFL);
491         if (flags == -1){
492                 LOG(L_ERR, "init_twrite_sock: fcntl failed: %s\n",
493                     strerror(errno));
494                 close(sock);
495                 return -1;
496         }
497                 
498         if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) {
499                 LOG(L_ERR, "init_twrite_sock: fcntl: set non-blocking failed:"
500                     " %s\n", strerror(errno));
501                 close(sock);
502                 return -1;
503         }
504         return 0;
505 }
506
507
508 int init_twrite_lines()
509 {
510         int i;
511
512         /* init the line table */
513         for(i=0;i<TWRITE_PARAMS;i++) {
514                 iov_lines_eol[2*i].iov_base = 0;
515                 iov_lines_eol[2*i].iov_len = 0;
516                 iov_lines_eol[2*i+1] = eol;
517         }
518
519         /* first line is the version - fill it now */
520         eol_line_s(0)   = TWRITE_VERSION_S;
521         eol_line_len(0) = TWRITE_VERSION_LEN;
522
523         return 0;
524 }
525
526
527 static int inline write_to_fifo(char *fifo, int cnt )
528 {
529         int   fd_fifo;
530
531         /* open FIFO file stream */
532         if((fd_fifo = open(fifo,O_WRONLY | O_NONBLOCK)) == -1){
533                 switch(errno){
534                         case ENXIO:
535                                 LOG(L_ERR,"ERROR:tm:write_to_fifo: nobody listening on "
536                                         " [%s] fifo for reading!\n",fifo);
537                         default:
538                                 LOG(L_ERR,"ERROR:tm:write_to_fifo: failed to open [%s] "
539                                         "fifo : %s\n", fifo, strerror(errno));
540                 }
541                 goto error;
542         }
543
544         /* write now (unbuffered straight-down write) */
545 repeat:
546         if (writev(fd_fifo, iov_lines_eol, 2*cnt)<0) {
547                 if (errno!=EINTR) {
548                         LOG(L_ERR, "ERROR:tm:write_to_fifo: writev failed: %s\n",
549                                 strerror(errno));
550                         close(fd_fifo);
551                         goto error;
552                 } else {
553                         goto repeat;
554                 }
555         }
556         close(fd_fifo);
557
558         DBG("DEBUG:tm:write_to_fifo: write completed\n");
559         return 1; /* OK */
560
561 error:
562         return -1;
563 }
564
565
566 static inline char* add2buf(char *buf, char *end, char *title, int title_len,
567                             char *value , int value_len)
568 {
569         if (buf+title_len+value_len+2+1>=end)
570                 return 0;
571         memcpy( buf, title, title_len);
572         buf += title_len;
573         *(buf++) = ':';
574         *(buf++) = ' ';
575         memcpy( buf, value, value_len);
576         buf += value_len;
577         *(buf++) = '\n';
578         return buf;
579 }
580
581
582 static inline char* append2buf( char *buf, int len, struct sip_msg *req, 
583                                 struct hdr_avp *ha)
584 {
585         struct hdr_field *hdr;
586         struct usr_avp   *avp;
587         int_str          avp_val;
588         int_str          avp_name;
589         char  *end;
590         str   foo;
591         int   msg_parsed;
592
593         end = buf+len;
594         msg_parsed = 0;
595
596         while(ha) {
597                 if (ha->type==ELEM_IS_AVP) {
598                         /* search for the AVP */
599                         if (ha->sval.s) {
600                                 avp_name.s=&ha->sval;
601                                 avp = search_first_avp( AVP_NAME_STR, avp_name, &avp_val);
602                                 DBG("AVP <%.*s>: %p\n",avp_name.s->len,avp_name.s->s,avp);
603                         } else {
604                                 avp_name.n=ha->ival;
605                                 avp = search_first_avp( 0, avp_name, &avp_val);
606                                 DBG("AVP <%i>: %p\n",avp_name.n,avp);
607                         }
608                         if (avp) {
609                                 if (avp->flags&AVP_VAL_STR) {
610                                         buf=add2buf( buf, end, ha->title.s, ha->title.len,
611                                                 avp_val.s->s , avp_val.s->len);
612                                         if (!buf)
613                                                 goto overflow_err;
614                                 } else {
615                                         foo.s=int2str( (unsigned long)avp_val.n, &foo.len);
616                                         buf=add2buf( buf, end, ha->title.s, ha->title.len,
617                                                 foo.s , foo.len);
618                                         if (!buf)
619                                                 goto overflow_err;
620                                 }
621                         }
622                 } else if (ha->type==ELEM_IS_HDR) {
623                         /* parse the HDRs */
624                         if (!msg_parsed) {
625                                 if (parse_headers( req, HDR_EOH_F, 0)!=0) {
626                                         LOG(L_ERR,"ERROR:tm:append2buf: parsing hdrs failed\n");
627                                         goto error;
628                                 }
629                                 msg_parsed = 1;
630                         }
631                         /* search the HDR */
632                         if (ha->ival==HDR_OTHER_T) {
633                                 for(hdr=req->headers;hdr;hdr=hdr->next)
634                                         if (ha->sval.len==hdr->name.len &&
635                                         strncasecmp( ha->sval.s, hdr->name.s, hdr->name.len)==0)
636                                                 break;
637                         } else {
638                                 for(hdr=req->headers;hdr;hdr=hdr->next)
639                                         if (ha->ival==hdr->type)
640                                                 break;
641                         }
642                         if (hdr) {
643                                 trim_len( foo.len, foo.s, hdr->body);
644                                 buf=add2buf( buf, end, ha->title.s, ha->title.len,
645                                         foo.s , foo.len);
646                                 if (!buf)
647                                         goto overflow_err;
648                         }
649                 } else {
650                         LOG(L_ERR,"BUG:tm:append2buf: unknown element type %d\n",
651                                 ha->type);
652                         goto error;
653                 }
654
655                 ha = ha->next;
656         }
657
658         return buf;
659 overflow_err:
660         LOG(L_ERR,"ERROR:tm:append2buf: overflow -> append exceeded %d len\n",len);
661 error:
662         return 0;
663 }
664
665
666 static int assemble_msg(struct sip_msg* msg, struct tw_info *twi)
667 {
668         static char     id_buf[IDBUF_LEN];
669         static char     route_buffer[ROUTE_BUFFER_MAX];
670         static char     append_buf[APPEND_BUFFER_MAX];
671         static char     cmd_buf[CMD_BUFFER_MAX];
672         static str      empty_param = STR_STATIC_INIT(".");
673         unsigned int      hash_index, label;
674         contact_body_t*   cb=0;
675         contact_t*        c=0;
676         name_addr_t       na;
677         rr_t*             record_route;
678         struct hdr_field* p_hdr;
679         param_hooks_t     hooks;
680         int               l;
681         char*             s, fproxy_lr;
682         str               route, next_hop, append, tmp_s, body, str_uri;
683
684         if(msg->first_line.type != SIP_REQUEST){
685                 LOG(L_ERR,"assemble_msg: called for something else then"
686                         "a SIP request\n");
687                 goto error;
688         }
689
690         /* parse all -- we will need every header field for a UAS */
691         if ( parse_headers(msg, HDR_EOH_F, 0)==-1) {
692                 LOG(L_ERR,"assemble_msg: parse_headers failed\n");
693                 goto error;
694         }
695
696         /* find index and hash; (the transaction can be safely used due 
697          * to refcounting till script completes) */
698         if( t_get_trans_ident(msg,&hash_index,&label) == -1 ) {
699                 LOG(L_ERR,"assemble_msg: t_get_trans_ident failed\n");
700                 goto error;
701         }
702
703          /* parse from header */
704         if (msg->from->parsed==0 && parse_from_header(msg)==-1 ) {
705                 LOG(L_ERR,"assemble_msg: while parsing <From:> header\n");
706                 goto error;
707         }
708
709         /* parse the RURI (doesn't make any malloc) */
710         msg->parsed_uri_ok = 0; /* force parsing */
711         if (parse_sip_msg_uri(msg)<0) {
712                 LOG(L_ERR,"assemble_msg: uri has not been parsed\n");
713                 goto error;
714         }
715
716         /* parse contact header */
717         str_uri.s = 0;
718         str_uri.len = 0;
719         if(msg->contact) {
720                 if (msg->contact->parsed==0 && parse_contact(msg->contact)==-1) {
721                         LOG(L_ERR,"assemble_msg: error while parsing "
722                             "<Contact:> header\n");
723                         goto error;
724                 }
725                 cb = (contact_body_t*)msg->contact->parsed;
726                 if(cb && (c=cb->contacts)) {
727                         str_uri = c->uri;
728                         if (find_not_quoted(&str_uri,'<')) {
729                                 parse_nameaddr(&str_uri,&na);
730                                 str_uri = na.uri;
731                         }
732                 }
733         }
734
735         /* str_uri is taken from caller's contact or from header
736          * for backwards compatibility with pre-3261 (from is already parsed)*/
737         if(!str_uri.len || !str_uri.s)
738                 str_uri = get_from(msg)->uri;
739
740         /* parse Record-Route headers */
741         route.s = s = route_buffer; route.len = 0;
742         fproxy_lr = 0;
743         next_hop = empty_param;
744
745         p_hdr = msg->record_route;
746         if(p_hdr) {
747                 if (p_hdr->parsed==0 && parse_rr(p_hdr)!=0 ) {
748                         LOG(L_ERR,"assemble_msg: while parsing "
749                             "'Record-Route:' header\n");
750                         goto error;
751                 }
752                 record_route = (rr_t*)p_hdr->parsed;
753         } else {
754                 record_route = 0;
755         }
756
757         if( record_route ) {
758                 if ( (tmp_s.s=find_not_quoted(&record_route->nameaddr.uri,';'))!=0 &&
759                 tmp_s.s+1!=record_route->nameaddr.uri.s+
760                 record_route->nameaddr.uri.len) {
761                         /* Parse all parameters */
762                         tmp_s.len = record_route->nameaddr.uri.len - (tmp_s.s-
763                                 record_route->nameaddr.uri.s);
764                         if (parse_params( &tmp_s, CLASS_URI, &hooks, 
765                         &record_route->params) < 0) {
766                                 LOG(L_ERR,"assemble_msg: error while parsing "
767                                     "record route uri params\n");
768                                 goto error;
769                         }
770                         fproxy_lr = (hooks.uri.lr != 0);
771                         DBG("assemble_msg: record_route->nameaddr.uri: %.*s\n",
772                                 record_route->nameaddr.uri.len,record_route->nameaddr.uri.s);
773                         if(fproxy_lr){
774                                 DBG("assemble_msg: first proxy has loose routing.\n");
775                                 copy_route(s,route.len,record_route->nameaddr.uri.s,
776                                         record_route->nameaddr.uri.len);
777                         }
778                 }
779                 for(p_hdr = p_hdr->next;p_hdr;p_hdr = p_hdr->next) {
780                         /* filter out non-RR hdr and empty hdrs */
781                         if( (p_hdr->type!=HDR_RECORDROUTE_T) || p_hdr->body.len==0)
782                                 continue;
783
784                         if(p_hdr->parsed==0 && parse_rr(p_hdr)!=0 ){
785                                 LOG(L_ERR,"assemble_msg: "
786                                     "while parsing <Record-route:> header\n");
787                                 goto error;
788                         }
789                         for(record_route=p_hdr->parsed; record_route;
790                             record_route=record_route->next){
791                                 DBG("assemble_msg: record_route->nameaddr.uri: "
792                                     "<%.*s>\n", record_route->nameaddr.uri.len,
793                                         record_route->nameaddr.uri.s);
794                                 copy_route(s,route.len,record_route->nameaddr.uri.s,
795                                         record_route->nameaddr.uri.len);
796                         }
797                 }
798
799                 if(!fproxy_lr){
800                         copy_route(s,route.len,str_uri.s,str_uri.len);
801                         str_uri = ((rr_t*)msg->record_route->parsed)->nameaddr.uri;
802                 } else {
803                         next_hop = ((rr_t*)msg->record_route->parsed)->nameaddr.uri;
804                 }
805         }
806
807         DBG("assemble_msg: calculated route: %.*s\n",
808             route.len,route.len ? route.s : "");
809         DBG("assemble_msg: next r-uri: %.*s\n",
810             str_uri.len,str_uri.len ? str_uri.s : "");
811         
812         if ( REQ_LINE(msg).method_value==METHOD_INVITE || 
813              REQ_LINE(msg).method_value==METHOD_INFO ||
814                         (twi->append && twi->append->add_body) ) {
815                 /* get body */
816                 if( (body.s = get_body(msg)) == 0 ){
817                         LOG(L_ERR, "assemble_msg: get_body failed\n");
818                         goto error;
819                 }
820                 body.len = msg->len - (body.s - msg->buf);
821         } else {
822                 body = empty_param;
823         }
824
825         /* additional headers */
826         append.s = s = append_buf;
827         if (sizeof(flag_t)*2+12+1 >= APPEND_BUFFER_MAX) {
828                 LOG(L_ERR,"assemble_msg: buffer overflow "
829                     "while copying optional header\n");
830                 goto error;
831         }
832         append_str(s,"P-MsgFlags: ",12);
833         l = APPEND_BUFFER_MAX - (12+1); /* include trailing `\n'*/
834
835         if (int2reverse_hex(&s, &l, (int)msg->msg_flags) == -1) {
836                 LOG(L_ERR,"assemble_msg: buffer overflow "
837                     "while copying optional header\n");
838                 goto error;
839         }
840         append_chr(s,'\n');
841
842         if ( twi->append && ((s=append2buf( s, APPEND_BUFFER_MAX-(s-append.s), msg,
843         twi->append->elems))==0) )
844                 goto error;
845
846         /* body separator */
847         append_chr(s,'.');
848         append.len = s-append.s;
849
850         eol_line_s(1) = s = cmd_buf;
851         if(twi->action.len+12 >= CMD_BUFFER_MAX){
852                 LOG(L_ERR,"assemble_msg: buffer overflow while "
853                     "copying command name\n");
854                 goto error;
855         }
856         append_str(s,"sip_request.",12);
857         append_str(s,twi->action.s,twi->action.len);
858         eol_line_len(1) = s - (char*)eol_line_s(1);
859
860         eol_line(2,REQ_LINE(msg).method);     /* method type */
861         eol_line(3,msg->parsed_uri.user);     /* user from r-uri */
862         eol_line(4,msg->parsed_uri.host);     /* domain */
863
864         eol_line(5,msg->rcv.bind_address->address_str); /* dst ip */
865
866         eol_line(6,msg->rcv.dst_port==SIP_PORT ?
867                         empty_param : msg->rcv.bind_address->port_no_str); /* port */
868
869         /* r_uri ('Contact:' for next requests) */
870         eol_line(7,msg->first_line.u.request.uri);
871
872         /* r_uri for subsequent requests */
873         eol_line(8,str_uri.len?str_uri:empty_param);
874
875         eol_line(9,get_from(msg)->body);                /* from */
876         eol_line(10,msg->to->body);                     /* to */
877         eol_line(11,msg->callid->body);         /* callid */
878         eol_line(12,get_from(msg)->tag_value);  /* from tag */
879         eol_line(13,get_to(msg)->tag_value);    /* to tag */
880         eol_line(14,get_cseq(msg)->number);     /* cseq number */
881
882         eol_line_s(15)=id_buf;       /* hash:label */
883         s = int2str(hash_index, &l);
884         if (l+1>=IDBUF_LEN) {
885                 LOG(L_ERR, "assemble_msg: too big hash\n");
886                 goto error;
887         }
888         memcpy(id_buf, s, l);
889         id_buf[l]=':';
890         eol_line_len(15)=l+1;
891         s = int2str(label, &l);
892         if (l+1+eol_line_len(15)>=IDBUF_LEN) {
893                 LOG(L_ERR, "assemble_msg: too big label\n");
894                 goto error;
895         }
896         memcpy(id_buf+eol_line_len(15), s, l);
897         eol_line_len(15) += l;
898
899         eol_line(16, route.len ? route : empty_param );
900         eol_line(17, next_hop );
901         eol_line(18, append );
902         eol_line(19, body );
903
904         /* success */
905         return 1;
906 error:
907         /* 0 would lead to immediate script exit -- -1 returns
908          * with 'false' to script processing */
909         return -1;
910 }
911
912
913 static int write_to_unixsock(char* sockname, int cnt)
914 {
915         int len, e;
916         struct sockaddr_un dest;
917
918         if (!sockname) {
919                 LOG(L_ERR, "write_to_unixsock: Invalid parameter\n");
920                 return E_UNSPEC;
921         }
922
923         len = strlen(sockname);
924         if (len == 0) {
925                 DBG("write_to_unixsock: Error - empty socket name\n");
926                 return -1;
927         } else if (len > 107) {
928                 LOG(L_ERR, "write_to_unixsock: Socket name too long\n");
929                 return -1;
930         }
931
932         memset(&dest, 0, sizeof(dest));
933         dest.sun_family = PF_LOCAL;
934         memcpy(dest.sun_path, sockname, len);
935 #ifdef HAVE_SOCKADDR_SA_LEN
936         dest.sun_len = len;
937 #endif
938
939         e = connect(sock, (struct sockaddr*)&dest, SUN_LEN(&dest));
940 #ifdef HAVE_CONNECT_ECONNRESET_BUG
941         /*
942          * Workaround for a nasty bug in BSD kernels dated back
943          * to the Berkeley days, so that can be found in many modern
944          * BSD-derived kernels. Workaround should be pretty harmless since
945          * in normal conditions connect(2) can never return ECONNRESET.
946          */
947         if ((e == -1) && (errno == ECONNRESET))
948                 e = 0;
949 #endif
950         if (e == -1) {
951                 LOG(L_ERR, "write_to_unixsock: Error in connect: %s\n", strerror(errno));
952                 return -1;
953         }
954
955         if (tsend_dgram_ev(sock, iov_lines_eol, 2 * cnt, tm_unix_tx_timeout * 1000) < 0) {
956                 LOG(L_ERR, "write_to_unixsock: writev failed: %s\n", strerror(errno));
957                 return -1;
958         }
959
960         return 0;
961 }
962
963
964 int t_write_req(struct sip_msg* msg, char* vm_fifo, char* info)
965 {
966         if (assemble_msg(msg, (struct tw_info*)info) < 0) {
967                 LOG(L_ERR, "ERROR:tm:t_write_req: Error int assemble_msg\n");
968                 return -1;
969         }
970                 
971         if (write_to_fifo(vm_fifo, TWRITE_PARAMS) == -1) {
972                 LOG(L_ERR, "ERROR:tm:t_write_req: write_to_fifo failed\n");
973                 return -1;
974         }
975         
976              /* make sure that if voicemail does not initiate a reply
977               * timely, a SIP timeout will be sent out */
978         if (add_blind_uac() == -1) {
979                 LOG(L_ERR, "ERROR:tm:t_write_req: add_blind failed\n");
980                 return -1;
981         }
982         return 1;
983 }
984
985
986 int t_write_unix(struct sip_msg* msg, char* socket, char* info)
987 {
988         if (assemble_msg(msg, (struct tw_info*)info) < 0) {
989                 LOG(L_ERR, "ERROR:tm:t_write_unix: Error in assemble_msg\n");
990                 return -1;
991         }
992
993         if (write_to_unixsock(socket, TWRITE_PARAMS) == -1) {
994                 LOG(L_ERR, "ERROR:tm:t_write_unix: write_to_unixsock failed\n");
995                 return -1;
996         }
997
998              /* make sure that if voicemail does not initiate a reply
999               * timely, a SIP timeout will be sent out */
1000         if (add_blind_uac() == -1) {
1001                 LOG(L_ERR, "ERROR:tm:t_write_unix: add_blind failed\n");
1002                 return -1;
1003         }
1004         return 1;
1005 }