Merge remote-tracking branch 'github-pull/77/head'

This commit is contained in:
Luke Dashjr 2025-03-10 18:02:30 +00:00
commit 9166d3c835
No known key found for this signature in database
GPG Key ID: A291A2C45D0C504A
5 changed files with 101 additions and 34 deletions

View File

@ -1163,7 +1163,7 @@ enum MHD_Result datum_api_answer(void *cls, struct MHD_Connection *connection, c
return ret;
}
static struct MHD_Daemon *datum_api_try_start(unsigned int flags) {
static struct MHD_Daemon *datum_api_try_start(unsigned int flags, const int sock) {
flags |= MHD_USE_AUTO; // event loop API
flags |= MHD_USE_INTERNAL_POLLING_THREAD;
return MHD_start_daemon(
@ -1171,6 +1171,7 @@ static struct MHD_Daemon *datum_api_try_start(unsigned int flags) {
datum_config.api_listen_port,
NULL, NULL, // accept policy filter
&datum_api_answer, NULL, // default URI handler
MHD_OPTION_LISTEN_SOCKET, sock,
MHD_OPTION_CONNECTION_LIMIT, 128,
MHD_OPTION_NOTIFY_COMPLETED, datum_api_request_completed, NULL,
MHD_OPTION_LISTENING_ADDRESS_REUSE, (unsigned int)1,
@ -1185,8 +1186,13 @@ void *datum_api_thread(void *ptr) {
return NULL;
}
daemon = datum_api_try_start(MHD_USE_DUAL_STACK);
if (!daemon) daemon = datum_api_try_start(0);
int listen_socks[1];
size_t listen_socks_len = 1;
if (!datum_sockets_setup_listening_sockets("API", datum_config.api_listen_addr, datum_config.api_listen_port, listen_socks, &listen_socks_len)) {
return NULL;
}
daemon = datum_api_try_start(0, listen_socks[0]);
if (!daemon) {
DLOG_FATAL("Unable to start daemon for API");
@ -1194,7 +1200,7 @@ void *datum_api_thread(void *ptr) {
return NULL;
}
DLOG_INFO("API listening on port %d", datum_config.api_listen_port);
DLOG_INFO("API listening on address %s port %d", datum_config.api_listen_addr[0] ? datum_config.api_listen_addr : "(any)", datum_config.api_listen_port);
while(1) {
sleep(3);

View File

@ -67,6 +67,8 @@ const T_DATUM_CONFIG_ITEM datum_config_options[] = {
.required = false, .ptr = &datum_config.bitcoind_notify_fallback, .default_bool = true },
// stratum v1 server configs
{ .var_type = DATUM_CONF_STRING, .category = "stratum", .name = "listen_addr", .description = "IP address to listen for Stratum Gateway connections",
.required = false, .ptr = datum_config.stratum_v1_listen_addr, .default_string[0] = "", .max_string_len = sizeof(datum_config.stratum_v1_listen_addr) },
{ .var_type = DATUM_CONF_INT, .category = "stratum", .name = "listen_port", .description = "Listening port for Stratum Gateway",
.required = false, .ptr = &datum_config.stratum_v1_listen_port, .default_int = 23334 },
{ .var_type = DATUM_CONF_INT, .category = "stratum", .name = "max_clients_per_thread", .description = "Maximum clients per Stratum server thread",
@ -109,6 +111,8 @@ const T_DATUM_CONFIG_ITEM datum_config_options[] = {
// API/dashboard
{ .var_type = DATUM_CONF_STRING, .category = "api", .name = "admin_password", .description = "API password for actions/changes (username 'admin'; disabled if blank)",
.required = false, .ptr = datum_config.api_admin_password, .default_string[0] = "", .max_string_len = sizeof(datum_config.api_admin_password) },
{ .var_type = DATUM_CONF_STRING, .category = "api", .name = "listen_addr", .description = "IP address to listen for API/dashboard requests",
.required = false, .ptr = datum_config.api_listen_addr, .default_string[0] = "", .max_string_len = sizeof(datum_config.api_listen_addr) },
{ .var_type = DATUM_CONF_INT, .category = "api", .name = "listen_port", .description = "Port to listen for API/dashboard requests (0=disabled)",
.required = false, .ptr = &datum_config.api_listen_port, .default_int = 0 },

View File

@ -78,6 +78,7 @@ typedef struct {
int bitcoind_work_update_seconds;
bool bitcoind_notify_fallback;
char stratum_v1_listen_addr[128];
int stratum_v1_listen_port;
int stratum_v1_max_clients;
int stratum_v1_max_threads;
@ -102,6 +103,7 @@ typedef struct {
char api_admin_password[64];
size_t api_admin_password_len;
char api_csrf_token[65];
char api_listen_addr[128];
int api_listen_port;
int extra_block_submissions_count;

View File

@ -33,11 +33,14 @@
*
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <sys/epoll.h>
@ -560,6 +563,84 @@ const char *datum_sockets_setup_listen_sock(const int listen_sock, const struct
return NULL;
}
bool datum_sockets_setup_listening_sockets(const char * const purpose, const char * const addr, const uint16_t port, int * const out_socks, size_t * const inout_socks_n) {
assert(*inout_socks_n > 0);
if (addr && addr[0]) {
char port_str[6];
snprintf(port_str, sizeof(port_str), "%u", (unsigned int)port);
const struct addrinfo hints = {
.ai_family = AF_UNSPEC,
.ai_socktype = SOCK_STREAM,
.ai_protocol = 0,
.ai_flags = AI_PASSIVE | AI_NUMERICHOST | AI_NUMERICSERV,
};
struct addrinfo *res;
int err = getaddrinfo(addr, port_str, &hints, &res);
if (err) {
DLOG_FATAL("Failed to resolve listen address '%s' (%s): %s", purpose, addr, gai_strerror(err));
panic_from_thread(__LINE__);
return false;
}
*out_socks = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
const char *errstr = datum_sockets_setup_listen_sock(*out_socks, res->ai_addr, res->ai_addrlen);
const int errno_saved = errno;
freeaddrinfo(res);
if (errstr) {
DLOG_FATAL("%s (%s): %s", errstr, purpose, strerror(errno_saved));
panic_from_thread(__LINE__);
return false;
}
*inout_socks_n = 1;
} else {
const struct sockaddr_in6 anyaddr6 = {
.sin6_family = AF_INET6,
.sin6_port = htons(port),
.sin6_addr = IN6ADDR_ANY_INIT,
};
out_socks[0] = socket(AF_INET6, SOCK_STREAM, 0);
#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
if (out_socks[0] != -1) {
static const int zero = 0;
setsockopt(out_socks[0], IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero));
}
#endif
const char * const errstr6 = datum_sockets_setup_listen_sock(out_socks[0], (const struct sockaddr *)&anyaddr6, sizeof(anyaddr6));
const int errno6 = errno;
unsigned int socks_n = 1;
if (errstr6 && out_socks[0] != -1) {
close(out_socks[0]);
out_socks[0] = -1;
--socks_n;
}
if (*inout_socks_n > socks_n) {
const struct sockaddr_in anyaddr4 = {
.sin_family = AF_INET,
.sin_port = htons(port),
.sin_addr.s_addr = INADDR_ANY,
};
out_socks[socks_n] = socket(AF_INET, SOCK_STREAM, 0);
const char *errstr = datum_sockets_setup_listen_sock(out_socks[socks_n], (const struct sockaddr *)&anyaddr4, sizeof(anyaddr4));
if (errstr && errstr6) {
const int errno4 = errno;
DLOG_FATAL("%s (IPv6): %s", errstr6, strerror(errno6));
DLOG_FATAL("%s (IPv4): %s", errstr, strerror(errno4));
panic_from_thread(__LINE__);
return false;
}
if (errstr && out_socks[socks_n] != -1) {
close(out_socks[socks_n]);
out_socks[socks_n] = -1;
} else {
++socks_n;
}
}
*inout_socks_n = socks_n;
}
return true;
}
void *datum_gateway_listener_thread(void *arg) {
int i, ret;
bool rejecting_now = false;
@ -577,7 +658,7 @@ void *datum_gateway_listener_thread(void *arg) {
return NULL;
}
DLOG_DEBUG("Setting up app '%s' on port %d. (T:%d/TC:%d/C:%d)", app->name, app->listen_port, app->max_threads, app->max_clients_thread, app->max_clients);
DLOG_DEBUG("Setting up app '%s' on address %s port %d. (T:%d/TC:%d/C:%d)", app->name, datum_config.stratum_v1_listen_addr[0] ? datum_config.stratum_v1_listen_addr : "(any)", app->listen_port, app->max_threads, app->max_clients_thread, app->max_clients);
// we assume the caller sets up the thread data in some way
// don't clobber those pointers
@ -598,37 +679,10 @@ void *datum_gateway_listener_thread(void *arg) {
app->datum_active_threads = 0;
const struct sockaddr_in6 anyaddr6 = {
.sin6_family = AF_INET6,
.sin6_port = htons(app->listen_port),
.sin6_addr = IN6ADDR_ANY_INIT,
};
listen_socks[0] = socket(AF_INET6, SOCK_STREAM, 0);
const char * const errstr6 = datum_sockets_setup_listen_sock(listen_socks[0], (const struct sockaddr *)&anyaddr6, sizeof(anyaddr6));
const int errno6 = errno;
if (errstr6 && listen_socks[0] != -1) {
close(listen_socks[0]);
listen_socks[0] = -1;
}
const struct sockaddr_in anyaddr4 = {
.sin_family = AF_INET,
.sin_port = htons(app->listen_port),
.sin_addr.s_addr = INADDR_ANY,
};
listen_socks[1] = socket(AF_INET, SOCK_STREAM, 0);
const char *errstr = datum_sockets_setup_listen_sock(listen_socks[1], (const struct sockaddr *)&anyaddr4, sizeof(anyaddr4));
if (errstr && errstr6) {
const int errno4 = errno;
DLOG_FATAL("%s (IPv6): %s", errstr6, strerror(errno6));
DLOG_FATAL("%s (IPv4): %s", errstr, strerror(errno4));
panic_from_thread(__LINE__);
size_t listen_socks_len = 2;
if (!datum_sockets_setup_listening_sockets("stratum", datum_config.stratum_v1_listen_addr, app->listen_port, listen_socks, &listen_socks_len)) {
return NULL;
}
if (errstr && listen_socks[1] != -1) {
close(listen_socks[1]);
listen_socks[1] = -1;
}
epollfd = epoll_create1(0);
if (epollfd < 0) {

View File

@ -161,6 +161,7 @@ typedef struct T_DATUM_THREAD_DATA {
void *app_thread_data;
} T_DATUM_THREAD_DATA;
bool datum_sockets_setup_listening_sockets(const char *purpose, const char *addr, uint16_t port, int *out_socks, size_t *inout_socks_n);
void *datum_gateway_listener_thread(void *arg);
void datum_socket_setoptions(int sock);