[xiph-commits] r9723 - icecast/branches/kh/icecast/src
karl at svn.xiph.org
karl at svn.xiph.org
Wed Aug 10 10:24:41 PDT 2005
Author: karl
Date: 2005-08-10 10:24:35 -0700 (Wed, 10 Aug 2005)
New Revision: 9723
Modified:
icecast/branches/kh/icecast/src/admin.c
icecast/branches/kh/icecast/src/auth.c
icecast/branches/kh/icecast/src/cfgfile.c
icecast/branches/kh/icecast/src/cfgfile.h
icecast/branches/kh/icecast/src/client.h
icecast/branches/kh/icecast/src/connection.c
icecast/branches/kh/icecast/src/fserve.c
icecast/branches/kh/icecast/src/main.c
icecast/branches/kh/icecast/src/slave.c
Log:
perform streamlist request via curl in a seperate thread, allow for using
an ssl port of the master server. Other minor cleanups, typos etc
Modified: icecast/branches/kh/icecast/src/admin.c
===================================================================
--- icecast/branches/kh/icecast/src/admin.c 2005-08-09 22:42:10 UTC (rev 9722)
+++ icecast/branches/kh/icecast/src/admin.c 2005-08-10 17:24:35 UTC (rev 9723)
@@ -1123,7 +1123,7 @@
/* catch all function for admin requests. If file has xsl extension then
- * transform it usinf the available stats, else send the XML tree of the
+ * transform it using the available stats, else send the XML tree of the
* stats
*/
static void command_stats (client_t *client)
Modified: icecast/branches/kh/icecast/src/auth.c
===================================================================
--- icecast/branches/kh/icecast/src/auth.c 2005-08-09 22:42:10 UTC (rev 9722)
+++ icecast/branches/kh/icecast/src/auth.c 2005-08-10 17:24:35 UTC (rev 9723)
@@ -324,7 +324,7 @@
else
{
avl_tree_unlock (global.source_tree);
- ret = fserve_client_create (client, mount);
+ fserve_client_create (client, mount);
}
return ret;
}
Modified: icecast/branches/kh/icecast/src/cfgfile.c
===================================================================
--- icecast/branches/kh/icecast/src/cfgfile.c 2005-08-09 22:42:10 UTC (rev 9722)
+++ icecast/branches/kh/icecast/src/cfgfile.c 2005-08-10 17:24:35 UTC (rev 9723)
@@ -463,6 +463,10 @@
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
configuration->master_relay_auth = atoi(tmp);
xmlFree (tmp);
+ } else if (strcmp(node->name, "master-ssl-port") == 0) {
+ tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
+ configuration->master_ssl_port = atoi(tmp);
+ xmlFree (tmp);
} else if (strcmp(node->name, "shoutcast-mount") == 0) {
if (configuration->shoutcast_mount &&
configuration->shoutcast_mount != CONFIG_DEFAULT_SHOUTCAST_MOUNT)
Modified: icecast/branches/kh/icecast/src/cfgfile.h
===================================================================
--- icecast/branches/kh/icecast/src/cfgfile.h 2005-08-09 22:42:10 UTC (rev 9722)
+++ icecast/branches/kh/icecast/src/cfgfile.h 2005-08-10 17:24:35 UTC (rev 9723)
@@ -140,6 +140,7 @@
char *master_username;
char *master_password;
int master_relay_auth;
+ int master_ssl_port;
relay_server *relay;
Modified: icecast/branches/kh/icecast/src/client.h
===================================================================
--- icecast/branches/kh/icecast/src/client.h 2005-08-09 22:42:10 UTC (rev 9722)
+++ icecast/branches/kh/icecast/src/client.h 2005-08-10 17:24:35 UTC (rev 9723)
@@ -38,7 +38,7 @@
/* http response code for this client */
int respcode;
- /* auth completed, 0 not yet, 1 passed, 2 failed */
+ /* auth completed, 0 not yet, 1 passed */
int authenticated;
/* is client getting intro data */
Modified: icecast/branches/kh/icecast/src/connection.c
===================================================================
--- icecast/branches/kh/icecast/src/connection.c 2005-08-09 22:42:10 UTC (rev 9722)
+++ icecast/branches/kh/icecast/src/connection.c 2005-08-10 17:24:35 UTC (rev 9723)
@@ -242,6 +242,8 @@
static int connection_read (connection_t *con, char *buf, unsigned len)
{
int bytes = sock_read_bytes (con->sock, buf, len);
+ if (bytes == 0)
+ con->error = 1;
if (bytes == -1 && !sock_recoverable (sock_error()))
con->error = 1;
return bytes;
Modified: icecast/branches/kh/icecast/src/fserve.c
===================================================================
--- icecast/branches/kh/icecast/src/fserve.c 2005-08-09 22:42:10 UTC (rev 9722)
+++ icecast/branches/kh/icecast/src/fserve.c 2005-08-10 17:24:35 UTC (rev 9723)
@@ -370,6 +370,9 @@
}
+/* client has requested a file, so check for it and send the file. Do not
+ * refer to the client_t afterwards. return 0 for success, -1 on error.
+ */
int fserve_client_create (client_t *httpclient, const char *path)
{
struct stat file_buf;
@@ -397,7 +400,7 @@
WARN2 ("req for file \"%s\" %s", fullpath, strerror (errno));
client_send_404 (httpclient, "The file you requested could not be found");
free (fullpath);
- return 0;
+ return -1;
}
m3u_file_available = 0;
}
@@ -448,7 +451,7 @@
client_send_404 (httpclient, "The file you requested could not be found");
config_release_config();
free (fullpath);
- return 0;
+ return -1;
}
config_release_config();
@@ -457,7 +460,7 @@
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 0;
+ return -1;
}
file = fopen (fullpath, "rb");
@@ -466,7 +469,7 @@
{
WARN1 ("Problem accessing file \"%s\"", fullpath);
client_send_404 (httpclient, "File not readable");
- return 0;
+ return -1;
}
content_length = (int64_t)file_buf.st_size;
@@ -537,7 +540,7 @@
/* If we run into any issues with the ranges
we fallback to a normal/non-range request */
client_send_416 (httpclient);
- return 0;
+ return -1;
}
Modified: icecast/branches/kh/icecast/src/main.c
===================================================================
--- icecast/branches/kh/icecast/src/main.c 2005-08-09 22:42:10 UTC (rev 9722)
+++ icecast/branches/kh/icecast/src/main.c 2005-08-10 17:24:35 UTC (rev 9723)
@@ -49,7 +49,6 @@
#include "xslt.h"
#include "fserve.h"
#include "yp.h"
-#include "format.h"
#include <libxml/xmlmemory.h>
Modified: icecast/branches/kh/icecast/src/slave.c
===================================================================
--- icecast/branches/kh/icecast/src/slave.c 2005-08-09 22:42:10 UTC (rev 9722)
+++ icecast/branches/kh/icecast/src/slave.c 2005-08-10 17:24:35 UTC (rev 9723)
@@ -38,6 +38,9 @@
#define strcasecmp stricmp
#define strncasecmp strnicmp
#endif
+#ifdef HAVE_CURL
+#include <curl/curl.h>
+#endif
#include "os.h"
@@ -563,112 +566,202 @@
}
-static int update_from_master(ice_config_t *config)
+#ifdef HAVE_CURL
+struct master_conn_details
{
- char *master = NULL, *password = NULL, *username= NULL;
+ char *server;
int port;
- sock_t mastersock;
- int ret = 0;
- char buf[256];
- do
- {
- char *authheader, *data;
- relay_server *new_relays = NULL, *cleanup_relays;
- int len, count = 1;
- int on_demand, send_auth;
+ int ssl_port;
+ int send_auth;
+ int on_demand;
+ int previous;
+ int ok;
+ char *buffer;
+ char *username;
+ char *password;
+ relay_server *new_relays;
+};
- username = strdup (config->master_username);
- if (config->master_password)
- password = strdup (config->master_password);
- if (config->master_server)
- master = strdup (config->master_server);
+/* process a single HTTP header from streamlist response */
+static size_t streamlist_header (void *ptr, size_t size, size_t nmemb, void *stream)
+{
+ size_t passed_len = size*nmemb;
+ char *eol = memchr (ptr, '\r', passed_len);
+ struct master_conn_details *master = stream;
- port = config->master_server_port;
-
- if (password == NULL || master == NULL || port == 0)
- break;
- on_demand = config->on_demand;
- send_auth = config->master_relay_auth;
- ret = 1;
- config_release_config();
- mastersock = sock_connect_wto (master, port, 0);
-
- if (mastersock == SOCK_ERROR)
+ /* drop EOL chars if any */
+ if (eol)
+ *eol = '\0';
+ else
+ {
+ eol = memchr (ptr, '\n', passed_len);
+ if (eol)
+ *eol = '\0';
+ else
+ return -1;
+ }
+ if (strncmp (ptr, "HTTP", 4) == 0)
+ {
+ int respcode;
+ if (sscanf (ptr, "HTTP%*s %d OK", &respcode) == 1 && respcode == 200)
{
- WARN0("Relay slave failed to contact master server to fetch stream list");
- break;
+ master->ok = 1;
}
+ else
+ {
+ WARN1 ("Failed response from master \"%s\"", (char*)ptr);
+ return -1;
+ }
+ }
+ return passed_len;
+}
- len = strlen(username) + strlen(password) + 2;
- authheader = malloc(len);
- snprintf (authheader, len, "%s:%s", username, password);
- data = util_base64_encode(authheader);
- sock_write (mastersock,
- "GET /admin/streamlist.txt HTTP/1.0\r\n"
- "Authorization: Basic %s\r\n"
- "\r\n", data);
- free(authheader);
- free(data);
- if (sock_read_line(mastersock, buf, sizeof(buf)) == 0 ||
- strncmp (buf, "HTTP/1.0 200", 12) != 0)
+/* process mountpoint list from master server. This may be called multiple
+ * times so watch for the last line in this block as it may be incomplete
+ */
+static size_t streamlist_data (void *ptr, size_t size, size_t nmemb, void *stream)
+{
+ struct master_conn_details *master = stream;
+ size_t passed_len = size*nmemb;
+ size_t len = passed_len + master->previous + 1;
+ char *buffer, *buf;
+
+ /* append newly read data to the end of any previous unprocess data */
+ buffer = realloc (master->buffer, len);
+ memcpy (buffer + master->previous, ptr, passed_len);
+ buffer [len] = '\0';
+
+ buf = buffer;
+ while (len)
+ {
+ int offset;
+ char *eol = strchr (buf, '\n');
+ if (eol)
{
- sock_close (mastersock);
- WARN0 ("Master rejected streamlist request");
+ offset = (eol - buf) + 1;
+ *eol = '\0';
+ eol = strchr (buf, '\r');
+ if (eol) *eol = '\0';
+ }
+ else
+ {
+ /* incomplete line, the rest may be in the next read */
+ unsigned rest = strlen (buf);
+ memmove (buffer, buf, rest);
+ master->previous = rest;
break;
}
- while (sock_read_line(mastersock, buf, sizeof(buf)))
+ DEBUG1 ("read from master \"%s\"", buf);
+ if (strlen (buf))
{
- if (!strlen(buf))
- break;
- }
- while (sock_read_line(mastersock, buf, sizeof(buf)))
- {
- relay_server *r;
- if (!strlen(buf))
- continue;
- DEBUG2 ("read %d from master \"%s\"", count++, buf);
- r = calloc (1, sizeof (relay_server));
- if (r)
+ relay_server *r = calloc (1, sizeof (relay_server));
+ r->server = xmlStrdup (master->server);
+ r->port = master->port;
+ r->mount = xmlStrdup (buf);
+ r->localmount = xmlStrdup (buf);
+ r->mp3metadata = 1;
+ r->on_demand = master->on_demand;
+ r->enable = 1;
+ if (master->send_auth)
{
- r->server = xmlStrdup (master);
- r->port = port;
- r->mount = xmlStrdup (buf);
- r->localmount = xmlStrdup (buf);
- r->mp3metadata = 1;
- r->on_demand = on_demand;
- r->enable = 1;
- if (send_auth)
- {
- r->username = xmlStrdup (username);
- r->password = xmlStrdup (password);
- }
- r->next = new_relays;
- new_relays = r;
+ r->username = xmlStrdup (master->username);
+ r->password = xmlStrdup (master->password);
}
+ r->next = master->new_relays;
+ master->new_relays = r;
}
- sock_close (mastersock);
+ buf += offset;
+ len -= offset;
+ }
+ master->buffer = buffer;
+ return passed_len;
+}
+
+/* retrieve streamlist from master server. The streamlist can be retrieved
+ * from an SSL port if curl is capable and the config is aware of the port
+ * to use
+ */
+static void *streamlist_thread (void *arg)
+{
+ struct master_conn_details *master = arg;
+ CURL *handle;
+ const char *protocol = "http";
+ int port = master->port;
+ char error [CURL_ERROR_SIZE];
+ char url [300], auth [100];
+
+ if (master->ssl_port)
+ {
+ protocol = "https";
+ port = master->ssl_port;
+ }
+ snprintf (auth, sizeof (auth), "%s:%s", master->username, master->password);
+ snprintf (url, sizeof (url), "%s://%s:%d/admin/streamlist.txt",
+ protocol, master->server, port);
+ handle = curl_easy_init ();
+ curl_easy_setopt (handle, CURLOPT_USERAGENT, ICECAST_VERSION_STRING);
+ curl_easy_setopt (handle, CURLOPT_URL, url);
+ curl_easy_setopt (handle, CURLOPT_HEADERFUNCTION, streamlist_header);
+ curl_easy_setopt (handle, CURLOPT_HEADERDATA, master);
+ curl_easy_setopt (handle, CURLOPT_WRITEFUNCTION, streamlist_data);
+ curl_easy_setopt (handle, CURLOPT_WRITEDATA, master);
+ curl_easy_setopt (handle, CURLOPT_USERPWD, auth);
+ curl_easy_setopt (handle, CURLOPT_ERRORBUFFER, error);
+ curl_easy_setopt (handle, CURLOPT_SSL_VERIFYPEER, FALSE);
+ curl_easy_setopt (handle, CURLOPT_NOSIGNAL, 1L);
+ curl_easy_setopt (handle, CURLOPT_TIMEOUT, 15L);
+
+ if (curl_easy_perform (handle) != 0)
+ WARN2 ("Failed URL access \"%s\" (%s)", url, error);
+ if (master->ok)
+ {
+ /* process retrieved relays */
+ relay_server *cleanup_relays;
+
thread_mutex_lock (&(config_locks()->relay_lock));
- cleanup_relays = update_relays (&global.master_relays, new_relays);
-
+ cleanup_relays = update_relays (&global.master_relays, master->new_relays);
+
relay_check_streams (global.master_relays, cleanup_relays);
- relay_check_streams (NULL, new_relays);
+ relay_check_streams (NULL, master->new_relays);
thread_mutex_unlock (&(config_locks()->relay_lock));
+ }
- } while(0);
+ curl_easy_cleanup (handle);
+ free (master->server);
+ free (master->username);
+ free (master->password);
+ free (master->buffer);
+ free (master);
+ return NULL;
+}
+#endif
- if (master)
- free (master);
- if (username)
- free (username);
- if (password)
- free (password);
- return ret;
+static void update_from_master (ice_config_t *config)
+{
+#ifdef HAVE_CURL
+ struct master_conn_details *details = calloc (1, sizeof (*details));
+
+ if (config->master_password == NULL || config->master_server == NULL ||
+ config->master_server_port == 0)
+ return;
+ details->server = strdup (config->master_server);
+ details->port = config->master_server_port;
+ details->ssl_port = config->master_ssl_port;
+ details->username = strdup (config->master_username);
+ details->password = strdup (config->master_password);
+ details->send_auth = config->master_relay_auth;
+ details->on_demand = config->on_demand;
+
+ thread_create ("streamlist", streamlist_thread, details, THREAD_DETACHED);
+#else
+ WARN0 ("streamlist request disabled, rebuild with libcurl if required");
+#endif
}
@@ -724,9 +817,7 @@
max_interval = config->master_update_interval;
update_master_as_slave (config);
- /* the connection could take some time, so the lock can drop */
- if (update_from_master (config))
- config = config_get_config();
+ update_from_master (config);
thread_mutex_lock (&(config_locks()->relay_lock));
More information about the commits
mailing list