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