|
@@ -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
|