tcp_conn.h
5b532c7f
 /*
53c7e0f1
  * Copyright (C) 2001-2003 FhG Fokus
5b532c7f
  *
6806e46a
  * This file is part of Kamailio, a free SIP server.
5b532c7f
  *
6806e46a
  * Kamailio is free software; you can redistribute it and/or modify
5b532c7f
  * 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
  *
6806e46a
  * Kamailio is distributed in the hope that it will be useful,
5b532c7f
  * 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
9e1ff448
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
049f64c2
  *
5b532c7f
  */
 
 #ifndef _tcp_conn_h
 #define _tcp_conn_h
 
3dc4f620
 #include "tcp_init.h"
885b9f62
 #include "tcp_options.h"
 
6ee62314
 #include "ip_addr.h"
ab130758
 #include "locking.h"
be7401cc
 #include "atomic_ops.h"
ef9e3860
 #include "timer_ticks.h"
ccb7fda2
 #include "timer.h"
5b532c7f
 
a288ee34
 /* maximum number of port aliases x search wildcard possibilities */
 #define TCP_CON_MAX_ALIASES (4*3) 
59653eb8
 
6bc40dea
 #define TCP_CHILD_TIMEOUT 5 /* after 5 seconds, the child "returns" 
 							 the connection to the tcp master process */
 #define TCP_MAIN_SELECT_TIMEOUT 5 /* how often "tcp main" checks for timeout*/
 #define TCP_CHILD_SELECT_TIMEOUT 2 /* the same as above but for children */
 
 
f6e50f08
 /* tcp connection flags */
fc665070
 #define F_CONN_READ_W       2 /* watched for READ ev. in main */
 #define F_CONN_WRITE_W      4 /* watched for WRITE (main) */
 #define F_CONN_READER       8 /* handled by a tcp reader */
19782e1c
 #define F_CONN_HASHED      16 /* in tcp_main hash */
d22b82a0
 #define F_CONN_FD_CLOSED   32 /* fd was already closed */
 #define F_CONN_PENDING     64 /* pending connect  (fd not known yet in main) */
 #define F_CONN_MAIN_TIMER 128 /* timer active in the tcp_main process */
7498b4dc
 #define F_CONN_EOF_SEEN   256 /* FIN or RST have been received */
 #define F_CONN_FORCE_EOF  512 /* act as if an EOF was received */
 #define F_CONN_OOB_DATA  1024 /* out of band data on the connection */
 #define F_CONN_WR_ERROR  2048 /* write error on the fd */
92c0024c
 #define F_CONN_WANTS_RD  4096  /* conn. should be watched for READ */
 #define F_CONN_WANTS_WR  8192  /* conn. should be watched for WRITE */
6d263c0c
 #define F_CONN_PASSIVE  16384 /* conn. created via accept() and not connect()*/
f6e50f08
 
2ad5ba6f
 #ifndef NO_READ_HTTP11
 #define READ_HTTP11
 #endif
f6e50f08
 
122e01f3
 #ifndef NO_READ_MSRP
 #define READ_MSRP
 #endif
 
3ec46961
 #ifndef NO_READ_WS
 #define READ_WS
 #endif
 
f2f969dd
 enum tcp_req_errors {	TCP_REQ_INIT, TCP_REQ_OK, TCP_READ_ERROR,
 						TCP_REQ_OVERRUN, TCP_REQ_BAD_LEN };
122e01f3
 enum tcp_req_states {	H_SKIP_EMPTY, H_SKIP_EMPTY_CR_FOUND,
 		H_SKIP_EMPTY_CRLF_FOUND, H_SKIP_EMPTY_CRLFCR_FOUND,
 		H_SKIP, H_LF, H_LFCR,  H_BODY, H_STARTWS,
6a157851
 		H_CONT_LEN1, H_CONT_LEN2, H_CONT_LEN3, H_CONT_LEN4, H_CONT_LEN5,
 		H_CONT_LEN6, H_CONT_LEN7, H_CONT_LEN8, H_CONT_LEN9, H_CONT_LEN10,
 		H_CONT_LEN11, H_CONT_LEN12, H_CONT_LEN13, H_L_COLON, 
96227c65
 		H_CONT_LEN_BODY, H_CONT_LEN_BODY_PARSE,
c7337a27
 		H_STUN_MSG, H_STUN_READ_BODY, H_STUN_FP, H_STUN_END, H_PING_CRLF
b4fbd9f5
 #ifdef READ_HTTP11
 		, H_HTTP11_CHUNK_START, H_HTTP11_CHUNK_SIZE,
 		H_HTTP11_CHUNK_BODY, H_HTTP11_CHUNK_END, H_HTTP11_CHUNK_FINISH
 #endif
122e01f3
 #ifdef READ_MSRP
 		, H_MSRP_BODY, H_MSRP_BODY_LF, H_MSRP_BODY_END, H_MSRP_FINISH
 #endif
6a157851
 	};
5b532c7f
 
efc23dce
 enum tcp_conn_states { S_CONN_ERROR=-2, S_CONN_BAD=-1,
 						S_CONN_OK=0, /* established (write or read) */
 						S_CONN_INIT, /* initial state (invalid) */
 						S_CONN_EOF,
 						S_CONN_ACCEPT, S_CONN_CONNECT
 					};
f6e50f08
 
 
0c5da34b
 /* fd communication commands */
3bcc0056
 enum conn_cmds {
 	CONN_DESTROY=-3 /* destroy connection & auto-dec. refcnt */,
 	CONN_ERROR=-2   /* error on connection & auto-dec. refcnt */,
 	CONN_EOF=-1     /* eof received or conn. closed & auto-dec refcnt */,
 	CONN_NOP=0      /* do-nothing (invalid for tcp_main) */,
 	CONN_RELEASE    /* release a connection from tcp_read back into tcp_main
 					   & auto-dec refcnt */,
 	CONN_GET_FD     /* request a fd from tcp_main */,
 	CONN_NEW        /* update/set a fd int a new tcp connection; refcnts are
 					  not touched */,
 	CONN_QUEUED_WRITE /* new write queue: start watching the fd for write &
 						 auto-dec refcnt */,
 	CONN_NEW_PENDING_WRITE /* like CONN_NEW+CONN_QUEUED_WRITE: set fd and
 							  start watching it for write (write queue
 							  non-empty); refcnts are not touced */,
 	CONN_NEW_COMPLETE  /* like CONN_NEW_PENDING_WRITE, but there is no
 						  pending write (the write queue might be empty) */
 };
06aaa54f
 /* CONN_RELEASE, EOF, ERROR, DESTROY can be used by "reader" processes
3bcc0056
  * CONN_GET_FD, CONN_NEW*, CONN_QUEUED_WRITE only by writers */
0c5da34b
 
5b532c7f
 struct tcp_req{
 	struct tcp_req* next;
 	/* sockaddr ? */
827cd3be
 	char* buf; /* bytes read so far (+0-terminator)*/
53c7e0f1
 	char* start; /* where the message starts, after all the empty lines are
c0c6207a
 					skipped*/
5b532c7f
 	char* pos; /* current position in buf */
 	char* parsed; /* last parsed position */
 	char* body; /* body position */
827cd3be
 	unsigned int b_size; /* buffer size-1 (extra space for 0-term)*/
6a157851
 	int content_len;
b4fbd9f5
 #ifdef READ_HTTP11
 	int chunk_size;
 #endif
0051630c
 	unsigned short flags; /* F_TCP_REQ_HAS_CLEN | F_TCP_REQ_COMPLETE */
6a157851
 	int bytes_to_go; /* how many bytes we have still to read from the body*/
f2f969dd
 	enum tcp_req_errors error;
 	enum tcp_req_states state;
5b532c7f
 };
 
0051630c
 /* tcp_req flags */
 #define F_TCP_REQ_HAS_CLEN 1
 #define F_TCP_REQ_COMPLETE 2
b4fbd9f5
 #ifdef READ_HTTP11
 #define F_TCP_REQ_BCHUNKED 4
 #endif
122e01f3
 #ifdef READ_MSRP
 #define F_TCP_REQ_MSRP_NO     8
 #define F_TCP_REQ_MSRP_FRAME  16
 #define F_TCP_REQ_MSRP_BODY   32
 #endif
0051630c
 
 #define TCP_REQ_HAS_CLEN(tr)  ((tr)->flags & F_TCP_REQ_HAS_CLEN)
 #define TCP_REQ_COMPLETE(tr)  ((tr)->flags & F_TCP_REQ_COMPLETE)
b4fbd9f5
 #ifdef READ_HTTP11
 #define TCP_REQ_BCHUNKED(tr)  ((tr)->flags & F_TCP_REQ_BCHUNKED)
 #endif
5b532c7f
 
6bc40dea
 
59653eb8
 struct tcp_connection;
 
 /* tcp port alias structure */
 struct tcp_conn_alias{
 	struct tcp_connection* parent;
 	struct tcp_conn_alias* next;
 	struct tcp_conn_alias* prev;
 	unsigned short port; /* alias port */
 	unsigned short hash; /* hash index in the address hash */
 };
 
 
76cb799e
 #ifdef TCP_ASYNC
885b9f62
 	struct tcp_wbuffer{
 		struct tcp_wbuffer* next;
 		unsigned int b_size;
 		char buf[1];
 	};
 
 	struct tcp_wbuffer_queue{
 		struct tcp_wbuffer* first;
 		struct tcp_wbuffer* last;
20863813
 		ticks_t wr_timeout; /* write timeout*/
885b9f62
 		unsigned int queued; /* total size */
 		unsigned int offset; /* offset in the first wbuffer were data
 								starts */
 		unsigned int last_used; /* how much of the last buffer is used */
 	};
 #endif
 
6bc40dea
 
 struct tcp_connection{
 	int s; /*socket, used by "tcp main" */
e29d027b
 	int fd; /* used only by "children", don't modify it! private data! */
0bd53297
 	gen_lock_t write_lock;
0c5da34b
 	int id; /* id (unique!) used to retrieve a specific connection when
 	           reply-ing*/
5c5cd736
 	int reader_pid; /* pid of the active reader process */
f2f969dd
 	struct receive_info rcv; /* src & dst ip, ports, proto a.s.o*/
6bc40dea
 	struct tcp_req req; /* request data */
be7401cc
 	atomic_t refcnt;
1c93f767
 	enum sip_protos type; /* PROTO_TCP or a protocol over it, e.g. TLS */
340ce466
 	unsigned short flags; /* connection related flags */
8cf5dde5
 	snd_flags_t send_flags; /* special send flags */
1c93f767
 	enum tcp_conn_states state; /* connection state */
f6e50f08
 	void* extra_data; /* extra data associated to the connection, 0 for tcp*/
ccb7fda2
 	struct timer_ln timer;
885b9f62
 	ticks_t timeout;/* connection timeout, after this it will be removed*/
2f14564f
 	ticks_t lifetime;/* connection lifetime */
59653eb8
 	unsigned id_hash; /* hash index in the id_hash */
8aeb47e2
 	struct tcp_connection* id_next; /* next, prev in id hash table */
 	struct tcp_connection* id_prev;
6ee62314
 	struct tcp_connection* c_next; /* child next prev (use locally) */
 	struct tcp_connection* c_prev;
7564dcab
 	struct tcp_conn_alias con_aliases[TCP_CON_MAX_ALIASES];
 	int aliases; /* aliases number, at least 1 */
76cb799e
 #ifdef TCP_ASYNC
885b9f62
 	struct tcp_wbuffer_queue wbuf_q;
 #endif
6bc40dea
 };
 
 
f73a84d5
 /* helper macros */
 
8cf5dde5
 #define tcpconn_set_send_flags(c, snd_flags) \
5d6752dc
 	SND_FLAGS_OR(&(c)->send_flags, &(c)->send_flags, &(snd_flags))
340ce466
 
8cf5dde5
 #define tcpconn_close_after_send(c)	((c)->send_flags.f & SND_F_CON_CLOSE)
340ce466
 
f73a84d5
 #define TCP_RCV_INFO(c) (&(c)->rcv)
 
 #define TCP_RCV_LADDR(r) (&((r).dst_ip))
 #define TCP_RCV_LPORT(r) ((r).dst_port)
 #define TCP_RCV_PADDR(r)  (&((r).src_ip))
 #define TCP_RCV_PPORT(r)  ((r).src_port)
 #define TCP_RCV_PSU(r)   (&(r).src_su)
 #define TCP_RCV_SOCK_INFO(r)  ((r).bind_address)
 #define TCP_RCV_PROTO(r)      ((r).proto)
 #ifdef USE_COMP
 #define TCP_RCV_COMP(r)       ((r).comp)
 #else
 #define TCP_RCV_COMP(r)  0
 #endif /* USE_COMP */
 
 #define TCP_LADDR(c) TCP_RCV_LADDR(c->rcv)
 #define TCP_LPORT(c) TCP_RCV_LPORT(c->rcv)
 #define TCP_PADDR(c) TCP_RCV_PADDR(c->rcv)
 #define TCP_PPORT(c) TCP_RCV_PPORT(c->rcv)
 #define TCP_PSU(c)   TCP_RCV_PSU(c->rcv)
 #define TCP_SOCK_INFO(c) TCP_RCV_SOCK_INFO(c->rcv)
 #define TCP_PROTO(c) TCP_RCV_PROTO(c->rcv)
 #define TCP_COMP(c) TCP_RCV_COMP(c->rcv)
6bc40dea
 
 
59653eb8
 
be7401cc
 #define tcpconn_ref(c) atomic_inc(&((c)->refcnt))
19782e1c
 #define tcpconn_put(c) atomic_dec_and_test(&((c)->refcnt))
be7401cc
 
59653eb8
 
827cd3be
 #define init_tcp_req( r, rd_buf, rd_buf_size) \
5b532c7f
 	do{ \
 		memset( (r), 0, sizeof(struct tcp_req)); \
827cd3be
 		(r)->buf=(rd_buf) ;\
 		(r)->b_size=(rd_buf_size)-1; /* space for 0 term. */ \
c0c6207a
 		(r)->parsed=(r)->pos=(r)->start=(r)->buf; \
5b532c7f
 		(r)->error=TCP_REQ_OK;\
c0c6207a
 		(r)->state=H_SKIP_EMPTY; \
5b532c7f
 	}while(0)
 
 
6bc40dea
 /* add a tcpconn to a list*/
6ee62314
 /* list head, new element, next member, prev member */
 #define tcpconn_listadd(head, c, next, prev) \
6bc40dea
 	do{ \
 		/* add it at the begining of the list*/ \
 		(c)->next=(head); \
 		(c)->prev=0; \
 		if ((head)) (head)->prev=(c); \
 		(head)=(c); \
 	} while(0)
 
5b532c7f
 
6bc40dea
 /* remove a tcpconn from a list*/
6ee62314
 #define tcpconn_listrm(head, c, next, prev) \
6bc40dea
 	do{ \
 		if ((head)==(c)) (head)=(c)->next; \
 		if ((c)->next) (c)->next->prev=(c)->prev; \
 		if ((c)->prev) (c)->prev->next=(c)->next; \
 	}while(0)
5b532c7f
 
 
8aeb47e2
 #define TCPCONN_LOCK lock_get(tcpconn_lock);
 #define TCPCONN_UNLOCK lock_release(tcpconn_lock);
5b532c7f
 
a288ee34
 #define TCP_ALIAS_HASH_SIZE 4096
8aeb47e2
 #define TCP_ID_HASH_SIZE 1024
 
a288ee34
 /* hash (dst_ip, dst_port, local_ip, local_port) */
 static inline unsigned tcp_addr_hash(	struct ip_addr* ip, 
 										unsigned short port,
 										struct ip_addr* l_ip,
 										unsigned short l_port)
8aeb47e2
 {
a288ee34
 	unsigned h;
 
 	if(ip->len==4)
 		h=(ip->u.addr32[0]^port)^(l_ip->u.addr32[0]^l_port);
8aeb47e2
 	else if (ip->len==16) 
a288ee34
 		h= (ip->u.addr32[0]^ip->u.addr32[1]^ip->u.addr32[2]^
 				ip->u.addr32[3]^port) ^
 			(l_ip->u.addr32[0]^l_ip->u.addr32[1]^l_ip->u.addr32[2]^
 				l_ip->u.addr32[3]^l_port);
8aeb47e2
 	else{
2ee98a71
 		LM_CRIT("bad len %d for an ip address\n", ip->len);
8aeb47e2
 		return 0;
 	}
a288ee34
 	/* make sure the first bits are influenced by all 32
 	 * (the first log2(TCP_ALIAS_HASH_SIZE) bits should be a mix of all
 	 *  32)*/
 	h ^= h>>17;
 	h ^= h>>7;
 	return h & (TCP_ALIAS_HASH_SIZE-1);
8aeb47e2
 }
 
 #define tcp_id_hash(id) (id&(TCP_ID_HASH_SIZE-1))
5b532c7f
 
ef9e3860
 struct tcp_connection* tcpconn_get(int id, struct ip_addr* ip, int port,
a288ee34
 									union sockaddr_union* local_addr,
ef9e3860
 									ticks_t timeout);
5b532c7f
 
51655771
 typedef struct tcp_event_info {
 	int type;
 	char *buf;
 	unsigned int len;
 	struct receive_info *rcv;
 	struct tcp_connection *con;
 } tcp_event_info_t;
 
1f139814
 typedef struct ws_event_info {
 	int type;
 	char *buf;
 	unsigned int len;
 	int id;
 } ws_event_info_t;
 
5b532c7f
 #endif