瀏覽代碼

- tcp send/connext timeout (read NEWS for the new cfg. parameters)
- tcp switched to non-blocking fd (untested)

Andrei Pelinescu-Onciul 22 年之前
父節點
當前提交
bc9778378c
共有 6 個文件被更改,包括 325 次插入196 次删除
  1. 81 27
      NEWS
  2. 13 0
      cfg.lex
  3. 37 0
      cfg.y
  4. 2 0
      globals.h
  5. 4 3
      tcp_conn.h
  6. 188 166
      tcp_main.c

+ 81 - 27
NEWS

@@ -3,16 +3,12 @@ Release notes for SIP Express Router (ser)
 
 $Id$
 
-0.8.12 changes
+0.8.13 changes
 
 new modules:
  - answer server options requests [options]
-texops:
- - subst('s/re/repl/flags') support
 core:
- - added switch to check the config file (-c)
  - changes: 
-       removed len_gt() and replaced with if (msg:len op number|max_len)
        protocol and port can be specified in the alias and listen lines, e.g.:
         alias= tcp:foo.bar:* udp:test.bar:5080 foo.com
         listen= eth0   tcp:eth0:5065 udp:127.0.0.1 [3ffe::1]
@@ -20,20 +16,11 @@ core:
                               ==, !=, ~= for strings
                               ==, !=, >, <, >=, <= for integers
  - new config variables:
-     advertised_address= ip | string
-       address advertised in via and in the DST_* lumps (e.g RR)
-       This is the default value, if empty (default) the socket
-       address will be used.
-       WARNING: - don't set it unless you know what you are doing
-                 (e.g. nat traversal)
-               - you can set anything here, no check is made
-                (e.g. foo.bar will be accepted even if 
-                 foo.bar doesn't exist)
-    advertised_port= no
-       port advertised in via and in the DST_*lumps (e.g. RR)
-       This is the default value, if empty (default) the socket
-       port will be used.
-       Same warnings as above.
+   tcp_connect_timeout= seconds
+       time before an ongoing connect will be aborted
+   tcp_send_timeout= seconds
+       time after a tcp connection will be closed if it is not available 
+       for writing in this interval (and ser wants to sen something on it)
    tcp_accept_aliases= yes|no
        if a message received over a tcp connection has "alias" in its via
        a new tcp alias port will be created for the connection the message
@@ -43,13 +30,6 @@ core:
         lookups and the need for them is questionable)
        See force_tcp_alias for more details.
  - new script commands:
-    set_advertised_address(ip|string)
-       same as advertised_address but it affects only the current message:
-       Message host/lump address= the set_advertised one if
-       present, else advertised_address else socket address.
-    set_advertised_port(no)
-       same as advertised_port but it affects only the current
-       message; see set_advertised_address & s/address/port/g
    force_tcp_alias()
    force_tcp_alias(port)
        adds a tcp port alias for the current connection (if tcp).
@@ -69,6 +49,80 @@ core:
 
 
 
+***********************************************
+* Changes/fixes introduced in 0.8.12
+***********************************************
++--------------------------------------------------------+
+| WARNING: if you want to use a 0.8.11 config script     |
+| with 0.8.12, replace if ( len_gt(number) ) with:       |
+|                      if ( msg:len > bumber )           |
++--------------------------------------------------------+
+
+New Features
+============
+
+texops:
+ - subst('s/re/repl/flags') support
+core:
+ - added switch to check the config file (-c)
+ - changes: removed len_gt() and replaced with if (msg:len op number|max_len)
+ - multiple operator support: ==, != for special operations (e.g myself, ip)
+                              ==, !=, ~= for strings
+                              ==, !=, >, <, >=, <= for integers
+ - new config variables:
+     advertised_address= ip | string
+       address advertised in via and in the DST_* lumps (e.g RR)
+       This is the default value, if empty (default) the socket
+       address will be used.
+       WARNING: - don't set it unless you know what you are doing
+                 (e.g. nat traversal)
+               - you can set anything here, no check is made
+                (e.g. foo.bar will be accepted even if 
+                 foo.bar doesn't exist)
+    advertised_port= no
+       port advertised in via and in the DST_*lumps (e.g. RR)
+       This is the default value, if empty (default) the socket
+       port will be used.
+       Same warnings as above.
+ - new script commands:
+    set_advertised_address(ip|string)
+       same as advertised_address but it affects only the current message:
+       Message host/lump address= the set_advertised one if
+       present, else advertised_address else socket address.
+    set_advertised_port(no)
+       same as advertised_port but it affects only the current
+       message; see set_advertised_address & s/address/port/g
+
+usrloc:
+ - usernames are case insensitive
+ 
+registrar:
+ - lookup function succeeds when appending of a branch failed
+
+auth_db:
+ - support for rpid stored in database (thanks to Jakob Schlyter)
+
+Bug fixes
+=========
+- memory leak in digest credentials parser fixed
+- authenticathion ha1 didn't include domain if username was of the form
+  user@domain and calculate_ha1 was set to yes (modules/auth_db)
+- tm reply processing race condition (modules/tm), special thanks go to
+ Dong Liu
+- Many bugs in pa module fixed, works with registrar again.
+ 
+Security updates
+================
+ 
+- fifo processing code will write responses only to other
+ fifos and only if they are not hard-linked, also default
+ ser fifo persmissions were changed to 0600.
+                                                                                
+Performance improvements
+========================
+- tuned internal malloc implementation parameters to better reflect the
+actual workload (malloc is a little bit faster now)
+
 
 
 ***********************************************
@@ -92,7 +146,7 @@ New features
 	- ENUM support [enum]
 	- presence agent [pa]
 	- dynamic domain management -- allows to manipulate 
-  	  hosting of multiple domains in run-time [module]
+	  hosting of multiple domains in run-time [module]
 	- flat-text-file database support [dbtext]
 	- rich access control lists [permissions]
 - Feature Improvements

+ 13 - 0
cfg.lex

@@ -43,6 +43,7 @@
  *  2003-10-10  replaced len_gt w/ msg:len (andrei)
  *  2003-10-13  added fifo_dir (andrei)
  *  2003-10-28  added tcp_accept_aliases (andrei)
+ *  2003-11-29  added {tcp_send, tcp_connect, tls_*}_timeout (andrei)
  */
 
 
@@ -179,6 +180,8 @@ MHOMED		mhomed
 DISABLE_TCP		"disable_tcp"
 TCP_CHILDREN	"tcp_children"
 TCP_ACCEPT_ALIASES	"tcp_accept_aliases"
+TCP_SEND_TIMEOUT	"tcp_send_timeout"
+TCP_CONNECT_TIMEOUT	"tcp_connect_timeout"
 DISABLE_TLS		"disable_tls"
 TLSLOG			"tlslog"|"tls_log"
 TLS_PORT_NO		"tls_port_no"
@@ -188,6 +191,8 @@ TLS_REQUIRE_CERTIFICATE "tls_require_certificate"
 TLS_CERTIFICATE	"tls_certificate"
 TLS_PRIVATE_KEY "tls_private_key"
 TLS_CA_LIST		"tls_ca_list"
+TLS_HANDSHAKE_TIMEOUT	"tls_handshake_timeout"
+TLS_SEND_TIMEOUT	"tls_send_timeout"
 ADVERTISED_ADDRESS	"advertised_address"
 ADVERTISED_PORT		"advertised_port"
 
@@ -328,6 +333,10 @@ EAT_ABLE	[\ \t\b\r]
 <INITIAL>{TCP_CHILDREN}	{ count(); yylval.strval=yytext; return TCP_CHILDREN; }
 <INITIAL>{TCP_ACCEPT_ALIASES}	{ count(); yylval.strval=yytext;
 									return TCP_ACCEPT_ALIASES; }
+<INITIAL>{TCP_SEND_TIMEOUT}		{ count(); yylval.strval=yytext;
+									return TCP_SEND_TIMEOUT; }
+<INITIAL>{TCP_CONNECT_TIMEOUT}		{ count(); yylval.strval=yytext;
+									return TCP_CONNECT_TIMEOUT; }
 <INITIAL>{DISABLE_TLS}	{ count(); yylval.strval=yytext; return DISABLE_TLS; }
 <INITIAL>{TLSLOG}		{ count(); yylval.strval=yytext; return TLS_PORT_NO; }
 <INITIAL>{TLS_PORT_NO}	{ count(); yylval.strval=yytext; return TLS_PORT_NO; }
@@ -341,6 +350,10 @@ EAT_ABLE	[\ \t\b\r]
 										return TLS_PRIVATE_KEY; }
 <INITIAL>{TLS_CA_LIST}	{ count(); yylval.strval=yytext; 
 										return TLS_CA_LIST; }
+<INITIAL>{TLS_HANDSHAKE_TIMEOUT}	{ count(); yylval.strval=yytext;
+										return TLS_HANDSHAKE_TIMEOUT; }
+<INITIAL>{TLS_SEND_TIMEOUT}	{ count(); yylval.strval=yytext;
+										return TLS_SEND_TIMEOUT; }
 <INITIAL>{FIFO}	{ count(); yylval.strval=yytext; return FIFO; }
 <INITIAL>{FIFO_DIR}	{ count(); yylval.strval=yytext; return FIFO_DIR; }
 <INITIAL>{FIFO_DB_URL}	{ count(); yylval.strval=yytext; return FIFO_DB_URL; }

+ 37 - 0
cfg.y

@@ -49,6 +49,7 @@
  * 2003-10-13  added FIFO_DIR & proto:host:port listen/alias support (andrei)
  * 2003-10-24  converted to the new socket_info lists (andrei)
  * 2003-10-28  added tcp_accept_aliases (andrei)
+ * 2003-11-20  added {tcp_connect, tcp_send, tls_*}_timeout (andrei)
  */
 
 
@@ -206,10 +207,14 @@ static struct id_list* mk_listen_id(char*, int, int);
 %token DISABLE_TCP
 %token TCP_ACCEPT_ALIASES
 %token TCP_CHILDREN
+%token TCP_CONNECT_TIMEOUT
+%token TCP_SEND_TIMEOUT
 %token DISABLE_TLS
 %token TLSLOG
 %token TLS_PORT_NO
 %token TLS_METHOD
+%token TLS_HANDSHAKE_TIMEOUT
+%token TLS_SEND_TIMEOUT
 %token SSLv23
 %token SSLv2
 %token SSLv3
@@ -428,6 +433,22 @@ assign_stm:	DEBUG EQUAL NUMBER { debug=$3; }
 									#endif
 									}
 		| TCP_CHILDREN EQUAL error { yyerror("number expected"); }
+		| TCP_CONNECT_TIMEOUT EQUAL NUMBER {
+									#ifdef USE_TCP
+										tcp_connect_timeout=$3;
+									#else
+										warn("tcp support not compiled in");
+									#endif
+									}
+		| TCP_CONNECT_TIMEOUT EQUAL error { yyerror("number expected"); }
+		| TCP_SEND_TIMEOUT EQUAL NUMBER {
+									#ifdef USE_TCP
+										tcp_send_timeout=$3;
+									#else
+										warn("tcp support not compiled in");
+									#endif
+									}
+		| TCP_SEND_TIMEOUT EQUAL error { yyerror("number expected"); }
 		| DISABLE_TLS EQUAL NUMBER {
 									#ifdef USE_TLS
 										tls_disable=$3;
@@ -530,6 +551,22 @@ assign_stm:	DEBUG EQUAL NUMBER { debug=$3; }
 									#endif
 									}
 		| TLS_CA_LIST EQUAL error { yyerror("string value expected"); }
+		| TLS_HANDSHAKE_TIMEOUT EQUAL NUMBER {
+									#ifdef USE_TLS
+										tls_handshake_timeout=$3;
+									#else
+										warn("tls support not compiled in");
+									#endif
+									}
+		| TLS_HANDSHAKE_TIMEOUT EQUAL error { yyerror("number expected"); }
+		| TLS_SEND_TIMEOUT EQUAL NUMBER {
+									#ifdef USE_TLS
+										tls_send_timeout=$3;
+									#else
+										warn("tls support not compiled in");
+									#endif
+									}
+		| TLS_SEND_TIMEOUT EQUAL error { yyerror("number expected"); }
 		| SERVER_SIGNATURE EQUAL NUMBER { server_signature=$3; }
 		| SERVER_SIGNATURE EQUAL error { yyerror("boolean value expected"); }
 		| REPLY_TO_VIA EQUAL NUMBER { reply_to_via=$3; }

+ 2 - 0
globals.h

@@ -71,6 +71,8 @@ extern int children_no;
 extern int tcp_children_no;
 extern int tcp_disable;
 extern int tcp_accept_aliases;
+extern int tcp_connect_timeout;
+extern int tcp_send_timeout;
 #endif
 #ifdef USE_TLS
 extern int tls_disable;

+ 4 - 3
tcp_conn.h

@@ -46,9 +46,10 @@
 #define TCP_BUF_SIZE 65535
 #define TCP_CON_TIMEOUT 120 /* in  seconds */
 #define TCP_CON_SEND_TIMEOUT 120 /* timeout after a send */
-#define TCP_SEND_TIMEOUT 10 /* if a send doesn't complete in 10s, timeout */
-#define TCP_CONNECT_TIMEOUT 10 /* if a connect doesn't complete in this time,
-                                  timeout */
+#define DEFAULT_TCP_SEND_TIMEOUT 10 /* if a send can't write for more then 10s,
+									   timeout */
+#define DEFAULT_TCP_CONNECT_TIMEOUT 10 /* if a connect doesn't complete in this
+										  time, timeout */
 #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*/

+ 188 - 166
tcp_main.c

@@ -76,6 +76,7 @@
 #include <netdb.h>
 
 #include <unistd.h>
+#include <fcntl.h>
 
 #include <errno.h>
 #include <string.h>
@@ -116,6 +117,8 @@ struct tcp_child{
 
 
 int tcp_accept_aliases=0; /* by default don't accept aliases */
+int tcp_connect_timeout=DEFAULT_TCP_CONNECT_TIMEOUT;
+int tcp_send_timeout=DEFAULT_TCP_SEND_TIMEOUT;
 
 /* connection hash table (after ip&port) , includes also aliases */
 struct tcp_conn_alias** tcpconn_aliases_hash=0;
@@ -132,6 +135,179 @@ int unix_tcp_sock;
 int tcp_proto_no=-1; /* tcp protocol number as returned by getprotobyname */
 
 
+
+/* set all socket/fd options:  disable nagle, tos lowdelay, non-blocking
+ * return -1 on error */
+static int init_sock_opt(int s)
+{
+	int flags;
+	int optval;
+	
+#ifdef DISABLE_NAGLE
+	flags=1;
+	if ( (tcp_proto_no!=-1) && (setsockopt(s, tcp_proto_no , TCP_NODELAY,
+					&flags, sizeof(flags))<0) ){
+		LOG(L_WARN, "WARNING: init_sock_opt: could not disable Nagle: %s\n",
+				strerror(errno));
+	}
+#endif
+	/* tos*/
+	optval=IPTOS_LOWDELAY;
+	if (setsockopt(s, IPPROTO_IP, IP_TOS, (void*)&optval,sizeof(optval)) ==-1){
+		LOG(L_WARN, "WARNING: init_sock_opt: setsockopt tos: %s\n",
+				strerror(errno));
+		/* continue since this is not critical */
+	}
+	/* non-blocking */
+	flags=fcntl(s, F_GETFL);
+	if (flags==-1){
+		LOG(L_ERR, "ERROR: init_sock_opt: fnctl failed: (%d) %s\n",
+				errno, strerror(errno));
+		goto error;
+	}
+	if (fcntl(s, F_SETFL, flags|O_NONBLOCK)==-1){
+		LOG(L_ERR, "ERROR: init_sock_opt: fcntl: set non-blocking failed:"
+				" (%d) %s\n", errno, strerror(errno));
+		goto error;
+	}
+	return 0;
+error:
+	return -1;
+}
+
+
+
+static int tcp_blocking_connect(int fd, const struct sockaddr *servaddr,
+								socklen_t addrlen)
+{
+	int n;
+	fd_set sel_set;
+	struct timeval timeout;
+	int ticks;
+	int err;
+	int err_len;
+	
+again:
+	n=connect(fd, servaddr, addrlen);
+	if (n==-1){
+		if (errno==EINTR) goto again;
+		if (errno!=EINPROGRESS && errno!=EALREADY){
+			LOG(L_ERR, "ERROR: tcp_blocking_connect: (%d) %s\n",
+					errno, strerror(errno));
+			goto error;
+		}
+	}else goto end;
+	
+	while(1){
+		FD_ZERO(&sel_set);
+		FD_SET(fd, &sel_set);
+		timeout.tv_sec=tcp_connect_timeout;
+		timeout.tv_usec=0;
+		ticks=get_ticks();
+		n=select(fd+1, 0, &sel_set, 0, &timeout);
+		if (n<0){
+			if (errno==EINTR) continue;
+			LOG(L_ERR, "ERROR: tcp_blocking_connect: select failed: (%d) %s\n",
+					errno, strerror(errno));
+			goto error;
+		}else if (n==0){
+			/* timeout */
+			if (get_ticks()-ticks>=tcp_connect_timeout){
+				LOG(L_ERR, "ERROR: tcp_blocking_connect: timeout (%d)\n",
+						tcp_connect_timeout);
+				goto error;
+			}
+			continue;
+		}
+		if (FD_ISSET(fd, &sel_set)){
+			err_len=sizeof(err);
+			getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &err_len);
+			if (err==0) goto end;
+			if (err!=EINPROGRESS && err!=EALREADY){
+				LOG(L_ERR, "ERROR: tcp_blocking_connect: SO_ERROR (%d) %s\n",
+						err, strerror(err));
+				goto error;
+			}
+		}
+	}
+error:
+	return -1;
+end:
+	return 0;
+}
+
+
+
+/* blocking write even on non-blocking sockets 
+ * if TCP_TIMEOUT will return with error */
+static int tcp_blocking_write(struct tcp_connection* c, int fd, char* buf,
+								unsigned int len)
+{
+	int n;
+	fd_set sel_set;
+	struct timeval timeout;
+	int ticks;
+	int initial_len;
+	
+	initial_len=len;
+again:
+	
+	n=send(fd, buf, len,
+#ifdef HAVE_MSG_NOSIGNAL
+			MSG_NOSIGNAL
+#else
+			0
+#endif
+		);
+	if (n<0){
+		if (errno==EINTR)	goto again;
+		else if (errno!=EAGAIN && errno!=EWOULDBLOCK){
+			LOG(L_ERR, "tcp_blocking_write: failed to send: (%d) %s\n",
+					errno, strerror(errno));
+			goto error;
+		}
+	}else if (n<len){
+		/* partial write */
+		buf+=n;
+		len-=n;
+	}else{
+		/* success: full write */
+		goto end;
+	}
+	while(1){
+		FD_ZERO(&sel_set);
+		FD_SET(fd, &sel_set);
+		timeout.tv_sec=tcp_send_timeout;
+		timeout.tv_usec=0;
+		ticks=get_ticks();
+		n=select(fd+1, 0, &sel_set, 0, &timeout);
+		if (n<0){
+			if (errno==EINTR) continue; /* signal, ignore */
+			LOG(L_ERR, "ERROR: tcp_blocking_write: select failed: "
+					" (%d) %s\n", errno, strerror(errno));
+			goto error;
+		}else if (n==0){
+			/* timeout */
+			if (get_ticks()-ticks>=tcp_send_timeout){
+				LOG(L_ERR, "ERROR: tcp_blocking_write: send timeout (%d)\n",
+						tcp_send_timeout);
+				goto error;
+			}
+			continue;
+		}
+		if (FD_ISSET(fd, &sel_set)){
+			/* we can write again */
+			goto again;
+		}
+	}
+error:
+		return -1;
+end:
+		return initial_len;
+}
+
+
+
 struct tcp_connection* tcpconn_new(int sock, union sockaddr_union* su,
 									struct socket_info* ba, int type, 
 									int state)
@@ -213,11 +389,7 @@ struct tcp_connection* tcpconn_connect(union sockaddr_union* server, int type)
 	struct socket_info* si;
 	union sockaddr_union my_name;
 	socklen_t my_name_len;
-	int optval;
 	struct tcp_connection* con;
-#ifdef DISABLE_NAGLE
-	int flag;
-#endif
 
 	s=socket(AF2PF(server->s.sa_family), SOCK_STREAM, 0);
 	if (s==-1){
@@ -225,25 +397,12 @@ struct tcp_connection* tcpconn_connect(union sockaddr_union* server, int type)
 				errno, strerror(errno));
 		goto error;
 	}
-#ifdef DISABLE_NAGLE
-	flag=1;
-	if ( (tcp_proto_no!=-1) && (setsockopt(s, tcp_proto_no , TCP_NODELAY,
-					&flag, sizeof(flag))<0) ){
-		LOG(L_ERR, "ERROR: tcp_connect: could not disable Nagle: %s\n",
-				strerror(errno));
-	}
-#endif
-	/* tos*/
-	optval=IPTOS_LOWDELAY;
-	if (setsockopt(s, IPPROTO_IP, IP_TOS, (void*)&optval, sizeof(optval)) ==-1){
-		LOG(L_WARN, "WARNING: tcpconn_connect: setsockopt tos: %s\n",
-				strerror(errno));
-		/* continue since this is not critical */
+	if (init_sock_opt(s)<0){
+		LOG(L_ERR, "ERROR: tcpconn_connect: init_sock_opt failed\n");
+		goto error;
 	}
-
-	if (connect(s, &server->s, sockaddru_len(*server))<0){
-		LOG(L_ERR, "ERROR: tcpconn_connect: connect: (%d) %s\n",
-				errno, strerror(errno));
+	if (tcp_blocking_connect(s, &server->s, sockaddru_len(*server))<0){
+		LOG(L_ERR, "ERROR: tcpconn_connect: tcp_blocking_connect failed\n");
 		goto error;
 	}
 	my_name_len=sizeof(my_name);
@@ -483,139 +642,6 @@ void tcpconn_put(struct tcp_connection* c)
 }
 
 
-static int tcp_blocking_connect(int fd, const struct sockaddr *servaddr,
-								socklen_t addrlen)
-{
-	int n;
-	fd_set sel_set;
-	struct timeval timeout;
-	int ticks;
-	int err;
-	int err_len;
-	
-again:
-	n=connect(fd, servaddr, addrlen);
-	if (n==-1){
-		if (errno==EINTR) goto again;
-		if (errno!=EINPROGRESS && errno!=EALREADY){
-			LOG(L_ERR, "ERROR: tcp_blocking_connect: (%d) %s\n",
-					errno, strerror(errno));
-			goto error;
-		}
-	}else goto end;
-	
-	while(1){
-		FD_ZERO(&sel_set);
-		FD_SET(fd, &sel_set);
-		timeout.tv_sec=TCP_CONNECT_TIMEOUT;
-		timeout.tv_usec=0;
-		ticks=get_ticks();
-		n=select(fd+1, 0, &sel_set, 0, &timeout);
-		if (n<0){
-			if (errno==EINTR) continue;
-			LOG(L_ERR, "ERROR: tcp_blocking_connect: select failed: (%d) %s\n",
-					errno, strerror(errno));
-			goto error;
-		}else if (n==0){
-			/* timeout */
-			if (get_ticks()-ticks>=TCP_CONNECT_TIMEOUT){
-				LOG(L_ERR, "ERROR: tcp_blocking_connect: send timeout\n");
-				goto error;
-			}
-			continue;
-		}
-		if (FD_ISSET(fd, &sel_set)){
-			err_len=sizeof(err);
-			getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &err_len);
-			if (err==0) goto end;
-			if (err!=EINPROGRESS && err!=EALREADY){
-				LOG(L_ERR, "ERROR: tcp_blocking_connect: SO_ERROR (%d) %s\n",
-						err, strerror(err));
-				goto error;
-			}
-		}
-	}
-error:
-	return -1;
-end:
-	return 0;
-}
-
-
-
-/* blocking write even on non-blocking sockets 
- * if TCP_TIMEOUT will return with error */
-static int tcp_blocking_write(struct tcp_connection* c, int fd, char* buf,
-								unsigned int len)
-{
-	int n;
-	fd_set sel_set;
-	struct timeval timeout;
-	int ticks;
-	int initial_len;
-	
-	initial_len=len;
-again:
-	/* try first without select */
-	if (c->state==S_CONN_CONNECT){
-		/* connect not finished,  try again ? */
-		LOG(L_CRIT, "BUG: tcp_blocking_write: connect not implemented yet\n");
-		goto error;
-	}
-	n=send(fd, buf, len,
-#ifdef HAVE_MSG_NOSIGNAL
-			MSG_NOSIGNAL
-#else
-			0
-#endif
-		);
-	if (n<0){
-		if (errno==EINTR)	goto again;
-		else if (errno!=EAGAIN && errno!=EWOULDBLOCK){
-			LOG(L_ERR, "tcp_blocking_write: failed to send: (%d) %s\n",
-					errno, strerror(errno));
-			goto error;
-		}
-	}else if (n<len){
-		/* partial write */
-		buf+=n;
-		len-=n;
-	}else{
-		/* success: full write */
-		goto end;
-	}
-	while(1){
-		FD_ZERO(&sel_set);
-		FD_SET(fd, &sel_set);
-		timeout.tv_sec=TCP_SEND_TIMEOUT;
-		timeout.tv_usec=0;
-		ticks=get_ticks();
-		n=select(fd+1, 0, &sel_set, 0, &timeout);
-		if (n<0){
-			if (errno==EINTR) continue; /* signal, ignore */
-			LOG(L_ERR, "ERROR: tcp_blocking_write: select failed: "
-					" (%d) %s\n", errno, strerror(errno));
-			goto error;
-		}else if (n==0){
-			/* timeout */
-			if (get_ticks()-ticks>=TCP_SEND_TIMEOUT){
-				LOG(L_ERR, "ERROR: tcp_blocking_write: send timeout\n");
-				goto error;
-			}
-			continue;
-		}
-		if (FD_ISSET(fd, &sel_set)){
-			/* we can write again */
-			goto again;
-		}
-	}
-error:
-		return -1;
-end:
-		return initial_len;
-}
-
-
 
 /* finds a tcpconn & sends on it */
 int tcp_send(int type, char* buf, unsigned len, union sockaddr_union* to,
@@ -730,21 +756,12 @@ send_it:
 		n=tls_blocking_write(c, fd, buf, len);
 	else
 #endif
-		n=send(fd, buf, len,
-#ifdef HAVE_MSG_NOSIGNAL
-			MSG_NOSIGNAL
-#else
-			0
-#endif
-			);
+		n=tcp_blocking_write(c, fd, buf, len);
 	lock_release(&c->write_lock);
 	DBG("tcp_send: after write: c= %p n=%d fd=%d\n",c, n, fd);
 	DBG("tcp_send: buf=\n%.*s\n", (int)len, buf);
 	if (n<0){
-		if (errno==EINTR) goto send_it; /* interrupted write, try again*/
-										/* keep the lock or lock/unlock again?*/
-		LOG(L_ERR, "ERROR: tcpsend: failed to send, n=%d: %s (%d)\n",
-				n, strerror(errno), errno);
+		LOG(L_ERR, "ERROR: tcp_send: failed to send\n");
 		/* error on the connection , mark it as bad and set 0 timeout */
 		c->state=S_CONN_BAD;
 		c->timeout=0;
@@ -959,6 +976,11 @@ static inline void handle_new_connect(struct socket_info* si,
 					" connection(%d): %s\n", errno, strerror(errno));
 			return;
 		}
+		if (init_sock_opt(new_sock)<0){
+			LOG(L_ERR, "ERROR: tcp_main_loop: init_sock_opt failed\n");
+			close(new_sock);
+			return;
+		}
 		
 		/* add socket to list */
 		tcpconn=tcpconn_new(new_sock, &su, si, si->proto, S_CONN_ACCEPT);