6def098b1b41c1998e53fb4ce5e34ec779949d04
[sip-router] / modules / tm / tm.c
1 /*
2  * $Id$
3  *
4  * TM module
5  *
6  *
7  * ***************************************************
8  * * Jiri's Source Memorial                          *
9  * *                                                 *
10  * * Welcome, pilgrim ! This is the greatest place   *
11  * * where dramatic changes happend. There are not   *
12  * * many places with a history like this, as there  *
13  * * are not so many people like Jiri, one of the    *
14  * * ser's fathers, who brought everywhere the wind  *
15  * * of change, the flood of clean-up. We all felt   *
16  * * his fatherly eye watching over us day and night.*
17  * *                                                 *
18  * * Please, preserve this codework heritage, as     *
19  * * it's unlikely for fresh, juicy pieces of code to  *
20  * * arise to give him the again the chance to       *
21  * * demonstrate his clean-up and improvement skills.*
22  * *                                                 *
23  * * Hereby, we solicit you to adopt this historical *
24  * * piece of code. For $100, your name will be      *
25  * * be printed in this banner and we will use       *
26  * * collected funds to create and display an ASCII  *
27  * * statue of Jiri  .                               *
28  * ***************************************************
29  *
30  *
31  * Copyright (C) 2001-2003 FhG Fokus
32  *
33  * This file is part of ser, a free SIP server.
34  *
35  * ser is free software; you can redistribute it and/or modify
36  * it under the terms of the GNU General Public License as published by
37  * the Free Software Foundation; either version 2 of the License, or
38  * (at your option) any later version
39  *
40  * For a license to use the ser software under conditions
41  * other than those described here, or to purchase support for this
42  * software, please contact iptel.org by e-mail at the following addresses:
43  *    info@iptel.org
44  *
45  * ser is distributed in the hope that it will be useful,
46  * but WITHOUT ANY WARRANTY; without even the implied warranty of
47  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
48  * GNU General Public License for more details.
49  *
50  * You should have received a copy of the GNU General Public License
51  * along with this program; if not, write to the Free Software
52  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
53  */
54 /*
55  * History:
56  * --------
57  *  2003-02-18  added t_forward_nonack_{udp, tcp}, t_relay_to_{udp,tcp},
58  *               t_replicate_{udp, tcp} (andrei)
59  *  2003-02-19  added t_rely_{udp, tcp} (andrei)
60  *  2003-03-06  voicemail changes accepted (jiri)
61  *  2003-03-10  module export interface updated to the new format (andrei)
62  *  2003-03-16  flags export parameter added (janakj)
63  *  2003-03-19  replaced all mallocs/frees w/ pkg_malloc/pkg_free (andrei)
64  *  2003-03-30  set_kr for requests only (jiri)
65  *  2003-04-05  s/reply_route/failure_route, onreply_route introduced (jiri)
66  *  2003-04-14  use protocol from uri (jiri)
67  *  2003-07-07  added t_relay_to_tls, t_replicate_tls, t_forward_nonack_tls
68  *              added #ifdef USE_TCP, USE_TLS
69  *              removed t_relay_{udp,tcp,tls} (andrei)
70  *  2003-09-26  added t_forward_nonack_uri() - same as t_forward_nonack() but
71  *              takes no parameters -> forwards to uri (bogdan)
72  *  2004-02-11  FIFO/CANCEL + alignments (hash=f(callid,cseq)) (uli+jiri)
73  *  2004-02-18  t_reply exported via FIFO - imported from VM (bogdan)
74  *  2004-10-01  added a new param.: restart_fr_on_each_reply (andrei)
75  *  2005-11-14  new timer support, changed timer related module params (andrei)
76  *  2005-12-09  fixup_hostport2proxy uses route_struct to access param #1
77  *              when fixing param #2
78  *  2005-12-09  added t_set_fr() (andrei)
79  *  2006-02-07  named routes support (andrei)
80  *  2006-09-28  added t_branch_replied, t_branch_timeout, t_any_replied, 
81  *               t_any_timeout, t_is_canceled (andrei)
82  *  2006-10-16  added a new param.: aggregate challenges (andrei)
83  */
84
85
86 #include "defs.h"
87
88
89 #include <stdio.h>
90 #include <string.h>
91 #include <netdb.h>
92
93 #include "../../sr_module.h"
94 #include "../../dprint.h"
95 #include "../../error.h"
96 #include "../../ut.h"
97 #include "../../script_cb.h"
98 #include "../../usr_avp.h"
99 #include "../../mem/mem.h"
100 #include "../../route_struct.h"
101 #include "../../route.h"
102
103 #include "sip_msg.h"
104 #include "h_table.h"
105 #include "t_hooks.h"
106 #include "tm_load.h"
107 #include "ut.h"
108 #include "t_reply.h"
109 #include "uac.h"
110 #include "t_fwd.h"
111 #include "t_lookup.h"
112 #include "t_stats.h"
113 #include "callid.h"
114 #include "t_cancel.h"
115 #include "t_fifo.h"
116 #include "timer.h"
117
118 MODULE_VERSION
119
120 /* fixup functions */
121 static int fixup_hostport2proxy(void** param, int param_no);
122 static int fixup_proto_hostport2proxy(void** param, int param_no);
123 static int fixup_on_failure(void** param, int param_no);
124 static int fixup_on_reply(void** param, int param_no);
125 static int fixup_on_branch(void** param, int param_no);
126 static int fixup_t_reply(void** param, int param_no);
127
128
129 /* init functions */
130 static int mod_init(void);
131 static int child_init(int rank);
132
133
134 /* exported functions */
135 inline static int w_t_check(struct sip_msg* msg, char* str, char* str2);
136 inline static int w_t_lookup_cancel(struct sip_msg* msg, char* str, char* str2);
137 inline static int w_t_reply(struct sip_msg* msg, char* str, char* str2);
138 inline static int w_t_release(struct sip_msg* msg, char* str, char* str2);
139 inline static int w_t_retransmit_reply(struct sip_msg* p_msg, char* foo,
140                                 char* bar );
141 inline static int w_t_newtran(struct sip_msg* p_msg, char* foo, char* bar );
142 inline static int w_t_relay( struct sip_msg  *p_msg , char *_foo, char *_bar);
143 inline static int w_t_relay_to_udp( struct sip_msg  *p_msg , char *proxy,
144                                  char *);
145 #ifdef USE_TCP
146 inline static int w_t_relay_to_tcp( struct sip_msg  *p_msg , char *proxy,
147                                 char *);
148 #endif
149 #ifdef USE_TLS
150 inline static int w_t_relay_to_tls( struct sip_msg  *p_msg , char *proxy,
151                                 char *);
152 #endif
153 inline static int w_t_relay_to(struct sip_msg* msg, char* str,char*);
154 inline static int w_t_replicate( struct sip_msg  *p_msg ,
155                                 char *proxy, /* struct proxy_l *proxy expected */
156                                 char *_foo       /* nothing expected */ );
157 inline static int w_t_replicate_udp( struct sip_msg  *p_msg ,
158                                 char *proxy, /* struct proxy_l *proxy expected */
159                                 char *_foo       /* nothing expected */ );
160 #ifdef USE_TCP
161 inline static int w_t_replicate_tcp( struct sip_msg  *p_msg ,
162                                 char *proxy, /* struct proxy_l *proxy expected */
163                                 char *_foo       /* nothing expected */ );
164 #endif
165 #ifdef USE_TLS
166 inline static int w_t_replicate_tls( struct sip_msg  *p_msg ,
167                                 char *proxy, /* struct proxy_l *proxy expected */
168                                 char *_foo       /* nothing expected */ );
169 #endif
170 inline static int w_t_replicate_to(struct sip_msg* msg, char* str,char*);
171 inline static int w_t_forward_nonack(struct sip_msg* msg, char* str, char* );
172 inline static int w_t_forward_nonack_uri(struct sip_msg* msg, char* str,char*);
173 inline static int w_t_forward_nonack_udp(struct sip_msg* msg, char* str,char*);
174 #ifdef USE_TCP
175 inline static int w_t_forward_nonack_tcp(struct sip_msg* msg, char* str,char*);
176 #endif
177 #ifdef USE_TLS
178 inline static int w_t_forward_nonack_tls(struct sip_msg* msg, char* str,char*);
179 #endif
180 inline static int w_t_forward_nonack_to(struct sip_msg* msg, char* str,char*);
181 inline static int w_t_on_negative(struct sip_msg* msg, char *go_to, char *foo);
182 inline static int w_t_on_branch(struct sip_msg* msg, char *go_to, char *foo);
183 inline static int w_t_on_reply(struct sip_msg* msg, char *go_to, char *foo );
184 inline static int t_check_status(struct sip_msg* msg, char *regexp, char *foo);
185 static int t_set_fr_inv(struct sip_msg* msg, char* fr_inv, char* foo);
186 static int t_set_fr_all(struct sip_msg* msg, char* fr_inv, char* fr);
187 static int t_branch_timeout(struct sip_msg* msg, char*, char*);
188 static int t_branch_replied(struct sip_msg* msg, char*, char*);
189 static int t_any_timeout(struct sip_msg* msg, char*, char*);
190 static int t_any_replied(struct sip_msg* msg, char*, char*);
191 static int t_is_canceled(struct sip_msg* msg, char*, char*);
192
193
194 static char *fr_timer_param = FR_TIMER_AVP;
195 static char *fr_inv_timer_param = FR_INV_TIMER_AVP;
196
197 static rpc_export_t tm_rpc[];
198
199 static int default_code = 500;
200 static str default_reason = STR_STATIC_INIT("Server Internal Error");
201
202
203 static cmd_export_t cmds[]={
204         {"t_newtran",          w_t_newtran,             0, 0,
205                         REQUEST_ROUTE},
206         {"t_lookup_request",   w_t_check,               0, 0,
207                         REQUEST_ROUTE},
208         {"t_lookup_cancel",    w_t_lookup_cancel,     0, 0,
209                         REQUEST_ROUTE},
210         {T_REPLY,              w_t_reply,               2, fixup_t_reply,
211                         REQUEST_ROUTE | FAILURE_ROUTE },
212         {"t_retransmit_reply", w_t_retransmit_reply,    0, 0,
213                         REQUEST_ROUTE},
214         {"t_release",          w_t_release,             0, 0,
215                         REQUEST_ROUTE},
216         {T_RELAY_TO_UDP,       w_t_relay_to_udp,        2, fixup_hostport2proxy,
217                         REQUEST_ROUTE|FAILURE_ROUTE},
218 #ifdef USE_TCP
219         {T_RELAY_TO_TCP,       w_t_relay_to_tcp,        2, fixup_hostport2proxy,
220                         REQUEST_ROUTE|FAILURE_ROUTE},
221 #endif
222 #ifdef USE_TLS
223         {T_RELAY_TO_TLS,       w_t_relay_to_tls,        2, fixup_hostport2proxy,
224                         REQUEST_ROUTE|FAILURE_ROUTE},
225 #endif
226         {"t_replicate",        w_t_replicate,           2, fixup_hostport2proxy,
227                         REQUEST_ROUTE},
228         {"t_replicate_udp",    w_t_replicate_udp,       2, fixup_hostport2proxy,
229                         REQUEST_ROUTE},
230 #ifdef USE_TCP
231         {"t_replicate_tcp",    w_t_replicate_tcp,       2, fixup_hostport2proxy,
232                         REQUEST_ROUTE},
233 #endif
234 #ifdef USE_TLS
235         {"t_replicate_tls",    w_t_replicate_tls,       2, fixup_hostport2proxy,
236                         REQUEST_ROUTE},
237 #endif
238         {"t_replicate_to", w_t_replicate_to,            2, fixup_proto_hostport2proxy,
239                         REQUEST_ROUTE},
240         {T_RELAY,              w_t_relay,               0, 0,
241                         REQUEST_ROUTE | FAILURE_ROUTE },
242         {"t_relay_to", w_t_relay_to,                    2, fixup_proto_hostport2proxy,
243                         REQUEST_ROUTE},
244         {T_FORWARD_NONACK,     w_t_forward_nonack,      2, fixup_hostport2proxy,
245                         REQUEST_ROUTE},
246         {T_FORWARD_NONACK_URI, w_t_forward_nonack_uri,  0, 0,
247                         REQUEST_ROUTE},
248         {T_FORWARD_NONACK_UDP, w_t_forward_nonack_udp,  2, fixup_hostport2proxy,
249                         REQUEST_ROUTE},
250 #ifdef USE_TCP
251         {T_FORWARD_NONACK_TCP, w_t_forward_nonack_tcp,  2, fixup_hostport2proxy,
252                         REQUEST_ROUTE},
253 #endif
254 #ifdef USE_TLS
255         {T_FORWARD_NONACK_TLS, w_t_forward_nonack_tls,  2, fixup_hostport2proxy,
256                         REQUEST_ROUTE},
257 #endif
258         {"t_forward_nonack_to", w_t_forward_nonack_to,  2, fixup_proto_hostport2proxy,
259                         REQUEST_ROUTE},
260         {"t_on_failure",       w_t_on_negative,         1, fixup_on_failure,
261                         REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
262         {"t_on_reply",         w_t_on_reply,            1, fixup_on_reply,
263                         REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
264         {"t_on_branch",       w_t_on_branch,         1, fixup_on_branch,
265                         REQUEST_ROUTE | FAILURE_ROUTE },
266         {"t_check_status",     t_check_status,          1, fixup_regex_1,
267                         REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
268         {"t_write_req",       t_write_req,              2, fixup_t_write,
269                         REQUEST_ROUTE | FAILURE_ROUTE },
270         {"t_write_unix",      t_write_unix,             2, fixup_t_write,
271                         REQUEST_ROUTE | FAILURE_ROUTE },
272         {"t_set_fr",          t_set_fr_inv,             1, fixup_var_int_1,
273                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
274         {"t_set_fr",          t_set_fr_all,             2, fixup_var_int_12,
275                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
276         {"t_branch_timeout",  t_branch_timeout,         0, 0,  FAILURE_ROUTE},
277         {"t_branch_replied",  t_branch_replied,         0, 0,  FAILURE_ROUTE},
278         {"t_any_timeout",     t_any_timeout,            0, 0, 
279                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
280         {"t_any_replied",     t_any_replied,            0, 0, 
281                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
282         {"t_is_canceled",     t_is_canceled,            0, 0,
283                         REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
284
285         /* not applicable from the script */
286         {"register_tmcb",      (cmd_function)register_tmcb,     NO_SCRIPT,   0, 0},
287         {"load_tm",            (cmd_function)load_tm,           NO_SCRIPT,   0, 0},
288         {T_REPLY_WB,           (cmd_function)t_reply_with_body, NO_SCRIPT,   0, 0},
289         {T_IS_LOCAL,           (cmd_function)t_is_local,        NO_SCRIPT,   0, 0},
290         {T_GET_TI,             (cmd_function)t_get_trans_ident, NO_SCRIPT,   0, 0},
291         {T_LOOKUP_IDENT,       (cmd_function)t_lookup_ident,    NO_SCRIPT,   0, 0},
292         {T_ADDBLIND,           (cmd_function)add_blind_uac,     NO_SCRIPT,   0, 0},
293         {"t_request_within",   (cmd_function)req_within,        NO_SCRIPT,   0, 0},
294         {"t_request_outside",  (cmd_function)req_outside,       NO_SCRIPT,   0, 0},
295         {"t_request",          (cmd_function)request,           NO_SCRIPT,   0, 0},
296         {"new_dlg_uac",        (cmd_function)new_dlg_uac,       NO_SCRIPT,   0, 0},
297         {"dlg_response_uac",   (cmd_function)dlg_response_uac,  NO_SCRIPT,   0, 0},
298         {"new_dlg_uas",        (cmd_function)new_dlg_uas,       NO_SCRIPT,   0, 0},
299         {"dlg_request_uas",    (cmd_function)dlg_request_uas,   NO_SCRIPT,   0, 0},
300         {"free_dlg",           (cmd_function)free_dlg,          NO_SCRIPT,   0, 0},
301         {"print_dlg",          (cmd_function)print_dlg,         NO_SCRIPT,   0, 0},
302         {T_GETT,               (cmd_function)get_t,             NO_SCRIPT,   0, 0},
303         {"calculate_hooks",    (cmd_function)w_calculate_hooks, NO_SCRIPT,   0, 0},
304         {"t_uac",              (cmd_function)t_uac,             NO_SCRIPT,   0, 0},
305         {0,0,0,0,0}
306 };
307
308
309 static param_export_t params[]={
310         {"ruri_matching",       PARAM_INT, &ruri_matching                        },
311         {"via1_matching",       PARAM_INT, &via1_matching                        },
312         {"fr_timer",            PARAM_INT, &fr_timeout                           },
313         {"fr_inv_timer",        PARAM_INT, &fr_inv_timeout                       },
314         {"wt_timer",            PARAM_INT, &wait_timeout                         },
315         {"delete_timer",        PARAM_INT, &delete_timeout                       },
316         {"retr_timer1",         PARAM_INT, &rt_t1_timeout                        },
317         {"retr_timer2"  ,       PARAM_INT, &rt_t2_timeout                        },
318         {"noisy_ctimer",        PARAM_INT, &noisy_ctimer                         },
319         {"uac_from",            PARAM_STRING, &uac_from                          },
320         {"unix_tx_timeout",     PARAM_INT, &tm_unix_tx_timeout                   },
321         {"restart_fr_on_each_reply", PARAM_INT, &restart_fr_on_each_reply        },
322         {"fr_timer_avp",        PARAM_STRING, &fr_timer_param                    },
323         {"fr_inv_timer_avp",    PARAM_STRING, &fr_inv_timer_param                },
324         {"tw_append",           PARAM_STRING|PARAM_USE_FUNC, 
325                                                                                                         (void*)parse_tw_append   },
326         {"pass_provisional_replies", PARAM_INT, &pass_provisional_replies        },
327         {"aggregate_challenges", PARAM_INT, &tm_aggregate_auth                   },
328         {"default_code",        PARAM_INT, &default_code                         },
329         {"default_reason",      PARAM_STR, &default_reason                       },
330         {0,0,0}
331 };
332
333
334 #ifdef STATIC_TM
335 struct module_exports tm_exports = {
336 #else
337 struct module_exports exports= {
338 #endif
339         "tm",
340         /* -------- exported functions ----------- */
341         cmds,
342         tm_rpc,    /* RPC methods */
343         /* ------------ exported variables ---------- */
344         params,
345
346         mod_init, /* module initialization function */
347         (response_function) reply_received,
348         (destroy_function) tm_shutdown,
349         0, /* w_onbreak, */
350         child_init /* per-child init function */
351 };
352
353
354
355 /* helper for fixup_on_* */
356 static int fixup_routes(char* r_type, struct route_list* rt, void** param)
357 {
358         int i;
359         
360         i=route_get(rt, (char*)*param);
361         if (i==-1){
362                 LOG(L_ERR, "ERROR: tm: fixup_routes: route_get failed\n");
363                 return E_UNSPEC;
364         }
365         if (rt->rlist[i]==0){
366                 LOG(L_WARN, "WARNING: %s(\"%s\"): empty/non existing route\n",
367                                 r_type, (char*)*param);
368         }
369         *param=(void*)(long)i;
370         return 0;
371 }
372
373 static int fixup_t_reply(void** param, int param_no)
374 {
375         int ret;
376
377         if (param_no == 1) {
378                 ret = fix_param(FPARAM_AVP, param);
379                 if (ret <= 0) return ret;
380                 return fix_param(FPARAM_INT, param);
381         } else if (param_no == 2) {
382                 return fixup_var_str_12(param, 2);
383         }
384     return 0;
385 }
386
387 static int fixup_on_failure(void** param, int param_no)
388 {
389         if (param_no==1){
390                 return fixup_routes("t_on_failure", &failure_rt, param);
391         }
392         return 0;
393 }
394
395
396
397 static int fixup_on_reply(void** param, int param_no)
398 {
399         if (param_no==1){
400                 return fixup_routes("t_on_reply", &onreply_rt, param);
401         }
402         return 0;
403 }
404
405
406
407 static int fixup_on_branch(void** param, int param_no)
408 {
409         if (param_no==1){
410                 return fixup_routes("t_on_branch", &branch_rt, param);
411         }
412         return 0;
413 }
414
415
416
417 /* (char *hostname, char *port_nr) ==> (struct proxy_l *, -)  */
418 static int fixup_hostport2proxy(void** param, int param_no)
419 {
420         unsigned int port;
421         char *host;
422         int err;
423         struct proxy_l *proxy;
424         action_u_t *a;
425         str s;
426
427         DBG("TM module: fixup_hostport2proxy(%s, %d)\n", (char*)*param, param_no);
428         if (param_no==1){
429                 return 0;
430         } else if (param_no==2) {
431                 a = fixup_get_param(param, param_no, 1);
432                 host= a->u.string;
433                 port=str2s(*param, strlen(*param), &err);
434                 if (err!=0) {
435                         LOG(L_ERR, "TM module:fixup_hostport2proxy: bad port number <%s>\n",
436                                 (char*)(*param));
437                          return E_UNSPEC;
438                 }
439                 s.s = host;
440                 s.len = strlen(host);
441                 proxy=mk_proxy(&s, port, 0); /* FIXME: udp or tcp? */
442                 if (proxy==0) {
443                         LOG(L_ERR, "ERROR: fixup_hostport2proxy: bad host name in URI <%s>\n",
444                                 host );
445                         return E_BAD_ADDRESS;
446                 }
447                 /* success -- fix the first parameter to proxy now ! */
448
449                 a->u.data=proxy;
450                 return 0;
451         } else {
452                 LOG(L_ERR,"ERROR: fixup_hostport2proxy called with parameter #<>{1,2}\n");
453                 return E_BUG;
454         }
455 }
456
457 /* (char *$proto, char *$host:port) ==> (fparam, fparam)  */
458 static int fixup_proto_hostport2proxy(void** param, int param_no) {
459         int ret;
460
461         ret = fix_param(FPARAM_AVP, param);
462         if (ret <= 0) return ret;
463 /*      if (param_no = 1) {             FIXME: param_str currently does not offer INT/STR overloading
464                 ret = fix_param(FPARAM_INT, param);
465                 if (ret <= 0) return ret;
466         } */
467         return fix_param(FPARAM_STRING, param);
468 }
469
470
471 /***************************** init functions *****************************/
472 static int w_t_unref( struct sip_msg *foo, void *bar)
473 {
474         return t_unref(foo);
475 }
476
477
478 static int script_init( struct sip_msg *foo, void *bar)
479 {
480         /* we primarily reset all private memory here to make sure
481          * private values left over from previous message will
482          * not be used again */
483
484         /* make sure the new message will not inherit previous
485                 message's t_on_negative value
486         */
487         t_on_negative( 0 );
488         t_on_reply(0);
489         t_on_branch(0);
490         /* reset the kr status */
491         set_kr(0);
492         /* set request mode so that multiple-mode actions know
493          * how to behave */
494         rmode=MODE_REQUEST;
495         return 1;
496 }
497
498
499 static int mod_init(void)
500 {
501         DBG( "TM - (sizeof cell=%ld, sip_msg=%ld) initializing...\n",
502                         (long)sizeof(struct cell), (long)sizeof(struct sip_msg));
503         /* checking if we have sufficient bitmap capacity for given
504            maximum number of  branches */
505         if (MAX_BRANCHES+1>31) {
506                 LOG(L_CRIT, "Too many max UACs for UAC branch_bm_t bitmap: %d\n",
507                         MAX_BRANCHES );
508                 return -1;
509         }
510
511         if (init_callid() < 0) {
512                 LOG(L_CRIT, "Error while initializing Call-ID generator\n");
513                 return -1;
514         }
515
516         /* building the hash table*/
517         if (!init_hash_table()) {
518                 LOG(L_ERR, "ERROR: mod_init: initializing hash_table failed\n");
519                 return -1;
520         }
521
522         /* init static hidden values */
523         init_t();
524
525         if (tm_init_timers()==-1) {
526                 LOG(L_ERR, "ERROR: mod_init: timer init failed\n");
527                 return -1;
528         }
529
530              /* First tm_stat initialization function only allocates the top level stat
531               * structure in shared memory, the initialization will complete in child
532               * init with init_tm_stats_child when the final value of estimated_process_count is
533               * known
534               */
535         if (init_tm_stats() < 0) {
536                 LOG(L_CRIT, "ERROR: mod_init: failed to init stats\n");
537                 return -1;
538         }
539
540         if (uac_init()==-1) {
541                 LOG(L_ERR, "ERROR: mod_init: uac_init failed\n");
542                 return -1;
543         }
544
545         if (init_tmcb_lists()!=1) {
546                 LOG(L_CRIT, "ERROR:tm:mod_init: failed to init tmcb lists\n");
547                 return -1;
548         }
549         
550         tm_init_tags();
551         init_twrite_lines();
552         if (init_twrite_sock() < 0) {
553                 LOG(L_ERR, "ERROR:tm:mod_init: Unable to create socket\n");
554                 return -1;
555         }
556
557         /* register post-script clean-up function */
558         if (register_script_cb( w_t_unref, POST_SCRIPT_CB|REQ_TYPE_CB, 0)<0 ) {
559                 LOG(L_ERR,"ERROR:tm:mod_init: failed to register POST request "
560                         "callback\n");
561                 return -1;
562         }
563         if (register_script_cb( script_init, PRE_SCRIPT_CB|REQ_TYPE_CB , 0)<0 ) {
564                 LOG(L_ERR,"ERROR:tm:mod_init: failed to register PRE request "
565                         "callback\n");
566                 return -1;
567         }
568
569         if (init_avp_params( fr_timer_param, fr_inv_timer_param)<0 ){
570                 LOG(L_ERR,"ERROR:tm:mod_init: failed to process timer AVPs\n");
571                 return -1;
572         }
573
574         tm_init = 1;
575         return 0;
576 }
577
578 static int child_init(int rank) {
579         if (child_init_callid(rank) < 0) {
580                 LOG(L_ERR, "ERROR: child_init: Error while initializing Call-ID generator\n");
581                 return -2;
582         }
583
584         if (rank == 1) {
585                 if (init_tm_stats_child() < 0) {
586                         ERR("Error while initializing tm statistics structures\n");
587                         return -1;
588                 }
589         }
590
591         return 0;
592 }
593
594
595
596
597
598 /**************************** wrapper functions ***************************/
599 static int t_check_status(struct sip_msg* msg, char *p1, char *foo)
600 {
601         regmatch_t pmatch;
602         struct cell *t;
603         char *status;
604         char backup;
605         int lowest_status;
606         int n;
607
608         /* first get the transaction */
609         if (t_check( msg , 0 )==-1) return -1;
610         if ( (t=get_t())==0) {
611                 LOG(L_ERR, "ERROR: t_check_status: cannot check status for a reply "
612                         "which has no T-state established\n");
613                 return -1;
614         }
615         backup = 0;
616
617         switch (rmode) {
618                 case MODE_REQUEST:
619                         /* use the status of the last sent reply */
620                         status = int2str( t->uas.status, 0);
621                         break;
622                 case MODE_ONREPLY:
623                         /* use the status of the current reply */
624                         status = msg->first_line.u.reply.status.s;
625                         backup = status[msg->first_line.u.reply.status.len];
626                         status[msg->first_line.u.reply.status.len] = 0;
627                         break;
628                 case MODE_ONFAILURE:
629                         /* use the status of the winning reply */
630                         if (t_pick_branch( -1, 0, t, &lowest_status)<0 ) {
631                                 LOG(L_CRIT,"BUG:t_check_status: t_pick_branch failed to get "
632                                         " a final response in MODE_ONFAILURE\n");
633                                 return -1;
634                         }
635                         status = int2str( lowest_status , 0);
636                         break;
637                 default:
638                         LOG(L_ERR,"ERROR:t_check_status: unsupported mode %d\n",rmode);
639                         return -1;
640         }
641
642         DBG("DEBUG:t_check_status: checked status is <%s>\n",status);
643         /* do the checking */
644         n = regexec(((fparam_t*)p1)->v.regex, status, 1, &pmatch, 0);
645
646         if (backup) status[msg->first_line.u.reply.status.len] = backup;
647         if (n!=0) return -1;
648         return 1;
649 }
650
651
652 inline static int w_t_check(struct sip_msg* msg, char* str, char* str2)
653 {
654         return t_check( msg , 0  ) ? 1 : -1;
655 }
656
657 inline static int w_t_lookup_cancel(struct sip_msg* msg, char* str, char* str2)
658 {
659         struct cell *ret;
660         if (msg->REQ_METHOD==METHOD_CANCEL) {
661                 ret = t_lookupOriginalT( msg );
662                 DBG("lookup_original: t_lookupOriginalT returned: %p\n", ret);
663                 if (ret != T_NULL_CELL) {
664                         /* The cell is reffed by t_lookupOriginalT, but T is not set.
665                         So we must unref it before returning. */
666                         UNREF(ret);
667                         return 1;
668                 }
669         } else {
670                 LOG(L_WARN, "WARNING: script error t_lookup_cancel() called for non-CANCEL request\n");
671         }
672         return -1;
673 }
674
675 inline static int str2proto(char *s, int len) {
676         if (len == 3 && !strncasecmp(s, "udp", 3))
677                 return PROTO_UDP;
678         else if (len == 3 && !strncasecmp(s, "tcp", 3))  /* tcp&tls checks will be passed in getproto() */
679                 return PROTO_TCP;
680         else if (len == 3 && !strncasecmp(s, "tls", 3))
681                 return PROTO_TLS;       
682         else
683                 return PROTO_NONE;
684 }
685
686 inline static struct proxy_l* t_protoaddr2proxy(char *proto_par, char *addr_par) {
687         struct proxy_l *proxy = 0;
688         avp_t* avp;
689         avp_value_t val;
690         int proto, port, err;
691         str s;
692         char *c;
693         
694         switch(((fparam_t *)proto_par)->type) {
695         case FPARAM_AVP:
696                 if (!(avp = search_first_avp(((fparam_t *)proto_par)->v.avp.flags, ((fparam_t *)proto_par)->v.avp.name, &val, 0))) {
697                         proto = PROTO_NONE;
698                 } else {
699                         if (avp->flags & AVP_VAL_STR) {
700                                 proto = str2proto(val.s.s, val.s.len);
701                         }
702                         else {
703                                 proto = val.n;
704                         }
705                 }
706                 break;
707
708         case FPARAM_INT:
709                 proto = ((fparam_t *)proto_par)->v.i;
710                 break;
711         case FPARAM_STRING:
712                 proto = str2proto( ((fparam_t *)proto_par)->v.asciiz, strlen(((fparam_t *)proto_par)->v.asciiz));
713                 break;
714         default:
715                 ERR("BUG: Invalid proto parameter value in t_protoaddr2proxy\n");
716                 return 0;
717         }
718
719
720         switch(((fparam_t *)addr_par)->type) {
721         case FPARAM_AVP:
722                 if (!(avp = search_first_avp(((fparam_t *)addr_par)->v.avp.flags, ((fparam_t *)addr_par)->v.avp.name, &val, 0))) {
723                         s.len = 0;
724                 } else {
725                         if ((avp->flags & AVP_VAL_STR) == 0) {
726                                 LOG(L_ERR, "tm:t_protoaddr2proxy: avp <%.*s> value is not string\n",
727                                         ((fparam_t *)addr_par)->v.avp.name.s.len, ((fparam_t *)addr_par)->v.avp.name.s.s);
728                                 return 0;
729                         }
730                         s = val.s;
731                 }
732                 break;
733
734         case FPARAM_STRING:
735                 s.s = ((fparam_t *) addr_par)->v.asciiz;
736                 s.len = strlen(s.s);
737                 break;
738
739         default:
740                 ERR("BUG: Invalid addr parameter value in t_protoaddr2proxy\n");
741                 return 0;
742         }
743
744         port = 5060;
745         if (s.len) {
746                 c = memchr(s.s, ':', s.len);
747                 if (c) {
748                         port = str2s(c+1, s.len-(c-s.s+1), &err);
749                         if (err!=0) {
750                                 LOG(L_ERR, "tm:t_protoaddr2proxy: bad port number <%.*s>\n",
751                                         s.len, s.s);
752                                  return 0;
753                         }
754                         s.len = c-s.s;
755                 }
756         }
757         if (!s.len) {
758                 LOG(L_ERR, "tm: protoaddr2proxy: host name is empty\n");
759                 return 0;
760         }
761         proxy=mk_proxy(&s, port, proto);
762         if (proxy==0) {
763                 LOG(L_ERR, "tm: protoaddr2proxy: bad host name in URI <%.*s>\n",
764                         s.len, s.s );
765                 return 0;
766         }
767         return proxy;
768 }
769
770 inline static int _w_t_forward_nonack(struct sip_msg* msg, struct proxy_l* proxy,
771         int proto)
772 {
773         struct cell *t;
774         if (t_check( msg , 0 )==-1) {
775                 LOG(L_ERR, "ERROR: forward_nonack: "
776                                 "can't forward when no transaction was set up\n");
777                 return -1;
778         }
779         t=get_t();
780         if ( t && t!=T_UNDEFINED ) {
781                 if (msg->REQ_METHOD==METHOD_ACK) {
782                         LOG(L_WARN,"WARNING: you don't really want to fwd hbh ACK\n");
783                         return -1;
784                 }
785                 return t_forward_nonack(t, msg, proxy, proto );
786         } else {
787                 DBG("DEBUG: forward_nonack: no transaction found\n");
788                 return -1;
789         }
790 }
791
792
793 inline static int w_t_forward_nonack( struct sip_msg* msg, char* proxy,
794                                                                                 char* foo)
795 {
796         return _w_t_forward_nonack(msg, ( struct proxy_l *) proxy, PROTO_NONE);
797 }
798
799
800 inline static int w_t_forward_nonack_uri(struct sip_msg* msg, char *foo,
801                                                                                                                                         char *bar)
802 {
803         return _w_t_forward_nonack(msg, 0, PROTO_NONE);
804 }
805
806
807 inline static int w_t_forward_nonack_udp( struct sip_msg* msg, char* proxy,
808                                                                                 char* foo)
809 {
810         return _w_t_forward_nonack(msg, ( struct proxy_l *) proxy, PROTO_UDP);
811 }
812
813
814 #ifdef USE_TCP
815 inline static int w_t_forward_nonack_tcp( struct sip_msg* msg, char* proxy,
816                                                                                 char* foo)
817 {
818         return _w_t_forward_nonack(msg, ( struct proxy_l *) proxy, PROTO_TCP);
819 }
820 #endif
821
822
823 #ifdef USE_TLS
824 inline static int w_t_forward_nonack_tls( struct sip_msg* msg, char* proxy,
825                                                                                 char* foo)
826 {
827         return _w_t_forward_nonack(msg, ( struct proxy_l *) proxy, PROTO_TLS);
828 }
829 #endif
830
831 inline static int w_t_forward_nonack_to( struct sip_msg  *p_msg ,
832         char *proto_par, 
833         char *addr_par   )
834 {
835         struct proxy_l *proxy;
836         int r = -1;
837         proxy = t_protoaddr2proxy(proto_par, addr_par);
838         if (proxy) {
839                 r = _w_t_forward_nonack(p_msg, proxy, proxy->proto);            
840                 free_proxy(proxy);
841         }
842         return r;
843 }
844
845
846 inline static int w_t_reply(struct sip_msg* msg, char* p1, char* p2)
847 {
848         struct cell *t;
849         int code, ret = -1;
850         str reason;
851         char* r;
852
853         if (msg->REQ_METHOD==METHOD_ACK) {
854                 LOG(L_WARN, "WARNING: t_reply: ACKs are not replied\n");
855                 return -1;
856         }
857         if (t_check( msg , 0 )==-1) return -1;
858         t=get_t();
859         if (!t) {
860                 LOG(L_ERR, "ERROR: t_reply: cannot send a t_reply to a message "
861                         "for which no T-state has been established\n");
862                 return -1;
863         }
864
865         if (get_int_fparam(&code, msg, (fparam_t*)p1) < 0) {
866             code = default_code;
867         }
868         
869         if (get_str_fparam(&reason, msg, (fparam_t*)p2) < 0) {
870             reason = default_reason;
871         }
872         
873         r = as_asciiz(&reason);
874         if (r == NULL) r = default_reason.s;
875         
876         /* if called from reply_route, make sure that unsafe version
877          * is called; we are already in a mutex and another mutex in
878          * the safe version would lead to a deadlock
879          */
880          
881         if (rmode==MODE_ONFAILURE) {
882                 DBG("DEBUG: t_reply_unsafe called from w_t_reply\n");
883                 ret = t_reply_unsafe(t, msg, code, r);
884         } else if (rmode==MODE_REQUEST) {
885                 ret = t_reply( t, msg, code, r);
886         } else {
887                 LOG(L_CRIT, "BUG: w_t_reply entered in unsupported mode\n");
888                 ret = -1;
889         }
890
891         if (r) pkg_free(r);
892         return ret;
893 }
894
895
896 inline static int w_t_release(struct sip_msg* msg, char* str, char* str2)
897 {
898         struct cell *t;
899         if (t_check( msg  , 0  )==-1) return -1;
900         t=get_t();
901         if ( t && t!=T_UNDEFINED )
902                 return t_release_transaction( t );
903         return 1;
904 }
905
906
907 inline static int w_t_retransmit_reply( struct sip_msg* p_msg, char* foo, char* bar)
908 {
909         struct cell *t;
910
911
912         if (t_check( p_msg  , 0 )==-1)
913                 return 1;
914         t=get_t();
915         if (t) {
916                 if (p_msg->REQ_METHOD==METHOD_ACK) {
917                         LOG(L_WARN, "WARNING: : ACKs transmit_replies not replied\n");
918                         return -1;
919                 }
920                 return t_retransmit_reply( t );
921         } else
922                 return -1;
923 }
924
925
926 inline static int w_t_newtran( struct sip_msg* p_msg, char* foo, char* bar )
927 {
928         /* t_newtran returns 0 on error (negative value means
929            'transaction exists' */
930         int ret;
931         ret = t_newtran( p_msg );
932         if (ret==E_SCRIPT) {
933                 LOG(L_ERR, "ERROR: t_newtran: "
934                         "transaction already in process %p\n", get_t() );
935         }
936         return ret;
937 }
938
939
940 inline static int w_t_on_negative( struct sip_msg* msg, char *go_to, char *foo)
941 {
942         t_on_negative( (unsigned int )(long) go_to );
943         return 1;
944 }
945
946 inline static int w_t_on_branch( struct sip_msg* msg, char *go_to, char *foo)
947 {
948         t_on_branch( (unsigned int )(long) go_to );
949         return 1;
950 }
951
952
953 inline static int w_t_on_reply( struct sip_msg* msg, char *go_to, char *foo )
954 {
955         t_on_reply( (unsigned int )(long) go_to );
956         return 1;
957 }
958
959
960
961 inline static int _w_t_relay_to( struct sip_msg  *p_msg ,
962         struct proxy_l *proxy )
963 {
964         struct cell *t;
965
966         if (rmode==MODE_ONFAILURE) {
967                 t=get_t();
968                 if (!t || t==T_UNDEFINED) {
969                         LOG(L_CRIT, "BUG: w_t_relay_to: undefined T\n");
970                         return -1;
971                 }
972                 if (t_forward_nonack(t, p_msg, proxy, PROTO_NONE)<=0 ) {
973                         LOG(L_ERR, "ERROR: w_t_relay_to: t_relay_to failed\n");
974                         return -1;
975                 }
976                 return 1;
977         }
978         if (rmode==MODE_REQUEST)
979                 return t_relay_to( p_msg, proxy, PROTO_NONE,
980                         0 /* no replication */ );
981         LOG(L_CRIT, "ERROR: w_t_relay_to: unsupported mode: %d\n", rmode);
982         return 0;
983 }
984
985
986 inline static int w_t_relay_to_udp( struct sip_msg  *p_msg ,
987         char *proxy, /* struct proxy_l *proxy expected */
988         char *_foo       /* nothing expected */ )
989 {
990         ((struct proxy_l *)proxy)->proto=PROTO_UDP;
991         return _w_t_relay_to( p_msg, ( struct proxy_l *) proxy);
992 }
993
994
995 #ifdef USE_TCP
996 inline static int w_t_relay_to_tcp( struct sip_msg  *p_msg ,
997         char *proxy, /* struct proxy_l *proxy expected */
998         char *_foo       /* nothing expected */ )
999 {
1000         ((struct proxy_l *)proxy)->proto=PROTO_TCP;
1001         return _w_t_relay_to( p_msg, ( struct proxy_l *) proxy);
1002 }
1003 #endif
1004
1005
1006 #ifdef USE_TLS
1007 inline static int w_t_relay_to_tls( struct sip_msg  *p_msg ,
1008         char *proxy, /* struct proxy_l *proxy expected */
1009         char *_foo       /* nothing expected */ )
1010 {
1011         ((struct proxy_l *)proxy)->proto=PROTO_TLS;
1012         return _w_t_relay_to( p_msg, ( struct proxy_l *) proxy);
1013 }
1014 #endif
1015
1016 inline static int w_t_relay_to( struct sip_msg  *p_msg ,
1017         char *proto_par, 
1018         char *addr_par   )
1019 {
1020         struct proxy_l *proxy;
1021         int r = -1;
1022         proxy = t_protoaddr2proxy(proto_par, addr_par);
1023         if (proxy) {
1024                 r = _w_t_relay_to(p_msg, proxy);                
1025                 free_proxy(proxy);
1026         }
1027         return r;
1028 }
1029
1030
1031 inline static int w_t_replicate( struct sip_msg  *p_msg ,
1032         char *proxy, /* struct proxy_l *proxy expected */
1033         char *_foo       /* nothing expected */ )
1034 {
1035         return t_replicate(p_msg, ( struct proxy_l *) proxy, p_msg->rcv.proto );
1036 }
1037
1038 inline static int w_t_replicate_udp( struct sip_msg  *p_msg ,
1039         char *proxy, /* struct proxy_l *proxy expected */
1040         char *_foo       /* nothing expected */ )
1041 {
1042         return t_replicate(p_msg, ( struct proxy_l *) proxy, PROTO_UDP );
1043 }
1044
1045
1046 #ifdef USE_TCP
1047 inline static int w_t_replicate_tcp( struct sip_msg  *p_msg ,
1048         char *proxy, /* struct proxy_l *proxy expected */
1049         char *_foo       /* nothing expected */ )
1050 {
1051         return t_replicate(p_msg, ( struct proxy_l *) proxy, PROTO_TCP );
1052 }
1053 #endif
1054
1055
1056 #ifdef USE_TLS
1057 inline static int w_t_replicate_tls( struct sip_msg  *p_msg ,
1058         char *proxy, /* struct proxy_l *proxy expected */
1059         char *_foo       /* nothing expected */ )
1060 {
1061         return t_replicate(p_msg, ( struct proxy_l *) proxy, PROTO_TLS );
1062 }
1063 #endif
1064
1065 inline static int w_t_replicate_to( struct sip_msg  *p_msg ,
1066         char *proto_par, 
1067         char *addr_par   )
1068 {
1069         struct proxy_l *proxy;
1070         int r = -1;
1071         proxy = t_protoaddr2proxy(proto_par, addr_par);
1072         if (proxy) {
1073                 r = t_replicate(p_msg, proxy, proxy->proto);            
1074                 free_proxy(proxy);
1075         }
1076         return r;
1077 }
1078
1079 inline static int w_t_relay( struct sip_msg  *p_msg ,
1080                                                 char *_foo, char *_bar)
1081 {
1082         struct cell *t;
1083
1084         if (rmode==MODE_ONFAILURE) {
1085                 t=get_t();
1086                 if (!t || t==T_UNDEFINED) {
1087                         LOG(L_CRIT, "BUG: w_t_relay: undefined T\n");
1088                         return -1;
1089                 }
1090                 if (t_forward_nonack(t, p_msg, ( struct proxy_l *) 0, PROTO_NONE)<=0) {
1091                         LOG(L_ERR, "ERROR: w_t_relay (failure mode): forwarding failed\n");
1092                         return -1;
1093                 }
1094                 return 1;
1095         }
1096         if (rmode==MODE_REQUEST)
1097                 return t_relay_to( p_msg,
1098                 (struct proxy_l *) 0 /* no proxy */, PROTO_NONE,
1099                 0 /* no replication */ );
1100         LOG(L_CRIT, "ERROR: w_t_relay_to: unsupported mode: %d\n", rmode);
1101         return 0;
1102 }
1103
1104 /* set fr_inv_timeout & or fr_timeout; 0 means: use the default value */
1105 static int t_set_fr_all(struct sip_msg* msg, char* p1, char* p2)
1106 {
1107     int fr, fr_inv;
1108
1109     if (get_int_fparam(&fr_inv, msg, (fparam_t*)p1) < 0) return -1;
1110     if (p2) {
1111         if (get_int_fparam(&fr, msg, (fparam_t*)p2) < 0) return -1;
1112     } else {
1113         fr = 0;
1114     }
1115
1116     return t_set_fr(msg, fr_inv, fr);
1117 }
1118
1119 static int t_set_fr_inv(struct sip_msg* msg, char* fr_inv, char* foo)
1120 {
1121         return t_set_fr_all(msg, fr_inv, (char*)0);
1122 }
1123
1124
1125
1126 /* script function, FAILURE_ROUTE only, returns true if the 
1127  * choosed "failure" branch failed because of a timeout, 
1128  * -1 otherwise */
1129 int t_branch_timeout(struct sip_msg* msg, char* foo, char* bar)
1130 {
1131         return (msg->msg_flags & FL_TIMEOUT)?1:-1;
1132 }
1133
1134
1135
1136 /* script function, FAILURE_ROUTE only, returns true if the 
1137  * choosed "failure" branch ever received a reply, -1 otherwise */
1138 int t_branch_replied(struct sip_msg* msg, char* foo, char* bar)
1139 {
1140         return (msg->msg_flags & FL_REPLIED)?1:-1;
1141 }
1142
1143
1144
1145 /* script function, returns: 1 if the transaction was canceled, -1 if not */
1146 int t_is_canceled(struct sip_msg* msg, char* foo, char* bar)
1147 {
1148         struct cell *t;
1149         int ret;
1150         
1151         
1152         if (t_check( msg , 0 )==-1) return -1;
1153         t=get_t();
1154         if ((t==0) || (t==T_UNDEFINED)){
1155                 LOG(L_ERR, "ERROR: t_is_canceled: cannot check a message "
1156                         "for which no T-state has been established\n");
1157                 ret=-1;
1158         }else{
1159                 ret=(t->flags & T_CANCELED)?1:-1;
1160         }
1161         return ret;
1162 }
1163
1164
1165
1166 /* script function, returns: 1 if any of the branches did timeout, -1 if not */
1167 int t_any_timeout(struct sip_msg* msg, char* foo, char* bar)
1168 {
1169         struct cell *t;
1170         int r;
1171         
1172         if (t_check( msg , 0 )==-1) return -1;
1173         t=get_t();
1174         if ((t==0) || (t==T_UNDEFINED)){
1175                 LOG(L_ERR, "ERROR: t_any_timeout: cannot check a message "
1176                         "for which no T-state has been established\n");
1177                 return -1;
1178         }else{
1179                 for (r=0; r<t->nr_of_outgoings; r++){
1180                         if (t->uac[r].request.flags & F_RB_TIMEOUT)
1181                                 return 1;
1182                 }
1183         }
1184         return -1;
1185 }
1186
1187
1188
1189 /* script function, returns: 1 if any of the branches received at leat one
1190  * reply, -1 if not */
1191 int t_any_replied(struct sip_msg* msg, char* foo, char* bar)
1192 {
1193         struct cell *t;
1194         int r;
1195         
1196         if (t_check( msg , 0 )==-1) return -1;
1197         t=get_t();
1198         if ((t==0) || (t==T_UNDEFINED)){
1199                 LOG(L_ERR, "ERROR: t_any_replied: cannot check a message "
1200                         "for which no T-state has been established\n");
1201                 return -1;
1202         }else{
1203                 for (r=0; r<t->nr_of_outgoings; r++){
1204                         if (t->uac[r].request.flags & F_RB_REPLIED)
1205                                 return 1;
1206                 }
1207         }
1208         return -1;
1209 }
1210
1211
1212
1213 static rpc_export_t tm_rpc[] = {
1214         {"tm.cancel", rpc_cancel,   rpc_cancel_doc,   0},
1215         {"tm.reply",  rpc_reply,    rpc_reply_doc,    0},
1216         {"tm.stats",  tm_rpc_stats, tm_rpc_stats_doc, 0},
1217         {0, 0, 0, 0}
1218 };
1219
1220 /* wrapper function needed after changes in w_t_reply */
1221 int w_t_reply_wrp(struct sip_msg *m, unsigned int code, char *txt)
1222 {
1223         fparam_t c;
1224         fparam_t r;
1225         
1226         c.type = FPARAM_INT;
1227         c.orig = NULL; /* ? */
1228         c.v.i = code;
1229         
1230         r.type = FPARAM_STRING;
1231         r.orig = NULL; /* ? */
1232         r.v.asciiz = txt;
1233
1234         return w_t_reply(m, (char *)&c, (char*)&r);
1235 }
1236