mirror of https://github.com/sipwise/kamailio.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
591 lines
18 KiB
591 lines
18 KiB
/*
|
|
* $Id$
|
|
*
|
|
* Copyright (C) 2001-2003 FhG Fokus
|
|
*
|
|
* This file is part of SIP-router, a free SIP server.
|
|
*
|
|
* SIP-router is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version
|
|
*
|
|
* SIP-router is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
* History:
|
|
* --------
|
|
* 2003-03-16 removed _TOTAG (jiri)
|
|
* 2003-03-06 we keep a list of 200/INV to-tags now (jiri)
|
|
* 2003-03-01 kr set through a function now (jiri)
|
|
* 2003-12-04 callbacks per transaction added; completion callback
|
|
* merge into them as LOCAL_COMPETED (bogdan)
|
|
* 2004-02-11 FIFO/CANCEL + alignments (hash=f(callid,cseq)) (uli+jiri)
|
|
* 2004-02-13 t->is_invite, t->local, t->noisy_ctimer replaced
|
|
* with flags (bogdan)
|
|
* 2004-08-23 avp support added - avp list linked in transaction (bogdan)
|
|
* 2005-11-03 updated to the new timer interface (dropped tm timers) (andrei)
|
|
* 2006-08-11 dns failover support (andrei)
|
|
* 2007-05-29 switch ref_count to atomic and delete a cell automatically on
|
|
* UNREF if the ref_count reaches 0 (andrei)
|
|
* 2007-06-01 support for different retransmissions intervals per transaction;
|
|
* added maximum inv. and non-inv. transaction life time (andrei)
|
|
* 2007-06-06 switched tm bucket list to a simpler and faster clist;
|
|
* inlined often used functions (andrei)
|
|
*/
|
|
|
|
/** TM :: hash table, flags and other general defines.
|
|
* @file
|
|
* @ingroup tm
|
|
*/
|
|
|
|
|
|
#ifndef _H_TABLE_H
|
|
#define _H_TABLE_H
|
|
|
|
#include "defs.h"
|
|
#include "t_stats.h"
|
|
|
|
#define TM_DEL_UNREF
|
|
/* uncomment the next define if you wish to keep hash statistics*/
|
|
/*
|
|
#define TM_HASH_STATS
|
|
*/
|
|
/* use hash stats always in debug mode */
|
|
#ifdef EXTRA_DEBUG
|
|
#ifndef TM_HASH_STATS
|
|
#define TM_HASH_STATS
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#include "../../clist.h"
|
|
#include "../../parser/msg_parser.h"
|
|
#include "../../types.h"
|
|
#include "../../md5utils.h"
|
|
#include "../../usr_avp.h"
|
|
#ifdef WITH_XAVP
|
|
#include "../../xavp.h"
|
|
#endif
|
|
#include "../../timer.h"
|
|
#include "../../flags.h"
|
|
#include "../../atomic_ops.h"
|
|
#include "../../hash_func.h"
|
|
#include "config.h"
|
|
|
|
/* if TM_DIFF_RT_TIMEOUT is defined, different retransmissions timeouts
|
|
* can be used for each transaction, at a small memory cost
|
|
* (extra 4 bytes/transaction) */
|
|
#define TM_DIFF_RT_TIMEOUT
|
|
|
|
|
|
struct s_table;
|
|
struct entry;
|
|
struct cell;
|
|
struct timer;
|
|
struct retr_buf;
|
|
struct ua_client;
|
|
|
|
#include "../../mem/shm_mem.h"
|
|
#include "lock.h"
|
|
#include "sip_msg.h"
|
|
#include "t_reply.h"
|
|
#include "t_hooks.h"
|
|
#ifdef USE_DNS_FAILOVER
|
|
#include "../../dns_cache.h"
|
|
#endif
|
|
|
|
|
|
#define LOCK_HASH(_h) lock_hash((_h))
|
|
#define UNLOCK_HASH(_h) unlock_hash((_h))
|
|
|
|
void lock_hash(int i);
|
|
void unlock_hash(int i);
|
|
|
|
|
|
#define NO_CANCEL ( (char*) 0 )
|
|
#define EXTERNAL_CANCEL ( (char*) -1)
|
|
|
|
#define TYPE_LOCAL_ACK -2
|
|
#define TYPE_LOCAL_CANCEL -1
|
|
#define TYPE_REQUEST 0
|
|
|
|
/* to be able to assess whether a script writer forgot to
|
|
release a transaction and leave it for ever in memory,
|
|
we mark it with operations done over it; if none of these
|
|
flags is set and script is being left, it is a sign of
|
|
script error and we need to release on writer's
|
|
behalf
|
|
|
|
REQ_FWDED means there is a UAC with final response timer
|
|
ticking. If it hits, transaction will be completed.
|
|
REQ_RPLD means that a transaction has been replied -- either
|
|
it implies going to wait state, or for invite transactions
|
|
FR timer is ticking until ACK arrives
|
|
REQ_RLSD means that a transaction was put on wait explicitly
|
|
from t_release_transaction
|
|
REQ_EXIST means that this request is a retransmission which does not
|
|
affect transactional state
|
|
REQ_ERR_DELAYED mean that tm wants to send reply(ser_error) but it
|
|
delayed it to end-of-script to allow it to be overriden.
|
|
If this is set and all of the above flag are not => send reply
|
|
on end of script. If any of the above flags is set, do not
|
|
send (especially REQ_RPLD and REQ_RLSD).
|
|
*/
|
|
enum kill_reason { REQ_FWDED=1, REQ_RPLD=2, REQ_RLSD=4, REQ_EXIST=8,
|
|
REQ_ERR_DELAYED=16 };
|
|
|
|
|
|
/* #define F_RB_T_ACTIVE 0x01 (obsolete) fr or retr active */
|
|
#define F_RB_T2 0x02
|
|
#define F_RB_RETR_DISABLED 0x04 /* retransmission disabled */
|
|
#define F_RB_FR_INV 0x08 /* timer switched to FR_INV */
|
|
#define F_RB_TIMEOUT 0x10 /* timeout */
|
|
#define F_RB_REPLIED 0x20 /* reply received */
|
|
#define F_RB_CANCELED 0x40 /* rb/branch canceled */
|
|
#define F_RB_DEL_TIMER 0x80 /* timer should be deleted if active */
|
|
#define F_RB_NH_LOOSE 0x100 /* next hop is a loose router */
|
|
#define F_RB_NH_STRICT 0x200 /* next hop is a strict router */
|
|
/* must detect when neither loose nor strict flag is set -> two flags.
|
|
* alternatively, 1x flag for strict/loose and 1x for loose|strict set/not */
|
|
|
|
|
|
/* if canceled or intended to be canceled, return true */
|
|
#define uac_dont_fork(uac) ((uac)->local_cancel.buffer)
|
|
|
|
|
|
typedef struct retr_buf
|
|
{
|
|
short activ_type;
|
|
/* set to status code if the buffer is a reply,
|
|
0 if request or -1 if local CANCEL */
|
|
volatile unsigned short flags; /* DISABLED, T2 */
|
|
volatile unsigned char t_active; /* timer active */
|
|
unsigned short branch; /* no more then 65k branches :-) */
|
|
int buffer_len;
|
|
char *buffer;
|
|
/*the cell that contains this retrans_buff*/
|
|
struct cell* my_T;
|
|
struct timer_ln timer;
|
|
struct dest_info dst;
|
|
ticks_t retr_expire;
|
|
ticks_t fr_expire; /* ticks value after which fr. will fire */
|
|
}retr_buf_type;
|
|
|
|
|
|
|
|
/* User Agent Server content */
|
|
|
|
typedef struct ua_server
|
|
{
|
|
struct sip_msg *request;
|
|
char *end_request;
|
|
struct retr_buf response;
|
|
/* keep to-tags for local 200 replies for INVITE --
|
|
* we need them for dialog-wise matching of ACKs;
|
|
* the pointer shows to shmem-ed reply */
|
|
str local_totag;
|
|
#ifdef CANCEL_REASON_SUPPORT
|
|
struct cancel_reason* cancel_reas; /* pointer to cancel reason, used
|
|
for e2e cancels */
|
|
#endif /* CANCEL_REASON_SUPPORT */
|
|
unsigned int status;
|
|
}ua_server_type;
|
|
|
|
|
|
|
|
/* User Agent Client content */
|
|
|
|
#define TM_UAC_FLAGS
|
|
#ifdef TM_UAC_FLAGS
|
|
/* UAC internal flags */
|
|
#define TM_UAC_FLAG_RR 1 /* Record-Route applied */
|
|
#define TM_UAC_FLAG_R2 2 /* 2nd Record-Route applied */
|
|
#define TM_UAC_FLAG_FB 4 /* Mark first entry in new branch set */
|
|
#endif
|
|
|
|
typedef struct ua_client
|
|
{
|
|
/* if we store a reply (branch picking), this is where it is */
|
|
struct sip_msg *reply;
|
|
struct retr_buf request;
|
|
/* we maintain a separate copy of cancel rather than
|
|
reuse the structure for original request; the
|
|
original request is no longer needed but its delayed
|
|
timer may fire and interfere with whoever tries to
|
|
rewrite it
|
|
*/
|
|
struct retr_buf local_cancel;
|
|
/* pointer to retransmission buffer where uri is printed;
|
|
good for generating ACK/CANCEL */
|
|
#ifdef USE_DNS_FAILOVER
|
|
struct dns_srv_handle dns_h;
|
|
#endif
|
|
str uri;
|
|
str path;
|
|
/* if we don't store, we at least want to know the status */
|
|
int last_received;
|
|
|
|
#ifdef TM_UAC_FLAGS
|
|
/* internal flags per tm uac */
|
|
unsigned int flags;
|
|
#endif
|
|
flag_t branch_flags;
|
|
#ifdef WITH_AS_SUPPORT
|
|
/**
|
|
* Resent for every rcvd 2xx reply.
|
|
* This member's as an alternative to passing the reply to the AS,
|
|
* every time a reply for local request is rcvd.
|
|
* Member can not be union'ed with local_cancel, since CANCEL can happen
|
|
* concurrently with a 2xx reply (to generate an ACK).
|
|
*/
|
|
struct retr_buf *local_ack;
|
|
#endif
|
|
}ua_client_type;
|
|
|
|
|
|
struct totag_elem {
|
|
struct totag_elem *next;
|
|
str tag;
|
|
volatile int acked;
|
|
};
|
|
|
|
|
|
|
|
/* transaction's flags */
|
|
/* is the transaction's request an INVITE? */
|
|
#define T_IS_INVITE_FLAG (1<<0)
|
|
/* is this a transaction generated by local request? */
|
|
#define T_IS_LOCAL_FLAG (1<<1)
|
|
/* set to one if you want to disallow silent transaction
|
|
dropping when C timer hits */
|
|
#define T_NOISY_CTIMER_FLAG (1<<2)
|
|
/* transaction canceled
|
|
* WARNING: this flag can be set outside reply lock from e2e_cancel().
|
|
* If a future flag could be affected by a race w/ e2e_cancel() the code
|
|
* should be changed.*/
|
|
#define T_CANCELED (1<<3)
|
|
/* 6xx received => stop forking */
|
|
#define T_6xx (1<<4)
|
|
|
|
#define T_IN_AGONY (1<<5) /* set if waiting to die (delete timer)
|
|
TODO: replace it with del on unref */
|
|
#define T_AUTO_INV_100 (1<<6) /* send an 100 reply automatically to inv. */
|
|
#ifdef WITH_AS_SUPPORT
|
|
/* don't generate automatically an ACK for local transaction */
|
|
# define T_NO_AUTO_ACK (1<<7)
|
|
#endif
|
|
|
|
#define T_DISABLE_6xx (1<<8) /* treat 6xx as a normal reply */
|
|
#define T_DISABLE_FAILOVER (1<<9) /* don't perform dns failover */
|
|
#ifdef CANCEL_REASON_SUPPORT
|
|
#define T_NO_E2E_CANCEL_REASON (1<<10) /* don't propagate CANCEL Reason */
|
|
#endif /* CANCEL_REASON_SUPPORT */
|
|
#define T_DONT_FORK (T_CANCELED|T_6xx)
|
|
|
|
#ifdef WITH_AS_SUPPORT
|
|
/* provisional replies must trigger callbacks for local transaction */
|
|
# define T_PASS_PROVISIONAL_FLAG (1<<11)
|
|
# define pass_provisional(_t_) ((_t_)->flags&T_PASS_PROVISIONAL_FLAG)
|
|
#endif
|
|
|
|
/* unsigned short should be enough for a retr. timer: max. 65535 ms =>
|
|
* max retr. = 65 s which should be enough and saves us 2*2 bytes */
|
|
typedef unsigned short retr_timeout_t;
|
|
|
|
/**
|
|
* extra data from SIP message context to transaction storage
|
|
*/
|
|
typedef struct tm_xdata
|
|
{
|
|
/* lists with avps */
|
|
struct usr_avp *uri_avps_from;
|
|
struct usr_avp *uri_avps_to;
|
|
struct usr_avp *user_avps_from;
|
|
struct usr_avp *user_avps_to;
|
|
struct usr_avp *domain_avps_from;
|
|
struct usr_avp *domain_avps_to;
|
|
#ifdef WITH_XAVP
|
|
sr_xavp_t *xavps_list;
|
|
#endif
|
|
} tm_xdata_t;
|
|
|
|
|
|
/**
|
|
* links to extra data from SIP message context to transaction storage
|
|
*/
|
|
typedef struct tm_xlinks
|
|
{
|
|
/* links to lists with avps */
|
|
struct usr_avp **uri_avps_from;
|
|
struct usr_avp **uri_avps_to;
|
|
struct usr_avp **user_avps_from;
|
|
struct usr_avp **user_avps_to;
|
|
struct usr_avp **domain_avps_from;
|
|
struct usr_avp **domain_avps_to;
|
|
#ifdef WITH_XAVP
|
|
sr_xavp_t **xavps_list;
|
|
#endif
|
|
} tm_xlinks_t;
|
|
|
|
|
|
/* transaction context */
|
|
|
|
typedef struct cell
|
|
{
|
|
/* linking data */
|
|
/* WARNING: don't move or change order of next_c or prev_c
|
|
* or breakage will occur */
|
|
struct cell* next_c;
|
|
struct cell* prev_c;
|
|
/* tells in which hash table entry the cell lives */
|
|
unsigned int hash_index;
|
|
/* sequence number within hash collision slot */
|
|
unsigned int label;
|
|
/* different information about the transaction */
|
|
unsigned short flags;
|
|
/* number of forks */
|
|
short nr_of_outgoings;
|
|
|
|
#ifdef TM_DEL_UNREF
|
|
/* every time the transaction/cell is referenced from somewhere this
|
|
* ref_count should be increased (via REF()) and every time the reference
|
|
* is removed the ref_count should be decreased (via UNREF()).
|
|
* This includes adding the cell to the hash table (REF() before adding)
|
|
* and removing it from the hash table (UNREF_FREE() after unlinking).
|
|
* Exception: it does not include starting/stopping timers (timers are
|
|
* forced-stopped every time when ref_count reaches 0)
|
|
* If the cell is no longer referenced (ref_count==0 after an UNREF),
|
|
* it will be automatically deleted by the UNREF() operation.
|
|
*/
|
|
atomic_t ref_count;
|
|
#else
|
|
/* how many processes are currently processing this transaction ;
|
|
note that only processes working on a request/reply belonging
|
|
to a transaction increase ref_count -- timers don't, since we
|
|
rely on transaction state machine to clean-up all but wait timer
|
|
when entering WAIT state and the wait timer is the only place
|
|
from which a transaction can be deleted (if ref_count==0); good
|
|
for protecting from conditions in which wait_timer hits and
|
|
tries to delete a transaction whereas at the same time
|
|
a delayed message belonging to the transaction is received */
|
|
volatile unsigned int ref_count;
|
|
#endif
|
|
|
|
/* needed for generating local ACK/CANCEL for local
|
|
transactions; all but cseq_n include the entire
|
|
header field value, cseq_n only Cseq number; with
|
|
local transactions, pointers point to outbound buffer,
|
|
with proxied transactions to inbound request */
|
|
str from, callid, cseq_n, to;
|
|
/* method shortcut -- for local transactions, pointer to
|
|
outbound buffer, for proxies transactions pointer to
|
|
original message; needed for reply matching */
|
|
str method;
|
|
|
|
/* head of callback list */
|
|
struct tmcb_head_list tmcb_hl;
|
|
|
|
/* bindings to wait and delete timer */
|
|
struct timer_ln wait_timer; /* used also for delete */
|
|
|
|
/* UA Server */
|
|
struct ua_server uas;
|
|
/* UA Clients */
|
|
struct ua_client uac[ MAX_BRANCHES ];
|
|
|
|
/* to-tags of 200/INVITEs which were received from downstream and
|
|
* forwarded or passed to UAC; note that there can be arbitrarily
|
|
* many due to downstream forking; */
|
|
struct totag_elem *fwded_totags;
|
|
|
|
/* lists with avps */
|
|
struct usr_avp *uri_avps_from;
|
|
struct usr_avp *uri_avps_to;
|
|
struct usr_avp *user_avps_from;
|
|
struct usr_avp *user_avps_to;
|
|
struct usr_avp *domain_avps_from;
|
|
struct usr_avp *domain_avps_to;
|
|
#ifdef WITH_XAVP
|
|
sr_xavp_t *xavps_list;
|
|
#endif
|
|
|
|
/* protection against concurrent reply processing */
|
|
ser_lock_t reply_mutex;
|
|
|
|
ticks_t fr_timeout; /* final response interval for retr_bufs */
|
|
ticks_t fr_inv_timeout; /* final inv. response interval for retr_bufs */
|
|
#ifdef TM_DIFF_RT_TIMEOUT
|
|
retr_timeout_t rt_t1_timeout_ms; /* start retr. interval for retr_bufs */
|
|
retr_timeout_t rt_t2_timeout_ms; /* maximum retr. interval for retr_bufs */
|
|
#endif
|
|
ticks_t end_of_life; /* maximum lifetime */
|
|
|
|
/* nr of replied branch; 0..MAX_BRANCHES=branch value,
|
|
* -1 no reply, -2 local reply */
|
|
short relayed_reply_branch;
|
|
|
|
/* the route to take if no final positive reply arrived */
|
|
unsigned short on_negative;
|
|
/* the onreply_route to be processed if registered to do so */
|
|
unsigned short on_reply;
|
|
/* The route to take for each downstream branch separately */
|
|
unsigned short on_branch;
|
|
|
|
/* place holder for MD5checksum (meaningful only if syn_branch=0) */
|
|
char md5[0]; /* if syn_branch==0 then MD5_LEN bytes are extra alloc'ed*/
|
|
|
|
} tm_cell_t;
|
|
|
|
|
|
#if 0
|
|
/* warning: padding too much => big size increase */
|
|
#define ENTRY_PAD_TO 128 /* should be a multiple of cacheline size for
|
|
best performance*/
|
|
#define ENTRY_PAD_BYTES \
|
|
(ENTRY_PAD_TO-2*sizeof(struct cell*)+sizeof(ser_lock_t)+sizeof(int)+ \
|
|
2*sizeof(long))
|
|
#else
|
|
#define ENTRY_PAD_BYTES 0
|
|
#endif
|
|
|
|
/* double-linked list of cells with hash synonyms */
|
|
typedef struct entry
|
|
{
|
|
/* WARNING: don't move or change order of next_c or prev_c
|
|
* or breakage will occur */
|
|
struct cell* next_c;
|
|
struct cell* prev_c;
|
|
/* sync mutex */
|
|
ser_lock_t mutex;
|
|
atomic_t locker_pid; /* pid of the process that holds the lock */
|
|
int rec_lock_level; /* recursive lock count */
|
|
/* currently highest sequence number in a synonym list */
|
|
unsigned int next_label;
|
|
#ifdef TM_HASH_STATS
|
|
unsigned long acc_entries;
|
|
unsigned long cur_entries;
|
|
#endif
|
|
char _pad[ENTRY_PAD_BYTES];
|
|
}entry_type;
|
|
|
|
|
|
|
|
/* transaction table */
|
|
struct s_table
|
|
{
|
|
/* table of hash entries; each of them is a list of synonyms */
|
|
struct entry entries[ TABLE_ENTRIES ];
|
|
};
|
|
|
|
/* pointer to the big table where all the transaction data
|
|
lives */
|
|
extern struct s_table* _tm_table; /* private internal stuff, don't touch
|
|
directly */
|
|
|
|
#define list_entry(ptr, type, member) \
|
|
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
|
|
|
|
#define get_retr_timer_payload(_tl_) \
|
|
list_entry( _tl_, struct retr_buf, retr_timer)
|
|
#define get_fr_timer_payload(_tl_) \
|
|
list_entry( _tl_, struct retr_buf, fr_timer)
|
|
#define get_wait_timer_payload(_tl_) \
|
|
list_entry( _tl_, struct cell, wait_tl)
|
|
#define get_dele_timer_payload(_tl_) \
|
|
list_entry( _tl_, struct cell, dele_tl)
|
|
|
|
#define get_T_from_reply_rb(_rb_) \
|
|
list_entry( list_entry( _rb_, (struct ua_server), response),\
|
|
struct cell, uas)
|
|
#define get_T_from_request_rb(_rb_, _br_) \
|
|
list_entry( list_entry( (rb_, (struct ua_client), request) - \
|
|
(_br_)*sizeof(struct retr_buf), struct cell, uas)
|
|
#define get_T_from_cancel_rb(_rb_, _br_) \
|
|
list_entry( list_entry( (rb_, (struct ua_client), local_cancel) - \
|
|
(_br_)*sizeof(struct retr_buf), struct cell, uas)
|
|
|
|
#define is_invite(_t_) ((_t_)->flags&T_IS_INVITE_FLAG)
|
|
#define is_local(_t_) ((_t_)->flags&T_IS_LOCAL_FLAG)
|
|
#define has_noisy_ctimer(_t_) ((_t_)->flags&T_NOISY_CTIMER_FLAG)
|
|
#define was_cancelled(_t_) ((_t_)->flags&T_CANCELED)
|
|
#define no_new_branches(_t_) ((_t_)->flags&T_6xx)
|
|
|
|
|
|
void reset_kr(void);
|
|
void set_kr( enum kill_reason kr );
|
|
enum kill_reason get_kr(void);
|
|
|
|
#define get_tm_table() (_tm_table)
|
|
|
|
typedef struct s_table* (*tm_get_table_f)(void);
|
|
struct s_table* tm_get_table(void);
|
|
|
|
struct s_table* init_hash_table(void);
|
|
void free_hash_table(void);
|
|
void free_cell( struct cell* dead_cell );
|
|
struct cell* build_cell( struct sip_msg* p_msg );
|
|
|
|
#ifdef TM_HASH_STATS
|
|
unsigned int transaction_count( void );
|
|
#endif
|
|
|
|
|
|
/* Takes an already created cell and links it into hash table on the
|
|
* appropriate entry. */
|
|
inline static void insert_into_hash_table_unsafe( struct cell * p_cell,
|
|
unsigned int hash )
|
|
{
|
|
p_cell->label = _tm_table->entries[hash].next_label++;
|
|
#ifdef EXTRA_DEBUG
|
|
DEBUG("cell label: %u\n", p_cell->label);
|
|
#endif
|
|
p_cell->hash_index=hash;
|
|
/* insert at the beginning */
|
|
clist_insert(&_tm_table->entries[hash], p_cell, next_c, prev_c);
|
|
|
|
/* update stats */
|
|
#ifdef TM_HASH_STATS
|
|
_tm_table->entries[hash].cur_entries++;
|
|
_tm_table->entries[hash].acc_entries++;
|
|
#endif
|
|
t_stats_new( is_local(p_cell) );
|
|
}
|
|
|
|
|
|
|
|
/* Un-link a cell from hash_table, but the cell itself is not released */
|
|
inline static void remove_from_hash_table_unsafe( struct cell * p_cell)
|
|
{
|
|
clist_rm(p_cell, next_c, prev_c);
|
|
# ifdef EXTRA_DEBUG
|
|
#ifdef TM_HASH_STATS
|
|
if (_tm_table->entries[p_cell->hash_index].cur_entries==0){
|
|
LOG(L_CRIT, "BUG: bad things happened: cur_entries=0\n");
|
|
abort();
|
|
}
|
|
#endif
|
|
# endif
|
|
#ifdef TM_HASH_STATS
|
|
_tm_table->entries[p_cell->hash_index].cur_entries--;
|
|
#endif
|
|
t_stats_deleted( is_local(p_cell) );
|
|
}
|
|
|
|
/**
|
|
* backup xdata from/to msg context to local var and use T lists
|
|
*/
|
|
void tm_xdata_swap(tm_cell_t *t, tm_xlinks_t *xd, int mode);
|
|
|
|
void tm_xdata_replace(tm_xdata_t *newxd, tm_xlinks_t *bakxd);
|
|
|
|
#endif
|
|
|
|
|