- added flags to tm onsend callbacks that should tell if the callbacks is
[sip-router] / modules / tm / t_cancel.c
1 /*
2  * $Id$
3  *
4  *
5  * Copyright (C) 2001-2003 FhG Fokus
6  *
7  * This file is part of ser, a free SIP server.
8  *
9  * ser is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version
13  *
14  * For a license to use the ser software under conditions
15  * other than those described here, or to purchase support for this
16  * software, please contact iptel.org by e-mail at the following addresses:
17  *    info@iptel.org
18  *
19  * ser is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License 
25  * along with this program; if not, write to the Free Software 
26  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27  *
28  * History:
29  * ----------
30  * 2003-04-14  checking if a reply sent before cancel is initiated
31  *             moved here (jiri)
32  * 2004-02-11  FIFO/CANCEL + alignments (hash=f(callid,cseq)) (uli+jiri)
33  * 2004-02-13  timer_link.payload removed (bogdan)
34  * 2006-10-10  cancel_uacs  & cancel_branch take more options now (andrei)
35  * 2007-03-15  TMCB_ONSEND hooks added (andrei)
36  */
37
38 #include <stdio.h> /* for FILE* in fifo_uac_cancel */
39
40 #include "defs.h"
41
42
43 #include "t_funcs.h"
44 #include "../../dprint.h"
45 #include "../../ut.h"
46 #include "t_reply.h"
47 #include "t_cancel.h"
48 #include "t_msgbuilder.h"
49 #include "t_lookup.h" /* for t_lookup_callid in fifo_uac_cancel */
50 #include "t_hooks.h"
51
52
53 /* determine which branches should be canceled; do it
54    only from within REPLY_LOCK, otherwise collisions
55    could occur (e.g., two 200 for two branches processed
56    by two processes might concurrently try to generate
57    a CANCEL for the third branch, resulting in race conditions
58    during writing to cancel buffer
59  WARNING: - has side effects, see should_cancel_branch() */
60 void which_cancel( struct cell *t, branch_bm_t *cancel_bm )
61 {
62         int i;
63         
64         *cancel_bm=0;
65         for( i=0 ; i<t->nr_of_outgoings ; i++ ) {
66                 if (should_cancel_branch(t, i)) 
67                         *cancel_bm |= 1<<i ;
68
69         }
70 }
71
72
73
74
75 /* cancel branches scheduled for deletion
76  * params: t          - transaction
77  *          cancel_bm - bitmap with the branches that are supposed to be 
78  *                       canceled 
79  *          flags     - how_to_cancel flags, see cancel_branch()
80  * returns: bitmap with the still active branches (on fr timer)
81  * WARNING: always fill cancel_bm using which_cancel(), supplying values
82  *          in any other way is a bug*/
83 int cancel_uacs( struct cell *t, branch_bm_t cancel_bm, int flags)
84 {
85         int i;
86         int ret;
87         int r;
88
89         ret=0;
90         /* cancel pending client transactions, if any */
91         for( i=0 ; i<t->nr_of_outgoings ; i++ ) 
92                 if (cancel_bm & (1<<i)){
93                         r=cancel_branch(t, i, flags);
94                         ret|=(r!=0)<<i;
95                 }
96         return ret;
97 }
98
99
100
101 /* 
102  * params:  t - transaction
103  *          branch - branch number to be canceled
104  *          flags - howto cancel: 
105  *                   F_CANCEL_B_KILL - will completely stop the 
106  *                     branch (stops the timers), use with care
107  *                   F_CANCEL_B_FAKE_REPLY - will send a fake 487
108  *                      to all branches that haven't received any response
109  *                      (>=100). It assumes the REPLY_LOCK is not held
110  *                      (if it is => deadlock)
111  *                  default: stop only the retransmissions for the branch
112  *                      and leave it to timeout if it doesn't receive any
113  *                      response to the CANCEL
114  * returns: 0 - branch inactive after running cancel_branch() 
115  *          1 - branch still active  (fr_timer)
116  *         -1 - error
117  * WARNING:
118  *          - F_CANCEL_KILL_B should be used only if the transaction is killed
119  *            explicitly afterwards (since it might kill all the timers
120  *            the transaction won't be able to "kill" itself => if not
121  *            explicitly "put_on_wait" it might live forever)
122  *          - F_CANCEL_B_FAKE_REPLY must be used only if the REPLY_LOCK is not
123  *            held
124  */
125 int cancel_branch( struct cell *t, int branch, int flags )
126 {
127         char *cancel;
128         unsigned int len;
129         struct retr_buf *crb, *irb;
130         int ret;
131         branch_bm_t tmp_bm;
132
133         crb=&t->uac[branch].local_cancel;
134         irb=&t->uac[branch].request;
135         ret=1;
136
137 #       ifdef EXTRA_DEBUG
138         if (crb->buffer!=0 && crb->buffer!=BUSY_BUFFER) {
139                 LOG(L_CRIT, "ERROR: attempt to rewrite cancel buffer\n");
140                 abort();
141         }
142 #       endif
143
144         if (flags & F_CANCEL_B_KILL){
145                 stop_rb_timers( irb );
146                 ret=0;
147                 if (t->uac[branch].last_received < 100) {
148                         DBG("DEBUG: cancel_branch: no response ever received: "
149                             "giving up on cancel\n");
150                         if (flags & F_CANCEL_B_FAKE_REPLY){
151                                 LOCK_REPLIES(t);
152                                 if (relay_reply(t, FAKED_REPLY, branch, 487, &tmp_bm) == 
153                                                                                 RPS_ERROR){
154                                         return -1;
155                                 }
156                         }
157                         /* do nothing, hope that the caller will clean up */
158                         return ret;
159                 }
160         }else{
161                 stop_rb_retr(irb); /* stop retransmissions */
162                 if (t->uac[branch].last_received < 100) {
163                         /* no response received => don't send a cancel on this branch,
164                          *  just drop it */
165                         if (flags & F_CANCEL_B_FAKE_REPLY){
166                                 stop_rb_timers( irb ); /* stop even the fr timer */
167                                 LOCK_REPLIES(t);
168                                 if (relay_reply(t, FAKED_REPLY, branch, 487, &tmp_bm) == 
169                                                                                 RPS_ERROR){
170                                         return -1;
171                                 }
172                                 return 0; /* should be inactive after the 487 */
173                         }
174                         /* do nothing, just wait for the final timeout */
175                         return 1;
176                 }
177         }
178         
179         cancel = build_local(t, branch, &len, CANCEL, CANCEL_LEN, &t->to);
180         if (!cancel) {
181                 LOG(L_ERR, "ERROR: attempt to build a CANCEL failed\n");
182                 return -1;
183         }
184         /* install cancel now */
185         crb->buffer = cancel;
186         crb->buffer_len = len;
187         crb->dst = irb->dst;
188         crb->branch = branch;
189         /* label it as cancel so that FR timer can better know how to
190            deal with it */
191         crb->activ_type = TYPE_LOCAL_CANCEL;
192
193         DBG("DEBUG: cancel_branch: sending cancel...\n");
194 #ifdef TMCB_ONSEND
195         if (SEND_BUFFER( crb )>=0)
196                 run_onsend_callbacks(TMCB_REQUEST_SENT, crb, TMCB_LOCAL_F);
197 #else
198         SEND_BUFFER( crb );
199 #endif
200         /*sets and starts the FINAL RESPONSE timer */
201         if (start_retr( crb )!=0)
202                 LOG(L_CRIT, "BUG: cancel_branch: failed to start retransmission"
203                                         " for %p\n", crb);
204         return ret;
205 }
206
207
208 const char* rpc_cancel_doc[2] = {
209         "Cancel a pending transaction",
210         0
211 };
212
213
214 /* fifo command to cancel a pending call (Uli)
215  * Syntax:
216  *
217  * ":uac_cancel:[response file]\n
218  * callid\n
219  * cseq\n
220  */
221 void rpc_cancel(rpc_t* rpc, void* c)
222 {
223         struct cell *trans;
224         static char cseq[128], callid[128];
225         branch_bm_t cancel_bm;
226         int i,j;
227
228         str cseq_s;   /* cseq */
229         str callid_s; /* callid */
230
231         cseq_s.s=cseq;
232         callid_s.s=callid;
233         cancel_bm=0;
234
235         if (rpc->scan(c, "SS", &callid_s, &cseq_s) < 2) {
236                 rpc->fault(c, 400, "Callid and CSeq expected as parameters");
237                 return;
238         }
239
240         if( t_lookup_callid(&trans, callid_s, cseq_s) < 0 ) {
241                 DBG("Lookup failed\n");
242                 rpc->fault(c, 400, "Transaction not found");
243                 return;
244         }
245         /*  find the branches that need cancel-ing */
246         LOCK_REPLIES(trans);
247                 which_cancel(trans, &cancel_bm);
248         UNLOCK_REPLIES(trans);
249          /* tell tm to cancel the call */
250         DBG("Now calling cancel_uacs\n");
251         i=cancel_uacs(trans, cancel_bm, 0); /* don't fake 487s, 
252                                                                                  just wait for timeout */
253         
254         /* t_lookup_callid REF`d the transaction for us, we must UNREF here! */
255         UNREF(trans);
256         j=0;
257         while(i){
258                 j++;
259                 i&=i-1;
260         }
261         rpc->add(c, "ds", j, "branches remaining (waiting for timeout)");
262 }