diff options
Diffstat (limited to '')
-rw-r--r-- | src/output/HttpdOutputPlugin.cxx (renamed from src/output/httpd_output_plugin.c) | 241 |
1 files changed, 95 insertions, 146 deletions
diff --git a/src/output/httpd_output_plugin.c b/src/output/HttpdOutputPlugin.cxx index 1d730df7f..d1a1a36df 100644 --- a/src/output/httpd_output_plugin.c +++ b/src/output/HttpdOutputPlugin.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2011 The Music Player Daemon Project + * Copyright (C) 2003-2013 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -18,9 +18,9 @@ */ #include "config.h" -#include "httpd_output_plugin.h" -#include "httpd_internal.h" -#include "httpd_client.h" +#include "HttpdOutputPlugin.hxx" +#include "HttpdInternal.hxx" +#include "HttpdClient.hxx" #include "output_api.h" #include "encoder_plugin.h" #include "encoder_list.h" @@ -28,7 +28,8 @@ #include "page.h" #include "icy_server.h" #include "fd_util.h" -#include "server_socket.h" +#include "ServerSocket.hxx" +#include "Main.hxx" #include <assert.h> @@ -60,9 +61,9 @@ httpd_output_quark(void) */ G_GNUC_PURE static bool -httpd_output_has_clients(const struct httpd_output *httpd) +httpd_output_has_clients(const httpd_output *httpd) { - return httpd->clients != NULL; + return !httpd->clients.empty(); } /** @@ -70,12 +71,10 @@ httpd_output_has_clients(const struct httpd_output *httpd) */ G_GNUC_PURE static bool -httpd_output_lock_has_clients(const struct httpd_output *httpd) +httpd_output_lock_has_clients(const httpd_output *httpd) { - g_mutex_lock(httpd->mutex); - bool result = httpd_output_has_clients(httpd); - g_mutex_unlock(httpd->mutex); - return result; + const ScopeLock protect(httpd->mutex); + return httpd_output_has_clients(httpd); } static void @@ -83,32 +82,28 @@ httpd_listen_in_event(int fd, const struct sockaddr *address, size_t address_length, int uid, void *ctx); static bool -httpd_output_bind(struct httpd_output *httpd, GError **error_r) +httpd_output_bind(httpd_output *httpd, GError **error_r) { httpd->open = false; - g_mutex_lock(httpd->mutex); - bool success = server_socket_open(httpd->server_socket, error_r); - g_mutex_unlock(httpd->mutex); - - return success; + const ScopeLock protect(httpd->mutex); + return server_socket_open(httpd->server_socket, error_r); } static void -httpd_output_unbind(struct httpd_output *httpd) +httpd_output_unbind(httpd_output *httpd) { assert(!httpd->open); - g_mutex_lock(httpd->mutex); + const ScopeLock protect(httpd->mutex); server_socket_close(httpd->server_socket); - g_mutex_unlock(httpd->mutex); } static struct audio_output * httpd_output_init(const struct config_param *param, GError **error) { - struct httpd_output *httpd = g_new(struct httpd_output, 1); + httpd_output *httpd = new httpd_output(); if (!ao_base_init(&httpd->base, &httpd_output_plugin, param, error)) { g_free(httpd); return NULL; @@ -140,7 +135,8 @@ httpd_output_init(const struct config_param *param, /* set up bind_to_address */ - httpd->server_socket = server_socket_new(httpd_listen_in_event, httpd); + httpd->server_socket = server_socket_new(*main_loop, + httpd_listen_in_event, httpd); const char *bind_to_address = config_get_block_string(param, "bind_to_address", NULL); @@ -174,50 +170,44 @@ httpd_output_init(const struct config_param *param, httpd->content_type = "application/octet-stream"; } - httpd->mutex = g_mutex_new(); - return &httpd->base; } static void httpd_output_finish(struct audio_output *ao) { - struct httpd_output *httpd = (struct httpd_output *)ao; + httpd_output *httpd = (httpd_output *)ao; if (httpd->metadata) page_unref(httpd->metadata); encoder_finish(httpd->encoder); server_socket_free(httpd->server_socket); - g_mutex_free(httpd->mutex); ao_base_finish(&httpd->base); - g_free(httpd); + delete httpd; } /** - * Creates a new #httpd_client object and adds it into the + * Creates a new #HttpdClient object and adds it into the * httpd_output.clients linked list. */ static void -httpd_client_add(struct httpd_output *httpd, int fd) +httpd_client_add(httpd_output *httpd, int fd) { - struct httpd_client *client = - httpd_client_new(httpd, fd, - httpd->encoder->plugin->tag == NULL); - - httpd->clients = g_list_prepend(httpd->clients, client); + httpd->clients.emplace_front(httpd, fd, + httpd->encoder->plugin->tag == NULL); httpd->clients_cnt++; /* pass metadata to client */ if (httpd->metadata) - httpd_client_send_metadata(client, httpd->metadata); + httpd->clients.front().PushMetaData(httpd->metadata); } static void httpd_listen_in_event(int fd, const struct sockaddr *address, size_t address_length, G_GNUC_UNUSED int uid, void *ctx) { - struct httpd_output *httpd = ctx; + httpd_output *httpd = (httpd_output *)ctx; /* the listener socket has become readable - a client has connected */ @@ -238,7 +228,6 @@ httpd_listen_in_event(int fd, const struct sockaddr *address, progname, hostaddr); g_free(hostaddr); close_socket(fd); - g_mutex_unlock(httpd->mutex); return; } @@ -249,7 +238,7 @@ httpd_listen_in_event(int fd, const struct sockaddr *address, (void)address_length; #endif /* HAVE_WRAP */ - g_mutex_lock(httpd->mutex); + const ScopeLock protect(httpd->mutex); if (fd >= 0) { /* can we allow additional client */ @@ -262,8 +251,6 @@ httpd_listen_in_event(int fd, const struct sockaddr *address, } else if (fd < 0 && errno != EINTR) { g_warning("accept() failed: %s", g_strerror(errno)); } - - g_mutex_unlock(httpd->mutex); } /** @@ -271,7 +258,7 @@ httpd_listen_in_event(int fd, const struct sockaddr *address, * as a new #page object. */ static struct page * -httpd_output_read_page(struct httpd_output *httpd) +httpd_output_read_page(httpd_output *httpd) { if (httpd->unflushed_input >= 65536) { /* we have fed a lot of input into the encoder, but it @@ -301,7 +288,7 @@ httpd_output_read_page(struct httpd_output *httpd) } static bool -httpd_output_encoder_open(struct httpd_output *httpd, +httpd_output_encoder_open(httpd_output *httpd, struct audio_format *audio_format, GError **error) { @@ -321,7 +308,7 @@ httpd_output_encoder_open(struct httpd_output *httpd, static bool httpd_output_enable(struct audio_output *ao, GError **error_r) { - struct httpd_output *httpd = (struct httpd_output *)ao; + httpd_output *httpd = (httpd_output *)ao; return httpd_output_bind(httpd, error_r); } @@ -329,7 +316,7 @@ httpd_output_enable(struct audio_output *ao, GError **error_r) static void httpd_output_disable(struct audio_output *ao) { - struct httpd_output *httpd = (struct httpd_output *)ao; + httpd_output *httpd = (httpd_output *)ao; httpd_output_unbind(httpd); } @@ -338,82 +325,75 @@ static bool httpd_output_open(struct audio_output *ao, struct audio_format *audio_format, GError **error) { - struct httpd_output *httpd = (struct httpd_output *)ao; + httpd_output *httpd = (httpd_output *)ao; + + assert(httpd->clients.empty()); - g_mutex_lock(httpd->mutex); + const ScopeLock protect(httpd->mutex); /* open the encoder */ - if (!httpd_output_encoder_open(httpd, audio_format, error)) { - g_mutex_unlock(httpd->mutex); + if (!httpd_output_encoder_open(httpd, audio_format, error)) return false; - } /* initialize other attributes */ - httpd->clients = NULL; httpd->clients_cnt = 0; httpd->timer = timer_new(audio_format); httpd->open = true; - g_mutex_unlock(httpd->mutex); return true; } static void -httpd_client_delete(gpointer data, G_GNUC_UNUSED gpointer user_data) -{ - struct httpd_client *client = data; - - httpd_client_free(client); -} - -static void httpd_output_close(struct audio_output *ao) { - struct httpd_output *httpd = (struct httpd_output *)ao; + httpd_output *httpd = (httpd_output *)ao; - g_mutex_lock(httpd->mutex); + const ScopeLock protect(httpd->mutex); httpd->open = false; timer_free(httpd->timer); - g_list_foreach(httpd->clients, httpd_client_delete, NULL); - g_list_free(httpd->clients); + httpd->clients.clear(); if (httpd->header != NULL) page_unref(httpd->header); encoder_close(httpd->encoder); - - g_mutex_unlock(httpd->mutex); } void -httpd_output_remove_client(struct httpd_output *httpd, - struct httpd_client *client) +httpd_output_remove_client(httpd_output *httpd, HttpdClient *client) { assert(httpd != NULL); + assert(httpd->clients_cnt > 0); assert(client != NULL); - httpd->clients = g_list_remove(httpd->clients, client); - httpd->clients_cnt--; + for (auto prev = httpd->clients.before_begin(), i = std::next(prev);; + prev = i, i = std::next(prev)) { + assert(i != httpd->clients.end()); + if (&*i == client) { + httpd->clients.erase_after(prev); + httpd->clients_cnt--; + break; + } + } } void -httpd_output_send_header(struct httpd_output *httpd, - struct httpd_client *client) +httpd_output_send_header(httpd_output *httpd, HttpdClient *client) { if (httpd->header != NULL) - httpd_client_send(client, httpd->header); + client->PushPage(httpd->header); } static unsigned httpd_output_delay(struct audio_output *ao) { - struct httpd_output *httpd = (struct httpd_output *)ao; + httpd_output *httpd = (httpd_output *)ao; if (!httpd_output_lock_has_clients(httpd) && httpd->base.pause) { /* if there's no client and this output is paused, @@ -433,51 +413,35 @@ httpd_output_delay(struct audio_output *ao) : 0; } -static void -httpd_client_check_queue(gpointer data, G_GNUC_UNUSED gpointer user_data) -{ - struct httpd_client *client = data; - - if (httpd_client_queue_size(client) > 256 * 1024) { - g_debug("client is too slow, flushing its queue"); - httpd_client_cancel(client); - } -} - -static void -httpd_client_send_page(gpointer data, gpointer user_data) -{ - struct httpd_client *client = data; - struct page *page = user_data; - - httpd_client_send(client, page); -} - /** * Broadcasts a page struct to all clients. */ static void -httpd_output_broadcast_page(struct httpd_output *httpd, struct page *page) +httpd_output_broadcast_page(httpd_output *httpd, struct page *page) { assert(page != NULL); - g_mutex_lock(httpd->mutex); - g_list_foreach(httpd->clients, httpd_client_send_page, page); - g_mutex_unlock(httpd->mutex); + const ScopeLock protect(httpd->mutex); + for (auto &client : httpd->clients) + client.PushPage(page); } /** * Broadcasts data from the encoder to all clients. */ static void -httpd_output_encoder_to_clients(struct httpd_output *httpd) +httpd_output_encoder_to_clients(httpd_output *httpd) { - struct page *page; - - g_mutex_lock(httpd->mutex); - g_list_foreach(httpd->clients, httpd_client_check_queue, NULL); - g_mutex_unlock(httpd->mutex); + httpd->mutex.lock(); + for (auto &client : httpd->clients) { + if (client.GetQueueSize() > 256 * 1024) { + g_debug("client is too slow, flushing its queue"); + client.CancelQueue(); + } + } + httpd->mutex.unlock(); + struct page *page; while ((page = httpd_output_read_page(httpd)) != NULL) { httpd_output_broadcast_page(httpd, page); page_unref(page); @@ -485,7 +449,7 @@ httpd_output_encoder_to_clients(struct httpd_output *httpd) } static bool -httpd_output_encode_and_play(struct httpd_output *httpd, +httpd_output_encode_and_play(httpd_output *httpd, const void *chunk, size_t size, GError **error) { if (!encoder_write(httpd->encoder, chunk, size, error)) @@ -502,7 +466,7 @@ static size_t httpd_output_play(struct audio_output *ao, const void *chunk, size_t size, GError **error_r) { - struct httpd_output *httpd = (struct httpd_output *)ao; + httpd_output *httpd = (httpd_output *)ao; if (httpd_output_lock_has_clients(httpd)) { if (!httpd_output_encode_and_play(httpd, chunk, size, error_r)) @@ -519,10 +483,10 @@ httpd_output_play(struct audio_output *ao, const void *chunk, size_t size, static bool httpd_output_pause(struct audio_output *ao) { - struct httpd_output *httpd = (struct httpd_output *)ao; + httpd_output *httpd = (httpd_output *)ao; if (httpd_output_lock_has_clients(httpd)) { - static const char silence[1020]; + static const char silence[1020] = { 0 }; return httpd_output_play(ao, silence, sizeof(silence), NULL) > 0; } else { @@ -531,18 +495,9 @@ httpd_output_pause(struct audio_output *ao) } static void -httpd_send_metadata(gpointer data, gpointer user_data) -{ - struct httpd_client *client = data; - struct page *icy_metadata = user_data; - - httpd_client_send_metadata(client, icy_metadata); -} - -static void httpd_output_tag(struct audio_output *ao, const struct tag *tag) { - struct httpd_output *httpd = (struct httpd_output *)ao; + httpd_output *httpd = (httpd_output *)ao; assert(tag != NULL); @@ -581,43 +536,37 @@ httpd_output_tag(struct audio_output *ao, const struct tag *tag) TAG_ARTIST, TAG_TITLE, TAG_NUM_OF_ITEM_TYPES); if (httpd->metadata != NULL) { - g_mutex_lock(httpd->mutex); - g_list_foreach(httpd->clients, - httpd_send_metadata, httpd->metadata); - g_mutex_unlock(httpd->mutex); + const ScopeLock protect(httpd->mutex); + for (auto &client : httpd->clients) + client.PushMetaData(httpd->metadata); } } } static void -httpd_client_cancel_callback(gpointer data, G_GNUC_UNUSED gpointer user_data) -{ - struct httpd_client *client = data; - - httpd_client_cancel(client); -} - -static void httpd_output_cancel(struct audio_output *ao) { - struct httpd_output *httpd = (struct httpd_output *)ao; + httpd_output *httpd = (httpd_output *)ao; - g_mutex_lock(httpd->mutex); - g_list_foreach(httpd->clients, httpd_client_cancel_callback, NULL); - g_mutex_unlock(httpd->mutex); + const ScopeLock protect(httpd->mutex); + for (auto &client : httpd->clients) + client.CancelQueue(); } const struct audio_output_plugin httpd_output_plugin = { - .name = "httpd", - .init = httpd_output_init, - .finish = httpd_output_finish, - .enable = httpd_output_enable, - .disable = httpd_output_disable, - .open = httpd_output_open, - .close = httpd_output_close, - .delay = httpd_output_delay, - .send_tag = httpd_output_tag, - .play = httpd_output_play, - .pause = httpd_output_pause, - .cancel = httpd_output_cancel, + "httpd", + nullptr, + httpd_output_init, + httpd_output_finish, + httpd_output_enable, + httpd_output_disable, + httpd_output_open, + httpd_output_close, + httpd_output_delay, + httpd_output_tag, + httpd_output_play, + nullptr, + httpd_output_cancel, + httpd_output_pause, + nullptr, }; |