memory access syncing protection added
[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 , int leave_new_locked )
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    p_msg->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",p_msg->hash_index,isACK);
100
101    /* lock the hole entry*/
102    lock( hash_table->entrys[p_msg->hash_index].mutex );
103
104    /* all the transactions from the entry are compared */
105    p_cell     = hash_table->entrys[p_msg->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    if (!leave_new_locked) unlock( hash_table->entrys[p_msg->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[p_msg->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         hash_index = p_msg->hash_index;
190    DBG("DEBUG: t_lookupOriginalT: searching on hash entry %d\n",hash_index );
191
192    /* all the transactions from the entry are compared */
193    p_cell     = hash_table->entrys[hash_index].first_cell;
194    tmp_cell = 0;
195    while( p_cell )
196    {
197      t_msg = p_cell->inbound_request;
198
199       /* is it the wanted transaction ? */
200       /* first only the length are checked */
201       if ( p_cell->inbound_request->REQ_METHOD!=METHOD_CANCEL )
202          if ( /*callid length*/ EQ_LEN(callid) )
203             if ( get_cseq(t_msg)->number.len==get_cseq(p_msg)->number.len )
204                if ( EQ_REQ_URI_LEN )
205                    if ( EQ_VIA_LEN(via1) )
206                   if ( EQ_LEN(from) && EQ_LEN(to) )
207                         //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) )
208                            /* so far the lengths are the same -> let's check the contents */
209                             if ( /*callid*/ EQ_STR(callid) )
210                                if ( /*cseq_nr*/ memcmp( get_cseq(t_msg)->number.s , get_cseq(p_msg)->number.s , get_cseq(p_msg)->number.len )==0 )
211                                   if ( EQ_REQ_URI_STR )
212                                   if ( EQ_VIA_STR(via1) )
213                                   if ( EQ_STR(from) && EQ_STR(to) )
214                                             //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) )
215                                               { /* WE FOUND THE GOLDEN EGG !!!! */
216                                                 DBG("DEBUG: t_lookupOriginalT: canceled transaction found (%x)! \n",p_cell );
217                                                 return p_cell;
218                                              }
219       /* next transaction */
220       tmp_cell = p_cell;
221       p_cell = p_cell->next_cell;
222    }
223
224    /* no transaction found */
225    DBG("DEBUG: t_lookupOriginalT: no CANCEL maching found! \n" );
226    return 0;
227 }
228
229
230
231
232 /* Returns 0 - nothing found
233   *              1  - T found
234   */
235 int t_reply_matching( struct sip_msg *p_msg , unsigned int *p_branch )
236 {
237    struct cell*  p_cell;
238    unsigned int hash_index = 0;
239    unsigned int entry_label  = 0;
240    unsigned int branch_id    = 0;
241    char  *hashi, *syni, *branchi, *p, *n;
242    int hashl, synl, branchl;
243    int scan_space;
244
245    /* split the branch into pieces: loop_detection_check(ignored),
246       hash_table_id, synonym_id, branch_id*/
247
248    if (! ( p_msg->via1 && p_msg->via1->branch && p_msg->via1->branch->value.s) )
249         goto nomatch2;
250
251    p=p_msg->via1->branch->value.s;
252    scan_space=p_msg->via1->branch->value.len;
253
254    /* loop detection ... ignore */
255    n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR );
256    scan_space-=n-p;
257    if (n==p || scan_space<2 || *n!=BRANCH_SEPARATOR) goto nomatch2;
258    p=n+1; scan_space--;
259
260    /* hash_id */
261    n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR);
262    hashl=n-p;
263    scan_space-=hashl;
264    if (!hashl || scan_space<2 || *n!=BRANCH_SEPARATOR) goto nomatch2;
265    hashi=p;
266    p=n+1;scan_space--;
267
268
269    /* sequence id */
270    n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR);
271    synl=n-p;
272    scan_space-=synl;
273    if (!synl || scan_space<2 || *n!=BRANCH_SEPARATOR) goto nomatch2;
274    syni=p;
275    p=n+1;scan_space--;
276
277    /* branch id */  /*  should exceed the scan_space */
278    n=eat_token_end( p, p+scan_space );
279    branchl=n-p;
280    if (!branchl ) goto nomatch2;
281    branchi=p;
282
283
284    hash_index=reverse_hex2int(hashi, hashl);
285    entry_label=reverse_hex2int(syni, synl);
286    branch_id=reverse_hex2int(branchi, branchl);
287         if (hash_index==-1 || entry_label==-1 || branch_id==-1) {
288                 DBG("DEBUG: t_reply_matching: poor reply lables %d label %d branch %d\n",
289                         hash_index, entry_label, branch_id );
290                 goto nomatch2;
291         }
292
293
294    DBG("DEBUG: t_reply_matching: hash %d label %d branch %d\n",
295         hash_index, entry_label, branch_id );
296
297    /* sanity check */
298    if (hash_index<0 || hash_index >=TABLE_ENTRIES ||
299     entry_label<0 || branch_id<0 || branch_id>=MAX_FORK ) {
300           DBG("DBG: t_reply_matching: snaity check failed\n");
301          goto nomatch2;
302    }
303
304    /* lock the hole entry*/
305    lock( hash_table->entrys[hash_index].mutex );
306
307    /*all the cells from the entry are scan to detect an entry_label matching */
308    p_cell     = hash_table->entrys[hash_index].first_cell;
309    while( p_cell )
310    {
311       /* is it the cell with the wanted entry_label? */
312       if ( p_cell->label == entry_label )
313          /* has the transaction the wanted branch? */
314          if ( p_cell->nr_of_outgoings>branch_id && p_cell->outbound_request[branch_id] )
315          {/* WE FOUND THE GOLDEN EGG !!!! */
316              T = p_cell;
317              *p_branch = branch_id;
318              T_REF( T );
319              unlock( hash_table->entrys[hash_index].mutex );
320              DBG("DEBUG:XXXXXXXXXXXXXXXXXXXXX t_reply_matching: reply matched (T=%p, ref=%x)!\n",T,T->ref_bitmap);
321             return 1;
322          }
323       /* next cell */
324       p_cell = p_cell->next_cell;
325    } /* while p_cell */
326
327    /* nothing found */
328    DBG("DEBUG: t_reply_matching: no matching transaction exists\n");
329
330 nomatch:
331    unlock( hash_table->entrys[hash_index].mutex );
332 nomatch2:
333    DBG("DEBUG: t_reply_matching: failure to match a transaction\n");
334    *p_branch = -1;
335    T = 0;
336    return -1;
337 }
338
339
340
341
342 /* Functions update T (T gets either a valid pointer in it or it equals zero) if no transaction
343   * for current message exists;
344   * it returns 1 if found, 0 if not found, -1 on error
345   */
346 int t_check( struct sip_msg* p_msg , int *param_branch)
347 {
348         int local_branch;
349
350         /* is T still up-to-date ? */
351         DBG("DEBUG: t_check : msg id=%d , global msg id=%d , T on entrance=%p\n", 
352                 p_msg->id,global_msg_id,T);
353         if ( p_msg->id != global_msg_id || T==T_UNDEFINED )
354         {
355                 global_msg_id = p_msg->id;
356                 T = T_UNDEFINED;
357                 /* transaction lookup */
358                 if ( p_msg->first_line.type==SIP_REQUEST ) {
359
360                         /* force parsing all the needed headers*/
361                         if (parse_headers(p_msg, HDR_EOH )==-1)
362                                 return -1;
363                 t_lookup_request( p_msg , 0 /* unlock before returning */ );
364                 } else {
365                         if ( parse_headers(p_msg, HDR_VIA1|HDR_VIA2|HDR_TO|HDR_CSEQ )==-1 ||
366                         !p_msg->via1 || !p_msg->via2 || !p_msg->to || !p_msg->cseq )
367                                 return -1;
368                         t_reply_matching( p_msg , ((param_branch!=0)?(param_branch):(&local_branch)) );
369                 }
370 #               ifdef EXTRA_DEBUG
371                 if ( T && T!=T_UNDEFINED && T->damocles) {
372                         LOG( L_ERR, "ERROR: transaction %p scheduled for deletion "
373                                 "and called from t_check\n", T);
374                         abort();
375                 }
376 #               endif
377                 DBG("DEBUG: t_check : msg id=%d , global msg id=%d , T on finish=%p\n",
378                         p_msg->id,global_msg_id,T);
379         } else {
380                 if (T)
381                         DBG("DEBUG: t_check: T alredy found!\n");
382                 else
383                         DBG("DEBUG: t_check: T previously sought and not found\n");
384         }
385
386         return ((T)?1:0) ;
387 }
388
389
390
391 /* append appropriate branch labels for fast reply-transaction matching
392    to outgoing requests
393 */
394 int add_branch_label( struct cell *trans, struct sip_msg *p_msg, int branch )
395 {
396         char *c;
397
398         char *begin;
399         unsigned int size, orig_size, n;
400
401         begin=p_msg->add_to_branch_s+p_msg->add_to_branch_len;
402         orig_size = size=MAX_BRANCH_PARAM_LEN - p_msg->add_to_branch_len;
403
404         if (size) { *begin=BRANCH_SEPARATOR; begin++; size--; } else return -1;
405         if (int2reverse_hex( &begin, &size, trans->hash_index)==-1) return -1;
406         if (size) { *begin=BRANCH_SEPARATOR; begin++; size--; } else return -1;
407         if (int2reverse_hex( &begin, &size, trans->label)==-1) return -1;
408         if (size) { *begin=BRANCH_SEPARATOR; begin++; size--; } else return -1;
409         if (int2reverse_hex( &begin, &size, branch)==-1) return -1;
410
411         p_msg->add_to_branch_len+=(orig_size-size);
412         DBG("DEBUG: XXX branch label created now: %*s (%d)\n",
413                 p_msg->add_to_branch_len, p_msg->add_to_branch_s );
414         return 0;
415
416 }
417
418 /* atomic "add_if_new" construct; it returns:
419         AIN_ERROR       if a fatal error (e.g, parsing) occured
420         AIN_RETR        it's a retransmission
421         AIN_NEW         it's a new request
422         AIN_NEWACK      it's an ACK for which no transaction exists
423         AIN_OLDACK      it's an ACK for an existing transaction
424 */
425 enum addifnew_status t_addifnew( struct sip_msg* p_msg )
426 {
427
428         int ret, lret;
429         struct cell *new_cell;
430
431         /* is T still up-to-date ? */
432         DBG("DEBUG: t_check_new_request: msg id=%d , global msg id=%d , T on entrance=%p\n", 
433                 p_msg->id,global_msg_id,T);
434         if ( p_msg->id != global_msg_id || T==T_UNDEFINED )
435         {
436                 global_msg_id = p_msg->id;
437                 T = T_UNDEFINED;
438                 /* transaction lookup */
439                 /* force parsing all the needed headers*/
440                 if (parse_headers(p_msg, HDR_EOH )==-1)
441                         return AIN_ERROR;
442                 lret = t_lookup_request( p_msg, 1 /* leave locked */ );
443                 if (lret==0) return AIN_ERROR;  
444                 if (lret==-1) {
445                         /* transaction not found, it's a new request */
446                         if ( p_msg->REQ_METHOD==METHOD_ACK ) {
447                                 ret=AIN_NEWACK;
448                         } else {
449                                 /* add new transaction */
450                                 new_cell = build_cell( p_msg ) ;
451                                 if  ( !new_cell ){
452                                         LOG(L_ERR, "ERROR: t_addifnew: out of mem:\n");
453                                         ret = AIN_ERROR;
454                                 } else {
455                                         insert_into_hash_table_unsafe( hash_table , new_cell );
456                                         ret = AIN_NEW;
457                                         T=new_cell;
458                                         T_REF(T);
459                                 }
460                         }
461                         unlock( hash_table->entrys[p_msg->hash_index].mutex );
462                         return ret;
463                 } else {
464                         /* tramsaction found, it's a retransmission  or ACK */
465                         return p_msg->REQ_METHOD==METHOD_ACK ? AIN_OLDACK : AIN_RETR;
466                 }
467         } else {
468                 if (T)
469                         LOG(L_ERR, "ERROR: t_check_new_request: already "
470                         "processing this message, T found!\n");
471                 else
472                         LOG(L_ERR, "ERROR: t_check_new_request: already "
473                         "processing this message, T not found!\n");
474                 return AIN_ERROR;
475         }
476
477 }
478
479
480