this mod_mp3-status patch is not more than a quick hack to add a status-report-handler mod_mp3 is available from http://media.tangent.org/ Requesting the status is simple: GET /?op=status HTTP/1.0 Host: your.mod_mp3.host This will give you something like this: # status 0.0.0.0 on air now 5 -1 192.168.0.222 0eed5ce2862a905a562b600a03db3473 This is a tab-separated list telling you which child (#) is currently streaming what song (on air now) to which client (0.0.0.0). In this case, child #5 streams 0eed5ce2862a905a562b600a03db3473 to the host with ip 192.168.0.222 in my local network. Of course, this doesn't really tell you much. I am using Ampache (available from http://ampache.kveton.com/), so i have a database available to ask for details, so this was enough for me. -lukas schroeder diff -ubNr mod_mp3-0.25.orig/mod_mp3.c mod_mp3-0.25/mod_mp3.c --- mod_mp3-0.25.orig/mod_mp3.c Tue Jul 17 05:49:54 2001 +++ mod_mp3-0.25/mod_mp3.c Sun Sep 16 13:03:40 2001 @@ -5,7 +5,7 @@ #include "mod_mp3.h" /* Setup for our scoreboard */ -static key_t shmkey = IPC_CREAT; +static key_t shmkey = 0xBEEBBEEB; /* sends out the right headers for data requests */ void send_headers(request_rec *r, mp3_conf* cfg, request_data *request) { @@ -51,6 +51,8 @@ int shmid = -1; scoreboard *shm = NULL; + scfg->pool = ap_make_sub_pool(p); + if ((shmid = shmget(shmkey, sizeof(scoreboard), IPC_CREAT | 0666)) < 0) { printf("%s - Cannot create Shared Memory", __FILE__); exit(1); @@ -72,7 +74,9 @@ return (void *) scfg; } -static int stream_content(request_rec *r, mp3_conf *cfg, mp3_data *content, request_data *request) { +static int stream_content(request_rec *r, mp3_conf *cfg, mp3_data *content, request_data *request) +{ + mp3_server_conf *scfg = ap_get_module_config(r->server->module_config, &mp3_module); FILE *file; int b = 0; int x = 0; @@ -91,6 +95,7 @@ ap_hard_timeout("mod_mp3_write", r); + connection_set_file(r, scfg, content->signature); if(content->data) { if(request->shout) { /* Bug in this at the moment */ @@ -483,6 +488,29 @@ return request; } +static int mp3_status_handler(request_rec *r) +{ + mp3_conf *cfg = ap_get_module_config(r->per_dir_config, &mp3_module); + mp3_server_conf *scfg = ap_get_module_config(r->server->module_config, &mp3_module); + int i; + + r->content_type = "text/plain"; + ap_send_http_header(r); + + ap_rprintf(r, "%s\t%s\t%s\t%s\n", "#", "status", "0.0.0.0", "on air now"); + for (i = 0; i < CHILDREN; i++) + { + if (scfg->board->servers[i].status) + { + ap_rprintf(r, "%d\t%d\t%s\t%s\n", + i, scfg->board->servers[i].status, scfg->board->servers[i].remote_ip, + scfg->board->servers[i].current_file); + } + } + + return OK; +} + static int mp3_fixup(request_rec *r) { mp3_conf *cfg = ap_get_module_config(r->per_dir_config, &mp3_module); mp3_server_conf *scfg = ap_get_module_config(r->server->module_config, &mp3_module); @@ -573,6 +601,8 @@ r->handler = "mp3-pls"; } else if(!mp3_match(request->op, "list")) { r->handler = "mp3-rss"; + } else if (!mp3_match(request->op, "status")) { + r->handler = "mp3-status"; } else if(!mp3_match(request->op, "play")) { if(!r->args) /* Basically, no args means this was default so lets go by the httpd.conf */ request->random = cfg->random_enabled; @@ -812,6 +842,7 @@ { "mp3", mp3_handler }, { "ogg", ogg_handler }, #endif + { "mp3-status", mp3_status_handler }, { "mp3-play", mp3_play_handler }, { "mp3-random", mp3_random_handler }, { "mp3-selection", mp3_selection_handler }, diff -ubNr mod_mp3-0.25.orig/mod_mp3.h mod_mp3-0.25/mod_mp3.h --- mod_mp3-0.25.orig/mod_mp3.h Tue Jul 17 05:50:51 2001 +++ mod_mp3-0.25/mod_mp3.h Sat Sep 15 17:47:26 2001 @@ -44,9 +44,16 @@ #define RSS10FOOTER "" +struct server_data +{ + int status; + char remote_ip[16]; + char current_file[33]; +}; + typedef struct { time_t time; /* Time of last regeneration */ - int servers[CHILDREN]; /* Servers we are tracking for live connections. Each one represents a childs_num */ + struct server_data servers[CHILDREN]; /* Servers we are tracking for live connections. Each one represents a childs_num */ } scoreboard; /* This is shared memory stuff for each instance */ typedef struct { @@ -78,6 +85,7 @@ int shmid; /* SHM id to the scoreboard */ time_t generation; /* Last time the files were reloaded */ scoreboard *board; /* Scoreboard for the server */ + ap_pool *pool; } mp3_server_conf; /* This the info that is stored on each section (directory, location, virtualhost...) */ typedef struct { diff -ubNr mod_mp3-0.25.orig/proto.h mod_mp3-0.25/proto.h --- mod_mp3-0.25.orig/proto.h Thu Jul 12 19:56:32 2001 +++ mod_mp3-0.25/proto.h Sat Sep 15 17:39:49 2001 @@ -24,6 +24,7 @@ int mp3_match(const char *s1, const char *s2); const char *add_default_op(cmd_parms * cmd, void *mconfig, char *param, char *type); int register_connection(request_rec *r, mp3_server_conf *scfg, int limit, int type); +void connection_set_file(request_rec *r, mp3_server_conf *scfg, char *file); const char * set_limit_connections(cmd_parms * cmd, void *mconfig, char *value); int get_id3_tag(pool *p, int fd, mp3_data *bank); void write_log(request_rec *r, mp3_conf *cfg, request_data *info, mp3_data *bank); diff -ubNr mod_mp3-0.25.orig/streamwriter.c mod_mp3-0.25/streamwriter.c --- mod_mp3-0.25.orig/streamwriter.c Tue May 8 09:59:45 2001 +++ mod_mp3-0.25/streamwriter.c Sat Sep 15 16:03:21 2001 @@ -30,7 +30,7 @@ } while((b = getchar()) != EOF) { for(x = 0; x < CHILDREN; x++) { - if(board->servers[x]){ + if(board->servers[x].status){ memset(buffer, 0 , HUGE_STRING_LEN); sprintf(buffer, "/tmp/mod_mp3.%d", x); if(!(file = fopen(buffer,"a"))) { diff -ubNr mod_mp3-0.25.orig/utility.c mod_mp3-0.25/utility.c --- mod_mp3-0.25.orig/utility.c Tue Jul 17 06:12:24 2001 +++ mod_mp3-0.25/utility.c Sat Sep 15 17:47:09 2001 @@ -3,6 +3,7 @@ */ #include "mod_mp3.h" +#include MP3_EXPORT(int)mp3_match(const char *s1, const char *s2) { if(!s1) @@ -96,20 +97,21 @@ request_rec *r = (request_rec *)rp; mp3_server_conf *scfg = ap_get_module_config(r->server->module_config, &mp3_module); - scfg->board->servers[r->connection->child_num] = 0; + memset(&scfg->board->servers[r->connection->child_num], 0, sizeof(struct server_data)); printf("Cleaning up %d(%d)\n", r->connection->child_num, scfg->board->servers[r->connection->child_num]); } -MP3_EXPORT(int) register_connection(request_rec *r, mp3_server_conf *scfg, int limit, int type) { +MP3_EXPORT(int) register_connection(request_rec *r, mp3_server_conf *scfg, int limit, int type) +{ + char *remote_host; int active = 0; int x = 0; - WATCHPOINT - printf("Connection limit %d\n", limit); + printf("Connection limit %d; Child: %d\n", limit, r->connection->child_num); if(limit) { for(x = 0; x < CHILDREN; x++) { - if(scfg->board->servers[x]) { - printf("Server %d(%d) is active \n", x, scfg->board->servers[x]); + if(scfg->board->servers[x].status) { + printf("Server %d(%d) is active \n", x, scfg->board->servers[x].status); active++; } } @@ -118,11 +120,18 @@ } } - scfg->board->servers[r->connection->child_num] = type; + remote_host = ap_get_remote_host(r->connection, r->per_dir_config, REMOTE_NOLOOKUP); + snprintf(scfg->board->servers[r->connection->child_num].remote_ip, 16, "%s", remote_host); + scfg->board->servers[r->connection->child_num].status = type; ap_register_cleanup(r->pool, r, cleanup_connection, ap_null_cleanup); WATCHPOINT return 0; +} + +MP3_EXPORT(void) connection_set_file(request_rec *r, mp3_server_conf *scfg, char *file) +{ + snprintf(scfg->board->servers[r->connection->child_num].current_file, 33, "%s", file); } MP3_EXPORT(array_header *) get_songs(pool *p, table * t) {