rid of the global btpd struct. Some fields in the struct got a corresponding global variable whereas some was made static and moved to a module. The bandwidht algorithm also got tweaked. It now tries to fire the event at specific times. This was to make the code simpler. It'll probably have to be tweaked again :P First step to make btpd run from a directory where it'll keep the log, socket, configuration, data on the known torrents, etc. Btpd now uses flock on the pidfile instead of connecting to the socket in order to be reasonably sure that no other btpd runs in the same directory.master
@@ -1,6 +1,8 @@ | |||||
bin_PROGRAMS=btpd | bin_PROGRAMS=btpd | ||||
btpd_SOURCES=\ | btpd_SOURCES=\ | ||||
main.c util.c\ | |||||
btpd.c btpd.h\ | btpd.c btpd.h\ | ||||
opts.c opts.h\ | |||||
cli_if.c\ | cli_if.c\ | ||||
net.c net.h\ | net.c net.h\ | ||||
net_buf.c net_buf.h\ | net_buf.c net_buf.h\ | ||||
@@ -17,8 +17,8 @@ | |||||
#include <getopt.h> | #include <getopt.h> | ||||
#include <math.h> | #include <math.h> | ||||
#include <locale.h> | #include <locale.h> | ||||
#include <pwd.h> | |||||
#include <signal.h> | #include <signal.h> | ||||
#include <stdarg.h> | |||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
@@ -26,146 +26,33 @@ | |||||
#include <unistd.h> | #include <unistd.h> | ||||
#include "btpd.h" | #include "btpd.h" | ||||
#include "tracker_req.h" | |||||
extern void client_connection_cb(int sd, short type, void *arg); | struct child { | ||||
pid_t pid; | |||||
struct btpd btpd; | void *arg; | ||||
void (*cb)(pid_t, void *); | |||||
void * | BTPDQ_ENTRY(child) entry; | ||||
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; | |||||
btpd.npeers = 0; | BTPDQ_HEAD(child_tq, child); | ||||
int nfiles = getdtablesize(); | static uint8_t m_peer_id[20]; | ||||
if (nfiles <= 20) | static struct event m_heartbeat; | ||||
btpd_err("Too few open files allowed (%d). " | static struct event m_sigint; | ||||
"Check \"ulimit -n\"\n", nfiles); | static struct event m_sigterm; | ||||
else if (nfiles < 64) | static struct event m_sigchld; | ||||
btpd_log(BTPD_L_BTPD, | static struct child_tq m_kids = BTPDQ_HEAD_INITIALIZER(m_kids); | ||||
"You have restricted the number of open files to %d. " | static unsigned m_ntorrents; | ||||
"More could be beneficial to the download performance.\n", | static struct torrent_tq m_cm_list = BTPDQ_HEAD_INITIALIZER(m_cm_list); | ||||
nfiles); | |||||
btpd.maxpeers = nfiles - 20; | |||||
btpd.choke_msg = nb_create_choke(); | unsigned long btpd_seconds; | ||||
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); | |||||
} | |||||
void | void | ||||
btpd_shutdown(void) | btpd_shutdown(void) | ||||
{ | { | ||||
struct torrent *tp; | struct torrent *tp; | ||||
tp = BTPDQ_FIRST(&btpd.cm_list); | tp = BTPDQ_FIRST(&m_cm_list); | ||||
while (tp != NULL) { | while (tp != NULL) { | ||||
struct torrent *next = BTPDQ_NEXT(tp, entry); | struct torrent *next = BTPDQ_NEXT(tp, entry); | ||||
torrent_unload(tp); | torrent_unload(tp); | ||||
@@ -182,6 +69,16 @@ signal_cb(int signal, short type, void *arg) | |||||
btpd_shutdown(); | 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 | static void | ||||
child_cb(int signal, short type, void *arg) | 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) { | while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { | ||||
if (WIFEXITED(status) || WIFSIGNALED(status)) { | 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) | while (kid != NULL && kid->pid != pid) | ||||
kid = BTPDQ_NEXT(kid, entry); | kid = BTPDQ_NEXT(kid, entry); | ||||
assert(kid != NULL); | assert(kid != NULL); | ||||
BTPDQ_REMOVE(&btpd.kids, kid, entry); | BTPDQ_REMOVE(&m_kids, kid, entry); | ||||
kid->child_done(kid); | kid->cb(kid->pid, kid->arg); | ||||
free(kid); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -205,224 +103,78 @@ heartbeat_cb(int sd, short type, void *arg) | |||||
{ | { | ||||
struct torrent *tp; | struct torrent *tp; | ||||
btpd.seconds++; | btpd_seconds++; | ||||
net_bw_rate(); | BTPDQ_FOREACH(tp, &m_cm_list, entry) | ||||
BTPDQ_FOREACH(tp, &btpd.cm_list, entry) | |||||
cm_by_second(tp); | cm_by_second(tp); | ||||
evtimer_add(&btpd.heartbeat, (& (struct timeval) { 1, 0 })); | evtimer_add(&m_heartbeat, (& (struct timeval) { 1, 0 })); | ||||
} | } | ||||
static void | void | ||||
usage() | btpd_add_torrent(struct torrent *tp) | ||||
{ | { | ||||
printf("Usage: btpd [options]\n" | BTPDQ_INSERT_TAIL(&m_cm_list, tp, entry); | ||||
"\n" | m_ntorrents++; | ||||
"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; | void | ||||
btpd_del_torrent(struct torrent *tp) | |||||
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) | |||||
{ | { | ||||
int error, ch; | BTPDQ_REMOVE(&m_cm_list, tp, entry); | ||||
char *logfile = NULL, *ipc = NULL; | m_ntorrents--; | ||||
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); | |||||
if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) | const struct torrent_tq * | ||||
btpd_err("socket: %s\n", strerror(errno)); | btpd_get_torrents(void) | ||||
setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)); | { | ||||
if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) == -1) | return &m_cm_list; | ||||
btpd_err("bind: %s\n", strerror(errno)); | } | ||||
listen(sd, 10); | |||||
set_nonblocking(sd); | |||||
btpd.peer4_sd = sd; | |||||
} | |||||
//ipc_init(); | unsigned | ||||
{ | btpd_get_ntorrents(void) | ||||
int sd; | { | ||||
struct sockaddr_un addr; | return m_ntorrents; | ||||
size_t psiz = sizeof(addr.sun_path); | } | ||||
addr.sun_family = PF_UNIX; | struct torrent * | ||||
if (ipc != NULL) { | btpd_get_torrent(const uint8_t *hash) | ||||
if (snprintf(addr.sun_path, psiz, "/tmp/btpd_%u_%s", | { | ||||
geteuid(), ipc) >= psiz) | struct torrent *tp = BTPDQ_FIRST(&m_cm_list); | ||||
btpd_err("%s is too long.\n", ipc); | while (tp != NULL && bcmp(hash, tp->meta.info_hash, 20) != 0) | ||||
} else | tp = BTPDQ_NEXT(tp, entry); | ||||
snprintf(addr.sun_path, psiz, "/tmp/btpd_%u_default", geteuid()); | return tp; | ||||
} | |||||
if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) | const uint8_t * | ||||
btpd_err("sock: %s\n", strerror(errno)); | btpd_get_peer_id(void) | ||||
if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) != 0) { | { | ||||
if (errno == EADDRINUSE) { | return m_peer_id; | ||||
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; | |||||
} | |||||
freopen("/dev/null", "r", stdin); | extern void ipc_init(void); | ||||
if (logfile == NULL) | |||||
logfile = "btpd.log"; | |||||
if (!d_opt) { | |||||
freopen(logfile, "w", stdout); | |||||
freopen(logfile, "w", stderr); | |||||
daemon(1, 1); | |||||
} | |||||
setlinebuf(stdout); | void | ||||
setlinebuf(stderr); | 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(SIGPIPE, SIG_IGN); | ||||
signal_set(&btpd.sigint, SIGINT, signal_cb, NULL); | signal_set(&m_sigint, SIGINT, signal_cb, NULL); | ||||
signal_add(&btpd.sigint, NULL); | signal_add(&m_sigint, NULL); | ||||
signal_set(&btpd.sigterm, SIGTERM, signal_cb, NULL); | signal_set(&m_sigterm, SIGTERM, signal_cb, NULL); | ||||
signal_add(&btpd.sigterm, NULL); | signal_add(&m_sigterm, NULL); | ||||
signal_set(&btpd.sigchld, SIGCHLD, child_cb, NULL); | signal_set(&m_sigchld, SIGCHLD, child_cb, NULL); | ||||
signal_add(&btpd.sigchld, NULL); | signal_add(&m_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); | |||||
return error; | evtimer_set(&m_heartbeat, heartbeat_cb, NULL); | ||||
evtimer_add(&m_heartbeat, (& (struct timeval) { 1, 0 })); | |||||
} | } |
@@ -25,69 +25,11 @@ | |||||
#include "policy.h" | #include "policy.h" | ||||
#include "subr.h" | #include "subr.h" | ||||
#define BTPD_VERSION (PACKAGE_NAME "/" PACKAGE_VERSION) | #include "opts.h" | ||||
#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; | |||||
int port; | #define BTPD_VERSION (PACKAGE_NAME "/" PACKAGE_VERSION) | ||||
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; | |||||
}; | |||||
extern struct btpd btpd; | extern unsigned long btpd_seconds; | ||||
#define BTPD_L_ALL 0xffffffff | #define BTPD_L_ALL 0xffffffff | ||||
#define BTPD_L_ERROR 0x00000001 | #define BTPD_L_ERROR 0x00000001 | ||||
@@ -97,6 +39,8 @@ extern struct btpd btpd; | |||||
#define BTPD_L_BTPD 0x00000010 | #define BTPD_L_BTPD 0x00000010 | ||||
#define BTPD_L_POL 0x00000020 | #define BTPD_L_POL 0x00000020 | ||||
void btpd_init(void); | |||||
void btpd_log(uint32_t type, const char *fmt, ...); | void btpd_log(uint32_t type, const char *fmt, ...); | ||||
void btpd_err(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_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 | #endif |
@@ -1,6 +1,8 @@ | |||||
#include <sys/types.h> | #include <sys/types.h> | ||||
#include <sys/socket.h> | #include <sys/socket.h> | ||||
#include <sys/un.h> | |||||
#include <arpa/inet.h> | #include <arpa/inet.h> | ||||
#include <sys/stat.h> | |||||
#include <inttypes.h> | #include <inttypes.h> | ||||
#include <limits.h> | #include <limits.h> | ||||
@@ -17,6 +19,8 @@ | |||||
#define buf_swrite(iob, s) buf_write(iob, s, sizeof(s) - 1) | #define buf_swrite(iob, s) buf_write(iob, s, sizeof(s) - 1) | ||||
static struct event m_cli_incoming; | |||||
static void | static void | ||||
errdie(int error) | errdie(int error) | ||||
{ | { | ||||
@@ -32,11 +36,11 @@ cmd_stat(int argc, const char *args, FILE *fp) | |||||
errdie(buf_init(&iob, (1 << 14))); | errdie(buf_init(&iob, (1 << 14))); | ||||
errdie(buf_swrite(&iob, "d")); | errdie(buf_swrite(&iob, "d")); | ||||
errdie(buf_print(&iob, "6:npeersi%ue", btpd.npeers)); | errdie(buf_print(&iob, "6:npeersi%ue", net_npeers)); | ||||
errdie(buf_print(&iob, "9:ntorrentsi%ue", btpd.ntorrents)); | errdie(buf_print(&iob, "9:ntorrentsi%ue", btpd_get_ntorrents())); | ||||
errdie(buf_print(&iob, "7:secondsi%lue", btpd.seconds)); | errdie(buf_print(&iob, "7:secondsi%lue", btpd_seconds)); | ||||
errdie(buf_swrite(&iob, "8:torrentsl")); | 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; | uint32_t seen_npieces = 0; | ||||
for (uint32_t i = 0; i < tp->meta.npieces; i++) | for (uint32_t i = 0; i < tp->meta.npieces; i++) | ||||
if (tp->piece_count[i] > 0) | if (tp->piece_count[i] > 0) | ||||
@@ -116,7 +120,7 @@ cmd_del(int argc, const char *args, FILE *fp) | |||||
return; | return; | ||||
} | } | ||||
tp = torrent_get_by_hash(hash); | tp = btpd_get_torrent(hash); | ||||
if (tp != NULL) { | if (tp != NULL) { | ||||
btpd_log(BTPD_L_BTPD, "del request for %s.\n", tp->relpath); | btpd_log(BTPD_L_BTPD, "del request for %s.\n", tp->relpath); | ||||
torrent_unload(tp); | torrent_unload(tp); | ||||
@@ -223,3 +227,35 @@ client_connection_cb(int sd, short type, void *arg) | |||||
fclose(fp); | 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); | |||||
} |
@@ -0,0 +1,182 @@ | |||||
#include <sys/types.h> | |||||
#include <sys/stat.h> | |||||
#include <assert.h> | |||||
#include <err.h> | |||||
#include <errno.h> | |||||
#include <fcntl.h> | |||||
#include <getopt.h> | |||||
#include <locale.h> | |||||
#include <pwd.h> | |||||
#include <stdio.h> | |||||
#include <stdlib.h> | |||||
#include <string.h> | |||||
#include <unistd.h> | |||||
#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; | |||||
} |
@@ -20,6 +20,18 @@ | |||||
#define min(x, y) ((x) <= (y) ? (x) : (y)) | #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 | void | ||||
net_write32(void *buf, uint32_t num) | net_write32(void *buf, uint32_t num) | ||||
{ | { | ||||
@@ -89,7 +101,7 @@ net_write(struct peer *p, unsigned long wmax) | |||||
peer_sent(p, nl->nb); | peer_sent(p, nl->nb); | ||||
if (nl->nb->type == NB_TORRENTDATA) { | if (nl->nb->type == NB_TORRENTDATA) { | ||||
p->tp->uploaded += bufdelta; | p->tp->uploaded += bufdelta; | ||||
p->rate_from_me[btpd.seconds % RATEHISTORY] += bufdelta; | p->rate_from_me[btpd_seconds % RATEHISTORY] += bufdelta; | ||||
} | } | ||||
bcount -= bufdelta; | bcount -= bufdelta; | ||||
BTPDQ_REMOVE(&p->outq, nl, entry); | BTPDQ_REMOVE(&p->outq, nl, entry); | ||||
@@ -100,7 +112,7 @@ net_write(struct peer *p, unsigned long wmax) | |||||
} else { | } else { | ||||
if (nl->nb->type == NB_TORRENTDATA) { | if (nl->nb->type == NB_TORRENTDATA) { | ||||
p->tp->uploaded += bcount; | p->tp->uploaded += bcount; | ||||
p->rate_from_me[btpd.seconds % RATEHISTORY] += bcount; | p->rate_from_me[btpd_seconds % RATEHISTORY] += bcount; | ||||
} | } | ||||
p->outq_off += bcount; | p->outq_off += bcount; | ||||
bcount = 0; | 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) { | if (p->net.state == BTP_MSGBODY && p->net.msg_num == MSG_PIECE) { | ||||
p->tp->downloaded += length; | 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; | break; | ||||
case SHAKE_INFO: | case SHAKE_INFO: | ||||
if (p->flags & PF_INCOMING) { | if (p->flags & PF_INCOMING) { | ||||
struct torrent *tp = torrent_get_by_hash(buf); | struct torrent *tp = btpd_get_torrent(buf); | ||||
if (tp == NULL) | if (tp == NULL) | ||||
goto bad; | goto bad; | ||||
p->tp = tp; | p->tp = tp; | ||||
@@ -235,7 +247,7 @@ net_state(struct peer *p, const char *buf) | |||||
break; | break; | ||||
case SHAKE_ID: | case SHAKE_ID: | ||||
if ((torrent_has_peer(p->tp, buf) | if ((torrent_has_peer(p->tp, buf) | ||||
|| bcmp(buf, btpd.peer_id, 20) == 0)) | || bcmp(buf, btpd_get_peer_id(), 20) == 0)) | ||||
goto bad; | goto bad; | ||||
bcopy(buf, p->id, 20); | bcopy(buf, p->id, 20); | ||||
peer_on_shake(p); | peer_on_shake(p); | ||||
@@ -378,7 +390,7 @@ net_connect(const char *ip, int port, int *sd) | |||||
struct addrinfo hints, *res; | struct addrinfo hints, *res; | ||||
char portstr[6]; | char portstr[6]; | ||||
assert(btpd.npeers < btpd.maxpeers); | assert(net_npeers < net_max_peers); | ||||
if (snprintf(portstr, sizeof(portstr), "%d", port) >= sizeof(portstr)) | if (snprintf(portstr, sizeof(portstr), "%d", port) >= sizeof(portstr)) | ||||
return EINVAL; | return EINVAL; | ||||
@@ -412,8 +424,8 @@ net_connection_cb(int sd, short type, void *arg) | |||||
return; | return; | ||||
} | } | ||||
assert(btpd.npeers <= btpd.maxpeers); | assert(net_npeers <= net_max_peers); | ||||
if (btpd.npeers == btpd.maxpeers) { | if (net_npeers == net_max_peers) { | ||||
close(nsd); | close(nsd); | ||||
return; | return; | ||||
} | } | ||||
@@ -424,17 +436,13 @@ net_connection_cb(int sd, short type, void *arg) | |||||
} | } | ||||
void | void | ||||
net_bw_rate(void) | add_bw_timer(void) | ||||
{ | { | ||||
unsigned sum = 0; | long wait = 1000000 / net_bw_hz; | ||||
for (int i = 0; i < BWCALLHISTORY - 1; i++) { | struct timeval now; | ||||
btpd.bwrate[i] = btpd.bwrate[i + 1]; | gettimeofday(&now, NULL); | ||||
sum += btpd.bwrate[i]; | wait = wait - now.tv_usec % wait; | ||||
} | evtimer_add(&m_bw_timer, (& (struct timeval) { 0, wait})); | ||||
btpd.bwrate[BWCALLHISTORY - 1] = btpd.bwcalls; | |||||
sum += btpd.bwrate[BWCALLHISTORY - 1]; | |||||
btpd.bwcalls = 0; | |||||
btpd.bw_hz_avg = sum / 5.0; | |||||
} | } | ||||
void | void | ||||
@@ -442,58 +450,50 @@ net_bw_cb(int sd, short type, void *arg) | |||||
{ | { | ||||
struct peer *p; | struct peer *p; | ||||
btpd.bwcalls++; | m_bw_bytes_out = net_bw_limit_out / net_bw_hz; | ||||
m_bw_bytes_in = net_bw_limit_in / net_bw_hz; | |||||
double avg_hz; | |||||
if (btpd.seconds < BWCALLHISTORY) | |||||
avg_hz = btpd.bw_hz; | |||||
else | |||||
avg_hz = btpd.bw_hz_avg; | |||||
btpd.obw_left = btpd.obwlim / avg_hz; | if (net_bw_limit_in > 0) { | ||||
btpd.ibw_left = btpd.ibwlim / avg_hz; | while ((p = BTPDQ_FIRST(&net_bw_readq)) != NULL && m_bw_bytes_in > 0) { | ||||
BTPDQ_REMOVE(&net_bw_readq, p, rq_entry); | |||||
if (btpd.ibwlim > 0) { | |||||
while ((p = BTPDQ_FIRST(&btpd.readq)) != NULL && btpd.ibw_left > 0) { | |||||
BTPDQ_REMOVE(&btpd.readq, p, rq_entry); | |||||
p->flags &= ~PF_ON_READQ; | 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 { | } else { | ||||
while ((p = BTPDQ_FIRST(&btpd.readq)) != NULL) { | while ((p = BTPDQ_FIRST(&net_bw_readq)) != NULL) { | ||||
BTPDQ_REMOVE(&btpd.readq, p, rq_entry); | BTPDQ_REMOVE(&net_bw_readq, p, rq_entry); | ||||
p->flags &= ~PF_ON_READQ; | p->flags &= ~PF_ON_READQ; | ||||
net_read(p, 0); | net_read(p, 0); | ||||
} | } | ||||
} | } | ||||
if (btpd.obwlim) { | if (net_bw_limit_out) { | ||||
while ((p = BTPDQ_FIRST(&btpd.writeq)) != NULL && btpd.obw_left > 0) { | while ((p = BTPDQ_FIRST(&net_bw_writeq)) != NULL && m_bw_bytes_out > 0) { | ||||
BTPDQ_REMOVE(&btpd.writeq, p, wq_entry); | BTPDQ_REMOVE(&net_bw_writeq, p, wq_entry); | ||||
p->flags &= ~PF_ON_WRITEQ; | 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 { | } else { | ||||
while ((p = BTPDQ_FIRST(&btpd.writeq)) != NULL) { | while ((p = BTPDQ_FIRST(&net_bw_writeq)) != NULL) { | ||||
BTPDQ_REMOVE(&btpd.writeq, p, wq_entry); | BTPDQ_REMOVE(&net_bw_writeq, p, wq_entry); | ||||
p->flags &= ~PF_ON_WRITEQ; | p->flags &= ~PF_ON_WRITEQ; | ||||
net_write(p, 0); | net_write(p, 0); | ||||
} | } | ||||
} | } | ||||
event_add(&btpd.bwlim, (& (struct timeval) { 0, 1000000 / btpd.bw_hz })); | add_bw_timer(); | ||||
} | } | ||||
void | void | ||||
net_read_cb(int sd, short type, void *arg) | net_read_cb(int sd, short type, void *arg) | ||||
{ | { | ||||
struct peer *p = (struct peer *)arg; | struct peer *p = (struct peer *)arg; | ||||
if (btpd.ibwlim == 0) | if (net_bw_limit_in == 0) | ||||
net_read(p, 0); | net_read(p, 0); | ||||
else if (btpd.ibw_left > 0) | else if (m_bw_bytes_in > 0) | ||||
btpd.ibw_left -= net_read(p, btpd.ibw_left); | m_bw_bytes_in -= net_read(p, m_bw_bytes_in); | ||||
else { | else { | ||||
p->flags |= PF_ON_READQ; | 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); | peer_kill(p); | ||||
return; | return; | ||||
} | } | ||||
if (btpd.obwlim == 0) { | if (net_bw_limit_out == 0) { | ||||
net_write(p, 0); | net_write(p, 0); | ||||
} else if (btpd.obw_left > 0) { | } else if (m_bw_bytes_out > 0) { | ||||
btpd.obw_left -= net_write(p, btpd.obw_left); | m_bw_bytes_out -= net_write(p, m_bw_bytes_out); | ||||
} else { | } else { | ||||
p->flags |= PF_ON_WRITEQ; | 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(); | |||||
} |
@@ -13,7 +13,10 @@ | |||||
#define WRITE_TIMEOUT (& (struct timeval) { 60, 0 }) | #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 { | enum net_state { | ||||
SHAKE_PSTR, | 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_set_state(struct peer *p, enum net_state state, size_t size); | ||||
void net_connection_cb(int sd, short type, void *arg); | void net_init(void); | ||||
void net_bw_rate(void); | |||||
void net_bw_cb(int sd, short type, void *arg); | void net_bw_cb(int sd, short type, void *arg); | ||||
void net_read_cb(int sd, short type, void *arg); | void net_read_cb(int sd, short type, void *arg); | ||||
@@ -3,10 +3,14 @@ | |||||
#include "btpd.h" | #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 | static void | ||||
kill_buf_no(char *buf, size_t len) | kill_buf_no(char *buf, size_t len) | ||||
{ | { | ||||
} | } | ||||
static void | static void | ||||
@@ -15,6 +19,12 @@ kill_buf_free(char *buf, size_t len) | |||||
free(buf); | free(buf); | ||||
} | } | ||||
static void | |||||
kill_buf_abort(char *buf, size_t len) | |||||
{ | |||||
abort(); | |||||
} | |||||
static struct net_buf * | static struct net_buf * | ||||
nb_create_alloc(short type, size_t len) | nb_create_alloc(short type, size_t len) | ||||
{ | { | ||||
@@ -47,6 +57,13 @@ nb_create_onesized(char mtype, int btype) | |||||
return out; | 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 * | struct net_buf * | ||||
nb_create_piece(uint32_t index, uint32_t begin, size_t blen) | 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 * | struct net_buf * | ||||
nb_create_unchoke(void) | 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 * | struct net_buf * | ||||
nb_create_choke(void) | 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 * | struct net_buf * | ||||
nb_create_uninterest(void) | 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 * | struct net_buf * | ||||
nb_create_interest(void) | 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 * | struct net_buf * | ||||
@@ -166,7 +193,7 @@ nb_create_shake(struct torrent *tp) | |||||
struct net_buf *out = nb_create_alloc(NB_SHAKE, 68); | 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("\x13""BitTorrent protocol\0\0\0\0\0\0\0\0", out->buf, 28); | ||||
bcopy(tp->meta.info_hash, out->buf + 28, 20); | 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; | return out; | ||||
} | } | ||||
@@ -0,0 +1,14 @@ | |||||
#include <btpd.h> | |||||
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; |
@@ -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; |
@@ -28,11 +28,11 @@ peer_kill(struct peer *p) | |||||
if (p->flags & PF_ATTACHED) | if (p->flags & PF_ATTACHED) | ||||
cm_on_lost_peer(p); | cm_on_lost_peer(p); | ||||
else | else | ||||
BTPDQ_REMOVE(&btpd.unattached, p, cm_entry); | BTPDQ_REMOVE(&net_unattached, p, cm_entry); | ||||
if (p->flags & PF_ON_READQ) | 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) | if (p->flags & PF_ON_WRITEQ) | ||||
BTPDQ_REMOVE(&btpd.writeq, p, wq_entry); | BTPDQ_REMOVE(&net_bw_writeq, p, wq_entry); | ||||
close(p->sd); | close(p->sd); | ||||
event_del(&p->in_ev); | event_del(&p->in_ev); | ||||
@@ -51,7 +51,7 @@ peer_kill(struct peer *p) | |||||
if (p->piece_field != NULL) | if (p->piece_field != NULL) | ||||
free(p->piece_field); | free(p->piece_field); | ||||
free(p); | free(p); | ||||
btpd.npeers--; | net_npeers--; | ||||
} | } | ||||
void | void | ||||
@@ -88,7 +88,7 @@ peer_unsend(struct peer *p, struct nb_link *nl) | |||||
free(nl); | free(nl); | ||||
if (BTPDQ_EMPTY(&p->outq)) { | if (BTPDQ_EMPTY(&p->outq)) { | ||||
if (p->flags & PF_ON_WRITEQ) { | 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; | p->flags &= ~PF_ON_WRITEQ; | ||||
} else | } else | ||||
event_del(&p->out_ev); | event_del(&p->out_ev); | ||||
@@ -194,7 +194,7 @@ void | |||||
peer_unchoke(struct peer *p) | peer_unchoke(struct peer *p) | ||||
{ | { | ||||
p->flags &= ~PF_I_CHOKE; | p->flags &= ~PF_I_CHOKE; | ||||
peer_send(p, btpd.unchoke_msg); | peer_send(p, nb_create_unchoke()); | ||||
} | } | ||||
void | void | ||||
@@ -213,7 +213,7 @@ peer_choke(struct peer *p) | |||||
} | } | ||||
p->flags |= PF_I_CHOKE; | p->flags |= PF_I_CHOKE; | ||||
peer_send(p, btpd.choke_msg); | peer_send(p, nb_create_choke()); | ||||
} | } | ||||
void | void | ||||
@@ -228,7 +228,7 @@ peer_want(struct peer *p, uint32_t index) | |||||
if (nl != NULL && nl->nb->type == NB_UNINTEREST) | if (nl != NULL && nl->nb->type == NB_UNINTEREST) | ||||
unsent = peer_unsend(p, nl); | unsent = peer_unsend(p, nl); | ||||
if (!unsent) | if (!unsent) | ||||
peer_send(p, btpd.interest_msg); | peer_send(p, nb_create_interest()); | ||||
} | } | ||||
p->flags |= PF_I_WANT; | p->flags |= PF_I_WANT; | ||||
} | } | ||||
@@ -242,7 +242,7 @@ peer_unwant(struct peer *p, uint32_t index) | |||||
if (p->nwant == 0) { | if (p->nwant == 0) { | ||||
p->flags &= ~PF_I_WANT; | p->flags &= ~PF_I_WANT; | ||||
if (p->nreqs_out == 0) | 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_set(&p->in_ev, p->sd, EV_READ, net_read_cb, p); | ||||
event_add(&p->in_ev, NULL); | event_add(&p->in_ev, NULL); | ||||
BTPDQ_INSERT_TAIL(&btpd.unattached, p, cm_entry); | BTPDQ_INSERT_TAIL(&net_unattached, p, cm_entry); | ||||
btpd.npeers++; | net_npeers++; | ||||
return p; | return p; | ||||
} | } | ||||
@@ -312,7 +312,7 @@ void | |||||
peer_on_no_reqs(struct peer *p) | peer_on_no_reqs(struct peer *p) | ||||
{ | { | ||||
if (p->nwant == 0) | if (p->nwant == 0) | ||||
peer_send(p, btpd.uninterest_msg); | peer_send(p, nb_create_uninterest()); | ||||
} | } | ||||
void | 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)); | peer_send(p, nb_create_torrentdata(content, length)); | ||||
p->npiece_msgs++; | p->npiece_msgs++; | ||||
if (p->npiece_msgs >= MAXPIECEMSGS) { | if (p->npiece_msgs >= MAXPIECEMSGS) { | ||||
peer_send(p, btpd.choke_msg); | peer_send(p, nb_create_choke()); | ||||
peer_send(p, btpd.unchoke_msg); | peer_send(p, nb_create_unchoke()); | ||||
p->flags |= PF_NO_REQUESTS; | p->flags |= PF_NO_REQUESTS; | ||||
} | } | ||||
} | } | ||||
@@ -67,7 +67,7 @@ choke_alg(struct torrent *tp) | |||||
} | } | ||||
} | } | ||||
tp->choke_time = btpd.seconds + 10; | tp->choke_time = btpd_seconds + 10; | ||||
} | } | ||||
void | void | ||||
@@ -86,5 +86,5 @@ next_optimistic(struct torrent *tp, struct peer *np) | |||||
} | } | ||||
assert(tp->optimistic != NULL); | assert(tp->optimistic != NULL); | ||||
choke_alg(tp); | choke_alg(tp); | ||||
tp->opt_time = btpd.seconds + 30; | tp->opt_time = btpd_seconds + 30; | ||||
} | } |
@@ -7,17 +7,17 @@ | |||||
void | void | ||||
cm_by_second(struct torrent *tp) | cm_by_second(struct torrent *tp) | ||||
{ | { | ||||
if (btpd.seconds == tp->tracker_time) | if (btpd_seconds == tp->tracker_time) | ||||
tracker_req(tp, TR_EMPTY); | tracker_req(tp, TR_EMPTY); | ||||
if (btpd.seconds == tp->opt_time) | if (btpd_seconds == tp->opt_time) | ||||
next_optimistic(tp, NULL); | next_optimistic(tp, NULL); | ||||
if (btpd.seconds == tp->choke_time) | if (btpd_seconds == tp->choke_time) | ||||
choke_alg(tp); | choke_alg(tp); | ||||
struct peer *p; | struct peer *p; | ||||
int ri = btpd.seconds % RATEHISTORY; | int ri = btpd_seconds % RATEHISTORY; | ||||
BTPDQ_FOREACH(p, &tp->peers, cm_entry) { | BTPDQ_FOREACH(p, &tp->peers, cm_entry) { | ||||
p->rate_to_me[ri] = 0; | p->rate_to_me[ri] = 0; | ||||
@@ -192,7 +192,7 @@ cm_on_new_peer(struct peer *p) | |||||
tp->npeers++; | tp->npeers++; | ||||
p->flags |= PF_ATTACHED; | p->flags |= PF_ATTACHED; | ||||
BTPDQ_REMOVE(&btpd.unattached, p, cm_entry); | BTPDQ_REMOVE(&net_unattached, p, cm_entry); | ||||
if (tp->npeers == 1) { | if (tp->npeers == 1) { | ||||
BTPDQ_INSERT_HEAD(&tp->peers, p, cm_entry); | BTPDQ_INSERT_HEAD(&tp->peers, p, cm_entry); | ||||
@@ -62,10 +62,9 @@ torrent_load3(const char *file, struct metainfo *mi, char *mem, size_t memsiz) | |||||
tp->meta = *mi; | tp->meta = *mi; | ||||
free(mi); | free(mi); | ||||
BTPDQ_INSERT_TAIL(&btpd.cm_list, tp, entry); | btpd_add_torrent(tp); | ||||
tracker_req(tp, TR_STARTED); | tracker_req(tp, TR_STARTED); | ||||
btpd.ntorrents++; | |||||
return 0; | return 0; | ||||
} | } | ||||
@@ -128,7 +127,7 @@ torrent_load(const char *file) | |||||
return error; | 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); | btpd_log(BTPD_L_BTPD, "%s has same hash as an already loaded torrent.\n", file); | ||||
error = EEXIST; | error = EEXIST; | ||||
} | } | ||||
@@ -158,12 +157,12 @@ torrent_unload(struct torrent *tp) | |||||
while (peer != NULL) { | while (peer != NULL) { | ||||
struct peer *next = BTPDQ_NEXT(peer, cm_entry); | struct peer *next = BTPDQ_NEXT(peer, cm_entry); | ||||
BTPDQ_REMOVE(&tp->peers, 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->flags &= ~PF_ATTACHED; | ||||
peer = next; | peer = next; | ||||
} | } | ||||
peer = BTPDQ_FIRST(&btpd.unattached); | peer = BTPDQ_FIRST(&net_unattached); | ||||
while (peer != NULL) { | while (peer != NULL) { | ||||
struct peer *next = BTPDQ_NEXT(peer, cm_entry); | struct peer *next = BTPDQ_NEXT(peer, cm_entry); | ||||
if (peer->tp == tp) | if (peer->tp == tp) | ||||
@@ -181,9 +180,8 @@ torrent_unload(struct torrent *tp) | |||||
munmap(tp->imem, tp->isiz); | munmap(tp->imem, tp->isiz); | ||||
BTPDQ_REMOVE(&btpd.cm_list, tp, entry); | btpd_del_torrent(tp); | ||||
free(tp); | free(tp); | ||||
btpd.ntorrents--; | |||||
} | } | ||||
off_t | off_t | ||||
@@ -241,15 +239,6 @@ torrent_has_peer(struct torrent *tp, const uint8_t *id) | |||||
return has; | 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 | off_t | ||||
torrent_piece_size(struct torrent *tp, uint32_t index) | torrent_piece_size(struct torrent *tp, uint32_t index) | ||||
{ | { | ||||
@@ -80,8 +80,6 @@ void torrent_unload(struct torrent *tp); | |||||
int torrent_has_peer(struct torrent *tp, const uint8_t *id); | 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); | off_t torrent_piece_size(struct torrent *tp, uint32_t index); | ||||
uint32_t torrent_block_size(struct piece *pc, uint32_t index); | uint32_t torrent_block_size(struct piece *pc, uint32_t index); | ||||
@@ -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) | if (benc_dget_str(pinfo, "peer id", &pid, &len) != 0 || len != 20) | ||||
return; | return; | ||||
if (bcmp(btpd.peer_id, pid, 20) == 0) | if (bcmp(btpd_get_peer_id(), pid, 20) == 0) | ||||
return; | return; | ||||
if (torrent_has_peer(tp, pid)) | if (torrent_has_peer(tp, pid)) | ||||
@@ -63,16 +63,16 @@ out: | |||||
} | } | ||||
static void | 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; | int failed = 0; | ||||
char *buf; | char *buf; | ||||
const char *peers; | const char *peers; | ||||
uint32_t interval; | uint32_t interval; | ||||
struct torrent *tp; | struct torrent *tp; | ||||
if ((tp = torrent_get_by_hash(req->info_hash)) == NULL) | if ((tp = btpd_get_torrent(req->info_hash)) == NULL) | ||||
goto out; | goto out; | ||||
if (benc_validate(req->res->buf, req->res->buf_off) != 0 | if (benc_validate(req->res->buf, req->res->buf_off) != 0 | ||||
@@ -100,14 +100,14 @@ tracker_done(struct child *child) | |||||
goto out; | goto out; | ||||
} | } | ||||
tp->tracker_time = btpd.seconds + interval; | tp->tracker_time = btpd_seconds + interval; | ||||
int error = 0; | int error = 0; | ||||
size_t length; | size_t length; | ||||
if ((error = benc_dget_lst(req->res->buf, "peers", &peers)) == 0) { | if ((error = benc_dget_lst(req->res->buf, "peers", &peers)) == 0) { | ||||
for (peers = benc_first(peers); | for (peers = benc_first(peers); | ||||
peers != NULL && btpd.npeers < btpd.maxpeers; | peers != NULL && net_npeers < net_max_peers; | ||||
peers = benc_next(peers)) | peers = benc_next(peers)) | ||||
maybe_connect_to(tp, 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); | error = benc_dget_str(req->res->buf, "peers", &peers, &length); | ||||
if (error == 0 && length % 6 == 0) { | if (error == 0 && length % 6 == 0) { | ||||
size_t i; | 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); | peer_create_out_compact(tp, peers + i); | ||||
} | } | ||||
} | } | ||||
@@ -134,7 +134,7 @@ out: | |||||
"Start request failed for %s.\n", tp->relpath); | "Start request failed for %s.\n", tp->relpath); | ||||
torrent_unload(tp); | torrent_unload(tp); | ||||
} else | } else | ||||
tp->tracker_time = btpd.seconds + 10; | tp->tracker_time = btpd_seconds + 10; | ||||
} | } | ||||
munmap(req->res, REQ_SIZE); | munmap(req->res, REQ_SIZE); | ||||
free(req); | free(req); | ||||
@@ -162,6 +162,7 @@ static int | |||||
create_url(struct tracker_req *req, struct torrent *tp, char **url) | create_url(struct tracker_req *req, struct torrent *tp, char **url) | ||||
{ | { | ||||
char e_hash[61], e_id[61]; | char e_hash[61], e_id[61]; | ||||
const uint8_t *peer_id = btpd_get_peer_id(); | |||||
char qc; | char qc; | ||||
int i; | int i; | ||||
uint64_t left; | 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]); | snprintf(e_hash + i * 3, 4, "%%%.2x", tp->meta.info_hash[i]); | ||||
for (i = 0; i < 20; 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); | left = torrent_bytes_left(tp); | ||||
@@ -187,7 +188,7 @@ create_url(struct tracker_req *req, struct torrent *tp, char **url) | |||||
"&left=%" PRIu64 | "&left=%" PRIu64 | ||||
"&compact=1" | "&compact=1" | ||||
"%s%s", | "%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, | tp->uploaded, tp->downloaded, left, | ||||
req->tr_event == TR_EMPTY ? "" : "&event=", | req->tr_event == TR_EMPTY ? "" : "&event=", | ||||
event); | event); | ||||
@@ -231,7 +232,7 @@ http_helper(struct tracker_req *req, struct torrent *tp) | |||||
err = curl_easy_setopt(handle, CURLOPT_URL, url); | err = curl_easy_setopt(handle, CURLOPT_URL, url); | ||||
if (err == 0) | if (err == 0) | ||||
err = curl_easy_setopt(handle, CURLOPT_USERAGENT, btpd.version); | err = curl_easy_setopt(handle, CURLOPT_USERAGENT, BTPD_VERSION); | ||||
if (err == 0) | if (err == 0) | ||||
err = curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, http_cb); | err = curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, http_cb); | ||||
if (err == 0) | if (err == 0) | ||||
@@ -276,13 +277,13 @@ void | |||||
tracker_req(struct torrent *tp, enum tr_event tr_event) | tracker_req(struct torrent *tp, enum tr_event tr_event) | ||||
{ | { | ||||
struct tracker_req *req; | struct tracker_req *req; | ||||
struct child *child; | pid_t pid; | ||||
btpd_log(BTPD_L_TRACKER, | btpd_log(BTPD_L_TRACKER, | ||||
"request for %s, event: %s.\n", | "request for %s, event: %s.\n", | ||||
tp->relpath, event2str(tr_event)); | 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, | req->res = mmap(NULL, REQ_SIZE, PROT_READ | PROT_WRITE, | ||||
MAP_ANON | MAP_SHARED, -1, 0); | MAP_ANON | MAP_SHARED, -1, 0); | ||||
@@ -299,18 +300,14 @@ tracker_req(struct torrent *tp, enum tr_event tr_event) | |||||
fflush(NULL); | fflush(NULL); | ||||
child = (struct child *)(req + 1); | pid = fork(); | ||||
child->data = req; | if (pid < 0) { | ||||
child->child_done = tracker_done; | |||||
BTPDQ_INSERT_TAIL(&btpd.kids, child, entry); | |||||
child->pid = fork(); | |||||
if (child->pid < 0) { | |||||
btpd_err("Couldn't fork (%s).\n", strerror(errno)); | btpd_err("Couldn't fork (%s).\n", strerror(errno)); | ||||
} else if (child->pid == 0) { // Child | } else if (pid == 0) { // Child | ||||
int nfiles = getdtablesize(); | int nfiles = getdtablesize(); | ||||
for (int i = 0; i < nfiles; i++) | for (int i = 0; i < nfiles; i++) | ||||
close(i); | close(i); | ||||
http_helper(req, tp); | http_helper(req, tp); | ||||
} | } else | ||||
btpd_add_child(pid, tracker_done, req); | |||||
} | } |
@@ -0,0 +1,70 @@ | |||||
#include <stdarg.h> | |||||
#include <stdio.h> | |||||
#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); | |||||
} |