[PATCH 22/31] Fix Shoutcast, Move it to a one-pass process

Niv Sardi <[email protected]>
Newsgroups gmane.comp.audio.icecast.devel
Message-ID <[email protected]>
(our function is re-entrant so timeouts are almost automatically handled)

test if we have a shoutcast connection.
stage1, read password, validate it, and prepare in-refbuf with POST (no auth)
get into the normal POST-like loop

Signed-off-by: Niv Sardi <[email protected]>
---
 src/connection.c |  180 ++++++++++++++++++++++++------------------------------
 1 files changed, 79 insertions(+), 101 deletions(-)

diff --git a/src/connection.c b/src/connection.c
index c66a240..9269ad6 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -116,8 +116,8 @@ cache_file_contents banned_ip, allowed_ip;
 
 rwlock_t _source_shutdown_rwlock;
 
-static void _handle_shoutcast_compatible (int shoutcast, char *shoutcast_mount);
 static int _handle_client (client_t *client);
+static int _handle_shoutcast_stage1 (connection_queue_t *node, char *shoutcast_mount, mount_proxy *mountinfo);
 static int _connection_process (connection_queue_t *node);
 static void *_connection_thread (void *arg);
 
@@ -711,19 +711,52 @@ out_fail:
     return err;
 }
 
+/* we don't need to clean up on err, as we'll go through the node struct and clean all we have inside */
 static int _connection_process (connection_queue_t *node) {
-    ice_config_t *config;
-    listener_t *listener;
     refbuf_t *header;
     http_parser_t *parser = NULL;
     int hdrsize = 0;
     int shoutcast = 0;
     int err;
     char *shoutcast_mount = NULL;
+    mount_proxy *mountinfo;
+
+    ice_config_t *config;
+    listener_t *listener;
 
     if (!node->refbuf)
 	    node->refbuf = refbuf_new (PER_CLIENT_REFBUF_SIZE);
     header = node->refbuf;
+
+    { /* this code tests for shoutcastness */
+        config = config_get_config();
+        listener = config_get_listen_sock (config, node->con);
+
+        if (listener) {
+            WARN("listner");
+            if (listener->shoutcast_compat)
+                shoutcast = 1;
+            if (listener->ssl && ssl_ok)
+                connection_uses_ssl (node->con);
+            if (listener->shoutcast_mount) {
+                shoutcast_mount = strdup (listener->shoutcast_mount);
+            } else {
+                shoutcast_mount = config->shoutcast_mount;
+            }
+        }
+
+        WARN("shoutcast %d, mount %s", shoutcast, shoutcast_mount);
+
+        mountinfo = config_find_mount (config, shoutcast_mount);
+        config_release_config();
+    }
+
+    if (shoutcast && !header->sync_point) { /* stage2 is actually handled by generic code */
+        err = _handle_shoutcast_stage1 (node, shoutcast_mount, mountinfo);
+        if (err < 0)
+            return err;
+    }
+
     hdrsize = util_read_header (node->con, header, HEADER_READ_ENTIRE);
     if (hdrsize < 0)
     {
@@ -763,42 +796,19 @@ static int _connection_process (connection_queue_t *node) {
         err = connection_client_setup (node);
         if (err < 0)
             return err;
-    }
-
-    header->len -= hdrsize;
-    if (header->len) {
-        memmove(header->data, header->data + hdrsize, header->len);
-        client_set_queue (node->client, header);
-    }
-    refbuf_release(header);
-
-    config = config_get_config();
-    listener = config_get_listen_sock (config, node->con);
 
-    if (listener)
-    {
-        if (listener->shoutcast_compat)
-            shoutcast = 1;
-        if (listener->ssl && ssl_ok)
-            connection_uses_ssl (node->con);
-        if (listener->shoutcast_mount)
-            shoutcast_mount = strdup (listener->shoutcast_mount);
-    }
-    config_release_config();
-
-/* XXX(xaiki): this should be 1, but actually, it's buggy, the client is already up and all.. */
-    if (node->con->con_timeout <= time(NULL)) {
-        WARN("there might be a bug if you see this");
-        client_destroy (node->client);
-        return -1;
+        header->len -= hdrsize;
+        if (header->len) {
+            memmove(header->data, header->data + hdrsize, header->len);
+            client_set_queue (node->client, header);
+        }
+        refbuf_release(header);
     }
 
     stats_event_inc (NULL, "connections");
 
-    if (shoutcast) {
-        _handle_shoutcast_compatible (shoutcast, shoutcast_mount);
-        return 0;
-    }
+    WARN("shoutcast = %d", shoutcast);
+
     return _handle_client (node->client);
 }
 
@@ -1218,81 +1228,49 @@ static void _handle_get_request (client_t *client, char *passed_uri)
     if (uri != passed_uri) free (uri);
 }
 
-static void _handle_shoutcast_compatible (int shoutcast, char *shoutcast_mount)
+static int _handle_shoutcast_stage1 (connection_queue_t *node, char *shoutcast_mount, mount_proxy *mountinfo)
 {
-/*
-  SHOUTCAST IS BROKEN
-*/
-    char *http_compliant;
-    int http_compliant_len = 0;
-    http_parser_t *parser;
-    ice_config_t *config = config_get_config ();
-    client_t *client = NULL; //node->client;
-    refbuf_t *refbuf = client->refbuf;
+    refbuf_t *refbuf = node->refbuf;
+    char *source_password;
+    int err, passlen;
 
-    if (!shoutcast_mount)
-        shoutcast_mount = config->shoutcast_mount;
-
-    if (shoutcast == 1)
-    {
-        char *source_password;
-        mount_proxy *mountinfo = config_find_mount (config, shoutcast_mount);
-        int hdrlen;
+    WARN ("IN");
 
-        if (mountinfo && mountinfo->password)
-            source_password = strdup (mountinfo->password);
-        else
-            source_password = strdup (config->source_password);
+    if (mountinfo && mountinfo->password) {
+        source_password = strdup (mountinfo->password);
+    } else {
+        ice_config_t *config = config_get_config ();
+        source_password = strdup (config->source_password);
         config_release_config();
+    }
 
-        if ((hdrlen = util_find_eos_delim (client->refbuf, 0, HEADER_READ_LINE)) < 0) {
-            client_destroy (client);
-            free (source_password);
-            return;
-        }
+    passlen = util_read_header (node->con, refbuf, HEADER_READ_LINE);
+    if (passlen <= 0) {
+        WARN ("HEADER READ FAILED");
+        err = passlen;
+        goto out_FAIL;
+    }
 
-        if (memmem (refbuf->data, hdrlen, source_password, strlen(source_password)) != NULL) {
-            client->respcode = 200;
-            /* send this non-blocking but if there is only a partial write
-             * then leave to header timeout */
-            sock_write (client->con->sock, "OK2\r\nicy-caps:11\r\n\r\n");
-            shoutcast = 2;
-            /* we've checked the password, now send it back for reading headers */
-//            _add_request_queue (node);
-            free (source_password);
-            return;
-        }
+    if (memmem (refbuf->data, passlen, source_password, strlen(source_password)) == NULL) {
+        INFO ("password does not match (%ld) \"%s\" (%d) \"%s\"",
+              strlen(source_password), source_password, passlen, refbuf->data);
+        err = -ENOENT;
+        goto out_FAIL;
+    }
 
-        INFO1 ("password does not match \"%s\"", refbuf->data);
+/* send this non-blocking but if there is only a partial write
+ * then leave to header timeout */
+    sock_write (node->con->sock, "OK2\r\nicy-caps:11\r\n\r\n");
 
-        client_destroy (client);
-        free (source_password);
-        return;
-    }
-    /* actually make a copy as we are dropping the config lock */
-    shoutcast_mount = strdup (shoutcast_mount);
-    config_release_config();
-    /* Here we create a valid HTTP request based of the information
-       that was passed in via the non-HTTP style protocol above. This
-       means we can use some of our existing code to handle this case */
-//    http_compliant_len = 20 + strlen (shoutcast_mount) + node->offset;
-    http_compliant = (char *)calloc(1, http_compliant_len);
-    snprintf (http_compliant, http_compliant_len,
-            "SOURCE %s HTTP/1.0\r\n%s", shoutcast_mount, refbuf->data);
-    parser = httpp_create_parser();
-    httpp_initialize(parser, NULL);
-    if (httpp_parse (parser, http_compliant, strlen(http_compliant)))
-    {
-        client->parser = parser;
-        source_startup (client, shoutcast_mount, SHOUTCAST_SOURCE_AUTH);
-    }
-    else {
-        httpp_destroy (parser);
-        client_destroy (client);
-    }
-    free (http_compliant);
-    free (shoutcast_mount);
-    return;
+    refbuf->sync_point = snprintf (refbuf->data, refbuf->len, "POST %s HTTP/1.0\r\n", shoutcast_mount);
+
+    /* we've checked the password, now send it back for reading headers */
+    free (source_password);
+    return 0;
+
+out_FAIL:
+    free (source_password);
+    return err;
 }
 
 static int _handle_client (client_t *client)
-- 
1.7.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.