tcp_read.c
5b532c7f
 /*
53c7e0f1
  * Copyright (C) 2001-2003 FhG Fokus
5b532c7f
  *
6a0f4382
  * This file is part of Kamailio, a free SIP server.
5b532c7f
  *
6a0f4382
  * 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
  *
6a0f4382
  * 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
5b532c7f
  */
 
6a0f4382
 /** Kamailio core :: tcp readers processes, tcp read and pre-parse msg. functions.
ce51fbb8
  * @file tcp_read.c
  * @ingroup core
  * Module: @ref core
1d0661db
  */
 
5b532c7f
 #ifdef USE_TCP
 
 #include <stdio.h>
 #include <errno.h>
 #include <string.h>
 
 
 #include <sys/time.h>
 #include <sys/types.h>
b988daef
 #include <sys/select.h>
5b532c7f
 #include <sys/socket.h>
 
 #include <unistd.h>
6c6659cb
 #include <stdlib.h> /* for abort() */
5b532c7f
 
 
6a157851
 #include "dprint.h"
5b532c7f
 #include "tcp_conn.h"
ce51fbb8
 #include "tcp_read.h"
7bb2b4ca
 #include "tcp_stats.h"
 #include "tcp_ev.h"
5b532c7f
 #include "pass_fd.h"
6a157851
 #include "globals.h"
 #include "receive.h"
6ee62314
 #include "timer.h"
ccb7fda2
 #include "local_timer.h"
ab130758
 #include "ut.h"
122e01f3
 #include "trim.h"
5c5cd736
 #include "pt.h"
9188021a
 #include "cfg/cfg_struct.h"
6c53d41a
 #ifdef CORE_TLS
28427aa4
 #include "tls/tls_server.h"
6c53d41a
 #else
 #include "tls_hooks.h"
38429f23
 #endif /* CORE_TLS */
 #ifdef USE_DST_BLACKLIST
 #include "dst_blacklist.h"
 #endif /* USE_DST_BLACKLIST */
5b532c7f
 
3135b4bb
 #define HANDLE_IO_INLINE
 #include "io_wait.h"
 #include <fcntl.h> /* must be included after io_wait.h if SIGIO_RT is used */
746f7674
 #include "tsend.h"
c7337a27
 #include "forward.h"
51655771
 #include "events.h"
c573aa70
 #include "stun.h"
96227c65
 
b4fbd9f5
 #ifdef READ_HTTP11
90cbe54c
 #define HTTP11CONTINUE	"HTTP/1.1 100 Continue\r\nContent-Length: 0\r\n\r\n"
b4fbd9f5
 #define HTTP11CONTINUE_LEN	(sizeof(HTTP11CONTINUE)-1)
 #endif
 
ccb7fda2
 #define TCPCONN_TIMEOUT_MIN_RUN  1 /* run the timers each new tick */
 
3135b4bb
 /* types used in io_wait* */
 enum fd_types { F_NONE, F_TCPMAIN, F_TCPCONN };
 
 /* list of tcp connections handled by this process */
 static struct tcp_connection* tcp_conn_lst=0;
 static io_wait_h io_w; /* io_wait handler*/
 static int tcpmain_sock=-1;
5b532c7f
 
ccb7fda2
 static struct local_timer tcp_reader_ltimer;
057063e6
 static ticks_t tcp_reader_prev_ticks;
ccb7fda2
 
c573aa70
 int is_msg_complete(struct tcp_req* r);
 
691a3439
 /**
  * control cloning of TCP receive buffer
  * - needed for operations working directly inside the buffer
  *   (like msg_apply_changes())
  */
 #define TCP_CLONE_RCVBUF
 static int tcp_clone_rcvbuf = 0;
 
 int tcp_set_clone_rcvbuf(int v)
 {
 	int r;
 	r = tcp_clone_rcvbuf;
 	tcp_clone_rcvbuf = v;
 	return r;
 }
 
b4fbd9f5
 #ifdef READ_HTTP11
33f8efe0
 static inline char *strfindcasestrz(str *haystack, char *needlez)
 {
 	int i,j;
 	str needle;
 
 	needle.s = needlez;
 	needle.len = strlen(needlez);
 	for(i=0;i<haystack->len-needle.len;i++) {
 		for(j=0;j<needle.len;j++) {
 			if ( !((haystack->s[i+j]==needle.s[j]) ||
 					( isalpha((int)haystack->s[i+j])
 						&& ((haystack->s[i+j])^(needle.s[j]))==0x20 )) )
 				break;
 		}
 		if (j==needle.len)
 			return haystack->s+i;
 	}
 	return 0;
 }
 
b4fbd9f5
 int tcp_http11_continue(struct tcp_connection *c)
 {
 	struct dest_info dst;
 	char *p;
 	struct msg_start fline;
 	int ret;
33f8efe0
 	str msg;
b4fbd9f5
 
 	ret = 0;
 
33f8efe0
 	msg.s = c->req.start;
 	msg.len = c->req.pos - c->req.start;
122e01f3
 #ifdef READ_MSRP
 	/* skip if MSRP message */
 	if(c->req.flags&F_TCP_REQ_MSRP_FRAME)
 		return 0;
 #endif
33f8efe0
 	p = parse_first_line(msg.s, msg.len, &fline);
b4fbd9f5
 	if(p==NULL)
 		return 0;
 
 	if(fline.type!=SIP_REQUEST)
 		return 0;
 
 	/* check if http request */
 	if(fline.u.request.version.len < HTTP_VERSION_LEN
 			|| strncasecmp(fline.u.request.version.s,
 				HTTP_VERSION, HTTP_VERSION_LEN))
 		return 0;
 
 	/* check for Expect header */
33f8efe0
 	if(strfindcasestrz(&msg, "Expect: 100-continue")!=NULL)
b4fbd9f5
 	{
 		init_dst_from_rcv(&dst, &c->rcv);
 		if (tcp_send(&dst, 0, HTTP11CONTINUE, HTTP11CONTINUE_LEN) < 0) {
8a1f2ede
 			LM_ERR("HTTP/1.1 continue failed\n");
b4fbd9f5
 		}
 	}
 	/* check for Transfer-Encoding header */
33f8efe0
 	if(strfindcasestrz(&msg, "Transfer-Encoding: chunked")!=NULL)
b4fbd9f5
 	{
 		c->req.flags |= F_TCP_REQ_BCHUNKED;
 		ret = 1;
 	}
54c178a9
 	/* check for HTTP Via header
 	 * - HTTP Via format is different that SIP Via
 	 * - workaround: replace with Hia to be ignored by SIP parser
 	 */
 	if((p=strfindcasestrz(&msg, "\nVia:"))!=NULL)
 	{
 		p++;
 		*p = 'H';
 		LM_DBG("replaced HTTP Via with Hia [[\n%.*s]]\n", msg.len, msg.s);
 	}
b4fbd9f5
 	return ret;
 }
 #endif /* HTTP11 */
 
5b532c7f
 
ce51fbb8
 /** reads data from an existing tcp connection.
  * Side-effects: blacklisting, sets connection state to S_CONN_OK, tcp stats.
  * @param fd - connection file descriptor
  * @param c - tcp connection structure. c->state might be changed and
  *             receive info might be used for blacklisting.
  * @param buf - buffer where the received data will be stored.
  * @param b_size - buffer size.
  * @param flags - value/result - used to signal a seen or "forced" EOF on the
7498b4dc
  *     connection (when it is known that no more data will come after the 
ce51fbb8
  *     current socket buffer is emptied )=> return/signal EOF on the first
7498b4dc
  *     short read (=> don't use it on POLLPRI, as OOB data will cause short
ce51fbb8
  *     reads even if there are still remaining bytes in the socket buffer)
  *     input: RD_CONN_FORCE_EOF  - force EOF after the first successful read
  *                                 (bytes_read >=0 )
  *     output: RD_CONN_SHORT_READ - if the read exhausted all the bytes
  *                                  in the socket read buffer.
  *             RD_CONN_EOF - if EOF detected (0 bytes read) or forced via
  *                           RD_CONN_FORCE_EOF.
  *             RD_CONN_REPEAT_READ - the read should be repeated immediately
  *                                   (used only by the tls code for now).
21b8cf90
  *     Note: RD_CONN_SHORT_READ & RD_CONN_EOF _are_ not cleared internally,
  *           so one should clear them before calling this function.
ce51fbb8
  * @return number of bytes read, 0 on EOF or -1 on error,
7498b4dc
  * on EOF it also sets c->state to S_CONN_EOF.
28427aa4
  * (to distinguish from reads that would block which could return 0)
7498b4dc
  * RD_CONN_SHORT_READ is also set in *flags for short reads.
ce51fbb8
  * EOF checking should be done by checking the RD_CONN_EOF flag.
  */
 int tcp_read_data(int fd, struct tcp_connection *c,
 					char* buf, int b_size, int* flags)
5b532c7f
 {
ce51fbb8
 	int bytes_read;
5b532c7f
 	
 again:
ce51fbb8
 	bytes_read=read(fd, buf, b_size);
 	
 	if (likely(bytes_read!=b_size)){
7498b4dc
 		if(unlikely(bytes_read==-1)){
 			if (errno == EWOULDBLOCK || errno == EAGAIN){
 				bytes_read=0; /* nothing has been read */
 			}else if (errno == EINTR) goto again;
 			else{
71eae780
 				if (unlikely(c->state==S_CONN_CONNECT)){
38429f23
 					switch(errno){
 						case ECONNRESET:
7bb2b4ca
 #ifdef USE_DST_BLACKLIST
5d6752dc
 							dst_blacklist_su(BLST_ERR_CONNECT, c->rcv.proto,
 												&c->rcv.src_su,
 												&c->send_flags, 0);
7bb2b4ca
 #endif /* USE_DST_BLACKLIST */
 							TCP_EV_CONNECT_RST(errno, TCP_LADDR(c),
 									TCP_LPORT(c), TCP_PSU(c), TCP_PROTO(c));
 							break;
38429f23
 						case ETIMEDOUT:
7bb2b4ca
 #ifdef USE_DST_BLACKLIST
5d6752dc
 							dst_blacklist_su(BLST_ERR_CONNECT, c->rcv.proto,
 												&c->rcv.src_su,
 												&c->send_flags, 0);
7bb2b4ca
 #endif /* USE_DST_BLACKLIST */
 							TCP_EV_CONNECT_TIMEOUT(errno, TCP_LADDR(c),
 									TCP_LPORT(c), TCP_PSU(c), TCP_PROTO(c));
38429f23
 							break;
7bb2b4ca
 						default:
 							TCP_EV_CONNECT_ERR(errno, TCP_LADDR(c),
 									TCP_LPORT(c), TCP_PSU(c), TCP_PROTO(c));
38429f23
 					}
7bb2b4ca
 					TCP_STATS_CONNECT_FAILED();
 				}else{
 						switch(errno){
 							case ECONNRESET:
 								TCP_STATS_CON_RESET();
 							case ETIMEDOUT:
 #ifdef USE_DST_BLACKLIST
5d6752dc
 								dst_blacklist_su(BLST_ERR_SEND, c->rcv.proto,
 													&c->rcv.src_su,
 													&c->send_flags, 0);
38429f23
 #endif /* USE_DST_BLACKLIST */
7bb2b4ca
 								break;
 						}
 				}
b198224d
 				LOG(cfg_get(core, core_cfg, corelog),
 						"error reading: %s (%d)\n", strerror(errno), errno);
7498b4dc
 				return -1;
 			}
 		}else if (unlikely((bytes_read==0) || 
 					(*flags & RD_CONN_FORCE_EOF))){
 			c->state=S_CONN_EOF;
 			*flags|=RD_CONN_EOF;
4a4da127
 			LM_DBG("EOF on %p, FD %d\n", c, fd);
38429f23
 		}else{
7bb2b4ca
 			if (unlikely(c->state==S_CONN_CONNECT || c->state==S_CONN_ACCEPT)){
 				TCP_STATS_ESTABLISHED(c->state);
38429f23
 				c->state=S_CONN_OK;
7bb2b4ca
 			}
5b532c7f
 		}
7498b4dc
 		/* short read */
 		*flags|=RD_CONN_SHORT_READ;
38429f23
 	}else{ /* else normal full read */
7bb2b4ca
 		if (unlikely(c->state==S_CONN_CONNECT || c->state==S_CONN_ACCEPT)){
 			TCP_STATS_ESTABLISHED(c->state);
38429f23
 			c->state=S_CONN_OK;
7bb2b4ca
 		}
38429f23
 	}
ce51fbb8
 	return bytes_read;
 }
 
 
 
 /* reads next available bytes
  *   c- tcp connection used for reading, tcp_read changes also c->state on
  *      EOF and c->req.error on read error
  *   * flags - value/result - used to signal a seen or "forced" EOF on the 
  *     connection (when it is known that no more data will come after the 
  *     current socket buffer is emptied )=> return/signal EOF on the first 
  *     short read (=> don't use it on POLLPRI, as OOB data will cause short
  *      reads even if there are still remaining bytes in the socket buffer)
  * return number of bytes read, 0 on EOF or -1 on error,
  * on EOF it also sets c->state to S_CONN_EOF.
  * (to distinguish from reads that would block which could return 0)
  * RD_CONN_SHORT_READ is also set in *flags for short reads.
  * sets also r->error */
 int tcp_read(struct tcp_connection *c, int* flags)
 {
 	int bytes_free, bytes_read;
 	struct tcp_req *r;
 	int fd;
 
 	r=&c->req;
 	fd=c->fd;
 	bytes_free=r->b_size- (int)(r->pos - r->buf);
 	
 	if (unlikely(bytes_free==0)){
8a1f2ede
 		LM_ERR("buffer overrun, dropping\n");
ce51fbb8
 		r->error=TCP_REQ_OVERRUN;
 		return -1;
 	}
 	bytes_read = tcp_read_data(fd, c, r->pos, bytes_free, flags);
 	if (unlikely(bytes_read < 0)){
 		r->error=TCP_READ_ERROR;
 		return -1;
 	}
f2e456c3
 #ifdef EXTRA_DEBUG
4a4da127
 	LM_DBG("read %d bytes:\n%.*s\n", bytes_read, bytes_read, r->pos);
f2e456c3
 #endif
5b532c7f
 	r->pos+=bytes_read;
 	return bytes_read;
 }
 
 
 
6a157851
 /* reads all headers (until double crlf), & parses the content-length header
53c7e0f1
  * (WARNING: inefficient, tries to reuse receive_msg but will go through
f2e456c3
  * the headers twice [once here looking for Content-Length and for the end
53c7e0f1
  * of the headers and once in receive_msg]; a more speed efficient version will
f2e456c3
  * result in either major code duplication or major changes to the receive code)
5b532c7f
  * returns number of bytes read & sets r->state & r->body
  * when either r->body!=0 or r->state==H_BODY =>
  * all headers have been read. It should be called in a while loop.
  * returns < 0 if error or 0 if EOF */
7498b4dc
 int tcp_read_headers(struct tcp_connection *c, int* read_flags)
5b532c7f
 {
6a157851
 	int bytes, remaining;
5b532c7f
 	char *p;
28427aa4
 	struct tcp_req* r;
96227c65
 	unsigned int mc;   /* magic cookie */
 	unsigned short body_len;
122e01f3
 
 #ifdef READ_MSRP
 	char *mfline;
eaa64733
 	str mtransid;
122e01f3
 #endif
 
6a157851
 	#define crlf_default_skip_case \
 					case '\n': \
 						r->state=H_LF; \
 						break; \
 					default: \
 						r->state=H_SKIP
 	
 	#define content_len_beg_case \
 					case ' ': \
 					case '\t': \
0051630c
 						if (!TCP_REQ_HAS_CLEN(r)) r->state=H_STARTWS; \
6a157851
 						else r->state=H_SKIP; \
 							/* not interested if we already found one */ \
 						break; \
 					case 'C': \
 					case 'c': \
0051630c
 						if(!TCP_REQ_HAS_CLEN(r)) r->state=H_CONT_LEN1; \
6a157851
 						else r->state=H_SKIP; \
607fcb90
 						break; \
 					case 'l': \
 					case 'L': \
 						/* short form for Content-Length */ \
0051630c
 						if (!TCP_REQ_HAS_CLEN(r)) r->state=H_L_COLON; \
607fcb90
 						else r->state=H_SKIP; \
 						break
6a157851
 						
 	#define change_state(upper, lower, newstate)\
 					switch(*p){ \
 						case upper: \
 						case lower: \
 							r->state=(newstate); break; \
 						crlf_default_skip_case; \
 					}
 	
 	#define change_state_case(state0, upper, lower, newstate)\
 					case state0: \
 							  change_state(upper, lower, newstate); \
 							  p++; \
 							  break
 
 
28427aa4
 	r=&c->req;
ab130758
 	/* if we still have some unparsed part, parse it first, don't do the read*/
7498b4dc
 	if (unlikely(r->parsed<r->pos)){
ab130758
 		bytes=0;
 	}else{
28427aa4
 #ifdef USE_TLS
7498b4dc
 		if (unlikely(c->type==PROTO_TLS))
ce51fbb8
 			bytes=tls_read(c, read_flags);
28427aa4
 		else
 #endif
7498b4dc
 			bytes=tcp_read(c, read_flags);
ab130758
 		if (bytes<=0) return bytes;
 	}
5b532c7f
 	p=r->parsed;
3ec46961
 
6a157851
 	while(p<r->pos && r->error==TCP_REQ_OK){
c0c6207a
 		switch((unsigned char)r->state){
6a157851
 			case H_BODY: /* read the body*/
 				remaining=r->pos-p;
 				if (remaining>r->bytes_to_go) remaining=r->bytes_to_go;
 				r->bytes_to_go-=remaining;
 				p+=remaining;
 				if (r->bytes_to_go==0){
0051630c
 					r->flags|=F_TCP_REQ_COMPLETE;
6a157851
 					goto skip;
 				}
 				break;
 				
 			case H_SKIP:
 				/* find lf, we are in this state if we are not interested
 				 * in anything till end of line*/
ab130758
 				p=q_memchr(p, '\n', r->pos-p);
5b532c7f
 				if (p){
122e01f3
 #ifdef READ_MSRP
 					/* catch if it is MSRP or not with first '\n' */
 					if(!((r->flags&F_TCP_REQ_MSRP_NO)
 								|| (r->flags&F_TCP_REQ_MSRP_FRAME))) {
 						if((r->pos - r->start)>5
 									&& strncmp(r->start, "MSRP ", 5)==0)
 						{
 							r->flags |= F_TCP_REQ_MSRP_FRAME;
 						} else {
 							r->flags |= F_TCP_REQ_MSRP_NO;
 						}
 					}
 #endif
5b532c7f
 					p++;
 					r->state=H_LF;
 				}else{
 					p=r->pos;
 				}
 				break;
 				
 			case H_LF:
 				/* terminate on LF CR LF or LF LF */
6a157851
 				switch (*p){
 					case '\r':
 						r->state=H_LFCR;
 						break;
 					case '\n':
 						/* found LF LF */
 						r->state=H_BODY;
54c178a9
 #ifdef READ_HTTP11
 						if (cfg_get(tcp, tcp_cfg, accept_no_cl)!=0)
 							tcp_http11_continue(c);
 #endif
0051630c
 						if (TCP_REQ_HAS_CLEN(r)){
6a157851
 							r->body=p+1;
 							r->bytes_to_go=r->content_len;
 							if (r->bytes_to_go==0){
0051630c
 								r->flags|=F_TCP_REQ_COMPLETE;
ab130758
 								p++;
6a157851
 								goto skip;
 							}
 						}else{
54c178a9
 							if(cfg_get(tcp, tcp_cfg, accept_no_cl)!=0) {
 #ifdef READ_MSRP
 								/* if MSRP message */
 								if(c->req.flags&F_TCP_REQ_MSRP_FRAME)
 								{
 									r->body=p+1;
 									/* at least 3 bytes: 0\r\n */
 									r->bytes_to_go=3;
 									p++;
 									r->content_len = 0;
 									r->state=H_MSRP_BODY;
 									break;
 								}
 #endif
 
 #ifdef READ_HTTP11
 								if(TCP_REQ_BCHUNKED(r)) {
 									r->body=p+1;
 									/* at least 3 bytes: 0\r\n */
 									r->bytes_to_go=3;
 									p++;
 									r->content_len = 0;
 									r->state=H_HTTP11_CHUNK_START;
 									break;
 								}
 #endif
 								r->body=p+1;
 								r->bytes_to_go=0;
 								r->flags|=F_TCP_REQ_COMPLETE;
 								p++;
 								goto skip;
 							} else {
4a4da127
 								LM_DBG("ERROR: no clen, p=%X\n", *p);
54c178a9
 								r->error=TCP_REQ_BAD_LEN;
 							}
6a157851
 						}
 						break;
122e01f3
 					case '-':
 						r->state=H_SKIP;
 #ifdef READ_MSRP
 						/* catch end of MSRP frame without body
 						 *     '-------sessid$\r\n'
 						 * follows headers wihtout extra CRLF */
 						if(r->flags&F_TCP_REQ_MSRP_FRAME) {
 							p--;
 							r->state=H_MSRP_BODY_END;
 						}
 #endif
 						break;
6a157851
 					content_len_beg_case;
 					default: 
 						r->state=H_SKIP;
 				}
5b532c7f
 				p++;
 				break;
 			case H_LFCR:
 				if (*p=='\n'){
 					/* found LF CR LF */
 					r->state=H_BODY;
b4fbd9f5
 #ifdef READ_HTTP11
 					if (cfg_get(tcp, tcp_cfg, accept_no_cl)!=0)
 						tcp_http11_continue(c);
 #endif
0051630c
 					if (TCP_REQ_HAS_CLEN(r)){
6a157851
 						r->body=p+1;
 						r->bytes_to_go=r->content_len;
 						if (r->bytes_to_go==0){
0051630c
 							r->flags|=F_TCP_REQ_COMPLETE;
ab130758
 							p++;
6a157851
 							goto skip;
 						}
 					}else{
d4cc4103
 						if (cfg_get(tcp, tcp_cfg, accept_no_cl)!=0) {
122e01f3
 #ifdef READ_MSRP
 							/* if MSRP message */
 							if(c->req.flags&F_TCP_REQ_MSRP_FRAME)
 							{
 								r->body=p+1;
 								/* at least 3 bytes: 0\r\n */
 								r->bytes_to_go=3;
 								p++;
 								r->content_len = 0;
 								r->state=H_MSRP_BODY;
 								break;
 							}
 #endif
 
b4fbd9f5
 #ifdef READ_HTTP11
 							if(TCP_REQ_BCHUNKED(r)) {
 								r->body=p+1;
 								/* at least 3 bytes: 0\r\n */
 								r->bytes_to_go=3;
 								p++;
 								r->content_len = 0;
 								r->state=H_HTTP11_CHUNK_START;
 								break;
 							}
 #endif
d4cc4103
 							r->body=p+1;
 							r->bytes_to_go=0;
 							r->flags|=F_TCP_REQ_COMPLETE;
 							p++;
 							goto skip;
 						} else {
4a4da127
 							LM_DBG("ERROR: no clen, p=%X\n", *p);
d4cc4103
 							r->error=TCP_REQ_BAD_LEN;
 						}
6a157851
 					}
 				}else r->state=H_SKIP;
5b532c7f
 				p++;
 				break;
 				
6a157851
 			case H_STARTWS:
 				switch (*p){
 					content_len_beg_case;
 					crlf_default_skip_case;
 				}
 				p++;
 				break;
c0c6207a
 			case H_SKIP_EMPTY:
 				switch (*p){
 					case '\n':
c7337a27
 						break;
c0c6207a
 					case '\r':
22db42e4
 						if (cfg_get(tcp, tcp_cfg, crlf_ping)) {
c7337a27
 							r->state=H_SKIP_EMPTY_CR_FOUND;
 							r->start=p;
 						}
 						break;
c0c6207a
 					case ' ':
 					case '\t':
 						/* skip empty lines */
 						break;
 					case 'C': 
 					case 'c': 
 						r->state=H_CONT_LEN1; 
 						r->start=p;
 						break;
607fcb90
 					case 'l':
 					case 'L':
 						/* short form for Content-Length */
 						r->state=H_L_COLON;
 						r->start=p;
 						break;
c0c6207a
 					default:
96227c65
 						/* stun test */						
c573aa70
 						if (unlikely(sr_event_enabled(SREV_STUN_IN)) && (unsigned char)*p == 0x00) {
96227c65
 							r->state=H_STUN_MSG;
 						/* body will used as pointer to the last used byte */
 							r->body=p;
0e3dd037
 							r->content_len = 0;
4a4da127
 							LM_DBG("stun msg detected\n");
c573aa70
 						} else {
 							r->state=H_SKIP;
 						}
c0c6207a
 						r->start=p;
 				};
 				p++;
 				break;
c7337a27
 
 			case H_SKIP_EMPTY_CR_FOUND:
 				if (*p=='\n'){
 					r->state=H_SKIP_EMPTY_CRLF_FOUND;
 					p++;
 				}else{
 					r->state=H_SKIP_EMPTY;
 				}
 				break;
 
 			case H_SKIP_EMPTY_CRLF_FOUND:
 				if (*p=='\r'){
 					r->state = H_SKIP_EMPTY_CRLFCR_FOUND;
 					p++;
 				}else{
 					r->state = H_SKIP_EMPTY;
 				}
 				break;
 
 			case H_SKIP_EMPTY_CRLFCR_FOUND:
 				if (*p=='\n'){
 					r->state = H_PING_CRLF;
0051630c
 					r->flags |= F_TCP_REQ_HAS_CLEN |
 							F_TCP_REQ_COMPLETE; /* hack to avoid error check */
c7337a27
 					p++;
 					goto skip;
 				}else{
 					r->state = H_SKIP_EMPTY;
 				}
 				break;
c573aa70
 
96227c65
 			case H_STUN_MSG:
 				if ((r->pos - r->body) >= sizeof(struct stun_hdr)) {
 					/* copy second short from buffer where should be body 
 					 * length 
 					 */
 					memcpy(&body_len, &r->start[sizeof(unsigned short)], 
 						sizeof(unsigned short));
 					
0e3dd037
 					body_len = ntohs(body_len);
96227c65
 					
 					/* check if there is valid magic cookie */
 					memcpy(&mc, &r->start[sizeof(unsigned int)], 
 						sizeof(unsigned int));
 					mc = ntohl(mc);
 					/* using has_content_len as a flag if there should be
 					 * fingerprint or no
 					 */
0051630c
 					r->flags |= (mc == MAGIC_COOKIE) ? F_TCP_REQ_HAS_CLEN : 0;
96227c65
 					
 					r->body += sizeof(struct stun_hdr);
 					p = r->body; 
 					
 					if (body_len > 0) {
 						r->state = H_STUN_READ_BODY;
 					}
 					else {
 						if (is_msg_complete(r) != 0) {
 							goto skip;
 						}
 						else {
 							/* set content_len to length of fingerprint */
c573aa70
 							body_len = sizeof(struct stun_attr) + 20;
 							/* 20 is SHA_DIGEST_LENGTH from openssl/sha.h */
96227c65
 						}
 					}
0e3dd037
 					r->content_len=body_len;
96227c65
 				}
 				else {
 					p = r->pos; 
 				}
 				break;
 				
 			case H_STUN_READ_BODY:
 				/* check if the whole body was read */
0e3dd037
 				body_len=r->content_len;
96227c65
 				if ((r->pos - r->body) >= body_len) {
 					r->body += body_len;
 					p = r->body;
 					if (is_msg_complete(r) != 0) {
0e3dd037
 						r->content_len=0;
96227c65
 						goto skip;
 					}
 					else {
 						/* set content_len to length of fingerprint */
c573aa70
 						body_len = sizeof(struct stun_attr) + 20;
 						/* 20 is SHA_DIGEST_LENGTH from openssl/sha.h */
0e3dd037
 						r->content_len=body_len;
96227c65
 					}
 				}
 				else {
 					p = r->pos;
 				}
 				break;
 				
 			case H_STUN_FP:
 				/* content_len contains length of fingerprint in this place! */
0e3dd037
 				body_len=r->content_len;
96227c65
 				if ((r->pos - r->body) >= body_len) {
 					r->body += body_len;
 					p = r->body;
 					r->state = H_STUN_END;
0051630c
 					r->flags |= F_TCP_REQ_COMPLETE |
 						F_TCP_REQ_HAS_CLEN; /* hack to avoid error check */
0e3dd037
 					r->content_len=0;
96227c65
 					goto skip;
 				}
 				else {
 					p = r->pos;
 				}
 				break;
c573aa70
 
6a157851
 			change_state_case(H_CONT_LEN1,  'O', 'o', H_CONT_LEN2);
 			change_state_case(H_CONT_LEN2,  'N', 'n', H_CONT_LEN3);
 			change_state_case(H_CONT_LEN3,  'T', 't', H_CONT_LEN4);
 			change_state_case(H_CONT_LEN4,  'E', 'e', H_CONT_LEN5);
 			change_state_case(H_CONT_LEN5,  'N', 'n', H_CONT_LEN6);
 			change_state_case(H_CONT_LEN6,  'T', 't', H_CONT_LEN7);
 			change_state_case(H_CONT_LEN7,  '-', '_', H_CONT_LEN8);
 			change_state_case(H_CONT_LEN8,  'L', 'l', H_CONT_LEN9);
 			change_state_case(H_CONT_LEN9,  'E', 'e', H_CONT_LEN10);
 			change_state_case(H_CONT_LEN10, 'N', 'n', H_CONT_LEN11);
 			change_state_case(H_CONT_LEN11, 'G', 'g', H_CONT_LEN12);
 			change_state_case(H_CONT_LEN12, 'T', 't', H_CONT_LEN13);
 			change_state_case(H_CONT_LEN13, 'H', 'h', H_L_COLON);
b4fbd9f5
 
6a157851
 			case H_L_COLON:
 				switch(*p){
 					case ' ':
 					case '\t':
 						break; /* skip space */
 					case ':':
 						r->state=H_CONT_LEN_BODY;
 						break;
 					crlf_default_skip_case;
 				};
 				p++;
 				break;
b4fbd9f5
 
6a157851
 			case  H_CONT_LEN_BODY:
 				switch(*p){
 					case ' ':
 					case '\t':
 						break; /* eat space */
 					case '0':
 					case '1':
 					case '2':
 					case '3':
 					case '4':
 					case '5':
 					case '6':
 					case '7':
 					case '8':
 					case '9':
 						r->state=H_CONT_LEN_BODY_PARSE;
 						r->content_len=(*p-'0');
 						break;
53c7e0f1
 					/*FIXME: content length on different lines ! */
6a157851
 					crlf_default_skip_case;
 				}
 				p++;
 				break;
b4fbd9f5
 
6a157851
 			case H_CONT_LEN_BODY_PARSE:
 				switch(*p){
 					case '0':
 					case '1':
 					case '2':
 					case '3':
 					case '4':
 					case '5':
 					case '6':
 					case '7':
 					case '8':
c0c6207a
 					case '9':
6a157851
 						r->content_len=r->content_len*10+(*p-'0');
 						break;
 					case '\r':
 					case ' ':
 					case '\t': /* FIXME: check if line contains only WS */
3c544209
 						if(r->content_len<0) {
8a1f2ede
 							LM_ERR("bad Content-Length header value %d in"
3c544209
 									" state %d\n", r->content_len, r->state);
 							r->content_len=0;
 							r->error=TCP_REQ_BAD_LEN;
 							r->state=H_SKIP; /* skip now */
 						}
6a157851
 						r->state=H_SKIP;
0051630c
 						r->flags|=F_TCP_REQ_HAS_CLEN;
6a157851
 						break;
 					case '\n':
53c7e0f1
 						/* end of line, parse successful */
3c544209
 						if(r->content_len<0) {
8a1f2ede
 							LM_ERR("bad Content-Length header value %d in"
3c544209
 									" state %d\n", r->content_len, r->state);
 							r->content_len=0;
 							r->error=TCP_REQ_BAD_LEN;
 							r->state=H_SKIP; /* skip now */
 						}
6a157851
 						r->state=H_LF;
0051630c
 						r->flags|=F_TCP_REQ_HAS_CLEN;
6a157851
 						break;
 					default:
8a1f2ede
 						LM_ERR("bad Content-Length header value, unexpected "
6a157851
 								"char %c in state %d\n", *p, r->state);
 						r->state=H_SKIP; /* try to find another?*/
 				}
 				p++;
 				break;
 			
b4fbd9f5
 #ifdef READ_HTTP11
 			case H_HTTP11_CHUNK_START: /* start a new body chunk: SIZE\r\nBODY\r\n */
 				r->chunk_size = 0;
 				r->state = H_HTTP11_CHUNK_SIZE;
 				break;
 			case H_HTTP11_CHUNK_BODY: /* content of chunnk */
 				remaining=r->pos-p;
 				if (remaining>r->bytes_to_go) remaining=r->bytes_to_go;
 				r->bytes_to_go-=remaining;
 				p+=remaining;
 				if (r->bytes_to_go==0){
 					r->state = H_HTTP11_CHUNK_END;
 					/* shift back body content */
da381afe
 					if(r->chunk_size>0 && p-r->chunk_size>r->body) {
38f1ee41
 						memmove(r->body + r->content_len, p - r->chunk_size,
b4fbd9f5
 								r->chunk_size);
 						r->content_len += r->chunk_size;
 					}
 					goto skip;
 				}
 				break;
 
 			case H_HTTP11_CHUNK_END:
 				switch(*p){
 					case '\r':
 					case ' ':
 					case '\t': /* skip */
 						break;
 					case '\n':
 						r->state = H_HTTP11_CHUNK_START;
 						break;
 					default:
 						LM_ERR("bad chunk, unexpected "
 								"char %c in state %d\n", *p, r->state);
 						r->state=H_SKIP; /* try to find another?*/
 				}
 				p++;
 				break;
 
 			case H_HTTP11_CHUNK_SIZE:
 				switch(*p){
 					case '0': case '1': case '2': case '3':
 					case '4': case '5': case '6': case '7':
 					case '8': case '9':
 						r->chunk_size <<= 4;
 						r->chunk_size += *p - '0';
 						break;
 					case 'a': case 'b': case 'c': case 'd':
 					case 'e': case 'f':
 						r->chunk_size <<= 4;
 						r->chunk_size += *p - 'a' + 10;
 						break;
 					case 'A': case 'B': case 'C': case 'D':
 					case 'E': case 'F':
 						r->chunk_size <<= 4;
 						r->chunk_size += *p - 'A' + 10;
 						break;
 					case '\r':
 					case ' ':
 					case '\t': /* skip */
 						break;
 					case '\n':
 						/* end of line, parse successful */
 						r->state=H_HTTP11_CHUNK_BODY;
 						r->bytes_to_go = r->chunk_size;
 						if (r->bytes_to_go==0){
 							r->state=H_HTTP11_CHUNK_FINISH;
 							r->flags|=F_TCP_REQ_COMPLETE;
 							p++;
 							goto skip;
 						}
 						break;
 					default:
 						LM_ERR("bad chunk size value, unexpected "
 								"char %c in state %d\n", *p, r->state);
 						r->state=H_SKIP; /* try to find another?*/
 				}
 				p++;
 				break;
 #endif
122e01f3
 #ifdef READ_MSRP
 			case H_MSRP_BODY: /* body of msrp frame */
 				/* find lf, we are in this state if we are not interested
 				 * in anything till end of line*/
 				r->flags |= F_TCP_REQ_MSRP_BODY;
 				p = q_memchr(p, '\n', r->pos-p);
 				if (p) {
 					p++;
 					r->state=H_MSRP_BODY_LF;
 				} else {
 					p=r->pos;
 				}
 				break;
 			case H_MSRP_BODY_LF: /* LF in body of msrp frame */
 				switch (*p) {
 					case '-':
 							p--;
 							r->state=H_MSRP_BODY_END;
 						break;
 					default:
 						r->state=H_MSRP_BODY;
 				}
 				p++;
 				break;
 			case H_MSRP_BODY_END: /* end of body for msrp frame */
 				/* find LF and check if it is end-line */
 				p = q_memchr(p, '\n', r->pos-p);
 				if (p) {
 					/* check if it is end line '-------sessid$\r\n' */
 					if(r->pos - r->start < 10) {
 						LM_ERR("weird situation when reading MSRP frame"
 								" - continue reading\n");
b255c406
 						/* *p=='\n' */
 						r->state=H_MSRP_BODY_LF;
122e01f3
 						p++;
 						break;
 					}
 					if(*(p-1)!='\r') {
 						/* not ending in '\r\n' - not end-line */
b255c406
 						/* *p=='\n' */
 						r->state=H_MSRP_BODY_LF;
122e01f3
 						p++;
 						break;
 					}
eaa64733
 					/* locate transaction id in first line
122e01f3
 					 * -- first line exists, that's why we are here */
 					mfline =  q_memchr(r->start, '\n', r->pos-r->start);
eaa64733
 					mtransid.s = q_memchr(r->start + 5 /* 'MSRP ' */, ' ',
122e01f3
 							mfline - r->start);
eaa64733
 					mtransid.len = mtransid.s - r->start - 5;
 					mtransid.s = r->start + 5;
 					trim(&mtransid);
 					if(memcmp(mtransid.s,
 							p - 1 /*\r*/ - 1 /* '+'|'#'|'$' */ - mtransid.len,
 							mtransid.len)!=0) {
122e01f3
 						/* no match on session id - not end-line */
b255c406
 						/* *p=='\n' */
 						r->state=H_MSRP_BODY_LF;
122e01f3
 						p++;
 						break;
 					}
eaa64733
 					if(memcmp(p - 1 /*\r*/ - 1 /* '+'|'#'|'$' */ - mtransid.len
122e01f3
 								- 7 /* 7 x '-' */ - 1 /* '\n' */, "\n-------",
 								8)!=0) {
 						/* no match on "\n-------" - not end-line */
b255c406
 						/* *p=='\n' */
 						r->state=H_MSRP_BODY_LF;
122e01f3
 						p++;
 						break;
 					}
 					r->state=H_MSRP_FINISH;
 					r->flags|=F_TCP_REQ_COMPLETE;
 					p++;
 					goto skip;
 
 				} else {
 					p=r->pos;
 				}
 				break;
 #endif
b4fbd9f5
 
5b532c7f
 			default:
8a1f2ede
 				LM_CRIT("unexpected state %d\n", r->state);
5b532c7f
 				abort();
 		}
 	}
6a157851
 skip:
5b532c7f
 	r->parsed=p;
 	return bytes;
 }
 
 
122e01f3
 #ifdef READ_MSRP
 int msrp_process_msg(char* tcpbuf, unsigned int len,
 		struct receive_info* rcv_info, struct tcp_connection* con)
 {
51655771
 	int ret;
 	tcp_event_info_t tev;
 
 	ret = 0;
122e01f3
 	LM_DBG("MSRP Message: [[>>>\n%.*s<<<]]\n", len, tcpbuf);
51655771
 	if(likely(sr_event_enabled(SREV_TCP_MSRP_FRAME))) {
 		memset(&tev, 0, sizeof(tcp_event_info_t));
 		tev.type = SREV_TCP_MSRP_FRAME;
 		tev.buf = tcpbuf;
 		tev.len = len;
 		tev.rcv = rcv_info;
 		tev.con = con;
 		ret = sr_event_exec(SREV_TCP_MSRP_FRAME, (void*)(&tev));
 	} else {
 		LM_DBG("no callback registering for handling MSRP - dropping!\n");
 	}
 	return ret;
122e01f3
 }
 #endif
 
3ec46961
 #ifdef READ_WS
1718093c
 static int tcp_read_ws(struct tcp_connection *c, int* read_flags)
 {
69c264b1
 	int bytes, size, pos, mask_present;
62691a52
 	unsigned int len;
1718093c
 	char *p;
 	struct tcp_req *r;
 
 	r=&c->req;
 #ifdef USE_TLS
8393efff
 	if (unlikely(c->type == PROTO_WSS))
d07a57f6
 		bytes = tls_read(c, read_flags);
 	else
1718093c
 #endif
d07a57f6
 		bytes = tcp_read(c, read_flags);
1718093c
 
d07a57f6
 	if (bytes <= 0)
 	{
 		if (likely(r->parsed >= r->pos))
1718093c
 			return 0;
 	}
 
d07a57f6
 	size = r->pos - r->parsed;
 
1718093c
 	p = r->parsed;
 	pos = 0;
 
 	/*
 	 0                   1                   2                   3
 	 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 	+-+-+-+-+-------+-+-------------+-------------------------------+
 	|F|R|R|R| opcode|M| Payload len |    Extended payload length    |
 	|I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
 	|N|V|V|V|       |S|             |   (if payload len==126/127)   |
 	| |1|2|3|       |K|             |                               |
 	+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
 	|     Extended payload length continued, if payload len == 127  |
 	+ - - - - - - - - - - - - - - - +-------------------------------+
 	|                               |Masking-key, if MASK set to 1  |
 	+-------------------------------+-------------------------------+
 	| Masking-key (continued)       |          Payload Data         |
 	+-------------------------------- - - - - - - - - - - - - - - - +
 	:                     Payload Data continued ...                :
 	+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
 	|                     Payload Data continued ...                |
 	+---------------------------------------------------------------+
 
 	Do minimal parse required to make sure the full message has been
 	received (websocket module will do full parse and validation).
 	*/
 
 	/* Process first two bytes */
69c264b1
 	if (size < pos + 2)
1718093c
 		goto skip;
 	pos++;
 	mask_present = p[pos] & 0x80;
 	len = (p[pos++] & 0xff) & ~0x80;
 
 	/* Work out real length */
 	if (len == 126)
 	{
69c264b1
 		if (size < pos + 2)
1718093c
 			goto skip;
 
62691a52
 		len =	  ((p[pos + 0] & 0xff) <<  8)
 			| ((p[pos + 1] & 0xff) <<  0);
 		pos += 2;
1718093c
 	}
 	else if (len == 127)
 	{
69c264b1
 		if (size < pos + 8)
1718093c
 			goto skip;
 
 		/* Only decoding the last four bytes of the length...
 		   This limits the size of WebSocket messages that can be
 		   handled to 2^32 - which should be plenty for SIP! */
62691a52
 		len =	  ((p[pos + 4] & 0xff) << 24)
 			| ((p[pos + 5] & 0xff) << 16)
 			| ((p[pos + 6] & 0xff) <<  8)
 			| ((p[pos + 7] & 0xff) <<  0);
 		pos += 8;
1718093c
 	}
 
 	/* Skip mask */
 	if (mask_present)
 	{
69c264b1
 		if (size < pos + 4)
1718093c
 			goto skip;
 		pos += 4;
 	}
 
 	/* Now check the whole message has been received */
69c264b1
 	if (size < pos + len)
1718093c
 		goto skip;
 
 	pos += len;
 	r->flags |= F_TCP_REQ_COMPLETE;
 	r->parsed = &p[pos];
 
 skip:
 	return bytes;
 }
 
3ec46961
 static int ws_process_msg(char* tcpbuf, unsigned int len,
 		struct receive_info* rcv_info, struct tcp_connection* con)
 {
 	int ret;
 	tcp_event_info_t tev;
 
 	ret = 0;
 	LM_DBG("WebSocket Message: [[>>>\n%.*s<<<]]\n", len, tcpbuf);
1f139814
 	if(likely(sr_event_enabled(SREV_TCP_WS_FRAME_IN))) {
3ec46961
 		memset(&tev, 0, sizeof(tcp_event_info_t));
1f139814
 		tev.type = SREV_TCP_WS_FRAME_IN;
3ec46961
 		tev.buf = tcpbuf;
 		tev.len = len;
 		tev.rcv = rcv_info;
 		tev.con = con;
1f139814
 		ret = sr_event_exec(SREV_TCP_WS_FRAME_IN, (void*)(&tev));
3ec46961
 	} else {
 		LM_DBG("no callback registering for handling WebSockets - dropping!\n");
 	}
 	return ret;
 }
 #endif
 
6ebd0a6b
 /**
  * @brief wrapper around receive_msg() to clone the tcpbuf content
  *
  * When receiving over TCP, tcpbuf points inside the TCP stream buffer, but during
  * processing of config, msg->buf content might be changed and may corrupt
  * the content of the stream. Safer, make a clone of buf content in a local
  * buffer and give that to receive_msg() to link to msg->buf
  */
122e01f3
 int receive_tcp_msg(char* tcpbuf, unsigned int len,
 		struct receive_info* rcv_info, struct tcp_connection* con)
6ebd0a6b
 {
a510d17d
 #ifdef TCP_CLONE_RCVBUF
6ebd0a6b
 #ifdef DYN_BUF
 	char *buf = NULL;
 #else
 	static char *buf = NULL;
 	static unsigned int bsize = 0;
 #endif
 	int blen;
 
691a3439
 	/* cloning is disabled via parameter */
122e01f3
 	if(likely(tcp_clone_rcvbuf==0)) {
 #ifdef READ_MSRP
 		if(unlikely(con->req.flags&F_TCP_REQ_MSRP_FRAME))
 			return msrp_process_msg(tcpbuf, len, rcv_info, con);
 #endif
c04689c5
 #ifdef READ_WS
8393efff
 		if(unlikely(con->type == PROTO_WS || con->type == PROTO_WSS))
c04689c5
 			return ws_process_msg(tcpbuf, len, rcv_info, con);
 #endif
 
691a3439
 		return receive_msg(tcpbuf, len, rcv_info);
122e01f3
 	}
691a3439
 
6ebd0a6b
 	/* min buffer size is BUF_SIZE */
 	blen = len;
 	if(blen < BUF_SIZE)
 		blen = BUF_SIZE;
 
 #ifdef DYN_BUF
 	buf=pkg_malloc(blen+1);
 	if (buf==0) {
 		LM_ERR("could not allocate receive buffer\n");
 		return -1;
 	}
 #else
 	/* allocate buffer when needed
 	 * - no buffer yet
 	 * - existing buffer too small (min size is BUF_SIZE - to accomodate most
 	 *   of SIP messages; expected larger for HTTP/XCAP)
 	 * - existing buffer too large (e.g., we got a too big message in the past,
 	 *   let's free it)
 	 *
 	 * - also, use system memory, not to eat from PKG (same as static buffer
 	 *   from PKG pov)
 	 */
 	if(buf==NULL || bsize < blen || blen < bsize/2) {
 		if(buf!=NULL)
 			free(buf);
 		buf=malloc(blen+1);
 		if (buf==0) {
 			LM_ERR("could not allocate receive buffer\n");
 			return -1;
 		}
 		bsize = blen;
 	}
 #endif
 
 	memcpy(buf, tcpbuf, len);
 	buf[len] = '\0';
122e01f3
 #ifdef READ_MSRP
 	if(unlikely(con->req.flags&F_TCP_REQ_MSRP_FRAME))
 		return msrp_process_msg(buf, len, rcv_info, con);
 #endif
c04689c5
 #ifdef READ_WS
8393efff
 	if(unlikely(con->type == PROTO_WS || con->type == PROTO_WSS))
c04689c5
 		return ws_process_msg(buf, len, rcv_info, con);
 #endif
6ebd0a6b
 	return receive_msg(buf, len, rcv_info);
a510d17d
 #else /* TCP_CLONE_RCVBUF */
122e01f3
 #ifdef READ_MSRP
 	if(unlikely(con->req.flags&F_TCP_REQ_MSRP_FRAME))
 		return msrp_process_msg(tcpbuf, len, rcv_info, con);
 #endif
c04689c5
 #ifdef READ_WS
8393efff
 	if(unlikely(con->type == PROTO_WS || con->type == PROTO_WSS))
c04689c5
 		return ws_process_msg(tcpbuf, len, rcv_info, con);
 #endif
a510d17d
 	return receive_msg(tcpbuf, len, rcv_info);
 #endif /* TCP_CLONE_RCVBUF */
6ebd0a6b
 }
5b532c7f
 
7498b4dc
 int tcp_read_req(struct tcp_connection* con, int* bytes_read, int* read_flags)
6ee62314
 {
 	int bytes;
06c04bc2
 	int total_bytes;
0c5da34b
 	int resp;
6ee62314
 	long size;
 	struct tcp_req* req;
c7337a27
 	struct dest_info dst;
8fc80c33
 	char c;
96227c65
 	int ret;
6ee62314
 		
3135b4bb
 		bytes=-1;
06c04bc2
 		total_bytes=0;
0c5da34b
 		resp=CONN_RELEASE;
6ee62314
 		req=&con->req;
28427aa4
 
ab130758
 again:
7498b4dc
 		if (likely(req->error==TCP_REQ_OK)){
1718093c
 #ifdef READ_WS
8393efff
 			if (unlikely(con->type == PROTO_WS || con->type == PROTO_WSS))
1718093c
 				bytes=tcp_read_ws(con, read_flags);
 			else
 #endif
 				bytes=tcp_read_headers(con, read_flags);
f2e456c3
 #ifdef EXTRA_DEBUG
6ee62314
 						/* if timeout state=0; goto end__req; */
4a4da127
 			LM_DBG("read= %d bytes, parsed=%d, state=%d, error=%d\n",
b988daef
 					bytes, (int)(req->parsed-req->start), req->state,
 					req->error );
4a4da127
 			LM_DBG("last char=0x%02X, parsed msg=\n%.*s\n",
b988daef
 					*(req->parsed-1), (int)(req->parsed-req->start),
 					req->start);
f2e456c3
 #endif
7498b4dc
 			if (unlikely(bytes==-1)){
b198224d
 				LOG(cfg_get(core, core_cfg, corelog),
 						"ERROR: tcp_read_req: error reading \n");
0c5da34b
 				resp=CONN_ERROR;
6ee62314
 				goto end_req;
 			}
06c04bc2
 			total_bytes+=bytes;
6ee07a24
 			/* eof check:
 			 * is EOF if eof on fd and req.  not complete yet,
 			 * if req. is complete we might have a second unparsed
 			 * request after it, so postpone release_with_eof
 			 */
0051630c
 			if (unlikely((con->state==S_CONN_EOF) && 
 						(! TCP_REQ_COMPLETE(req)))) {
4a4da127
 				LM_DBG("EOF\n");
0c5da34b
 				resp=CONN_EOF;
6ee62314
 				goto end_req;
 			}
 		}
7498b4dc
 		if (unlikely(req->error!=TCP_REQ_OK)){
8a1f2ede
 			LM_ERR("bad request, state=%d, error=%d buf:\n%.*s\nparsed:\n%.*s\n",
 					req->state, req->error,
 					(int)(req->pos-req->buf), req->buf,
 					(int)(req->parsed-req->start), req->start);
4a4da127
 			LM_DBG("received from: port %d\n", con->rcv.src_port);
 			print_ip("received from: ip", &con->rcv.src_ip, "\n");
0c5da34b
 			resp=CONN_ERROR;
6ee62314
 			goto end_req;
 		}
0051630c
 		if (likely(TCP_REQ_COMPLETE(req))){
f2e456c3
 #ifdef EXTRA_DEBUG
4a4da127
 			LM_DBG("end of header part\n");
 			LM_DBG("received from: port %d\n", con->rcv.src_port);
 			print_ip("received from: ip", &con->rcv.src_ip, "\n");
 			LM_DBG("headers:\n%.*s.\n",
b988daef
 					(int)(req->body-req->start), req->start);
f2e456c3
 #endif
0051630c
 			if (likely(TCP_REQ_HAS_CLEN(req))){
4a4da127
 				LM_DBG("content-length=%d\n", req->content_len);
f2e456c3
 #ifdef EXTRA_DEBUG
4a4da127
 				LM_DBG("body:\n%.*s\n", req->content_len,req->body);
f2e456c3
 #endif
6ee62314
 			}else{
d4cc4103
 				if (cfg_get(tcp, tcp_cfg, accept_no_cl)==0) {
 					req->error=TCP_REQ_BAD_LEN;
8a1f2ede
 					LM_ERR("content length not present or unparsable\n");
d4cc4103
 					resp=CONN_ERROR;
 					goto end_req;
 				}
6ee62314
 			}
 			/* if we are here everything is nice and ok*/
0c5da34b
 			resp=CONN_RELEASE;
f2e456c3
 #ifdef EXTRA_DEBUG
4a4da127
 			LM_DBG("receiving msg(%p, %d)\n",
ab130758
 					req->start, (int)(req->parsed-req->start));
f2e456c3
 #endif
 			/* rcv.bind_address should always be !=0 */
21e0d5c1
 			bind_address=con->rcv.bind_address;
f2e456c3
 			/* just for debugging use sendipv4 as receiving socket  FIXME*/
21e0d5c1
 			/*
7ec958f3
 			if (con->rcv.dst_ip.af==AF_INET6){
 				bind_address=sendipv6_tcp;
 			}else{
 				bind_address=sendipv4_tcp;
 			}
21e0d5c1
 			*/
f2f969dd
 			con->rcv.proto_reserved1=con->id; /* copy the id */
8fc80c33
 			c=*req->parsed; /* ugly hack: zero term the msg & save the
 							   previous char, req->parsed should be ok
 							   because we always alloc BUF_SIZE+1 */
 			*req->parsed=0;
c7337a27
 
 			if (req->state==H_PING_CRLF) {
 				init_dst_from_rcv(&dst, &con->rcv);
 
 				if (tcp_send(&dst, 0, CRLF, CRLF_LEN) < 0) {
8a1f2ede
 					LM_ERR("CRLF ping: tcp_send() failed\n");
c7337a27
 				}
 				ret = 0;
c573aa70
 			} else if (unlikely(req->state==H_STUN_END)) {
96227c65
 				/* stun request */
 				ret = stun_process_msg(req->start, req->parsed-req->start,
 									 &con->rcv);
c573aa70
 			} else
122e01f3
 #ifdef READ_MSRP
 			// if (unlikely(req->flags&F_TCP_REQ_MSRP_FRAME)){
 			if (unlikely(req->state==H_MSRP_FINISH)){
 				/* msrp frame */
 				ret = receive_tcp_msg(req->start, req->parsed-req->start,
 									&con->rcv, con);
 			}else
 #endif
b4fbd9f5
 #ifdef READ_HTTP11
 			if (unlikely(req->state==H_HTTP11_CHUNK_FINISH)){
 				/* http chunked request */
 				req->body[req->content_len] = 0;
6ebd0a6b
 				ret = receive_tcp_msg(req->start,
b4fbd9f5
 						req->body + req->content_len - req->start,
122e01f3
 						&con->rcv, con);
b4fbd9f5
 			}else
96227c65
 #endif
1718093c
 #ifdef READ_WS
8393efff
 			if (unlikely(con->type == PROTO_WS || con->type == PROTO_WSS)){
c04689c5
 				ret = receive_tcp_msg(req->start, req->parsed-req->start,
1718093c
 									&con->rcv, con);
 			}else
 #endif
6ebd0a6b
 				ret = receive_tcp_msg(req->start, req->parsed-req->start,
122e01f3
 									&con->rcv, con);
96227c65
 				
6a8978e5
 			if (unlikely(ret < 0)) {
8fc80c33
 				*req->parsed=c;
0c5da34b
 				resp=CONN_ERROR;
 				goto end_req;
 			}
8fc80c33
 			*req->parsed=c;
6ee62314
 			
 			/* prepare for next request */
c0c6207a
 			size=req->pos-req->parsed;
 			req->start=req->buf;
6ee62314
 			req->body=0;
 			req->error=TCP_REQ_OK;
c0c6207a
 			req->state=H_SKIP_EMPTY;
0051630c
 			req->flags=0;
 			req->content_len=0;
6ee62314
 			req->bytes_to_go=0;
7498b4dc
 			req->pos=req->buf+size;
 			
 			if (unlikely(size)){ 
 				memmove(req->buf, req->parsed, size);
 				req->parsed=req->buf; /* fix req->parsed after using it */
 #ifdef EXTRA_DEBUG
4a4da127
 				LM_DBG("preparing for new request, kept %ld bytes\n", size);
7498b4dc
 #endif
 				/*if we still have some unparsed bytes, try to parse them too*/
 				goto again;
 			} else if (unlikely(con->state==S_CONN_EOF)){
4a4da127
 				LM_DBG("EOF after reading complete request\n");
6ee07a24
 				resp=CONN_EOF;
 			}
7498b4dc
 			req->parsed=req->buf; /* fix req->parsed */
6ee62314
 		}
 		
 		
 	end_req:
6a8978e5
 		if (likely(bytes_read)) *bytes_read=total_bytes;
0c5da34b
 		return resp;
6ee62314
 }
 
 
 
 void release_tcpconn(struct tcp_connection* c, long state, int unix_sock)
 {
 	long response[2];
 	
4a4da127
 		LM_DBG("releasing con %p, state %ld, fd=%d, id=%d\n",
30e8735f
 				c, state, c->fd, c->id);
4a4da127
 		LM_DBG("extra_data %p\n", c->extra_data);
6ee62314
 		/* release req & signal the parent */
5c5cd736
 		c->reader_pid=0; /* reset it */
b4fa727e
 		if (c->fd!=-1){
 			close(c->fd);
 			c->fd=-1;
 		}
6ee62314
 		/* errno==EINTR, EWOULDBLOCK a.s.o todo */
 		response[0]=(long)c;
 		response[1]=state;
746f7674
 		
 		if (tsend_stream(unix_sock, (char*)response, sizeof(response), -1)<=0)
8a1f2ede
 			LM_ERR("tsend_stream failed\n");
6ee62314
 }
 
 
ccb7fda2
 
 static ticks_t tcpconn_read_timeout(ticks_t t, struct timer_ln* tl, void* data)
5b532c7f
 {
ccb7fda2
 	struct tcp_connection *c;
5b532c7f
 	
ccb7fda2
 	c=(struct tcp_connection*)data; 
 	/* or (struct tcp...*)(tl-offset(c->timer)) */
5b532c7f
 	
ccb7fda2
 	if (likely(!(c->state<0) && TICKS_LT(t, c->timeout))){
 		/* timeout extended, exit */
 		return (ticks_t)(c->timeout - t);
5b532c7f
 	}
ccb7fda2
 	/* if conn->state is ERROR or BAD => force timeout too */
316130a7
 	if (unlikely(io_watch_del(&io_w, c->fd, -1, IO_FD_CLOSING)<0)){
8a1f2ede
 		LM_ERR("io_watch_del failed for %p"
b4fa727e
 					" id %d fd %d, state %d, flags %x, main fd %d\n",
 					c, c->id, c->fd, c->state, c->flags, c->s);
316130a7
 	}
ccb7fda2
 	tcpconn_listrm(tcp_conn_lst, c, c_next, c_prev);
 	release_tcpconn(c, (c->state<0)?CONN_ERROR:CONN_RELEASE, tcpmain_sock);
 	
 	return 0;
5b532c7f
 }
3135b4bb
 
 
 
 /* handle io routine, based on the fd_map type
  * (it will be called from io_wait_loop* )
  * params:  fm  - pointer to a fd hash entry
  *          idx - index in the fd_array (or -1 if not known)
  * return: -1 on error, or when we are not interested any more on reads
  *            from this fd (e.g.: we are closing it )
  *          0 on EAGAIN or when by some other way it is known that no more 
  *            io events are queued on the fd (the receive buffer is empty).
  *            Usefull to detect when there are no more io events queued for
  *            sigio_rt, epoll_et, kqueue.
  *         >0 on successfull read from the fd (when there might be more io
  *            queued -- the receive buffer might still be non-empty)
  */
a0553f4e
 inline static int handle_io(struct fd_map* fm, short events, int idx)
3135b4bb
 {	
 	int ret;
 	int n;
7498b4dc
 	int read_flags;
3135b4bb
 	struct tcp_connection* con;
 	int s;
 	long resp;
ccb7fda2
 	ticks_t t;
3135b4bb
 	
9188021a
 	/* update the local config */
 	cfg_update();
 	
3135b4bb
 	switch(fm->type){
 		case F_TCPMAIN:
 again:
 			ret=n=receive_fd(fm->fd, &con, sizeof(con), &s, 0);
4a4da127
 			LM_DBG("received n=%d con=%p, fd=%d\n", n, con, s);
ccb7fda2
 			if (unlikely(n<0)){
3135b4bb
 				if (errno == EWOULDBLOCK || errno == EAGAIN){
 					ret=0;
 					break;
 				}else if (errno == EINTR) goto again;
 				else{
8a1f2ede
 					LM_CRIT("read_fd: %s \n", strerror(errno));
3135b4bb
 						abort(); /* big error*/
 				}
 			}
ccb7fda2
 			if (unlikely(n==0)){
8a1f2ede
 				LM_ERR("0 bytes read\n");
301fa314
 				goto error;
3135b4bb
 			}
ccb7fda2
 			if (unlikely(con==0)){
8a1f2ede
 					LM_CRIT("null pointer\n");
301fa314
 					goto error;
3135b4bb
 			}
 			con->fd=s;
ccb7fda2
 			if (unlikely(s==-1)) {
8a1f2ede
 				LM_ERR("read_fd: no fd read\n");
3135b4bb
 				goto con_error;
 			}
5c5cd736
 			con->reader_pid=my_pid();
ccb7fda2
 			if (unlikely(con==tcp_conn_lst)){
8a1f2ede
 				LM_CRIT("duplicate connection received: %p, id %d, fd %d, refcnt %d"
3135b4bb
 							" state %d (n=%d)\n", con, con->id, con->fd,
be7401cc
 							atomic_get(&con->refcnt), con->state, n);
316130a7
 				goto con_error;
3135b4bb
 				break; /* try to recover */
 			}
316130a7
 			if (unlikely(con->state==S_CONN_BAD)){
8a1f2ede
 				LM_WARN("received an already bad connection: %p id %d refcnt %d\n",
316130a7
 							con, con->id, atomic_get(&con->refcnt));
 				goto con_error;
 			}
6a8978e5
 			/* if we received the fd there is most likely data waiting to
 			 * be read => process it first to avoid extra sys calls */
7f1b8eb8
 			read_flags=((con->flags & (F_CONN_EOF_SEEN|F_CONN_FORCE_EOF)) &&
7498b4dc
 						!(con->flags & F_CONN_OOB_DATA))? RD_CONN_FORCE_EOF
 						:0;
21b8cf90
 #ifdef USE_TLS
 repeat_1st_read:
 #endif /* USE_TLS */
7498b4dc
 			resp=tcp_read_req(con, &n, &read_flags);
6a8978e5
 			if (unlikely(resp<0)){
 				/* some error occured, but on the new fd, not on the tcp
 				 * main fd, so keep the ret value */
 				if (unlikely(resp!=CONN_EOF))
 					con->state=S_CONN_BAD;
 				release_tcpconn(con, resp, tcpmain_sock);
 				break;
 			}
ce51fbb8
 #ifdef USE_TLS
 			/* repeat read if requested (for now only tls might do this) */
 			if (unlikely(read_flags & RD_CONN_REPEAT_READ))
 				goto repeat_1st_read;
 #endif /* USE_TLS */
6a8978e5
 			
3135b4bb
 			/* must be before io_watch_add, io_watch_add might catch some
 			 * already existing events => might call handle_io and
 			 * handle_io might decide to del. the new connection =>
 			 * must be in the list */
 			tcpconn_listadd(tcp_conn_lst, con, c_next, c_prev);
ccb7fda2
 			t=get_ticks_raw();
 			con->timeout=t+S_TO_TICKS(TCP_CHILD_TIMEOUT);
 			/* re-activate the timer */
 			con->timer.f=tcpconn_read_timeout;
8b0472d7
 			local_timer_reinit(&con->timer);
ccb7fda2
 			local_timer_add(&tcp_reader_ltimer, &con->timer,
 								S_TO_TICKS(TCP_CHILD_TIMEOUT), t);
b4fa727e
 			if (unlikely(io_watch_add(&io_w, s, POLLIN, F_TCPCONN, con)<0)){
8a1f2ede
 				LM_CRIT("io_watch_add failed for %p id %d fd %d, state %d, flags %x,"
b4fa727e
 							" main fd %d, refcnt %d\n",
 							con, con->id, con->fd, con->state, con->flags,
 							con->s, atomic_get(&con->refcnt));
3135b4bb
 				tcpconn_listrm(tcp_conn_lst, con, c_next, c_prev);
ccb7fda2
 				local_timer_del(&tcp_reader_ltimer, &con->timer);
3135b4bb
 				goto con_error;
 			}
 			break;
 		case F_TCPCONN:
 			con=(struct tcp_connection*)fm->data;
316130a7
 			if (unlikely(con->state==S_CONN_BAD)){
 				resp=CONN_ERROR;
8cf5dde5
 				if (!(con->send_flags.f & SND_F_CON_CLOSE))
8a1f2ede
 					LM_WARN("F_TCPCONN connection marked as bad: %p id %d refcnt %d\n",
316130a7
 							con, con->id, atomic_get(&con->refcnt));
 				goto read_error;
 			}
28e31325
 			read_flags=((
7498b4dc
 #ifdef POLLRDHUP
28e31325
 						(events & POLLRDHUP) |
 #endif /* POLLRDHUP */
 						(events & (POLLHUP|POLLERR)) |
7498b4dc
 							(con->flags & (F_CONN_EOF_SEEN|F_CONN_FORCE_EOF)))
 						&& !(events & POLLPRI))? RD_CONN_FORCE_EOF: 0;
21b8cf90
 #ifdef USE_TLS
 repeat_read:
 #endif /* USE_TLS */
7498b4dc
 			resp=tcp_read_req(con, &ret, &read_flags);
ccb7fda2
 			if (unlikely(resp<0)){
316130a7
 read_error:
3135b4bb
 				ret=-1; /* some error occured */
316130a7
 				if (unlikely(io_watch_del(&io_w, con->fd, idx,
 											IO_FD_CLOSING) < 0)){
8a1f2ede
 					LM_CRIT("io_watch_del failed for %p id %d fd %d,"
b4fa727e
 							" state %d, flags %x, main fd %d, refcnt %d\n",
 							con, con->id, con->fd, con->state,
 							con->flags, con->s, atomic_get(&con->refcnt));
316130a7
 				}
3135b4bb
 				tcpconn_listrm(tcp_conn_lst, con, c_next, c_prev);
ccb7fda2
 				local_timer_del(&tcp_reader_ltimer, &con->timer);
b4fa727e
 				if (unlikely(resp!=CONN_EOF))
 					con->state=S_CONN_BAD;
3135b4bb
 				release_tcpconn(con, resp, tcpmain_sock);
 			}else{
ce51fbb8
 #ifdef USE_TLS
 				if (unlikely(read_flags & RD_CONN_REPEAT_READ))
 						goto repeat_read;
 #endif /* USE_TLS */
3135b4bb
 				/* update timeout */
49d12f5f
 				con->timeout=get_ticks_raw()+S_TO_TICKS(TCP_CHILD_TIMEOUT);
7498b4dc
 				/* ret= 0 (read the whole socket buffer) if short read & 
 				 *  !POLLPRI,  bytes read otherwise */
ce51fbb8
 				ret&=(((read_flags & RD_CONN_SHORT_READ) &&
7498b4dc
 						!(events & POLLPRI)) - 1);
3135b4bb
 			}
 			break;
 		case F_NONE:
8a1f2ede
 			LM_CRIT("empty fd map %p (%d): {%d, %d, %p}\n",
 						fm, (int)(fm-io_w.fd_hash),
3135b4bb
 						fm->fd, fm->type, fm->data);
 			goto error;
 		default:
8a1f2ede
 			LM_CRIT("uknown fd type %d\n", fm->type); 
3135b4bb
 			goto error;
 	}
 	
 	return ret;
 con_error:
 	con->state=S_CONN_BAD;
316130a7
 	release_tcpconn(con, CONN_ERROR, tcpmain_sock);
3135b4bb
 	return ret;
 error:
 	return -1;
 }
5b532c7f
 
 
3135b4bb
 
b264d2c6
 inline static void tcp_reader_timer_run(void)
5b532c7f
 {
49d12f5f
 	ticks_t ticks;
3135b4bb
 	
49d12f5f
 	ticks=get_ticks_raw();
057063e6
 	if (unlikely((ticks-tcp_reader_prev_ticks)<TCPCONN_TIMEOUT_MIN_RUN))
 		return;
 	tcp_reader_prev_ticks=ticks;
ccb7fda2
 	local_timer_run(&tcp_reader_ltimer, ticks);
5b532c7f
 }
 
 
3135b4bb
 
 void tcp_receive_loop(int unix_sock)
 {
 	
 	/* init */
 	tcpmain_sock=unix_sock; /* init com. socket */
3e999281
 	if (init_io_wait(&io_w, get_max_open_fds(), tcp_poll_method)<0)
3135b4bb
 		goto error;
057063e6
 	tcp_reader_prev_ticks=get_ticks_raw();
ccb7fda2
 	if (init_local_timer(&tcp_reader_ltimer, get_ticks_raw())!=0)
 		goto error;
3135b4bb
 	/* add the unix socket */
a0553f4e
 	if (io_watch_add(&io_w, tcpmain_sock, POLLIN,  F_TCPMAIN, 0)<0){
8a1f2ede
 		LM_CRIT("failed to add socket to the fd list\n");
3135b4bb
 		goto error;
 	}
9188021a
 
 	/* initialize the config framework */
 	if (cfg_child_init()) goto error;
 
3135b4bb
 	/* main loop */
 	switch(io_w.poll_method){
 		case POLL_POLL:
 				while(1){
 					io_wait_loop_poll(&io_w, TCP_CHILD_SELECT_TIMEOUT, 0);
ccb7fda2
 					tcp_reader_timer_run();
3135b4bb
 				}
 				break;
 #ifdef HAVE_SELECT
 		case POLL_SELECT:
 			while(1){
 				io_wait_loop_select(&io_w, TCP_CHILD_SELECT_TIMEOUT, 0);
ccb7fda2
 				tcp_reader_timer_run();
3135b4bb
 			}
 			break;
 #endif
 #ifdef HAVE_SIGIO_RT
 		case POLL_SIGIO_RT:
 			while(1){
 				io_wait_loop_sigio_rt(&io_w, TCP_CHILD_SELECT_TIMEOUT);
ccb7fda2
 				tcp_reader_timer_run();
3135b4bb
 			}
 			break;
 #endif
 #ifdef HAVE_EPOLL
 		case POLL_EPOLL_LT:
 			while(1){
 				io_wait_loop_epoll(&io_w, TCP_CHILD_SELECT_TIMEOUT, 0);
ccb7fda2
 				tcp_reader_timer_run();
3135b4bb
 			}
 			break;
 		case POLL_EPOLL_ET:
 			while(1){
 				io_wait_loop_epoll(&io_w, TCP_CHILD_SELECT_TIMEOUT, 1);
ccb7fda2
 				tcp_reader_timer_run();
3135b4bb
 			}
 			break;
5b532c7f
 #endif
3135b4bb
 #ifdef HAVE_KQUEUE
 		case POLL_KQUEUE:
 			while(1){
 				io_wait_loop_kqueue(&io_w, TCP_CHILD_SELECT_TIMEOUT, 0);
ccb7fda2
 				tcp_reader_timer_run();
3135b4bb
 			}
 			break;
 #endif
 #ifdef HAVE_DEVPOLL
 		case POLL_DEVPOLL:
 			while(1){
 				io_wait_loop_devpoll(&io_w, TCP_CHILD_SELECT_TIMEOUT, 0);
ccb7fda2
 				tcp_reader_timer_run();
3135b4bb
 			}
 			break;
 #endif
 		default:
8a1f2ede
 			LM_CRIT("no support for poll method %s (%d)\n", 
3135b4bb
 					poll_method_name(io_w.poll_method), io_w.poll_method);
 			goto error;
 	}
 error:
 	destroy_io_wait(&io_w);
8a1f2ede
 	LM_CRIT("exiting...");
3135b4bb
 	exit(-1);
 }
 
ccb7fda2
 
96227c65
 int is_msg_complete(struct tcp_req* r)
 {
0051630c
 	if (TCP_REQ_HAS_CLEN(r)) {
96227c65
 		r->state = H_STUN_FP;
 		return 0;
 	}
 	else {
 		/* STUN message is complete */
 		r->state = H_STUN_END;
0051630c
 		r->flags |= F_TCP_REQ_COMPLETE |
 					F_TCP_REQ_HAS_CLEN; /* hack to avoid error check */
96227c65
 		return 1;
 	}
 }
 
3135b4bb
 #endif /* USE_TCP */