From b520eb32721c0c7bafdbfa1b20903edcee53e9ab Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Fri, 7 Mar 2003 14:57:36 +0000 Subject: [PATCH] Implement listing of all currently connected clients on a mountpoint svn path=/trunk/icecast/; revision=4434 --- News | 11 ++++++++ src/admin.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++--- src/net/sock.c | 9 ++++++ src/net/sock.h | 2 ++ 4 files changed, 92 insertions(+), 4 deletions(-) diff --git a/News b/News index 5460af00..151c8e09 100644 --- a/News +++ b/News @@ -1,3 +1,14 @@ +2003-03-08 + Started implementing generic admin interface. Supports (so far): + - dynamic configuration of mount fallbacks + /admin/fallbacks?mount=/mount&fallback=/fallback + - setting of mp3 metadata + /admin/metadata?mount=/mount&mode=updinfo&song=New%20Title + - dumping raw xml stats + /admin/rawstats + - listing all connected clients on a mountpoint: + /admin/listclients?mount=/mountname + 2003-03-05 Implemented the ability to reread the config file on SIGHUP. For now, this does not affect configuration for currently running sources (only new diff --git a/src/admin.c b/src/admin.c index 026d2b73..73068ac0 100644 --- a/src/admin.c +++ b/src/admin.c @@ -1,5 +1,7 @@ #include #include +#include +#include #include "config.h" #include "connection.h" @@ -21,6 +23,7 @@ #define COMMAND_FALLBACK 1 #define COMMAND_RAW_STATS 2 #define COMMAND_METADATA_UPDATE 3 +#define COMMAND_SHOW_LISTENERS 4 int admin_get_command(char *command) { @@ -32,12 +35,15 @@ int admin_get_command(char *command) return COMMAND_RAW_STATS; else if(!strcmp(command, "metadata")) return COMMAND_METADATA_UPDATE; + else if(!strcmp(command, "listclients")) + return COMMAND_SHOW_LISTENERS; else return COMMAND_ERROR; } static void command_fallback(client_t *client, source_t *source); static void command_metadata(client_t *client, source_t *source); +static void command_show_listeners(client_t *client, source_t *source); static void command_raw_stats(client_t *client); @@ -132,10 +138,13 @@ static void admin_handle_mount_request(client_t *client, source_t *source, case COMMAND_METADATA_UPDATE: command_metadata(client, source); break; + case COMMAND_SHOW_LISTENERS: + command_show_listeners(client, source); + break; default: WARN0("Mount request not recognised"); client_send_400(client, "Mount request unknown"); - return; + break; } } @@ -148,7 +157,7 @@ static void admin_handle_mount_request(client_t *client, source_t *source, } \ } while(0); -static void command_success(client_t *client, char *message) +static void html_success(client_t *client, char *message) { int bytes; @@ -161,6 +170,63 @@ static void command_success(client_t *client, char *message) client_destroy(client); } +static void html_head(client_t *client) +{ + int bytes; + + client->respcode = 200; + bytes = sock_write(client->con->sock, + "HTTP/1.0 200 OK\r\n" + "Content-Type: text/html\r\n" + "\r\n" + "Admin request" + ""); + if(bytes > 0) client->con->sent_bytes = bytes; +} + +static void html_write(client_t *client, char *fmt, ...) +{ + int bytes; + va_list ap; + + va_start(ap, fmt); + bytes = sock_write_fmt(client->con->sock, fmt, ap); + va_end(ap); + if(bytes > 0) client->con->sent_bytes = bytes; +} + +static void command_show_listeners(client_t *client, source_t *source) +{ + avl_node *client_node; + client_t *current; + time_t now = time(NULL); + + DEBUG1("Dumping listeners on mountpoint %s", source->mount); + + html_head(client); + + html_write(client, + ""); + + avl_tree_rlock(source->client_tree); + + client_node = avl_get_first(source->client_tree); + while(client_node) { + current = (client_t *)client_node->key; + + html_write(client, "", + current->con->ip, now-current->con->con_time, current->con->id); + + client_node = avl_get_next(client_node); + } + + avl_tree_unlock(source->client_tree); + + html_write(client, "
IPConnectedID
%s%d%ld
"); + + client_destroy(client); +} + static void command_fallback(client_t *client, source_t *source) { char *fallback; @@ -174,7 +240,7 @@ static void command_fallback(client_t *client, source_t *source) source->fallback_mount = strdup(fallback); free(old); - command_success(client, "Fallback configured"); + html_success(client, "Fallback configured"); } static void command_metadata(client_t *client, source_t *source) @@ -210,7 +276,7 @@ static void command_metadata(client_t *client, source_t *source) DEBUG2("Metadata on mountpoint %s changed to \"%s\"", source->mount, value); stats_event(source->mount, "title", value); - command_success(client, "Metadata update successful"); + html_success(client, "Metadata update successful"); } static void command_raw_stats(client_t *client) { diff --git a/src/net/sock.c b/src/net/sock.c index f31491b0..d5a8f519 100644 --- a/src/net/sock.c +++ b/src/net/sock.c @@ -314,6 +314,15 @@ int sock_write(sock_t sock, const char *fmt, ...) return sock_write_bytes(sock, buff, strlen(buff)); } +int sock_write_fmt(sock_t sock, char *fmt, va_list ap) +{ + char buff[1024]; + + vsnprintf(buff, 1024, fmt, ap); + + return sock_write_bytes(sock, buff, strlen(buff)); +} + int sock_read_bytes(sock_t sock, char *buff, const int len) { diff --git a/src/net/sock.h b/src/net/sock.h index 6944bd05..c4d78e73 100644 --- a/src/net/sock.h +++ b/src/net/sock.h @@ -22,6 +22,7 @@ #ifndef __SOCK_H #define __SOCK_H +#include #ifdef _WIN32 #include @@ -87,6 +88,7 @@ int sock_connected (int sock, unsigned timeout); /* Socket write functions */ int sock_write_bytes(sock_t sock, const void *buff, const size_t len); int sock_write(sock_t sock, const char *fmt, ...); +int sock_write_fmt(sock_t sock, char *fmt, va_list ap); int sock_write_string(sock_t sock, const char *buff); ssize_t sock_writev (int sock, const struct iovec *iov, const size_t count);