Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

socket: new socket library

Move everything which directly accesses the socket or the input buffer
to socket.c / socket.h.
  • Loading branch information...
commit 640a3d7bdf10385c6b9c477e2de594b3f2d478d5 1 parent 307ff00
@MaxKellermann MaxKellermann authored
View
1  Makefile.am
@@ -33,6 +33,7 @@ src_libmpdclient_la_SOURCES = \
src/return_element.c \
src/entity.c \
src/idle.c \
+ src/socket.c src/socket.h \
src/song.c \
src/status.c \
src/stats.c \
View
2  include/mpd/connection.h
@@ -104,8 +104,6 @@ mpd_get_server_version(const struct mpd_connection *connection);
void mpd_getNextReturnElement(struct mpd_connection *connection);
-int mpd_recv(struct mpd_connection *connection);
-
void
mpd_executeCommand(struct mpd_connection *connection, const char *command);
View
301 src/connection.c
@@ -86,148 +86,19 @@ static int winsock_dll_error(struct mpd_connection *connection)
}
return 0;
}
-
-static int do_connect_fail(struct mpd_connection *connection,
- const struct sockaddr *serv_addr, int addrlen)
-{
- int iMode = 1; /* 0 = blocking, else non-blocking */
- if (connect(connection->sock, serv_addr, addrlen) == SOCKET_ERROR)
- return 1;
- ioctlsocket(connection->sock, FIONBIO, (u_long FAR*) &iMode);
- return 0;
-}
-#else /* !WIN32 (sane operating systems) */
-static int do_connect_fail(struct mpd_connection *connection,
- const struct sockaddr *serv_addr, int addrlen)
-{
- int flags;
- if (connect(connection->sock, serv_addr, addrlen) < 0)
- return 1;
- flags = fcntl(connection->sock, F_GETFL, 0);
- fcntl(connection->sock, F_SETFL, flags | O_NONBLOCK);
- return 0;
-}
#endif /* !WIN32 */
-/**
- * Wait for the socket to become readable.
- */
-static int mpd_wait(struct mpd_connection *connection)
-{
- struct timeval tv;
- fd_set fds;
- int ret;
-
- assert(connection->sock >= 0);
-
- while (1) {
- tv = connection->timeout;
- FD_ZERO(&fds);
- FD_SET(connection->sock, &fds);
-
- ret = select(connection->sock + 1, &fds, NULL, NULL, &tv);
- if (ret > 0)
- return 0;
-
- if (ret == 0 || !SELECT_ERRNO_IGNORE)
- return -1;
- }
-}
-
-/**
- * Wait until the socket is connected and check its result. Returns 1
- * on success, 0 on timeout, -errno on error.
- */
-static int mpd_wait_connected(struct mpd_connection *connection)
-{
- int ret;
- int s_err = 0;
- socklen_t s_err_size = sizeof(s_err);
-
- ret = mpd_wait(connection);
- if (ret < 0)
- return 0;
-
- ret = getsockopt(connection->sock, SOL_SOCKET, SO_ERROR,
- (char*)&s_err, &s_err_size);
- if (ret < 0)
- return -errno;
-
- if (s_err != 0)
- return -s_err;
-
- return 1;
-}
-
static int
mpd_connect(struct mpd_connection *connection, const char * host, int port)
{
- struct resolver *resolver;
- const struct resolver_address *address;
- int ret;
+ bool ret;
- resolver = resolver_new(host, port);
- if (resolver == NULL) {
- mpd_error_code(&connection->error, MPD_ERROR_UNKHOST);
- mpd_error_printf(&connection->error,
- "host \"%s\" not found", host);
+ ret = mpd_socket_connect(&connection->socket, host, port,
+ &connection->error);
+ if (!ret)
return -1;
- }
-
- while ((address = resolver_next(resolver)) != NULL) {
- connection->sock = socket(address->family, SOCK_STREAM,
- address->protocol);
- if (connection->sock < 0) {
- mpd_error_clear(&connection->error);
- mpd_error_code(&connection->error, MPD_ERROR_SYSTEM);
- mpd_error_printf(&connection->error,
- "problems creating socket: %s",
- strerror(errno));
- continue;
- }
-
- ret = do_connect_fail(connection,
- address->addr, address->addrlen);
- if (ret != 0) {
- mpd_error_clear(&connection->error);
- mpd_error_code(&connection->error, MPD_ERROR_CONNPORT);
- mpd_error_printf(&connection->error,
- "problems connecting to \"%s\" on port %i: %s",
- host, port, strerror(errno));
-
- closesocket(connection->sock);
- connection->sock = -1;
- continue;
- }
- ret = mpd_wait_connected(connection);
- if (ret > 0) {
- resolver_free(resolver);
- mpd_clearError(connection);
- return 0;
- }
-
- if (ret == 0) {
- mpd_error_clear(&connection->error);
- mpd_error_code(&connection->error,
- MPD_ERROR_NORESPONSE);
- mpd_error_printf(&connection->error,
- "timeout in attempting to get a response from \"%s\" on port %i",
- host, port);
- } else if (ret < 0) {
- mpd_error_clear(&connection->error);
- mpd_error_code(&connection->error, MPD_ERROR_CONNPORT);
- mpd_error_printf(&connection->error,
- "problems connecting to \"%s\" on port %i: %s",
- host, port, strerror(-ret));
- }
-
- closesocket(connection->sock);
- connection->sock = -1;
- }
-
- resolver_free(resolver);
- return -1;
+ return 0;
}
static int
@@ -269,12 +140,14 @@ struct mpd_connection *
mpd_newConnection(const char *host, int port, float timeout)
{
int err;
- char * rt;
+ const char *line;
struct mpd_connection *connection = malloc(sizeof(*connection));
+ const struct timeval tv = {
+ .tv_sec = (long)timeout,
+ .tv_usec = ((long)(timeout * 1e6)) % 1000000,
+ };
- connection->sock = -1;
- connection->buflen = 0;
- connection->bufstart = 0;
+ mpd_socket_init(&connection->socket, &tv);
mpd_error_init(&connection->error);
connection->doneProcessing = 0;
connection->commandList = 0;
@@ -299,19 +172,13 @@ mpd_newConnection(const char *host, int port, float timeout)
if (err < 0)
return connection;
- while (!(rt = memchr(connection->buffer, '\n', connection->buflen))) {
- err = mpd_recv(connection);
- if (err < 0)
- return connection;
- }
+ line = mpd_socket_recv_line(&connection->socket, &connection->error);
+ if (line == NULL)
+ return connection;
- *rt = '\0';
- if (mpd_parseWelcome(connection, host, port, connection->buffer) == 0)
+ if (mpd_parseWelcome(connection, host, port, line) == 0)
connection->doneProcessing = 1;
- connection->buflen -= rt + 1 - connection->buffer;
- memmove(connection->buffer, rt + 1, connection->buflen);
-
return connection;
}
@@ -349,7 +216,8 @@ void mpd_clearError(struct mpd_connection *connection)
void mpd_closeConnection(struct mpd_connection *connection)
{
- closesocket(connection->sock);
+ mpd_socket_deinit(&connection->socket);
+
if (connection->returnElement) free(connection->returnElement);
if (connection->request) free(connection->request);
@@ -362,10 +230,12 @@ void mpd_closeConnection(struct mpd_connection *connection)
void
mpd_setConnectionTimeout(struct mpd_connection *connection, float timeout)
{
- connection->timeout.tv_sec = (int)timeout;
- connection->timeout.tv_usec = (int)(timeout*1e6 -
- connection->timeout.tv_sec*1000000 +
- 0.5);
+ const struct timeval tv = {
+ .tv_sec = (long)timeout,
+ .tv_usec = ((long)(timeout * 1e6)) % 1000000,
+ };
+
+ mpd_socket_set_timeout(&connection->socket, &tv);
}
const int *
@@ -374,85 +244,12 @@ mpd_get_server_version(const struct mpd_connection *connection)
return connection->version;
}
-/**
- * Attempt to read data from the socket into the input buffer.
- * Returns 0 on success, -1 on error.
- */
-int mpd_recv(struct mpd_connection *connection)
-{
- int ret;
- ssize_t nbytes;
-
- assert(connection != NULL);
- assert(connection->buflen <= sizeof(connection->buffer));
- assert(connection->bufstart <= connection->buflen);
-
- if (connection->sock < 0) {
- mpd_error_code(&connection->error, MPD_ERROR_CONNCLOSED);
- mpd_error_message(&connection->error, "not connected");
- connection->doneProcessing = 1;
- connection->doneListOk = 0;
- return -1;
- }
-
- if (connection->buflen >= sizeof(connection->buffer)) {
- /* delete consumed data from beginning of buffer */
- connection->buflen -= connection->bufstart;
- memmove(connection->buffer,
- connection->buffer + connection->bufstart,
- connection->buflen);
- connection->bufstart = 0;
- }
-
- if (connection->buflen >= sizeof(connection->buffer)) {
- mpd_error_code(&connection->error, MPD_ERROR_BUFFEROVERRUN);
- mpd_error_message(&connection->error, "buffer overrun");
- connection->doneProcessing = 1;
- connection->doneListOk = 0;
- return -1;
- }
-
- while (1) {
- ret = mpd_wait(connection);
- if (ret < 0) {
- mpd_error_code(&connection->error, MPD_ERROR_TIMEOUT);
- mpd_error_message(&connection->error,
- "connection timeout");
- connection->doneProcessing = 1;
- connection->doneListOk = 0;
- return -1;
- }
-
- nbytes = read(connection->sock,
- connection->buffer + connection->buflen,
- sizeof(connection->buffer) - connection->buflen);
- if (nbytes > 0) {
- connection->buflen += nbytes;
- return 0;
- }
-
- if (nbytes == 0 || !SENDRECV_ERRNO_IGNORE) {
- mpd_error_code(&connection->error,
- MPD_ERROR_CONNCLOSED);
- mpd_error_message(&connection->error,
- "connection closed");
- connection->doneProcessing = 1;
- connection->doneListOk = 0;
- return -1;
- }
- }
-}
-
void
mpd_executeCommand(struct mpd_connection *connection, const char *command)
{
- int ret;
- struct timeval tv;
- fd_set fds;
- const char *commandPtr = command;
- int commandLen = strlen(command);
+ bool ret;
- if (connection->sock < 0) {
+ if (!mpd_socket_defined(&connection->socket)) {
mpd_error_code(&connection->error, MPD_ERROR_CONNCLOSED);
mpd_error_message(&connection->error, "connection closed");
return;
@@ -470,37 +267,10 @@ mpd_executeCommand(struct mpd_connection *connection, const char *command)
mpd_clearError(connection);
- FD_ZERO(&fds);
- FD_SET(connection->sock,&fds);
- tv.tv_sec = connection->timeout.tv_sec;
- tv.tv_usec = connection->timeout.tv_usec;
-
- while ((ret = select(connection->sock+1,NULL,&fds,NULL,&tv)==1) ||
- (ret==-1 && SELECT_ERRNO_IGNORE)) {
- ret = send(connection->sock,commandPtr,commandLen,MSG_DONTWAIT);
- if (ret<=0)
- {
- if (SENDRECV_ERRNO_IGNORE) continue;
- mpd_error_code(&connection->error, MPD_ERROR_SENDING);
- mpd_error_printf(&connection->error,
- "problems giving command \"%s\"",
- command);
- return;
- }
- else {
- commandPtr+=ret;
- commandLen-=ret;
- }
-
- if (commandLen<=0) break;
- }
-
- if (commandLen>0) {
- mpd_error_code(&connection->error, MPD_ERROR_TIMEOUT);
- mpd_error_printf(&connection->error,
- "timeout sending command \"%s\"", command);
+ ret = mpd_socket_send(&connection->socket, command, strlen(command),
+ &connection->error);
+ if (!ret)
return;
- }
if (!connection->commandList)
connection->doneProcessing = 0;
@@ -511,11 +281,9 @@ mpd_executeCommand(struct mpd_connection *connection, const char *command)
void mpd_getNextReturnElement(struct mpd_connection *connection)
{
char * output = NULL;
- char * rt = NULL;
char * name = NULL;
char * value = NULL;
char * tok = NULL;
- int err;
int pos;
if (connection->returnElement) mpd_freeReturnElement(connection->returnElement);
@@ -529,16 +297,9 @@ void mpd_getNextReturnElement(struct mpd_connection *connection)
return;
}
- while (!(rt = memchr(connection->buffer + connection->bufstart, '\n',
- connection->buflen - connection->bufstart))) {
- err = mpd_recv(connection);
- if (err < 0)
- return;
- }
-
- *rt = '\0';
- output = connection->buffer+connection->bufstart;
- connection->bufstart = rt - connection->buffer + 1;
+ output = mpd_socket_recv_line(&connection->socket, &connection->error);
+ if (output == NULL)
+ return;
if (strcmp(output, "OK")==0) {
if (connection->listOks > 0) {
View
9 src/internal.h
@@ -31,6 +31,7 @@
#include "ierror.h"
#include <mpd/connection.h>
+#include "socket.h"
/* mpd_Connection
* holds info about connection to mpd
@@ -43,16 +44,14 @@ struct mpd_connection {
struct mpd_error_info error;
/* DON'T TOUCH any of the rest of this stuff */
- int sock;
- char buffer[16384];
- size_t buflen;
- size_t bufstart;
+
+ struct mpd_socket socket;
+
int doneProcessing;
int listOks;
int doneListOk;
int commandList;
struct mpd_return_element *returnElement;
- struct timeval timeout;
char *request;
int idle;
void (*notify_cb)(struct mpd_connection *connection,
View
348 src/socket.c
@@ -0,0 +1,348 @@
+/* libmpdclient
+ (c) 2003-2008 The Music Player Daemon Project
+ This project's homepage is: http://www.musicpd.org
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "socket.h"
+#include "resolver.h"
+#include "ierror.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#ifdef WIN32
+# include <ws2tcpip.h>
+# include <winsock.h>
+#else
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# include <sys/socket.h>
+# include <netdb.h>
+# include <sys/un.h>
+#endif
+
+#ifndef MSG_DONTWAIT
+# define MSG_DONTWAIT 0
+#endif
+
+#ifdef WIN32
+# define SELECT_ERRNO_IGNORE (errno == WSAEINTR || errno == WSAEINPROGRESS)
+# define SENDRECV_ERRNO_IGNORE SELECT_ERRNO_IGNORE
+#else
+# define SELECT_ERRNO_IGNORE (errno == EINTR)
+# define SENDRECV_ERRNO_IGNORE (errno == EINTR || errno == EAGAIN)
+# define winsock_dll_error(c) 0
+# define closesocket(s) close(s)
+# define WSACleanup() do { /* nothing */ } while (0)
+#endif
+
+void
+mpd_socket_deinit(struct mpd_socket *s)
+{
+ if (s->fd >= 0)
+ closesocket(s->fd);
+}
+
+#ifdef WIN32
+
+static int do_connect_fail(struct mpd_socket *s,
+ const struct sockaddr *serv_addr, int addrlen)
+{
+ int iMode = 1; /* 0 = blocking, else non-blocking */
+ if (connect(s->fd, serv_addr, addrlen) == SOCKET_ERROR)
+ return 1;
+ ioctlsocket(s->fd, FIONBIO, (u_long FAR*) &iMode);
+ return 0;
+}
+
+#else /* !WIN32 (sane operating systems) */
+
+static int do_connect_fail(struct mpd_socket *s,
+ const struct sockaddr *serv_addr, int addrlen)
+{
+ int flags;
+ if (connect(s->fd, serv_addr, addrlen) < 0)
+ return 1;
+ flags = fcntl(s->fd, F_GETFL, 0);
+ fcntl(s->fd, F_SETFL, flags | O_NONBLOCK);
+ return 0;
+}
+
+#endif /* !WIN32 */
+
+/**
+ * Wait for the socket to become readable.
+ */
+static int
+mpd_socket_wait(struct mpd_socket *s)
+{
+ struct timeval tv;
+ fd_set fds;
+ int ret;
+
+ assert(s->fd >= 0);
+
+ while (1) {
+ tv = s->timeout;
+ FD_ZERO(&fds);
+ FD_SET(s->fd, &fds);
+
+ ret = select(s->fd + 1, &fds, NULL, NULL, &tv);
+ if (ret > 0)
+ return 0;
+
+ if (ret == 0 || !SELECT_ERRNO_IGNORE)
+ return -1;
+ }
+}
+
+/**
+ * Wait until the socket is connected and check its result. Returns 1
+ * on success, 0 on timeout, -errno on error.
+ */
+static int
+mpd_socket_wait_connected(struct mpd_socket *s)
+{
+ int ret;
+ int s_err = 0;
+ socklen_t s_err_size = sizeof(s_err);
+
+ ret = mpd_socket_wait(s);
+ if (ret < 0)
+ return 0;
+
+ ret = getsockopt(s->fd, SOL_SOCKET, SO_ERROR,
+ (char*)&s_err, &s_err_size);
+ if (ret < 0)
+ return -errno;
+
+ if (s_err != 0)
+ return -s_err;
+
+ return 1;
+}
+
+bool
+mpd_socket_connect(struct mpd_socket *s, const char *host, int port,
+ struct mpd_error_info *error)
+{
+ struct resolver *resolver;
+ const struct resolver_address *address;
+ int ret;
+
+ resolver = resolver_new(host, port);
+ if (resolver == NULL) {
+ mpd_error_code(error, MPD_ERROR_UNKHOST);
+ mpd_error_printf(error, "host \"%s\" not found", host);
+ return false;
+ }
+
+ while ((address = resolver_next(resolver)) != NULL) {
+ s->fd = socket(address->family, SOCK_STREAM,
+ address->protocol);
+ if (!mpd_socket_defined(s)) {
+ mpd_error_code(error, MPD_ERROR_SYSTEM);
+ mpd_error_printf(error,
+ "problems creating socket: %s",
+ strerror(errno));
+ continue;
+ }
+
+ ret = do_connect_fail(s, address->addr, address->addrlen);
+ if (ret != 0) {
+ mpd_error_code(error, MPD_ERROR_CONNPORT);
+ mpd_error_printf(error,
+ "problems connecting to \"%s\" on port %i: %s",
+ host, port, strerror(errno));
+
+ closesocket(s->fd);
+ s->fd = -1;
+ continue;
+ }
+
+ ret = mpd_socket_wait_connected(s);
+ if (ret > 0) {
+ resolver_free(resolver);
+ mpd_error_clear(error);
+ return true;
+ }
+
+ if (ret == 0) {
+ mpd_error_code(error, MPD_ERROR_NORESPONSE);
+ mpd_error_printf(error,
+ "timeout in attempting to get a response from \"%s\" on port %i",
+ host, port);
+ } else if (ret < 0) {
+ mpd_error_code(error, MPD_ERROR_CONNPORT);
+ mpd_error_printf(error,
+ "problems connecting to \"%s\" on port %i: %s",
+ host, port, strerror(-ret));
+ }
+
+ closesocket(s->fd);
+ s->fd = -1;
+ }
+
+ resolver_free(resolver);
+ return false;
+}
+
+static inline bool
+mpd_socket_buffer_full(const struct mpd_socket *s)
+{
+ assert(s->buflen <= sizeof(s->buffer));
+
+ return s->buflen == sizeof(s->buffer);
+}
+
+/**
+ * Attempt to read data from the socket into the input buffer.
+ *
+ * @return true if data was received, false on error or timeout
+ */
+static bool
+mpd_socket_recv(struct mpd_socket *s, struct mpd_error_info *error)
+{
+ int ret;
+ ssize_t nbytes;
+
+ assert(s != NULL);
+ assert(s->buflen <= sizeof(s->buffer));
+ assert(s->bufstart <= s->buflen);
+
+ if (!mpd_socket_defined(s)) {
+ mpd_error_code(error, MPD_ERROR_CONNCLOSED);
+ mpd_error_message(error, "not connected");
+ return false;
+ }
+
+ if (mpd_socket_buffer_full(s)) {
+ /* delete consumed data from beginning of buffer */
+ s->buflen -= s->bufstart;
+ memmove(s->buffer, s->buffer + s->bufstart, s->buflen);
+ s->bufstart = 0;
+ }
+
+ if (s->buflen >= sizeof(s->buffer)) {
+ mpd_error_code(error, MPD_ERROR_BUFFEROVERRUN);
+ mpd_error_message(error, "buffer overrun");
+ return false;
+ }
+
+ while (1) {
+ ret = mpd_socket_wait(s);
+ if (ret < 0) {
+ mpd_error_code(error, MPD_ERROR_TIMEOUT);
+ mpd_error_message(error, "connection timeout");
+ return false;
+ }
+
+ nbytes = read(s->fd, s->buffer + s->buflen,
+ sizeof(s->buffer) - s->buflen);
+ if (nbytes > 0) {
+ s->buflen += nbytes;
+ return true;
+ }
+
+ if (nbytes == 0 || !SENDRECV_ERRNO_IGNORE) {
+ mpd_error_code(error, MPD_ERROR_CONNCLOSED);
+ mpd_error_message(error, "connection closed");
+ return false;
+ }
+ }
+}
+
+char *
+mpd_socket_recv_line(struct mpd_socket *s, struct mpd_error_info *error)
+{
+ char *newline;
+ bool ret;
+
+ assert(!mpd_error_is_defined(error));
+
+ while (true) {
+ char *start = s->buffer + s->bufstart;
+
+ newline = memchr(start, '\n', s->buflen - s->bufstart);
+ if (newline != NULL) {
+ *newline++ = 0;
+ s->bufstart = newline - s->buffer;
+ return start;
+ }
+
+ ret = mpd_socket_recv(s, error);
+ if (!ret)
+ return NULL;
+ }
+}
+
+bool
+mpd_socket_send(struct mpd_socket *s, const void *data0, size_t length,
+ struct mpd_error_info *error)
+{
+ const unsigned char *data = data0;
+ struct timeval tv = s->timeout;
+ ssize_t nbytes;
+
+ while (length > 0) {
+ nbytes = send(s->fd, data, length, MSG_DONTWAIT);
+ if (nbytes > 0) {
+ data += nbytes;
+ length -= nbytes;
+ } else if (SENDRECV_ERRNO_IGNORE) {
+ fd_set fds;
+ int ret;
+
+ FD_ZERO(&fds);
+ FD_SET(s->fd, &fds);
+
+ ret = select(s->fd + 1, NULL, &fds, NULL, &tv);
+ if (ret == 0) {
+ mpd_error_code(error, MPD_ERROR_TIMEOUT);
+ mpd_error_message(error,
+ "timeout while sending to MPD");
+ return false;
+ } else if (ret < 0 && !SELECT_ERRNO_IGNORE) {
+ mpd_error_code(error, MPD_ERROR_SYSTEM);
+ mpd_error_printf(error, "select() failed: %s",
+ strerror(errno));
+ return false;
+ }
+ } else {
+ mpd_error_code(error, MPD_ERROR_SENDING);
+ mpd_error_printf(error,
+ "Sending to MPD failed: %s",
+ strerror(errno));
+ return false;
+ }
+ }
+
+ return true;
+}
View
121 src/socket.h
@@ -0,0 +1,121 @@
+/* libmpdclient
+ (c) 2003-2008 The Music Player Daemon Project
+ This project's homepage is: http://www.musicpd.org
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MPD_SOCKET_H
+#define MPD_SOCKET_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <sys/select.h>
+
+struct mpd_error_info;
+
+/**
+ * A socket connection between the client (that's us) and the MPD
+ * server.
+ */
+struct mpd_socket {
+ /** the socket file descriptor */
+ int fd;
+
+ char buffer[16384];
+ size_t buflen;
+ size_t bufstart;
+
+ struct timeval timeout;
+};
+
+/**
+ * Checks whether the socket object is defined, i.e. the OS level
+ * socket was created, but it may not be connected yet.
+ */
+static inline bool
+mpd_socket_defined(const struct mpd_socket *s)
+{
+ return s->fd >= 0;
+}
+
+/**
+ * Modifies the timeout for sending and receiving.
+ */
+static inline void
+mpd_socket_set_timeout(struct mpd_socket *s, const struct timeval *timeout)
+{
+ s->timeout = *timeout;
+}
+
+/**
+ * Initialize a socket object. This does not create the OS level
+ * socket, and does not attempt to connect it.
+ */
+static inline void
+mpd_socket_init(struct mpd_socket *s, const struct timeval *timeout)
+{
+ s->fd = -1;
+ s->buflen = 0;
+ s->bufstart = 0;
+ mpd_socket_set_timeout(s, timeout);
+}
+
+/**
+ * Free all resources of the socket object.
+ */
+void
+mpd_socket_deinit(struct mpd_socket *s);
+
+/**
+ * Connects the socket to the specified host and port.
+ *
+ * @return false if an error occured
+ */
+bool
+mpd_socket_connect(struct mpd_socket *s, const char *host, int port,
+ struct mpd_error_info *error);
+
+/**
+ * Attempt to read one line from the socket into the input buffer.
+ * This function returns a writable string pointer, because callers
+ * may find it useful to modify the buffer during parsing.
+ *
+ * @return a pointer to the beginning of the line; NULL on error or
+ * timeout
+ */
+char *
+mpd_socket_recv_line(struct mpd_socket *s, struct mpd_error_info *error);
+
+/**
+ * Attempt to send data.
+ *
+ * @return true if everything was sent; false on error or timeout;
+ * partial write plus timeout is regarded as an error
+ */
+bool
+mpd_socket_send(struct mpd_socket *s, const void *data, size_t length,
+ struct mpd_error_info *error);
+
+#endif
Please sign in to comment.
Something went wrong with that request. Please try again.