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