Browse Source

Step one of many to make the sub systems more modular. This commit gets

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
Richard Nyberg 19 years ago
parent
commit
71b986e549
17 changed files with 590 additions and 519 deletions
  1. +2
    -0
      btpd/Makefile.am
  2. +86
    -334
      btpd/btpd.c
  3. +14
    -61
      btpd/btpd.h
  4. +41
    -5
      btpd/cli_if.c
  5. +182
    -0
      btpd/main.c
  6. +90
    -49
      btpd/net.c
  7. +5
    -3
      btpd/net.h
  8. +33
    -6
      btpd/net_buf.c
  9. +14
    -0
      btpd/opts.c
  10. +8
    -0
      btpd/opts.h
  11. +14
    -14
      btpd/peer.c
  12. +2
    -2
      btpd/policy_choke.c
  13. +5
    -5
      btpd/policy_if.c
  14. +5
    -16
      btpd/torrent.c
  15. +0
    -2
      btpd/torrent.h
  16. +19
    -22
      btpd/tracker_req.c
  17. +70
    -0
      btpd/util.c

+ 2
- 0
btpd/Makefile.am View File

@@ -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\


+ 86
- 334
btpd/btpd.c View File

@@ -17,8 +17,8 @@
#include <getopt.h>
#include <math.h>
#include <locale.h>
#include <pwd.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -26,146 +26,33 @@
#include <unistd.h>

#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 }));
}

+ 14
- 61
btpd/btpd.h View File

@@ -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

+ 41
- 5
btpd/cli_if.c View File

@@ -1,6 +1,8 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <arpa/inet.h>
#include <sys/stat.h>

#include <inttypes.h>
#include <limits.h>
@@ -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);
}

+ 182
- 0
btpd/main.c View File

@@ -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;
}

+ 90
- 49
btpd/net.c View File

@@ -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();
}

+ 5
- 3
btpd/net.h View File

@@ -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);


+ 33
- 6
btpd/net_buf.c View File

@@ -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;
}



+ 14
- 0
btpd/opts.c View File

@@ -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;

+ 8
- 0
btpd/opts.h View File

@@ -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;

+ 14
- 14
btpd/peer.c View File

@@ -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;
}
}


+ 2
- 2
btpd/policy_choke.c View File

@@ -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;
}

+ 5
- 5
btpd/policy_if.c View File

@@ -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);


+ 5
- 16
btpd/torrent.c View File

@@ -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)
{


+ 0
- 2
btpd/torrent.h View File

@@ -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);



+ 19
- 22
btpd/tracker_req.c View File

@@ -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);
}

+ 70
- 0
btpd/util.c View File

@@ -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);
}

Loading…
Cancel
Save