2 (c) 2003-2017 The Music Player Daemon Project
3 This project's homepage is: http://www.musicpd.org
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
9 - Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
12 - Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
20 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include <mpd/socket.h>
40 #include <sys/types.h>
45 # include <basetsd.h> /* for SSIZE_T */
47 typedef SSIZE_T ssize_t
;
50 # include <sys/socket.h>
54 #define MSG_DONTWAIT 0
60 struct mpd_error_info error
;
62 struct mpd_buffer input
;
64 struct mpd_buffer output
;
70 struct mpd_async
*async
;
72 assert(fd
!= MPD_INVALID_SOCKET
);
74 async
= malloc(sizeof(*async
));
79 mpd_error_init(&async
->error
);
81 mpd_buffer_init(&async
->input
);
82 mpd_buffer_init(&async
->output
);
88 mpd_async_free(struct mpd_async
*async
)
90 assert(async
!= NULL
);
92 mpd_socket_close(async
->fd
);
93 mpd_error_deinit(&async
->error
);
98 mpd_async_get_error(const struct mpd_async
*async
)
100 assert(async
!= NULL
);
102 return async
->error
.code
;
106 mpd_async_get_error_message(const struct mpd_async
*async
)
108 assert(async
!= NULL
);
110 return mpd_error_get_message(&async
->error
);
114 mpd_async_get_system_error(const struct mpd_async
*async
)
116 assert(async
!= NULL
);
117 assert(async
->error
.code
== MPD_ERROR_SYSTEM
);
119 return async
->error
.system
;
123 mpd_async_copy_error(const struct mpd_async
*async
,
124 struct mpd_error_info
*dest
)
126 assert(async
!= NULL
);
128 return mpd_error_copy(dest
, &async
->error
);
132 mpd_async_get_fd(const struct mpd_async
*async
)
134 assert(async
!= NULL
);
135 assert(async
->fd
!= MPD_INVALID_SOCKET
);
141 mpd_async_set_keepalive(struct mpd_async
*async
,
144 assert(async
!= NULL
);
145 assert(async
->fd
!= MPD_INVALID_SOCKET
);
147 mpd_socket_keepalive(async
->fd
, keepalive
);
151 mpd_async_events(const struct mpd_async
*async
)
153 enum mpd_async_event events
;
155 assert(async
!= NULL
);
157 if (mpd_error_is_defined(&async
->error
))
160 /* always listen to hangups and errors */
161 events
= MPD_ASYNC_EVENT_HUP
| MPD_ASYNC_EVENT_ERROR
;
163 if (mpd_buffer_room(&async
->input
) > 0)
164 /* there's room left in the input buffer: attempt to
166 events
|= MPD_ASYNC_EVENT_READ
;
168 if (mpd_buffer_size(&async
->output
) > 0)
169 /* there's data in the output buffer: attempt to
171 events
|= MPD_ASYNC_EVENT_WRITE
;
177 mpd_async_read(struct mpd_async
*async
)
182 assert(async
!= NULL
);
183 assert(async
->fd
!= MPD_INVALID_SOCKET
);
184 assert(!mpd_error_is_defined(&async
->error
));
186 room
= mpd_buffer_room(&async
->input
);
190 nbytes
= recv(async
->fd
, mpd_buffer_write(&async
->input
), room
,
195 if (mpd_socket_ignore_errno(mpd_socket_errno()))
198 mpd_error_errno(&async
->error
);
203 mpd_error_code(&async
->error
, MPD_ERROR_CLOSED
);
204 mpd_error_message(&async
->error
,
205 "Connection closed by the server");
209 mpd_buffer_expand(&async
->input
, (size_t)nbytes
);
214 mpd_async_write(struct mpd_async
*async
)
219 assert(async
!= NULL
);
220 assert(async
->fd
!= MPD_INVALID_SOCKET
);
221 assert(!mpd_error_is_defined(&async
->error
));
223 size
= mpd_buffer_size(&async
->output
);
227 nbytes
= send(async
->fd
, mpd_buffer_read(&async
->output
), size
,
232 if (mpd_socket_ignore_errno(mpd_socket_errno()))
235 mpd_error_errno(&async
->error
);
239 mpd_buffer_consume(&async
->output
, (size_t)nbytes
);
244 mpd_async_io(struct mpd_async
*async
, enum mpd_async_event events
)
248 assert(async
!= NULL
);
250 if (mpd_error_is_defined(&async
->error
))
253 if ((events
& (MPD_ASYNC_EVENT_HUP
|MPD_ASYNC_EVENT_ERROR
)) != 0) {
254 mpd_error_code(&async
->error
, MPD_ERROR_CLOSED
);
255 mpd_error_message(&async
->error
, "Socket connection aborted");
259 if (events
& MPD_ASYNC_EVENT_READ
) {
260 success
= mpd_async_read(async
);
265 assert(!mpd_error_is_defined(&async
->error
));
267 if (events
& MPD_ASYNC_EVENT_WRITE
) {
268 success
= mpd_async_write(async
);
273 assert(!mpd_error_is_defined(&async
->error
));
279 mpd_async_send_command_v(struct mpd_async
*async
, const char *command
,
283 char *dest
, *end
, *p
;
286 assert(async
!= NULL
);
287 assert(command
!= NULL
);
289 if (mpd_error_is_defined(&async
->error
))
292 room
= mpd_buffer_room(&async
->output
);
293 length
= strlen(command
);
297 dest
= mpd_buffer_write(&async
->output
);
298 /* -1 because we reserve space for the \n character */
299 end
= dest
+ room
- 1;
301 /* copy the command (no quoting, we asumme it is "clean") */
303 memcpy(dest
, command
, length
);
306 /* now append all arguments (quoted) */
308 while ((arg
= va_arg(args
, const char *)) != NULL
) {
309 /* append a space separator */
316 /* quote the argument into the destination buffer */
318 p
= quote(p
, end
, arg
);
319 assert(p
== NULL
|| (p
>= dest
&& p
<= end
));
325 /* append the newline to finish this command */
329 mpd_buffer_expand(&async
->output
, p
- dest
);
334 mpd_async_send_command(struct mpd_async
*async
, const char *command
, ...)
339 assert(async
!= NULL
);
340 assert(command
!= NULL
);
342 va_start(args
, command
);
343 success
= mpd_async_send_command_v(async
, command
, args
);
350 mpd_async_recv_line(struct mpd_async
*async
)
355 assert(async
!= NULL
);
357 size
= mpd_buffer_size(&async
->input
);
361 src
= mpd_buffer_read(&async
->input
);
363 newline
= memchr(src
, '\n', size
);
364 if (newline
== NULL
) {
365 /* line is not finished yet */
366 if (mpd_buffer_full(&async
->input
)) {
367 /* .. but the buffer is full - line is too
368 long, abort connection and bail out */
369 mpd_error_code(&async
->error
, MPD_ERROR_MALFORMED
);
370 mpd_error_message(&async
->error
,
371 "Response line too large");
378 mpd_buffer_consume(&async
->input
, newline
+ 1 - src
);