#include #include #include #include #include #include #include #include #include #include #define S0(x) (x ? x : "") #define So(x, o) (x ? x : o) #define TORRENT_USERDATA struct dht * dht; #define DHT_USERDATA struct pollfd ** pollfds; size_t * pollfds_size; nfds_t * nfds; #include #define DISCONNECTION_MIXIN_BOTTOM if (t->dl->flags & goodmeta) t->type &= ~(info | peers); #include 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()+atoi(So(getenv("TTL"), "256")); t->type |= info | peers; } else { if (last_added + atoi(So(getenv("COOLDOWN"), "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()+atoi(So(getenv("TTL"), "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; if (getenv("INSERT_PEER")) { dht->insert_peer.sin6_family = AF_INET6; dht->insert_peer.sin6_port = htons(atoi(So(getenv("INSERT_PEER_PORT"), "1337"))); if (inet_pton(AF_INET6, getenv("INSERT_PEER"), dht->insert_peer.sin6_addr.s6_addr) != 1) { error_at_line(0, 0, __FILE__, __LINE__, "inet_pton(AF_INET6, getenv(INSERT_PEER)) != 1"); r = 14; goto r; } error_at_line(0, 0, __FILE__, __LINE__, "feature INSERT_PEER not implemented completely -- bugs: travnik somehow starts sending packets to inserted peer ... perhaps he sends get_peers to himself?"); r = 15; goto r; } if (getenv("TOOMUCH")) dht->toomuch = atoi(getenv("TOOMUCH")); 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) | (getenv("TRAVNIK_DEBUG") ? debug : 0) | (getenv("TRAVNIK_EXPECTED") ? expected : 0); 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; }