Browse Source

Separated timeout for websocket and other requests (1/2)

bel 10 năm trước cách đây
mục cha
commit
67c7a2c6f7
1 tập tin đã thay đổi với 56 bổ sung32 xóa
  1. 56 32
      src/civetweb.c

+ 56 - 32
src/civetweb.c

@@ -60,13 +60,13 @@
 /* non-constant aggregate initializer: issued due to missing C99 support */
 #pragma warning(disable : 4204)
 /* padding added after data member */
-#pragma warning (disable : 4820)
+#pragma warning(disable : 4820)
 /* not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */
-#pragma warning (disable : 4668)
+#pragma warning(disable : 4668)
 /* no function prototype given: converting '()' to '(void)' */
-#pragma warning (disable : 4255)
+#pragma warning(disable : 4255)
 /* function has been selected for automatic inline expansion */
-#pragma warning (disable : 4711)
+#pragma warning(disable : 4711)
 #endif
 
 /* This code uses static_assert to check some conditions.
@@ -180,6 +180,9 @@ int clock_gettime(int clk_id, struct timespec *t)
 #ifndef MAX_WORKER_THREADS
 #define MAX_WORKER_THREADS (1024 * 64)
 #endif
+#ifndef SOCKET_TIMEOUT_QUANTUM
+#define SOCKET_TIMEOUT_QUANTUM (10000)
+#endif
 
 mg_static_assert(MAX_WORKER_THREADS >= 1,
                  "worker threads must be a positive number");
@@ -2960,18 +2963,15 @@ push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf, int64_t len)
 
 /* Read from IO channel - opened file descriptor, socket, or SSL descriptor.
  * Return negative value on error, or number of bytes read on success. */
-static int pull(FILE *fp, struct mg_connection *conn, char *buf, int len)
+static int
+pull(FILE *fp, struct mg_connection *conn, char *buf, int len, double timeout)
 {
 	int nread;
-	double timeout = -1;
 	struct timespec start, now;
 
 	memset(&start, 0, sizeof(start));
 	memset(&now, 0, sizeof(now));
 
-	if (conn->ctx->config[REQUEST_TIMEOUT]) {
-		timeout = atoi(conn->ctx->config[REQUEST_TIMEOUT]) / 1000.0;
-	}
 	if (timeout > 0) {
 		clock_gettime(CLOCK_MONOTONIC, &start);
 	}
@@ -3013,9 +3013,14 @@ static int pull(FILE *fp, struct mg_connection *conn, char *buf, int len)
 static int pull_all(FILE *fp, struct mg_connection *conn, char *buf, int len)
 {
 	int n, nread = 0;
+	double timeout = -1.0;
+
+	if (conn->ctx->config[REQUEST_TIMEOUT]) {
+		timeout = atoi(conn->ctx->config[REQUEST_TIMEOUT]) / 1000.0;
+	}
 
 	while (len > 0 && conn->ctx->stop_flag == 0) {
-		n = pull(fp, conn, buf + nread, len);
+		n = pull(fp, conn, buf + nread, len, timeout);
 		if (n < 0) {
 			nread = n; /* Propagate the error */
 			break;
@@ -4606,7 +4611,7 @@ static SOCKET conn2(struct mg_context *ctx /* may be null */,
 #pragma warning(push)
 /* TODO(lsm): use something threadsafe instead of gethostbyname() */
 /* getaddrinfo is the replacement here but isn't cross platform */
-#pragma warning(disable: 4996)
+#pragma warning(disable : 4996)
 #endif
 	} else if ((he = gethostbyname(host)) == NULL) {
 #ifdef _MSC_VER
@@ -5308,12 +5313,14 @@ static int read_request(
 	}
 
 	request_len = get_request_len(buf, *nread);
-	while ((conn->ctx->stop_flag == 0) && (*nread < bufsiz) &&
-	       (request_len == 0) &&
-	       ((mg_difftimespec(&last_action_time, &(conn->req_time)) <=
-	         request_timeout) ||
-	        (request_timeout < 0)) &&
-	       ((n = pull(fp, conn, buf + *nread, bufsiz - *nread)) > 0)) {
+	while (
+	    (conn->ctx->stop_flag == 0) && (*nread < bufsiz) &&
+	    (request_len == 0) &&
+	    ((mg_difftimespec(&last_action_time, &(conn->req_time)) <=
+	      request_timeout) ||
+	     (request_timeout < 0)) &&
+	    ((n = pull(fp, conn, buf + *nread, bufsiz - *nread, request_timeout)) >
+	     0)) {
 		*nread += n;
 		/* assert(*nread <= bufsiz); */
 		if (*nread > bufsiz)
@@ -5400,9 +5407,14 @@ forward_body_data(struct mg_connection *conn, FILE *fp, SOCKET sock, SSL *ssl)
 	char buf[MG_BUF_LEN];
 	int to_read, nread, success = 0;
 	int64_t buffered_len;
+	double timeout = -1.0;
 
-	if (!conn)
+	if (!conn) {
 		return 0;
+	}
+	if (conn->ctx->config[REQUEST_TIMEOUT]) {
+		timeout = atoi(conn->ctx->config[REQUEST_TIMEOUT]) / 1000.0;
+	}
 
 	expect = mg_get_header(conn, "Expect");
 	/* assert(fp != NULL); */
@@ -5454,7 +5466,7 @@ forward_body_data(struct mg_connection *conn, FILE *fp, SOCKET sock, SSL *ssl)
 			if ((int64_t)to_read > conn->content_len - conn->consumed_content) {
 				to_read = (int)(conn->content_len - conn->consumed_content);
 			}
-			nread = pull(NULL, conn, buf, to_read);
+			nread = pull(NULL, conn, buf, to_read, timeout);
 			if (nread <= 0 || push(fp, sock, ssl, buf, nread) != nread) {
 				break;
 			}
@@ -6796,6 +6808,11 @@ static void read_websocket(struct mg_connection *conn,
 	char mem[4096];
 	char *data = mem;
 	unsigned char mop; /* mask flag and opcode */
+	double timeout = -1.0;
+
+	if (conn->ctx->config[REQUEST_TIMEOUT]) {
+		timeout = atoi(conn->ctx->config[REQUEST_TIMEOUT]) / 1000.0;
+	}
 
 	mg_set_thread_name("wsock");
 
@@ -6852,7 +6869,8 @@ static void read_websocket(struct mg_connection *conn,
 				memcpy(data, buf + header_len, len);
 				error = 0;
 				while (len < data_len) {
-					n = pull(NULL, conn, data + len, (int)(data_len - len));
+					n = pull(
+					    NULL, conn, data + len, (int)(data_len - len), timeout);
 					if (n <= 0) {
 						error = 1;
 						break;
@@ -6914,7 +6932,8 @@ static void read_websocket(struct mg_connection *conn,
 			if ((n = pull(NULL,
 			              conn,
 			              conn->buf + conn->data_len,
-			              conn->buf_size - conn->data_len)) <= 0) {
+			              conn->buf_size - conn->data_len,
+			              timeout)) <= 0) {
 				/* Error, no bytes read */
 				break;
 			}
@@ -8671,13 +8690,20 @@ static void close_socket_gracefully(struct mg_connection *conn)
 	int n;
 #endif
 	struct linger linger;
+	double timeout = -1.0;
+
+	if (!conn) {
+		return;
+	}
+	if (conn->ctx->config[REQUEST_TIMEOUT]) {
+		timeout = atoi(conn->ctx->config[REQUEST_TIMEOUT]) / 1000.0;
+	}
 
 	/* Set linger option to avoid socket hanging out after close. This prevent
 	 * ephemeral port exhaust problem under high QPS. */
 	linger.l_onoff = 1;
 	linger.l_linger = 1;
-	if (!conn)
-		return;
+
 	if (setsockopt(conn->client.sock,
 	               SOL_SOCKET,
 	               SO_LINGER,
@@ -8700,7 +8726,7 @@ static void close_socket_gracefully(struct mg_connection *conn)
 	 * when server decides to close the connection; then when client
 	 * does recv() it gets no data back. */
 	do {
-		n = pull(NULL, conn, buf, sizeof(buf));
+		n = pull(NULL, conn, buf, sizeof(buf), timeout);
 	} while (n > 0);
 #endif
 
@@ -9440,15 +9466,13 @@ static void accept_new_connection(const struct socket *listener,
 			timeout = -1;
 		}
 
-		/* Set socket timeout to the given value, but not more than 10 seconds,
-		 * so the server can exit after 10 seconds if required. */
-		/* TODO: Currently values > 10 s are round up to the next 10 s.
-		 * For values like 24 s a socket timeout of 8 or 12 s would be better.
-		 */
-		if ((timeout > 0) && (timeout < 10000)) {
+		/* Set socket timeout to the given value, but not more than a
+		 * a certain limit (SOCKET_TIMEOUT_QUANTUM, default 10 seconds),
+		 * so the server can exit after that time if requested. */
+		if ((timeout > 0) && (timeout < SOCKET_TIMEOUT_QUANTUM)) {
 			set_sock_timeout(so.sock, timeout);
 		} else {
-			set_sock_timeout(so.sock, 10000);
+			set_sock_timeout(so.sock, SOCKET_TIMEOUT_QUANTUM);
 		}
 
 		produce_socket(ctx, &so);
@@ -9673,7 +9697,7 @@ static void get_system_name(char **sysName)
 #ifdef _MSC_VER
 #pragma warning(push)
 // GetVersion was declared deprecated
-#pragma warning(disable: 4996)
+#pragma warning(disable : 4996)
 #endif
 	dwVersion = GetVersion();
 #ifdef _MSC_VER