#include #include #include #include #include "event.h" #include "httpd.h" #include "linebuffer.h" #include "list.h" #include "logging.h" #include "sockaddr.h" #include "tcpsocket.h" static LIST_HEAD(client_list); struct client_con { struct list_head list; struct sockaddr_in addr; struct event_fd *event; struct linebuffer *lbuf; int bw_up; int bw_dn; unsigned long long total_up; unsigned long long total_dn; int chunk_total; int chunk_avail; int chunk_have; }; static void free_client(struct client_con *con) { close(event_get_fd(con->event)); event_remove_fd(con->event); free(con->lbuf); free(con); } 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; } char *line; while ((line = linebuffer_getline(con->lbuf, NULL)) != NULL) { if (strncmp(line, "CTBW ", 5) == 0) { int bwup, bwdn, liup, lidn; if (sscanf(line +5, "%d,%d %d,%d", &bwdn, &bwup, &lidn, &liup) == 4) { con->bw_up = bwup; con->bw_dn = bwdn; } } else if (strncmp(line, "CTSTATUS ", 9) == 0) { int seeds1 = 0, seeds2 = 0, leech1 = 0, leech2 = 0, count = 0; int chunk1 = 0, chunk2 = 0, chunk3 = 0, bwdn = 0, bwup = 0; int lidn = 0, liup = 0, cache = 0; unsigned long long totdn = 0, totup = 0; if (sscanf(line +9, "%d:%d/%d:%d/%d %d/%d/%d %d,%d %llu,%llu %d,%d %d", &seeds1, &seeds2, &leech1, &leech2, &count, &chunk1, &chunk2, &chunk3, &bwdn, &bwup, &totdn, &totup, &lidn, &liup, &cache) == 15) { con->total_up = totup; con->total_dn = totdn; con->chunk_have = chunk1; con->chunk_total = chunk2; con->chunk_avail = chunk3; } } linebuffer_freeline(con->lbuf); } return 0; } int ctcs_trigger_status(void *privdata) { struct client_con *con; list_for_each_entry(con, &client_list, list) write(event_get_fd(con->event), "SENDSTATUS\n", 11); return 0; } int ctcs_accept_handler(int fd, void *privdata) { struct client_con *con = malloc(sizeof(struct client_con)); if (con == NULL) { log_print(LOG_WARN, "accept_cb(): out of memory"); return 0; } memset(con, 0, sizeof(struct client_con)); con->lbuf = create_linebuffer(1024); if (con->lbuf == NULL) { log_print(LOG_WARN, "accept_cb(): out of memory"); free(con); return 0; } unsigned int i = sizeof(con->addr); int sockfd = accept(fd, (struct sockaddr *)&con->addr, &i); if (sockfd < 0) { log_print(LOG_WARN, "accept_cb(): accept()"); free(con->lbuf); free(con); return 0; } con->event = event_add_readfd(NULL, sockfd, data_cb, con); list_add(&con->list, &client_list); return 0; } int ctcs_httpd_handler(struct httpd_con *con, void *privdata) { struct linebuffer *lbuf = create_linebuffer(4096); if (lbuf == NULL) { httpd_send_error(con, "500 ERROR", "Out of Memory"); return -1; } linebuffer_printf(lbuf, "

ctorrent stats

\n\n"); linebuffer_printf(lbuf, "\n"); struct client_con *tmp; list_for_each_entry(tmp, &client_list, list) { linebuffer_printf(lbuf, "\n", get_sockaddr_buf(&tmp->addr), (double)tmp->chunk_have / (double)tmp->chunk_total * 100.0, tmp->chunk_have, tmp->chunk_total, tmp->chunk_avail, tmp->total_dn, tmp->bw_dn, tmp->total_up, tmp->bw_up); } linebuffer_printf(lbuf, "
Client IP:PortChunks (have/total/avail)Download total(current)Upload total(current)
%s%3.2lf%% (%d/%d/%d)%llu (%d)%llu (%d)
\n\n"); httpd_send_header(con, "200 OK", "text/html"); linebuffer_writefd(lbuf, con->fd); linebuffer_free(lbuf); return 0; }