872c2c627e9a103988d479c6048a79570854411e
[sip-router] / modules / tm / t_lookup.c
1 /*
2  * $Id$
3  *
4  * This C-file takes care of matching requests and replies with
5  * existing transactions. Note that we do not do SIP-compliant
6  * request matching as asked by SIP spec. We do bitwise matching of 
7  * all header fields in requests which form a transaction key. 
8  * It is much faster and it worx pretty well -- we haven't 
9  * had any interop issue neither in lab nor in bake-offs. The reason
10  * is that retransmissions do look same as original requests
11  * (it would be really silly if they wuld be mangled). The only
12  * exception is we parse To as To in ACK is compared to To in
13  * reply and both  of them are constructed by different software.
14  * 
15  * As for reply matching, we match based on branch value -- that is
16  * faster too. There are two versions .. with SYNONYMs #define
17  * enabled, the branch includes ordinal number of a transaction
18  * in a synonym list in hash table and is somewhat faster but
19  * not reboot-resilient. SYNONYMs turned off are little slower
20  * but work across reboots as well.
21  *
22  * The branch parameter is formed as follows:
23  * SYNONYMS  on: hash.synonym.branch
24  * SYNONYMS off: md5.hash.branch
25  *
26  * -jiri
27  *
28  */
29
30 #include <assert.h>
31 #include "../../dprint.h"
32 #include "../../config.h"
33 #include "../../parser/parser_f.h"
34 #include "../../ut.h"
35 #include "../../timer.h"
36 #include "hash_func.h"
37 #include "t_funcs.h"
38 #include "config.h"
39 #include "sip_msg.h"
40
41
42 #define EQ_LEN(_hf) (t_msg->_hf->body.len==p_msg->_hf->body.len)
43 #define EQ_STR(_hf) (memcmp(t_msg->_hf->body.s,\
44         translate_pointer(p_msg->orig,p_msg->buf,p_msg->_hf->body.s), \
45         p_msg->_hf->body.len)==0)
46 #define EQ_REQ_URI_LEN\
47         (p_msg->first_line.u.request.uri.len==t_msg->first_line.u.request.uri.len)
48 #define EQ_REQ_URI_STR\
49         ( memcmp( t_msg->first_line.u.request.uri.s,\
50         translate_pointer(p_msg->orig,p_msg->buf,p_msg->first_line.u.request.uri.s),\
51         p_msg->first_line.u.request.uri.len)==0)
52 #define EQ_VIA_LEN(_via)\
53         ( (p_msg->via1->bsize-(p_msg->_via->name.s-(p_msg->_via->hdr.s+p_msg->_via->hdr.len)))==\
54         (t_msg->via1->bsize-(t_msg->_via->name.s-(t_msg->_via->hdr.s+t_msg->_via->hdr.len))) )
55
56 #define EQ_VIA_STR(_via)\
57         ( memcmp( t_msg->_via->name.s,\
58          translate_pointer(p_msg->orig,p_msg->buf,p_msg->_via->name.s),\
59          (t_msg->via1->bsize-(t_msg->_via->name.s-(t_msg->_via->hdr.s+t_msg->_via->hdr.len)))\
60         )==0 )
61
62
63
64 /* function returns:
65  *      -1 - transaction wasn't found
66  *       1  - transaction found
67  */
68 int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked )
69 {
70         struct cell         *p_cell;
71         struct cell         *tmp_cell;
72         unsigned int       isACK;
73         struct sip_msg  *t_msg;
74
75         /* parse all*/
76         if (check_transaction_quadruple(p_msg)==0)
77         {
78                 LOG(L_ERR, "ERROR: TM module: t_lookup_request: too few headers\n");
79                 T=0;
80                 /* stop processing */
81                 return 0;
82         }
83
84         /* start searching into the table */
85         p_msg->hash_index=hash( p_msg->callid->body , get_cseq(p_msg)->number ) ;
86         isACK = p_msg->REQ_METHOD==METHOD_ACK;
87         DBG("t_lookup_request: start searching: hash=%d, isACK=%d\n",
88                 p_msg->hash_index,isACK);
89
90         /* lock the hole entry*/
91         lock(&(hash_table->entrys[p_msg->hash_index].mutex));
92
93         /* all the transactions from the entry are compared */
94         p_cell   = hash_table->entrys[p_msg->hash_index].first_cell;
95         tmp_cell = 0;
96         while( p_cell )
97         {
98                 t_msg = p_cell->uas.request;
99
100                 /* is it the wanted transaction ? */
101                 if ( !isACK )
102                 { /* is not an ACK request */
103                         /* first only the length are checked */
104                         if ( /*callied*/EQ_LEN(callid) && /*cseq*/EQ_LEN(cseq)
105                         && /*req URI*/EQ_REQ_URI_LEN && /*VIA*/EQ_VIA_LEN(via1)
106                         && /*from*/EQ_LEN(from) && /*to*/EQ_LEN(to)  )
107                                 /* so far the lengths are the same
108                                 -> let's check the contents */
109                                 if ( /*callid*/EQ_STR(callid) && /*cseq*/EQ_STR(cseq)
110                                 && /*req URI*/EQ_REQ_URI_STR && /*VIA*/EQ_VIA_STR(via1)
111                                 && /*from*/EQ_STR(from) && /*to*/EQ_STR(to) )
112                                         { /* WE FOUND THE GOLDEN EGG !!!! */
113                                                 goto found;
114                                         }
115                 }
116                 else
117                 { /* it's a ACK request*/
118                         /* first only the length are checked */
119                         /* use shortcut; -jiri
120                         if ( t_msg->first_line.u.request.method_value==METHOD_INVITE */
121                         if (t_msg->REQ_METHOD==METHOD_INVITE
122                         /* && (fprintf(stderr,"------Method name OK->testing callid len...\n")) */
123                         && /*callid length*/ EQ_LEN(callid)
124                         /* && (fprintf(stderr,"------CallID OK -> testing cseq nr len\n")) */
125                         && get_cseq(t_msg)->number.len==get_cseq(p_msg)->number.len
126                         /* && (fprintf(stderr,"------Cseq nr OK -> testing from len\n")) */
127                         && /*from length*/ EQ_LEN(from)
128                         /* && (fprintf(stderr,"------from OK -> testing To uri len\n")) */
129                         && /*to uri*/get_to(t_msg)->uri.len==get_to(p_msg)->uri.len
130                         /* && (fprintf(stderr,"------To uri OK -> testing To tag len\n")) */
131                         && /*to tag*/p_cell->uas.tag->len==get_to(p_msg)->tag_value.len
132                         /* && (fprintf(stderr,"------To tag OK -> testing uri len\n")) */
133
134                         /* in ACKs to 200, r-uri and Via may be different than in
135                            original INVITE; we still try to match the transaction
136                            so that we can retransmit an ACK on resent 200 -- different
137                            from SIP spec which kills transaction state after INVITE-200
138                            and considers 200-ACK a new transaction which just happens
139                            to have the same CSeq. -jiri
140                         */
141
142                         && /*req URI*/(p_cell->uas.status==200 || EQ_REQ_URI_LEN )
143                         /* && (fprintf(stderr,"------uri OK -> testing via len\n")) */
144                         && /*VIA*/(p_cell->uas.status==200 || EQ_VIA_LEN(via1)) )
145                                 /* so far the lengths are the same
146                                 -> let's check the contents */
147                                 if ( /* fprintf(stderr,"------callid |%.*s| |%.*s|\n",
148                                         p_msg->callid->body.len,p_msg->callid->body.s,
149                                         t_msg->callid->body.len,t_msg->callid->body.s)
150                                 && */ /*callid*/!memcmp( t_msg->callid->body.s,
151                                         p_msg->callid->body.s,p_msg->callid->body.len)
152                                 /* && fprintf(stderr,"------cseq |%.*s| |%.*s|\n",
153                                         get_cseq(p_msg)->number.len,get_cseq(p_msg)->number.s,
154                                         get_cseq(t_msg)->number.len,get_cseq(t_msg)->number.s) */
155                                 && /*cseq nr*/!memcmp(get_cseq(t_msg)->number.s,
156                                         get_cseq(p_msg)->number.s,get_cseq(p_msg)->number.len)
157                                 /* &&  fprintf(stderr,"------from |%.*s| |%.*s|\n",
158                                         p_msg->from->body.len, translate_pointer(p_msg->orig,
159                                                 p_msg->buf,p_msg->from->body.s),
160                                         t_msg->from->body.len,t_msg->from->body.s) */
161                                 && /*from*/EQ_STR(from)
162                                 /* && fprintf(stderr,"------to uri |%.*s| |%.*s|\n",
163                                         get_to(p_msg)->uri.len,get_to(p_msg)->uri.s,
164                                         get_to(t_msg)->uri.len,get_to(t_msg)->uri.s) */
165                                 && /*to uri*/!memcmp(get_to(t_msg)->uri.s,
166                                         get_to(p_msg)->uri.s,get_to(t_msg)->uri.len)
167                                 /* && fprintf(stderr,"------to tag |%.*s| |%.*s|\n",
168                     get_to(p_msg)->tag_value.len,get_to(p_msg)->tag_value.s,
169                     p_cell->uas.tag->len, p_cell->uas.tag->s) */
170                                 && /*to tag*/!memcmp(p_cell->uas.tag->s,
171                                         get_to(p_msg)->tag_value.s,p_cell->uas.tag->len)
172                                 /* && fprintf(stderr,"------URI %d |%.*s| |%.*s|\n",
173                                         p_cell->uas.status,p_msg->first_line.u.request.uri.len,
174                                         translate_pointer(p_msg->orig, p_msg->buf,
175                                                 p_msg->first_line.u.request.uri.s),
176                                         t_msg->first_line.u.request.uri.len,
177                                         t_msg->first_line.u.request.uri.s) */
178                                 && /*req URI*/(p_cell->uas.status==200 || EQ_REQ_URI_STR)
179                                 /* && fprintf(stderr,"------VIA %d |%.*s| |%.*s|\n",
180                                         p_cell->uas.status, 
181                                         (p_msg->via1->bsize-(p_msg->via1->name.s-
182                                                 (p_msg->via1->hdr.s+p_msg->via1->hdr.len))),
183                                         translate_pointer(p_msg->orig,p_msg->buf,
184                                                 p_msg->via1->name.s),
185                     (t_msg->via1->bsize-(t_msg->via1->name.s-
186                                                 (t_msg->via1->hdr.s+t_msg->via1->hdr.len))),
187                                         t_msg->via1->name.s) */
188                                 && /*VAI*/(p_cell->uas.status==200 ||EQ_VIA_STR(via1)) )
189                                         { /* WE FOUND THE GOLDEN EGG !!!! */
190                                                 goto found;
191                                         }
192                 }
193                 /* next transaction */
194                 tmp_cell = p_cell;
195                 p_cell = p_cell->next_cell;
196         } /* synonym loop */
197
198         /* no transaction found */
199         T = 0;
200         if (!leave_new_locked)
201                 unlock(&(hash_table->entrys[p_msg->hash_index].mutex));
202         DBG("DEBUG: t_lookup_request: no transaction found\n");
203         /* DON'T FORGET TO REMOVE IT!!!!! bogdan */
204         //if (isACK) assert(0);
205         return -1;
206
207 found:
208         T=p_cell;
209         T_REF( T );
210         DBG("DEBUG: t_lookup_request: transaction found (T=%p , ref=%x)\n",
211                 T,T->ref_bitmap);
212         unlock(&(hash_table->entrys[p_msg->hash_index].mutex));
213         return 1;
214 }
215
216
217
218
219 /* function returns:
220  *       0 - transaction wasn't found
221  *       T - transaction found
222  */
223 struct cell* t_lookupOriginalT(  struct s_table* hash_table ,
224                                                                                                         struct sip_msg* p_msg )
225 {
226         struct cell     *p_cell;
227         struct cell     *tmp_cell;
228         unsigned int     hash_index=0;
229         struct sip_msg  *t_msg=0;
230
231
232         /* start searching into the table */
233         hash_index = p_msg->hash_index;
234         DBG("DEBUG: t_lookupOriginalT: searching on hash entry %d\n",hash_index );
235
236         /* all the transactions from the entry are compared */
237         p_cell   = hash_table->entrys[hash_index].first_cell;
238         tmp_cell = 0;
239         while( p_cell )
240         {
241                 t_msg = p_cell->uas.request;
242
243                 /* is it the wanted transaction ? */
244                 /* first only the length are checked */
245                 if ( /* fprintf(stderr,"starting\n")  && */ p_cell->uas.request->REQ_METHOD!=METHOD_CANCEL
246                         /* && fprintf(stderr,"checking callid length....\n") */
247                         && /*callid length*/ EQ_LEN(callid)
248                         /* && fprintf(stderr,"OK. checking cseg nr len....\n")   */
249                         && get_cseq(t_msg)->number.len==get_cseq(p_msg)->number.len
250                         /* && fprintf(stderr,"OK. checking REQ_URI len.... \n") */
251                         && EQ_REQ_URI_LEN
252                         /* && fprintf(stderr,"OK. checking VIA %d %d....\n",
253                                 (p_msg->via1->bsize-(p_msg->via1->name.s-
254                                         (p_msg->via1->hdr.s+p_msg->via1->hdr.len))),
255                                 (t_msg->via1->bsize-(t_msg->via1->name.s-
256                                         (t_msg->via1->hdr.s+t_msg->via1->hdr.len)))) */
257             /* && fprintf(stderr,"OK. VIA |%.*s| |%.*s|\n",
258                 (p_msg->via1->bsize-(p_msg->via1->name.s-
259                      (p_msg->via1->hdr.s+p_msg->via1->hdr.len))),
260                 translate_pointer(p_msg->orig,p_msg->buf,
261                        p_msg->via1->name.s),
262                 (t_msg->via1->bsize-(t_msg->via1->name.s-
263                       (t_msg->via1->hdr.s+t_msg->via1->hdr.len))),
264                 t_msg->via1->name.s) */
265                         && EQ_VIA_LEN(via1) 
266                         /* && fprintf(stderr,"OK. checking FROM len... \n") */
267                         && EQ_LEN(from)
268                         /* && fprintf(stderr,"OK. checking TO len... \n") */
269                         && EQ_LEN(to)
270                         /* && fprintf(stderr,"OK\n") */ )
271                                 /* so far the lengths are the same
272                                  let's check the contents */
273                                 if (
274                         /* fprintf(stderr,"checking callid |%.*s| |%.*s|\n",
275                         p_msg->callid->body.len, translate_pointer(p_msg->orig,
276                                 p_msg->buf,p_msg->callid->body.s),
277                         t_msg->callid->body.len,t_msg->callid->body.s) 
278                                         && *//*callid*/ EQ_STR(callid)
279                                         /* && fprintf(stderr,"OK. cseq nr |%.*s| |%.*s|\n",
280                                                 get_cseq(p_msg)->number.len,get_cseq(p_msg)->number.s,
281                                                 get_cseq(t_msg)->number.len,get_cseq(t_msg)->number.s) */
282                                         && /*cseq_nr*/ !memcmp(get_cseq(t_msg)->number.s,
283                                                 get_cseq(p_msg)->number.s,get_cseq(p_msg)->number.len)
284                         /* && fprintf(stderr,"OK. URI %d |%.*s| |%.*s|\n",
285                         p_cell->uas.status,p_msg->first_line.u.request.uri.len,
286                         translate_pointer(p_msg->orig, p_msg->buf,
287                                 p_msg->first_line.u.request.uri.s),
288                         t_msg->first_line.u.request.uri.len,
289                         t_msg->first_line.u.request.uri.s) */
290                                         && EQ_REQ_URI_STR
291                         /* && fprintf(stderr,"OK. VIA |%.*s| |%.*s|\n",
292                             (p_msg->via1->bsize-(p_msg->via1->name.s-
293                             (p_msg->via1->hdr.s+p_msg->via1->hdr.len))),
294                             translate_pointer(p_msg->orig,p_msg->buf,
295                             p_msg->via1->name.s),
296                                         (t_msg->via1->bsize-(t_msg->via1->name.s-
297                             (t_msg->via1->hdr.s+t_msg->via1->hdr.len))),
298                                                 t_msg->via1->name.s) */
299                                         && EQ_VIA_STR(via1)
300                         /* && fprintf(stderr,"OK. from |%.*s| |%.*s|\n",
301                         p_msg->from->body.len, translate_pointer(p_msg->orig,
302                             p_msg->buf,p_msg->from->body.s),
303                         t_msg->from->body.len,t_msg->from->body.s) */
304                                         && EQ_STR(from)
305                                         /* && fprintf(stderr,"OK\n") */ )
306                                         { /* WE FOUND THE GOLDEN EGG !!!! */
307                                                 DBG("DEBUG: t_lookupOriginalT: canceled transaction"
308                                                         " found (%p)! \n",p_cell );
309                                                 return p_cell;
310                                         }
311                 /* next transaction */
312                 tmp_cell = p_cell;
313                 p_cell = p_cell->next_cell;
314         }
315
316         /* no transaction found */
317         DBG("DEBUG: t_lookupOriginalT: no CANCEL maching found! \n" );
318         return 0;
319 }
320
321
322
323
324 /* Returns 0 - nothing found
325  *         1  - T found
326  */
327 int t_reply_matching( struct sip_msg *p_msg , int *p_branch ,
328                                                                                          int *local_cancel)
329 {
330         struct cell*  p_cell;
331         int hash_index   = 0;
332         int entry_label  = 0;
333         int branch_id    = 0;
334         char  *hashi, *branchi, *p, *n;
335         int hashl, branchl;
336         int scan_space;
337 #ifndef USE_SYNONIM
338         char *loopi;
339         int loopl;
340 #else
341         char *syni;
342         int synl;
343 #endif
344
345         /* split the branch into pieces: loop_detection_check(ignored),
346          hash_table_id, synonym_id, branch_id */
347
348         if (!(p_msg->via1 && p_msg->via1->branch && p_msg->via1->branch->value.s))
349                 goto nomatch2;
350
351         p=p_msg->via1->branch->value.s;
352         scan_space=p_msg->via1->branch->value.len;
353
354 #ifndef USE_SYNONIM
355         /* loop detection ... ignore */
356         n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR );
357         loopl = n-p;
358         scan_space-= loopl;
359         if (n==p || scan_space<2 || *n!=BRANCH_SEPARATOR) goto nomatch2;
360         loopi=p;
361         p=n+1; scan_space--;
362 #endif
363
364         /* hash_id */
365         n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR);
366         hashl=n-p;
367         scan_space-=hashl;
368         if (!hashl || scan_space<2 || *n!=BRANCH_SEPARATOR) goto nomatch2;
369         hashi=p;
370         p=n+1;scan_space--;
371
372 #ifdef USE_SYNONIM
373         /* sequence id */
374         n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR);
375         synl=n-p;
376         scan_space-=synl;
377         if (!synl || scan_space<2 || *n!=BRANCH_SEPARATOR) goto nomatch2;
378         syni=p;
379         p=n+1;scan_space--;
380 #endif
381
382         /* branch id  -  should exceed the scan_space */
383         n=eat_token_end( p, p+scan_space );
384         branchl=n-p;
385         if (!branchl ) goto nomatch2;
386         branchi=p;
387
388         /* sanity check */
389         if ((hash_index=reverse_hex2int(hashi, hashl))<0||hash_index>=TABLE_ENTRIES
390                 || (branch_id=reverse_hex2int(branchi, branchl))<0||branch_id>=MAX_FORK
391 #ifdef USE_SYNONIM
392                 || (entry_label=reverse_hex2int(syni, synl))<0
393 #else
394                 || loopl!=MD5_LEN
395 #endif
396         ) {
397                 DBG("DEBUG: t_reply_matching: poor reply lables %d label %d "
398                         "branch %d\n",hash_index, entry_label, branch_id );
399                 goto nomatch2;
400         }
401
402
403         DBG("DEBUG: t_reply_matching: hash %d label %d branch %d\n",
404                 hash_index, entry_label, branch_id );
405
406
407         /* search the hash table list at entry 'hash_index'; lock the
408            entry first 
409         */
410         lock(&(hash_table->entrys[hash_index].mutex));
411         for (p_cell = hash_table->entrys[hash_index].first_cell; p_cell; 
412                 p_cell=p_cell->next_cell) {
413
414                 /* does method match ? */
415                 if (get_cseq(p_msg)->method.len==
416                           get_cseq(p_cell->uas.request)->method.len 
417                         && get_cseq(p_msg)->method.s[0]==
418                           get_cseq(p_cell->uas.request)->method.s[0]) {
419                                 *local_cancel=0;
420                 /* or is it perhaps a CANCEL ? */
421                 } else if ( p_cell->uas.request->REQ_METHOD==METHOD_INVITE 
422                         && get_cseq(p_msg)->method.len==CANCEL_LEN 
423                         && memcmp( get_cseq(p_msg)->method.s, CANCEL, CANCEL_LEN )==0 
424                         && p_cell->uac[branch_id].request.cancel!=NO_CANCEL 
425                         && p_cell->uac[branch_id].request.cancel!=EXTERNAL_CANCEL ) {
426                                 *local_cancel=1;
427                 } else { /* method mismatched */
428                         continue;
429                 };
430                 #ifdef USE_SYNONIM
431                 if (p_cell->label != entry_label) 
432                         continue;
433                 #else
434                 if ( p_cell->uas.request->add_to_branch_len<MD5_LEN 
435                          || memcmp(p_cell->uas.request->add_to_branch_s,loopi,MD5_LEN)!=0)
436                                 continue;
437                 #endif
438                 /* sanity check ... too high branch ? */
439                 if ( branch_id>=p_cell->nr_of_outgoings )
440                         continue;
441                 /* we passed all disqualifying factors .... the transaction has been
442                    matched !
443                 */
444                 T=p_cell;
445                 *p_branch = branch_id;
446                 T_REF( T );
447                 unlock(&(hash_table->entrys[hash_index].mutex));
448                 DBG("DEBUG: t_reply_matching: reply matched (T=%p,ref=%x)!\n",
449                         T,T->ref_bitmap);
450                 return 1;
451         } /* for cycle */
452
453         /* nothing found */
454         unlock(&(hash_table->entrys[hash_index].mutex));
455         DBG("DEBUG: t_reply_matching: no matching transaction exists\n");
456
457 nomatch2:
458         DBG("DEBUG: t_reply_matching: failure to match a transaction\n");
459         *p_branch = -1;
460         T = 0;
461         return -1;
462 }
463
464
465
466
467 /* Functions update T (T gets either a valid pointer in it or it equals zero) if no transaction
468   * for current message exists;
469   * it returns 1 if found, 0 if not found, -1 on error
470   */
471 int t_check( struct sip_msg* p_msg , int *param_branch, int *param_cancel)
472 {
473         int local_branch;
474         int local_cancel;
475
476         /* is T still up-to-date ? */
477         DBG("DEBUG: t_check: msg id=%d global id=%d T start=%p\n", 
478                 p_msg->id,global_msg_id,T);
479         if ( p_msg->id != global_msg_id || T==T_UNDEFINED )
480         {
481                 global_msg_id = p_msg->id;
482                 T = T_UNDEFINED;
483                 /* transaction lookup */
484                 if ( p_msg->first_line.type==SIP_REQUEST ) {
485                         /* force parsing all the needed headers*/
486                         if (parse_headers(p_msg, HDR_EOH )==-1)
487                                 return -1;
488                         t_lookup_request( p_msg , 0 /* unlock before returning */ );
489                 } else {
490                         if ( parse_headers(p_msg, HDR_VIA1|HDR_TO|HDR_CSEQ )==-1
491                         || !p_msg->via1 || !p_msg->to || !p_msg->cseq )
492                                 return -1;
493                         t_reply_matching( p_msg ,
494                                 ((param_branch!=0)?(param_branch):(&local_branch)),
495                                 ((param_cancel!=0)?(param_cancel):(&local_cancel)));
496
497                 }
498 #ifdef EXTRA_DEBUG
499                 if ( T && T!=T_UNDEFINED && T->damocles) {
500                         LOG( L_ERR, "ERROR: transaction %p scheduled for deletion "
501                                 "and called from t_check\n", T);
502                         abort();
503                 }
504 #endif
505                 DBG("DEBUG: t_check: msg id=%d global id=%d T end=%p\n",
506                         p_msg->id,global_msg_id,T);
507         } else {
508                 if (T)
509                         DBG("DEBUG: t_check: T alredy found!\n");
510                 else
511                         DBG("DEBUG: t_check: T previously sought and not found\n");
512         }
513
514         return ((T)?1:0) ;
515 }
516
517
518
519 /* append appropriate branch labels for fast reply-transaction matching
520    to outgoing requests
521 */
522 int add_branch_label( struct cell *trans, struct sip_msg *p_msg, int branch )
523 {
524         char *begin;
525         int size, orig_size;
526
527         /* this is actually a hack made by Bogdan; I wanted to have a structure
528            to which anybody can append some branch stuff which may be utilizied
529            during reply processing; Bogdan ignored that and resets it all the
530            time to construct multiple branches for multiple via's during
531            forking (otherwise, the next branch would be now appended to
532            previous branch)
533
534            keywords: HACK
535         */
536         
537         p_msg->add_to_branch_len = 0; /*bogdan*/
538
539
540         begin=p_msg->add_to_branch_s+p_msg->add_to_branch_len;
541         orig_size = size=MAX_BRANCH_PARAM_LEN - p_msg->add_to_branch_len;
542
543 #ifndef USE_SYNONIM
544         if (memcpy(begin,trans->md5,MD5_LEN)) {begin+=MD5_LEN;size-=MD5_LEN;} else return -1;
545         if (size) { *begin=BRANCH_SEPARATOR; begin++; size--; } else return -1;
546 #endif
547         if (int2reverse_hex( &begin, &size, trans->hash_index)==-1) return -1;
548 #ifdef USE_SYNONIM
549         if (size) { *begin=BRANCH_SEPARATOR; begin++; size--; } else return -1;
550         if (int2reverse_hex( &begin, &size, trans->label)==-1) return -1;
551 #endif
552         if (size) { *begin=BRANCH_SEPARATOR; begin++; size--; } else return -1;
553         if (int2reverse_hex( &begin, &size, branch)==-1) return -1;
554
555         p_msg->add_to_branch_len+=(orig_size-size);
556         DBG("DEBUG: XXX branch label created now: %.*s\n",
557                 p_msg->add_to_branch_len, p_msg->add_to_branch_s );
558         return 0;
559
560 }
561
562
563
564
565 /* atomic "add_if_new" construct; it returns:
566         AIN_ERROR       if a fatal error (e.g, parsing) occured
567         AIN_RETR        it's a retransmission
568         AIN_NEW         it's a new request
569         AIN_NEWACK      it's an ACK for which no transaction exists
570         AIN_OLDACK      it's an ACK for an existing transaction
571 */
572 enum addifnew_status t_addifnew( struct sip_msg* p_msg )
573 {
574
575         int ret, lret;
576         struct cell *new_cell;
577
578         /* is T still up-to-date ? */
579         DBG("DEBUG: t_addifnew: msg id=%d , global msg id=%d ,"
580                 " T on entrance=%p\n",p_msg->id,global_msg_id,T);
581         if ( p_msg->id != global_msg_id || T==T_UNDEFINED 
582                 /* if someone tried to do something previously by mistake with
583                    a transaction which did not exist yet, try to look-up
584                    the transacion too */
585                 || T==T_NULL)
586         {
587                 global_msg_id = p_msg->id;
588                 T = T_UNDEFINED;
589                 /* transaction lookup */
590                 /* force parsing all the needed headers*/
591                 if (parse_headers(p_msg, HDR_EOH )==-1)
592                         return AIN_ERROR;
593                 lret = t_lookup_request( p_msg, 1 /* leave locked */ );
594                 if (lret==0) return AIN_ERROR;
595                 if (lret==-1) {
596                         /* transaction not found, it's a new request */
597                         if ( p_msg->REQ_METHOD==METHOD_ACK ) {
598                                 ret=AIN_NEWACK;
599                         } else {
600                                 /* add new transaction */
601                                 new_cell = build_cell( p_msg ) ;
602                                 if  ( !new_cell ){
603                                         LOG(L_ERR, "ERROR: t_addifnew: out of mem:\n");
604                                         ret = AIN_ERROR;
605                                 } else {
606                                         insert_into_hash_table_unsafe( hash_table , new_cell );
607                                         ret = AIN_NEW;
608                                         T=new_cell;
609                                         T_REF(T);
610                                 }
611                         }
612                         unlock(&(hash_table->entrys[p_msg->hash_index].mutex));
613                         return ret;
614                 } else {
615                         /* tramsaction found, it's a retransmission  or ACK */
616                         if (p_msg->REQ_METHOD!=METHOD_ACK)
617                                 return AIN_RETR;
618                         else {
619                                 if (T->uas.isACKed)
620                                         return AIN_RTRACK;
621                                 else
622                                         return AIN_OLDACK;
623                                 }
624                         //return p_msg->REQ_METHOD==METHOD_ACK ? AIN_OLDACK : AIN_RETR;
625                 }
626         } else {
627                 if (T)
628                         LOG(L_ERR, "ERROR: t_addifnew: already "
629                         "processing this message, T found!\n");
630                 else
631                         LOG(L_ERR, "ERROR: t_check_new_request: already "
632                         "processing this message, T not found!\n");
633                 return AIN_ERROR;
634         }
635 }
636
637
638