modules/tm/h_table.h
7611117f
 /*
  * $Id$
7dd0b342
  *
84d8e165
  * Copyright (C) 2001-2003 FhG Fokus
7dd0b342
  *
  * This file is part of ser, a free SIP server.
  *
  * ser 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
  *
  * For a license to use the ser software under conditions
  * other than those described here, or to purchase support for this
  * software, please contact iptel.org by e-mail at the following addresses:
  *    info@iptel.org
  *
  * ser 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
c0899aa1
  *
  * History:
  * --------
851f8e6f
  * 2003-03-16  removed _TOTAG (jiri)
d505936f
  * 2003-03-06  we keep a list of 200/INV to-tags now (jiri)
c0899aa1
  * 2003-03-01  kr set through a function now (jiri)
a70eb298
  * 2003-12-04  callbacks per transaction added; completion callback
  *             merge into them as LOCAL_COMPETED (bogdan)
c2ea965c
  * 2004-02-11  FIFO/CANCEL + alignments (hash=f(callid,cseq)) (uli+jiri)
2be21e31
  * 2004-02-13  t->is_invite, t->local, t->noisy_ctimer replaced
0be6158b
  *             with flags (bogdan)
2be21e31
  * 2004-08-23  avp support added - avp list linked in transaction (bogdan)
57857a94
  * 2005-11-03  updated to the new timer interface (dropped tm timers) (andrei)
dcb59e67
  * 2006-08-11  dns failover support (andrei)
e67d9509
  * 2007-05-29  switch ref_count to atomic and delete a cell automatically on
  *             UNREF if the ref_count reaches 0 (andrei)
c0ff60b6
  * 2007-06-01  support for different retransmissions intervals per transaction;
  *             added maximum inv. and non-inv. transaction life time (andrei)
99e9192a
  * 2007-06-06  switched tm bucket list to a simpler and faster clist;
  *              inlined often used functions (andrei)
7611117f
  */
 
d214be66
 #ifndef _H_TABLE_H
 #define _H_TABLE_H
 
99e9192a
 #include "defs.h"
 #include "t_stats.h"
 
 #define TM_DEL_UNREF
 /* uncomment the next define if you wish to keep hash statistics*/
9217a640
 /*
99e9192a
 #define TM_HASH_STATS
9217a640
 */
99e9192a
 /* use hash stats always in debug mode */
 #ifdef EXTRA_DEBUG
 #ifndef TM_HASH_STATS
 #define TM_HASH_STATS
 #endif
 #endif
4ffa91a7
 
99e9192a
 
 #include "../../clist.h"
3881f12c
 #include "../../parser/msg_parser.h"
4bd1673d
 #include "../../types.h"
1f377e97
 #include "../../md5utils.h"
2be21e31
 #include "../../usr_avp.h"
57857a94
 #include "../../timer.h"
cd9460b0
 #include "../../flags.h"
e67d9509
 #include "../../atomic_ops.h"
1ac9ca35
 #include "../../hash_func.h"
dda9dab1
 #include "config.h"
2414d738
 
c0ff60b6
 /* 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
 
 
d214be66
 struct s_table;
2414d738
 struct entry;
d214be66
 struct cell;
b5afaba1
 struct timer;
caf80ae6
 struct retr_buf;
cd9460b0
 struct ua_client;
d214be66
 
caf80ae6
 #include "../../mem/shm_mem.h"
2414d738
 #include "lock.h"
6432d5d9
 #include "sip_msg.h"
caf80ae6
 #include "t_reply.h"
 #include "t_hooks.h"
dcb59e67
 #ifdef USE_DNS_FAILOVER
 #include "../../dns_cache.h"
 #endif
b1f1656e
 
e67d9509
 
b1f1656e
 #define LOCK_HASH(_h) lock_hash((_h))
 #define UNLOCK_HASH(_h) unlock_hash((_h))
 
 void lock_hash(int i);
 void unlock_hash(int i);
6790ac44
 
 
46931a4d
 #define NO_CANCEL       ( (char*) 0 )
 #define EXTERNAL_CANCEL ( (char*) -1)
549d5e1c
 
9217a640
 #define TYPE_LOCAL_ACK    -2
46931a4d
 #define TYPE_LOCAL_CANCEL -1
 #define TYPE_REQUEST       0
01e1ce2f
 
caf80ae6
 /* 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
c0899aa1
 
    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
84d8e165
    REQ_RLSD means that a transaction was put on wait explicitly
c0899aa1
             from t_release_transaction
    REQ_EXIST means that this request is a retransmission which does not
             affect transactional state
b4a4494d
    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).
caf80ae6
 */
b4a4494d
 enum kill_reason { REQ_FWDED=1, REQ_RPLD=2, REQ_RLSD=4, REQ_EXIST=8,
 				   REQ_ERR_DELAYED=16 };
46931a4d
 
0be6158b
 
57857a94
 /* #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 */
9ca82d27
 #define F_RB_TIMEOUT	0x10 /* timeout */
 #define F_RB_REPLIED	0x20 /* reply received */
3357dbdf
 #define F_RB_CANCELED	0x40 /* rb/branch canceled */
431de0d9
 #define F_RB_DEL_TIMER	0x80 /* timer should be deleted if active */
d65cdd3f
 #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 */
57857a94
 
 
81f72c6c
 /* if canceled or intended to be canceled, return true */
 #define uac_dont_fork(uac)	((uac)->local_cancel.buffer)
 
 
46931a4d
 typedef struct retr_buf
2414d738
 {
57857a94
 	short activ_type;
46931a4d
 	/* set to status code if the buffer is a reply,
 	0 if request or -1 if local CANCEL */
d65cdd3f
 	volatile unsigned short flags; /* DISABLED, T2 */
57857a94
 	volatile unsigned char t_active; /* timer active */
 	unsigned short branch; /* no more then 65k branches :-) */
d65cdd3f
 	short buffer_len;
46931a4d
 	char *buffer;
84d8e165
 	/*the cell that contains this retrans_buff*/
d3b31abd
 	struct cell* my_T;
57857a94
 	struct timer_ln timer;
 	struct dest_info dst;
 	ticks_t retr_expire;
 	ticks_t fr_expire; /* ticks value after which fr. will fire */
46931a4d
 }retr_buf_type;
 
 
 
 /* User Agent Server content */
 
 typedef struct ua_server
 {
 	struct sip_msg   *request;
d9f8744f
 	char             *end_request;
46931a4d
 	struct retr_buf  response;
fde02f64
 	/* 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;
57857a94
 	unsigned int     status;
46931a4d
 }ua_server_type;
549d5e1c
 
dda9dab1
 
46931a4d
 
 /* User Agent Client content */
 
388683b5
 #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 */
7718bd4d
 #define TM_UAC_FLAG_FB	4	/* Mark first entry in new branch set */
388683b5
 #endif
 
46931a4d
 typedef struct ua_client
 {
dcb59e67
 	/* if we store a reply (branch picking), this is where it is */
 	struct sip_msg  *reply;
46931a4d
 	struct retr_buf  request;
caf80ae6
 	/* we maintain a separate copy of cancel rather than
84d8e165
 	   reuse the structure for original request; the 
caf80ae6
 	   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 */
dcb59e67
 #ifdef USE_DNS_FAILOVER
 	struct dns_srv_handle dns_h;
 #endif
7d242ad8
 	str uri;
 	str path;
caf80ae6
 	/* if we don't store, we at least want to know the status */
0be6158b
 	int             last_received;
388683b5
 
 #ifdef TM_UAC_FLAGS
 	/* internal flags per tm uac */
 	unsigned int flags;
 #endif
cd9460b0
 	flag_t branch_flags;
d65cdd3f
 #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
46931a4d
 }ua_client_type;
 
2414d738
 
fde02f64
 struct totag_elem {
57857a94
 	struct totag_elem *next;
fde02f64
 	str tag;
9c88dca8
 	volatile int acked;
fde02f64
 };
5a447104
 
0be6158b
 
 
84d8e165
 /* transaction's flags */
0be6158b
 /* is the transaction's request an INVITE? */
 #define T_IS_INVITE_FLAG     (1<<0)
84d8e165
 /* is this a transaction generated by local request? */
0be6158b
 #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)
c1deee7e
 /* 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.*/
ec76200f
 #define T_CANCELED           (1<<3)
65e998d1
 /* 6xx received => stop forking */
81f72c6c
 #define T_6xx            (1<<4) 
0be6158b
 
65e998d1
 #define T_IN_AGONY (1<<5) /* set if waiting to die (delete timer)
57857a94
                              TODO: replace it with del on unref */
b4a4494d
 #define T_AUTO_INV_100 (1<<6) /* send an 100 reply automatically  to inv. */
d65cdd3f
 #ifdef WITH_AS_SUPPORT
 	/* don't generate automatically an ACK for local transaction */
 #	define T_NO_AUTO_ACK	(1<<7)
 #endif
4f03bb4d
 
 #define T_DISABLE_6xx (1<<8) /* treat 6xx as a normal reply */
 #define T_DISABLE_FAILOVER (1<<9) /* don't perform dns failover */
81f72c6c
 #define T_DONT_FORK   (T_CANCELED|T_6xx)
 
c0ff60b6
 /* unsigned short should be enough for a retr. timer: max. 65535 ticks =>
  * max  retr. = 1023 s for tick = 15 ms, which should be more then enough and
  * saves us 2*2 bytes */
 typedef unsigned short retr_timeout_t;
81f72c6c
 
dda9dab1
 /* transaction context */
4c69201e
 
d214be66
 typedef struct cell
 {
4bd1673d
 	/* linking data */
99e9192a
 	/* 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;
0be6158b
 	/* 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 */
57857a94
 	unsigned short flags;
 	/* number of forks */
 	short nr_of_outgoings;
0be6158b
 
e67d9509
 #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 
0be6158b
 	/* 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;
e67d9509
 #endif
4bd1673d
 
caf80ae6
 	/* 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
a70eb298
 	   original message; needed for reply matching */
caf80ae6
 	str method;
 
a70eb298
 	/* head of callback list */
 	struct tmcb_head_list tmcb_hl;
caf80ae6
 
4bd1673d
 	/* bindings to wait and delete timer */
57857a94
 	struct timer_ln wait_timer; /* used also for delete */
4bd1673d
 
 	/* UA Server */
46931a4d
 	struct ua_server  uas;
4bd1673d
 	/* UA Clients */
caf80ae6
 	struct ua_client  uac[ MAX_BRANCHES ];
57857a94
 	
 	/* 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;
d002d02d
 
 	     /* list with avp */
51b8201f
 	struct usr_avp *uri_avps_from;
 	struct usr_avp *uri_avps_to;
d002d02d
 	struct usr_avp *user_avps_from;
 	struct usr_avp *user_avps_to;
 	struct usr_avp *domain_avps_from;
 	struct usr_avp *domain_avps_to;
57857a94
 	
d3b31abd
 	/* protection against concurrent reply processing */
01e1ce2f
 	ser_lock_t   reply_mutex;
57857a94
 	
 	ticks_t fr_timeout;     /* final response interval for retr_bufs */
 	ticks_t fr_inv_timeout; /* final inv. response interval for retr_bufs */
c0ff60b6
 #ifdef TM_DIFF_RT_TIMEOUT
 	retr_timeout_t rt_t1_timeout; /* start retr. interval for retr_bufs */
 	retr_timeout_t rt_t2_timeout; /* maximum retr. interval for retr_bufs */
 #endif
 	ticks_t end_of_life; /* maximum lifetime */
57857a94
 
 	/* nr of replied branch; 0..MAX_BRANCHES=branch value,
 	 * -1 no reply, -2 local reply */
 	short relayed_reply_branch;
4566d0bb
 
caf80ae6
 	/* the route to take if no final positive reply arrived */
57857a94
 	unsigned short on_negative;
87405423
 	/* the onreply_route to be processed if registered to do so */
57857a94
 	unsigned short on_reply;
 	 /* The route to take for each downstream branch separately */
 	unsigned short on_branch;
4566d0bb
 
99e9192a
 	/* 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*/
dda9dab1
 
d214be66
 }cell_type;
 
 
99e9192a
 #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
4c69201e
 
d214be66
 /* double-linked list of cells with hash synonyms */
 typedef struct entry
 {
99e9192a
 	/* 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;
46931a4d
 	/* sync mutex */
 	ser_lock_t      mutex;
99e9192a
 	/* currently highest sequence number in a synonym list */
 	unsigned int    next_label;
 #ifdef TM_HASH_STATS
9c88aeba
 	unsigned long acc_entries;
 	unsigned long cur_entries;
99e9192a
 #endif
 	char _pad[ENTRY_PAD_BYTES];
d214be66
 }entry_type;
 
2414d738
 
4c69201e
 
dda9dab1
 /* transaction table */
d214be66
 struct s_table
 {
46931a4d
 	/* table of hash entries; each of them is a list of synonyms  */
99e9192a
 	struct entry   entries[ TABLE_ENTRIES ];
d214be66
 };
 
99e9192a
 /* pointer to the big table where all the transaction data
    lives */
efbb8d1d
 extern struct s_table*  _tm_table; /* private internal stuff, don't touch
 									  directly */
fde02f64
 
0be6158b
 #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)
50837fd7
 #define was_cancelled(_t_)       ((_t_)->flags&T_CANCELED)
 #define no_new_branches(_t_)     ((_t_)->flags&T_6xx)
0be6158b
 
 
8ba678f2
 void reset_kr();
fde02f64
 void set_kr( enum kill_reason kr );
 enum kill_reason get_kr();
d214be66
 
99e9192a
 #define get_tm_table() (_tm_table)
 
412a5e22
 struct s_table* init_hash_table();
b1f1656e
 void   free_hash_table( );
46931a4d
 void   free_cell( struct cell* dead_cell );
f69b4256
 struct cell*  build_cell( struct sip_msg* p_msg );
4f938453
 
99e9192a
 #ifdef TM_HASH_STATS
caf80ae6
 unsigned int transaction_count( void );
99e9192a
 #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++;
d65cdd3f
 #ifdef EXTRA_DEBUG
 	DEBUG("cell label: %u\n", p_cell->label);
 #endif
99e9192a
 	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) );
 }
caf80ae6
 
d214be66
 #endif
46931a4d