Browse Source

Make fc/fake_connection thread-safe

Do not share one fake_connection object. That means we can not use
multiple contexts (multiple servers, a server and a client, etc.)
safely in a process.
Be careful of sizeof(mg_connection). It is currently small enough
to put on the stack.
xtne6f 6 years ago
parent
commit
7d568a31cc
2 changed files with 246 additions and 219 deletions
  1. 240 217
      src/civetweb.c
  2. 6 2
      src/mod_lua.inl

+ 240 - 217
src/civetweb.c

@@ -2788,13 +2788,17 @@ static int is_websocket_protocol(const struct mg_connection *conn);
 
 
 #define mg_cry_internal(conn, fmt, ...)                                        \
-	mg_cry_internal_wrap(conn, __func__, __LINE__, fmt, __VA_ARGS__)
+	mg_cry_internal_wrap(conn, NULL, __func__, __LINE__, fmt, __VA_ARGS__)
+
+#define mg_cry_ctx_internal(ctx, fmt, ...)                                     \
+	mg_cry_internal_wrap(NULL, ctx, __func__, __LINE__, fmt, __VA_ARGS__)
 
 static void mg_cry_internal_wrap(const struct mg_connection *conn,
+                                 struct mg_context *ctx,
                                  const char *func,
                                  unsigned line,
                                  const char *fmt,
-                                 ...) PRINTF_ARGS(4, 5);
+                                 ...) PRINTF_ARGS(5, 6);
 
 
 #if !defined(NO_THREAD_NAME)
@@ -3733,8 +3737,22 @@ mg_cry_internal_impl(const struct mg_connection *conn,
 #endif /* Externally provided function */
 
 
+/* Construct fake connection structure. Used for logging, if connection
+ * is not applicable at the moment of logging. */
+static struct mg_connection *
+fake_connection(struct mg_connection *fc, struct mg_context *ctx)
+{
+	static const struct mg_connection conn_zero = {0};
+	*fc = conn_zero;
+	fc->phys_ctx = ctx;
+	fc->dom_ctx = &(ctx->dd);
+	return fc;
+}
+
+
 static void
 mg_cry_internal_wrap(const struct mg_connection *conn,
+                     struct mg_context *ctx,
                      const char *func,
                      unsigned line,
                      const char *fmt,
@@ -3742,7 +3760,12 @@ mg_cry_internal_wrap(const struct mg_connection *conn,
 {
 	va_list ap;
 	va_start(ap, fmt);
-	mg_cry_internal_impl(conn, func, line, fmt, ap);
+	if (!conn && ctx) {
+		struct mg_connection fc;
+		mg_cry_internal_impl(fake_connection(&fc, ctx), func, line, fmt, ap);
+	} else {
+		mg_cry_internal_impl(conn, func, line, fmt, ap);
+	}
 	va_end(ap);
 }
 
@@ -3760,18 +3783,6 @@ mg_cry(const struct mg_connection *conn, const char *fmt, ...)
 #define mg_cry DO_NOT_USE_THIS_FUNCTION__USE_mg_cry_internal
 
 
-/* Return fake connection structure. Used for logging, if connection
- * is not applicable at the moment of logging. */
-static struct mg_connection *
-fc(struct mg_context *ctx)
-{
-	static struct mg_connection fake_connection;
-	fake_connection.phys_ctx = ctx;
-	fake_connection.dom_ctx = &(ctx->dd);
-	return &fake_connection;
-}
-
-
 const char *
 mg_version(void)
 {
@@ -5456,9 +5467,12 @@ poll(struct mg_pollfd *pfd, unsigned int n, int milliseconds)
 
 
 static void
-set_close_on_exec(SOCKET sock, struct mg_connection *conn /* may be null */)
+set_close_on_exec(SOCKET sock,
+                  const struct mg_connection *conn /* may be null */,
+                  struct mg_context *ctx /* may be null */)
 {
 	(void)conn; /* Unused. */
+	(void)ctx;
 #if defined(_WIN32_WCE)
 	(void)sock;
 #else
@@ -5835,11 +5849,14 @@ mg_stat(const struct mg_connection *conn,
 
 
 static void
-set_close_on_exec(SOCKET fd, struct mg_connection *conn /* may be null */)
+set_close_on_exec(SOCKET fd,
+                  const struct mg_connection *conn /* may be null */,
+                  struct mg_context *ctx /* may be null */)
 {
 	if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) {
-		if (conn) {
-			mg_cry_internal(conn,
+		if (conn || ctx) {
+			struct mg_connection fc;
+			mg_cry_internal((conn ? conn : fake_connection(&fc, ctx)),
 			                "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s",
 			                __func__,
 			                strerror(ERRNO));
@@ -8849,7 +8866,7 @@ connect_socket(struct mg_context *ctx /* may be NULL */,
 		return 0;
 	}
 
-	set_close_on_exec(*sock, fc(ctx));
+	set_close_on_exec(*sock, NULL, ctx);
 
 	if (ip_ver == 4) {
 		/* connected with IPv4 */
@@ -11048,12 +11065,12 @@ handle_cgi_request(struct mg_connection *conn, const char *prog)
 #endif
 
 	/* Make sure child closes all pipe descriptors. It must dup them to 0,1 */
-	set_close_on_exec((SOCKET)fdin[0], conn);  /* stdin read */
-	set_close_on_exec((SOCKET)fdin[1], conn);  /* stdin write */
-	set_close_on_exec((SOCKET)fdout[0], conn); /* stdout read */
-	set_close_on_exec((SOCKET)fdout[1], conn); /* stdout write */
-	set_close_on_exec((SOCKET)fderr[0], conn); /* stderr read */
-	set_close_on_exec((SOCKET)fderr[1], conn); /* stderr write */
+	set_close_on_exec((SOCKET)fdin[0], conn, NULL);  /* stdin read */
+	set_close_on_exec((SOCKET)fdin[1], conn, NULL);  /* stdin write */
+	set_close_on_exec((SOCKET)fdout[0], conn, NULL); /* stdout read */
+	set_close_on_exec((SOCKET)fdout[1], conn, NULL); /* stdout write */
+	set_close_on_exec((SOCKET)fderr[0], conn, NULL); /* stderr read */
+	set_close_on_exec((SOCKET)fderr[1], conn, NULL); /* stderr write */
 
 	/* Parent closes only one side of the pipes.
 	 * If we don't mark them as closed, close() attempt before
@@ -13318,18 +13335,18 @@ mg_set_handler_type(struct mg_context *phys_ctx,
 	                                            phys_ctx);
 	if (tmp_rh == NULL) {
 		mg_unlock_context(phys_ctx);
-		mg_cry_internal(fc(phys_ctx),
-		                "%s",
-		                "Cannot create new request handler struct, OOM");
+		mg_cry_ctx_internal(phys_ctx,
+		                    "%s",
+		                    "Cannot create new request handler struct, OOM");
 		return;
 	}
 	tmp_rh->uri = mg_strdup_ctx(uri, phys_ctx);
 	if (!tmp_rh->uri) {
 		mg_unlock_context(phys_ctx);
 		mg_free(tmp_rh);
-		mg_cry_internal(fc(phys_ctx),
-		                "%s",
-		                "Cannot create new request handler struct, OOM");
+		mg_cry_ctx_internal(phys_ctx,
+		                    "%s",
+		                    "Cannot create new request handler struct, OOM");
 		return;
 	}
 	tmp_rh->uri_len = urilen;
@@ -13338,14 +13355,14 @@ mg_set_handler_type(struct mg_context *phys_ctx,
 		if (0 != pthread_mutex_init(&tmp_rh->refcount_mutex, NULL)) {
 			mg_unlock_context(phys_ctx);
 			mg_free(tmp_rh);
-			mg_cry_internal(fc(phys_ctx), "%s", "Cannot init refcount mutex");
+			mg_cry_ctx_internal(phys_ctx, "%s", "Cannot init refcount mutex");
 			return;
 		}
 		if (0 != pthread_cond_init(&tmp_rh->refcount_cond, NULL)) {
 			mg_unlock_context(phys_ctx);
 			pthread_mutex_destroy(&tmp_rh->refcount_mutex);
 			mg_free(tmp_rh);
-			mg_cry_internal(fc(phys_ctx), "%s", "Cannot init refcount cond");
+			mg_cry_ctx_internal(phys_ctx, "%s", "Cannot init refcount cond");
 			return;
 		}
 		tmp_rh->refcount = 0;
@@ -14486,8 +14503,8 @@ set_ports_option(struct mg_context *phys_ctx)
 		portsTotal++;
 
 		if (!parse_port_string(&vec, &so, &ip_version)) {
-			mg_cry_internal(
-			    fc(phys_ctx),
+			mg_cry_ctx_internal(
+			    phys_ctx,
 			    "%.*s: invalid port spec (entry %i). Expecting list of: %s",
 			    (int)vec.len,
 			    vec.ptr,
@@ -14499,9 +14516,9 @@ set_ports_option(struct mg_context *phys_ctx)
 #if !defined(NO_SSL)
 		if (so.is_ssl && phys_ctx->dd.ssl_ctx == NULL) {
 
-			mg_cry_internal(fc(phys_ctx),
-			                "Cannot add SSL socket (entry %i)",
-			                portsTotal);
+			mg_cry_ctx_internal(phys_ctx,
+			                    "Cannot add SSL socket (entry %i)",
+			                    portsTotal);
 			continue;
 		}
 #endif
@@ -14509,9 +14526,9 @@ set_ports_option(struct mg_context *phys_ctx)
 		if ((so.sock = socket(so.lsa.sa.sa_family, SOCK_STREAM, 6))
 		    == INVALID_SOCKET) {
 
-			mg_cry_internal(fc(phys_ctx),
-			                "cannot create socket (entry %i)",
-			                portsTotal);
+			mg_cry_ctx_internal(phys_ctx,
+			                    "cannot create socket (entry %i)",
+			                    portsTotal);
 			continue;
 		}
 
@@ -14533,8 +14550,8 @@ set_ports_option(struct mg_context *phys_ctx)
 		    != 0) {
 
 			/* Set reuse option, but don't abort on errors. */
-			mg_cry_internal(
-			    fc(phys_ctx),
+			mg_cry_ctx_internal(
+			    phys_ctx,
 			    "cannot set socket option SO_EXCLUSIVEADDRUSE (entry %i)",
 			    portsTotal);
 		}
@@ -14547,9 +14564,10 @@ set_ports_option(struct mg_context *phys_ctx)
 		    != 0) {
 
 			/* Set reuse option, but don't abort on errors. */
-			mg_cry_internal(fc(phys_ctx),
-			                "cannot set socket option SO_REUSEADDR (entry %i)",
-			                portsTotal);
+			mg_cry_ctx_internal(
+				phys_ctx,
+				"cannot set socket option SO_REUSEADDR (entry %i)",
+				portsTotal);
 		}
 #endif
 
@@ -14566,8 +14584,8 @@ set_ports_option(struct mg_context *phys_ctx)
 				           != 0) {
 
 					/* Set IPv6 only option, but don't abort on errors. */
-					mg_cry_internal(
-					    fc(phys_ctx),
+					mg_cry_ctx_internal(
+					    phys_ctx,
 					    "cannot set socket option IPV6_V6ONLY=off (entry %i)",
 					    portsTotal);
 				}
@@ -14581,14 +14599,14 @@ set_ports_option(struct mg_context *phys_ctx)
 				           != 0) {
 
 					/* Set IPv6 only option, but don't abort on errors. */
-					mg_cry_internal(
-					    fc(phys_ctx),
+					mg_cry_ctx_internal(
+					    phys_ctx,
 					    "cannot set socket option IPV6_V6ONLY=on (entry %i)",
 					    portsTotal);
 				}
 			}
 #else
-			mg_cry_internal(fc(phys_ctx), "%s", "IPv6 not available");
+			mg_cry_ctx_internal(phys_ctx, "%s", "IPv6 not available");
 			closesocket(so.sock);
 			so.sock = INVALID_SOCKET;
 			continue;
@@ -14599,12 +14617,12 @@ set_ports_option(struct mg_context *phys_ctx)
 
 			len = sizeof(so.lsa.sin);
 			if (bind(so.sock, &so.lsa.sa, len) != 0) {
-				mg_cry_internal(fc(phys_ctx),
-				                "cannot bind to %.*s: %d (%s)",
-				                (int)vec.len,
-				                vec.ptr,
-				                (int)ERRNO,
-				                strerror(errno));
+				mg_cry_ctx_internal(phys_ctx,
+				                    "cannot bind to %.*s: %d (%s)",
+				                    (int)vec.len,
+				                    vec.ptr,
+				                    (int)ERRNO,
+				                    strerror(errno));
 				closesocket(so.sock);
 				so.sock = INVALID_SOCKET;
 				continue;
@@ -14615,12 +14633,12 @@ set_ports_option(struct mg_context *phys_ctx)
 
 			len = sizeof(so.lsa.sin6);
 			if (bind(so.sock, &so.lsa.sa, len) != 0) {
-				mg_cry_internal(fc(phys_ctx),
-				                "cannot bind to IPv6 %.*s: %d (%s)",
-				                (int)vec.len,
-				                vec.ptr,
-				                (int)ERRNO,
-				                strerror(errno));
+				mg_cry_ctx_internal(phys_ctx,
+				                    "cannot bind to IPv6 %.*s: %d (%s)",
+				                    (int)vec.len,
+				                    vec.ptr,
+				                    (int)ERRNO,
+				                    strerror(errno));
 				closesocket(so.sock);
 				so.sock = INVALID_SOCKET;
 				continue;
@@ -14628,8 +14646,8 @@ set_ports_option(struct mg_context *phys_ctx)
 		}
 #endif
 		else {
-			mg_cry_internal(
-			    fc(phys_ctx),
+			mg_cry_ctx_internal(
+			    phys_ctx,
 			    "cannot bind: address family not supported (entry %i)",
 			    portsTotal);
 			closesocket(so.sock);
@@ -14639,12 +14657,12 @@ set_ports_option(struct mg_context *phys_ctx)
 
 		if (listen(so.sock, SOMAXCONN) != 0) {
 
-			mg_cry_internal(fc(phys_ctx),
-			                "cannot listen to %.*s: %d (%s)",
-			                (int)vec.len,
-			                vec.ptr,
-			                (int)ERRNO,
-			                strerror(errno));
+			mg_cry_ctx_internal(phys_ctx,
+			                    "cannot listen to %.*s: %d (%s)",
+			                    (int)vec.len,
+			                    vec.ptr,
+			                    (int)ERRNO,
+			                    strerror(errno));
 			closesocket(so.sock);
 			so.sock = INVALID_SOCKET;
 			continue;
@@ -14654,12 +14672,12 @@ set_ports_option(struct mg_context *phys_ctx)
 		    || (usa.sa.sa_family != so.lsa.sa.sa_family)) {
 
 			int err = (int)ERRNO;
-			mg_cry_internal(fc(phys_ctx),
-			                "call to getsockname failed %.*s: %d (%s)",
-			                (int)vec.len,
-			                vec.ptr,
-			                err,
-			                strerror(errno));
+			mg_cry_ctx_internal(phys_ctx,
+			                    "call to getsockname failed %.*s: %d (%s)",
+			                    (int)vec.len,
+			                    vec.ptr,
+			                    err,
+			                    strerror(errno));
 			closesocket(so.sock);
 			so.sock = INVALID_SOCKET;
 			continue;
@@ -14682,7 +14700,7 @@ set_ports_option(struct mg_context *phys_ctx)
 		                        phys_ctx))
 		    == NULL) {
 
-			mg_cry_internal(fc(phys_ctx), "%s", "Out of memory");
+			mg_cry_ctx_internal(phys_ctx, "%s", "Out of memory");
 			closesocket(so.sock);
 			so.sock = INVALID_SOCKET;
 			continue;
@@ -14695,14 +14713,14 @@ set_ports_option(struct mg_context *phys_ctx)
 		                        phys_ctx))
 		    == NULL) {
 
-			mg_cry_internal(fc(phys_ctx), "%s", "Out of memory");
+			mg_cry_ctx_internal(phys_ctx, "%s", "Out of memory");
 			closesocket(so.sock);
 			so.sock = INVALID_SOCKET;
 			mg_free(ptr);
 			continue;
 		}
 
-		set_close_on_exec(so.sock, fc(phys_ctx));
+		set_close_on_exec(so.sock, NULL, phys_ctx);
 		phys_ctx->listening_sockets = ptr;
 		phys_ctx->listening_sockets[phys_ctx->num_listening_sockets] = so;
 		phys_ctx->listening_socket_fds = pfd;
@@ -14853,9 +14871,9 @@ check_acl(struct mg_context *phys_ctx, uint32_t remote_ip)
 			flag = vec.ptr[0];
 			if ((flag != '+' && flag != '-')
 			    || (parse_net(&vec.ptr[1], &net, &mask) == 0)) {
-				mg_cry_internal(fc(phys_ctx),
-				                "%s: subnet must be [+|-]x.x.x.x[/x]",
-				                __func__);
+				mg_cry_ctx_internal(phys_ctx,
+				                    "%s: subnet must be [+|-]x.x.x.x[/x]",
+				                    __func__);
 				return -1;
 			}
 
@@ -14886,10 +14904,10 @@ set_uid_option(struct mg_context *phys_ctx)
 		if (run_as_user != NULL && (to_pw = getpwnam(run_as_user)) == NULL) {
 			/* run_as_user does not exist on the system. We can't proceed
 			 * further. */
-			mg_cry_internal(fc(phys_ctx),
-			                "%s: unknown user [%s]",
-			                __func__,
-			                run_as_user);
+			mg_cry_ctx_internal(phys_ctx,
+			                    "%s: unknown user [%s]",
+			                    __func__,
+			                    run_as_user);
 		} else if (run_as_user == NULL || curr_uid == to_pw->pw_uid) {
 			/* There was either no request to change user, or we're already
 			 * running as run_as_user. Nothing else to do.
@@ -14898,22 +14916,22 @@ set_uid_option(struct mg_context *phys_ctx)
 		} else {
 			/* Valid change request.  */
 			if (setgid(to_pw->pw_gid) == -1) {
-				mg_cry_internal(fc(phys_ctx),
-				                "%s: setgid(%s): %s",
-				                __func__,
-				                run_as_user,
-				                strerror(errno));
+				mg_cry_ctx_internal(phys_ctx,
+				                    "%s: setgid(%s): %s",
+				                    __func__,
+				                    run_as_user,
+				                    strerror(errno));
 			} else if (setgroups(0, NULL) == -1) {
-				mg_cry_internal(fc(phys_ctx),
-				                "%s: setgroups(): %s",
-				                __func__,
-				                strerror(errno));
+				mg_cry_ctx_internal(phys_ctx,
+				                    "%s: setgroups(): %s",
+				                    __func__,
+				                    strerror(errno));
 			} else if (setuid(to_pw->pw_uid) == -1) {
-				mg_cry_internal(fc(phys_ctx),
-				                "%s: setuid(%s): %s",
-				                __func__,
-				                run_as_user,
-				                strerror(errno));
+				mg_cry_ctx_internal(phys_ctx,
+				                    "%s: setuid(%s): %s",
+				                    __func__,
+				                    run_as_user,
+				                    strerror(errno));
 			} else {
 				success = 1;
 			}
@@ -15004,8 +15022,8 @@ refresh_trust(struct mg_connection *conn)
 			                                  ca_file,
 			                                  ca_path)
 			    != 1) {
-				mg_cry_internal(
-				    fc(conn->phys_ctx),
+				mg_cry_ctx_internal(
+				    conn->phys_ctx,
 				    "SSL_CTX_load_verify_locations error: %s "
 				    "ssl_verify_peer requires setting "
 				    "either ssl_ca_path or ssl_ca_file. Is any of them "
@@ -15529,29 +15547,29 @@ ssl_use_pem_file(struct mg_context *phys_ctx,
                  const char *chain)
 {
 	if (SSL_CTX_use_certificate_file(dom_ctx->ssl_ctx, pem, 1) == 0) {
-		mg_cry_internal(fc(phys_ctx),
-		                "%s: cannot open certificate file %s: %s",
-		                __func__,
-		                pem,
-		                ssl_error());
+		mg_cry_ctx_internal(phys_ctx,
+		                    "%s: cannot open certificate file %s: %s",
+		                    __func__,
+		                    pem,
+		                    ssl_error());
 		return 0;
 	}
 
 	/* could use SSL_CTX_set_default_passwd_cb_userdata */
 	if (SSL_CTX_use_PrivateKey_file(dom_ctx->ssl_ctx, pem, 1) == 0) {
-		mg_cry_internal(fc(phys_ctx),
-		                "%s: cannot open private key file %s: %s",
-		                __func__,
-		                pem,
-		                ssl_error());
+		mg_cry_ctx_internal(phys_ctx,
+		                    "%s: cannot open private key file %s: %s",
+		                    __func__,
+		                    pem,
+		                    ssl_error());
 		return 0;
 	}
 
 	if (SSL_CTX_check_private_key(dom_ctx->ssl_ctx) == 0) {
-		mg_cry_internal(fc(phys_ctx),
-		                "%s: certificate and private key do not match: %s",
-		                __func__,
-		                pem);
+		mg_cry_ctx_internal(phys_ctx,
+		                    "%s: certificate and private key do not match: %s",
+		                    __func__,
+		                    pem);
 		return 0;
 	}
 
@@ -15565,11 +15583,11 @@ ssl_use_pem_file(struct mg_context *phys_ctx,
 	 */
 	if (chain) {
 		if (SSL_CTX_use_certificate_chain_file(dom_ctx->ssl_ctx, chain) == 0) {
-			mg_cry_internal(fc(phys_ctx),
-			                "%s: cannot use certificate chain file %s: %s",
-			                __func__,
-			                pem,
-			                ssl_error());
+			mg_cry_ctx_internal(phys_ctx,
+			                    "%s: cannot use certificate chain file %s: %s",
+			                    __func__,
+			                    pem,
+			                    ssl_error());
 			return 0;
 		}
 	}
@@ -15734,16 +15752,16 @@ init_ssl_ctx_impl(struct mg_context *phys_ctx,
 
 #if defined(OPENSSL_API_1_1)
 	if ((dom_ctx->ssl_ctx = SSL_CTX_new(TLS_server_method())) == NULL) {
-		mg_cry_internal(fc(phys_ctx),
-		                "SSL_CTX_new (server) error: %s",
-		                ssl_error());
+		mg_cry_ctx_internal(phys_ctx,
+		                    "SSL_CTX_new (server) error: %s",
+		                    ssl_error());
 		return 0;
 	}
 #else
 	if ((dom_ctx->ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) {
-		mg_cry_internal(fc(phys_ctx),
-		                "SSL_CTX_new (server) error: %s",
-		                ssl_error());
+		mg_cry_ctx_internal(phys_ctx,
+		                    "SSL_CTX_new (server) error: %s",
+		                    ssl_error());
 		return 0;
 	}
 #endif /* OPENSSL_API_1_1 */
@@ -15796,9 +15814,9 @@ init_ssl_ctx_impl(struct mg_context *phys_ctx,
 	 * If it returns 1, civetweb assumes the calback already did this.
 	 * If it returns -1, initializing ssl fails. */
 	if (callback_ret < 0) {
-		mg_cry_internal(fc(phys_ctx),
-		                "SSL callback returned error: %i",
-		                callback_ret);
+		mg_cry_ctx_internal(phys_ctx,
+		                    "SSL callback returned error: %i",
+		                    callback_ret);
 		return 0;
 	}
 	if (callback_ret > 0) {
@@ -15859,13 +15877,13 @@ init_ssl_ctx_impl(struct mg_context *phys_ctx,
 		ca_file = dom_ctx->config[SSL_CA_FILE];
 		if (SSL_CTX_load_verify_locations(dom_ctx->ssl_ctx, ca_file, ca_path)
 		    != 1) {
-			mg_cry_internal(fc(phys_ctx),
-			                "SSL_CTX_load_verify_locations error: %s "
-			                "ssl_verify_peer requires setting "
-			                "either ssl_ca_path or ssl_ca_file. "
-			                "Is any of them present in the "
-			                ".conf file?",
-			                ssl_error());
+			mg_cry_ctx_internal(phys_ctx,
+			                    "SSL_CTX_load_verify_locations error: %s "
+			                    "ssl_verify_peer requires setting "
+			                    "either ssl_ca_path or ssl_ca_file. "
+			                    "Is any of them present in the "
+			                    ".conf file?",
+			                    ssl_error());
 			return 0;
 		}
 
@@ -15880,9 +15898,9 @@ init_ssl_ctx_impl(struct mg_context *phys_ctx,
 
 		if (use_default_verify_paths
 		    && (SSL_CTX_set_default_verify_paths(dom_ctx->ssl_ctx) != 1)) {
-			mg_cry_internal(fc(phys_ctx),
-			                "SSL_CTX_set_default_verify_paths error: %s",
-			                ssl_error());
+			mg_cry_ctx_internal(phys_ctx,
+			                    "SSL_CTX_set_default_verify_paths error: %s",
+			                    ssl_error());
 			return 0;
 		}
 
@@ -15896,9 +15914,9 @@ init_ssl_ctx_impl(struct mg_context *phys_ctx,
 		if (SSL_CTX_set_cipher_list(dom_ctx->ssl_ctx,
 		                            dom_ctx->config[SSL_CIPHER_LIST])
 		    != 1) {
-			mg_cry_internal(fc(phys_ctx),
-			                "SSL_CTX_set_cipher_list error: %s",
-			                ssl_error());
+			mg_cry_ctx_internal(phys_ctx,
+			                    "SSL_CTX_set_cipher_list error: %s",
+			                    ssl_error());
 		}
 	}
 
@@ -15939,14 +15957,14 @@ init_ssl_ctx(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx)
 	                                                phys_ctx->user_data));
 
 	if (callback_ret < 0) {
-		mg_cry_internal(fc(phys_ctx),
-		                "external_ssl_ctx callback returned error: %i",
-		                callback_ret);
+		mg_cry_ctx_internal(phys_ctx,
+		                    "external_ssl_ctx callback returned error: %i",
+		                    callback_ret);
 		return 0;
 	} else if (callback_ret > 0) {
 		dom_ctx->ssl_ctx = (SSL_CTX *)ssl_ctx;
 		if (!initialize_ssl(ebuf, sizeof(ebuf))) {
-			mg_cry_internal(fc(phys_ctx), "%s", ebuf);
+			mg_cry_ctx_internal(phys_ctx, "%s", ebuf);
 			return 0;
 		}
 		return 1;
@@ -15961,9 +15979,9 @@ init_ssl_ctx(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx)
 		/* No certificate and no callback:
 		 * Essential data to set up TLS is missing.
 		 */
-		mg_cry_internal(fc(phys_ctx),
-		                "Initializing SSL failed: -%s is not set",
-		                config_options[SSL_CERTIFICATE].name);
+		mg_cry_ctx_internal(phys_ctx,
+		                    "Initializing SSL failed: -%s is not set",
+		                    config_options[SSL_CERTIFICATE].name);
 		return 0;
 	}
 
@@ -15976,7 +15994,7 @@ init_ssl_ctx(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx)
 	}
 
 	if (!initialize_ssl(ebuf, sizeof(ebuf))) {
-		mg_cry_internal(fc(phys_ctx), "%s", ebuf);
+		mg_cry_ctx_internal(phys_ctx, "%s", ebuf);
 		return 0;
 	}
 
@@ -16031,15 +16049,17 @@ set_gpass_option(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx)
 	if (phys_ctx) {
 		struct mg_file file = STRUCT_FILE_INITIALIZER;
 		const char *path;
+		struct mg_connection fc;
 		if (!dom_ctx) {
 			dom_ctx = &(phys_ctx->dd);
 		}
 		path = dom_ctx->config[GLOBAL_PASSWORDS_FILE];
-		if ((path != NULL) && !mg_stat(fc(phys_ctx), path, &file.stat)) {
-			mg_cry_internal(fc(phys_ctx),
-			                "Cannot open %s: %s",
-			                path,
-			                strerror(ERRNO));
+		if ((path != NULL)
+		    && !mg_stat(fake_connection(&fc, phys_ctx), path, &file.stat)) {
+			mg_cry_ctx_internal(phys_ctx,
+			                    "Cannot open %s: %s",
+			                    path,
+			                    strerror(ERRNO));
 			return 0;
 		}
 		return 1;
@@ -17863,9 +17883,9 @@ worker_thread_run(struct mg_connection *conn)
 	thread_index = (int)(conn - ctx->worker_connections);
 	if ((thread_index < 0)
 	    || ((unsigned)thread_index >= (unsigned)ctx->cfg_worker_threads)) {
-		mg_cry_internal(fc(ctx),
-		                "Internal error: Invalid worker index %i",
-		                thread_index);
+		mg_cry_ctx_internal(ctx,
+		                    "Internal error: Invalid worker index %i",
+		                    thread_index);
 		return;
 	}
 
@@ -17874,9 +17894,10 @@ worker_thread_run(struct mg_connection *conn)
 	 * of interest to anyone observing a server status.  */
 	conn->buf = (char *)mg_malloc_ctx(ctx->max_request_size, conn->phys_ctx);
 	if (conn->buf == NULL) {
-		mg_cry_internal(fc(ctx),
-		                "Out of memory: Cannot allocate buffer for worker %i",
-		                thread_index);
+		mg_cry_ctx_internal(
+			ctx,
+			"Out of memory: Cannot allocate buffer for worker %i",
+			thread_index);
 		return;
 	}
 	conn->buf_size = (int)ctx->max_request_size;
@@ -17892,7 +17913,7 @@ worker_thread_run(struct mg_connection *conn)
 	 */
 	if (0 != pthread_mutex_init(&conn->mutex, &pthread_mutex_attr)) {
 		mg_free(conn->buf);
-		mg_cry_internal(fc(ctx), "%s", "Cannot create mutex");
+		mg_cry_ctx_internal(ctx, "%s", "Cannot create mutex");
 		return;
 	}
 
@@ -18041,22 +18062,22 @@ accept_new_connection(const struct socket *listener, struct mg_context *ctx)
 	    == INVALID_SOCKET) {
 	} else if (!check_acl(ctx, ntohl(*(uint32_t *)&so.rsa.sin.sin_addr))) {
 		sockaddr_to_string(src_addr, sizeof(src_addr), &so.rsa);
-		mg_cry_internal(fc(ctx),
-		                "%s: %s is not allowed to connect",
-		                __func__,
-		                src_addr);
+		mg_cry_ctx_internal(ctx,
+		                    "%s: %s is not allowed to connect",
+		                    __func__,
+		                    src_addr);
 		closesocket(so.sock);
 	} else {
 		/* Put so socket structure into the queue */
 		DEBUG_TRACE("Accepted socket %d", (int)so.sock);
-		set_close_on_exec(so.sock, fc(ctx));
+		set_close_on_exec(so.sock, NULL, ctx);
 		so.is_ssl = listener->is_ssl;
 		so.ssl_redir = listener->ssl_redir;
 		if (getsockname(so.sock, &so.lsa.sa, &len) != 0) {
-			mg_cry_internal(fc(ctx),
-			                "%s: getsockname() failed: %s",
-			                __func__,
-			                strerror(ERRNO));
+			mg_cry_ctx_internal(ctx,
+			                    "%s: getsockname() failed: %s",
+			                    __func__,
+			                    strerror(ERRNO));
 		}
 
 		/* Set TCP keep-alive. This is needed because if HTTP-level
@@ -18072,8 +18093,8 @@ accept_new_connection(const struct socket *listener, struct mg_context *ctx)
 		               (SOCK_OPT_TYPE)&on,
 		               sizeof(on))
 		    != 0) {
-			mg_cry_internal(
-			    fc(ctx),
+			mg_cry_ctx_internal(
+			    ctx,
 			    "%s: setsockopt(SOL_SOCKET SO_KEEPALIVE) failed: %s",
 			    __func__,
 			    strerror(ERRNO));
@@ -18089,8 +18110,8 @@ accept_new_connection(const struct socket *listener, struct mg_context *ctx)
 		if ((ctx->dd.config[CONFIG_TCP_NODELAY] != NULL)
 		    && (!strcmp(ctx->dd.config[CONFIG_TCP_NODELAY], "1"))) {
 			if (set_tcp_nodelay(so.sock, 1) != 0) {
-				mg_cry_internal(
-				    fc(ctx),
+				mg_cry_ctx_internal(
+				    ctx,
 				    "%s: setsockopt(IPPROTO_TCP TCP_NODELAY) failed: %s",
 				    __func__,
 				    strerror(ERRNO));
@@ -18511,9 +18532,10 @@ mg_start(const struct mg_callbacks *callbacks,
 	if (!ok) {
 		/* Fatal error - abort start. However, this situation should never
 		 * occur in practice. */
-		mg_cry_internal(fc(ctx),
-		                "%s",
-		                "Cannot initialize thread synchronization objects");
+		mg_cry_ctx_internal(
+			ctx,
+			"%s",
+			"Cannot initialize thread synchronization objects");
 		mg_free(ctx);
 		pthread_setspecific(sTlsKey, NULL);
 		return NULL;
@@ -18535,18 +18557,18 @@ mg_start(const struct mg_callbacks *callbacks,
 	/* Store options */
 	while (options && (name = *options++) != NULL) {
 		if ((idx = get_option_index(name)) == -1) {
-			mg_cry_internal(fc(ctx), "Invalid option: %s", name);
+			mg_cry_ctx_internal(ctx, "Invalid option: %s", name);
 			free_context(ctx);
 			pthread_setspecific(sTlsKey, NULL);
 			return NULL;
 		} else if ((value = *options++) == NULL) {
-			mg_cry_internal(fc(ctx), "%s: option value cannot be NULL", name);
+			mg_cry_ctx_internal(ctx, "%s: option value cannot be NULL", name);
 			free_context(ctx);
 			pthread_setspecific(sTlsKey, NULL);
 			return NULL;
 		}
 		if (ctx->dd.config[idx] != NULL) {
-			mg_cry_internal(fc(ctx), "warning: %s: duplicate option", name);
+			mg_cry_ctx_internal(ctx, "warning: %s: duplicate option", name);
 			mg_free(ctx->dd.config[idx]);
 		}
 		ctx->dd.config[idx] = mg_strdup_ctx(value, ctx);
@@ -18564,7 +18586,7 @@ mg_start(const struct mg_callbacks *callbacks,
 	/* Request size option */
 	itmp = atoi(ctx->dd.config[MAX_REQUEST_SIZE]);
 	if (itmp < 1024) {
-		mg_cry_internal(fc(ctx), "%s", "max_request_size too small");
+		mg_cry_ctx_internal(ctx, "%s", "max_request_size too small");
 		free_context(ctx);
 		pthread_setspecific(sTlsKey, NULL);
 		return NULL;
@@ -18575,14 +18597,14 @@ mg_start(const struct mg_callbacks *callbacks,
 	workerthreadcount = atoi(ctx->dd.config[NUM_THREADS]);
 
 	if (workerthreadcount > MAX_WORKER_THREADS) {
-		mg_cry_internal(fc(ctx), "%s", "Too many worker threads");
+		mg_cry_ctx_internal(ctx, "%s", "Too many worker threads");
 		free_context(ctx);
 		pthread_setspecific(sTlsKey, NULL);
 		return NULL;
 	}
 
 	if (workerthreadcount <= 0) {
-		mg_cry_internal(fc(ctx), "%s", "Invalid number of worker threads");
+		mg_cry_ctx_internal(ctx, "%s", "Invalid number of worker threads");
 		free_context(ctx);
 		pthread_setspecific(sTlsKey, NULL);
 		return NULL;
@@ -18591,7 +18613,7 @@ mg_start(const struct mg_callbacks *callbacks,
 /* Document root */
 #if defined(NO_FILES)
 	if (ctx->dd.config[DOCUMENT_ROOT] != NULL) {
-		mg_cry_internal(fc(ctx), "%s", "Document root must not be set");
+		mg_cry_ctx_internal(ctx, "%s", "Document root must not be set");
 		free_context(ctx);
 		pthread_setspecific(sTlsKey, NULL);
 		return NULL;
@@ -18610,7 +18632,7 @@ mg_start(const struct mg_callbacks *callbacks,
 		lua_State *state = mg_prepare_lua_context_script(
 		    ctx->dd.config[LUA_BACKGROUND_SCRIPT], ctx, ebuf, sizeof(ebuf));
 		if (!state) {
-			mg_cry_internal(fc(ctx), "lua_background_script error: %s", ebuf);
+			mg_cry_ctx_internal(ctx, "lua_background_script error: %s", ebuf);
 			free_context(ctx);
 			pthread_setspecific(sTlsKey, NULL);
 			return NULL;
@@ -18657,9 +18679,9 @@ mg_start(const struct mg_callbacks *callbacks,
 	                                                   ctx);
 
 	if (ctx->worker_threadids == NULL) {
-		mg_cry_internal(fc(ctx),
-		                "%s",
-		                "Not enough memory for worker thread ID array");
+		mg_cry_ctx_internal(ctx,
+		                    "%s",
+		                    "Not enough memory for worker thread ID array");
 		free_context(ctx);
 		pthread_setspecific(sTlsKey, NULL);
 		return NULL;
@@ -18669,9 +18691,10 @@ mg_start(const struct mg_callbacks *callbacks,
 	                                          sizeof(struct mg_connection),
 	                                          ctx);
 	if (ctx->worker_connections == NULL) {
-		mg_cry_internal(fc(ctx),
-		                "%s",
-		                "Not enough memory for worker thread connection array");
+		mg_cry_ctx_internal(
+			ctx,
+			"%s",
+			"Not enough memory for worker thread connection array");
 		free_context(ctx);
 		pthread_setspecific(sTlsKey, NULL);
 		return NULL;
@@ -18684,9 +18707,9 @@ mg_start(const struct mg_callbacks *callbacks,
 	                           ctx->cfg_worker_threads,
 	                           ctx);
 	if (ctx->client_wait_events == NULL) {
-		mg_cry_internal(fc(ctx),
-		                "%s",
-		                "Not enough memory for worker event array");
+		mg_cry_ctx_internal(ctx,
+		                    "%s",
+		                    "Not enough memory for worker event array");
 		mg_free(ctx->worker_threadids);
 		free_context(ctx);
 		pthread_setspecific(sTlsKey, NULL);
@@ -18698,9 +18721,9 @@ mg_start(const struct mg_callbacks *callbacks,
 	                                   ctx->cfg_worker_threads,
 	                                   ctx);
 	if (ctx->client_socks == NULL) {
-		mg_cry_internal(fc(ctx),
-		                "%s",
-		                "Not enough memory for worker socket array");
+		mg_cry_ctx_internal(ctx,
+		                    "%s",
+		                    "Not enough memory for worker socket array");
 		mg_free(ctx->client_wait_events);
 		mg_free(ctx->worker_threadids);
 		free_context(ctx);
@@ -18711,7 +18734,7 @@ mg_start(const struct mg_callbacks *callbacks,
 	for (i = 0; (unsigned)i < ctx->cfg_worker_threads; i++) {
 		ctx->client_wait_events[i] = event_create();
 		if (ctx->client_wait_events[i] == 0) {
-			mg_cry_internal(fc(ctx), "Error creating worker event %i", i);
+			mg_cry_ctx_internal(ctx, "Error creating worker event %i", i);
 			while (i > 0) {
 				i--;
 				event_destroy(ctx->client_wait_events[i]);
@@ -18729,7 +18752,7 @@ mg_start(const struct mg_callbacks *callbacks,
 
 #if defined(USE_TIMERS)
 	if (timers_init(ctx) != 0) {
-		mg_cry_internal(fc(ctx), "%s", "Error creating timers");
+		mg_cry_ctx_internal(ctx, "%s", "Error creating timers");
 		free_context(ctx);
 		pthread_setspecific(sTlsKey, NULL);
 		return NULL;
@@ -18757,14 +18780,14 @@ mg_start(const struct mg_callbacks *callbacks,
 
 			/* thread was not created */
 			if (i > 0) {
-				mg_cry_internal(fc(ctx),
-				                "Cannot start worker thread %i: error %ld",
-				                i + 1,
-				                (long)ERRNO);
+				mg_cry_ctx_internal(ctx,
+				                    "Cannot start worker thread %i: error %ld",
+				                    i + 1,
+				                    (long)ERRNO);
 			} else {
-				mg_cry_internal(fc(ctx),
-				                "Cannot create threads: error %ld",
-				                (long)ERRNO);
+				mg_cry_ctx_internal(ctx,
+				                    "Cannot create threads: error %ld",
+				                    (long)ERRNO);
 				free_context(ctx);
 				pthread_setspecific(sTlsKey, NULL);
 				return NULL;
@@ -18805,16 +18828,16 @@ mg_start_domain(struct mg_context *ctx, const char **options)
 	/* Store options - TODO: unite duplicate code */
 	while (options && (name = *options++) != NULL) {
 		if ((idx = get_option_index(name)) == -1) {
-			mg_cry_internal(fc(ctx), "Invalid option: %s", name);
+			mg_cry_ctx_internal(ctx, "Invalid option: %s", name);
 			mg_free(new_dom);
 			return -2;
 		} else if ((value = *options++) == NULL) {
-			mg_cry_internal(fc(ctx), "%s: option value cannot be NULL", name);
+			mg_cry_ctx_internal(ctx, "%s: option value cannot be NULL", name);
 			mg_free(new_dom);
 			return -2;
 		}
 		if (new_dom->config[idx] != NULL) {
-			mg_cry_internal(fc(ctx), "warning: %s: duplicate option", name);
+			mg_cry_ctx_internal(ctx, "warning: %s: duplicate option", name);
 			mg_free(new_dom->config[idx]);
 		}
 		new_dom->config[idx] = mg_strdup_ctx(value, ctx);
@@ -18824,7 +18847,7 @@ mg_start_domain(struct mg_context *ctx, const char **options)
 	/* Authentication domain is mandatory */
 	/* TODO: Maybe use a new option hostname? */
 	if (!new_dom->config[AUTHENTICATION_DOMAIN]) {
-		mg_cry_internal(fc(ctx), "%s", "authentication domain required");
+		mg_cry_ctx_internal(ctx, "%s", "authentication domain required");
 		mg_free(new_dom);
 		return -4;
 	}
@@ -18863,9 +18886,9 @@ mg_start_domain(struct mg_context *ctx, const char **options)
 		if (!mg_strcasecmp(new_dom->config[AUTHENTICATION_DOMAIN],
 		                   dom->config[AUTHENTICATION_DOMAIN])) {
 			/* Domain collision */
-			mg_cry_internal(fc(ctx),
-			                "domain %s already in use",
-			                new_dom->config[AUTHENTICATION_DOMAIN]);
+			mg_cry_ctx_internal(ctx,
+			                    "domain %s already in use",
+			                    new_dom->config[AUTHENTICATION_DOMAIN]);
 			mg_free(new_dom);
 			return -5;
 		}

+ 6 - 2
src/mod_lua.inl

@@ -1780,14 +1780,18 @@ lua_action(struct laction_arg *arg)
 
 	err = luaL_loadstring(arg->state, arg->txt);
 	if (err != 0) {
-		lua_cry(fc(ctx), err, arg->state, arg->script, "timer");
+		struct mg_connection fc;
+		lua_cry(fake_connection(&fc, ctx), err, arg->state, arg->script,
+		        "timer");
 		(void)pthread_mutex_unlock(arg->pmutex);
 		mg_free(arg);
 		return 0;
 	}
 	err = lua_pcall(arg->state, 0, 1, 0);
 	if (err != 0) {
-		lua_cry(fc(ctx), err, arg->state, arg->script, "timer");
+		struct mg_connection fc;
+		lua_cry(fake_connection(&fc, ctx), err, arg->state, arg->script,
+		        "timer");
 		(void)pthread_mutex_unlock(arg->pmutex);
 		mg_free(arg);
 		return 0;