#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <error.h>
#include <fcntl.h>
#include <signal.h>
#include <poll.h>
#include <sys/time.h>
#define S0(x) (x ? x : "")
#define TORRENT_USERDATA struct dht * dht;
#define DHT_USERDATA struct pollfd ** pollfds; size_t * pollfds_size; nfds_t * nfds;
#include <dht.c>
#define DISCONNECTION_MIXIN_BOTTOM if (t->dl->flags & goodmeta) t->type &= ~(info | peers);
#include <tcp.c>
int samomor = 0;
int periodično = 0;
int sigusr1 = 0;
void handler (int s) {
switch (s) {
case SIGINT:
case SIGTERM:
samomor++;
break;
case SIGALRM:
periodično++;
break;
case SIGUSR1:
sigusr1++;
break;
}
}
time_t last_added = 0;
void found_torrent (struct dht * d __attribute__((unused)), const unsigned char * h, struct torrent * t) {
char buf[128];
bin2hex(buf, h, 20);
buf[40] = '\0';
struct stat statbuf;
strcat(buf, ".torrent");
if (!stat(buf, &statbuf)) {
L(expected, d, "%s already exists", buf);
return;
}
L(debug, d, "%s%s", buf, t ? " stored" : " new");
if (t) {
if (!t->type)
t->ttl = seconds()+256;
t->type |= info | peers;
} else {
if (last_added + 2 > seconds()) {
L(debug, d, "not adding a torrent this fast");
return;
}
last_added = seconds();
t = torrent_init();
memcpy(t->hash, h, 20);
t->type |= info | peers;
t->ttl = seconds()+256;
add_torrent(d, t);
}
}
int main (int argc, char ** argv) {
size_t pollfds_size = 1;
nfds_t nfds = 1;
struct pollfd * pollfds = NULL;
int r = 0;
struct dht * dht = NULL;
char * cfr = NULL;
struct bencoding * config = NULL;
struct sigaction sigact = {
.sa_handler = handler,
.sa_flags = SA_RESTART
};
if (sigaction(SIGALRM, &sigact, NULL) == -1)
error_at_line(1, errno, __FILE__, __LINE__, "sigaction(SIGALRM)");
if (sigaction(SIGINT, &sigact, NULL) == -1)
error_at_line(2, errno, __FILE__, __LINE__, "sigaction(SIGINT)");
if (sigaction(SIGTERM, &sigact, NULL) == -1)
error_at_line(3, errno, __FILE__, __LINE__, "sigaction(SIGTERM)");
if (sigaction(SIGUSR1, &sigact, NULL) == -1)
error_at_line(4, errno, __FILE__, __LINE__, "sigaction(SIGUSR1)");
sigset_t sigset;
if (sigemptyset(&sigset) == -1)
error_at_line(5, errno, __FILE__, __LINE__, "sigemptyset");
if (sigaddset(&sigset, SIGUSR1) == -1)
error_at_line(6, errno, __FILE__, __LINE__, "sigaddset(SIGUSR1)");
if (sigaddset(&sigset, SIGALRM) == -1)
error_at_line(7, errno, __FILE__, __LINE__, "sigaddset(SIGALRM)");
if (sigaddset(&sigset, SIGTERM) == -1)
error_at_line(8, errno, __FILE__, __LINE__, "sigaddset(SIGTERM)");
if (sigprocmask(SIG_UNBLOCK, &sigset, NULL) == -1)
error_at_line(9, errno, __FILE__, __LINE__, "sigprocmask");
struct itimerval itimerval = {
.it_interval = {
.tv_sec = PERIODIC
},
.it_value = {
.tv_sec = PERIODIC
}
};
if (setitimer(ITIMER_REAL, &itimerval, NULL) == -1)
error_at_line(9, errno, __FILE__, __LINE__, "setitimer");
if (argc != 1+1)
error_at_line(10, 0, __FILE__, __LINE__, "%s configfile.ben", S0(argv[0]));
int cf = open(argv[1], O_RDWR | O_CLOEXEC | O_CREAT, 00664);
if (cf == -1)
error_at_line(11, errno, __FILE__, __LINE__, "open(%s)", argv[1]);
struct stat statbuf;
if (fstat(cf, &statbuf) == -1) {
error_at_line(0, errno, __FILE__, __LINE__, "fstat(cf, &statbuf)");
r = 12;
goto r;
}
if (statbuf.st_size && !(cfr = mmap(NULL, statbuf.st_size, PROT_READ, MAP_SHARED, cf, 0))) {
error_at_line(0, errno, __FILE__, __LINE__, "mmap(NULL, %ld, PROT_READ, MAP_SHARED, cf, 0)", statbuf.st_size);
r = 13;
goto r;
}
config = bdecode(cfr, statbuf.st_size, replace);
dht = dht_init(config);
free_bencoding(config);
config = NULL;
dht->possible_torrent = found_torrent;
dht->connection = connection;
pollfds = malloc(sizeof *pollfds);
pollfds[0].fd = dht->socket;
pollfds[0].events = POLLIN;
dht->pollfds = &pollfds;
dht->pollfds_size = &pollfds_size;
dht->nfds = &nfds;
dht->verbosity |= (getenv("TRAVNIK_INCOMING_DHT") ? incoming_dht : 0) | (getenv("TRAVNIK_OUTGOING_DHT") ? outgoing_dht : 0) | expected | debug;
dht->torrents_max = K;
dht->peers_per_torrent_max = K;
struct torrent * torrent = torrent_init();
memcpy(torrent->hash, "\xdd\x82\x55\xec\xdc\x7c\xa5\x5f\xb0\xbb\xf8\x13\x23\xd8\x70\x62\xdb\x1f\x6d\x1c", 20);
torrent->type = /* (useless, since we have no listening system yet) announce | */ peers | info;
torrent->ttl = seconds()+128; /**< idk, enough to bootstrap i guess */
add_torrent(dht, torrent);
periodic(dht);
// alarm(PERIODIC);
w:
while (poll(pollfds, nfds, -1) != -1) { // can't timeout
if (sigusr1) {
sigusr1 = 0;
dht_print(stdout, dht);
fflush(stdout);
goto w;
}
if (periodično) {
periodično = 0;
// alarm(PERIODIC);
periodic(dht);
goto w;
}
if (samomor)
goto s;
work(dht);
}
switch (errno) {
case EINTR:
if (sigusr1) {
sigusr1 = 0;
dht_print(stdout, dht);
fflush(stdout);
goto w;
}
if (periodično) {
periodično = 0;
// alarm(PERIODIC);
periodic(dht);
goto w;
}
if (!samomor) {
error_at_line(0, errno, __FILE__, __LINE__, "poll");
r = 114;
}
break;
default:
error_at_line(0, errno, __FILE__, __LINE__, "poll");
r = 115;
goto r;
}
s:
config = persistent(dht);
dht_free(dht);
dht = NULL;
if (cfr && munmap(cfr, statbuf.st_size) == -1) {
error_at_line(0, errno, __FILE__, __LINE__, "munmap(cf, %ld)", statbuf.st_size);
r = 116;
goto r;
}
cfr = NULL;
if (ftruncate(cf, (statbuf.st_size = bencode_length(config))) == -1) {
error_at_line(0, errno, __FILE__, __LINE__, "ftruncate(cf, %ld)", statbuf.st_size);
r = 117;
goto r;
}
if (!(cfr = mmap(NULL, statbuf.st_size, PROT_WRITE, MAP_SHARED, cf, 0))) {
error_at_line(0, errno, __FILE__, __LINE__, "mmap(NULL, %ld, PROT_READ, MAP_SHARED, cf, 0)", statbuf.st_size);
r = 118;
goto r;
}
bencode(cfr, config);
r:
if (dht) {
dht_free(dht);
dht = NULL;
}
if (config) {
free_bencoding(config);
config = NULL;
}
if (cfr && munmap(cfr, statbuf.st_size) == -1)
error_at_line(0, errno, __FILE__, __LINE__, "munmap(cf, %ld)", statbuf.st_size);
if (close(cf) == -1)
error_at_line(0, errno, __FILE__, __LINE__, "close(cf)");
if (pollfds)
free(pollfds);
fprintf(stderr, "exiting cleanly with status %d node_init_count=%u node_free_count=%u\n", r, node_init_count, node_free_count);
return r;
}