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