From 2e21d27d10be294f0d6ba69dc65b5bdf089f0fb7 Mon Sep 17 00:00:00 2001 From: Olaf Rempel Date: Sat, 7 Jul 2007 13:11:51 +0200 Subject: [PATCH] multi torrent support --- connection.c | 124 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 96 insertions(+), 28 deletions(-) diff --git a/connection.c b/connection.c index 7035a29..82b49a3 100644 --- a/connection.c +++ b/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, "

ctorrent stats

\n\n"); - linebuffer_printf(lbuf, "\n"); + linebuffer_printf(lbuf, "

ctorrent stats

\n"); - struct client_con *tmp; - list_for_each_entry(tmp, &client_list, list) { - linebuffer_printf(lbuf, "\n", + struct torrent_file *torrent; + list_for_each_entry(torrent, &torrent_list, list) { + if (list_empty(&torrent->client_list)) + continue; + + linebuffer_printf(lbuf, "
Client IP:PortChunks (have/total/avail)Download total(current)Upload total(current)Completed since
%s%3.2lf%% (%d/%d/%d)%llu (%d)%llu (%d)%s
\n\n", torrent->name); + linebuffer_printf(lbuf, ""); + linebuffer_printf(lbuf, "\n"); + + struct client_con *tmp; + list_for_each_entry(tmp, &torrent->client_list, list) { + linebuffer_printf(lbuf, "", 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, "\n", tmp->total_dn, tmp->bw_dn, tmp->total_up, tmp->bw_up, (tmp->completed != 0) ? ctime(&tmp->completed) : "-"); + } + linebuffer_printf(lbuf, "
%s
Client IP:PortChunks (have/total/avail)Download total(current)Upload total(current)Completed since
%s%3.2lf%% (%d/%d/%d)%llu (%d)%llu (%d)%s
\n

\n"); } - - linebuffer_printf(lbuf, "\n\n"); + linebuffer_printf(lbuf, "\n"); linebuffer_writefd(lbuf, con->fd); linebuffer_free(lbuf);