[xiph-commits] r9399 - icecast/trunk/icecast/src

karl at motherfish-iii.xiph.org karl at motherfish-iii.xiph.org
Tue Jun 7 18:37:03 PDT 2005


Author: karl
Date: 2005-06-07 18:36:51 -0700 (Tue, 07 Jun 2005)
New Revision: 9399

Modified:
   icecast/trunk/icecast/src/client.c
   icecast/trunk/icecast/src/client.h
   icecast/trunk/icecast/src/connection.c
   icecast/trunk/icecast/src/format.c
   icecast/trunk/icecast/src/format.h
   icecast/trunk/icecast/src/format_mp3.c
   icecast/trunk/icecast/src/format_ogg.c
   icecast/trunk/icecast/src/source.c
Log:
Do normal http header writing in source thread instead of the connection
thread, this will allow on-demand relays to fail and still handle the initial
listener correctly (fallback or 404 response).


Modified: icecast/trunk/icecast/src/client.c
===================================================================
--- icecast/trunk/icecast/src/client.c	2005-06-08 00:46:03 UTC (rev 9398)
+++ icecast/trunk/icecast/src/client.c	2005-06-08 01:36:51 UTC (rev 9399)
@@ -63,7 +63,7 @@
     client->parser = parser;
     client->refbuf = NULL;
     client->pos = 0;
-    client->check_buffer = format_advance_queue;
+    client->write_to_client = format_generic_write_to_client;
 
     return client;
 }

Modified: icecast/trunk/icecast/src/client.h
===================================================================
--- icecast/trunk/icecast/src/client.h	2005-06-08 00:46:03 UTC (rev 9398)
+++ icecast/trunk/icecast/src/client.h	2005-06-08 01:36:51 UTC (rev 9399)
@@ -50,6 +50,9 @@
     /* function to call to release format specific resources */
     void (*free_client_data)(struct _client_tag *client);
 
+    /* write out data associated with client */
+    int (*write_to_client)(struct _client_tag *client);
+
     /* function to check if refbuf needs updating */
     int (*check_buffer)(struct source_tag *source, struct _client_tag *client);
 

Modified: icecast/trunk/icecast/src/connection.c
===================================================================
--- icecast/trunk/icecast/src/connection.c	2005-06-08 00:46:03 UTC (rev 9398)
+++ icecast/trunk/icecast/src/connection.c	2005-06-08 01:36:51 UTC (rev 9399)
@@ -943,18 +943,13 @@
         }
         global_unlock();
                         
-        source->format->create_client_data (source, client);
-
-        source->format->client_send_headers(source->format, source, client);
-                        
-        bytes = sock_write(client->con->sock, "\r\n");
-        if(bytes > 0) client->con->sent_bytes += bytes;
-                            
         sock_set_blocking(client->con->sock, SOCK_NONBLOCK);
         sock_set_nodelay(client->con->sock);
 
-        client->check_buffer = format_check_file_buffer;
-                        
+        client->write_to_client = format_generic_write_to_client;
+        client->check_buffer = format_check_http_buffer;
+        client->refbuf = refbuf_new (4096);
+
         avl_tree_wlock(source->pending_tree);
         avl_insert(source->pending_tree, (void *)client);
         avl_tree_unlock(source->pending_tree);

Modified: icecast/trunk/icecast/src/format.c
===================================================================
--- icecast/trunk/icecast/src/format.c	2005-06-08 00:46:03 UTC (rev 9398)
+++ icecast/trunk/icecast/src/format.c	2005-06-08 01:36:51 UTC (rev 9399)
@@ -46,8 +46,12 @@
 #ifdef WIN32
 #define strcasecmp stricmp
 #define strncasecmp strnicmp
+#define snprintf _snprintf
 #endif
 
+static int format_prepare_headers (source_t *source, client_t *client);
+
+
 format_type_t format_get_type(char *contenttype)
 {
     if(strcmp(contenttype, "application/x-ogg") == 0)
@@ -144,17 +148,9 @@
 
     if (refbuf == NULL)
     {
-        if (source->intro_file && client->intro_offset == 0)
-        {
-            refbuf = refbuf_new (4096);
-            client->refbuf = refbuf;
-            client->pos = refbuf->len;
-        }
-        else
-        {
-            find_client_start (source, client);
-            return -1;
-        }
+        /* client refers to no data, must be from a move */
+        find_client_start (source, client);
+        return -1;
     }
     if (client->pos == refbuf->len)
     {
@@ -168,7 +164,6 @@
             if (source->stream_data_tail)
             {
                 /* better find the right place in queue for this client */
-                client->intro_offset = -1;
                 client_set_queue (client, NULL);
                 find_client_start (source, client);
             }
@@ -181,6 +176,57 @@
 }
 
 
+/* call this to verify that the HTTP data has been sent and if so setup
+ * callbacks to the appropriate format functions
+ */
+int format_check_http_buffer (source_t *source, client_t *client)
+{
+    refbuf_t *refbuf = client->refbuf;
+
+    if (refbuf == NULL)
+        return -1;
+
+    if (client->respcode == 0)
+    {
+        DEBUG0("processing pending client headers");
+
+        client->respcode = 200;
+        if (format_prepare_headers (source, client) < 0)
+        {
+            ERROR0 ("internal problem, dropping client");
+            client->con->error = 1;
+            return -1;
+        }
+    }
+
+    if (client->pos == refbuf->len)
+    {
+        client->write_to_client = source->format->write_buf_to_client;
+        client->check_buffer = format_check_file_buffer;
+        client->intro_offset = 0;
+        client->pos = refbuf->len = 4096;
+        return -1;
+    }
+    return 0;
+}
+
+
+int format_generic_write_to_client (client_t *client)
+{
+    refbuf_t *refbuf = client->refbuf;
+    int ret;
+    const char *buf = refbuf->data + client->pos;
+    unsigned int len = refbuf->len - client->pos;
+
+    ret = client_send_bytes (client, buf, len);
+
+    if (ret > 0)
+        client->pos += ret;
+
+    return ret;
+}
+
+
 /* This is the commonly used for source streams, here we just progress to
  * the next buffer in the queue if there is no more left to be written from 
  * the existing buffer.
@@ -205,64 +251,95 @@
 }
 
 
-void format_send_general_headers(format_plugin_t *format,
-        source_t *source, client_t *client)
+static int format_prepare_headers (source_t *source, client_t *client)
 {
-    http_var_t *var;
+    unsigned remaining;
+    char *ptr;
+    int bytes;
+    int bitrate_filtered = 0;
     avl_node *node;
-    int bytes;
 
+    remaining = client->refbuf->len;
+    ptr = client->refbuf->data;
+    client->respcode = 200;
+
+    bytes = snprintf (ptr, remaining, "HTTP/1.0 200 OK\r\n"
+            "Content-Type: %s\r\n", source->format->contenttype);
+
+    remaining -= bytes;
+    ptr += bytes;
+
     /* iterate through source http headers and send to client */
     avl_tree_rlock(source->parser->vars);
     node = avl_get_first(source->parser->vars);
     while (node)
     {
-        var = (http_var_t *)node->key;
-        if (!strcasecmp(var->name, "ice-audio-info")) {
+        int next = 1;
+        http_var_t *var = (http_var_t *)node->key;
+        bytes = 0;
+        if (!strcasecmp(var->name, "ice-audio-info"))
+        {
             /* convert ice-audio-info to icy-br */
-            char *brfield;
+            char *brfield = NULL;
             unsigned int bitrate;
 
-            brfield = strstr(var->value, "bitrate=");
-            if (brfield && sscanf(var->value, "bitrate=%u", &bitrate)) {
-                bytes = sock_write(client->con->sock, "icy-br:%u\r\n", bitrate);
-                if (bytes > 0)
-                    client->con->sent_bytes += bytes;
+            if (bitrate_filtered == 0)
+                brfield = strstr(var->value, "bitrate=");
+            if (brfield && sscanf (brfield, "bitrate=%u", &bitrate))
+            {           
+                bytes = snprintf (ptr, remaining, "icy-br:%u\r\n", bitrate);
+                next = 0;
+                bitrate_filtered = 1;
             }
+            else
+                /* show ice-audio_info header as well because of relays */
+                bytes = snprintf (ptr, remaining, "%s: %s\r\n", var->name, var->value);
         }
         else
         {
             if (strcasecmp(var->name, "ice-password") &&
                 strcasecmp(var->name, "icy-metaint"))
             {
-                bytes = 0;
                 if (!strncasecmp("ice-", var->name, 4))
                 {
-                    if (!strcasecmp("ice-bitrate", var->name))
-                        bytes += sock_write(client->con->sock, "icy-br:%s\r\n", var->value);
+                    if (!strcasecmp("ice-public", var->name))
+                        bytes = snprintf (ptr, remaining, "icy-pub:%s\r\n", var->value);
                     else
-                        if (!strcasecmp("ice-public", var->name))
-                            bytes += sock_write(client->con->sock, 
-                                "icy-pub:%s\r\n", var->value);
+                        if (!strcasecmp ("ice-bitrate", var->name))
+                            bytes = snprintf (ptr, remaining, "icy-br:%s\r\n", var->value);
                         else
-                            bytes = sock_write(client->con->sock, "icy%s:%s\r\n",
+                            bytes = snprintf (ptr, remaining, "icy%s:%s\r\n",
+                                    var->name + 3, var->value);
+                }
+                else
+                    if (!strncasecmp("icy-", var->name, 4))
+                    {
+                        bytes = snprintf (ptr, remaining, "icy%s:%s\r\n",
                                 var->name + 3, var->value);
-                            
-                }
-                if (!strncasecmp("icy-", var->name, 4))
-                {
-                    bytes = sock_write(client->con->sock, "icy%s:%s\r\n",
-                            var->name + 3, var->value);
-                }
-                if (bytes > 0)
-                    client->con->sent_bytes += bytes;
+                    }
             }
         }
-        node = avl_get_next(node);
+
+        remaining -= bytes;
+        ptr += bytes;
+        if (next)
+            node = avl_get_next(node);
     }
     avl_tree_unlock(source->parser->vars);
-    bytes = sock_write(client->con->sock,
-            "Server: %s\r\n", ICECAST_VERSION_STRING);
-    if(bytes > 0) client->con->sent_bytes += bytes;
+
+    bytes = snprintf (ptr, remaining, "Server: %s\r\n", ICECAST_VERSION_STRING);
+    remaining -= bytes;
+    ptr += bytes;
+
+    bytes = snprintf (ptr, remaining, "\r\n");
+    remaining -= bytes;
+    ptr += bytes;
+
+    client->refbuf->len -= remaining;
+    if (source->format->create_client_data)
+        if (source->format->create_client_data (source, client) < 0)
+            return -1;
+    return 0;
 }
 
+

Modified: icecast/trunk/icecast/src/format.h
===================================================================
--- icecast/trunk/icecast/src/format.h	2005-06-08 00:46:03 UTC (rev 9398)
+++ icecast/trunk/icecast/src/format.h	2005-06-08 01:36:51 UTC (rev 9399)
@@ -44,11 +44,9 @@
     uint64_t sent_bytes;
 
     refbuf_t *(*get_buffer)(struct source_tag *);
-    int (*write_buf_to_client)(struct _format_plugin_tag *format, client_t *client);
+    int (*write_buf_to_client)(client_t *client);
     void (*write_buf_to_file)(struct source_tag *source, refbuf_t *refbuf);
     int (*create_client_data)(struct source_tag *source, client_t *client);
-    void (*client_send_headers)(struct _format_plugin_tag *format, 
-            struct source_tag *source, client_t *client);
     void (*set_tag)(struct _format_plugin_tag *plugin, char *tag, char *value);
     void (*free_plugin)(struct _format_plugin_tag *self);
     void (*apply_settings)(client_t *client, struct _format_plugin_tag *format, struct _mount_proxy *mount);
@@ -61,7 +59,9 @@
 char *format_get_mimetype(format_type_t type);
 int format_get_plugin(format_type_t type, struct source_tag *source);
 
+int format_generic_write_to_client (client_t *client);
 int format_advance_queue (struct source_tag *source, client_t *client);
+int format_check_http_buffer (struct source_tag *source, client_t *client);
 int format_check_file_buffer (struct source_tag *source, client_t *client);
 
 void format_send_general_headers(format_plugin_t *format, 

Modified: icecast/trunk/icecast/src/format_mp3.c
===================================================================
--- icecast/trunk/icecast/src/format_mp3.c	2005-06-08 00:46:03 UTC (rev 9398)
+++ icecast/trunk/icecast/src/format_mp3.c	2005-06-08 01:36:51 UTC (rev 9399)
@@ -59,9 +59,7 @@
 
 static int  format_mp3_create_client_data (source_t *source, client_t *client);
 static void free_mp3_client_data (client_t *client);
-static int format_mp3_write_buf_to_client(format_plugin_t *self, client_t *client);
-static void format_mp3_send_headers(format_plugin_t *self, 
-        source_t *source, client_t *client);
+static int format_mp3_write_buf_to_client(client_t *client);
 static void write_mp3_to_file (struct source_tag *source, refbuf_t *refbuf);
 static void mp3_set_tag (format_plugin_t *plugin, char *tag, char *value);
 static void format_mp3_apply_settings(client_t *client, format_plugin_t *format, mount_proxy *mount);
@@ -89,7 +87,6 @@
     plugin->write_buf_to_client = format_mp3_write_buf_to_client;
     plugin->write_buf_to_file = write_mp3_to_file;
     plugin->create_client_data = format_mp3_create_client_data;
-    plugin->client_send_headers = format_mp3_send_headers;
     plugin->free_plugin = format_mp3_free_plugin;
     plugin->set_tag = mp3_set_tag;
     plugin->apply_settings = format_mp3_apply_settings;
@@ -320,7 +317,7 @@
 /* Handler for writing mp3 data to a client, taking into account whether
  * client has requested shoutcast style metadata updates
  */
-static int format_mp3_write_buf_to_client (format_plugin_t *self, client_t *client) 
+static int format_mp3_write_buf_to_client(client_t *client)
 {
     int ret, written = 0;
     mp3_client_data *client_mp3 = client->format_data;
@@ -573,12 +570,24 @@
 static int format_mp3_create_client_data(source_t *source, client_t *client)
 {
     mp3_client_data *client_mp3 = calloc(1,sizeof(mp3_client_data));
-    char *metadata;
     mp3_state *source_mp3 = source->format->_state;
+    const char *metadata; 
+    /* the +-2 is for overwriting the last set of \r\n */
+    unsigned remaining = 4096 - client->refbuf->len + 2;
+    char *ptr = client->refbuf->data + client->refbuf->len - 2;
+    int bytes;
 
     if (client_mp3 == NULL)
         return -1;
 
+    /* hack for flash player, it wants a length */
+    if (httpp_getvar(client->parser, "x-flash-version"))
+    {
+        bytes = snprintf (ptr, remaining, "Content-Length: 347122319\r\n");
+        remaining -= bytes;
+        ptr += bytes;
+    }
+
     client->format_data = client_mp3;
     client->free_client_data = free_mp3_client_data;
     metadata = httpp_getvar(client->parser, "icy-metadata");
@@ -588,8 +597,19 @@
             client_mp3->interval = source_mp3->interval;
         else
             client_mp3->interval = ICY_METADATA_INTERVAL;
+        bytes = snprintf (ptr, remaining, "icy-metaint:%u\r\n",
+                client_mp3->interval);
+        if (bytes > 0)
+        {
+            remaining -= bytes;
+            ptr += bytes;
+        }
     }
+    bytes = snprintf (ptr, remaining, "\r\n");
+    remaining -= bytes;
+    ptr += bytes;
 
+    client->refbuf->len = 4096 - remaining;
 
     return 0;
 }
@@ -602,54 +622,6 @@
 }
 
 
-static void format_mp3_send_headers(format_plugin_t *self,
-        source_t *source, client_t *client)
-{
-    int bytes;
-    char *content_length;
-
-    mp3_client_data *mp3data = client->format_data;
-    
-    client->respcode = 200;
-
-    /* This little bit of code is for compatability with
-       flash mp3 streaming. Flash requires a content-length
-       in order for it to stream mp3s, and so based off a
-       trial and error effort, the following number was derived.
-       It is the largest content-length that we can send, anything
-       larger causes flash streaming not to work. Note that it
-       is also possible that other flash-based players may not
-       send this request header (x-flash-version), but given the
-       sampleset I had access to, this should suffice. */
-    if (httpp_getvar(client->parser, "x-flash-version")) {
-        content_length = "Content-Length: 347122319\r\n";
-    }
-    else {
-        content_length = "";
-    }
-
-    /* TODO: This may need to be ICY/1.0 for shoutcast-compatibility? */
-    bytes = sock_write(client->con->sock, 
-            "HTTP/1.0 200 OK\r\n" 
-            "Content-Type: %s\r\n"
-            "%s", 
-            source->format->contenttype,
-            content_length);
-
-    if (bytes > 0)
-        client->con->sent_bytes += bytes;
-
-    if (mp3data->interval)
-    {
-        int bytes = sock_write(client->con->sock, "icy-metaint:%d\r\n", 
-                mp3data->interval);
-        if(bytes > 0)
-            client->con->sent_bytes += bytes;
-    }
-    format_send_general_headers(self, source, client);
-}
-
-
 static void write_mp3_to_file (struct source_tag *source, refbuf_t *refbuf)
 {
     if (refbuf->len == 0)

Modified: icecast/trunk/icecast/src/format_ogg.c
===================================================================
--- icecast/trunk/icecast/src/format_ogg.c	2005-06-08 00:46:03 UTC (rev 9398)
+++ icecast/trunk/icecast/src/format_ogg.c	2005-06-08 01:36:51 UTC (rev 9399)
@@ -54,13 +54,11 @@
 
 static void format_ogg_free_plugin (format_plugin_t *plugin);
 static int  create_ogg_client_data(source_t *source, client_t *client);
-static void format_ogg_send_headers(format_plugin_t *self,
-        source_t *source, client_t *client);
 static void free_ogg_client_data (client_t *client);
 
 static void write_ogg_to_file (struct source_tag *source, refbuf_t *refbuf);
 static refbuf_t *ogg_get_buffer (source_t *source);
-static int write_buf_to_client (format_plugin_t *self, client_t *client);
+static int write_buf_to_client (client_t *client);
 
 
 struct ogg_client
@@ -167,7 +165,6 @@
     plugin->write_buf_to_client = write_buf_to_client;
     plugin->write_buf_to_file = write_ogg_to_file;
     plugin->create_client_data = create_ogg_client_data;
-    plugin->client_send_headers = format_ogg_send_headers;
     plugin->free_plugin = format_ogg_free_plugin;
     plugin->set_tag = NULL;
     plugin->contenttype = "application/ogg";
@@ -501,7 +498,7 @@
 /* main client write routine for sending ogg data. Each refbuf has a
  * single page so we only need to determine if there are new headers
  */
-static int write_buf_to_client (format_plugin_t *self, client_t *client)
+static int write_buf_to_client (client_t *client)
 {
     refbuf_t *refbuf = client->refbuf;
     char *buf = refbuf->data + client->pos;
@@ -570,19 +567,3 @@
 }
 
 
-static void format_ogg_send_headers(format_plugin_t *self,
-        source_t *source, client_t *client)
-{
-    int bytes;
-
-    client->respcode = 200;
-    bytes = sock_write(client->con->sock, 
-            "HTTP/1.0 200 OK\r\n" 
-            "Content-Type: %s\r\n", 
-            source->format->contenttype);
-
-    if(bytes > 0) client->con->sent_bytes += bytes;
-
-    format_send_general_headers(self, source, client);
-}
-

Modified: icecast/trunk/icecast/src/source.c
===================================================================
--- icecast/trunk/icecast/src/source.c	2005-06-08 00:46:03 UTC (rev 9398)
+++ icecast/trunk/icecast/src/source.c	2005-06-08 01:36:51 UTC (rev 9399)
@@ -475,7 +475,7 @@
         if (client->check_buffer (source, client) < 0)
             break;
 
-        bytes = source->format->write_buf_to_client (source->format, client);
+        bytes = client->write_to_client (client);
         if (bytes <= 0)
             break;  /* can't write any more */
 
@@ -790,7 +790,11 @@
 {
     client_t *client = (client_t *)key;
 
-    client_destroy(client);
+    /* if no response has been sent then send a 404 */
+    if (client->respcode == 0)
+        client_send_404 (client, "Mount unavailable");
+    else
+        client_destroy(client);
     
     return 1;
 }



More information about the commits mailing list