Преглед изворни кода

- tcp timeout preliminary stuff (not yet enabled)

Andrei Pelinescu-Onciul пре 22 година
родитељ
комит
c55f330820
2 измењених фајлова са 139 додато и 0 уклоњено
  1. 3 0
      tcp_conn.h
  2. 136 0
      tcp_main.c

+ 3 - 0
tcp_conn.h

@@ -46,6 +46,9 @@
 #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 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*/

+ 136 - 0
tcp_main.c

@@ -50,6 +50,9 @@
  *              to/from readers/writers (andrei)
  *  2003-11-17  handle_new_connect & tcp_connect will close the 
  *              new socket if tcpconn_new return 0 (e.g. out of mem) (andrei)
+ *  2003-11-28  tcp_blocking_write & tcp_blocking_connect added (andrei)
+ *   TODO: switch to non-blocking tcp sockets, replace send & connect
+ *         with tcp_blocking_*
  */
 
 
@@ -480,6 +483,139 @@ 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,