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