multi torrent support
This commit is contained in:
parent
419ce7766e
commit
2e21d27d10
124
connection.c
124
connection.c
@ -12,7 +12,13 @@
|
||||
#include "sockaddr.h"
|
||||
#include "tcpsocket.h"
|
||||
|
||||
static LIST_HEAD(client_list);
|
||||
static LIST_HEAD(torrent_list);
|
||||
|
||||
struct torrent_file {
|
||||
struct list_head list;
|
||||
struct list_head client_list;
|
||||
char *name;
|
||||
};
|
||||
|
||||
struct client_con {
|
||||
struct list_head list;
|
||||
@ -32,10 +38,47 @@ struct client_con {
|
||||
int chunk_have;
|
||||
|
||||
long completed;
|
||||
|
||||
struct torrent_file *torrent;
|
||||
};
|
||||
|
||||
static struct torrent_file * find_create_torrent(const char *filename)
|
||||
{
|
||||
struct torrent_file *torrent;
|
||||
list_for_each_entry(torrent, &torrent_list, list) {
|
||||
if (strcmp(torrent->name, filename) == 0)
|
||||
return torrent;
|
||||
}
|
||||
|
||||
torrent = malloc(sizeof(struct torrent_file) + strlen(filename));
|
||||
if (torrent == NULL) {
|
||||
log_print(LOG_WARN, "find_create_torrent(): out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&torrent->client_list);
|
||||
torrent->name = strdup(filename);
|
||||
|
||||
struct torrent_file *search;
|
||||
list_for_each_entry(search, &torrent_list, list)
|
||||
if (strcmp(search->name, torrent->name) > 0)
|
||||
break;
|
||||
|
||||
list_add_tail(&torrent->list, &search->list);
|
||||
return torrent;
|
||||
}
|
||||
|
||||
static void free_client(struct client_con *con)
|
||||
{
|
||||
list_del(&con->list);
|
||||
|
||||
/* remove torrents without clients */
|
||||
if (list_empty(&con->torrent->client_list)) {
|
||||
list_del(&con->torrent->list);
|
||||
free(con->torrent->name);
|
||||
free(con->torrent);
|
||||
}
|
||||
|
||||
close(event_get_fd(con->event));
|
||||
event_remove_fd(con->event);
|
||||
free(con->lbuf);
|
||||
@ -47,8 +90,6 @@ static int data_cb(int fd, void *privdata)
|
||||
struct client_con *con = (struct client_con *)privdata;
|
||||
|
||||
if (linebuffer_readfd(con->lbuf, fd) < 0) {
|
||||
log_print(LOG_WARN, "data_cb(): client %s read", get_sockaddr_buf(&con->addr));
|
||||
list_del(&con->list);
|
||||
free_client(con);
|
||||
return -1;
|
||||
}
|
||||
@ -80,6 +121,17 @@ static int data_cb(int fd, void *privdata)
|
||||
con->chunk_total = chunk2;
|
||||
con->chunk_avail = chunk3;
|
||||
}
|
||||
|
||||
} else if (strncmp(line, "CTORRENT ", 9) == 0) {
|
||||
char *filename = strrchr(line +9, ' ');
|
||||
if (filename != NULL) {
|
||||
struct torrent_file *torrent = find_create_torrent(filename +1);
|
||||
if (torrent != NULL) {
|
||||
list_del(&con->list);
|
||||
con->torrent = torrent;
|
||||
list_add_tail(&con->list, &con->torrent->client_list);
|
||||
}
|
||||
}
|
||||
}
|
||||
linebuffer_freeline(con->lbuf);
|
||||
}
|
||||
@ -91,7 +143,7 @@ static int data_cb(int fd, void *privdata)
|
||||
list_del(&con->list);
|
||||
|
||||
struct client_con *search;
|
||||
list_for_each_entry(search, &client_list, list) {
|
||||
list_for_each_entry(search, &con->torrent->client_list, list) {
|
||||
if (search->completed == 0)
|
||||
break;
|
||||
|
||||
@ -106,26 +158,30 @@ static int data_cb(int fd, void *privdata)
|
||||
|
||||
int ctcs_trigger_status(void *privdata)
|
||||
{
|
||||
int delete = 0;
|
||||
long timeout = time(NULL) - 300;
|
||||
|
||||
struct client_con *con;
|
||||
list_for_each_entry(con, &client_list, list) {
|
||||
write(event_get_fd(con->event), "SENDSTATUS\n", 11);
|
||||
struct torrent_file *torrent;
|
||||
list_for_each_entry(torrent, &torrent_list, list) {
|
||||
int delete = 0;
|
||||
|
||||
delete += (con->completed == 0) ? -1 : 1;
|
||||
}
|
||||
struct client_con *con;
|
||||
list_for_each_entry(con, &torrent->client_list, list) {
|
||||
write(event_get_fd(con->event), "SENDSTATUS\n", 11);
|
||||
|
||||
/* delete holds the number of clients to quit */
|
||||
list_for_each_entry(con, &client_list, list) {
|
||||
if (delete <= 0)
|
||||
break;
|
||||
delete += (con->completed == 0) ? -1 : 1;
|
||||
}
|
||||
|
||||
if (con->completed == 0 || con->completed > timeout)
|
||||
continue;
|
||||
/* delete holds the number of clients to quit */
|
||||
list_for_each_entry(con, &torrent->client_list, list) {
|
||||
if (delete <= 0)
|
||||
break;
|
||||
|
||||
write(event_get_fd(con->event), "CTQUIT\n", 7);
|
||||
delete--;
|
||||
if (con->completed == 0 || con->completed > timeout)
|
||||
continue;
|
||||
|
||||
write(event_get_fd(con->event), "CTQUIT\n", 7);
|
||||
delete--;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -158,32 +214,44 @@ int ctcs_accept_handler(int fd, void *privdata)
|
||||
|
||||
con->event = event_add_readfd(NULL, sockfd, data_cb, con);
|
||||
|
||||
list_add_tail(&con->list, &client_list);
|
||||
con->torrent = find_create_torrent("[unknown]");
|
||||
list_add_tail(&con->list, &con->torrent->client_list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ctcs_httpd_handler(struct httpd_con *con, void *privdata)
|
||||
{
|
||||
struct linebuffer *lbuf = create_linebuffer(4096);
|
||||
struct linebuffer *lbuf = create_linebuffer(16384);
|
||||
if (lbuf == NULL) {
|
||||
httpd_send_error(con, "500 ERROR", "Out of Memory");
|
||||
return -1;
|
||||
}
|
||||
|
||||
linebuffer_printf(lbuf, "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n");
|
||||
linebuffer_printf(lbuf, "<html><head><meta http-equiv=\"refresh\" content=\"30;\"></head><body><h1>ctorrent stats</h1>\n<table border=\"1\">\n");
|
||||
linebuffer_printf(lbuf, "<tr><td><b>Client IP:Port</b></td><td><b>Chunks (have/total/avail)</b></td><td><b>Download total(current)</b></td><td><b>Upload total(current)</b></td><td><b>Completed since</b></td></tr>\n");
|
||||
linebuffer_printf(lbuf, "<html><head><meta http-equiv=\"refresh\" content=\"30;\"></head><body><h1>ctorrent stats</h1>\n");
|
||||
|
||||
struct client_con *tmp;
|
||||
list_for_each_entry(tmp, &client_list, list) {
|
||||
linebuffer_printf(lbuf, "<tr><td align=\"right\">%s</td><td align=\"right\">%3.2lf%% (%d/%d/%d)</td><td align=\"right\">%llu (%d)</td><td align=\"right\">%llu (%d)</td><td align=\"right\">%s</td></tr>\n",
|
||||
struct torrent_file *torrent;
|
||||
list_for_each_entry(torrent, &torrent_list, list) {
|
||||
if (list_empty(&torrent->client_list))
|
||||
continue;
|
||||
|
||||
linebuffer_printf(lbuf, "<table border=\"1\">\n<tr><td colspan=\"5\" align=\"center\">%s</td></tr>\n", torrent->name);
|
||||
linebuffer_printf(lbuf, "<tr></td><td><b>Client IP:Port</b></td><td><b>Chunks (have/total/avail)</b></td>");
|
||||
linebuffer_printf(lbuf, "<td><b>Download total(current)</b></td><td><b>Upload total(current)</b></td><td><b>Completed since</b></td></tr>\n");
|
||||
|
||||
struct client_con *tmp;
|
||||
list_for_each_entry(tmp, &torrent->client_list, list) {
|
||||
linebuffer_printf(lbuf, "<tr><td align=\"right\">%s</td><td align=\"right\">%3.2lf%% (%d/%d/%d)</td>",
|
||||
get_sockaddr_buf(&tmp->addr),
|
||||
(double)tmp->chunk_have / (double)tmp->chunk_total * 100.0, tmp->chunk_have, tmp->chunk_total, tmp->chunk_avail,
|
||||
(double)tmp->chunk_have / (double)tmp->chunk_total * 100.0, tmp->chunk_have, tmp->chunk_total, tmp->chunk_avail);
|
||||
|
||||
linebuffer_printf(lbuf, "<td align=\"right\">%llu (%d)</td><td align=\"right\">%llu (%d)</td><td align=\"right\">%s</td></tr>\n",
|
||||
tmp->total_dn, tmp->bw_dn, tmp->total_up, tmp->bw_up,
|
||||
(tmp->completed != 0) ? ctime(&tmp->completed) : "-");
|
||||
}
|
||||
linebuffer_printf(lbuf, "</table>\n<br><br>\n");
|
||||
}
|
||||
|
||||
linebuffer_printf(lbuf, "</table>\n</body></html>\n");
|
||||
linebuffer_printf(lbuf, "</body></html>\n");
|
||||
|
||||
linebuffer_writefd(lbuf, con->fd);
|
||||
linebuffer_free(lbuf);
|
||||
|
Loading…
Reference in New Issue
Block a user