torrent-stats/connection.c

192 lines
5.0 KiB
C
Raw Normal View History

2007-06-18 15:44:05 +02:00
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
2007-06-20 16:08:38 +02:00
#include <time.h>
2007-06-18 15:44:05 +02:00
#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;
2007-06-20 16:08:38 +02:00
long completed;
2007-06-18 15:44:05 +02:00
};
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;
2007-06-19 15:20:31 +02:00
if (linebuffer_readfd(con->lbuf, fd) < 0) {
2007-06-18 15:44:05 +02:00
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;
2007-06-19 15:20:31 +02:00
while ((line = linebuffer_getline(con->lbuf, NULL)) != NULL) {
2007-06-18 15:44:05 +02:00
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;
}
}
2007-06-19 15:20:31 +02:00
linebuffer_freeline(con->lbuf);
2007-06-18 15:44:05 +02:00
}
2007-06-20 16:08:38 +02:00
/* move completed clients to top of the list, ordered by their timestamp */
if (con->chunk_have == con->chunk_total && con->chunk_total != 0 && con->completed == 0) {
con->completed = time(NULL);
list_del(&con->list);
struct client_con *search;
list_for_each_entry(search, &client_list, list) {
if (search->completed == 0)
break;
if (search->completed > con->completed)
break;
}
list_add_tail(&con->list, &search->list);
return 0;
}
2007-06-18 15:44:05 +02:00
return 0;
}
2007-06-19 15:44:57 +02:00
int ctcs_trigger_status(void *privdata)
{
2007-06-20 16:08:38 +02:00
int delete = 0;
long timeout = time(NULL) - 300;
2007-06-19 15:44:57 +02:00
struct client_con *con;
2007-06-20 16:08:38 +02:00
list_for_each_entry(con, &client_list, list) {
2007-06-19 15:44:57 +02:00
write(event_get_fd(con->event), "SENDSTATUS\n", 11);
2007-06-20 16:08:38 +02:00
delete += (con->completed == 0) ? -1 : 1;
}
/* delete holds the number of clients to quit */
list_for_each_entry(con, &client_list, list) {
if (delete <= 0)
break;
if (con->completed == 0 || con->completed > timeout)
continue;
write(event_get_fd(con->event), "CTQUIT\n", 7);
delete--;
}
2007-06-19 15:44:57 +02:00
return 0;
}
2007-06-18 15:44:05 +02:00
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);
2007-06-20 16:08:38 +02:00
list_add_tail(&con->list, &client_list);
2007-06-18 15:44:05 +02:00
return 0;
}
int ctcs_httpd_handler(struct httpd_con *con, void *privdata)
{
2007-06-19 15:44:57 +02:00
struct linebuffer *lbuf = create_linebuffer(4096);
if (lbuf == NULL) {
2007-06-18 15:44:05 +02:00
httpd_send_error(con, "500 ERROR", "Out of Memory");
return -1;
}
2007-06-20 16:08:38 +02:00
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");
2007-06-18 15:44:05 +02:00
struct client_con *tmp;
list_for_each_entry(tmp, &client_list, list) {
2007-06-20 16:08:38 +02:00
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",
2007-06-18 15:44:05 +02:00
get_sockaddr_buf(&tmp->addr),
(double)tmp->chunk_have / (double)tmp->chunk_total * 100.0, tmp->chunk_have, tmp->chunk_total, tmp->chunk_avail,
2007-06-20 16:08:38 +02:00
tmp->total_dn, tmp->bw_dn, tmp->total_up, tmp->bw_up,
(tmp->completed != 0) ? ctime(&tmp->completed) : "-");
2007-06-18 15:44:05 +02:00
}
2007-06-19 15:44:57 +02:00
linebuffer_printf(lbuf, "</table>\n</body></html>\n");
2007-06-18 15:44:05 +02:00
2007-06-19 15:44:57 +02:00
linebuffer_writefd(lbuf, con->fd);
linebuffer_free(lbuf);
2007-06-18 15:44:05 +02:00
return 0;
}