diff --git a/btpd/Makefile.am b/btpd/Makefile.am index 7135b63..718cfbd 100644 --- a/btpd/Makefile.am +++ b/btpd/Makefile.am @@ -1,6 +1,8 @@ bin_PROGRAMS=btpd btpd_SOURCES=\ + main.c util.c\ btpd.c btpd.h\ + opts.c opts.h\ cli_if.c\ net.c net.h\ net_buf.c net_buf.h\ diff --git a/btpd/btpd.c b/btpd/btpd.c index 7f905f9..fe6b099 100644 --- a/btpd/btpd.c +++ b/btpd/btpd.c @@ -17,8 +17,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -26,146 +26,33 @@ #include #include "btpd.h" -#include "tracker_req.h" -extern void client_connection_cb(int sd, short type, void *arg); - -struct btpd btpd; - -void * -btpd_malloc(size_t size) -{ - void *a; - if ((a = malloc(size)) == NULL) - btpd_err("Failed to allocate %d bytes.\n", (int)size); - return a; -} - -void * -btpd_calloc(size_t nmemb, size_t size) -{ - void *a; - if ((a = calloc(nmemb, size)) == NULL) - btpd_err("Failed to allocate %d bytes.\n", (int)(nmemb * size)); - return a; -} - -const char * -logtype_str(uint32_t type) -{ - if (type & BTPD_L_BTPD) - return "btpd"; - else if (type & BTPD_L_ERROR) - return "error"; - else if (type & BTPD_L_CONN) - return "conn"; - else if (type & BTPD_L_TRACKER) - return "tracker"; - else if (type & BTPD_L_MSG) - return "msg"; - else - return ""; -} - -void -btpd_err(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - if (BTPD_L_ERROR & btpd.logmask) { - char tbuf[20]; - time_t tp = time(NULL); - strftime(tbuf, 20, "%b %e %T", localtime(&tp)); - printf("%s %s: ", tbuf, logtype_str(BTPD_L_ERROR)); - vprintf(fmt, ap); - } - va_end(ap); - exit(1); -} - -void -btpd_log(uint32_t type, const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - if (type & btpd.logmask) { - char tbuf[20]; - time_t tp = time(NULL); - strftime(tbuf, 20, "%b %e %T", localtime(&tp)); - printf("%s %s: ", tbuf, logtype_str(type)); - vprintf(fmt, ap); - } - va_end(ap); -} - -static void -btpd_init(void) -{ - bcopy(BTPD_VERSION, btpd.peer_id, sizeof(BTPD_VERSION) - 1); - btpd.peer_id[sizeof(BTPD_VERSION) - 1] = '|'; - srandom(time(NULL)); - for (int i = sizeof(BTPD_VERSION); i < 20; i++) - btpd.peer_id[i] = rint(random() * 255.0 / RAND_MAX); - - btpd.version = BTPD_VERSION; - -#ifdef DEBUG - btpd.logmask = BTPD_L_ALL; -#else - btpd.logmask = BTPD_L_BTPD | BTPD_L_ERROR; -#endif - - BTPDQ_INIT(&btpd.kids); - - btpd.ntorrents = 0; - BTPDQ_INIT(&btpd.cm_list); - - BTPDQ_INIT(&btpd.readq); - BTPDQ_INIT(&btpd.writeq); - - BTPDQ_INIT(&btpd.unattached); - - btpd.port = 6881; - - btpd.bw_hz = 8; - btpd.bwcalls = 0; - for (int i = 0; i < BWCALLHISTORY; i++) - btpd.bwrate[i] = 0; - - btpd.obwlim = 0; - btpd.ibwlim = 0; - btpd.obw_left = 0; - btpd.ibw_left = 0; +struct child { + pid_t pid; + void *arg; + void (*cb)(pid_t, void *); + BTPDQ_ENTRY(child) entry; +}; - btpd.npeers = 0; +BTPDQ_HEAD(child_tq, child); - int nfiles = getdtablesize(); - if (nfiles <= 20) - btpd_err("Too few open files allowed (%d). " - "Check \"ulimit -n\"\n", nfiles); - else if (nfiles < 64) - btpd_log(BTPD_L_BTPD, - "You have restricted the number of open files to %d. " - "More could be beneficial to the download performance.\n", - nfiles); - btpd.maxpeers = nfiles - 20; +static uint8_t m_peer_id[20]; +static struct event m_heartbeat; +static struct event m_sigint; +static struct event m_sigterm; +static struct event m_sigchld; +static struct child_tq m_kids = BTPDQ_HEAD_INITIALIZER(m_kids); +static unsigned m_ntorrents; +static struct torrent_tq m_cm_list = BTPDQ_HEAD_INITIALIZER(m_cm_list); - btpd.choke_msg = nb_create_choke(); - nb_hold(btpd.choke_msg); - btpd.unchoke_msg = nb_create_unchoke(); - nb_hold(btpd.unchoke_msg); - btpd.interest_msg = nb_create_interest(); - nb_hold(btpd.interest_msg); - btpd.uninterest_msg = nb_create_uninterest(); - nb_hold(btpd.uninterest_msg); -} +unsigned long btpd_seconds; void btpd_shutdown(void) { struct torrent *tp; - tp = BTPDQ_FIRST(&btpd.cm_list); + tp = BTPDQ_FIRST(&m_cm_list); while (tp != NULL) { struct torrent *next = BTPDQ_NEXT(tp, entry); torrent_unload(tp); @@ -182,6 +69,16 @@ signal_cb(int signal, short type, void *arg) btpd_shutdown(); } +void +btpd_add_child(pid_t pid, void (*cb)(pid_t, void *), void *arg) +{ + struct child *kid = btpd_calloc(1, sizeof(*kid)); + kid->pid = pid; + kid->arg = arg; + kid->cb = cb; + BTPDQ_INSERT_TAIL(&m_kids, kid, entry); +} + static void child_cb(int signal, short type, void *arg) { @@ -190,12 +87,13 @@ child_cb(int signal, short type, void *arg) while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { if (WIFEXITED(status) || WIFSIGNALED(status)) { - struct child *kid = BTPDQ_FIRST(&btpd.kids); + struct child *kid = BTPDQ_FIRST(&m_kids); while (kid != NULL && kid->pid != pid) kid = BTPDQ_NEXT(kid, entry); assert(kid != NULL); - BTPDQ_REMOVE(&btpd.kids, kid, entry); - kid->child_done(kid); + BTPDQ_REMOVE(&m_kids, kid, entry); + kid->cb(kid->pid, kid->arg); + free(kid); } } } @@ -205,224 +103,78 @@ heartbeat_cb(int sd, short type, void *arg) { struct torrent *tp; - btpd.seconds++; + btpd_seconds++; - net_bw_rate(); - - BTPDQ_FOREACH(tp, &btpd.cm_list, entry) + BTPDQ_FOREACH(tp, &m_cm_list, entry) cm_by_second(tp); - evtimer_add(&btpd.heartbeat, (& (struct timeval) { 1, 0 })); + evtimer_add(&m_heartbeat, (& (struct timeval) { 1, 0 })); } -static void -usage() +void +btpd_add_torrent(struct torrent *tp) { - printf("Usage: btpd [options]\n" - "\n" - "Options:\n" - "\n" - "--bw-hz n\n" - "\tRun the bandwidth limiter at n hz.\n" - "\tDefault is 8 hz.\n" - "\n" - "--bw-in n\n" - "\tLimit incoming BitTorrent traffic to n kB/s.\n" - "\tDefault is 0 which means unlimited.\n" - "\n" - "--bw-out n\n" - "\tLimit outgoing BitTorrent traffic to n kB/s.\n" - "\tDefault is 0 which means unlimited.\n" - "\n" - "-d\n" - "\tKeep the btpd process in the foregorund and log to std{out,err}.\n" - "\tThis option is intended for debugging purposes.\n" - "\n" - "--ipc key\n" - "\tThe same key must be used by the cli to talk to this\n" - "\tbtpd instance. You shouldn't need to use this option.\n" - "\n" - "--logfile file\n" - "\tLog to the given file. By default btpd logs to ./btpd.log.\n" - "\n" - "-p n, --port n\n" - "\tListen at port n. Default is 6881.\n" - "\n" - "--help\n" - "\tShow this help.\n" - "\n"); - exit(1); + BTPDQ_INSERT_TAIL(&m_cm_list, tp, entry); + m_ntorrents++; } -static int longval = 0; - -static struct option longopts[] = { - { "port", required_argument, NULL, 'p' }, - { "bw-hz", required_argument, &longval, 6 }, - { "bw-in", required_argument, &longval, 1 }, - { "bw-out", required_argument, &longval, 2 }, - { "logfile", required_argument, &longval, 3 }, - { "ipc", required_argument, &longval, 4 }, - { "help", no_argument, &longval, 5 }, - { NULL, 0, NULL, 0 } -}; - -int -main(int argc, char **argv) +void +btpd_del_torrent(struct torrent *tp) { - int error, ch; - char *logfile = NULL, *ipc = NULL; - int d_opt = 0; - - setlocale(LC_ALL, ""); - btpd_init(); - - while ((ch = getopt_long(argc, argv, "dp:", longopts, NULL)) != -1) { - switch (ch) { - case 'd': - d_opt = 1; - break; - case 'p': - btpd.port = atoi(optarg); - break; - case 0: - switch (longval) { - case 1: - btpd.ibwlim = atoi(optarg) * 1024; - break; - case 2: - btpd.obwlim = atoi(optarg) * 1024; - break; - case 3: - logfile = optarg; - break; - case 4: - ipc = optarg; - for (int i = 0; i < strlen(ipc); i++) - if (!isalnum(ipc[i])) - btpd_err("--ipc only takes letters and digits.\n"); - break; - case 5: - usage(); - case 6: - btpd.bw_hz = atoi(optarg); - if (btpd.bw_hz <= 0 || btpd.bw_hz > 100) - btpd_err("I will only accept bw limiter hz " - "between 1 and 100.\n"); - break; - default: - usage(); - } - break; - case '?': - default: - usage(); - } - } - argc -= optind; - argv += optind; - - if (argc != 0) - usage(); - - //net_init(); - { - int sd; - int flag = 1; - struct sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_ANY); - addr.sin_port = htons(btpd.port); + BTPDQ_REMOVE(&m_cm_list, tp, entry); + m_ntorrents--; +} - if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) - btpd_err("socket: %s\n", strerror(errno)); - setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)); - if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) == -1) - btpd_err("bind: %s\n", strerror(errno)); - listen(sd, 10); - set_nonblocking(sd); - btpd.peer4_sd = sd; - } +const struct torrent_tq * +btpd_get_torrents(void) +{ + return &m_cm_list; +} - //ipc_init(); - { - int sd; - struct sockaddr_un addr; - size_t psiz = sizeof(addr.sun_path); +unsigned +btpd_get_ntorrents(void) +{ + return m_ntorrents; +} - addr.sun_family = PF_UNIX; - if (ipc != NULL) { - if (snprintf(addr.sun_path, psiz, "/tmp/btpd_%u_%s", - geteuid(), ipc) >= psiz) - btpd_err("%s is too long.\n", ipc); - } else - snprintf(addr.sun_path, psiz, "/tmp/btpd_%u_default", geteuid()); +struct torrent * +btpd_get_torrent(const uint8_t *hash) +{ + struct torrent *tp = BTPDQ_FIRST(&m_cm_list); + while (tp != NULL && bcmp(hash, tp->meta.info_hash, 20) != 0) + tp = BTPDQ_NEXT(tp, entry); + return tp; +} - if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) - btpd_err("sock: %s\n", strerror(errno)); - if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) != 0) { - if (errno == EADDRINUSE) { - if (connect(sd, (struct sockaddr *)&addr, sizeof(addr)) == 0) - btpd_err("btpd already running at %s.\n", addr.sun_path); - else { - unlink(addr.sun_path); - if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) != 0) - btpd_err("bind: %s\n", strerror(errno)); - } - } else - btpd_err("bind: %s\n", strerror(errno)); - } - if (chmod(addr.sun_path, 0600) == -1) - btpd_err("chmod: %s (%s).\n", addr.sun_path, strerror(errno)); - listen(sd, 4); - set_nonblocking(sd); - btpd.ipc_sd = sd; - } +const uint8_t * +btpd_get_peer_id(void) +{ + return m_peer_id; +} - freopen("/dev/null", "r", stdin); - if (logfile == NULL) - logfile = "btpd.log"; - if (!d_opt) { - freopen(logfile, "w", stdout); - freopen(logfile, "w", stderr); - daemon(1, 1); - } +extern void ipc_init(void); - setlinebuf(stdout); - setlinebuf(stderr); +void +btpd_init(void) +{ + bcopy(BTPD_VERSION, m_peer_id, sizeof(BTPD_VERSION) - 1); + m_peer_id[sizeof(BTPD_VERSION) - 1] = '|'; + srandom(time(NULL)); + for (int i = sizeof(BTPD_VERSION); i < 20; i++) + m_peer_id[i] = rint(random() * 255.0 / RAND_MAX); - event_init(); + net_init(); + ipc_init(); signal(SIGPIPE, SIG_IGN); - signal_set(&btpd.sigint, SIGINT, signal_cb, NULL); - signal_add(&btpd.sigint, NULL); - signal_set(&btpd.sigterm, SIGTERM, signal_cb, NULL); - signal_add(&btpd.sigterm, NULL); - signal_set(&btpd.sigchld, SIGCHLD, child_cb, NULL); - signal_add(&btpd.sigchld, NULL); - - evtimer_set(&btpd.heartbeat, heartbeat_cb, NULL); - evtimer_add(&btpd.heartbeat, (& (struct timeval) { 1, 0 })); - - event_set(&btpd.cli, btpd.ipc_sd, EV_READ | EV_PERSIST, - client_connection_cb, &btpd); - event_add(&btpd.cli, NULL); - - event_set(&btpd.accept4, btpd.peer4_sd, EV_READ | EV_PERSIST, - net_connection_cb, &btpd); - event_add(&btpd.accept4, NULL); - - evtimer_set(&btpd.bwlim, net_bw_cb, NULL); - if (btpd.obwlim > 0 || btpd.ibwlim > 0) { - btpd.ibw_left = btpd.ibwlim / btpd.bw_hz; - btpd.obw_left = btpd.obwlim / btpd.bw_hz; - evtimer_add(&btpd.bwlim, - (& (struct timeval) { 0, 1000000 / btpd.bw_hz })); - } - - error = event_dispatch(); - btpd_err("Returned from dispatch. Error = %d.\n", error); + signal_set(&m_sigint, SIGINT, signal_cb, NULL); + signal_add(&m_sigint, NULL); + signal_set(&m_sigterm, SIGTERM, signal_cb, NULL); + signal_add(&m_sigterm, NULL); + signal_set(&m_sigchld, SIGCHLD, child_cb, NULL); + signal_add(&m_sigchld, NULL); - return error; + evtimer_set(&m_heartbeat, heartbeat_cb, NULL); + evtimer_add(&m_heartbeat, (& (struct timeval) { 1, 0 })); } diff --git a/btpd/btpd.h b/btpd/btpd.h index 1a5c357..4b0a4a0 100644 --- a/btpd/btpd.h +++ b/btpd/btpd.h @@ -25,69 +25,11 @@ #include "policy.h" #include "subr.h" -#define BTPD_VERSION (PACKAGE_NAME "/" PACKAGE_VERSION) - -#define BWCALLHISTORY 5 - -struct child { - pid_t pid; - void *data; - void (*child_done)(struct child *child); - BTPDQ_ENTRY(child) entry; -}; - -BTPDQ_HEAD(child_tq, child); - -struct btpd { - uint8_t peer_id[20]; - - const char *version; - - uint32_t logmask; - - struct child_tq kids; - - unsigned ntorrents; - struct torrent_tq cm_list; - - struct peer_tq readq; - struct peer_tq writeq; - - struct peer_tq unattached; +#include "opts.h" - int port; - int peer4_sd; - int ipc_sd; - - unsigned bw_hz; - double bw_hz_avg; - unsigned bwcalls; - unsigned bwrate[BWCALLHISTORY]; - unsigned long obwlim, ibwlim; - unsigned long ibw_left, obw_left; - struct event bwlim; - - unsigned npeers; - unsigned maxpeers; - - unsigned long seconds; - - struct event cli; - struct event accept4; - - struct event heartbeat; - - struct event sigint; - struct event sigterm; - struct event sigchld; - - struct net_buf *choke_msg; - struct net_buf *unchoke_msg; - struct net_buf *interest_msg; - struct net_buf *uninterest_msg; -}; +#define BTPD_VERSION (PACKAGE_NAME "/" PACKAGE_VERSION) -extern struct btpd btpd; +extern unsigned long btpd_seconds; #define BTPD_L_ALL 0xffffffff #define BTPD_L_ERROR 0x00000001 @@ -97,6 +39,8 @@ extern struct btpd btpd; #define BTPD_L_BTPD 0x00000010 #define BTPD_L_POL 0x00000020 +void btpd_init(void); + void btpd_log(uint32_t type, const char *fmt, ...); void btpd_err(const char *fmt, ...); @@ -106,4 +50,13 @@ void *btpd_calloc(size_t nmemb, size_t size); void btpd_shutdown(void); +void btpd_add_child(pid_t pid, void (*cb)(pid_t, void *), void *arg); + +struct torrent * btpd_get_torrent(const uint8_t *hash); +const struct torrent_tq *btpd_get_torrents(void); +void btpd_add_torrent(struct torrent *tp); +void btpd_del_torrent(struct torrent *tp); +unsigned btpd_get_ntorrents(void); +const uint8_t *btpd_get_peer_id(void); + #endif diff --git a/btpd/cli_if.c b/btpd/cli_if.c index 07662fe..a10d60b 100644 --- a/btpd/cli_if.c +++ b/btpd/cli_if.c @@ -1,6 +1,8 @@ #include #include +#include #include +#include #include #include @@ -17,6 +19,8 @@ #define buf_swrite(iob, s) buf_write(iob, s, sizeof(s) - 1) +static struct event m_cli_incoming; + static void errdie(int error) { @@ -32,11 +36,11 @@ cmd_stat(int argc, const char *args, FILE *fp) errdie(buf_init(&iob, (1 << 14))); errdie(buf_swrite(&iob, "d")); - errdie(buf_print(&iob, "6:npeersi%ue", btpd.npeers)); - errdie(buf_print(&iob, "9:ntorrentsi%ue", btpd.ntorrents)); - errdie(buf_print(&iob, "7:secondsi%lue", btpd.seconds)); + errdie(buf_print(&iob, "6:npeersi%ue", net_npeers)); + errdie(buf_print(&iob, "9:ntorrentsi%ue", btpd_get_ntorrents())); + errdie(buf_print(&iob, "7:secondsi%lue", btpd_seconds)); errdie(buf_swrite(&iob, "8:torrentsl")); - BTPDQ_FOREACH(tp, &btpd.cm_list, entry) { + BTPDQ_FOREACH(tp, btpd_get_torrents(), entry) { uint32_t seen_npieces = 0; for (uint32_t i = 0; i < tp->meta.npieces; i++) if (tp->piece_count[i] > 0) @@ -116,7 +120,7 @@ cmd_del(int argc, const char *args, FILE *fp) return; } - tp = torrent_get_by_hash(hash); + tp = btpd_get_torrent(hash); if (tp != NULL) { btpd_log(BTPD_L_BTPD, "del request for %s.\n", tp->relpath); torrent_unload(tp); @@ -223,3 +227,35 @@ client_connection_cb(int sd, short type, void *arg) fclose(fp); } + +void +ipc_init(void) +{ + int sd; + struct sockaddr_un addr; + size_t psiz = sizeof(addr.sun_path); + + addr.sun_family = PF_UNIX; + if (snprintf(addr.sun_path, psiz, "%s/sock", btpd_dir) >= psiz) + btpd_err("'%s/sock' is too long.\n", btpd_dir); + + if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + btpd_err("sock: %s\n", strerror(errno)); + if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) != 0) { + if (errno == EADDRINUSE) { + unlink(addr.sun_path); + if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) != 0) + btpd_err("bind: %s\n", strerror(errno)); + } else + btpd_err("bind: %s\n", strerror(errno)); + } + + if (chmod(addr.sun_path, 0600) == -1) + btpd_err("chmod: %s (%s).\n", addr.sun_path, strerror(errno)); + listen(sd, 4); + set_nonblocking(sd); + + event_set(&m_cli_incoming, sd, EV_READ | EV_PERSIST, + client_connection_cb, NULL); + event_add(&m_cli_incoming, NULL); +} diff --git a/btpd/main.c b/btpd/main.c new file mode 100644 index 0000000..8c75a3d --- /dev/null +++ b/btpd/main.c @@ -0,0 +1,182 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "btpd.h" + +static void +writepid(int pidfd) +{ + FILE *fp = fdopen(dup(pidfd), "w"); + fprintf(fp, "%d", getpid()); + fclose(fp); +} + +static char * +find_homedir(void) +{ + char *res = getenv("BTPD_HOME"); + if (res == NULL) { + char *home = getenv("HOME"); + if (home == NULL) { + struct passwd *pwent = getpwuid(getuid()); + if (pwent == NULL) + errx(1, "Can't find my home directory.\n"); + home = pwent->pw_dir; + endpwent(); + } + asprintf(&res, "%s/.btpd", home); + } + return res; +} + +static void +setup_daemon(const char *dir) +{ + int pidfd; + + if (dir == NULL) + dir = find_homedir(); + + btpd_dir = dir; + + if (mkdir(dir, 0777) == -1 && errno != EEXIST) + err(1, "Couldn't create home '%s'", dir); + + if (chdir(dir) != 0) + err(1, "Couldn't change working directory to '%s'", dir); + + pidfd = open("pid", O_CREAT|O_WRONLY|O_NONBLOCK|O_EXLOCK, 0666); + if (pidfd == -1) + err(1, "Couldn't open 'pid'"); + + if (btpd_daemon) { + if (daemon(1, 1) != 0) + err(1, "Failed to daemonize"); + freopen("/dev/null", "r", stdin); + if (freopen("log", "a", stdout) == NULL) + err(1, "Couldn't open 'log'"); + dup2(fileno(stdout), fileno(stderr)); + setlinebuf(stdout); + setlinebuf(stderr); + } + + writepid(pidfd); +} + +static void +usage(void) +{ + printf("Usage: btpd [options]\n" + "\n" + "Options:\n" + "\n" + "--bw-hz n\n" + "\tRun the bandwidth limiter at n hz.\n" + "\tDefault is 8 hz.\n" + "\n" + "--bw-in n\n" + "\tLimit incoming BitTorrent traffic to n kB/s.\n" + "\tDefault is 0 which means unlimited.\n" + "\n" + "--bw-out n\n" + "\tLimit outgoing BitTorrent traffic to n kB/s.\n" + "\tDefault is 0 which means unlimited.\n" + "\n" + "-d\n" + "\tKeep the btpd process in the foregorund and log to std{out,err}.\n" + "\tThis option is intended for debugging purposes.\n" + "\n" + "--ipc key\n" + "\tThe same key must be used by the cli to talk to this\n" + "\tbtpd instance. You shouldn't need to use this option.\n" + "\n" + "--logfile file\n" + "\tLog to the given file. By default btpd logs to ./btpd.log.\n" + "\n" + "-p n, --port n\n" + "\tListen at port n. Default is 6881.\n" + "\n" + "--help\n" + "\tShow this help.\n" + "\n"); + exit(1); +} + +static int longval = 0; + +static struct option longopts[] = { + { "port", required_argument, NULL, 'p' }, + { "bw-hz", required_argument, &longval, 6 }, + { "bw-in", required_argument, &longval, 1 }, + { "bw-out", required_argument, &longval, 2 }, + { "help", no_argument, &longval, 5 }, + { NULL, 0, NULL, 0 } +}; + +int +main(int argc, char **argv) +{ + char *dir = NULL; + + setlocale(LC_ALL, ""); + + for (;;) { + switch (getopt_long(argc, argv, "dp:", longopts, NULL)) { + case -1: + goto args_done; + case 'd': + btpd_daemon = 0; + break; + case 'p': + net_port = atoi(optarg); + break; + case 0: + switch (longval) { + case 1: + net_bw_limit_in = atoi(optarg) * 1024; + break; + case 2: + net_bw_limit_out = atoi(optarg) * 1024; + break; + case 6: + net_bw_hz = atoi(optarg); + break; + default: + usage(); + } + break; + case '?': + default: + usage(); + } + } +args_done: + argc -= optind; + argv += optind; + + if (argc != 0) + usage(); + + setup_daemon(dir); + + event_init(); + + btpd_init(); + + event_dispatch(); + btpd_err("Unexpected exit from libevent.\n"); + + return 1; +} diff --git a/btpd/net.c b/btpd/net.c index 3e32beb..2eb57cf 100644 --- a/btpd/net.c +++ b/btpd/net.c @@ -20,6 +20,18 @@ #define min(x, y) ((x) <= (y) ? (x) : (y)) +static struct event m_bw_timer; +static unsigned long m_bw_bytes_in; +static unsigned long m_bw_bytes_out; + +static struct event m_net_incoming; + +unsigned net_npeers; + +struct peer_tq net_bw_readq = BTPDQ_HEAD_INITIALIZER(net_bw_readq); +struct peer_tq net_bw_writeq = BTPDQ_HEAD_INITIALIZER(net_bw_writeq); +struct peer_tq net_unattached = BTPDQ_HEAD_INITIALIZER(net_unattached); + void net_write32(void *buf, uint32_t num) { @@ -89,7 +101,7 @@ net_write(struct peer *p, unsigned long wmax) peer_sent(p, nl->nb); if (nl->nb->type == NB_TORRENTDATA) { p->tp->uploaded += bufdelta; - p->rate_from_me[btpd.seconds % RATEHISTORY] += bufdelta; + p->rate_from_me[btpd_seconds % RATEHISTORY] += bufdelta; } bcount -= bufdelta; BTPDQ_REMOVE(&p->outq, nl, entry); @@ -100,7 +112,7 @@ net_write(struct peer *p, unsigned long wmax) } else { if (nl->nb->type == NB_TORRENTDATA) { p->tp->uploaded += bcount; - p->rate_from_me[btpd.seconds % RATEHISTORY] += bcount; + p->rate_from_me[btpd_seconds % RATEHISTORY] += bcount; } p->outq_off += bcount; bcount = 0; @@ -209,7 +221,7 @@ net_progress(struct peer *p, size_t length) { if (p->net.state == BTP_MSGBODY && p->net.msg_num == MSG_PIECE) { p->tp->downloaded += length; - p->rate_to_me[btpd.seconds % RATEHISTORY] += length; + p->rate_to_me[btpd_seconds % RATEHISTORY] += length; } } @@ -224,7 +236,7 @@ net_state(struct peer *p, const char *buf) break; case SHAKE_INFO: if (p->flags & PF_INCOMING) { - struct torrent *tp = torrent_get_by_hash(buf); + struct torrent *tp = btpd_get_torrent(buf); if (tp == NULL) goto bad; p->tp = tp; @@ -235,7 +247,7 @@ net_state(struct peer *p, const char *buf) break; case SHAKE_ID: if ((torrent_has_peer(p->tp, buf) - || bcmp(buf, btpd.peer_id, 20) == 0)) + || bcmp(buf, btpd_get_peer_id(), 20) == 0)) goto bad; bcopy(buf, p->id, 20); peer_on_shake(p); @@ -378,7 +390,7 @@ net_connect(const char *ip, int port, int *sd) struct addrinfo hints, *res; char portstr[6]; - assert(btpd.npeers < btpd.maxpeers); + assert(net_npeers < net_max_peers); if (snprintf(portstr, sizeof(portstr), "%d", port) >= sizeof(portstr)) return EINVAL; @@ -412,8 +424,8 @@ net_connection_cb(int sd, short type, void *arg) return; } - assert(btpd.npeers <= btpd.maxpeers); - if (btpd.npeers == btpd.maxpeers) { + assert(net_npeers <= net_max_peers); + if (net_npeers == net_max_peers) { close(nsd); return; } @@ -424,17 +436,13 @@ net_connection_cb(int sd, short type, void *arg) } void -net_bw_rate(void) +add_bw_timer(void) { - unsigned sum = 0; - for (int i = 0; i < BWCALLHISTORY - 1; i++) { - btpd.bwrate[i] = btpd.bwrate[i + 1]; - sum += btpd.bwrate[i]; - } - btpd.bwrate[BWCALLHISTORY - 1] = btpd.bwcalls; - sum += btpd.bwrate[BWCALLHISTORY - 1]; - btpd.bwcalls = 0; - btpd.bw_hz_avg = sum / 5.0; + long wait = 1000000 / net_bw_hz; + struct timeval now; + gettimeofday(&now, NULL); + wait = wait - now.tv_usec % wait; + evtimer_add(&m_bw_timer, (& (struct timeval) { 0, wait})); } void @@ -442,58 +450,50 @@ net_bw_cb(int sd, short type, void *arg) { struct peer *p; - btpd.bwcalls++; - - double avg_hz; - if (btpd.seconds < BWCALLHISTORY) - avg_hz = btpd.bw_hz; - else - avg_hz = btpd.bw_hz_avg; + m_bw_bytes_out = net_bw_limit_out / net_bw_hz; + m_bw_bytes_in = net_bw_limit_in / net_bw_hz; - btpd.obw_left = btpd.obwlim / avg_hz; - btpd.ibw_left = btpd.ibwlim / avg_hz; - - if (btpd.ibwlim > 0) { - while ((p = BTPDQ_FIRST(&btpd.readq)) != NULL && btpd.ibw_left > 0) { - BTPDQ_REMOVE(&btpd.readq, p, rq_entry); + if (net_bw_limit_in > 0) { + while ((p = BTPDQ_FIRST(&net_bw_readq)) != NULL && m_bw_bytes_in > 0) { + BTPDQ_REMOVE(&net_bw_readq, p, rq_entry); p->flags &= ~PF_ON_READQ; - btpd.ibw_left -= net_read(p, btpd.ibw_left); + m_bw_bytes_in -= net_read(p, m_bw_bytes_in); } } else { - while ((p = BTPDQ_FIRST(&btpd.readq)) != NULL) { - BTPDQ_REMOVE(&btpd.readq, p, rq_entry); + while ((p = BTPDQ_FIRST(&net_bw_readq)) != NULL) { + BTPDQ_REMOVE(&net_bw_readq, p, rq_entry); p->flags &= ~PF_ON_READQ; net_read(p, 0); } } - if (btpd.obwlim) { - while ((p = BTPDQ_FIRST(&btpd.writeq)) != NULL && btpd.obw_left > 0) { - BTPDQ_REMOVE(&btpd.writeq, p, wq_entry); + if (net_bw_limit_out) { + while ((p = BTPDQ_FIRST(&net_bw_writeq)) != NULL && m_bw_bytes_out > 0) { + BTPDQ_REMOVE(&net_bw_writeq, p, wq_entry); p->flags &= ~PF_ON_WRITEQ; - btpd.obw_left -= net_write(p, btpd.obw_left); + m_bw_bytes_out -= net_write(p, m_bw_bytes_out); } } else { - while ((p = BTPDQ_FIRST(&btpd.writeq)) != NULL) { - BTPDQ_REMOVE(&btpd.writeq, p, wq_entry); + while ((p = BTPDQ_FIRST(&net_bw_writeq)) != NULL) { + BTPDQ_REMOVE(&net_bw_writeq, p, wq_entry); p->flags &= ~PF_ON_WRITEQ; net_write(p, 0); } } - event_add(&btpd.bwlim, (& (struct timeval) { 0, 1000000 / btpd.bw_hz })); + add_bw_timer(); } void net_read_cb(int sd, short type, void *arg) { struct peer *p = (struct peer *)arg; - if (btpd.ibwlim == 0) + if (net_bw_limit_in == 0) net_read(p, 0); - else if (btpd.ibw_left > 0) - btpd.ibw_left -= net_read(p, btpd.ibw_left); + else if (m_bw_bytes_in > 0) + m_bw_bytes_in -= net_read(p, m_bw_bytes_in); else { p->flags |= PF_ON_READQ; - BTPDQ_INSERT_TAIL(&btpd.readq, p, rq_entry); + BTPDQ_INSERT_TAIL(&net_bw_readq, p, rq_entry); } } @@ -506,12 +506,53 @@ net_write_cb(int sd, short type, void *arg) peer_kill(p); return; } - if (btpd.obwlim == 0) { + if (net_bw_limit_out == 0) { net_write(p, 0); - } else if (btpd.obw_left > 0) { - btpd.obw_left -= net_write(p, btpd.obw_left); + } else if (m_bw_bytes_out > 0) { + m_bw_bytes_out -= net_write(p, m_bw_bytes_out); } else { p->flags |= PF_ON_WRITEQ; - BTPDQ_INSERT_TAIL(&btpd.writeq, p, wq_entry); + BTPDQ_INSERT_TAIL(&net_bw_writeq, p, wq_entry); } } + +void +net_init(void) +{ + m_bw_bytes_out = net_bw_limit_out / net_bw_hz; + m_bw_bytes_in = net_bw_limit_in / net_bw_hz; + + int nfiles = getdtablesize(); + if (nfiles <= 20) + btpd_err("Too few open files allowed (%d). " + "Check \"ulimit -n\"\n", nfiles); + else if (nfiles < 64) + btpd_log(BTPD_L_BTPD, + "You have restricted the number of open files to %d. " + "More could be beneficial to the download performance.\n", + nfiles); + net_max_peers = nfiles - 20; + + int sd; + int flag = 1; + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = htons(net_port); + + if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) + btpd_err("socket: %s\n", strerror(errno)); + setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)); + if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) == -1) + btpd_err("bind: %s\n", strerror(errno)); + listen(sd, 10); + set_nonblocking(sd); + + event_set(&m_net_incoming, sd, EV_READ | EV_PERSIST, + net_connection_cb, NULL); + event_add(&m_net_incoming, NULL); + + evtimer_set(&m_bw_timer, net_bw_cb, NULL); + if (net_bw_limit_out > 0 || net_bw_limit_in > 0) + add_bw_timer(); +} diff --git a/btpd/net.h b/btpd/net.h index 33b5424..b2ede1d 100644 --- a/btpd/net.h +++ b/btpd/net.h @@ -13,7 +13,10 @@ #define WRITE_TIMEOUT (& (struct timeval) { 60, 0 }) -#define SHAKE_LEN 68 +extern struct peer_tq net_unattached; +extern struct peer_tq net_bw_readq; +extern struct peer_tq net_bw_writeq; +extern unsigned net_npeers; enum net_state { SHAKE_PSTR, @@ -27,8 +30,7 @@ enum net_state { void net_set_state(struct peer *p, enum net_state state, size_t size); -void net_connection_cb(int sd, short type, void *arg); -void net_bw_rate(void); +void net_init(void); void net_bw_cb(int sd, short type, void *arg); void net_read_cb(int sd, short type, void *arg); diff --git a/btpd/net_buf.c b/btpd/net_buf.c index c879e10..06289df 100644 --- a/btpd/net_buf.c +++ b/btpd/net_buf.c @@ -3,10 +3,14 @@ #include "btpd.h" +static struct net_buf *m_choke; +static struct net_buf *m_unchoke; +static struct net_buf *m_interest; +static struct net_buf *m_uninterest; + static void kill_buf_no(char *buf, size_t len) { - } static void @@ -15,6 +19,12 @@ kill_buf_free(char *buf, size_t len) free(buf); } +static void +kill_buf_abort(char *buf, size_t len) +{ + abort(); +} + static struct net_buf * nb_create_alloc(short type, size_t len) { @@ -47,6 +57,13 @@ nb_create_onesized(char mtype, int btype) return out; } +static struct net_buf *nb_singleton(struct net_buf *nb) +{ + nb_hold(nb); + nb->kill_buf = kill_buf_abort; + return nb; +} + struct net_buf * nb_create_piece(uint32_t index, uint32_t begin, size_t blen) { @@ -119,25 +136,35 @@ nb_create_multihave(struct torrent *tp) struct net_buf * nb_create_unchoke(void) { - return nb_create_onesized(MSG_UNCHOKE, NB_UNCHOKE); + if (m_unchoke == NULL) + m_unchoke = nb_singleton(nb_create_onesized(MSG_UNCHOKE, NB_UNCHOKE)); + return m_unchoke; } struct net_buf * nb_create_choke(void) { - return nb_create_onesized(MSG_CHOKE, NB_CHOKE); + if (m_choke == NULL) + m_choke = nb_singleton(nb_create_onesized(MSG_CHOKE, NB_CHOKE)); + return m_choke; } struct net_buf * nb_create_uninterest(void) { - return nb_create_onesized(MSG_UNINTEREST, NB_UNINTEREST); + if (m_uninterest == NULL) + m_uninterest = + nb_singleton(nb_create_onesized(MSG_UNINTEREST, NB_UNINTEREST)); + return m_uninterest; } struct net_buf * nb_create_interest(void) { - return nb_create_onesized(MSG_INTEREST, NB_INTEREST); + if (m_interest == NULL) + m_interest = + nb_singleton(nb_create_onesized(MSG_INTEREST, NB_INTEREST)); + return m_interest; } struct net_buf * @@ -166,7 +193,7 @@ nb_create_shake(struct torrent *tp) struct net_buf *out = nb_create_alloc(NB_SHAKE, 68); bcopy("\x13""BitTorrent protocol\0\0\0\0\0\0\0\0", out->buf, 28); bcopy(tp->meta.info_hash, out->buf + 28, 20); - bcopy(btpd.peer_id, out->buf + 48, 20); + bcopy(btpd_get_peer_id(), out->buf + 48, 20); return out; } diff --git a/btpd/opts.c b/btpd/opts.c new file mode 100644 index 0000000..e72daf9 --- /dev/null +++ b/btpd/opts.c @@ -0,0 +1,14 @@ +#include + +short btpd_daemon = 1; +const char *btpd_dir; +#ifdef DEBUG +uint32_t btpd_logmask = BTPD_L_ALL; +#else +uint32_t btpd_logmask = BTPD_L_BTPD | BTPD_L_ERROR; +#endif +unsigned net_max_peers; +unsigned net_bw_limit_in; +unsigned net_bw_limit_out; +short net_bw_hz = 8; +int net_port = 6881; diff --git a/btpd/opts.h b/btpd/opts.h new file mode 100644 index 0000000..c24b13b --- /dev/null +++ b/btpd/opts.h @@ -0,0 +1,8 @@ +extern short btpd_daemon; +extern const char *btpd_dir; +extern uint32_t btpd_logmask; +extern unsigned net_max_peers; +extern unsigned net_bw_limit_in; +extern unsigned net_bw_limit_out; +extern short net_bw_hz; +extern int net_port; diff --git a/btpd/peer.c b/btpd/peer.c index 358523c..85a1666 100644 --- a/btpd/peer.c +++ b/btpd/peer.c @@ -28,11 +28,11 @@ peer_kill(struct peer *p) if (p->flags & PF_ATTACHED) cm_on_lost_peer(p); else - BTPDQ_REMOVE(&btpd.unattached, p, cm_entry); + BTPDQ_REMOVE(&net_unattached, p, cm_entry); if (p->flags & PF_ON_READQ) - BTPDQ_REMOVE(&btpd.readq, p, rq_entry); + BTPDQ_REMOVE(&net_bw_readq, p, rq_entry); if (p->flags & PF_ON_WRITEQ) - BTPDQ_REMOVE(&btpd.writeq, p, wq_entry); + BTPDQ_REMOVE(&net_bw_writeq, p, wq_entry); close(p->sd); event_del(&p->in_ev); @@ -51,7 +51,7 @@ peer_kill(struct peer *p) if (p->piece_field != NULL) free(p->piece_field); free(p); - btpd.npeers--; + net_npeers--; } void @@ -88,7 +88,7 @@ peer_unsend(struct peer *p, struct nb_link *nl) free(nl); if (BTPDQ_EMPTY(&p->outq)) { if (p->flags & PF_ON_WRITEQ) { - BTPDQ_REMOVE(&btpd.writeq, p, wq_entry); + BTPDQ_REMOVE(&net_bw_writeq, p, wq_entry); p->flags &= ~PF_ON_WRITEQ; } else event_del(&p->out_ev); @@ -194,7 +194,7 @@ void peer_unchoke(struct peer *p) { p->flags &= ~PF_I_CHOKE; - peer_send(p, btpd.unchoke_msg); + peer_send(p, nb_create_unchoke()); } void @@ -213,7 +213,7 @@ peer_choke(struct peer *p) } p->flags |= PF_I_CHOKE; - peer_send(p, btpd.choke_msg); + peer_send(p, nb_create_choke()); } void @@ -228,7 +228,7 @@ peer_want(struct peer *p, uint32_t index) if (nl != NULL && nl->nb->type == NB_UNINTEREST) unsent = peer_unsend(p, nl); if (!unsent) - peer_send(p, btpd.interest_msg); + peer_send(p, nb_create_interest()); } p->flags |= PF_I_WANT; } @@ -242,7 +242,7 @@ peer_unwant(struct peer *p, uint32_t index) if (p->nwant == 0) { p->flags &= ~PF_I_WANT; if (p->nreqs_out == 0) - peer_send(p, btpd.uninterest_msg); + peer_send(p, nb_create_uninterest()); } } @@ -262,8 +262,8 @@ peer_create_common(int sd) event_set(&p->in_ev, p->sd, EV_READ, net_read_cb, p); event_add(&p->in_ev, NULL); - BTPDQ_INSERT_TAIL(&btpd.unattached, p, cm_entry); - btpd.npeers++; + BTPDQ_INSERT_TAIL(&net_unattached, p, cm_entry); + net_npeers++; return p; } @@ -312,7 +312,7 @@ void peer_on_no_reqs(struct peer *p) { if (p->nwant == 0) - peer_send(p, btpd.uninterest_msg); + peer_send(p, nb_create_uninterest()); } void @@ -461,8 +461,8 @@ peer_on_request(struct peer *p, uint32_t index, uint32_t begin, peer_send(p, nb_create_torrentdata(content, length)); p->npiece_msgs++; if (p->npiece_msgs >= MAXPIECEMSGS) { - peer_send(p, btpd.choke_msg); - peer_send(p, btpd.unchoke_msg); + peer_send(p, nb_create_choke()); + peer_send(p, nb_create_unchoke()); p->flags |= PF_NO_REQUESTS; } } diff --git a/btpd/policy_choke.c b/btpd/policy_choke.c index 64a2b0d..dccb1ea 100644 --- a/btpd/policy_choke.c +++ b/btpd/policy_choke.c @@ -67,7 +67,7 @@ choke_alg(struct torrent *tp) } } - tp->choke_time = btpd.seconds + 10; + tp->choke_time = btpd_seconds + 10; } void @@ -86,5 +86,5 @@ next_optimistic(struct torrent *tp, struct peer *np) } assert(tp->optimistic != NULL); choke_alg(tp); - tp->opt_time = btpd.seconds + 30; + tp->opt_time = btpd_seconds + 30; } diff --git a/btpd/policy_if.c b/btpd/policy_if.c index bcb0176..e660928 100644 --- a/btpd/policy_if.c +++ b/btpd/policy_if.c @@ -7,17 +7,17 @@ void cm_by_second(struct torrent *tp) { - if (btpd.seconds == tp->tracker_time) + if (btpd_seconds == tp->tracker_time) tracker_req(tp, TR_EMPTY); - if (btpd.seconds == tp->opt_time) + if (btpd_seconds == tp->opt_time) next_optimistic(tp, NULL); - if (btpd.seconds == tp->choke_time) + if (btpd_seconds == tp->choke_time) choke_alg(tp); struct peer *p; - int ri = btpd.seconds % RATEHISTORY; + int ri = btpd_seconds % RATEHISTORY; BTPDQ_FOREACH(p, &tp->peers, cm_entry) { p->rate_to_me[ri] = 0; @@ -192,7 +192,7 @@ cm_on_new_peer(struct peer *p) tp->npeers++; p->flags |= PF_ATTACHED; - BTPDQ_REMOVE(&btpd.unattached, p, cm_entry); + BTPDQ_REMOVE(&net_unattached, p, cm_entry); if (tp->npeers == 1) { BTPDQ_INSERT_HEAD(&tp->peers, p, cm_entry); diff --git a/btpd/torrent.c b/btpd/torrent.c index 3712b5b..6fe5a35 100644 --- a/btpd/torrent.c +++ b/btpd/torrent.c @@ -62,10 +62,9 @@ torrent_load3(const char *file, struct metainfo *mi, char *mem, size_t memsiz) tp->meta = *mi; free(mi); - BTPDQ_INSERT_TAIL(&btpd.cm_list, tp, entry); + btpd_add_torrent(tp); tracker_req(tp, TR_STARTED); - btpd.ntorrents++; return 0; } @@ -128,7 +127,7 @@ torrent_load(const char *file) return error; } - if (torrent_get_by_hash(mi->info_hash) != NULL) { + if (btpd_get_torrent(mi->info_hash) != NULL) { btpd_log(BTPD_L_BTPD, "%s has same hash as an already loaded torrent.\n", file); error = EEXIST; } @@ -158,12 +157,12 @@ torrent_unload(struct torrent *tp) while (peer != NULL) { struct peer *next = BTPDQ_NEXT(peer, cm_entry); BTPDQ_REMOVE(&tp->peers, peer, cm_entry); - BTPDQ_INSERT_TAIL(&btpd.unattached, peer, cm_entry); + BTPDQ_INSERT_TAIL(&net_unattached, peer, cm_entry); peer->flags &= ~PF_ATTACHED; peer = next; } - peer = BTPDQ_FIRST(&btpd.unattached); + peer = BTPDQ_FIRST(&net_unattached); while (peer != NULL) { struct peer *next = BTPDQ_NEXT(peer, cm_entry); if (peer->tp == tp) @@ -181,9 +180,8 @@ torrent_unload(struct torrent *tp) munmap(tp->imem, tp->isiz); - BTPDQ_REMOVE(&btpd.cm_list, tp, entry); + btpd_del_torrent(tp); free(tp); - btpd.ntorrents--; } off_t @@ -241,15 +239,6 @@ torrent_has_peer(struct torrent *tp, const uint8_t *id) return has; } -struct torrent * -torrent_get_by_hash(const uint8_t *hash) -{ - struct torrent *tp = BTPDQ_FIRST(&btpd.cm_list); - while (tp != NULL && bcmp(hash, tp->meta.info_hash, 20) != 0) - tp = BTPDQ_NEXT(tp, entry); - return tp; -} - off_t torrent_piece_size(struct torrent *tp, uint32_t index) { diff --git a/btpd/torrent.h b/btpd/torrent.h index e5b7b2c..f535b4c 100644 --- a/btpd/torrent.h +++ b/btpd/torrent.h @@ -80,8 +80,6 @@ void torrent_unload(struct torrent *tp); int torrent_has_peer(struct torrent *tp, const uint8_t *id); -struct torrent *torrent_get_by_hash(const uint8_t *hash); - off_t torrent_piece_size(struct torrent *tp, uint32_t index); uint32_t torrent_block_size(struct piece *pc, uint32_t index); diff --git a/btpd/tracker_req.c b/btpd/tracker_req.c index 0e4fe57..7f0a74b 100644 --- a/btpd/tracker_req.c +++ b/btpd/tracker_req.c @@ -43,7 +43,7 @@ maybe_connect_to(struct torrent *tp, const char *pinfo) if (benc_dget_str(pinfo, "peer id", &pid, &len) != 0 || len != 20) return; - if (bcmp(btpd.peer_id, pid, 20) == 0) + if (bcmp(btpd_get_peer_id(), pid, 20) == 0) return; if (torrent_has_peer(tp, pid)) @@ -63,16 +63,16 @@ out: } static void -tracker_done(struct child *child) +tracker_done(pid_t pid, void *arg) { - struct tracker_req *req = child->data; + struct tracker_req *req = arg; int failed = 0; char *buf; const char *peers; uint32_t interval; struct torrent *tp; - if ((tp = torrent_get_by_hash(req->info_hash)) == NULL) + if ((tp = btpd_get_torrent(req->info_hash)) == NULL) goto out; if (benc_validate(req->res->buf, req->res->buf_off) != 0 @@ -100,14 +100,14 @@ tracker_done(struct child *child) goto out; } - tp->tracker_time = btpd.seconds + interval; + tp->tracker_time = btpd_seconds + interval; int error = 0; size_t length; if ((error = benc_dget_lst(req->res->buf, "peers", &peers)) == 0) { for (peers = benc_first(peers); - peers != NULL && btpd.npeers < btpd.maxpeers; + peers != NULL && net_npeers < net_max_peers; peers = benc_next(peers)) maybe_connect_to(tp, peers); } @@ -116,7 +116,7 @@ tracker_done(struct child *child) error = benc_dget_str(req->res->buf, "peers", &peers, &length); if (error == 0 && length % 6 == 0) { size_t i; - for (i = 0; i < length && btpd.npeers < btpd.maxpeers; i += 6) + for (i = 0; i < length && net_npeers < net_max_peers; i += 6) peer_create_out_compact(tp, peers + i); } } @@ -134,7 +134,7 @@ out: "Start request failed for %s.\n", tp->relpath); torrent_unload(tp); } else - tp->tracker_time = btpd.seconds + 10; + tp->tracker_time = btpd_seconds + 10; } munmap(req->res, REQ_SIZE); free(req); @@ -162,6 +162,7 @@ static int create_url(struct tracker_req *req, struct torrent *tp, char **url) { char e_hash[61], e_id[61]; + const uint8_t *peer_id = btpd_get_peer_id(); char qc; int i; uint64_t left; @@ -175,7 +176,7 @@ create_url(struct tracker_req *req, struct torrent *tp, char **url) snprintf(e_hash + i * 3, 4, "%%%.2x", tp->meta.info_hash[i]); for (i = 0; i < 20; i++) - snprintf(e_id + i * 3, 4, "%%%.2x", btpd.peer_id[i]); + snprintf(e_id + i * 3, 4, "%%%.2x", peer_id[i]); left = torrent_bytes_left(tp); @@ -187,7 +188,7 @@ create_url(struct tracker_req *req, struct torrent *tp, char **url) "&left=%" PRIu64 "&compact=1" "%s%s", - tp->meta.announce, qc, e_hash, e_id, btpd.port, + tp->meta.announce, qc, e_hash, e_id, net_port, tp->uploaded, tp->downloaded, left, req->tr_event == TR_EMPTY ? "" : "&event=", event); @@ -231,7 +232,7 @@ http_helper(struct tracker_req *req, struct torrent *tp) err = curl_easy_setopt(handle, CURLOPT_URL, url); if (err == 0) - err = curl_easy_setopt(handle, CURLOPT_USERAGENT, btpd.version); + err = curl_easy_setopt(handle, CURLOPT_USERAGENT, BTPD_VERSION); if (err == 0) err = curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, http_cb); if (err == 0) @@ -276,13 +277,13 @@ void tracker_req(struct torrent *tp, enum tr_event tr_event) { struct tracker_req *req; - struct child *child; + pid_t pid; btpd_log(BTPD_L_TRACKER, "request for %s, event: %s.\n", tp->relpath, event2str(tr_event)); - req = (struct tracker_req *)btpd_calloc(1, sizeof(*req) + sizeof(*child)); + req = (struct tracker_req *)btpd_calloc(1, sizeof(*req)); req->res = mmap(NULL, REQ_SIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0); @@ -299,18 +300,14 @@ tracker_req(struct torrent *tp, enum tr_event tr_event) fflush(NULL); - child = (struct child *)(req + 1); - child->data = req; - child->child_done = tracker_done; - BTPDQ_INSERT_TAIL(&btpd.kids, child, entry); - - child->pid = fork(); - if (child->pid < 0) { + pid = fork(); + if (pid < 0) { btpd_err("Couldn't fork (%s).\n", strerror(errno)); - } else if (child->pid == 0) { // Child + } else if (pid == 0) { // Child int nfiles = getdtablesize(); for (int i = 0; i < nfiles; i++) close(i); http_helper(req, tp); - } + } else + btpd_add_child(pid, tracker_done, req); } diff --git a/btpd/util.c b/btpd/util.c new file mode 100644 index 0000000..1cf6526 --- /dev/null +++ b/btpd/util.c @@ -0,0 +1,70 @@ +#include +#include + +#include "btpd.h" + +void * +btpd_malloc(size_t size) +{ + void *a; + if ((a = malloc(size)) == NULL) + btpd_err("Failed to allocate %d bytes.\n", (int)size); + return a; +} + +void * +btpd_calloc(size_t nmemb, size_t size) +{ + void *a; + if ((a = calloc(nmemb, size)) == NULL) + btpd_err("Failed to allocate %d bytes.\n", (int)(nmemb * size)); + return a; +} + +static const char * +logtype_str(uint32_t type) +{ + if (type & BTPD_L_BTPD) + return "btpd"; + else if (type & BTPD_L_ERROR) + return "error"; + else if (type & BTPD_L_CONN) + return "conn"; + else if (type & BTPD_L_TRACKER) + return "tracker"; + else if (type & BTPD_L_MSG) + return "msg"; + else + return ""; +} + +void +btpd_err(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + if (BTPD_L_ERROR & btpd_logmask) { + char tbuf[20]; + time_t tp = time(NULL); + strftime(tbuf, 20, "%b %e %T", localtime(&tp)); + printf("%s %s: ", tbuf, logtype_str(BTPD_L_ERROR)); + vprintf(fmt, ap); + } + va_end(ap); + exit(1); +} + +void +btpd_log(uint32_t type, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + if (type & btpd_logmask) { + char tbuf[20]; + time_t tp = time(NULL); + strftime(tbuf, 20, "%b %e %T", localtime(&tp)); + printf("%s %s: ", tbuf, logtype_str(type)); + vprintf(fmt, ap); + } + va_end(ap); +}