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