|
@@ -183,13 +183,15 @@ _civet_clock_gettime(int clk_id, struct timespec *t)
|
|
|
|
|
|
/* if clock_gettime is declared, then __CLOCK_AVAILABILITY will be defined */
|
|
/* if clock_gettime is declared, then __CLOCK_AVAILABILITY will be defined */
|
|
#ifdef __CLOCK_AVAILABILITY
|
|
#ifdef __CLOCK_AVAILABILITY
|
|
-/* If we compiled with Mac OSX 10.12 or later, then clock_gettime will be declared
|
|
|
|
|
|
+/* If we compiled with Mac OSX 10.12 or later, then clock_gettime will be
|
|
|
|
+ * declared
|
|
* but it may be NULL at runtime. So we need to check before using it. */
|
|
* but it may be NULL at runtime. So we need to check before using it. */
|
|
int _civet_safe_clock_gettime(int clk_id, struct timespec *t);
|
|
int _civet_safe_clock_gettime(int clk_id, struct timespec *t);
|
|
|
|
|
|
int
|
|
int
|
|
-_civet_safe_clock_gettime(int clk_id, struct timespec *t) {
|
|
|
|
- if( clock_gettime ) {
|
|
|
|
|
|
+_civet_safe_clock_gettime(int clk_id, struct timespec *t)
|
|
|
|
+{
|
|
|
|
+ if (clock_gettime) {
|
|
return clock_gettime(clk_id, t);
|
|
return clock_gettime(clk_id, t);
|
|
}
|
|
}
|
|
return _civet_clock_gettime(clk_id, t);
|
|
return _civet_clock_gettime(clk_id, t);
|
|
@@ -10714,12 +10716,21 @@ close_all_listening_sockets(struct mg_context *ctx)
|
|
|
|
|
|
|
|
|
|
/* Valid listening port specification is: [ip_address:]port[s]
|
|
/* Valid listening port specification is: [ip_address:]port[s]
|
|
- * Examples for IPv4: 80, 443s, 127.0.0.1:3128, 1.2.3.4:8080s
|
|
|
|
|
|
+ * Examples for IPv4: 80, 443s, 127.0.0.1:3128, 192.0.2.3:8080s
|
|
* Examples for IPv6: [::]:80, [::1]:80,
|
|
* Examples for IPv6: [::]:80, [::1]:80,
|
|
- * [FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:443s
|
|
|
|
- * see https://tools.ietf.org/html/rfc3513#section-2.2 */
|
|
|
|
|
|
+ * [2001:0db8:7654:3210:FEDC:BA98:7654:3210]:443s
|
|
|
|
+ * see https://tools.ietf.org/html/rfc3513#section-2.2
|
|
|
|
+ * In order to bind to both, IPv4 and IPv6, you can either add
|
|
|
|
+ * both ports using 8080,[::]:8080, or the short form +8080.
|
|
|
|
+ * Both forms differ in detail: 8080,[::]:8080 create two sockets,
|
|
|
|
+ * one only accepting IPv4 the other only IPv6. +8080 creates
|
|
|
|
+ * one socket accepting IPv4 and IPv6. Depending on the IPv6
|
|
|
|
+ * environment, they might work differently, or might not work
|
|
|
|
+ * at all - it must be tested what options work best in the
|
|
|
|
+ * relevant network environment.
|
|
|
|
+ */
|
|
static int
|
|
static int
|
|
-parse_port_string(const struct vec *vec, struct socket *so)
|
|
|
|
|
|
+parse_port_string(const struct vec *vec, struct socket *so, int *ip_version)
|
|
{
|
|
{
|
|
unsigned int a, b, c, d, port;
|
|
unsigned int a, b, c, d, port;
|
|
int ch, len;
|
|
int ch, len;
|
|
@@ -10732,6 +10743,7 @@ parse_port_string(const struct vec *vec, struct socket *so)
|
|
* for both IPv4 and IPv6 (INADDR_ANY and IN6ADDR_ANY_INIT). */
|
|
* for both IPv4 and IPv6 (INADDR_ANY and IN6ADDR_ANY_INIT). */
|
|
memset(so, 0, sizeof(*so));
|
|
memset(so, 0, sizeof(*so));
|
|
so->lsa.sin.sin_family = AF_INET;
|
|
so->lsa.sin.sin_family = AF_INET;
|
|
|
|
+ *ip_version = 0;
|
|
|
|
|
|
if (sscanf(vec->ptr, "%u.%u.%u.%u:%u%n", &a, &b, &c, &d, &port, &len)
|
|
if (sscanf(vec->ptr, "%u.%u.%u.%u:%u%n", &a, &b, &c, &d, &port, &len)
|
|
== 5) {
|
|
== 5) {
|
|
@@ -10739,6 +10751,8 @@ parse_port_string(const struct vec *vec, struct socket *so)
|
|
so->lsa.sin.sin_addr.s_addr =
|
|
so->lsa.sin.sin_addr.s_addr =
|
|
htonl((a << 24) | (b << 16) | (c << 8) | d);
|
|
htonl((a << 24) | (b << 16) | (c << 8) | d);
|
|
so->lsa.sin.sin_port = htons((uint16_t)port);
|
|
so->lsa.sin.sin_port = htons((uint16_t)port);
|
|
|
|
+ *ip_version = 4;
|
|
|
|
+
|
|
#if defined(USE_IPV6)
|
|
#if defined(USE_IPV6)
|
|
} else if (sscanf(vec->ptr, "[%49[^]]]:%u%n", buf, &port, &len) == 2
|
|
} else if (sscanf(vec->ptr, "[%49[^]]]:%u%n", buf, &port, &len) == 2
|
|
&& mg_inet_pton(
|
|
&& mg_inet_pton(
|
|
@@ -10747,10 +10761,29 @@ parse_port_string(const struct vec *vec, struct socket *so)
|
|
/* so->lsa.sin6.sin6_family = AF_INET6; already set by mg_inet_pton
|
|
/* so->lsa.sin6.sin6_family = AF_INET6; already set by mg_inet_pton
|
|
*/
|
|
*/
|
|
so->lsa.sin6.sin6_port = htons((uint16_t)port);
|
|
so->lsa.sin6.sin6_port = htons((uint16_t)port);
|
|
|
|
+ *ip_version = 6;
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+ } else if ((vec->ptr[0] == '+')
|
|
|
|
+ && (sscanf(vec->ptr + 1, "%u%n", &port, &len) == 1)) {
|
|
|
|
+/* Port is specified with a +, bind to IPv6 and IPv4, INADDR_ANY */
|
|
|
|
+
|
|
|
|
+#if defined(USE_IPV6)
|
|
|
|
+ /* Set socket family to IPv6, do not use IPV6_V6ONLY */
|
|
|
|
+ so->lsa.sin6.sin6_family = AF_INET6;
|
|
|
|
+ so->lsa.sin6.sin6_port = htons((uint16_t)port);
|
|
|
|
+ *ip_version = 4 + 6;
|
|
|
|
+#else
|
|
|
|
+ /* Bind to IPv4 only, since IPv6 is not built in. */
|
|
|
|
+ so->lsa.sin.sin_port = htons((uint16_t)port);
|
|
|
|
+ *ip_version = 4;
|
|
#endif
|
|
#endif
|
|
|
|
+
|
|
} else if (sscanf(vec->ptr, "%u%n", &port, &len) == 1) {
|
|
} else if (sscanf(vec->ptr, "%u%n", &port, &len) == 1) {
|
|
/* If only port is specified, bind to IPv4, INADDR_ANY */
|
|
/* If only port is specified, bind to IPv4, INADDR_ANY */
|
|
so->lsa.sin.sin_port = htons((uint16_t)port);
|
|
so->lsa.sin.sin_port = htons((uint16_t)port);
|
|
|
|
+ *ip_version = 4;
|
|
|
|
+
|
|
} else {
|
|
} else {
|
|
/* Parsing failure. Make port invalid. */
|
|
/* Parsing failure. Make port invalid. */
|
|
port = 0;
|
|
port = 0;
|
|
@@ -10786,6 +10819,7 @@ set_ports_option(struct mg_context *ctx)
|
|
struct pollfd *pfd;
|
|
struct pollfd *pfd;
|
|
union usa usa;
|
|
union usa usa;
|
|
socklen_t len;
|
|
socklen_t len;
|
|
|
|
+ int ip_version;
|
|
|
|
|
|
int portsTotal = 0;
|
|
int portsTotal = 0;
|
|
int portsOk = 0;
|
|
int portsOk = 0;
|
|
@@ -10798,11 +10832,12 @@ set_ports_option(struct mg_context *ctx)
|
|
memset(&usa, 0, sizeof(usa));
|
|
memset(&usa, 0, sizeof(usa));
|
|
len = sizeof(usa);
|
|
len = sizeof(usa);
|
|
list = ctx->config[LISTENING_PORTS];
|
|
list = ctx->config[LISTENING_PORTS];
|
|
|
|
+
|
|
while ((list = next_option(list, &vec, NULL)) != NULL) {
|
|
while ((list = next_option(list, &vec, NULL)) != NULL) {
|
|
|
|
|
|
portsTotal++;
|
|
portsTotal++;
|
|
|
|
|
|
- if (!parse_port_string(&vec, &so)) {
|
|
|
|
|
|
+ if (!parse_port_string(&vec, &so, &ip_version)) {
|
|
mg_cry(fc(ctx),
|
|
mg_cry(fc(ctx),
|
|
"%.*s: invalid port spec (entry %i). Expecting list of: %s",
|
|
"%.*s: invalid port spec (entry %i). Expecting list of: %s",
|
|
(int)vec.len,
|
|
(int)vec.len,
|
|
@@ -10846,6 +10881,7 @@ set_ports_option(struct mg_context *ctx)
|
|
(SOCK_OPT_TYPE)&on,
|
|
(SOCK_OPT_TYPE)&on,
|
|
sizeof(on)) != 0) {
|
|
sizeof(on)) != 0) {
|
|
|
|
|
|
|
|
+ /* Set reuse option, but don't abort on errors. */
|
|
mg_cry(fc(ctx),
|
|
mg_cry(fc(ctx),
|
|
"cannot set socket option SO_EXCLUSIVEADDRUSE (entry %i)",
|
|
"cannot set socket option SO_EXCLUSIVEADDRUSE (entry %i)",
|
|
portsTotal);
|
|
portsTotal);
|
|
@@ -10857,25 +10893,36 @@ set_ports_option(struct mg_context *ctx)
|
|
(SOCK_OPT_TYPE)&on,
|
|
(SOCK_OPT_TYPE)&on,
|
|
sizeof(on)) != 0) {
|
|
sizeof(on)) != 0) {
|
|
|
|
|
|
|
|
+ /* Set reuse option, but don't abort on errors. */
|
|
mg_cry(fc(ctx),
|
|
mg_cry(fc(ctx),
|
|
"cannot set socket option SO_REUSEADDR (entry %i)",
|
|
"cannot set socket option SO_REUSEADDR (entry %i)",
|
|
portsTotal);
|
|
portsTotal);
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
+ if (ip_version > 4) {
|
|
#if defined(USE_IPV6)
|
|
#if defined(USE_IPV6)
|
|
- if (so.lsa.sa.sa_family == AF_INET6
|
|
|
|
- && setsockopt(so.sock,
|
|
|
|
- IPPROTO_IPV6,
|
|
|
|
- IPV6_V6ONLY,
|
|
|
|
- (void *)&off,
|
|
|
|
- sizeof(off)) != 0) {
|
|
|
|
-
|
|
|
|
- mg_cry(fc(ctx),
|
|
|
|
- "cannot set socket option IPV6_V6ONLY (entry %i)",
|
|
|
|
- portsTotal);
|
|
|
|
- }
|
|
|
|
|
|
+ if (ip_version == 6) {
|
|
|
|
+ if (so.lsa.sa.sa_family == AF_INET6
|
|
|
|
+ && setsockopt(so.sock,
|
|
|
|
+ IPPROTO_IPV6,
|
|
|
|
+ IPV6_V6ONLY,
|
|
|
|
+ (void *)&off,
|
|
|
|
+ sizeof(off)) != 0) {
|
|
|
|
+
|
|
|
|
+ /* Set IPv6 only option, but don't abort on errors. */
|
|
|
|
+ mg_cry(fc(ctx),
|
|
|
|
+ "cannot set socket option IPV6_V6ONLY (entry %i)",
|
|
|
|
+ portsTotal);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+#else
|
|
|
|
+ mg_cry(fc(ctx), "IPv6 not available");
|
|
|
|
+ closesocket(so.sock);
|
|
|
|
+ so.sock = INVALID_SOCKET;
|
|
|
|
+ continue;
|
|
#endif
|
|
#endif
|
|
|
|
+ }
|
|
|
|
|
|
if (so.lsa.sa.sa_family == AF_INET) {
|
|
if (so.lsa.sa.sa_family == AF_INET) {
|
|
|
|
|