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.
21 #include "client_internal.h"
28 client_write_deferred_buffer(struct client
*client
,
29 const struct deferred_buffer
*buffer
)
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
);
43 case G_IO_STATUS_NORMAL
:
46 case G_IO_STATUS_AGAIN
:
50 /* client has disconnected */
52 client_set_expired(client
);
55 case G_IO_STATUS_ERROR
:
58 client_set_expired(client
);
59 g_warning("failed to flush buffer for %i: %s",
60 client
->num
, error
->message
);
70 client_write_deferred(struct client
*client
)
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
);
85 if (ret
< buf
->size
) {
86 assert(client
->deferred_bytes
>= (size_t)ret
);
87 client
->deferred_bytes
-= ret
;
89 memmove(buf
->data
, buf
->data
+ ret
, buf
->size
);
92 size_t decr
= sizeof(*buf
) -
93 sizeof(buf
->data
) + buf
->size
;
95 assert(client
->deferred_bytes
>= decr
);
96 client
->deferred_bytes
-= decr
;
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
)
115 struct deferred_buffer
*buf
;
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)",
125 (unsigned long)client
->deferred_bytes
,
126 (unsigned long)client_max_output_buffer_size
);
127 /* cause client to close */
128 client_set_expired(client
);
132 buf
= g_malloc(alloc
);
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
;
146 assert(client
!= NULL
);
147 assert(client
->channel
!= NULL
);
148 assert(data
!= NULL
);
150 assert(g_queue_is_empty(client
->deferred_send
));
152 status
= g_io_channel_write_chars(client
->channel
, data
, length
,
153 &bytes_written
, &error
);
155 case G_IO_STATUS_NORMAL
:
156 case G_IO_STATUS_AGAIN
:
159 case G_IO_STATUS_EOF
:
160 /* client has disconnected */
162 client_set_expired(client
);
165 case G_IO_STATUS_ERROR
:
168 client_set_expired(client
);
169 g_warning("failed to write to %i: %s",
170 client
->num
, error
->message
);
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
);
184 client_write_output(struct client
*client
)
186 if (client_is_expired(client
) || !client
->send_buf_used
)
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
))
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
);
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
))
220 while (buflen
> 0 && !client_is_expired(client
)) {
223 assert(client
->send_buf_used
< sizeof(client
->send_buf
));
225 copylen
= sizeof(client
->send_buf
) - client
->send_buf_used
;
226 if (copylen
> buflen
)
229 memcpy(client
->send_buf
+ client
->send_buf_used
, buffer
,
232 client
->send_buf_used
+= 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
)
251 length
= vsnprintf(NULL
, 0, fmt
, tmp
);
258 buffer
= g_malloc(length
+ 1);
259 vsnprintf(buffer
, length
+ 1, fmt
, args
);
260 client_write(client
, buffer
, length
);
264 G_GNUC_PRINTF(2, 3) void client_printf(struct client
*client
, const char *fmt
, ...)
269 client_vprintf(client
, fmt
, args
);