// swarmd — a generic swarm daemon.
//
// swarmd --socket <path> [--bootstrap host:port] [--storage <dir>]
//
// Omit --bootstrap to use the public DHT. Omit --storage and the content plane
// stays off — content commands are then refused, which is a better answer than
// accepting a fetch that has nowhere to put a file.
#include <csignal>
#include <cstdio>
#include <cstring>
#include <sodium.h>
#include <string>
#include <unistd.h>
#include "daemon.h"
// ⛔ A DAEMON MUST NAME ITS OWN PROCESS. Without this the only way to stop one
// is to match its command line, and a pattern that matches a daemon's argv also
// matches the shell that typed it — `pkill -f` killed an ssh session's own
// remote shell twice in this project. The pidfile sits beside the socket, so
// whoever can reach the socket can stop exactly the process behind it.
static void write_pidfile(const std::string &socket_path) {
FILE *f = fopen((socket_path + ".pid").c_str(), "w");
if (!f) return; // diagnostics, never a blocker
fprintf(f, "%ld\n", (long)getpid());
fclose(f);
}
static void remove_pidfile(const std::string &socket_path) {
::unlink((socket_path + ".pid").c_str());
}
static volatile sig_atomic_t g_stop = 0;
static void on_signal(int) { g_stop = 1; }
int main(int argc, char **argv) {
if (sodium_init() < 0) {
fprintf(stderr, "sodium_init failed\n");
return 1;
}
const char *sock = nullptr;
const char *bootstrap = nullptr;
const char *storage = nullptr;
for (int i = 1; i < argc; i++) {
if (!strcmp(argv[i], "--socket") && i + 1 < argc) sock = argv[++i];
else if (!strcmp(argv[i], "--bootstrap") && i + 1 < argc) bootstrap = argv[++i];
else if (!strcmp(argv[i], "--storage") && i + 1 < argc) storage = argv[++i];
}
if (!sock) {
fprintf(stderr, "usage: swarmd --socket <path> [--bootstrap host:port] "
"[--storage <dir>]\n");
return 1;
}
signal(SIGINT, on_signal);
signal(SIGTERM, on_signal);
swarmd::Daemon d;
if (!d.start(sock, bootstrap, storage)) {
fprintf(stderr, "failed to start (socket %s)\n", sock);
return 1;
}
write_pidfile(sock);
printf("[swarmd] listening on %s (pid %ld)\n", sock, (long)getpid());
fflush(stdout);
// ⛔ SAY WHETHER THE SWARM IS REACHABLE, not just whether we started.
// "listening" is a LOCAL fact. Two peers once sat on one topic for ten
// minutes both reporting success while neither had ever bootstrapped.
int ticks = 0;
int last_peers = -1;
bool last_boot = false;
while (!g_stop) {
d.poll(200);
const bool boot = d.dht_bootstrapped();
const int peers = d.peers();
if (boot != last_boot || peers != last_peers || (ticks % 25) == 0) {
printf("[swarmd] dht=%s peers=%d local=%d\n",
boot ? "up" : (d.dht_active() ? "connecting" : "starting"),
peers, d.local_clients());
fflush(stdout);
last_boot = boot;
last_peers = peers;
}
ticks++;
}
printf("[swarmd] stopping\n");
d.stop();
remove_pidfile(sock);
return 0;
}