configure.ac: Move OggVorbis Encoder to Encoder Plugins.
[mpd-mk.git] / src / client_write.c
blobe0974150b0e35c6b1caaa9f105465593966c6e7d
1 /*
2 * Copyright (C) 2003-2010 The Music Player Daemon Project
3 * http://www.musicpd.org
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "config.h"
21 #include "client_internal.h"
23 #include <assert.h>
24 #include <string.h>
25 #include <stdio.h>
27 static size_t
28 client_write_deferred_buffer(struct client *client,
29 const struct deferred_buffer *buffer)
31 GError *error = NULL;
32 GIOStatus status;
33 gsize bytes_written;
35 assert(client != NULL);
36 assert(client->channel != NULL);
37 assert(buffer != NULL);
39 status = g_io_channel_write_chars
40 (client->channel, buffer->data, buffer->size,
41 &bytes_written, &error);
42 switch (status) {
43 case G_IO_STATUS_NORMAL:
44 return bytes_written;
46 case G_IO_STATUS_AGAIN:
47 return 0;
49 case G_IO_STATUS_EOF:
50 /* client has disconnected */
52 client_set_expired(client);
53 return 0;
55 case G_IO_STATUS_ERROR:
56 /* I/O error */
58 client_set_expired(client);
59 g_warning("failed to flush buffer for %i: %s",
60 client->num, error->message);
61 g_error_free(error);
62 return 0;
65 /* unreachable */
66 return 0;
69 void
70 client_write_deferred(struct client *client)
72 size_t ret;
74 while (!g_queue_is_empty(client->deferred_send)) {
75 struct deferred_buffer *buf =
76 g_queue_peek_head(client->deferred_send);
78 assert(buf->size > 0);
79 assert(buf->size <= client->deferred_bytes);
81 ret = client_write_deferred_buffer(client, buf);
82 if (ret == 0)
83 break;
85 if (ret < buf->size) {
86 assert(client->deferred_bytes >= (size_t)ret);
87 client->deferred_bytes -= ret;
88 buf->size -= ret;
89 memmove(buf->data, buf->data + ret, buf->size);
90 break;
91 } else {
92 size_t decr = sizeof(*buf) -
93 sizeof(buf->data) + buf->size;
95 assert(client->deferred_bytes >= decr);
96 client->deferred_bytes -= decr;
97 g_free(buf);
98 g_queue_pop_head(client->deferred_send);
101 g_timer_start(client->last_activity);
104 if (g_queue_is_empty(client->deferred_send)) {
105 g_debug("[%u] buffer empty %lu", client->num,
106 (unsigned long)client->deferred_bytes);
107 assert(client->deferred_bytes == 0);
111 static void client_defer_output(struct client *client,
112 const void *data, size_t length)
114 size_t alloc;
115 struct deferred_buffer *buf;
117 assert(length > 0);
119 alloc = sizeof(*buf) - sizeof(buf->data) + length;
120 client->deferred_bytes += alloc;
121 if (client->deferred_bytes > client_max_output_buffer_size) {
122 g_warning("[%u] output buffer size (%lu) is "
123 "larger than the max (%lu)",
124 client->num,
125 (unsigned long)client->deferred_bytes,
126 (unsigned long)client_max_output_buffer_size);
127 /* cause client to close */
128 client_set_expired(client);
129 return;
132 buf = g_malloc(alloc);
133 buf->size = length;
134 memcpy(buf->data, data, length);
136 g_queue_push_tail(client->deferred_send, buf);
139 static void client_write_direct(struct client *client,
140 const char *data, size_t length)
142 GError *error = NULL;
143 GIOStatus status;
144 gsize bytes_written;
146 assert(client != NULL);
147 assert(client->channel != NULL);
148 assert(data != NULL);
149 assert(length > 0);
150 assert(g_queue_is_empty(client->deferred_send));
152 status = g_io_channel_write_chars(client->channel, data, length,
153 &bytes_written, &error);
154 switch (status) {
155 case G_IO_STATUS_NORMAL:
156 case G_IO_STATUS_AGAIN:
157 break;
159 case G_IO_STATUS_EOF:
160 /* client has disconnected */
162 client_set_expired(client);
163 return;
165 case G_IO_STATUS_ERROR:
166 /* I/O error */
168 client_set_expired(client);
169 g_warning("failed to write to %i: %s",
170 client->num, error->message);
171 g_error_free(error);
172 return;
175 if (bytes_written < length)
176 client_defer_output(client, data + bytes_written,
177 length - bytes_written);
179 if (!g_queue_is_empty(client->deferred_send))
180 g_debug("[%u] buffer created", client->num);
183 void
184 client_write_output(struct client *client)
186 if (client_is_expired(client) || !client->send_buf_used)
187 return;
189 if (!g_queue_is_empty(client->deferred_send)) {
190 client_defer_output(client, client->send_buf,
191 client->send_buf_used);
193 if (client_is_expired(client))
194 return;
196 /* try to flush the deferred buffers now; the current
197 server command may take too long to finish, and
198 meanwhile try to feed output to the client,
199 otherwise it will time out. One reason why
200 deferring is slow might be that currently each
201 client_write() allocates a new deferred buffer.
202 This should be optimized after MPD 0.14. */
203 client_write_deferred(client);
204 } else
205 client_write_direct(client, client->send_buf,
206 client->send_buf_used);
208 client->send_buf_used = 0;
212 * Write a block of data to the client.
214 static void client_write(struct client *client, const char *buffer, size_t buflen)
216 /* if the client is going to be closed, do nothing */
217 if (client_is_expired(client))
218 return;
220 while (buflen > 0 && !client_is_expired(client)) {
221 size_t copylen;
223 assert(client->send_buf_used < sizeof(client->send_buf));
225 copylen = sizeof(client->send_buf) - client->send_buf_used;
226 if (copylen > buflen)
227 copylen = buflen;
229 memcpy(client->send_buf + client->send_buf_used, buffer,
230 copylen);
231 buflen -= copylen;
232 client->send_buf_used += copylen;
233 buffer += copylen;
234 if (client->send_buf_used >= sizeof(client->send_buf))
235 client_write_output(client);
239 void client_puts(struct client *client, const char *s)
241 client_write(client, s, strlen(s));
244 void client_vprintf(struct client *client, const char *fmt, va_list args)
246 va_list tmp;
247 int length;
248 char *buffer;
250 va_copy(tmp, args);
251 length = vsnprintf(NULL, 0, fmt, tmp);
252 va_end(tmp);
254 if (length <= 0)
255 /* wtf.. */
256 return;
258 buffer = g_malloc(length + 1);
259 vsnprintf(buffer, length + 1, fmt, args);
260 client_write(client, buffer, length);
261 g_free(buffer);
264 G_GNUC_PRINTF(2, 3) void client_printf(struct client *client, const char *fmt, ...)
266 va_list args;
268 va_start(args, fmt);
269 client_vprintf(client, fmt, args);
270 va_end(args);