da6eaac73560d724b61967b4cbe46591f8a26cce
[sip-router] / modules / tm / t_lookup.c
1 /*
2  * $Id$
3  *
4  */
5
6 #include "hash_func.h"
7 #include "t_funcs.h"
8 #include "../../dprint.h"
9 #include "../../config.h"
10 #include "../../parser_f.h"
11 #include "../../ut.h"
12 #include "../../timer.h"
13
14 static int reverse_hex2int( char *c, int len )
15 {
16         char *pc;
17         int r;
18         char mychar;
19
20         r=0;
21         for (pc=c+len-1; len>0; pc--, len--) {
22                 r <<= 4 ;
23                 mychar=*pc;
24                 if ( mychar >='0' && mychar <='9') r+=mychar -'0';
25                 else if (mychar >='a' && mychar <='f') r+=mychar -'a'+10;
26                 else if (mychar  >='A' && mychar <='F') r+=mychar -'A'+10;
27                 else return -1;
28         }
29         return r;
30 }
31
32 inline static int int2reverse_hex( char **c, int *size, int nr )
33 {
34         unsigned short digit;
35
36         if (*size && nr==0) {
37                 **c = '0';
38                 (*c)++;
39                 (*size)--;
40                 return 1;
41         }
42
43         while (*size && nr ) {
44                 digit = nr & 0xf ;
45                 **c= digit >= 10 ? digit + 'a' - 10 : digit + '0';
46                 nr >>= 4;
47                 (*c)++;
48                 (*size)--;
49         }
50         return nr ? -1 /* number not processed; too little space */ : 1;
51 }
52
53 /* function returns:
54  *      -1 - transaction wasn't found
55  *       1  - transaction found
56  */
57 int t_lookup_request( struct sip_msg* p_msg )
58 {
59    struct cell      *p_cell;
60    struct cell      *tmp_cell;
61    unsigned int  hash_index=0;
62    unsigned int  isACK;
63    struct sip_msg       *t_msg;
64
65    DBG("t_lookup_request: start searching\n");
66
67    /* parse all*/
68    if (check_transaction_quadruple(p_msg)==0)
69    {
70       LOG(L_ERR, "ERROR: TM module: t_lookup_request: too few headers\n");
71       T=0;
72       return -1;
73    }
74
75    /* start searching into the table */
76    hash_index = hash( p_msg->callid->body , get_cseq(p_msg)->number ) ;
77    isACK = p_msg->REQ_METHOD==METHOD_ACK;
78    DBG("t_lookup_request: continue searching;  hash=%d, isACK=%d\n",hash_index,isACK);
79
80    /* lock the hole entry*/
81    lock( hash_table->entrys[hash_index].mutex );
82
83    /* all the transactions from the entry are compared */
84    p_cell     = hash_table->entrys[hash_index].first_cell;
85    tmp_cell = 0;
86    while( p_cell )
87    {
88                 int abba;
89
90                 t_msg = p_cell->inbound_request;
91
92 #define EQ_LEN(_hf) (t_msg->_hf->body.len==p_msg->_hf->body.len)
93 #define EQ_STR(_hf) (memcmp(t_msg->_hf->body.s, p_msg->_hf->body.s, \
94                 p_msg->_hf->body.len)==0)
95
96
97                 if ( EQ_LEN(from) && EQ_LEN(callid) &&
98                   EQ_STR(callid) && EQ_STR(callid) &&
99                   /* we compare only numerical parts of CSEQ ...
100                      the method name should be the same as in first line */
101                   memcmp( get_cseq(t_msg)->number.s , get_cseq(p_msg)->number.s , 
102                                 get_cseq(p_msg)->number.len ) ==0 )
103                 {
104                         if (!isACK) {
105                                 if (t_msg->REQ_METHOD == p_msg->REQ_METHOD &&
106                                         EQ_LEN(to) && EQ_STR(to))
107                                         goto found;
108                         } else { /* ACK */
109                                 if (t_msg->REQ_METHOD == METHOD_INVITE  &&
110                                         //p_cell->tag &&  p_cell->tag->len==p_msg->tag->body.len &&
111                         //if ( /*tag*/ memcmp( p_cell->tag->s , p_msg->tag->body.s , 
112                                         // p_msg->tag->body.len ) ==0 )
113                                         EQ_STR( to ) ) {
114                                         goto found;
115                                 }
116                         } /* ACK */
117                 } /* common HFs equal */
118
119       /* next transaction */
120       tmp_cell = p_cell;
121       p_cell = p_cell->next_cell;
122    } /* synonym loop */
123
124    /* no transaction found */
125    T = 0;
126    unlock( hash_table->entrys[hash_index].mutex );
127    DBG("DEBUG: t_lookup_request: no transaction found\n");
128    return -1;
129
130 found:
131         T=p_cell;
132         ref_T( T );
133         DBG("DEBUG:XXXXXXXXXXXXXXXXXXXXX t_lookup_request: "
134                         "transaction found ( T=%p , ref=%d)\n",T,T->ref_counter);
135         unlock( hash_table->entrys[hash_index].mutex );
136         return 1;
137 }
138
139
140
141
142 /* function returns:
143  *       0 - transaction wasn't found
144  *       T - transaction found
145  */
146 struct cell* t_lookupOriginalT(  struct s_table* hash_table , struct sip_msg* p_msg )
147 {
148    struct cell      *p_cell;
149    struct cell      *tmp_cell;
150    unsigned int  hash_index=0;
151
152    /* it's a CANCEL request for sure */
153
154    /* start searching into the table */
155    hash_index = hash( p_msg->callid->body , get_cseq(p_msg)->number  ) ;
156    DBG("DEBUG: t_lookupOriginalT: searching on hash entry %d\n",hash_index );
157
158    /* all the transactions from the entry are compared */
159    p_cell     = hash_table->entrys[hash_index].first_cell;
160    tmp_cell = 0;
161    while( p_cell )
162    {
163       /* is it the wanted transaction ? */
164       /* first only the length are checked */
165       if ( /*from length*/ p_cell->inbound_request->from->body.len == p_msg->from->body.len )
166          if ( /*to length*/ p_cell->inbound_request->to->body.len == p_msg->to->body.len )
167             //if ( /*tag length*/ (!p_cell->inbound_request->tag && !p_msg->tag) || (p_cell->inbound_request->tag && p_msg->tag && p_cell->inbound_request->tag->body.len == p_msg->tag->body.len) )
168                if ( /*callid length*/ p_cell->inbound_request->callid->body.len == p_msg->callid->body.len )
169                   if ( /*cseq_nr length*/ get_cseq(p_cell->inbound_request)->number.len == get_cseq(p_msg)->number.len )
170                       if ( /*cseq_method type*/ p_cell->inbound_request->REQ_METHOD!=METHOD_CANCEL )
171                          if ( /*req_uri length*/ p_cell->inbound_request->first_line.u.request.uri.len == p_msg->first_line.u.request.uri.len )
172                              /* so far the lengths are the same -> let's check the contents */
173                              if ( /*from*/ memcmp( p_cell->inbound_request->from->body.s , p_msg->from->body.s , p_msg->from->body.len )==0 )
174                                 if ( /*to*/ memcmp( p_cell->inbound_request->to->body.s , p_msg->to->body.s , p_msg->to->body.len)==0  )
175                                    //if ( /*tag*/ (!p_cell->inbound_request->tag && !p_msg->tag) || (p_cell->inbound_request->tag && p_msg->tag && memcmp( p_cell->inbound_request->tag->body.s , p_msg->tag->body.s , p_msg->tag->body.len )==0) )
176                                       if ( /*callid*/ memcmp( p_cell->inbound_request->callid->body.s , p_msg->callid->body.s , p_msg->callid->body.len )==0 )
177                                           if ( /*cseq_nr*/ memcmp( get_cseq(p_cell->inbound_request)->number.s , get_cseq(p_msg)->number.s , get_cseq(p_msg)->number.len )==0 )
178                                              if ( /*req_uri*/ memcmp( p_cell->inbound_request->first_line.u.request.uri.s , p_msg->first_line.u.request.uri.s , p_msg->first_line.u.request.uri.len )==0 )
179                                              { /* WE FOUND THE GOLDEN EGG !!!! */
180                                                 return p_cell;
181                                              }
182       /* next transaction */
183       tmp_cell = p_cell;
184       p_cell = p_cell->next_cell;
185    }
186
187    /* no transaction found */
188    T = 0;
189    return 0;
190
191
192    return 0;
193 }
194
195
196
197
198 /* Returns 0 - nothing found
199   *              1  - T found
200   */
201 int t_reply_matching( struct sip_msg *p_msg , unsigned int *p_branch )
202 {
203    struct cell*  p_cell;
204    struct cell* tmp_cell;
205    unsigned int hash_index = 0;
206    unsigned int entry_label  = 0;
207    unsigned int branch_id    = 0;
208    char  *hashi, *syni, *branchi, *p, *n;
209    int hashl, synl, branchl;
210    int scan_space;
211
212    /* split the branch into pieces: loop_detection_check(ignored),
213       hash_table_id, synonym_id, branch_id*/
214
215    if (! ( p_msg->via1 && p_msg->via1->branch && p_msg->via1->branch->value.s) )
216         goto nomatch2;
217
218    p=p_msg->via1->branch->value.s;
219    scan_space=p_msg->via1->branch->value.len;
220
221    /* loop detection ... ignore */
222    n=eat_token2_end( p, p+scan_space, '.');
223    scan_space-=n-p;
224    if (n==p || scan_space<2 || *n!='.') goto nomatch2;
225    p=n+1; scan_space--;
226
227    /* hash_id */
228    n=eat_token2_end( p, p+scan_space, '.');
229    hashl=n-p;
230    scan_space-=hashl;
231    if (!hashl || scan_space<2 || *n!='.') goto nomatch2;
232    hashi=p;
233    p=n+1;scan_space--;
234
235
236    /* sequence id */
237    n=eat_token2_end( p, p+scan_space, '.');
238    synl=n-p;
239    scan_space-=synl;
240    if (!synl || scan_space<2 || *n!='.') goto nomatch2;
241    syni=p;
242    p=n+1;scan_space--;
243
244    /* branch id */  /*  should exceed the scan_space */
245    n=eat_token_end( p, p+scan_space );
246    branchl=n-p;
247    if (!branchl ) goto nomatch2;
248    branchi=p;
249
250
251    hash_index=reverse_hex2int(hashi, hashl);
252    entry_label=reverse_hex2int(syni, synl);
253    branch_id=reverse_hex2int(branchi, branchl);
254         if (hash_index==-1 || entry_label==-1 || branch_id==-1) {
255                 DBG("DEBUG: t_reply_matching: poor reply lables %d label %d branch %d\n",
256                         hash_index, entry_label, branch_id );
257                 goto nomatch2;
258         }
259
260
261    DBG("DEBUG: t_reply_matching: hash %d label %d branch %d\n",
262         hash_index, entry_label, branch_id );
263
264    /* sanity check */
265    if (hash_index<0 || hash_index >=TABLE_ENTRIES ||
266        entry_label<0 || branch_id<0 || branch_id>=MAX_FORK ) {
267                         DBG("DBG: t_reply_matching: snaity check failed\n");
268                 goto nomatch2;
269         }
270
271    /* lock the hole entry*/
272    lock( hash_table->entrys[hash_index].mutex );
273
274    /*all the cells from the entry are scan to detect an entry_label matching */
275    p_cell     = hash_table->entrys[hash_index].first_cell;
276    tmp_cell = 0;
277    while( p_cell )
278    {
279       /* is it the cell with the wanted entry_label? */
280       if ( p_cell->label == entry_label )
281       /* has the transaction the wanted branch? */
282       if ( p_cell->nr_of_outgoings>branch_id && p_cell->outbound_request[branch_id] )
283       {/* WE FOUND THE GOLDEN EGG !!!! */
284           T = p_cell;
285           *p_branch = branch_id;
286           /* T->ref_counter ++; */
287                   ref_T( T );
288           unlock( hash_table->entrys[hash_index].mutex );
289           DBG("DEBUG:XXXXXXXXXXXXXXXXXXXXX t_reply_matching: reply matched (T=%p, ref=%d)!\n",T,T->ref_counter);
290         return 1;
291       }
292       /* next cell */
293       tmp_cell = p_cell;
294       p_cell = p_cell->next_cell;
295
296    } /* while p_cell */
297
298    /* nothing found */
299    DBG("DEBUG: t_reply_matching: no matching transaction exists\n");
300
301 nomatch:
302    unlock( hash_table->entrys[hash_index].mutex );
303 nomatch2:
304    DBG("DEBUG: t_reply_matching: failure to match a transaction\n");
305    *p_branch = -1;
306    T = 0;
307    return -1;
308 }
309
310
311
312
313 /* Functions update T (T gets either a valid pointer in it or it equals zero) if no transaction
314   * for current message exists;
315   */
316 int t_check( struct sip_msg* p_msg , int *param_branch)
317 {
318    int local_branch;
319
320    /* is T still up-to-date ? */
321    DBG("DEBUG: t_check : msg id=%d , global msg id=%d , T=%p\n", p_msg->id,global_msg_id,T);
322    if ( p_msg->id != global_msg_id || T==T_UNDEFINED )
323    {
324       global_msg_id = p_msg->id;
325       if ( T && T!=T_UNDEFINED )
326          unref_T(T);
327       T = T_UNDEFINED;
328       /* transaction lookup */
329      if ( p_msg->first_line.type==SIP_REQUEST )
330          t_lookup_request( p_msg );
331      else
332          t_reply_matching( p_msg , ((param_branch!=0)?(param_branch):(&local_branch)) );
333 #ifdef EXTRA_DEBUG
334         if ( T && T!=T_UNDEFINED && T->damocles) {
335                 LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and called from t_check\n", T);
336                 abort();
337         }
338 #endif
339
340    }
341    else
342    {
343       if (T)
344          DBG("DEBUG: t_check: T alredy found!\n");
345       else
346           DBG("DEBUG: t_check: T previously sought and not found\n");
347    }
348
349    return ((T)?1:-1) ;
350 }
351
352
353
354 /* append appropriate branch labels for fast reply-transaction matching
355    to outgoing requests
356 */
357 int add_branch_label( struct cell *trans, struct sip_msg *p_msg, int branch )
358 {
359         char *c;
360
361         char *begin;
362         unsigned int size, orig_size, n;
363
364         begin=p_msg->add_to_branch_s+p_msg->add_to_branch_len;
365         orig_size = size=MAX_BRANCH_PARAM_LEN - p_msg->add_to_branch_len;
366
367         if (size) { *begin='.'; begin++; size--; } else return -1;
368         if (int2reverse_hex( &begin, &size, trans->hash_index)==-1) return -1;
369         if (size) { *begin='.'; begin++; size--; } else return -1;
370         if (int2reverse_hex( &begin, &size, trans->label)==-1) return -1;
371         if (size) { *begin='.'; begin++; size--; } else return -1;
372         if (int2reverse_hex( &begin, &size, branch)==-1) return -1;
373
374         p_msg->add_to_branch_len+=(orig_size-size);
375         DBG("DEBUG: XXX branch label created now: %*s (%d)\n",
376                 p_msg->add_to_branch_len, p_msg->add_to_branch_s );
377         return 0;
378
379 }
380