1
0
mirror of https://gitlab.xiph.org/xiph/icecast-server.git synced 2024-11-03 04:17:17 -05:00

perform streamlist request via curl in a seperate thread, allow for using

an ssl port of the master server.  Other minor cleanups, typos etc

svn path=/icecast/branches/kh/icecast/; revision=9723
This commit is contained in:
Karl Heyes 2005-08-10 17:24:35 +00:00
parent de20891c40
commit 1ff370d384
9 changed files with 199 additions and 99 deletions

View File

@ -1123,7 +1123,7 @@ static void command_shoutcast_metadata(client_t *client, source_t *source)
/* 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)

View File

@ -324,7 +324,7 @@ static int add_authenticated_client (const char *mount, mount_proxy *mountinfo,
else
{
avl_tree_unlock (global.source_tree);
ret = fserve_client_create (client, mount);
fserve_client_create (client, mount);
}
return ret;
}

View File

@ -463,6 +463,10 @@ static void _parse_root(xmlDocPtr doc, xmlNodePtr node,
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)

View File

@ -140,6 +140,7 @@ typedef struct ice_config_tag
char *master_username;
char *master_password;
int master_relay_auth;
int master_ssl_port;
relay_server *relay;

View File

@ -38,7 +38,7 @@ typedef struct _client_tag
/* 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 */

View File

@ -242,6 +242,8 @@ static int connection_send_ssl (connection_t *con, const char *buf, unsigned len
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;

View File

@ -370,6 +370,9 @@ static void fserve_client_destroy(fserve_t *fclient)
}
/* 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 @@ int fserve_client_create (client_t *httpclient, const char *path)
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 @@ int fserve_client_create (client_t *httpclient, const char *path)
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 @@ int fserve_client_create (client_t *httpclient, const char *path)
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 @@ int fserve_client_create (client_t *httpclient, const char *path)
{
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 @@ int fserve_client_create (client_t *httpclient, const char *path)
/* 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;
}

View File

@ -49,7 +49,6 @@
#include "xslt.h"
#include "fserve.h"
#include "yp.h"
#include "format.h"
#include <libxml/xmlmemory.h>

View File

@ -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 void relay_check_streams (relay_server *to_start, relay_server *to_free)
}
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
int ssl_port;
int send_auth;
int on_demand;
int previous;
int ok;
char *buffer;
char *username;
char *password;
relay_server *new_relays;
};
/* 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;
/* drop EOL chars if any */
if (eol)
*eol = '\0';
else
{
char *authheader, *data;
relay_server *new_relays = NULL, *cleanup_relays;
int len, count = 1;
int on_demand, send_auth;
username = strdup (config->master_username);
if (config->master_password)
password = strdup (config->master_password);
if (config->master_server)
master = strdup (config->master_server);
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)
eol = memchr (ptr, '\n', passed_len);
if (eol)
*eol = '\0';
else
return -1;
}
if (strncmp (ptr, "HTTP", 4) == 0)
{
WARN0("Relay slave failed to contact master server to fetch stream list");
int respcode;
if (sscanf (ptr, "HTTP%*s %d OK", &respcode) == 1 && respcode == 200)
{
master->ok = 1;
}
else
{
WARN1 ("Failed response from master \"%s\"", (char*)ptr);
return -1;
}
}
return passed_len;
}
/* 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)
{
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;
}
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)
DEBUG1 ("read from master \"%s\"", buf);
if (strlen (buf))
{
sock_close (mastersock);
WARN0 ("Master rejected streamlist request");
break;
}
while (sock_read_line(mastersock, buf, sizeof(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)
{
r->server = xmlStrdup (master);
r->port = port;
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 = on_demand;
r->on_demand = master->on_demand;
r->enable = 1;
if (send_auth)
if (master->send_auth)
{
r->username = xmlStrdup (username);
r->password = xmlStrdup (password);
r->username = xmlStrdup (master->username);
r->password = xmlStrdup (master->password);
}
r->next = new_relays;
new_relays = r;
r->next = master->new_relays;
master->new_relays = r;
}
buf += offset;
len -= offset;
}
sock_close (mastersock);
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);
if (master)
curl_easy_cleanup (handle);
free (master->server);
free (master->username);
free (master->password);
free (master->buffer);
free (master);
if (username)
free (username);
if (password)
free (password);
return NULL;
}
#endif
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 @@ static void *_slave_thread(void *arg)
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));