[xiph-cvs] cvs commit: icecast/src admin.c admin.h Makefile.am connection.c connection.h source.c util.c util.h
Michael Smith
msmith at xiph.org
Thu Mar 6 06:17:33 PST 2003
msmith 03/03/06 09:17:33
Modified: src Makefile.am connection.c connection.h source.c
util.c util.h
Added: src admin.c admin.h
Log:
Split admin stuff out into a seperate file, add various utility functions there.
rename util_url_escape to util_url_unescape, and write a util_escape function
that actually DOES escape things. Fix all the callers of the function to call
the correct one of these two.
Revision Changes Path
1.14 +1 -1 icecast/src/Makefile.am
Index: Makefile.am
===================================================================
RCS file: /usr/local/cvsroot/icecast/src/Makefile.am,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -r1.13 -r1.14
--- Makefile.am 5 Mar 2003 13:03:35 -0000 1.13
+++ Makefile.am 6 Mar 2003 14:17:33 -0000 1.14
@@ -11,7 +11,7 @@
compat.h format_mp3.h fserve.h xslt.h geturl.h yp.h event.h
icecast_SOURCES = config.c main.c logging.c sighandler.c connection.c global.c\
util.c slave.c source.c stats.c refbuf.c client.c format.c format_vorbis.c\
- format_mp3.c xslt.c fserve.c geturl.c yp.c event.c
+ format_mp3.c xslt.c fserve.c geturl.c yp.c event.c admin.c
icecast_LDADD = net/libicenet.la thread/libicethread.la httpp/libicehttpp.la\
log/libicelog.la avl/libiceavl.la timing/libicetiming.la
<p><p>1.58 +10 -128 icecast/src/connection.c
Index: connection.c
===================================================================
RCS file: /usr/local/cvsroot/icecast/src/connection.c,v
retrieving revision 1.57
retrieving revision 1.58
diff -u -r1.57 -r1.58
--- connection.c 5 Mar 2003 13:03:35 -0000 1.57
+++ connection.c 6 Mar 2003 14:17:33 -0000 1.58
@@ -41,6 +41,7 @@
#include "format.h"
#include "format_mp3.h"
#include "event.h"
+#include "admin.h"
#define CATMODULE "connection"
@@ -437,7 +438,7 @@
return 1;
}
-static int _check_relay_pass(http_parser_t *parser)
+int connection_check_relay_pass(http_parser_t *parser)
{
ice_config_t *config = config_get_config();
char *pass = config->relay_password;
@@ -448,7 +449,7 @@
return _check_pass_http(parser, "relay", pass);
}
-static int _check_admin_pass(http_parser_t *parser)
+int connection_check_admin_pass(http_parser_t *parser)
{
ice_config_t *config = config_get_config();
char *pass = config->admin_password;
@@ -461,7 +462,7 @@
return _check_pass_http(parser, "admin", pass);
}
-static int _check_source_pass(http_parser_t *parser, char *mount)
+int connection_check_source_pass(http_parser_t *parser, char *mount)
{
ice_config_t *config = config_get_config();
char *pass = config->source_password;
@@ -502,108 +503,6 @@
return ret;
}
-static void handle_fallback_request(client_t *client)
-{
- source_t *source;
- char *mount, *value, *old;
- int bytes;
-
- mount = httpp_get_query_param(client->parser, "mount");
- value = httpp_get_query_param(client->parser, "fallback");
-
- if(!_check_source_pass(client->parser, mount)) {
- INFO0("Bad or missing password on fallback configuration request");
- client_send_401(client);
- return;
- }
-
- if(value == NULL || mount == NULL) {
- client_send_400(client, "Missing parameter");
- return;
- }
-
- avl_tree_rlock(global.source_tree);
- source = source_find_mount(mount);
- avl_tree_unlock(global.source_tree);
-
- if(source == NULL) {
- client_send_400(client, "Current source not found");
- return;
- }
-
- old = source->fallback_mount;
- source->fallback_mount = strdup(value);
- free(old);
-
- client->respcode = 200;
- bytes = sock_write(client->con->sock,
- "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n"
- "Fallback configured");
- if(bytes > 0) client->con->sent_bytes = bytes;
- client_destroy(client);
-}
-
-static void handle_metadata_request(client_t *client)
-{
- source_t *source;
- char *action;
- char *mount;
- char *value;
- mp3_state *state;
- int bytes;
-
- action = httpp_get_query_param(client->parser, "mode");
- mount = httpp_get_query_param(client->parser, "mount");
- value = httpp_get_query_param(client->parser, "song");
-
- if(!_check_source_pass(client->parser, mount)) {
- INFO0("Metadata request with wrong or missing password");
- client_send_401(client);
- return;
- }
-
- if(value == NULL || action == NULL || mount == NULL) {
- client_send_400(client, "Missing parameter");
- return;
- }
-
- avl_tree_rlock(global.source_tree);
- source = source_find_mount(mount);
- avl_tree_unlock(global.source_tree);
-
- if(source == NULL) {
- client_send_400(client, "No such mountpoint");
- return;
- }
-
- if(source->format->type != FORMAT_TYPE_MP3) {
- client_send_400(client, "Not mp3, cannot update metadata");
- return;
- }
-
- if(strcmp(action, "updinfo") != 0) {
- client_send_400(client, "No such action");
- return;
- }
-
- state = source->format->_state;
- thread_mutex_lock(&(state->lock));
- free(state->metadata);
- state->metadata = strdup(value);
- state->metadata_age++;
- state->metadata_raw = 0;
- thread_mutex_unlock(&(state->lock));
-
- DEBUG2("Metadata on mountpoint %s changed to \"%s\"", mount, value);
- stats_event(mount, "title", value);
- client->respcode = 200;
- bytes = sock_write(client->con->sock,
- "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n"
- "Update successful");
- if(bytes > 0) client->con->sent_bytes = bytes;
- client_destroy(client);
-}
-
static void _handle_source_request(connection_t *con,
http_parser_t *parser, char *uri)
{
@@ -614,7 +513,7 @@
INFO1("Source logging in at mountpoint \"%s\"", uri);
stats_event_inc(NULL, "source_connections");
- if (!_check_source_pass(parser, uri)) {
+ if (!connection_check_source_pass(parser, uri)) {
INFO1("Source (%s) attempted to login with invalid or missing password", uri);
client_send_401(client);
return;
@@ -645,7 +544,7 @@
stats_event_inc(NULL, "stats_connections");
- if (!_check_admin_pass(parser)) {
+ if (!connection_check_admin_pass(parser)) {
ERROR0("Bad password for stats connection");
connection_close(con);
httpp_destroy(parser);
@@ -699,27 +598,10 @@
** aren't subject to the limits.
*/
/* TODO: add GUID-xxxxxx */
- if (strcmp(uri, "/admin/stats.xml") == 0) {
- if (!_check_admin_pass(parser)) {
- INFO0("Request for /admin/stats.xml with incorrect or no password");
- client_send_401(client);
- return;
- }
- DEBUG0("Stats request, sending xml stats");
- stats_sendxml(client);
- client_destroy(client);
- return;
- }
-
- if(strcmp(uri, "/admin/metadata") == 0) {
- DEBUG0("Got metadata update request");
- handle_metadata_request(client);
- return;
- }
- if(strcmp(uri, "/admin/fallbacks") == 0) {
- DEBUG0("Got fallback request");
- handle_fallback_request(client);
+ /* Dispatch all admin requests */
+ if (strncmp(uri, "/admin/", 7) == 0) {
+ admin_handle_request(client, uri);
return;
}
@@ -801,7 +683,7 @@
}
if (strcmp(uri, "/admin/streamlist") == 0) {
- if (!_check_relay_pass(parser)) {
+ if (!connection_check_relay_pass(parser)) {
INFO0("Client attempted to fetch /admin/streamlist with bad password");
client_send_401(client);
} else {
<p><p>1.8 +4 -0 icecast/src/connection.h
Index: connection.h
===================================================================
RCS file: /usr/local/cvsroot/icecast/src/connection.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- connection.h 5 Mar 2003 13:03:35 -0000 1.7
+++ connection.h 6 Mar 2003 14:17:33 -0000 1.8
@@ -37,6 +37,10 @@
void connection_inject_event(int eventnum, void *event_data);
+int connection_check_source_pass(http_parser_t *parser, char *mount);
+int connection_check_relay_pass(http_parser_t *parser);
+int connection_check_admin_pass(http_parser_t *parser);
+
extern rwlock_t _source_shutdown_rwlock;
#endif /* __CONNECTION_H__ */
<p><p>1.42 +2 -5 icecast/src/source.c
Index: source.c
===================================================================
RCS file: /usr/local/cvsroot/icecast/src/source.c,v
retrieving revision 1.41
retrieving revision 1.42
diff -u -r1.41 -r1.42
--- source.c 5 Mar 2003 13:03:35 -0000 1.41
+++ source.c 6 Mar 2003 14:17:33 -0000 1.42
@@ -674,13 +674,10 @@
pvar = strchr(token, '=');
if (pvar) {
variable = (char *)malloc(pvar-token+1);
- memset(variable, '\000', pvar-token+1);
strncpy(variable, token, pvar-token);
pvar++;
if (strlen(pvar)) {
- value = (char *)malloc(strlen(pvar)+1);
- memset(value, '\000', strlen(pvar)+1);
- strncpy(value, pvar, strlen(pvar));
+ value = util_url_unescape(pvar);
util_dict_set(source->audio_info, variable, value);
stats_event(source->mount, variable, value);
if (value) {
@@ -688,7 +685,7 @@
}
}
if (variable) {
- free(variable);
+ free(variable);
}
}
s = NULL;
<p><p>1.20 +49 -2 icecast/src/util.c
Index: util.c
===================================================================
RCS file: /usr/local/cvsroot/icecast/src/util.c,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -r1.19 -r1.20
--- util.c 5 Mar 2003 13:03:35 -0000 1.19
+++ util.c 6 Mar 2003 14:17:33 -0000 1.20
@@ -216,9 +216,56 @@
return fullpath;
}
+static char hexchars[16] = {
+ '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
+};
+
+static char safechars[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
char *util_url_escape(char *src)
{
int len = strlen(src);
+ /* Efficiency not a big concern here, keep the code simple/conservative */
+ char *dst = calloc(1, len*3 + 1);
+ unsigned char *source = src;
+ int i,j=0;
+
+ for(i=0; i < len; i++) {
+ if(safechars[source[i]]) {
+ dst[j++] = source[i];
+ }
+ else {
+ dst[j] = '%';
+ dst[j+1] = hexchars[ source[i] & 0x15 ];
+ dst[j+2] = hexchars[ (source[i] >> 4) & 0x15 ];
+ j+= 3;
+ }
+ }
+
+ dst[j] = 0;
+ return dst;
+}
+
+char *util_url_unescape(char *src)
+{
+ int len = strlen(src);
unsigned char *decoded;
int i;
char *dst;
@@ -247,7 +294,7 @@
done = 1;
break;
case 0:
- ERROR0("Fatal internal logic error in util_url_escape()");
+ ERROR0("Fatal internal logic error in util_url_unescape()");
free(decoded);
return NULL;
break;
@@ -275,7 +322,7 @@
if(uri[0] != '/')
return NULL;
- path = util_url_escape(uri);
+ path = util_url_unescape(uri);
if(path == NULL) {
WARN1("Error decoding URI: %s\n", uri);
<p><p>1.11 +1 -0 icecast/src/util.h
Index: util.h
===================================================================
RCS file: /usr/local/cvsroot/icecast/src/util.h,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- util.h 26 Feb 2003 23:52:23 -0000 1.10
+++ util.h 6 Mar 2003 14:17:33 -0000 1.11
@@ -14,6 +14,7 @@
char *util_base64_encode(char *data);
char *util_base64_decode(unsigned char *input);
+char *util_url_unescape(char *src);
char *util_url_escape(char *src);
/* String dictionary type, without support for NULL keys, or multiple
<p><p>1.1 icecast/src/admin.c
Index: admin.c
===================================================================
#include <string.h>
#include <stdlib.h>
#include "config.h"
#include "connection.h"
#include "refbuf.h"
#include "client.h"
#include "source.h"
#include "global.h"
#include "event.h"
#include "stats.h"
#include "format.h"
#include "format_mp3.h"
#include "logging.h"
#define CATMODULE "admin"
#define COMMAND_ERROR (-1)
#define COMMAND_FALLBACK 1
#define COMMAND_RAW_STATS 2
#define COMMAND_METADATA_UPDATE 3
int admin_get_command(char *command)
{
if(!strcmp(command, "fallbacks"))
return COMMAND_FALLBACK;
else if(!strcmp(command, "rawstats"))
return COMMAND_RAW_STATS;
else if(!strcmp(command, "stats.xml")) /* The old way */
return COMMAND_RAW_STATS;
else if(!strcmp(command, "metadata"))
return COMMAND_METADATA_UPDATE;
else
return COMMAND_ERROR;
}
tatic void command_fallback(client_t *client, source_t *source);
static void command_metadata(client_t *client, source_t *source);
tatic void command_raw_stats(client_t *client);
tatic void admin_handle_mount_request(client_t *client, source_t *source,
int command);
static void admin_handle_general_request(client_t *client, int command);
void admin_handle_request(client_t *client, char *uri)
{
char *mount, *command_string;
int command;
if(strncmp("/admin/", uri, 7)) {
ERROR0("Internal error: admin request isn't");
client_send_401(client);
return;
}
command_string = uri + 7;
command = admin_get_command(command_string);
if(command < 0) {
ERROR1("Error parsing command string or unrecognised command: %s",
command_string);
client_send_400(client, "Unrecognised command");
return;
}
mount = httpp_get_query_param(client->parser, "mount");
if(mount != NULL) {
source_t *source;
/* This is a mount request, handle it as such */
if(!connection_check_source_pass(client->parser, mount)) {
INFO1("Bad or missing password on mount modification admin "
"request (command: %s)", command_string);
client_send_401(client);
return;
}
avl_tree_rlock(global.source_tree);
source = source_find_mount(mount);
avl_tree_unlock(global.source_tree);
if(source == NULL) {
WARN2("Admin command %s on non-existent source %s",
command_string, mount);
client_send_400(client, "Source does not exist");
return;
}
INFO2("Received admin command %s on mount \"%s\"",
command_string, mount);
admin_handle_mount_request(client, source, command);
}
else {
if(!connection_check_admin_pass(client->parser)) {
INFO1("Bad or missing password on admin command "
"request (command: %s)", command_string);
client_send_401(client);
return;
}
admin_handle_general_request(client, command);
}
}
tatic void admin_handle_general_request(client_t *client, int command)
{
switch(command) {
case COMMAND_RAW_STATS:
command_raw_stats(client);
break;
default:
WARN0("General admin request not recognised");
client_send_400(client, "Unknown admin request");
return;
}
}
tatic void admin_handle_mount_request(client_t *client, source_t *source,
int command)
{
switch(command) {
case COMMAND_FALLBACK:
command_fallback(client, source);
break;
case COMMAND_METADATA_UPDATE:
command_metadata(client, source);
break;
default:
WARN0("Mount request not recognised");
client_send_400(client, "Mount request unknown");
return;
}
}
#define COMMAND_REQUIRE(client,name,var) \
do { \
(var) = httpp_get_query_param((client)->parser, (name)); \
if((var) == NULL) { \
client_send_400((client), "Missing parameter"); \
return; \
} \
} while(0);
tatic void command_success(client_t *client, char *message)
{
int bytes;
client->respcode = 200;
bytes = sock_write(client->con->sock,
"HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n"
"<html><head><title>Admin request successful</title></head>"
"<body><p>%s</p></body></html>", message);
if(bytes > 0) client->con->sent_bytes = bytes;
client_destroy(client);
}
tatic void command_fallback(client_t *client, source_t *source)
{
char *fallback;
char *old;
DEBUG0("Got fallback request");
COMMAND_REQUIRE(client, "fallback", fallback);
old = source->fallback_mount;
source->fallback_mount = strdup(fallback);
free(old);
command_success(client, "Fallback configured");
}
tatic void command_metadata(client_t *client, source_t *source)
{
char *action;
char *value;
mp3_state *state;
DEBUG0("Got metadata update request");
COMMAND_REQUIRE(client, "mode", action);
COMMAND_REQUIRE(client, "song", value);
if(source->format->type != FORMAT_TYPE_MP3) {
client_send_400(client, "Not mp3, cannot update metadata");
return;
}
if(strcmp(action, "updinfo") != 0) {
client_send_400(client, "No such action");
return;
}
state = source->format->_state;
thread_mutex_lock(&(state->lock));
free(state->metadata);
state->metadata = strdup(value);
state->metadata_age++;
state->metadata_raw = 0;
thread_mutex_unlock(&(state->lock));
DEBUG2("Metadata on mountpoint %s changed to \"%s\"", source->mount, value);
stats_event(source->mount, "title", value);
command_success(client, "Metadata update successful");
}
tatic void command_raw_stats(client_t *client) {
DEBUG0("Stats request, sending xml stats");
stats_sendxml(client);
client_destroy(client);
return;
}
<p><p><p>1.1 icecast/src/admin.h
Index: admin.h
===================================================================
#ifndef __ADMIN_H__
#define __ADMIN_H__
#include "refbuf.h"
#include "client.h"
void admin_handle_request(client_t *client, char *uri);
#endif /* __ADMIN_H__ */
<p><p>--- >8 ----
List archives: http://www.xiph.org/archives/
Ogg project homepage: http://www.xiph.org/ogg/
To unsubscribe from this list, send a message to 'cvs-request at xiph.org'
containing only the word 'unsubscribe' in the body. No subject is needed.
Unsubscribe messages sent to the list will be ignored/filtered.
More information about the commits
mailing list