From dde143d4b14b4913e8f7be4e9f5516409417b985 Mon Sep 17 00:00:00 2001 From: Karl Heyes Date: Fri, 12 Aug 2005 15:27:32 +0000 Subject: [PATCH] make various responses going back to the client be done via the file serving thread svn path=/icecast/trunk/icecast/; revision=9740 --- src/client.c | 33 ++++++++++++--------------------- src/connection.c | 21 +++++++++++---------- src/fserve.c | 36 ++++++++++++++++++++++++++++++++---- src/fserve.h | 5 +++++ src/source.c | 46 ++++++++++++++++++++++++---------------------- src/source.h | 1 + src/stats.c | 21 +++++++++++++++++---- src/stats.h | 2 +- 8 files changed, 103 insertions(+), 62 deletions(-) diff --git a/src/client.c b/src/client.c index bb43d8cd..7339b187 100644 --- a/src/client.c +++ b/src/client.c @@ -32,6 +32,7 @@ #include "refbuf.h" #include "format.h" #include "stats.h" +#include "fserve.h" #include "client.h" #include "logging.h" @@ -143,46 +144,36 @@ int client_read_bytes (client_t *client, void *buf, unsigned len) void client_send_400(client_t *client, char *message) { - int bytes; - bytes = sock_write(client->con->sock, "HTTP/1.0 400 Bad Request\r\n" + snprintf (client->refbuf->data, PER_CLIENT_REFBUF_SIZE, + "HTTP/1.0 400 Bad Request\r\n" "Content-Type: text/html\r\n\r\n" "%s\r\n", message); - if(bytes > 0) client->con->sent_bytes = bytes; client->respcode = 400; - client_destroy(client); + client->refbuf->len = strlen (client->refbuf->data); + fserve_add_client (client, NULL); } void client_send_404(client_t *client, char *message) { - int bytes; - bytes = sock_write(client->con->sock, "HTTP/1.0 404 File Not Found\r\n" + snprintf (client->refbuf->data, PER_CLIENT_REFBUF_SIZE, + "HTTP/1.0 404 File Not Found\r\n" "Content-Type: text/html\r\n\r\n" "%s\r\n", message); - if(bytes > 0) client->con->sent_bytes = bytes; client->respcode = 404; - client_destroy(client); + client->refbuf->len = strlen (client->refbuf->data); + fserve_add_client (client, NULL); } -void client_send_504(client_t *client, char *message) { - int bytes; - client->respcode = 504; - bytes = sock_write(client->con->sock, - "HTTP/1.0 504 Server Full\r\n" - "Content-Type: text/html\r\n\r\n" - "%s\r\n", message); - if (bytes > 0) client->con->sent_bytes = bytes; - client_destroy(client); -} void client_send_401(client_t *client) { - int bytes = sock_write(client->con->sock, + snprintf (client->refbuf->data, PER_CLIENT_REFBUF_SIZE, "HTTP/1.0 401 Authentication Required\r\n" "WWW-Authenticate: Basic realm=\"Icecast2 Server\"\r\n" "\r\n" "You need to authenticate\r\n"); - if(bytes > 0) client->con->sent_bytes = bytes; client->respcode = 401; - client_destroy(client); + client->refbuf->len = strlen (client->refbuf->data); + fserve_add_client (client, NULL); } void client_send_403(client_t *client) { diff --git a/src/connection.c b/src/connection.c index 439f08d4..4f9e9acf 100644 --- a/src/connection.c +++ b/src/connection.c @@ -764,8 +764,13 @@ static void _handle_source_request (client_t *client, char *uri, int auth_style) source_free_source (source); } else - thread_create ("Source Thread", source_client_thread, - source, THREAD_DETACHED); + { + client->respcode = 200; + snprintf (client->refbuf->data, PER_CLIENT_REFBUF_SIZE, + "HTTP/1.0 200 OK\r\n\r\n"); + client->refbuf->len = strlen (client->refbuf->data); + fserve_add_client_callback (client, source_client_callback, source); + } } else { @@ -787,14 +792,10 @@ static void _handle_stats_request (client_t *client, char *uri) } client->respcode = 200; - if (sock_write (client->con->sock, "HTTP/1.0 200 OK\r\n\r\n") < 19) - { - client_destroy (client); - ERROR0 ("failed to write header"); - return; - } - - thread_create("Stats Connection", stats_connection, (void *)client, THREAD_DETACHED); + snprintf (client->refbuf->data, PER_CLIENT_REFBUF_SIZE, + "HTTP/1.0 200 OK\r\n\r\n"); + client->refbuf->len = strlen (client->refbuf->data); + fserve_add_client_callback (client, stats_callback, NULL); } static void _handle_get_request (client_t *client, char *passed_uri) diff --git a/src/fserve.c b/src/fserve.c index f00ae6bf..0a9fa22e 100644 --- a/src/fserve.c +++ b/src/fserve.c @@ -352,8 +352,11 @@ static void fserve_client_destroy(fserve_t *fclient) if (fclient->file) fclose (fclient->file); - if (fclient->client) - client_destroy (fclient->client); + if (fclient->callback) + fclient->callback (fclient->client, fclient->arg); + else + if (fclient->client) + client_destroy (fclient->client); free (fclient); } } @@ -396,8 +399,7 @@ int fserve_client_create (client_t *httpclient, const char *path) m3u_file_available = 0; } - client_set_queue (httpclient, NULL); - httpclient->refbuf = refbuf_new (BUFSIZE); + httpclient->refbuf->len = PER_CLIENT_REFBUF_SIZE; if (m3u_requested && m3u_file_available == 0) { @@ -580,6 +582,32 @@ int fserve_add_client (client_t *client, FILE *file) } +/* add client to file serving engine, but just write out the buffer contents, + * then pass the client to the callback with the provided arg + */ +void fserve_add_client_callback (client_t *client, fserve_callback_t callback, void *arg) +{ + 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; + } + fclient->file = NULL; + fclient->client = client; + fclient->ready = 0; + fclient->callback = callback; + fclient->arg = arg; + + thread_mutex_lock (&pending_lock); + fclient->next = (fserve_t *)pending_list; + pending_list = fclient; + thread_mutex_unlock (&pending_lock); +} + + static int _delete_mapping(void *mapping) { mime_type *map = mapping; free(map->ext); diff --git a/src/fserve.h b/src/fserve.h index 48408cb6..1b000915 100644 --- a/src/fserve.h +++ b/src/fserve.h @@ -15,12 +15,16 @@ #include +typedef void (*fserve_callback_t)(client_t *, void *); + typedef struct _fserve_t { client_t *client; FILE *file; int ready; + void (*callback)(client_t *, void *); + void *arg; struct _fserve_t *next; } fserve_t; @@ -28,6 +32,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); +void fserve_add_client_callback (client_t *client, fserve_callback_t callback, void *arg); char *fserve_content_type (const char *path); diff --git a/src/source.c b/src/source.c index 787f36dc..d2e20401 100644 --- a/src/source.c +++ b/src/source.c @@ -1184,28 +1184,6 @@ void *source_client_thread (void *arg) { source_t *source = arg; - if (source->client && source->client->con) - { - 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"); @@ -1218,6 +1196,30 @@ void *source_client_thread (void *arg) } +void source_client_callback (client_t *client, void *arg) +{ + const char *agent; + source_t *source = arg; + + if (client->con->error) + { + global_lock(); + global.sources--; + global_unlock(); + source_free_source (source); + client_destroy (client); + return; + } + 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); + + thread_create ("Source Thread", source_client_thread, + source, THREAD_DETACHED); +} + + #ifndef _WIN32 static void source_run_script (char *command, char *mountpoint) { diff --git a/src/source.h b/src/source.h index a4b8da41..52c88084 100644 --- a/src/source.h +++ b/src/source.h @@ -78,6 +78,7 @@ typedef struct source_tag source_t *source_reserve (const char *mount); void *source_client_thread (void *arg); +void source_client_callback (client_t *client, void *source); void source_update_settings (ice_config_t *config, source_t *source, mount_proxy *mountinfo); void source_clear_source (source_t *source); source_t *source_find_mount(const char *mount); diff --git a/src/stats.c b/src/stats.c index 3952aee7..60453ff7 100644 --- a/src/stats.c +++ b/src/stats.c @@ -59,17 +59,17 @@ typedef struct _event_listener_tag struct _event_listener_tag *next; } event_listener_t; -volatile static int _stats_running = 0; +static volatile int _stats_running = 0; static thread_type *_stats_thread_id; -volatile static int _stats_threads = 0; +static volatile int _stats_threads = 0; static stats_t _stats; static mutex_t _stats_mutex; -volatile static stats_event_t *_global_event_queue; +static volatile stats_event_t *_global_event_queue; mutex_t _global_event_mutex; -volatile static event_listener_t *_event_listeners; +static volatile event_listener_t *_event_listeners; static void *_stats_thread(void *arg); @@ -842,6 +842,19 @@ void *stats_connection(void *arg) return NULL; } + +void stats_callback (client_t *client, void *notused) +{ + if (client->con->error) + { + client_destroy (client); + return; + } + client_set_queue (client, NULL); + thread_create("Stats Connection", stats_connection, (void *)client, THREAD_DETACHED); +} + + typedef struct _source_xml_tag { char *mount; xmlNodePtr node; diff --git a/src/stats.h b/src/stats.h index 59025198..45ca5920 100644 --- a/src/stats.h +++ b/src/stats.h @@ -84,7 +84,7 @@ void stats_event_hidden (const char *source, const char *name, int hidden); void stats_event_time (const char *mount, const char *name); void *stats_connection(void *arg); -void *stats_callback(void *arg); +void stats_callback (client_t *client, void *notused); void stats_transform_xslt(client_t *client, const char *uri); void stats_sendxml(client_t *client);