[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