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

karl at motherfish-iii.xiph.org karl at motherfish-iii.xiph.org
Fri Jun 17 15:56:04 PDT 2005


Author: karl
Date: 2005-06-17 15:55:59 -0700 (Fri, 17 Jun 2005)
New Revision: 9462

Modified:
   icecast/trunk/icecast/src/connection.c
   icecast/trunk/icecast/src/fserve.c
   icecast/trunk/icecast/src/fserve.h
Log:
push HTTP header writing for file download into file serving thread to prevent
stalls in connection thread.  perform most file checking in fserve but allow
for m3u file override and using the Host header if available.


Modified: icecast/trunk/icecast/src/connection.c
===================================================================
--- icecast/trunk/icecast/src/connection.c	2005-06-17 21:00:14 UTC (rev 9461)
+++ icecast/trunk/icecast/src/connection.c	2005-06-17 22:55:59 UTC (rev 9462)
@@ -765,7 +765,6 @@
     struct stat statbuf;
     source_t *source;
     int fileserve;
-    char *host = NULL;
     int port;
     int i;
     char *serverhost = NULL;
@@ -777,8 +776,6 @@
 
     config = config_get_config();
     fileserve = config->fileserve;
-    if (config->hostname)
-        host = strdup (config->hostname);
     port = config->port;
     for(i = 0; i < global.server_sockets; i++) {
         if(global.serversock[i] == client->con->serversock) {
@@ -817,7 +814,6 @@
         (strncmp(uri, "/admin/", 7) == 0)) {
         admin_handle_request(client, uri);
         if (uri != passed_uri) free (uri);
-        free (host);
         return;
     }
 
@@ -842,46 +838,17 @@
         }
         free(fullpath);
         if (uri != passed_uri) free (uri);
-        free (host);
         return;
     }
-    else if(fileserve && stat(fullpath, &statbuf) == 0 && 
-#ifdef _WIN32
-            ((statbuf.st_mode) & _S_IFREG))
-#else
-            S_ISREG(statbuf.st_mode)) 
-#endif
+
+    if (fserve_client_create (client, uri))
     {
-        fserve_client_create(client, fullpath);
         free(fullpath);
         if (uri != passed_uri) free (uri);
-        free (host);
         return;
     }
     free(fullpath);
 
-    if(strcmp(util_get_extension(uri), "m3u") == 0) {
-        char *sourceuri = strdup(uri);
-        char *dot = strrchr(sourceuri, '.');
-        *dot = 0;
-        client->respcode = 200;
-        bytes = sock_write(client->con->sock,
-                    "HTTP/1.0 200 OK\r\n"
-                    "Content-Type: audio/x-mpegurl\r\n\r\n"
-                    "http://%s:%d%s\r\n", 
-                    host, 
-                    port,
-                    sourceuri
-                    );
-        if(bytes > 0) client->con->sent_bytes = bytes;
-        client_destroy(client);
-        free(sourceuri);
-        if (uri != passed_uri) free (uri);
-        free (host);
-        return;
-    }
-    free (host);
-
     avl_tree_rlock(global.source_tree);
     source = source_find_mount(uri);
     if (source) {

Modified: icecast/trunk/icecast/src/fserve.c
===================================================================
--- icecast/trunk/icecast/src/fserve.c	2005-06-17 21:00:14 UTC (rev 9461)
+++ icecast/trunk/icecast/src/fserve.c	2005-06-17 22:55:59 UTC (rev 9462)
@@ -32,6 +32,7 @@
 #include <winsock2.h>
 #include <windows.h>
 #define snprintf _snprintf
+#define S_ISREG(mode)  ((mode) & _S_IFREG)
 #endif
 
 #include "thread/thread.h"
@@ -93,14 +94,6 @@
 
 void fserve_initialize(void)
 {
-    ice_config_t *config = config_get_config();
-    int serve = config->fileserve;
-
-    config_release_config();
-
-    if(!serve)
-        return;
-
     create_mime_mappings(MIMETYPESFILE);
 
     thread_mutex_create (&pending_lock);
@@ -230,7 +223,7 @@
             pending_list = NULL;
             thread_mutex_unlock (&pending_lock);
         }
-        /* drop out of here is someone is ready */
+        /* drop out of here if someone is ready */
         if (fserve_client_waiting())
             break;
     }
@@ -259,7 +252,10 @@
                 if (client->pos == refbuf->len)
                 {
                     /* Grab a new chunk */
-                    bytes = fread (refbuf->data, 1, BUFSIZE, fclient->file);
+                    if (fclient->file)
+                        bytes = fread (refbuf->data, 1, BUFSIZE, fclient->file);
+                    else
+                        bytes = 0;
                     if (bytes == 0)
                     {
                         fserve_t *to_go = fclient;
@@ -341,6 +337,8 @@
             return "image/jpeg";
         else if(!strcmp(ext, "png"))
             return "image/png";
+        else if(!strcmp(ext, "m3u"))
+            return "audio/x-mpegurl";
         else
             return "application/octet-stream";
     }
@@ -362,43 +360,107 @@
 
 int fserve_client_create(client_t *httpclient, const char *path)
 {
-    fserve_t *client;
     int bytes;
     struct stat file_buf;
     char *range = NULL;
     int64_t new_content_len = 0;
-    int64_t rangenumber = 0;
+    int64_t rangenumber = 0, content_length;
     int rangeproblem = 0;
     int ret = 0;
+    char *fullpath;
+    int m3u_requested = 0, m3u_file_available = 1;
+    ice_config_t *config;
+    FILE *file;
 
-    if (stat (path, &file_buf) != 0)
+    fullpath = util_get_path_from_normalised_uri (path);
+    INFO2 ("checking for file %s (%s)", path, fullpath);
+
+    if (strcmp (util_get_extension (fullpath), "m3u") == 0)
+        m3u_requested = 1;
+
+    /* check for the actual file */
+    if (stat (fullpath, &file_buf) != 0)
     {
+        /* the m3u can be generated, but send an m3u file if available */
+        if (m3u_requested == 0)
+        {
+            free (fullpath);
+            return 0;
+        }
+        m3u_file_available = 0;
+    }
+
+    client_set_queue (httpclient, NULL);
+    httpclient->refbuf = refbuf_new (BUFSIZE);
+
+    if (m3u_requested && m3u_file_available == 0)
+    {
+        char *host = httpp_getvar (httpclient->parser, "host");
+        char *sourceuri = strdup (path);
+        char *dot = strrchr(sourceuri, '.');
+        *dot = 0;
+        httpclient->respcode = 200;
+        if (host == NULL)
+        {
+            config = config_get_config();
+            snprintf (httpclient->refbuf->data, BUFSIZE,
+                    "HTTP/1.0 200 OK\r\n"
+                    "Content-Type: audio/x-mpegurl\r\n\r\n"
+                    "http://%s:%d%s\r\n", 
+                    config->hostname, config->port,
+                    sourceuri
+                    );
+            config_release_config();
+        }
+        else
+        {
+            snprintf (httpclient->refbuf->data, BUFSIZE,
+                    "HTTP/1.0 200 OK\r\n"
+                    "Content-Type: audio/x-mpegurl\r\n\r\n"
+                    "http://%s%s\r\n", 
+                    host, 
+                    sourceuri
+                    );
+        }
+        httpclient->refbuf->len = strlen (httpclient->refbuf->data);
+        fserve_add_client (httpclient, NULL);
+        free (sourceuri);
+        free (fullpath);
+        return 1;
+    }
+
+    /* on demand file serving check */
+    config = config_get_config();
+    if (config->fileserve == 0)
+    {
+        DEBUG1 ("on demand file \"%s\" refused", fullpath);
         client_send_404 (httpclient, "The file you requested could not be found");
+        config_release_config();
+        free (fullpath);
         return 0;
     }
+    config_release_config();
 
-    client = calloc (1, sizeof(fserve_t));
-    if (client == NULL) 
+    if (S_ISREG (file_buf.st_mode) == 0)
     {
-        client_send_404 (httpclient, "memory exhausted");
-        return 0;
+        client_send_404 (httpclient, "The file you requested could not be found");
+        WARN1 ("found requested file but there is no handler for it: %s", fullpath);
+        free (fullpath);
+        return 1;
     }
-    client->file = fopen (path, "rb");
-    if (client->file == NULL)
+
+    file = fopen (fullpath, "rb");
+    free (fullpath);
+    if (file == NULL)
     {
+        WARN1 ("Problem accessing file \"%s\"", fullpath);
         client_send_404 (httpclient, "File not readable");
-        fserve_client_destroy (client);
-        return 0;
+        return 1;
     }
 
-    client->client = httpclient;
-    client->ready = 0;
-    client_set_queue (httpclient, NULL);
-    httpclient->refbuf = refbuf_new (BUFSIZE);
-    client->content_length = (int64_t)file_buf.st_size;
+    content_length = (int64_t)file_buf.st_size;
+    range = httpp_getvar (httpclient->parser, "range");
 
-    range = httpp_getvar (client->client->parser, "range");
-
     if (range != NULL) {
         ret = sscanf(range, "bytes=" FORMAT_INT64 "-", &rangenumber);
         if (ret != 1) {
@@ -410,9 +472,9 @@
             rangeproblem = 1;
         }
         if (!rangeproblem) {
-            ret = fseek(client->file, rangenumber, SEEK_SET);
+            ret = fseek (file, rangenumber, SEEK_SET);
             if (ret != -1) {
-                new_content_len = client->content_length - rangenumber;
+                new_content_len = content_length - rangenumber;
                 if (new_content_len < 0) {
                     rangeproblem = 1;
                 }
@@ -445,25 +507,25 @@
                     new_content_len,
                     rangenumber,
                     endpos,
-                    client->content_length,
+                    content_length,
                     fserve_content_type(path));
             }
             else {
                 httpclient->respcode = 416;
-                bytes = snprintf (httpclient->refbuf->data, BUFSIZE,
+                sock_write (httpclient->con->sock,
                     "HTTP/1.0 416 Request Range Not Satisfiable\r\n\r\n");
-                fserve_client_destroy(client);
-                return -1;
+                client_destroy (httpclient);
+                return 1;
             }
         }
         else {
             /* If we run into any issues with the ranges
                we fallback to a normal/non-range request */
             httpclient->respcode = 416;
-            bytes = snprintf (httpclient->refbuf->data, BUFSIZE,
+            sock_write (httpclient->con->sock,
                 "HTTP/1.0 416 Request Range Not Satisfiable\r\n\r\n");
-            fserve_client_destroy(client);
-            return -1;
+            client_destroy (httpclient);
+            return 1;
         }
     }
     else {
@@ -473,17 +535,42 @@
             "HTTP/1.0 200 OK\r\n"
             "Content-Length: " FORMAT_INT64 "\r\n"
             "Content-Type: %s\r\n\r\n",
-            client->content_length,
+            content_length,
             fserve_content_type(path));
     }
     httpclient->refbuf->len = bytes;
+    httpclient->pos = 0;
+
     stats_event_inc (NULL, "file_connections");
-    sock_set_blocking(client->client->con->sock, SOCK_NONBLOCK);
-    sock_set_nodelay(client->client->con->sock);
+    fserve_add_client (httpclient, file);
 
+    return 1;
+}
+
+
+/* Add client to fserve thread, client needs to have refbuf set and filled
+ * but may provide a NULL file if no data needs to be read
+ */
+int fserve_add_client (client_t *client, FILE *file)
+{
+    fserve_t *fclient = calloc (1, sizeof(fserve_t));
+
+    DEBUG0 ("Adding client to file serving engine");
+    if (fclient == NULL)
+    {
+        client_send_404 (client, "memory exhausted");
+        return -1;
+    }
+    fclient->file = file;
+    fclient->client = client;
+    fclient->ready = 0;
+
+    sock_set_blocking (client->con->sock, SOCK_NONBLOCK);
+    sock_set_nodelay (client->con->sock);
+
     thread_mutex_lock (&pending_lock);
-    client->next = (fserve_t *)pending_list;
-    pending_list = client;
+    fclient->next = (fserve_t *)pending_list;
+    pending_list = fclient;
     thread_mutex_unlock (&pending_lock);
 
     return 0;

Modified: icecast/trunk/icecast/src/fserve.h
===================================================================
--- icecast/trunk/icecast/src/fserve.h	2005-06-17 21:00:14 UTC (rev 9461)
+++ icecast/trunk/icecast/src/fserve.h	2005-06-17 22:55:59 UTC (rev 9462)
@@ -14,14 +14,12 @@
 #define __FSERVE_H__
 
 #include <stdio.h>
-#include "compat.h"
 
 typedef struct _fserve_t
 {
     client_t *client;
 
     FILE *file;
-    int64_t content_length;
     int ready;
     struct _fserve_t *next;
 } fserve_t;
@@ -29,6 +27,7 @@
 void fserve_initialize(void);
 void fserve_shutdown(void);
 int fserve_client_create(client_t *httpclient, const char *path);
+int fserve_add_client (client_t *client, FILE *file);
 char *fserve_content_type (const char *path);
 
 



More information about the commits mailing list