memory access syncing protection added
[sip-router] / modules / tm / t_funcs.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 struct cell         *T;
15 unsigned int     global_msg_id;
16 struct s_table*  hash_table;
17
18
19
20
21 /* determine timer length and put on a correct timer list */
22 inline void set_timer( struct s_table *hash_table,
23         struct timer_link *new_tl, enum lists list_id )
24 {
25         unsigned int timeout;
26         struct timer* list;
27         static enum lists to_table[NR_OF_TIMER_LISTS] =
28                 {       FR_TIME_OUT, INV_FR_TIME_OUT, WT_TIME_OUT, DEL_TIME_OUT,
29                         RETR_T1, RETR_T1 << 1,  RETR_T1 << 2, RETR_T2 };
30
31         if (list_id<FR_TIMER_LIST || list_id>=NR_OF_TIMER_LISTS) {
32                 LOG(L_CRIT, "ERROR: set_timer: unkown list: %d\n", list_id);
33 #ifdef EXTRA_DEBUG
34                 abort();
35 #endif
36                 return;
37         }
38         timeout = to_table[ list_id ];
39         list= &(hash_table->timers[ list_id ]);
40 /*
41         add_to_tail_of_timer_list( &(hash_table->timers[ list_id ]),
42                 new_tl,get_ticks()+timeout);
43 */
44         lock(  list->mutex );
45         /* make sure I'm not already on a list */
46         remove_timer_unsafe( new_tl );
47         add_timer_unsafe( list, new_tl, get_ticks()+timeout);
48         unlock( list->mutex );
49 }
50
51 /* remove from timer list */
52 inline void reset_timer( struct s_table *hash_table,
53         struct timer_link* tl )
54 {
55         lock( timer_group_lock[ tl->tg ] );
56         remove_timer_unsafe( tl );
57         unlock( timer_group_lock[ tl->tg ] );
58 }
59
60 static inline void reset_retr_timers( struct s_table *h_table,
61         struct cell *p_cell )
62 {
63         int ijk;
64         struct retrans_buff *rb;
65
66         DBG("DEBUG:stop_RETR_and_FR_timers : start \n");
67         /* lock the first timer list of the FR group -- all other
68            lists share the same lock
69         */
70         lock(  hash_table->timers[FR_TIMER_LIST].mutex );
71         /* reset_timer( h_table, &(p_cell->outbound_response.retr_timer)); */
72         remove_timer_unsafe( & p_cell->outbound_response.retr_timer );
73         for( ijk=0 ; ijk<(p_cell)->nr_of_outgoings ; ijk++ )  { 
74                         if ( rb = p_cell->outbound_request[ijk] ) {
75                                 /* reset_timer(h_table, &(rb->retr_timer)); */
76                                 remove_timer_unsafe( & rb->retr_timer );
77                         }
78                 } 
79         unlock(  hash_table->timers[FR_TIMER_LIST].mutex );
80         lock(  hash_table->timers[RT_T1_TO_1].mutex );
81         /* reset_timer( h_table, &(p_cell->outbound_response.fr_timer)); */
82         remove_timer_unsafe( & p_cell->outbound_response.fr_timer );
83         for( ijk=0 ; ijk<(p_cell)->nr_of_outgoings ; ijk++ )  { 
84                         if ( rb = p_cell->outbound_request[ijk] ) {
85                                 /* reset_timer(h_table, &(rb->fr_timer)); */
86                                 remove_timer_unsafe( & rb->fr_timer );
87                         }
88                 } 
89         unlock(  hash_table->timers[RT_T1_TO_1].mutex );
90         DBG("DEBUG:stop_RETR_and_FR_timers : stop\n");
91 }
92
93 int tm_startup()
94 {
95    /* building the hash table*/
96    hash_table = init_hash_table();
97    if (!hash_table)
98       return -1;
99
100 #define init_timer(_id,_handler) \
101         hash_table->timers[(_id)].timeout_handler=(_handler); \
102         hash_table->timers[(_id)].id=(_id);
103
104    init_timer( RT_T1_TO_1, retransmission_handler );
105    init_timer( RT_T1_TO_2, retransmission_handler );
106    init_timer( RT_T1_TO_3, retransmission_handler );
107    init_timer( RT_T2, retransmission_handler );
108    init_timer( FR_TIMER_LIST, final_response_handler );
109    init_timer( FR_INV_TIMER_LIST, final_response_handler );
110    init_timer( WT_TIMER_LIST, wait_handler );
111    init_timer( DELETE_LIST, delete_handler );
112
113    /* register the timer function */
114    register_timer( timer_routine , hash_table , 1 );
115
116    /*first msg id*/
117    global_msg_id = 0;
118    T = T_UNDEFINED;
119
120    return 0;
121 }
122
123
124
125
126 void tm_shutdown()
127 {
128     struct timer_link  *tl, *end, *tmp;
129     int i;
130
131     DBG("DEBUG: tm_shutdown : start\n");
132     /*remember the DELETE LIST */
133     tl = hash_table->timers[DELETE_LIST].first_tl.next_tl;
134         end = & hash_table->timers[DELETE_LIST].last_tl;
135     /*unlink the lists*/
136     for( i=0; i<NR_OF_TIMER_LISTS ; i++ )
137     {
138        //lock( hash_table->timers[i].mutex );
139                 reset_timer_list( hash_table, i );
140        //unlock( hash_table->timers[i].mutex );
141     }
142
143     DBG("DEBUG: tm_shutdown : empting DELETE list\n");
144     /* deletes all cells from DELETE_LIST list (they are no more accessible from enrys) */
145         while (tl!=end) {
146                 tmp=tl->next_tl;
147                 free_cell((struct cell*)tl->payload);
148                  tl=tmp;
149         }
150
151     /* destroy the hash table */
152     DBG("DEBUG: tm_shutdown : empting hash table\n");
153     free_hash_table( hash_table );
154     DBG("DEBUG: tm_shutdown : removing semaphores\n");
155         lock_cleanup();
156     DBG("DEBUG: tm_shutdown : done\n");
157 }
158
159
160
161
162 /* function returns:
163  *       1 - a new transaction was created
164  *      -1 - error, including retransmission
165  */
166 int t_add_transaction( struct sip_msg* p_msg )
167 {
168    struct cell*    new_cell;
169
170    DBG("DEBUG: t_add_transaction: adding......\n");
171
172    /* sanity check: ACKs can never establish a transaction */
173    if ( p_msg->REQ_METHOD==METHOD_ACK )
174    {
175        LOG(L_ERR, "ERROR: add_transaction: ACK can't be used to add transaction\n");
176       return -1;
177    }
178
179    /* it's about the same transaction or not?*/
180         /* if (t_check( p_msg , 0 )==-1) return -1; */
181
182    /* if the lookup's result is not 0 means that it's a retransmission */
183    /* if ( T )
184    {
185       LOG(L_ERR,"ERROR: t_add_transaction: won't add a retransmission\n");
186       return -1;
187    } */
188
189    /* creates a new transaction */
190    new_cell = build_cell( p_msg ) ;
191    DBG("DEBUG: t_add_transaction: new transaction created %p\n", new_cell);
192    if  ( !new_cell ){
193            LOG(L_ERR, "ERROR: add_transaction: out of mem:\n");
194            sh_status();
195       return -1;
196         }
197    /*insert the transaction into hash table*/
198    insert_into_hash_table( hash_table , new_cell );
199    DBG("DEBUG: t_add_transaction: new transaction inserted, hash: %d\n", new_cell->hash_index );
200
201    T = new_cell;
202         T_REF(T);
203    return 1;
204 }
205
206
207
208 #ifdef _OBSOLETED_TM
209 /* function returns:
210  *       1 - forward successfull
211  *      -1 - error during forward
212  */
213 int t_forward( struct sip_msg* p_msg , unsigned int dest_ip_param , unsigned int dest_port_param )
214 {
215         unsigned int  dest_ip     = dest_ip_param;
216         unsigned int  dest_port  = dest_port_param;
217         int            branch;
218         unsigned int  len;
219         char                          *buf, *shbuf;
220         struct retrans_buff  *rb;
221
222         buf=NULL;
223         shbuf = NULL;
224         branch = 0;     /* we don't do any forking right now */
225
226         /* it's about the same transaction or not? */
227         /* if (t_check( p_msg , 0 )==-1) return -1; */
228
229         /*if T hasn't been found after all -> return not found (error) */
230         /*
231         if ( !T )
232         {
233                 DBG("DEBUG: t_forward: no transaction found for request forwarding\n");
234                 return -1;
235         }
236         */
237
238         /*if it's an ACK and the status is not final or is final, but error the
239         ACK is not forwarded*/
240         if ( p_msg->REQ_METHOD==METHOD_ACK  && (T->status/100)!=2 ) {
241                 DBG("DEBUG: t_forward: local ACK; don't forward\n");
242                 return 1;
243         }
244
245         /* if it's forwarded for the first time ; else the request is retransmited
246          * from the transaction buffer
247          * when forwarding an ACK, this condition will be all the time false because
248          * the forwarded INVITE is in the retransmission buffer */
249         if ( T->outbound_request[branch]==NULL )
250 {
251                 DBG("DEBUG: t_forward: first time forwarding\n");
252                 /* special case : CANCEL */
253                 if ( p_msg->REQ_METHOD==METHOD_CANCEL  )
254                 {
255                         DBG("DEBUG: t_forward: it's CANCEL\n");
256                         /* find original cancelled transaction; if found, use its
257                            next-hops; otherwise use those passed by script */
258                         if (T->T_canceled==T_UNDEFINED)
259                                 T->T_canceled = t_lookupOriginalT( hash_table , p_msg );
260                         /* if found */
261                         if ( T->T_canceled!=T_NULL )
262                         {
263                                 /* if in 1xx status, send to the same destination */
264                                 if ( (T->T_canceled->status/100)==1 )
265                                 {
266                                         DBG("DEBUG: t_forward: it's CANCEL and I will send "
267                                                 "to the same place where INVITE went\n");
268                                         dest_ip=T->T_canceled->outbound_request[branch]->
269                                                 to.sin_addr.s_addr;
270                                         dest_port = T->T_canceled->outbound_request[branch]->
271                                                 to.sin_port;
272                                 } else { /* transaction exists, but nothing to cancel */
273                                         DBG("DEBUG: t_forward: it's CANCEL but "
274                                                 "I have nothing to cancel here\n");
275                                         /* continue forwarding CANCEL as a stand-alone transaction */
276                                 }
277                         } else { /* transaction does not exists  */
278                                 DBG("DEBUG: t_forward: canceled request not found! "
279                                         "nothing to CANCEL\n");
280                         }
281                 }/* end special case CANCEL*/
282
283                 if ( add_branch_label( T, T->inbound_request , branch )==-1)
284                         goto error;
285                 if ( add_branch_label( T, p_msg , branch )==-1)
286                         goto error;
287                 if ( !(buf = build_req_buf_from_sip_req  ( p_msg, &len)))
288                         goto error;
289
290                 /* allocates a new retrans_buff for the outbound request */
291                 DBG("DEBUG: t_forward: building outbound request\n");
292                 shm_lock();
293                 T->outbound_request[branch] = rb =
294                         (struct retrans_buff*)shm_malloc_unsafe( sizeof(struct retrans_buff)  );
295                 if (!rb)
296                 {
297                         LOG(L_ERR, "ERROR: t_forward: out of shmem\n");
298                         shm_unlock();
299                         goto error;
300                 }
301                 shbuf = (char *) shm_malloc_unsafe( len );
302                 if (!shbuf)
303                 {
304                         LOG(L_ERR, "ERROR: t_forward: out of shmem buffer\n");
305                         shm_unlock();
306                         goto error;
307                 }
308                 shm_unlock();
309                 memset( rb , 0 , sizeof (struct retrans_buff) );
310                 rb->retr_timer.tg=TG_RT;
311                 rb->fr_timer.tg=TG_FR;
312                 rb->retr_buffer = shbuf;
313                 rb->retr_timer.payload =  rb;
314                 rb->fr_timer.payload =  rb;
315                 rb->to.sin_family = AF_INET;
316                 rb->my_T =  T;
317                 T->nr_of_outgoings = 1;
318                 rb->bufflen = len ;
319                 memcpy( rb->retr_buffer , buf , len );
320                 free( buf ) ; buf=NULL;
321
322                 DBG("DEBUG: t_forward: starting timers (retrans and FR) %d\n",get_ticks() );
323                 /*sets and starts the FINAL RESPONSE timer */
324                 set_timer( hash_table, &(rb->fr_timer), FR_TIMER_LIST );
325
326                 /* sets and starts the RETRANS timer */
327                 rb->retr_list = RT_T1_TO_1;
328                 set_timer( hash_table, &(rb->retr_timer), RT_T1_TO_1 );
329         }/* end for the first time */
330
331         /* if we are forwarding an ACK*/
332         if (  p_msg->REQ_METHOD==METHOD_ACK &&
333                 T->relaied_reply_branch>=0 &&
334                 T->relaied_reply_branch<=T->nr_of_outgoings)
335         {
336                 DBG("DEBUG: t_forward: forwarding ACK [%d]\n",T->relaied_reply_branch);
337                 t_build_and_send_ACK( T, branch ,
338                         T->inbound_response[T->relaied_reply_branch] );
339                 T->inbound_request_isACKed = 1;
340                 return 1;
341         } else /* if we are forwarding a CANCEL*/
342         if (  p_msg->REQ_METHOD==METHOD_CANCEL )
343         {
344                 DBG("DEBUG: t_forward: forwarding CANCEL \n");
345                 /* if no transaction to CANCEL
346                     or if the canceled transaction has a final status -> drop the CANCEL*/
347                 if ( T->T_canceled!=T_NULL && T->T_canceled->status>=200)
348                 {
349                         reset_timer( hash_table, &(rb->fr_timer ));
350                         reset_timer( hash_table, &(rb->retr_timer ));
351                         return 1;
352                 }
353         }
354
355         /* send the request */
356         /* known to be in network order */
357         rb->to.sin_port     =  dest_port;
358         rb->to.sin_addr.s_addr =  dest_ip;
359         rb->to.sin_family = AF_INET;
360
361         SEND_BUFFER( rb );
362
363    return 1;
364
365 error:
366         if (shbuf) shm_free(shbuf);
367         if (rb) {
368                 shm_free(rb);
369                 T->outbound_request[branch]=NULL;
370         }
371         if (buf) free( buf );
372
373         return -1;
374
375 }
376
377
378 /* Forwards the inbound request to dest. from via.  Returns:
379  *       1 - forward successfull
380  *      -1 - error during forward
381  */
382 int t_forward_uri( struct sip_msg* p_msg  )
383 {
384    unsigned int     ip, port;
385
386    if ( get_ip_and_port_from_uri( p_msg , &ip, &port)<0 )
387    {
388       LOG( L_ERR , "ERROR: t_forward_uri: unable to extarct ip and port from uri!\n" );
389       return -1;
390    }
391
392    return t_forward( p_msg , ip , port );
393 }
394 #endif
395
396
397 /*  This function is called whenever a reply for our module is received; 
398   * we need to register  this function on module initialization;
399   *  Returns :   0 - core router stops
400   *              1 - core router relay statelessly
401   */
402 int t_on_reply_received( struct sip_msg  *p_msg )
403 {
404         unsigned int  branch,len, msg_status, msg_class, save_clone;
405         struct sip_msg *clone, *backup;
406         int relay;
407         int start_fr;
408         int is_invite;
409         struct retrans_buff *rb;
410
411
412         /* make sure we know the assosociated tranaction ... */
413         if (t_check( p_msg  , &branch )==-1) return 1;
414         /* ... if there is no such, tell the core router to forward statelessly */
415         if ( T<=0 ) return 1;
416
417         DBG("DEBUG: t_on_reply_received: Original status =%d\n",T->status);
418
419         /* it can take quite long -- better do it now than later 
420            inside a reply_lock */
421         if (!(clone=sip_msg_cloner( p_msg ))) {
422                 goto error;
423         }
424         msg_status=p_msg->REPLY_STATUS;
425         msg_class=REPLY_CLASS(p_msg);
426         is_invite= T->inbound_request->REQ_METHOD==METHOD_INVITE;
427
428         /* *** stop timers *** */
429         rb=T->outbound_request[branch];
430         /* stop retransmission */
431         reset_timer( hash_table, &(rb->retr_timer));
432         /* stop final response timer only if I got a final response */
433         if ( msg_class>1 )
434                 reset_timer( hash_table, &(rb->fr_timer));
435
436         LOCK_REPLIES( T );
437         /* if a got the first prov. response for an INVITE ->
438            change FR_TIME_OUT to INV_FR_TIME_UT */
439         start_fr = !T->inbound_response[branch] && msg_class==1 && is_invite;
440
441         /* *** store and relay message as needed *** */
442         relay = t_should_relay_response( T , msg_status, branch, &save_clone );
443
444         if (save_clone) {
445                 /* release previously hold message */
446                 backup = T->inbound_response[branch];
447                 T->inbound_response[branch] = clone;
448         } else {
449                 backup = NULL;
450                 sip_msg_free( clone );
451         }
452
453         if (relay>=0 &&  push_reply_from_uac_to_uas( T, relay)==-1 ) {
454                 /* restore original state first */
455                 if (save_clone) T->inbound_response[branch] = backup;
456                 /* restart FR */
457                 start_fr=1;
458                 goto cleanup;
459         }
460
461
462         /* *** ACK handling *** */
463         if ( is_invite )
464         {
465                 if ( T->outbound_ack[branch] )
466                 {   /*retransmit*/
467                         SEND_BUFFER( T->outbound_ack[branch] );
468                 } else if (msg_class>2 ) {   /*on a non-200 reply to INVITE*/
469                         DBG("DEBUG: t_on_reply_received: >=3xx reply to INVITE: send ACK\n");
470                         if ( t_build_and_send_ACK( T , branch , p_msg )==-1)
471                         {
472                         LOG( L_ERR , "ERROR: t_on_reply_received: unable to send ACK\n" );
473                                         /* restart FR */
474                                         start_fr=1;
475                         }
476                 }
477         }
478 cleanup:
479         UNLOCK_REPLIES( T );
480         if (backup) sip_msg_free(backup);
481         if (start_fr) set_timer( hash_table, &(rb->fr_timer), FR_INV_TIMER_LIST );
482         /* restart retransmission if a provisional response came for 
483            a non_INVITE -> retrasmit at RT_T2*/
484         if ( msg_class==1 && !is_invite )
485         {
486                 rb->retr_list = RT_T2;
487                 set_timer( hash_table, &(rb->retr_timer), RT_T2 );
488         }
489 error:
490         T_UNREF( T );
491         /* don't try to relay statelessly on error; on troubles, simply do nothing;
492            that will make the other party to retransmit; hopefuly, we'll then 
493            be better off */
494         return 0;
495 }
496
497 #ifdef _OBSOLETED_TM
498 int t_on_request_received( struct sip_msg  *p_msg , 
499         unsigned int ip , unsigned int port)
500 {
501         if ( t_check( p_msg , 0 ) )
502         {
503                 if ( p_msg->first_line.u.request.method_value==METHOD_ACK )
504                 {
505                         DBG( "SER: ACK received -> t_release\n");
506                         if ( !t_forward( p_msg , ip , port ) )
507                         {
508                                 DBG( "SER: WARNING: bad forward\n");
509                         }
510                         if ( !t_release_transaction( p_msg ) )
511                         {
512                                 DBG( "SER: WARNING: bad t_release\n");
513                         }
514                 }
515                 else
516                 {
517                         if ( !t_retransmit_reply( p_msg ) )
518                         {
519                                 DBG( "SER: WARNING: bad t_retransmit_reply\n");
520                         }
521                         DBG( "SER: yet another annoying retranmission\n");
522                 }
523                 t_unref( /* p_msg */ );
524         } else {
525                 if ( p_msg->first_line.u.request.method_value==METHOD_ACK )
526                 {
527                         DBG( "SER: forwarding ACK  statelessly\n");
528                         /* no established transaction ... forward ACK just statelessly*/
529                         forward_request( p_msg , mk_proxy_from_ip(ip,port) );
530                 }
531                 else
532                 {
533                         /* establish transaction*/
534                         if ( !t_add_transaction(p_msg) )
535                         {
536                                 DBG( "SER: ERROR in ser: t_add_transaction\n");
537                         }
538                         /* reply */
539                         if ( p_msg->first_line.u.request.method_value==METHOD_CANCEL)
540                         {
541                                 DBG( "SER: new CANCEL\n");
542                                 if ( !t_send_reply( p_msg , 200, "glad to cancel") )
543                                 {
544                                         DBG( "SER:ERROR: t_send_reply\n");
545                                 }
546                         } else {
547                                 DBG( "SER: new transaction\n");
548                                 if ( !t_send_reply( p_msg , 100 , "trying -- your call is important to us") )
549                                 {
550                                         DBG( "SER: ERROR: t_send_reply (100)\n");
551                                 }
552                         }
553                         if ( !t_forward( p_msg, ip, port ) )
554                         {
555                                 DBG( "SER:ERROR: t_forward \n");
556                         }
557                         t_unref( /* p_msg */ );
558                 }
559         }
560
561 }
562
563
564
565
566 int t_on_request_received_uri( struct sip_msg  *p_msg )
567 {
568         unsigned int     ip, port;
569
570         if ( get_ip_and_port_from_uri( p_msg , &ip, &port)<0 )
571         {
572                 LOG( L_ERR , "ERROR: t_on_request_received_uri: \
573                     unable to extract ip and port from uri!\n" );
574                 return -1;
575         }
576
577         return t_on_request_received( p_msg , ip , port );
578 }
579
580 #endif
581
582
583 /*   returns 1 if everything was OK or -1 for error
584   */
585 int t_release_transaction( struct sip_msg* p_msg)
586 {
587 /*
588         if (t_check( p_msg  , 0 )==-1) return 1;
589
590    if ( T && T!=T_UNDEFINED )
591 */
592       return t_put_on_wait( T );
593
594 /*   return 1; */
595 }
596
597
598
599
600 /* Retransmits the last sent inbound reply.
601
602   * input: p_msg==request for which I want to retransmit an associated
603     reply
604   * Returns  -1 -error
605   *                1 - OK
606   */
607 int t_retransmit_reply( struct sip_msg* p_msg   )
608 {
609 /*      if (t_check( p_msg  , 0 )==-1) return 1; */
610
611    /* if no transaction exists or no reply to be resend -> out */
612 /*   if ( T ) */
613    {
614         LOCK_REPLIES( T );
615         SEND_BUFFER( & T->outbound_response );
616         UNLOCK_REPLIES( T );
617         return 1;
618    }
619
620   /* no transaction found */
621 /*   return -1; */
622 }
623
624
625
626
627 int t_unref( /* struct sip_msg* p_msg */ )
628 {
629 /*
630         if (T==T_UNDEFINED || T==T_NULL)
631                 return -1;
632 */
633         T_UNREF( T );
634         T=T_UNDEFINED;
635         return 1;
636 }
637
638
639
640
641 /* Force a new response into inbound response buffer.
642   * returns 1 if everything was OK or -1 for erro
643   */
644 int t_send_reply(  struct sip_msg* p_msg , unsigned int code , char * text )
645 {
646         unsigned int len, buf_len;
647         char * buf, *shbuf;
648         struct retrans_buff *rb;
649
650         DBG("DEBUG: t_send_reply: entered\n");
651         /* if (t_check( p_msg , 0 )==-1) return -1;
652
653         if (!T)
654         {
655                 LOG(L_ERR, "ERROR: t_send_reply: cannot send a t_reply to a message "
656                         "for which no T-state has been established\n");
657                 return -1;
658         }
659         */
660
661         buf = build_res_buf_from_sip_req( code , text , T->inbound_request , &len );
662         DBG("DEBUG: t_send_reply: buffer computed\n");
663         if (!buf)
664         {
665                 DBG("DEBUG: t_send_reply: response building failed\n");
666                 goto error;
667         }
668
669         LOCK_REPLIES( T );
670
671         rb = & T->outbound_response;
672         if (!rb->retr_buffer) {
673                 /* initialize retransmission structure */
674                 memset( rb , 0 , sizeof (struct retrans_buff) );
675                 if (update_sock_struct_from_via(  &(rb->to),  p_msg->via1 )==-1)
676                 {
677                         LOG(L_ERR, "ERROR: t_send_reply: cannot lookup reply dst: %s\n",
678                                 p_msg->via1->host.s );
679                         goto error;
680                 }
681
682                 rb->retr_timer.tg=TG_RT;
683                 rb->fr_timer.tg=TG_FR;
684                 rb->retr_timer.payload = rb;
685                 rb->fr_timer.payload = rb;
686                 rb->to.sin_family = AF_INET;
687                 rb->my_T = T;
688                 rb->reply = code;
689         }
690
691
692         /* if this is a first reply (?100), longer replies will probably follow;
693            try avoiding shm_resize by higher buffer size */
694         buf_len = rb->retr_buffer ? len : len + REPLY_OVERBUFFER_LEN;
695
696         if (! (rb->retr_buffer = (char*)shm_resize( rb->retr_buffer, buf_len )))
697         {
698                 LOG(L_ERR, "ERROR: t_send_reply: cannot allocate shmem buffer\n");
699                 goto error2;
700         }
701         rb->bufflen = len ;
702         memcpy( rb->retr_buffer , buf , len );
703         T->status = code;
704         SEND_BUFFER( rb );
705         /* needs to be protected too because what timers are set depends
706            on current transactions status
707         */
708         t_update_timers_after_sending_reply( rb );
709         UNLOCK_REPLIES( T );
710
711         free( buf ) ;
712         /* start/stops the proper timers*/
713
714         DBG("DEBUG: t_send_reply: finished\n");
715
716         return 1;
717
718 error2:
719         free ( buf );
720 error:
721         return -1;
722 }
723
724
725
726 /* Push a previously stored reply from UA Client to UA Server
727   * and send it out
728   */
729 static int push_reply_from_uac_to_uas( struct cell* trans , unsigned int branch )
730 {
731         char *buf;
732         unsigned int len, buf_len;
733         struct retrans_buff *rb;
734
735         DBG("DEBUG: push_reply_from_uac_to_uas: start\n");
736         rb= & trans->outbound_response;
737         /* if there is a reply, release the buffer (everything else stays same) */
738         if ( ! rb->retr_buffer ) {
739                 /*init retrans buffer*/
740                 memset( rb , 0 , sizeof (struct retrans_buff) );
741                 if (update_sock_struct_from_via(  &(rb->to),
742                         trans->inbound_response[branch]->via2 )==-1) {
743                                 LOG(L_ERR, "ERROR: push_reply_from_uac_to_uas: "
744                                         "cannot lookup reply dst: %s\n",
745                                 trans->inbound_response[branch]->via2->host.s );
746                                 goto error;
747                 }
748                 rb->retr_timer.tg=TG_RT;
749                 rb->fr_timer.tg=TG_FR;
750                 rb->retr_timer.payload = rb;
751                 rb->fr_timer.payload =  rb;
752                 rb->to.sin_family = AF_INET;
753                 rb->my_T = trans;
754                 rb->reply = trans->inbound_response[branch]->REPLY_STATUS;
755
756         } else {
757                 reset_timer( hash_table, &(rb->retr_timer));
758                 reset_timer( hash_table, &(rb->fr_timer));
759         }
760
761         /*  generate the retrans buffer */
762         buf = build_res_buf_from_sip_res ( trans->inbound_response[branch], &len);
763         if (!buf) {
764                 LOG(L_ERR, "ERROR: push_reply_from_uac_to_uas: "
765                         "no shmem for outbound reply buffer\n");
766                 goto error;
767         }
768
769         /* if this is a first reply (?100), longer replies will probably follow;
770         try avoiding shm_resize by higher buffer size */
771         buf_len = rb->retr_buffer ? len : len + REPLY_OVERBUFFER_LEN;
772         if (! (rb->retr_buffer = (char*)shm_resize( rb->retr_buffer, buf_len )))
773         {
774                 LOG(L_ERR, "ERROR: t_send_reply: cannot allocate shmem buffer\n");
775                 goto error1;
776         }
777         rb->bufflen = len ;
778         memcpy( rb->retr_buffer , buf , len );
779         free( buf ) ;
780
781         /* update the status*/
782         trans->status = trans->inbound_response[branch]->REPLY_STATUS;
783         if ( trans->inbound_response[branch]->REPLY_STATUS>=200 &&
784                 trans->relaied_reply_branch==-1 ) {
785
786                 memcpy( & trans->ack_to, & trans->outbound_request[ branch ]->to,
787                         sizeof( struct sockaddr_in ) );
788                 trans->relaied_reply_branch = branch;
789         }
790
791         /* start/stops the proper timers*/
792         t_update_timers_after_sending_reply( rb );
793
794         /*send the reply*/
795         SEND_BUFFER( rb );
796         return 1;
797
798 error1:
799         free( buf );
800 error:
801         return -1;
802 }
803
804
805
806
807
808 /* ----------------------------HELPER FUNCTIONS-------------------------------- */
809
810
811
812
813
814 /*
815   */
816 int t_update_timers_after_sending_reply( struct retrans_buff *rb )
817 {
818         struct cell *Trans = rb->my_T;
819
820         /* make sure that if we send something final upstream, everything else
821            will be cancelled */
822         if (Trans->status>=300 && Trans->inbound_request->REQ_METHOD==METHOD_INVITE )
823         {
824                 rb->retr_list = RT_T1_TO_1;
825                 set_timer( hash_table, &(rb->retr_timer), RT_T1_TO_1 );
826                 set_timer( hash_table, &(rb->fr_timer), FR_TIMER_LIST );
827         } else if ( Trans->inbound_request->REQ_METHOD==METHOD_CANCEL ) {
828                 if ( Trans->T_canceled==T_UNDEFINED )
829                         Trans->T_canceled = t_lookupOriginalT( hash_table ,
830                                 Trans->inbound_request );
831                 if ( Trans->T_canceled==T_NULL )
832                         return 1;
833                 /* put CANCEL transaction on wait only if canceled transaction already
834                     is in final status and there is nothing to cancel; */
835                 if ( Trans->T_canceled->status>=200)
836                         t_put_on_wait( Trans );
837         } else if (Trans->status>=200)
838                 t_put_on_wait( Trans );
839    return 1;
840 }
841
842
843
844
845 /* Checks if the new reply (with new_code status) should be sent or not
846  *  based on the current
847   * transactin status.
848   * Returns     - branch number (0,1,...) which should be relayed
849                 - -1 if nothing to be relayed
850   */
851 int t_should_relay_response( struct cell *Trans , int new_code, 
852         int branch , int *should_store )
853 {
854         int T_code;
855         int b, lowest_b, lowest_s;
856
857         T_code = Trans->status;
858
859         /* note: this code never lets replies to CANCEL go through;
860            we generate always a local 200 for CANCEL; 200s are
861            not relayed because it's not an INVITE transaction;
862            >= 300 are not relayed because 200 was already sent
863            out
864         */
865
866         /* if final response sent out, allow only INVITE 2xx  */
867         if ( T_code >= 200 ) { 
868                 if (new_code>=200 && new_code < 300  && 
869                         Trans->inbound_request->REQ_METHOD==METHOD_INVITE) {
870                         DBG("DBG: t_should_relay: 200 INV after final sent\n");
871                         *should_store=1;
872                         return branch;
873                 } else {
874                         *should_store=0;
875                         return -1;
876                 }
877         } else { /* no final response sent yet */
878
879                 /* negative replies subject to fork picking */
880                 if (new_code >=300 ) {
881                         *should_store=1;
882                         /* if all_final return lowest */
883                         lowest_b=-1; lowest_s=999;
884                         for ( b=0; b<Trans->nr_of_outgoings ; b++ ) {
885                                 /* "fake" for the currently processed branch */
886                                 if (b==branch) {
887                                         if (new_code<lowest_s) {
888                                                 lowest_b=b;
889                                                 lowest_s=new_code;
890                                         }
891                                         continue;
892                                 }
893                                 /* there is still an unfinished UAC transaction; wait now! */
894                                 if ( !Trans->inbound_response[b] ||
895                                         Trans->inbound_response[b]->REPLY_STATUS<200 )
896                                         return -1;
897                                 if ( Trans->inbound_response[b]->REPLY_STATUS<lowest_s )
898                                 {
899                                         lowest_b =b;
900                                         lowest_s = T->inbound_response[b]->REPLY_STATUS;
901                                 }
902                         }
903                         return lowest_b;
904
905                 /* 1xx except 100 and 2xx will be relayed */
906                 } else if (new_code>100) {
907                         *should_store=1;
908                         return branch;
909                 }
910                 /* 100 won't be relayed */
911                 else {
912                         if (!T->inbound_response[branch]) *should_store=1; 
913                         else *should_store=0;
914                         return -1;
915                 }
916         }
917
918         LOG(L_CRIT, "ERROR: Oh my gooosh! We don't know whether to relay\n");
919         abort();
920 }
921
922
923 /*
924   */
925 int t_put_on_wait(  struct cell  *Trans  )
926 {
927         struct timer_link *tl;
928         unsigned int i;
929         struct retrans_buff* rb;
930
931         if (is_in_timer_list2( &(Trans->wait_tl)))
932         {
933                 DBG("DEBUG: t_put_on_wait: already on wait\n");
934                 return 1;
935         }
936
937         /* remove from  retranssmision  and  final response   list */
938         DBG("DEBUG: t_put_on_wait: stopping timers (FR and RETR)\n");
939         reset_retr_timers(hash_table,Trans) ;
940
941         /* cancel pending client transactions, if any */
942         for( i=0 ; i<Trans->nr_of_outgoings ; i++ )
943                 if ( Trans->inbound_response[i] && 
944                 REPLY_CLASS(Trans->inbound_response[i])==1)
945                 t_cancel_branch(i);
946
947
948         /* we don't need outbound requests anymore -- let's save
949            memory and junk them right now!
950         */
951 /*
952         shm_lock();
953         for ( i =0 ; i<Trans->nr_of_outgoings;  i++ )
954         {
955                 if ( rb=Trans->outbound_request[i] )
956                 {
957                         if (rb->retr_buffer) shm_free_unsafe( rb->retr_buffer );
958                         Trans->outbound_request[i] = NULL;
959                         shm_free_unsafe( rb );
960                 }
961         }
962         shm_unlock();
963 */
964
965         /* adds to Wait list*/
966         set_timer( hash_table, &(Trans->wait_tl), WT_TIMER_LIST );
967         return 1;
968 }
969
970
971
972
973 /*
974   */
975 int t_cancel_branch(unsigned int branch)
976 {
977         LOG(L_ERR, "ERROR: t_cancel_branch: NOT IMPLEMENTED YET\n");
978 }
979
980
981
982
983 /* Builds an ACK request based on an INVITE request. ACK is send
984   * to same address
985   */
986 int t_build_and_send_ACK( struct cell *Trans, unsigned int branch, struct sip_msg* rpl)
987 {
988    struct sip_msg* p_msg , *r_msg;
989    struct hdr_field *hdr;
990    char *ack_buf, *p, *via;
991    unsigned int len, via_len;
992    int n;
993         struct retrans_buff *srb;
994
995    ack_buf = 0;
996    via =0;
997
998    p_msg = Trans->inbound_request;
999    r_msg = rpl;
1000
1001    if ( parse_headers(rpl,HDR_TO)==-1 || !rpl->to )
1002    {
1003         LOG(L_ERR, "ERROR: t_build_and_send_ACK: "
1004                 "cannot generate a HBH ACK if key HFs in reply missing\n");
1005         goto error;
1006    }
1007
1008     len = 0;
1009     /*first line's len */
1010     len += 4+p_msg->first_line.u.request.uri.len+1+
1011                 p_msg->first_line.u.request.version.len+CRLF_LEN;
1012     /*via*/
1013     via = via_builder( p_msg , &via_len );
1014     if (!via)
1015     {
1016         LOG(L_ERR, "ERROR: t_build_and_send_ACK: no via header got from builder\n");
1017         goto error;
1018     }
1019     len+= via_len;
1020     /*headers*/
1021    for ( hdr=p_msg->headers ; hdr ; hdr=hdr->next )
1022       if ( hdr->type==HDR_FROM || hdr->type==HDR_CALLID || hdr->type==HDR_CSEQ )
1023                  len += ((hdr->body.s+hdr->body.len ) - hdr->name.s ) + CRLF_LEN ;
1024       else if ( hdr->type==HDR_TO )
1025                  len += ((r_msg->to->body.s+r_msg->to->body.len ) - r_msg->to->name.s ) + CRLF_LEN ;
1026       /*else if ( hdr->type==HDR_)*/
1027
1028    /* CSEQ method : from INVITE-> ACK */
1029    len -= 3  ;
1030    /* end of message */
1031    len += CRLF_LEN; /*new line*/
1032
1033    /* ack_buf = (char *)pkg_malloc( len +1); */
1034         srb = (struct retrans_buff *) sh_malloc( sizeof(struct retrans_buff) + len + 1 );
1035         if (!srb) {
1036                 LOG(L_ERR, "ERROR: t_build_and_send_ACK: cannot allocate memory\n");
1037                 goto error1;
1038         }
1039         ack_buf = (char *) srb + sizeof(struct retrans_buff);
1040
1041    p = ack_buf;
1042    DBG("DEBUG: t_build_and_send_ACK: len = %d \n",len);
1043
1044    /* first line */
1045    memcpy( p , "ACK " , 4);
1046    p += 4;
1047
1048    memcpy( p , p_msg->orig+(p_msg->first_line.u.request.uri.s-p_msg->buf) , p_msg->first_line.u.request.uri.len );
1049    p += p_msg->first_line.u.request.uri.len;
1050
1051    *(p++) = ' ';
1052
1053    memcpy( p , p_msg->orig+(p_msg->first_line.u.request.version.s-p_msg->buf) , p_msg->first_line.u.request.version.len );
1054    p += p_msg->first_line.u.request.version.len;
1055
1056    memcpy( p, CRLF, CRLF_LEN );
1057    p+=CRLF_LEN;
1058
1059    /* insert our via */
1060    memcpy( p , via , via_len );
1061    p += via_len;
1062
1063    /*other headers*/
1064    for ( hdr=p_msg->headers ; hdr ; hdr=hdr->next )
1065    {
1066       if ( hdr->type==HDR_FROM || hdr->type==HDR_CALLID  )
1067         {
1068                 memcpy( p , p_msg->orig+(hdr->name.s-p_msg->buf) ,
1069                         ((hdr->body.s+hdr->body.len ) - hdr->name.s ) );
1070                 p += ((hdr->body.s+hdr->body.len ) - hdr->name.s );
1071                 memcpy( p, CRLF, CRLF_LEN );
1072                 p+=CRLF_LEN;
1073         }
1074       else if ( hdr->type==HDR_TO )
1075         {
1076                 memcpy( p , r_msg->orig+(r_msg->to->name.s-r_msg->buf) ,
1077                         ((r_msg->to->body.s+r_msg->to->body.len ) - r_msg->to->name.s ) );
1078                 p += ((r_msg->to->body.s+r_msg->to->body.len ) - r_msg->to->name.s );
1079                 memcpy( p, CRLF, CRLF_LEN );
1080                 p+=CRLF_LEN;
1081         }
1082        else if ( hdr->type==HDR_CSEQ )
1083         {
1084                 memcpy( p , p_msg->orig+(hdr->name.s-p_msg->buf) ,
1085                         (( ((struct cseq_body*)hdr->parsed)->method.s ) - hdr->name.s ) );
1086                 p += (( ((struct cseq_body*)hdr->parsed)->method.s ) - hdr->name.s );
1087                 memcpy( p , "ACK" CRLF, 3+CRLF_LEN );
1088                 p += 3+CRLF_LEN;
1089         }
1090     }
1091
1092     memcpy( p , CRLF , CRLF_LEN );
1093     p += CRLF_LEN;
1094
1095         send_ack( T, branch, srb, p-ack_buf );
1096         pkg_free( via );
1097         DBG("DEBUG: t_build_and_send_ACK: ACK sent\n");
1098         return 0;
1099                 
1100 error1:
1101    pkg_free(via );
1102 error:
1103    return -1;
1104 }
1105
1106
1107 void delete_cell( struct cell *p_cell )
1108 {
1109 #ifdef EXTRA_DEBUG
1110         int i;
1111
1112         if (is_in_timer_list2(& p_cell->wait_tl )) {
1113                 LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and still on WAIT\n",
1114                         p_cell);
1115                 abort();
1116         }
1117         /*
1118         if (is_in_timer_list2(& p_cell->outbound_response.retr_timer )) {
1119                 LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and still on RETR (rep)\n",
1120                         p_cell);
1121                 abort();
1122         }
1123         if (is_in_timer_list2(& p_cell->outbound_response.fr_timer )) {
1124                 LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and still on FR (rep)\n",
1125                         p_cell);
1126                 abort();
1127         }
1128         for (i=0; i<p_cell->nr_of_outgoings; i++) {
1129                 if (is_in_timer_list2(& p_cell->outbound_request[i]->retr_timer)) {
1130                         LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and still on RETR (req %d)\n",
1131                         p_cell, i);
1132                         abort();
1133                 }
1134                 if (is_in_timer_list2(& p_cell->outbound_request[i]->fr_timer)) {
1135                         LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and still on FR (req %d)\n",
1136                         p_cell, i);
1137                         abort();
1138                 }
1139         }
1140         */
1141         reset_retr_timers( hash_table, p_cell );
1142 #endif
1143         /* still in use ... don't delete */
1144         if ( T_IS_REFED(p_cell) ) {
1145 #ifdef  EXTRA_DEBUG
1146                 if (T_REFCOUNTER(p_cell)>1) {
1147                         DBG("DEBUG: while debugging with a single process, ref_count > 1\n");
1148                         DBG("DEBUG: transaction =%p\n", p_cell );
1149                         abort();
1150                 }
1151 #endif
1152                 DBG("DEBUG: delete_cell: t=%p post for delete (refbitmap %x, refcount %d)\n",
1153                         p_cell,p_cell->ref_bitmap, T_REFCOUNTER(p_cell));
1154                 /* it's added to del list for future del */
1155                 set_timer( hash_table, &(p_cell->dele_tl), DELETE_LIST );
1156         } else {
1157                 DBG("DEBUG: delete transaction %p\n", p_cell );
1158                 free_cell( p_cell );
1159         }
1160 }
1161
1162
1163 /* Returns  -1 = error
1164                     0 = OK
1165 */
1166 int get_ip_and_port_from_uri( struct sip_msg* p_msg , unsigned int *param_ip, unsigned int *param_port)
1167 {
1168         struct hostent  *nhost;
1169         unsigned int      ip, port;
1170         struct sip_uri    parsed_uri;
1171         str                      uri;
1172         int                      err;
1173 #ifdef DNS_IP_HACK
1174         int                      len;
1175 #endif
1176
1177         /* the original uri has been changed? */
1178         if (p_msg->new_uri.s==0 || p_msg->new_uri.len==0)
1179                 uri = p_msg->first_line.u.request.uri;
1180         else
1181                 uri = p_msg->new_uri;
1182
1183         /* parsing the request uri in order to get host and port */
1184         if (parse_uri( uri.s , uri.len , &parsed_uri )<0)
1185         {
1186                 LOG(L_ERR, "ERROR: get_ip_and_port_from_uri: "
1187                    "unable to parse destination uri\n");
1188                 goto error;
1189         }
1190
1191         /* getting the port */
1192         if ( parsed_uri.port.s==0 || parsed_uri.port.len==0 )
1193                 port = SIP_PORT;
1194         else{
1195                 port = str2s( parsed_uri.port.s , parsed_uri.port.len , &err );
1196                 if ( err<0 ){
1197                         LOG(L_ERR, "ERROR: get_ip_and_port_from_uri: "
1198                           "converting port from str to int failed; using default SIP port\n");
1199                         port = SIP_PORT;
1200                 }
1201         }
1202         port = htons( port );
1203
1204         /* getting host address*/
1205 #ifdef DNS_IP_HACK
1206         len=strlen( parsed_uri.host.s );
1207         ip=str2ip(parsed_uri.host.s, len, &err);
1208         if (err==0)
1209                 goto success;
1210 #endif
1211         /* fail over to normal lookup */
1212         nhost = gethostbyname( parsed_uri.host.s );
1213         if ( !nhost )
1214         {
1215                 LOG(L_ERR, "ERROR: get_ip_and_port_from_uri: "
1216                   "cannot resolve host\n");
1217                 goto error;
1218         }
1219         memcpy(&ip, nhost->h_addr_list[0], sizeof(unsigned int));
1220
1221
1222 success:
1223         *param_ip = ip;
1224         *param_port = port;
1225         return 0;
1226
1227 error:
1228         *param_ip = 0;
1229         *param_port = 0;
1230         return -1;
1231 }
1232
1233
1234
1235
1236
1237
1238 /*---------------------TIMEOUT HANDLERS--------------------------*/
1239
1240
1241 void retransmission_handler( void *attr)
1242 {
1243         struct retrans_buff* r_buf ;
1244         enum lists id;
1245
1246         r_buf = (struct retrans_buff*)attr;
1247 #ifdef EXTRA_DEBUG
1248         if (r_buf->my_T->damocles) {
1249                 LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and called from RETR timer\n",
1250                         r_buf->my_T);
1251                 abort();
1252         }       
1253 #endif
1254
1255
1256         /*the transaction is already removed from RETRANSMISSION_LIST by timer*/
1257
1258         /* retransmision */
1259         DBG("DEBUG: retransmission_handler : resending (t=%p)\n", r_buf->my_T);
1260         if (r_buf->reply) {
1261                 LOCK_REPLIES( r_buf->my_T );
1262                 SEND_BUFFER( r_buf );
1263                 UNLOCK_REPLIES( r_buf->my_T );
1264         } else {
1265                 SEND_BUFFER( r_buf );
1266         }
1267
1268         id = r_buf->retr_list;
1269         r_buf->retr_list = id < RT_T2 ? id + 1 : RT_T2;
1270
1271         set_timer( hash_table, &(r_buf->retr_timer), id < RT_T2 ? id + 1 : RT_T2 );
1272
1273         DBG("DEBUG: retransmission_handler : done\n");
1274 }
1275
1276
1277
1278
1279 void final_response_handler( void *attr)
1280 {
1281         struct retrans_buff* r_buf = (struct retrans_buff*)attr;
1282
1283 #ifdef EXTRA_DEBUG
1284         if (r_buf->my_T->damocles) {
1285                 LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and called from FR timer\n",
1286                         r_buf->my_T);
1287                 abort();
1288         }       
1289 #endif
1290
1291         /* the transaction is already removed from FR_LIST by the timer */
1292         /* send a 408 */
1293         if ( r_buf->my_T->status<200)
1294         {
1295                 DBG("DEBUG: final_response_handler:stop retransmission and send 408 (t=%p)\n", r_buf->my_T);
1296                 reset_timer( hash_table, &(r_buf->retr_timer) );
1297                 /* dirty hack: t_send_reply would increase ref_count which would indeed
1298                    result in refcount++ which would not -- until timer processe's
1299                    T changes again; currently only on next call to t_send_reply from
1300                    FR timer; thus I fake the values now to avoid recalculating T
1301                    and refcount++
1302
1303                         -jku
1304             */
1305                 T=r_buf->my_T;
1306                 global_msg_id=T->inbound_request->id;
1307
1308                 t_send_reply( r_buf->my_T->inbound_request , 408 , "Request Timeout" );
1309         } else {
1310                 /* put it on WT_LIST - transaction is over */
1311                 DBG("DEBUG: final_response_handler:cancel transaction->put on wait (t=%p)\n", r_buf->my_T);
1312                 t_put_on_wait(  r_buf->my_T );
1313         }
1314         DBG("DEBUG: final_response_handler : done\n");
1315 }
1316
1317
1318
1319
1320 void wait_handler( void *attr)
1321 {
1322         struct cell *p_cell = (struct cell*)attr;
1323
1324 #ifdef EXTRA_DEBUG
1325         if (p_cell->damocles) {
1326                 LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and called from WAIT timer\n",
1327                         p_cell);
1328                 abort();
1329         }       
1330 #endif
1331
1332         /* the transaction is already removed from WT_LIST by the timer */
1333         /* the cell is removed from the hash table */
1334         DBG("DEBUG: wait_handler : removing %p from table \n", p_cell );
1335         remove_from_hash_table( hash_table, p_cell );
1336         /* jku: no more here -- we do it when we put a transaction on wait */
1337         DBG("DEBUG: wait_handler : stopping all timers\n");
1338         reset_retr_timers(hash_table,p_cell) ; 
1339         /* put it on DEL_LIST - sch for del */
1340 #ifdef EXTRA_DEBUG
1341         p_cell->damocles = 1;
1342 #endif
1343         delete_cell( p_cell );
1344         DBG("DEBUG: wait_handler : done\n");
1345 }
1346
1347
1348 void delete_handler( void *attr)
1349 {
1350         struct cell *p_cell = (struct cell*)attr;
1351
1352         DBG("DEBUG: delete_handler : removing %p \n", p_cell );
1353 #ifdef EXTRA_DEBUG
1354         if (p_cell->damocles==0) {
1355                 LOG( L_ERR, "ERROR: transaction %p not scheduled for deletion and called from DELETE timer\n",
1356                         p_cell);
1357                 abort();
1358         }       
1359 #endif
1360         delete_cell( p_cell );
1361     DBG("DEBUG: delete_handler : done\n");
1362 }