mirror of
https://gitlab.xiph.org/xiph/icecast-server.git
synced 2024-12-04 14:46:30 -05:00
merge in fallback to file, override also works
svn path=/icecast/trunk/icecast/; revision=9434
This commit is contained in:
parent
05a14555d9
commit
be78a3ae11
@ -434,6 +434,17 @@ mountpoint that is just not available, then those clients will be disconnected.
|
||||
If clients are falling back to a mountpoint and the fallback-mount is not actively streaming
|
||||
but defines a fallback-mount itself then those clients may be moved there instead.
|
||||
This multi-level fallback allows clients to cascade several mountpoints.
|
||||
<p>A fallback mount can also state a file that is located in webroot. This is useful for
|
||||
playing a pre-recorded file in the case of a stream going down. It will repeat until either
|
||||
the listener disconnects or a stream comes back available and takes the listeners back.
|
||||
As per usual, the file format should match the stream format, failing to do so may cause
|
||||
problems with playback.
|
||||
</p>
|
||||
<p>Note that the fallback file is not timed so be careful if you intend to relay this.
|
||||
They are fine on slave streams but don't use them on master streams, if you do then the
|
||||
relay will consume stream data at a faster rate and the listeners on the relay would
|
||||
eventually get kicked off.
|
||||
</p>
|
||||
</div>
|
||||
<h4>fallback-override</h4>
|
||||
<div class="indentedbox">
|
||||
|
@ -75,10 +75,11 @@ void client_destroy(client_t *client)
|
||||
/* write log entry if ip is set (some things don't set it, like outgoing
|
||||
* slave requests
|
||||
*/
|
||||
if(client->con->ip)
|
||||
if (client->con && client->con->ip)
|
||||
logging_access(client);
|
||||
|
||||
connection_close(client->con);
|
||||
if (client->con)
|
||||
connection_close(client->con);
|
||||
httpp_destroy(client->parser);
|
||||
|
||||
global_lock ();
|
||||
|
12
src/format.c
12
src/format.c
@ -150,8 +150,16 @@ int format_check_file_buffer (source_t *source, client_t *client)
|
||||
if (refbuf == NULL)
|
||||
{
|
||||
/* client refers to no data, must be from a move */
|
||||
find_client_start (source, client);
|
||||
return -1;
|
||||
if (source->client->con)
|
||||
{
|
||||
find_client_start (source, client);
|
||||
return -1;
|
||||
}
|
||||
/* source -> file fallback, need a refbuf for data */
|
||||
refbuf = refbuf_new (4096);
|
||||
client->refbuf = refbuf;
|
||||
client->pos = refbuf->len;
|
||||
client->intro_offset = 0;
|
||||
}
|
||||
if (client->pos == refbuf->len)
|
||||
{
|
||||
|
@ -317,7 +317,7 @@ static void *fserv_thread_function(void *arg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *fserve_content_type(const char *path)
|
||||
char *fserve_content_type (const char *path)
|
||||
{
|
||||
char *ext = util_get_extension(path);
|
||||
mime_type exttype = {ext, NULL};
|
||||
|
@ -32,6 +32,7 @@ typedef struct _fserve_t
|
||||
void fserve_initialize(void);
|
||||
void fserve_shutdown(void);
|
||||
int fserve_client_create(client_t *httpclient, const char *path);
|
||||
char *fserve_content_type (const char *path);
|
||||
|
||||
|
||||
#endif
|
||||
|
132
src/source.c
132
src/source.c
@ -48,6 +48,7 @@
|
||||
#include "util.h"
|
||||
#include "source.h"
|
||||
#include "format.h"
|
||||
#include "fserve.h"
|
||||
#include "auth.h"
|
||||
#include "os.h"
|
||||
|
||||
@ -373,6 +374,8 @@ void source_move_clients (source_t *source, source_t *dest)
|
||||
{
|
||||
client_set_queue (client, NULL);
|
||||
client->check_buffer = format_check_file_buffer;
|
||||
if (source->con == NULL)
|
||||
client->intro_offset = -1;
|
||||
}
|
||||
|
||||
avl_insert (dest->pending_tree, (void *)client);
|
||||
@ -397,6 +400,8 @@ void source_move_clients (source_t *source, source_t *dest)
|
||||
{
|
||||
client_set_queue (client, NULL);
|
||||
client->check_buffer = format_check_file_buffer;
|
||||
if (source->con == NULL)
|
||||
client->intro_offset = -1;
|
||||
}
|
||||
avl_insert (dest->pending_tree, (void *)client);
|
||||
count++;
|
||||
@ -435,10 +440,16 @@ static refbuf_t *get_next_buffer (source_t *source)
|
||||
delay = 0;
|
||||
while (global.running == ICE_RUNNING && source->running)
|
||||
{
|
||||
int fds;
|
||||
int fds = 0;
|
||||
time_t current = time (NULL);
|
||||
|
||||
fds = util_timed_wait_for_fd (source->con->sock, delay);
|
||||
if (source->client->con)
|
||||
fds = util_timed_wait_for_fd (source->con->sock, delay);
|
||||
else
|
||||
{
|
||||
thread_sleep (delay*1000);
|
||||
source->last_read = current;
|
||||
}
|
||||
|
||||
if (current >= source->client_stats_update)
|
||||
{
|
||||
@ -470,7 +481,7 @@ static refbuf_t *get_next_buffer (source_t *source)
|
||||
}
|
||||
source->last_read = current;
|
||||
refbuf = source->format->get_buffer (source);
|
||||
if (source->client->con->error)
|
||||
if (source->client->con && source->client->con->error)
|
||||
{
|
||||
INFO1 ("End of Stream %s", source->mount);
|
||||
source->running = 0;
|
||||
@ -585,7 +596,8 @@ static void source_init (source_t *source)
|
||||
stats_event_inc (NULL, "source_total_connections");
|
||||
stats_event (source->mount, "slow_listeners", "0");
|
||||
|
||||
sock_set_blocking (source->con->sock, SOCK_NONBLOCK);
|
||||
if (source->client->con)
|
||||
sock_set_blocking (source->con->sock, SOCK_NONBLOCK);
|
||||
|
||||
DEBUG0("Source creation complete");
|
||||
source->last_read = time (NULL);
|
||||
@ -1095,6 +1107,9 @@ static void source_apply_mount (source_t *source, mount_proxy *mountinfo)
|
||||
*/
|
||||
void source_update_settings (ice_config_t *config, source_t *source, mount_proxy *mountinfo)
|
||||
{
|
||||
/* skip if source is a fallback to file */
|
||||
if (source->running && source->client->con == NULL)
|
||||
return;
|
||||
/* set global settings first */
|
||||
source->queue_size_limit = config->queue_size_limit;
|
||||
source->timeout = config->source_timeout;
|
||||
@ -1147,26 +1162,29 @@ void source_update_settings (ice_config_t *config, source_t *source, mount_proxy
|
||||
void *source_client_thread (void *arg)
|
||||
{
|
||||
source_t *source = arg;
|
||||
const char ok_msg[] = "HTTP/1.0 200 OK\r\n\r\n";
|
||||
int bytes;
|
||||
const char *agent;
|
||||
|
||||
source->client->respcode = 200;
|
||||
bytes = sock_write_bytes (source->client->con->sock, ok_msg, sizeof (ok_msg)-1);
|
||||
if (bytes < (int)(sizeof (ok_msg)-1))
|
||||
if (source->client && source->client->con)
|
||||
{
|
||||
global_lock();
|
||||
global.sources--;
|
||||
global_unlock();
|
||||
WARN0 ("Error writing 200 OK message to source client");
|
||||
source_free_source (source);
|
||||
return NULL;
|
||||
}
|
||||
stats_event (source->mount, "source_ip", source->client->con->ip);
|
||||
agent = httpp_getvar (source->client->parser, "user-agent");
|
||||
if (agent)
|
||||
stats_event (source->mount, "user_agent", agent);
|
||||
const char ok_msg[] = "HTTP/1.0 200 OK\r\n\r\n";
|
||||
int bytes;
|
||||
const char *agent;
|
||||
|
||||
source->client->respcode = 200;
|
||||
bytes = sock_write_bytes (source->client->con->sock, ok_msg, sizeof (ok_msg)-1);
|
||||
if (bytes < (int)(sizeof (ok_msg)-1))
|
||||
{
|
||||
global_lock();
|
||||
global.sources--;
|
||||
global_unlock();
|
||||
WARN0 ("Error writing 200 OK message to source client");
|
||||
source_free_source (source);
|
||||
return NULL;
|
||||
}
|
||||
stats_event (source->mount, "source_ip", source->client->con->ip);
|
||||
agent = httpp_getvar (source->client->parser, "user-agent");
|
||||
if (agent)
|
||||
stats_event (source->mount, "user_agent", agent);
|
||||
}
|
||||
stats_event_inc(NULL, "source_client_connections");
|
||||
stats_event (source->mount, "listeners", "0");
|
||||
|
||||
@ -1214,6 +1232,67 @@ static void source_run_script (char *command, char *mountpoint)
|
||||
#endif
|
||||
|
||||
|
||||
static void *source_fallback_file (void *arg)
|
||||
{
|
||||
char *mount = arg;
|
||||
char *type;
|
||||
char *path;
|
||||
unsigned int len;
|
||||
FILE *file = NULL;
|
||||
source_t *source = NULL;
|
||||
ice_config_t *config;
|
||||
http_parser_t *parser;
|
||||
|
||||
do
|
||||
{
|
||||
if (mount == NULL || mount[0] != '/')
|
||||
break;
|
||||
config = config_get_config();
|
||||
len = strlen (config->webroot_dir) + strlen (mount) + 1;
|
||||
path = malloc (len);
|
||||
if (path)
|
||||
snprintf (path, len, "%s%s", config->webroot_dir, mount);
|
||||
|
||||
config_release_config ();
|
||||
if (path == NULL)
|
||||
break;
|
||||
|
||||
file = fopen (path, "rb");
|
||||
if (file == NULL)
|
||||
{
|
||||
DEBUG1 ("unable to open file \"%s\"", path);
|
||||
free (path);
|
||||
break;
|
||||
}
|
||||
free (path);
|
||||
source = source_reserve (mount);
|
||||
if (source == NULL)
|
||||
{
|
||||
DEBUG1 ("mountpoint \"%s\" already reserved", mount);
|
||||
break;
|
||||
}
|
||||
type = fserve_content_type (mount);
|
||||
parser = httpp_create_parser();
|
||||
httpp_initialize (parser, NULL);
|
||||
httpp_setvar (parser, "content-type", type);
|
||||
|
||||
source->hidden = 1;
|
||||
source->yp_public = 0;
|
||||
source->intro_file = file;
|
||||
source->parser = parser;
|
||||
file = NULL;
|
||||
|
||||
if (connection_complete_source (source) < 0)
|
||||
break;
|
||||
source_client_thread (source);
|
||||
} while (0);
|
||||
if (file)
|
||||
fclose (file);
|
||||
free (mount);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* rescan the mount list, so that xsl files are updated to show
|
||||
* unconnected but active fallback mountpoints
|
||||
*/
|
||||
@ -1249,6 +1328,17 @@ void source_recheck_mounts (void)
|
||||
else
|
||||
stats_event (mount->mountname, NULL, NULL);
|
||||
|
||||
/* check for fallback to file */
|
||||
if (global.running == ICE_RUNNING && mount->fallback_mount)
|
||||
{
|
||||
source_t *fallback = source_find_mount (mount->fallback_mount);
|
||||
if (fallback == NULL)
|
||||
{
|
||||
thread_create ("Fallback file thread", source_fallback_file,
|
||||
strdup (mount->fallback_mount), THREAD_DETACHED);
|
||||
}
|
||||
}
|
||||
|
||||
mount = mount->next;
|
||||
}
|
||||
avl_tree_unlock (global.source_tree);
|
||||
|
Loading…
Reference in New Issue
Block a user