// clang-format off /* * pooler | MatterLinux pool server * MatterLinux 2023-2024 (https://matterlinux.xyz) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ // clang-format on #include #include #include #include #include #include #include #include "config.h" #include "intl.h" #include "log.h" #include "util.h" void sockaddr_to_str(struct sockaddr *addr, char *str) { struct sockaddr_in *ipv4; struct sockaddr_in6 *ipv6; switch (addr->sa_family) { case AF_INET: ipv4 = (struct sockaddr_in *)addr; inet_ntop(AF_INET, &ipv4->sin_addr, str, INET_ADDRSTRLEN); break; case AF_INET6: ipv6 = (struct sockaddr_in6 *)addr; inet_ntop(AF_INET6, &ipv6->sin6_addr, str, INET6_ADDRSTRLEN); break; } } bool sync_callback( lm_ctx_t *ctx, lm_pool_t *pool, lm_ctx_sync_state_t state, size_t current, size_t total, void *data) { switch (state) { case SYNC_INFO_SUCCESS: info(_("%s: successfuly loaded the pool info"), pool->name); break; case SYNC_INFO_FAIL: info(_("%s: failed to load the pool info (%s)"), pool->name, lm_strerror()); return false; case SYNC_LIST_SUCCESS: info(_("%s: successfuly loaded the package list"), pool->name); break; case SYNC_LIST_FAIL: info(_("%s: failed to load the package list (%s)"), pool->name, lm_strerror()); return false; default: // ignore other callbacks break; } return true; } bool serve_callback(lm_pool_t *pool, lm_mptp_t *packet, struct sockaddr *addr, void *data) { char ipaddr[INET6_ADDRSTRLEN]; bzero(ipaddr, sizeof(ipaddr)); sockaddr_to_str(addr, ipaddr); switch (MPTP_FLAGS_CODE(packet)) { case MPTP_C2S_PING: info(_("Request from %s: PING (%s)"), ipaddr, pool->name); break; case MPTP_C2S_INFO: info(_("Request from %s: INFO (%s)"), ipaddr, pool->name); break; case MPTP_C2S_LIST: info(_("Request from %s: LIST (%s)"), ipaddr, pool->name); break; case MPTP_C2S_PULL: info(_("Request from %s: PULL (%s)"), ipaddr, pool->name); break; } return true; } int main(int argc, char *argv[]) { setbuf(stdout, NULL); // disable buffering so docker-compose logs works correctly info(_("Starting pooler %s (libmp %s)"), VERSION, LM_VERSION); if (argc != 2) { error(_("Configuration file not specified")); return EXIT_FAILURE; } char *addr = NULL, *logfile = NULL, *tmpdir = NULL; int ret = EXIT_FAILURE; pool_config_t *pool = NULL; size_t pool_count = 0; lm_ctx_t ctx; if (!config_load(argv[1])) goto end_config; info(_("Loaded the configuration")); if ((tmpdir = config_get_string("tmpdir")) == NULL) { error(_("Failed to get the temp directory configuration option (tmpdir)")); goto end_config; } lm_ctx_new(&ctx, NULL, tmpdir, NULL); addr = config_get_string("addr"); if (config_get_integer("threads") <= 0 || config_get_integer("threads") > 1000) { error(_("Please specify a valid thread count (1-1000)")); goto end_ctx; } if ((pool = config.pools) == NULL) { error(_("Please specify at least one pool in the configuration")); goto end_ctx; } while (NULL != pool) { info(_("%s: loading the pool"), pool->name); if (NULL == pool->host) { error(_("%s: hostname not specified for pool, skipping"), pool->name); goto end_ctx; } char url[strlen(pool->host) + 20 + (pool->path == NULL ? 0 : strlen(pool->path))]; if (NULL == pool->path) sprintf(url, "mptp://%s/", pool->host); else if (pool->path[0] == '/') sprintf(url, "mptp://%s%s", pool->host, pool->path); else sprintf(url, "mptp://%s/%s", pool->host, pool->path); if (!file_canread(pool->dir)) { error(_("%s: failed access the pool directory (%s)"), pool->name, pool->dir); goto end_ctx; } if (NULL == lm_ctx_pool_add(&ctx, pool->name, url, pool->dir)) { error(_("%s: failed to add pool to the list (%s)"), pool->name, lm_strerror()); goto end_ctx; } pool = pool->next; } if ((pool_count = lm_ctx_sync(&ctx, false, sync_callback, NULL)) < 0) { error(_("Failed to sync the pools: %s"), lm_strerror()); goto end_ctx; } if (pool_count == 0) { error(_("None of the pools is available for serving")); goto end_ctx; } info(pool_count == 1 ? _("Serving %lu pool on %s") : _("Serving %lu pools on %s"), pool_count, addr); if (!lm_ctx_serve(&ctx, addr, config_get_integer("threads"), NULL, serve_callback, NULL)) { error(_("Failed to start the server: %s"), lm_strerror()); goto end_ctx; } ret = EXIT_SUCCESS; end_ctx: lm_ctx_free(&ctx); end_config: config_free(); return ret; }