diff options
| author | Richard Nyberg <rnyberg@murmeldjur.se> | 2009-01-25 13:10:27 +0100 |
|---|---|---|
| committer | Richard Nyberg <rnyberg@murmeldjur.se> | 2009-01-26 22:15:10 +0100 |
| commit | 438881f16f8f67de06cc03eb5cc86c1e82ab4dc0 (patch) | |
| tree | 585c7d9cf0269394aea8ab180d69d0120e5ec839 | |
| parent | 50b69abbcdbd5d670d987a9affba41dff57c9525 (diff) | |
| download | btpd-438881f16f8f67de06cc03eb5cc86c1e82ab4dc0.tar.gz btpd-438881f16f8f67de06cc03eb5cc86c1e82ab4dc0.zip | |
Improve the torrent stop and btpd shutdown sequences.
Torrents are now considered stopped and may be restarted even if the stop event haven't been sent the trackers yet. The same holds for the del and add commands. A btpd process in shutdown mode that only have stopped torrents, but is still sending the stop event to trackers, will release resources that would block a new btpd to start. It will the silently exit when it's finished with the trackers. This also makes the timeout parameter for shutdown unnecessary.
| -rw-r--r-- | btpd/btpd.c | 50 | ||||
| -rw-r--r-- | btpd/btpd.h | 2 | ||||
| -rw-r--r-- | btpd/cli_if.c | 53 | ||||
| -rw-r--r-- | btpd/main.c | 6 | ||||
| -rw-r--r-- | btpd/net.c | 11 | ||||
| -rw-r--r-- | btpd/tlib.c | 18 | ||||
| -rw-r--r-- | btpd/tlib.h | 3 | ||||
| -rw-r--r-- | btpd/torrent.c | 90 | ||||
| -rw-r--r-- | btpd/torrent.h | 8 | ||||
| -rw-r--r-- | cli/kill.c | 17 | ||||
| -rw-r--r-- | misc/btpd_if.c | 7 | ||||
| -rw-r--r-- | misc/btpd_if.h | 2 |
12 files changed, 179 insertions, 88 deletions
diff --git a/btpd/btpd.c b/btpd/btpd.c index 6d48d55..109c7b6 100644 --- a/btpd/btpd.c +++ b/btpd/btpd.c @@ -5,9 +5,9 @@ static uint8_t m_peer_id[20]; static struct timeout m_heartbeat; -static struct timeout m_grace_timer; static int m_signal; static int m_shutdown; +static int m_ghost; long btpd_seconds; @@ -18,29 +18,35 @@ btpd_exit(int code) exit(code); } +extern int pidfd; +void ipc_shutdown(void); +void net_shutdown(void); + static void -grace_cb(int fd, short type, void *arg) +death_procedure(void) { - struct torrent *tp; - BTPDQ_FOREACH(tp, torrent_get_all(), entry) - torrent_stop(tp, 0); + assert(m_shutdown); + if (torrent_count() == 0) + btpd_exit(0); + if (!m_ghost && torrent_count() == torrent_ghosts()) { + btpd_log(BTPD_L_BTPD, "Entering pre exit mode. Bye!\n"); + fclose(stderr); + fclose(stdout); + net_shutdown(); + ipc_shutdown(); + close(pidfd); + m_ghost = 1; + } } void -btpd_shutdown(int grace_seconds) +btpd_shutdown(void) { - if (torrent_count() == 0) - btpd_exit(0); - else { - struct torrent *tp; - m_shutdown = 1; - BTPDQ_FOREACH(tp, torrent_get_all(), entry) - if (tp->state != T_STOPPING) - torrent_stop(tp, 0); - if (grace_seconds >= 0) - btpd_timer_add(&m_grace_timer, - (& (struct timespec){ grace_seconds, 0 })); - } + m_shutdown = 1; + struct torrent *tp, *next; + BTPDQ_FOREACH_MUTABLE(tp, torrent_get_all(), entry, next) + torrent_stop(tp, 0); + death_procedure(); } int btpd_is_stopping(void) @@ -69,11 +75,12 @@ heartbeat_cb(int fd, short type, void *arg) torrent_on_tick_all(); if (m_signal) { btpd_log(BTPD_L_BTPD, "Got signal %d.\n", m_signal); - btpd_shutdown(30); m_signal = 0; + if (!m_shutdown) + btpd_shutdown(); } - if (m_shutdown && torrent_count() == 0) - btpd_exit(0); + if (m_shutdown) + death_procedure(); } void tr_init(void); @@ -123,7 +130,6 @@ btpd_init(void) tr_init(); tlib_init(); - timer_init(&m_grace_timer, grace_cb, NULL); timer_init(&m_heartbeat, heartbeat_cb, NULL); btpd_timer_add(&m_heartbeat, (& (struct timespec) { 1, 0 })); } diff --git a/btpd/btpd.h b/btpd/btpd.h index 4312a03..f28591d 100644 --- a/btpd/btpd.h +++ b/btpd/btpd.h @@ -82,7 +82,7 @@ void btpd_ev_disable(struct fdev *ev, uint16_t flags); void btpd_timer_add(struct timeout *to, struct timespec *ts); void btpd_timer_del(struct timeout *to); -void btpd_shutdown(int grace_seconds); +void btpd_shutdown(void); int btpd_is_stopping(void); const uint8_t *btpd_get_peer_id(void); diff --git a/btpd/cli_if.c b/btpd/cli_if.c index e129b88..61858b9 100644 --- a/btpd/cli_if.c +++ b/btpd/cli_if.c @@ -8,6 +8,7 @@ struct cli { struct fdev read; }; +static int m_listen_sd; static struct fdev m_cli_incoming; static int @@ -135,6 +136,8 @@ write_ans(struct iobuf *iob, struct tlib *tl, enum ipc_tval val) case T_LEECH: ts = IPC_TSTATE_LEECH; break; + case T_GHOST: + break; } } iobuf_print(iob, "i%de", ts); @@ -185,9 +188,10 @@ cmd_tget(struct cli *cli, int argc, const char *args) struct tlib *tlv[tlib_count()]; tlib_put_all(tlv); for (int i = 0; i < sizeof(tlv) / sizeof(tlv[0]); i++) { - if ((from == IPC_TWC_ALL || - (tlv[i]->tp == NULL && from == IPC_TWC_INACTIVE) || - (tlv[i]->tp != NULL && from == IPC_TWC_ACTIVE))) { + if (!torrent_haunting(tlv[i]) && ( + from == IPC_TWC_ALL || + (!torrent_active(tlv[i]) && from == IPC_TWC_INACTIVE) || + (torrent_active(tlv[i]) && from == IPC_TWC_ACTIVE))) { iobuf_swrite(&iob, "l"); for (int k = 0; k < nkeys; k++) write_ans(&iob, tlv[i], opts[k]); @@ -206,7 +210,7 @@ cmd_tget(struct cli *cli, int argc, const char *args) free(opts); return IPC_COMMERR; } - if (tl != NULL) { + if (tl != NULL && !torrent_haunting(tl)) { iobuf_swrite(&iob, "l"); for (int i = 0; i < nkeys; i++) write_ans(&iob, tl, opts[i]); @@ -248,10 +252,15 @@ cmd_add(struct cli *cli, int argc, const char *args) content[csize] = '\0'; tl = tlib_by_hash(mi_info_hash(mi, hash)); - if (tl != NULL) + if (tl != NULL && !torrent_haunting(tl)) return write_code_buffer(cli, IPC_ETENTEXIST); - tl = tlib_add(hash, mi, mi_size, content, - benc_dget_str(args, "name", NULL)); + if (tl != NULL) { + tl = tlib_readd(tl, hash, mi, mi_size, content, + benc_dget_str(args, "name", NULL)); + } else { + tl = tlib_add(hash, mi, mi_size, content, + benc_dget_str(args, "name", NULL)); + } return write_add_buffer(cli, tl->num); } @@ -270,7 +279,7 @@ cmd_del(struct cli *cli, int argc, const char *args) else return IPC_COMMERR; - if (tl == NULL) + if (tl == NULL || torrent_haunting(tl)) ret = write_code_buffer(cli, IPC_ENOTENT); else { ret = write_code_buffer(cli, IPC_OK); @@ -300,9 +309,9 @@ cmd_start(struct cli *cli, int argc, const char *args) else return IPC_COMMERR; - if (tl == NULL) + if (tl == NULL || torrent_haunting(tl)) code = IPC_ENOTENT; - else if (tl->tp != NULL) + else if (!torrent_startable(tl)) code = IPC_ETACTIVE; else if ((code = torrent_start(tl)) == IPC_OK) @@ -324,9 +333,9 @@ cmd_stop(struct cli *cli, int argc, const char *args) else return IPC_COMMERR; - if (tl == NULL) + if (tl == NULL || torrent_haunting(tl)) return write_code_buffer(cli, IPC_ENOTENT); - else if (tl->tp == NULL) + else if (!torrent_active(tl)) return write_code_buffer(cli, IPC_ETINACTIVE); else { // Stopping a torrent may trigger exit so we need to reply before. @@ -340,12 +349,11 @@ cmd_stop(struct cli *cli, int argc, const char *args) static int cmd_stop_all(struct cli *cli, int argc, const char *args) { - struct torrent *tp; + struct torrent *tp, *next; int ret = write_code_buffer(cli, IPC_OK); active_clear(); - BTPDQ_FOREACH(tp, torrent_get_all(), entry) - if (tp->state != T_STOPPING) - torrent_stop(tp, 0); + BTPDQ_FOREACH_MUTABLE(tp, torrent_get_all(), entry, next) + torrent_stop(tp, 0); return ret; } @@ -354,11 +362,8 @@ cmd_die(struct cli *cli, int argc, const char *args) { int err = write_code_buffer(cli, IPC_OK); if (!btpd_is_stopping()) { - int grace_seconds = -1; - if (argc == 1 && benc_isint(args)) - grace_seconds = benc_int(args, NULL); btpd_log(BTPD_L_BTPD, "Someone wants me dead.\n"); - btpd_shutdown(grace_seconds); + btpd_shutdown(); } return err; } @@ -450,6 +455,13 @@ client_connection_cb(int sd, short type, void *arg) } void +ipc_shutdown(void) +{ + btpd_ev_del(&m_cli_incoming); + close(m_listen_sd); +} + +void ipc_init(void) { int sd; @@ -477,4 +489,5 @@ ipc_init(void) set_nonblocking(sd); btpd_ev_new(&m_cli_incoming, sd, EV_READ, client_connection_cb, NULL); + m_listen_sd = sd; } diff --git a/btpd/main.c b/btpd/main.c index efa0e5d..c3cd395 100644 --- a/btpd/main.c +++ b/btpd/main.c @@ -5,6 +5,7 @@ int btpd_daemon_phase = 2; int first_btpd_comm[2]; +int pidfd; void first_btpd_exit(char code) @@ -15,7 +16,7 @@ first_btpd_exit(char code) } static void -writepid(int pidfd) +writepid(void) { int nw; char pidtxt[100]; @@ -28,7 +29,6 @@ static void setup_daemon(int daemonize, const char *dir) { char c; - int pidfd; pid_t pid; struct timespec ts; @@ -91,7 +91,7 @@ setup_daemon(int daemonize, const char *dir) if (lockf(pidfd, F_TLOCK, 0) == -1) btpd_err("Another instance of btpd is probably running in %s.\n", dir); - writepid(pidfd); + writepid(); } static void diff --git a/btpd/net.c b/btpd/net.c index 0112abe..2208223 100644 --- a/btpd/net.c +++ b/btpd/net.c @@ -14,6 +14,7 @@ struct net_listener { struct fdev ev; }; +static int m_nlisteners; static struct net_listener *m_net_listeners; unsigned net_npeers; @@ -669,6 +670,15 @@ net_af_spec(void) } void +net_shutdown(void) +{ + for (int i = 0; i < m_nlisteners; i++) { + btpd_ev_del(&m_net_listeners[i].ev); + close(m_net_listeners[i].sd); + } +} + +void net_init(void) { m_bw_bytes_out = net_bw_limit_out; @@ -699,6 +709,7 @@ net_init(void) net_ipv6 = found_ipv6; if (!net_ipv4 && !net_ipv6) btpd_err("no usable address found. wrong use of -4/-6 perhaps.\n"); + m_nlisteners = count; m_net_listeners = btpd_calloc(count, sizeof(*m_net_listeners)); for (ai = res; ai != NULL; ai = ai->ai_next) { count--; diff --git a/btpd/tlib.c b/btpd/tlib.c index e68c341..bd4fbc6 100644 --- a/btpd/tlib.c +++ b/btpd/tlib.c @@ -65,7 +65,7 @@ tlib_del(struct tlib *tl) char path[PATH_MAX]; DIR *dir; struct dirent *de; - assert(tl->tp == NULL); + assert(tl->tp == NULL || tl->tp->state == T_GHOST); snprintf(path, PATH_MAX, "torrents/%s", bin2hex(tl->hash, relpath, 20)); if ((dir = opendir(path)) != NULL) { while ((de = readdir(dir)) != NULL) { @@ -78,7 +78,8 @@ tlib_del(struct tlib *tl) } snprintf(path, PATH_MAX, "torrents/%s", relpath); remove(path); - tlib_kill(tl); + if (tl->tp == NULL) + tlib_kill(tl); return 0; } @@ -257,6 +258,19 @@ tlib_add(const uint8_t *hash, const char *mi, size_t mi_size, return tl; } +struct tlib * +tlib_readd(struct tlib *tl, const uint8_t *hash, const char *mi, + size_t mi_size, const char *content, char *name) +{ + struct tlib *tln; + struct torrent *tp = tl->tp; + tp->delete = 0; + tlib_kill(tl); + tln = tlib_add(hash, mi, mi_size, content, name); + tln->tp = tp; + return tln; +} + static int num_test(const void *k1, const void *k2) { diff --git a/btpd/tlib.h b/btpd/tlib.h index 0147c36..51eacbb 100644 --- a/btpd/tlib.h +++ b/btpd/tlib.h @@ -26,7 +26,10 @@ void tlib_put_all(struct tlib **v); struct tlib *tlib_add(const uint8_t *hash, const char *mi, size_t mi_size, const char *content, char *name); +struct tlib *tlib_readd(struct tlib *tl, const uint8_t *hash, const char *mi, + size_t mi_size, const char *content, char *name); int tlib_del(struct tlib *tl); +void tlib_kill(struct tlib *tl); void tlib_update_info(struct tlib *tl, int only_file); diff --git a/btpd/torrent.c b/btpd/torrent.c index c48e844..0ec0b65 100644 --- a/btpd/torrent.c +++ b/btpd/torrent.c @@ -4,6 +4,7 @@ #define SAVE_INTERVAL 300 +static unsigned m_nghosts; static unsigned m_ntorrents; static struct torrent_tq m_torrents = BTPDQ_HEAD_INITIALIZER(m_torrents); @@ -22,6 +23,12 @@ torrent_count(void) return m_ntorrents; } +unsigned +torrent_ghosts(void) +{ + return m_nghosts; +} + struct torrent * torrent_by_num(unsigned num) { @@ -71,12 +78,41 @@ torrent_block_size(struct torrent *tp, uint32_t piece, uint32_t nblocks, } } +static void +torrent_kill(struct torrent *tp) +{ + assert(m_ntorrents > 0); + assert(!(net_active(tp) || cm_active(tp))); + if (tp->state == T_GHOST) + m_nghosts--; + m_ntorrents--; + BTPDQ_REMOVE(&m_torrents, tp, entry); + if (tp->delete) + tlib_kill(tp->tl); + else + tp->tl->tp = NULL; + tr_kill(tp); + net_kill(tp); + cm_kill(tp); + mi_free_files(tp->nfiles, tp->files); + if (m_savetp == tp) + if ((m_savetp = BTPDQ_NEXT(tp, entry)) == NULL) + m_savetp = BTPDQ_FIRST(&m_torrents); + free(tp); +} + enum ipc_err torrent_start(struct tlib *tl) { struct torrent *tp; char *mi; + if (tl->tp != NULL) { + assert(torrent_startable(tl)); + torrent_kill(tl->tp); + tl->tp = NULL; + } + if (tl->dir == NULL) return IPC_EBADTENT; @@ -111,25 +147,16 @@ torrent_start(struct tlib *tl) return IPC_OK; } -static void -torrent_kill(struct torrent *tp) +static +void become_ghost(struct torrent *tp) { btpd_log(BTPD_L_BTPD, "Stopped torrent '%s'.\n", torrent_name(tp)); - assert(m_ntorrents > 0); - assert(!(tr_active(tp) || net_active(tp) || cm_active(tp))); - m_ntorrents--; - BTPDQ_REMOVE(&m_torrents, tp, entry); - tp->tl->tp = NULL; + tp->state = T_GHOST; if (tp->delete) tlib_del(tp->tl); - tr_kill(tp); - net_kill(tp); - cm_kill(tp); - mi_free_files(tp->nfiles, tp->files); - if (m_savetp == tp) - if ((m_savetp = BTPDQ_NEXT(tp, entry)) == NULL) - m_savetp = BTPDQ_FIRST(&m_torrents); - free(tp); + else + tlib_update_info(tp->tl, 0); + m_nghosts++; } void @@ -148,10 +175,13 @@ torrent_stop(struct torrent *tp, int delete) tr_stop(tp); if (cm_active(tp)) cm_stop(tp); - if (!delete) - tlib_update_info(tp->tl, 0); + if (!cm_active(tp)) { + become_ghost(tp); + if (!tr_active(tp)) + torrent_kill(tp); + } break; - case T_STOPPING: + default: break; } } @@ -187,7 +217,11 @@ torrent_on_tick(struct torrent *tp) } break; case T_STOPPING: - if (!(cm_active(tp) || tr_active(tp))) + if (cm_active(tp)) + break; + become_ghost(tp); + case T_GHOST: + if (!tr_active(tp)) torrent_kill(tp); break; default: @@ -213,3 +247,21 @@ torrent_on_tick_all(void) } } } + +int +torrent_active(struct tlib *tl) +{ + return tl->tp != NULL && tl->tp->state != T_GHOST; +} + +int +torrent_startable(struct tlib *tl) +{ + return tl->tp == NULL || (tl->tp->state == T_GHOST && !tl->tp->delete); +} + +int +torrent_haunting(struct tlib *tl) +{ + return tl->tp != NULL && tl->tp->delete && tl->tp->state == T_GHOST; +} diff --git a/btpd/torrent.h b/btpd/torrent.h index e8eee4c..273b32f 100644 --- a/btpd/torrent.h +++ b/btpd/torrent.h @@ -8,7 +8,8 @@ enum torrent_state { T_STARTING, T_LEECH, T_SEED, - T_STOPPING + T_STOPPING, + T_GHOST }; struct torrent { @@ -34,6 +35,7 @@ struct torrent { BTPDQ_HEAD(torrent_tq, torrent); unsigned torrent_count(void); +unsigned torrent_ghosts(void); const struct torrent_tq *torrent_get_all(void); struct torrent *torrent_by_num(unsigned num); struct torrent *torrent_by_hash(const uint8_t *hash); @@ -41,6 +43,10 @@ struct torrent *torrent_by_hash(const uint8_t *hash); enum ipc_err torrent_start(struct tlib *tl); void torrent_stop(struct torrent *tp, int delete); +int torrent_active(struct tlib *tl); +int torrent_haunting(struct tlib *tl); +int torrent_startable(struct tlib *tl); + off_t torrent_piece_size(struct torrent *tp, uint32_t piece); uint32_t torrent_piece_blocks(struct torrent *tp, uint32_t piece); uint32_t torrent_block_size(struct torrent *tp, uint32_t piece, diff --git a/cli/kill.c b/cli/kill.c index 9ae57f1..1d727bb 100644 --- a/cli/kill.c +++ b/cli/kill.c @@ -6,12 +6,7 @@ usage_kill(void) printf( "Shutdown btpd.\n" "\n" - "Usage: kill [seconds]\n" - "\n" - "Arguments:\n" - "seconds\n" - "\tThe number of seconds btpd waits before giving up on unresponsive\n" - "\ttrackers.\n" + "Usage: kill\n" "\n" ); exit(1); @@ -20,18 +15,12 @@ usage_kill(void) void cmd_kill(int argc, char **argv) { - int seconds = -1; enum ipc_err code; - char *endptr; - if (argc == 2) { - seconds = strtol(argv[1], &endptr, 10); - if (strlen(argv[1]) > endptr - argv[1] || seconds < 0) - usage_kill(); - } else if (argc > 2) + if (argc > 1) usage_kill(); btpd_connect(); - if ((code = btpd_die(ipc, seconds)) != 0) + if ((code = btpd_die(ipc)) != 0) diemsg("command failed (%s).\n", ipc_strerror(code)); } diff --git a/misc/btpd_if.c b/misc/btpd_if.c index f01cab9..a62daba 100644 --- a/misc/btpd_if.c +++ b/misc/btpd_if.c @@ -155,13 +155,10 @@ ipc_buf_req_code(struct ipc *ipc, struct iobuf *iob) } enum ipc_err -btpd_die(struct ipc *ipc, int seconds) +btpd_die(struct ipc *ipc) { struct iobuf iob = iobuf_init(16); - if (seconds >= 0) - iobuf_print(&iob, "l3:diei%dee", seconds); - else - iobuf_swrite(&iob, "l3:diee"); + iobuf_swrite(&iob, "l3:diee"); return ipc_buf_req_code(ipc, &iob); } diff --git a/misc/btpd_if.h b/misc/btpd_if.h index 0879bd4..526e5c3 100644 --- a/misc/btpd_if.h +++ b/misc/btpd_if.h @@ -80,7 +80,7 @@ enum ipc_err btpd_del(struct ipc *ipc, struct ipc_torrent *tp); enum ipc_err btpd_start(struct ipc *ipc, struct ipc_torrent *tp); enum ipc_err btpd_stop(struct ipc *ipc, struct ipc_torrent *tp); enum ipc_err btpd_stop_all(struct ipc *ipc); -enum ipc_err btpd_die(struct ipc *ipc, int seconds); +enum ipc_err btpd_die(struct ipc *ipc); enum ipc_err btpd_get(struct ipc *ipc, enum ipc_dval *keys, size_t nkeys, tget_cb_t cb, void *arg); enum ipc_err btpd_tget(struct ipc *ipc, struct ipc_torrent *tps, size_t ntps, |