diff options
author | Max Kellermann <max@duempel.org> | 2013-01-15 01:12:08 +0100 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2013-01-15 10:59:28 +0100 |
commit | 3e035279300d1ac238f2f063e5ca5f478923d7cb (patch) | |
tree | ac49f4cbcf26317ac6836c1d77966287815eaf1f /src/ClientWrite.cxx | |
parent | 4fa724461e558561402b05bd4eadf8c7b6874556 (diff) | |
download | mpd-3e035279300d1ac238f2f063e5ca5f478923d7cb.tar.gz mpd-3e035279300d1ac238f2f063e5ca5f478923d7cb.tar.xz mpd-3e035279300d1ac238f2f063e5ca5f478923d7cb.zip |
Client: move output buffer code to new class PeakBuffer
Diffstat (limited to '')
-rw-r--r-- | src/ClientWrite.cxx | 171 |
1 files changed, 29 insertions, 142 deletions
diff --git a/src/ClientWrite.cxx b/src/ClientWrite.cxx index 1fe0e7bbd..86abc152c 100644 --- a/src/ClientWrite.cxx +++ b/src/ClientWrite.cxx @@ -25,20 +25,18 @@ #include <stdio.h> static size_t -client_write_deferred_buffer(Client *client, - const struct deferred_buffer *buffer) +client_write_direct(Client *client, const void *data, size_t length) { - GError *error = NULL; - GIOStatus status; - gsize bytes_written; - assert(client != NULL); assert(client->channel != NULL); - assert(buffer != NULL); + assert(data != NULL); + assert(length > 0); - status = g_io_channel_write_chars - (client->channel, buffer->data, buffer->size, - &bytes_written, &error); + gsize bytes_written; + GError *error = NULL; + GIOStatus status = + g_io_channel_write_chars(client->channel, (const gchar *)data, + length, &bytes_written, &error); switch (status) { case G_IO_STATUS_NORMAL: return bytes_written; @@ -56,186 +54,75 @@ client_write_deferred_buffer(Client *client, /* I/O error */ client->SetExpired(); - g_warning("failed to flush buffer for %i: %s", + g_warning("failed to write to %i: %s", client->num, error->message); g_error_free(error); return 0; } /* unreachable */ + assert(false); return 0; } void client_write_deferred(Client *client) { - size_t ret; + assert(!client_is_expired(client)); - while (!g_queue_is_empty(client->deferred_send)) { - struct deferred_buffer *buf = - (struct deferred_buffer *) - g_queue_peek_head(client->deferred_send); - - assert(buf->size > 0); - assert(buf->size <= client->deferred_bytes); - - ret = client_write_deferred_buffer(client, buf); - if (ret == 0) + while (true) { + size_t length; + const void *data = client->output_buffer.Read(&length); + if (data == nullptr) break; - if (ret < buf->size) { - assert(client->deferred_bytes >= (size_t)ret); - client->deferred_bytes -= ret; - buf->size -= ret; - memmove(buf->data, buf->data + ret, buf->size); - break; - } else { - size_t decr = sizeof(*buf) - - sizeof(buf->data) + buf->size; + size_t nbytes = client_write_direct(client, data, length); + if (nbytes == 0) + return; - assert(client->deferred_bytes >= decr); - client->deferred_bytes -= decr; - g_free(buf); - g_queue_pop_head(client->deferred_send); - } + client->output_buffer.Consume(nbytes); - g_timer_start(client->last_activity); - } + if (nbytes < length) + return; - if (g_queue_is_empty(client->deferred_send)) { - g_debug("[%u] buffer empty %lu", client->num, - (unsigned long)client->deferred_bytes); - assert(client->deferred_bytes == 0); + g_timer_start(client->last_activity); } } static void client_defer_output(Client *client, const void *data, size_t length) { - size_t alloc; - struct deferred_buffer *buf; - - assert(length > 0); - - alloc = sizeof(*buf) - sizeof(buf->data) + length; - client->deferred_bytes += alloc; - if (client->deferred_bytes > client_max_output_buffer_size) { - g_warning("[%u] output buffer size (%lu) is " + if (!client->output_buffer.Append(data, length)) { + g_warning("[%u] output buffer size is " "larger than the max (%lu)", client->num, - (unsigned long)client->deferred_bytes, (unsigned long)client_max_output_buffer_size); /* cause client to close */ client->SetExpired(); return; } - - buf = (struct deferred_buffer *)g_malloc(alloc); - buf->size = length; - memcpy(buf->data, data, length); - - g_queue_push_tail(client->deferred_send, buf); -} - -static void -client_write_direct(Client *client, const char *data, size_t length) -{ - GError *error = NULL; - GIOStatus status; - gsize bytes_written; - - assert(client != NULL); - assert(client->channel != NULL); - assert(data != NULL); - assert(length > 0); - assert(g_queue_is_empty(client->deferred_send)); - - status = g_io_channel_write_chars(client->channel, data, length, - &bytes_written, &error); - switch (status) { - case G_IO_STATUS_NORMAL: - case G_IO_STATUS_AGAIN: - break; - - case G_IO_STATUS_EOF: - /* client has disconnected */ - - client->SetExpired(); - return; - - case G_IO_STATUS_ERROR: - /* I/O error */ - - client->SetExpired(); - g_warning("failed to write to %i: %s", - client->num, error->message); - g_error_free(error); - return; - } - - if (bytes_written < length) - client_defer_output(client, data + bytes_written, - length - bytes_written); - - if (!g_queue_is_empty(client->deferred_send)) - g_debug("[%u] buffer created", client->num); } void client_write_output(Client *client) { - if (client->IsExpired() || !client->send_buf_used) + if (client->IsExpired()) return; - if (!g_queue_is_empty(client->deferred_send)) { - client_defer_output(client, client->send_buf, - client->send_buf_used); - - if (client->IsExpired()) - return; - - /* try to flush the deferred buffers now; the current - server command may take too long to finish, and - meanwhile try to feed output to the client, - otherwise it will time out. One reason why - deferring is slow might be that currently each - client_write() allocates a new deferred buffer. - This should be optimized after MPD 0.14. */ - client_write_deferred(client); - } else - client_write_direct(client, client->send_buf, - client->send_buf_used); - - client->send_buf_used = 0; + client_write_deferred(client); } /** * Write a block of data to the client. */ static void -client_write(Client *client, const char *buffer, size_t buflen) +client_write(Client *client, const char *data, size_t length) { /* if the client is going to be closed, do nothing */ - if (client->IsExpired()) + if (client->IsExpired() || length == 0) return; - while (buflen > 0 && !client->IsExpired()) { - size_t copylen; - - assert(client->send_buf_used < sizeof(client->send_buf)); - - copylen = sizeof(client->send_buf) - client->send_buf_used; - if (copylen > buflen) - copylen = buflen; - - memcpy(client->send_buf + client->send_buf_used, buffer, - copylen); - buflen -= copylen; - client->send_buf_used += copylen; - buffer += copylen; - if (client->send_buf_used >= sizeof(client->send_buf)) - client_write_output(client); - } + client_defer_output(client, data, length); } void |