43ed5463e42cbb8e9a1e2ac3e1d535dca0ce76ed
[sip-router] / modules / tm / t_funcs.c
1 /*
2  * $Id$
3  *
4  * transaction maintenance functions
5  */
6
7 #include <limits.h>
8 #include "../../dprint.h"
9 #include "../../config.h"
10 #include "../../parser/parser_f.h"
11 #include "../../ut.h"
12 #include "../../hash_func.h"
13 #include "../../dset.h"
14 #include "t_funcs.h"
15 #include "t_fwd.h"
16 #include "t_lookup.h"
17 #include "config.h"
18
19
20 /* ----------------------------------------------------- */
21
22 int send_pr_buffer( struct retr_buf *rb,
23         void *buf, int len, char *function, int line )
24 {
25         if (buf && len && rb )
26                 return udp_send( rb->send_sock, buf, len, &rb->to) ;
27         else {
28                 LOG(L_CRIT, "ERROR: sending an empty buffer from %s (%d)\n",
29                         function, line );
30                 return -1;
31         }
32 }
33
34 void start_retr( struct retr_buf *rb )
35 {
36         rb->retr_list=RT_T1_TO_1;
37         set_timer( &rb->retr_timer, RT_T1_TO_1 );
38         set_timer( &rb->fr_timer, FR_TIMER_LIST );
39 }
40
41
42
43
44
45 void tm_shutdown()
46 {
47
48         DBG("DEBUG: tm_shutdown : start\n");
49         unlink_timer_lists();
50
51         /* destroy the hash table */
52         DBG("DEBUG: tm_shutdown : empting hash table\n");
53         free_hash_table( );
54         DBG("DEBUG: tm_shutdown: releasing timers\n");
55         free_timer_table();
56         DBG("DEBUG: tm_shutdown : removing semaphores\n");
57         lock_cleanup();
58         DBG("DEBUG: tm_shutdown : done\n");
59 }
60
61
62 /*   returns 1 if everything was OK or -1 for error
63 */
64 int t_release_transaction( struct cell *trans )
65 {
66         trans->kr|=REQ_RLSD;
67
68         reset_timer( & trans->uas.response.fr_timer );
69         reset_timer( & trans->uas.response.retr_timer );
70
71         cleanup_uac_timers( trans );
72         
73         put_on_wait( trans );
74         return 1;
75 }
76
77
78 /* ----------------------------HELPER FUNCTIONS-------------------------------- */
79
80
81 /*
82   */
83 void put_on_wait(  struct cell  *Trans  )
84 {
85
86 #ifdef _XWAIT
87         LOCK_WAIT(Trans);
88         if (Trans->on_wait)
89         {
90                 DBG("DEBUG: t_put_on_wait: already on wait\n");
91                 UNLOCK_WAIT(Trans);
92         } else {
93                 Trans->on_wait=1;
94                 UNLOCK_WAIT(Trans);
95         }
96 #endif
97 #ifdef EXTRA_DEBUG
98         DBG("DEBUG: --- out on WAIT --- \n");
99 #endif
100
101
102         /* we put the transaction on wait timer; we do it only once
103            in transaction's timelife because putting it multiple-times
104            might result in a second instance of a wait timer to be
105            set after the first one fired; on expiration of the second
106            instance, the transaction would be re-deleted
107
108                         PROCESS1                PROCESS2                TIMER PROCESS
109                 0. 200/INVITE rx;
110                    put_on_wait
111                 1.                                      200/INVITE rx;
112                 2.                                                                      WAIT fires; transaction
113                                                                                         about to be deleted
114                 3.                                      avoid putting
115                                                         on WAIT again
116                 4.                                                                      WAIT timer executed,
117                                                                                         transaction deleted
118         */
119         set_1timer( &Trans->wait_tl, WT_TIMER_LIST );
120 }
121
122
123
124 static int kill_transaction( struct cell *trans )
125 {
126         char err_buffer[128];
127         int sip_err;
128         int reply_ret;
129         int ret;
130
131         /*  we reply statefuly and enter WAIT state since error might
132                 have occured in middle of forking and we do not
133                 want to put the forking burden on upstream client;
134                 howver, it may fail too due to lack of memory */
135
136         ret=err2reason_phrase( ser_error, &sip_err,
137                 err_buffer, sizeof(err_buffer), "TM" );
138         if (ret>0) {
139                 reply_ret=t_reply( trans, trans->uas.request, 
140                         sip_err, err_buffer);
141                 /* t_release_transaction( T ); */
142                 return reply_ret;
143         } else {
144                 LOG(L_ERR, "ERROR: kill_transaction: err2reason failed\n");
145                 return -1;
146         }
147 }
148
149
150
151 int t_relay_to( struct sip_msg  *p_msg , struct proxy_l *proxy,
152         int replicate)
153 {
154         int ret;
155         int new_tran;
156         str *uri;
157         int reply_ret;
158         /* struct hdr_field *hdr; */
159         struct cell *t;
160 #ifdef ACK_FORKING_HACK
161         str ack_uri;
162         str backup_uri;
163 #endif
164
165         ret=0;
166
167         new_tran = t_newtran( p_msg );
168         
169
170         /* parsing error, memory alloc, whatever ... if via is bad
171            and we are forced to reply there, return with 0 (->break),
172            pass error status otherwise
173         */
174         if (new_tran<0) {
175                 ret = (ser_error==E_BAD_VIA && reply_to_via) ? 0 : new_tran;
176                 goto done;
177         }
178         /* if that was a retransmission, return we are happily done */
179         if (new_tran==0) {
180                 ret = 1;
181                 goto done;
182         }
183
184         /* new transaction */
185
186         /* ACKs do not establish a transaction and are fwd-ed statelessly */
187         if ( p_msg->REQ_METHOD==METHOD_ACK) {
188                 DBG( "SER: forwarding ACK  statelessly \n");
189                 if (proxy==0) {
190                         uri=(p_msg->new_uri.s==0 || p_msg->new_uri.len==0) ?
191                                 &p_msg->first_line.u.request.uri :
192                                 &p_msg->new_uri;
193                         proxy=uri2proxy( uri );
194                         if (proxy==0) {
195                                         ret=E_BAD_ADDRESS;
196                                         goto done;
197                         }
198                         ret=forward_request( p_msg , proxy ) ;
199                         free_proxy( proxy );    
200                         free( proxy );
201 #ifdef ACK_FORKING_HACK
202                         backup_uri=p_msg->new_uri;
203                         init_branch_iterator();
204                         while((ack_uri.s=next_branch(&ack_uri.len))) {
205                                 p_msg->new_uri=ack_uri;
206                                 proxy=uri2proxy(ack_uri);
207                                 if (proxy==0) continue;
208                                 forward_request(p_msg, proxy);
209                                 free_proxy( proxy );    
210                                 free( proxy );
211                         }
212                         p_msg->new_uri=backup_uri;
213 #endif
214                 } else {
215                         ret=forward_request( p_msg , proxy ) ;
216 #ifdef ACK_FORKING_HACK
217                         backup_uri=p_msg->new_uri;
218                         init_branch_iterator();
219                         while((ack_uri.s=next_branch(&ack_uri.len))) {
220                                 p_msg->new_uri=ack_uri;
221                                 forward_request(p_msg, proxy);
222                         }
223                         p_msg->new_uri=backup_uri;
224 #endif
225                 }
226                 goto done;
227         }
228
229         /* if replication flag is set, mark the transaction as local
230            so that replies will not be relaied
231         */
232         t=get_t();
233         t->local=replicate;
234
235         /* INVITE processing might take long, partcularly because of DNS
236            look-ups -- let upstream know we're working on it */
237         if (p_msg->REQ_METHOD==METHOD_INVITE )
238         {
239                 DBG( "SER: new INVITE\n");
240                 if (!t_reply( t, p_msg , 100 ,
241                         "trying -- your call is important to us"))
242                                 DBG("SER: ERROR: t_reply (100)\n");
243         } 
244
245         /* now go ahead and forward ... */
246         ret=t_forward_nonack(t, p_msg, proxy);
247         if (ret<=0) {
248                 DBG( "SER:ERROR: t_forward \n");
249                 reply_ret=kill_transaction( t );
250                 if (reply_ret>0) {
251                         /* we have taken care of all -- do nothing in
252                         script */
253                         DBG("ERROR: generation of a stateful reply "
254                                 "on error succeeded\n");
255                         ret=0;
256                 }  else {
257                         DBG("ERROR: generation of a stateful reply "
258                                 "on error failed\n");
259                 }
260         } else {
261                 DBG( "SER: new transaction fwd'ed\n");
262         }
263
264 done:
265         return ret;
266 }