bug_fix: checking of return value of snprintf aligned to C99
[sip-router] / modules / tm / uac.c
1 /*
2  * $Id$
3  *
4  * simple UAC for things such as SUBSCRIBE or SMS gateway;
5  * no authentication and other UAC features -- just send
6  * a message, retransmit and await a reply; forking is not
7  * supported during client generation, in all other places
8  * it is -- adding it should be simple
9  *
10  * Copyright (C) 2001-2003 Fhg Fokus
11  *
12  * This file is part of ser, a free SIP server.
13  *
14  * ser is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version
18  *
19  * For a license to use the ser software under conditions
20  * other than those described here, or to purchase support for this
21  * software, please contact iptel.org by e-mail at the following addresses:
22  *    info@iptel.org
23  *
24  * ser is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27  * GNU General Public License for more details.
28  *
29  * You should have received a copy of the GNU General Public License 
30  * along with this program; if not, write to the Free Software 
31  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
32  */
33
34
35 #include <stdlib.h>
36 #include <sys/types.h>
37 #include <unistd.h>
38 #include <stdio.h>
39 #include <errno.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <fcntl.h>
43 #include <signal.h>
44 #include <limits.h>
45 #include <string.h>
46 #include "../../dprint.h"
47 #include "../../ut.h"
48 #include "../../hash_func.h"
49 #include "../../md5utils.h"
50 #include "../../mem/mem.h"
51 #include "../../fifo_server.h"
52 #include "../../error.h"
53 #include "../../pt.h"
54 #include "../../crc.h"
55 #include "t_funcs.h"
56 #include "config.h"
57 #include "sip_msg.h"
58 #include "ut.h"
59 #include "t_msgbuilder.h"
60 #include "uac.h"
61
62 /* Call-ID has the following form: <callid_nr>-<pid>@<ip>
63  * callid_nr is initialized as a random number and continually
64  * increases; -<pid>@<ip> is kept in callid_suffix
65  */
66
67 #define CALLID_SUFFIX_LEN (1 /* - */ + 5 /* pid */ \
68         + 42 /* embedded v4inv6 address can be looong '128.' */ \
69         + 2 /* parenthessis [] */ + 1 /* ZT 0 */ \
70         + 16 /* one never knows ;-) */ )
71 #define CALLID_NR_LEN 20
72
73 /* the character which separates random from constant part */
74 #define CID_SEP '-'
75
76 /* length of FROM tags */
77 #define FROM_TAG_LEN (MD5_LEN +1 /* - */ + CRC16_LEN)
78
79 static unsigned long callid_nr;
80 static char *callid_suffix;
81 static int callid_suffix_len;
82 static int rand_len;    /* number of chars to display max rand */
83 static char callid[CALLID_NR_LEN+CALLID_SUFFIX_LEN];
84
85 char *uac_from="\"UAC Account\" <sip:uac@dev.null:9>";
86
87 str uac_from_str;
88
89 static char from_tag[ FROM_TAG_LEN+1 ];
90
91
92
93 int uac_init() {
94
95         int i; 
96         unsigned long uli;
97         int rand_len_bits;
98         int rand_cnt; /* number of rands() to be long enough */
99         int rand_bits; /* length of rands() in bits */
100         str src[3];
101
102         if (RAND_MAX<TABLE_ENTRIES) {
103                 LOG(L_WARN, "Warning: uac does not spread "
104                         "accross the whole hash table\n");
105         }
106
107         /* calculate the initial call-id */
108
109         /* how many bits and chars do we need to display the 
110          * whole ULONG number */
111         for (rand_len_bits=0,uli=ULONG_MAX;uli;
112                         uli>>=1, rand_len_bits++ );
113         rand_len=rand_len_bits/4;
114         if (rand_len>CALLID_NR_LEN) {
115                 LOG(L_ERR, "ERROR: Too small callid buffer\n");
116                 return -1;
117         }
118
119         /* how long are the rand()s ? */
120         for (rand_bits=0,i=RAND_MAX;i;i>>=1,rand_bits++);
121         /* how many rands() fit in the ULONG ? */
122         rand_cnt=rand_len_bits / rand_bits;
123
124         /* now fill in the callid with as many random
125          * numbers as you can + 1 */
126         callid_nr=rand(); /* this is the + 1 */
127         while(rand_cnt) {
128                 rand_cnt--;
129                 callid_nr<<=rand_bits;
130                 callid_nr|=rand();
131         }
132         callid_suffix=callid+rand_len;
133         DBG("CALLID initialization: %lx (len=%d)\n", 
134                         callid_nr, rand_len );
135         DBG("CALLID0=%0*lx\n", rand_len, callid_nr );
136
137
138         /* calculate the initial From tag */
139
140         src[0].s="Long live SER server";
141         src[0].len=strlen(src[0].s);
142         src[1].s=sock_info[bind_idx].address_str.s;
143         src[1].len=strlen(src[1].s);
144         src[2].s=sock_info[bind_idx].port_no_str.s;
145         src[2].len=strlen(src[2].s);
146
147         MDStringArray( from_tag, src, 3 );
148         from_tag[MD5_LEN]=CID_SEP;
149
150         uac_from_str.s = uac_from;
151         uac_from_str.len = strlen(uac_from);
152
153         return 1;
154 }
155
156
157 int uac_child_init( int rank ) 
158 {
159         callid_suffix_len=snprintf(callid_suffix,CALLID_SUFFIX_LEN,
160                         "%c%d@%.*s", CID_SEP, my_pid(), 
161                         sock_info[bind_idx].address_str.len,
162                         sock_info[bind_idx].address_str.s );
163         if (callid_suffix_len==-1 || callid_suffix_len>=CALLID_SUFFIX_LEN) {
164                 LOG(L_ERR, "ERROR: uac_child_init: buffer too small\n");
165                 return -1;
166         }
167         DBG("DEBUG: callid_suffix: %s\n", callid_suffix );
168         return 1;
169 }
170
171 int t_uac( str *msg_type, str *dst, 
172         str *headers, str *body, str *from, 
173         transaction_cb completion_cb, void *cbp, 
174         dlg_t dlg)
175 {
176
177         int r;
178         struct cell *new_cell;
179         struct proxy_l *proxy;
180         int branch;
181         int ret;
182         unsigned int req_len;
183         char *buf;
184         union sockaddr_union to;
185         struct socket_info* send_sock;
186         struct retr_buf *request;
187         str dummy_from;
188         str callid_s;
189         str fromtag;
190
191         /* make -Wall shut up */
192         ret=0;
193
194         proxy=uri2proxy( dst );
195         if (proxy==0) {
196                 ser_error=ret=E_BAD_ADDRESS;
197                 LOG(L_ERR, "ERROR: t_uac: can't create a dst proxy\n");
198                 goto done;
199         }
200         branch=0;
201         /* might go away -- we ignore it in send_pr_buffer anyway */
202         /* T->uac[branch].request.to_len=sizeof(union sockaddr_union); */
203         hostent2su(&to, &proxy->host, proxy->addr_idx, 
204                 (proxy->port)?htons(proxy->port):htons(SIP_PORT));
205         send_sock=get_send_socket( &to, PROTO_UDP );
206         if (send_sock==0) {
207                 LOG(L_ERR, "ERROR: t_uac: no corresponding listening socket "
208                         "for af %d\n", to.s.sa_family );
209                 ret=E_NO_SOCKET;
210                 goto error00;
211         }
212
213         /* update callid */
214         /* generate_callid(); */
215         callid_nr++;
216         r=snprintf(callid, rand_len+1, "%0*lx", rand_len, callid_nr );
217         if (r==-1 || r>=rand_len+1) {
218                 LOG(L_CRIT, "BUG: SORRY, callid calculation failed\n");
219                 goto error00;
220         }
221         /* fix the ZT 0 */
222         callid[rand_len]=CID_SEP;
223         callid_s.s=callid;
224         callid_s.len=rand_len+callid_suffix_len;
225         DBG("DEBUG: sufix_len = %d\n",callid_suffix_len);
226         DBG("DEBUG: NEW CALLID:%.*s[%d]:\n", callid_s.len, callid_s.s 
227                 , callid_s.len);
228         new_cell = build_cell( NULL ) ; 
229         if (!new_cell) {
230                 ret=E_OUT_OF_MEM;
231                 LOG(L_ERR, "ERROR: t_uac: short of cell shmem\n");
232                 goto error00;
233         }
234         new_cell->completion_cb=completion_cb;
235         new_cell->cbp=cbp;
236         /* cbp is installed -- tell error handling bellow not to free it */
237         cbp=0;
238         new_cell->is_invite=msg_type->len==INVITE_LEN 
239                 && memcmp(msg_type->s, INVITE, INVITE_LEN)==0;
240         new_cell->local=1;
241         new_cell->kr=REQ_FWDED;
242
243
244         request=&new_cell->uac[branch].request;
245         request->to=to;
246         request->send_sock=send_sock;
247
248         /* need to put in table to calculate label which is needed for printing */
249         LOCK_HASH(new_cell->hash_index);
250         insert_into_hash_table_unsafe(  new_cell );
251         UNLOCK_HASH(new_cell->hash_index);
252
253         if (from) dummy_from=*from; else { dummy_from.s=0; dummy_from.len=0; }
254         /* calculate from tag from callid */
255         crcitt_string_array(&from_tag[MD5_LEN+1], &callid_s, 1 );
256         fromtag.s=from_tag; fromtag.len=FROM_TAG_LEN;
257         buf=build_uac_request(  *msg_type, *dst, 
258                         dummy_from, fromtag,
259                         DEFAULT_CSEQ, callid_s, 
260                         *headers, *body, branch,
261                         new_cell, /* t carries hash_index, label, md5,
262                                 uac[].send_sock and other pieces of
263                                 information needed to print a message*/
264                 &req_len );
265         if (!buf) {
266                 ret=E_OUT_OF_MEM;
267                 LOG(L_ERR, "ERROR: t_uac: short of req shmem\n");
268                 goto error01;
269         }      
270         new_cell->method.s=buf;new_cell->method.len=msg_type->len;
271
272
273         request->buffer = buf;
274         request->buffer_len = req_len;
275         new_cell->nr_of_outgoings++;
276
277
278         proxy->tx++;
279         proxy->tx_bytes+=req_len;
280
281         if (SEND_BUFFER( request)==-1) {
282                 LOG(L_ERR, "ERROR: t_uac: UAC sending to %.*s failed\n",
283                         dst->len, dst->s );
284                 proxy->errors++;
285                 proxy->ok=0;
286         }
287         start_retr( request );
288
289         /* success */
290         return 1;
291
292 error01:
293         LOCK_HASH(new_cell->hash_index);
294         remove_from_hash_table_unsafe( new_cell );
295         UNLOCK_HASH(new_cell->hash_index);
296         free_cell(new_cell);
297 error00:
298         free_proxy( proxy );
299         free( proxy );
300 done: 
301         /* if we did not install cbp, release it now */
302         if (cbp) shm_free(cbp);
303         return ser_error=ret;
304 }
305
306
307 /*
308  * Send a request within a dialog
309  */
310 int t_uac_dlg(str* msg,                     /* Type of the message - MESSAGE, OPTIONS etc. */
311               str* dst,                     /* Real destination (can be different than R-URI) */
312               str* ruri,                    /* Request-URI */
313               str* to,                      /* To - w/o tag*/
314               str* from,                    /* From - w/o tag*/
315               str* totag,                   /* To tag */
316               str* fromtag,                 /* From tag */
317               int* cseq,                    /* Variable holding CSeq */
318               str* cid,                     /* Call-ID */
319               str* headers,                 /* Optional headers including CRLF */
320               str* body,                    /* Message body */
321               transaction_cb completion_cb, /* Callback parameter */
322               void* cbp                     /* Callback pointer */
323               )
324 {
325
326         int r, branch, ret;
327         unsigned int req_len;
328         char *buf;
329         struct cell *new_cell;
330         struct proxy_l *proxy;
331         union sockaddr_union to_su;
332         struct socket_info* send_sock;
333         struct retr_buf *request;
334         str callid_s, ftag, tmp;
335
336         /* make -Wall shut up */
337         ret=0;
338
339         proxy = uri2proxy((dst) ? (dst) : ((ruri) ? (ruri) : (to)));
340         if (proxy == 0) {
341                 ser_error = ret = E_BAD_ADDRESS;
342                 LOG(L_ERR, "ERROR: t_uac_dlg: Can't create a dst proxy\n");
343                 goto done;
344         }
345
346         branch=0;
347         hostent2su(&to_su, &proxy->host, proxy->addr_idx, (proxy->port) ? htons(proxy->port) : htons(SIP_PORT));
348         send_sock=get_send_socket(&to_su, PROTO_UDP);
349         if (send_sock == 0) {
350                 LOG(L_ERR, "ERROR: t_uac_dlg: no corresponding listening socket for af %d\n", to_su.s.sa_family );
351                 ret = E_NO_SOCKET;
352                 goto error00;
353         }
354         
355              /* No Call-ID given, calculate it */
356         if (cid == 0) {
357                 callid_nr++;
358                 r = snprintf(callid, rand_len + 1, "%0*lx", rand_len, callid_nr);
359                 if (r == -1 || r>=rand_len+1) {
360                         LOG(L_CRIT, "BUG: SORRY, callid calculation failed\n");
361                         goto error00;
362                 }
363
364                      /* fix the ZT 0 */
365                 callid[rand_len] = CID_SEP;
366                 callid_s.s = callid;
367                 callid_s.len = rand_len + callid_suffix_len;
368         }
369
370         new_cell = build_cell(0); 
371         if (!new_cell) {
372                 ret = E_OUT_OF_MEM;
373                 LOG(L_ERR, "ERROR: t_uac: short of cell shmem\n");
374                 goto error00;
375         }
376
377         new_cell->completion_cb = completion_cb;
378         new_cell->cbp = cbp;
379
380         /* cbp is installed -- tell error handling bellow not to free it */
381         cbp = 0;
382
383         new_cell->is_invite = msg->len == INVITE_LEN && memcmp(msg->s, INVITE, INVITE_LEN) == 0;
384         new_cell->local= 1 ;
385         new_cell->kr = REQ_FWDED;
386
387         request = &new_cell->uac[branch].request;
388         request->to = to_su;
389         request->send_sock = send_sock;
390
391         /* need to put in table to calculate label which is needed for printing */
392         LOCK_HASH(new_cell->hash_index);
393         insert_into_hash_table_unsafe(new_cell);
394         UNLOCK_HASH(new_cell->hash_index);
395
396         if (fromtag == 0) {
397                      /* calculate from tag from callid */
398                 crcitt_string_array(&from_tag[MD5_LEN + 1], (cid) ? (cid) : (&callid_s), 1);
399                 ftag.s = from_tag; 
400                 ftag.len = FROM_TAG_LEN;
401         }
402
403         buf = build_uac_request_dlg(msg, 
404                                     (ruri) ? (ruri) : (to),
405                                     to, 
406                                     (from) ? (from) : (&uac_from_str), 
407                                     totag,
408                                     (fromtag) ? (fromtag) : (&ftag), 
409                                     (cseq) ? (*cseq) : DEFAULT_CSEQ, 
410                                     (cid) ? (cid) : (&callid_s), 
411                                     headers, 
412                                     body, 
413                                     branch,
414                                     new_cell,
415                                     &req_len);
416         if (!buf) {
417                 ret = E_OUT_OF_MEM;
418                 LOG(L_ERR, "ERROR: t_uac: short of req shmem\n");
419                 goto error01;
420         }
421         new_cell->method.s = buf;
422         new_cell->method.len = msg->len;
423
424         request->buffer = buf;
425         request->buffer_len = req_len;
426         new_cell->nr_of_outgoings++;
427
428         proxy->tx++;
429         proxy->tx_bytes += req_len;
430
431         if (SEND_BUFFER(request) == -1) {
432                 if (dst) {
433                         tmp = *dst;
434                 } else if (ruri) {
435                         tmp = *ruri;
436                 } else {
437                         tmp = *to;
438                 }
439                 LOG(L_ERR, "ERROR: t_uac: UAC sending to \'%.*s\' failed\n", tmp.len, tmp.s);
440                 proxy->errors++;
441                 proxy->ok = 0;
442         }
443         
444         start_retr(request);
445
446         /* success */
447         return 1;
448
449 error01:
450         LOCK_HASH(new_cell->hash_index);
451         remove_from_hash_table_unsafe(new_cell);
452         UNLOCK_HASH(new_cell->hash_index);
453         free_cell(new_cell);
454
455 error00:
456         free_proxy(proxy);
457         free(proxy);
458
459 done: 
460         /* if we did not install cbp, release it now */
461         if (cbp) shm_free(cbp);
462         return ser_error = ret;
463 }
464
465
466 static void fifo_callback( struct cell *t, struct sip_msg *msg,
467         int code, void *param)
468 {
469
470         char *filename;
471         str text;
472
473         DBG("DEBUG: fifo UAC completed with status %d\n", code);
474         if (!t->cbp) {
475                 LOG(L_INFO, "INFO: fifo UAC completed with status %d\n", code);
476                 return;
477         }
478
479         filename=(char *)(t->cbp);
480         get_reply_status(&text,msg,code);
481         if (text.s==0) {
482                 LOG(L_ERR, "ERROR: fifo_callback: get_reply_status failed\n");
483                 fifo_reply(filename, "500 fifo_callback: get_reply_status failed\n");
484                 return;
485         }
486         fifo_reply(filename, "%.*s", text.len, text.s );
487         pkg_free(text.s);
488         DBG("DEBUG: fifo_callback sucesssfuly completed\n");
489 }       
490
491 /* to be obsoleted in favor of fifo_uac_from */
492 int fifo_uac( FILE *stream, char *response_file ) 
493 {
494         char method[MAX_METHOD];
495         char header[MAX_HEADER];
496         char body[MAX_BODY];
497         char dst[MAX_DST];
498         str sm, sh, sb, sd;
499         char *shmem_file;
500         int fn_len;
501         int ret;
502         int sip_error;
503         char err_buf[MAX_REASON_LEN];
504
505         sm.s=method; sh.s=header; sb.s=body; sd.s=dst;
506         if (!read_line(method, MAX_METHOD, stream,&sm.len)||sm.len==0) {
507                 /* line breaking must have failed -- consume the rest
508                    and proceed to a new request
509                 */
510                 LOG(L_ERR, "ERROR: fifo_uac: method expected\n");
511                 fifo_reply(response_file, 
512                         "400 fifo_uac: method expected");
513                 return 1;
514         }
515         DBG("DEBUG: fifo_uac: method: %.*s\n", sm.len, method );
516         if (!read_line(dst, MAX_DST, stream, &sd.len)||sd.len==0) {
517                 fifo_reply(response_file, 
518                         "400 fifo_uac: destination expected\n");
519                 LOG(L_ERR, "ERROR: fifo_uac: destination expected\n");
520                 return 1;
521         }
522         DBG("DEBUG: fifo_uac:  dst: %.*s\n", sd.len, dst );
523         /* now read header fields line by line */
524         if (!read_line_set(header, MAX_HEADER, stream, &sh.len)) {
525                 fifo_reply(response_file, 
526                         "400 fifo_uac: HFs expected\n");
527                 LOG(L_ERR, "ERROR: fifo_uac: header fields expected\n");
528                 return 1;
529         }
530         DBG("DEBUG: fifo_uac: header: %.*s\n", sh.len, header );
531         /* and eventually body */
532         if (!read_body(body, MAX_BODY, stream, &sb.len)) {
533                 fifo_reply(response_file, 
534                         "400 fifo_uac: body expected\n");
535                 LOG(L_ERR, "ERROR: fifo_uac: body expected\n");
536                 return 1;
537         }
538         DBG("DEBUG: fifo_uac: body: %.*s\n", sb.len, body );
539         DBG("DEBUG: fifo_uac: EoL -- proceeding to transaction creation\n");
540         /* we got it all, initiate transaction now! */
541         if (response_file) {
542                 fn_len=strlen(response_file)+1;
543                 shmem_file=shm_malloc(fn_len);
544                 if (shmem_file==0) {
545                         LOG(L_ERR, "ERROR: fifo_uac: no shmem\n");
546                         fifo_reply(response_file, 
547                                 "500 fifo_uac: no shmem for shmem_file\n");
548                         return 1;
549                 }
550                 memcpy(shmem_file, response_file, fn_len );
551         } else {
552                 shmem_file=0;
553         }
554         ret=t_uac(&sm,&sd,&sh,&sb, 0 /* default from */,
555                 fifo_callback,shmem_file,0 /* no dialog */);
556         if (ret>0) {
557                 if (err2reason_phrase(ret, &sip_error, err_buf,
558                                 sizeof(err_buf), "FIFO/UAC" ) > 0 ) 
559                 {
560                         fifo_reply(response_file, "500 FIFO/UAC error: %d\n",
561                                 ret );
562                 } else {
563                         fifo_reply(response_file, err_buf );
564                 }
565         }
566         return 1;
567 }
568
569 /* syntax:
570
571         :t_uac_from:[file] EOL
572         method EOL
573         [from] EOL (if none, server's default from is taken)
574         dst EOL (put in r-uri and To)
575         [CR-LF separated HFs]* EOL
576         EOL
577         [body] EOL
578         EOL
579
580 */
581
582 int fifo_uac_from( FILE *stream, char *response_file ) 
583 {
584         char method[MAX_METHOD];
585         char header[MAX_HEADER];
586         char body[MAX_BODY];
587         char dst[MAX_DST];
588         char from[MAX_FROM];
589         str sm, sh, sb, sd, sf;
590         char *shmem_file;
591         int fn_len;
592         int ret;
593         int sip_error;
594         char err_buf[MAX_REASON_LEN];
595         int err_ret;
596
597         sm.s=method; sh.s=header; sb.s=body; sd.s=dst;sf.s=from;
598
599         if (!read_line(method, MAX_METHOD, stream,&sm.len)||sm.len==0) {
600                 /* line breaking must have failed -- consume the rest
601                    and proceed to a new request
602                 */
603                 LOG(L_ERR, "ERROR: fifo_uac: method expected\n");
604                 fifo_reply(response_file, 
605                         "400 fifo_uac: method expected");
606                 return 1;
607         }
608         DBG("DEBUG: fifo_uac: method: %.*s\n", sm.len, method );
609         if (!read_line(from, MAX_FROM, stream, &sf.len)) {
610                 fifo_reply(response_file, 
611                         "400 fifo_uac: from expected\n");
612                 LOG(L_ERR, "ERROR: fifo_uac: from expected\n");
613                 return 1;
614         }
615         DBG("DEBUG: fifo_uac:  from: %.*s\n", sf.len, from);
616         if (!read_line(dst, MAX_DST, stream, &sd.len)||sd.len==0) {
617                 fifo_reply(response_file, 
618                         "400 fifo_uac: destination expected\n");
619                 LOG(L_ERR, "ERROR: fifo_uac: destination expected\n");
620                 return 1;
621         }
622         DBG("DEBUG: fifo_uac:  dst: %.*s\n", sd.len, dst );
623         /* now read header fields line by line */
624         if (!read_line_set(header, MAX_HEADER, stream, &sh.len)) {
625                 fifo_reply(response_file, 
626                         "400 fifo_uac: HFs expected\n");
627                 LOG(L_ERR, "ERROR: fifo_uac: header fields expected\n");
628                 return 1;
629         }
630         DBG("DEBUG: fifo_uac: header: %.*s\n", sh.len, header );
631         /* and eventually body */
632         if (!read_body(body, MAX_BODY, stream, &sb.len)) {
633                 fifo_reply(response_file, 
634                         "400 fifo_uac: body expected\n");
635                 LOG(L_ERR, "ERROR: fifo_uac: body expected\n");
636                 return 1;
637         }
638         DBG("DEBUG: fifo_uac: body: %.*s\n", sb.len, body );
639         DBG("DEBUG: fifo_uac: EoL -- proceeding to transaction creation\n");
640         /* we got it all, initiate transaction now! */
641         if (response_file) {
642                 fn_len=strlen(response_file)+1;
643                 shmem_file=shm_malloc(fn_len);
644                 if (shmem_file==0) {
645                         LOG(L_ERR, "ERROR: fifo_uac: no shmem\n");
646                         fifo_reply(response_file, 
647                                 "500 fifo_uac: no memory for shmem_file\n");
648                         return 1;
649                 }
650                 memcpy(shmem_file, response_file, fn_len );
651         } else {
652                 shmem_file=0;
653         }
654         /* HACK: there is yet a shortcoming -- if t_uac fails, callback
655            will not be triggered and no feedback will be printed
656            to shmem_file
657         */
658         ret=t_uac(&sm,&sd,&sh,&sb, sf.len==0 ? 0 : &sf /* default from */,
659                 fifo_callback,shmem_file,0 /* no dialog */);
660         if (ret<=0) {
661                 err_ret=err2reason_phrase(ret, &sip_error, err_buf,
662                                 sizeof(err_buf), "FIFO/UAC" ) ;
663                 if (err_ret > 0 )
664                 {
665                         fifo_reply(response_file, "%d %s", sip_error, err_buf );
666                 } else {
667                         fifo_reply(response_file, "500 FIFO/UAC error: %d\n",
668                                 ret );
669                 }
670         }
671         return 1;
672
673 }