pooler/src/main.c

202 lines
5.3 KiB
C

// 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 <https://www.gnu.org/licenses/>.
*/
// clang-format on
#include <arpa/inet.h>
#include <errno.h>
#include <libmp/all.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#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;
}