summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 44c3a54)
raw | patch | inline | side by side (parent: 44c3a54)
author | Max Kellermann <max@duempel.org> | |
Wed, 17 Sep 2008 23:10:40 +0000 (01:10 +0200) | ||
committer | Max Kellermann <max@duempel.org> | |
Wed, 17 Sep 2008 23:10:40 +0000 (01:10 +0200) |
Create generic utility functions for doint I/O: two wait functions,
and mpd_recv() fills the input buffer. These functions are used in
mpd_newConnection() and mpd_getNextReturnElement().
and mpd_recv() fills the input buffer. These functions are used in
mpd_newConnection() and mpd_getNextReturnElement().
src/libmpdclient.c | patch | blob | history |
diff --git a/src/libmpdclient.c b/src/libmpdclient.c
index 1b0851ff125c08b4d8d86dc9806b5af676a6345d..b2c907b49e6d078a3504bf3234bf1036030aa4be 100644 (file)
--- a/src/libmpdclient.c
+++ b/src/libmpdclient.c
#include "libmpdclient.h"
#include "str_pool.h"
+#include <assert.h>
#include <errno.h>
#include <sys/types.h>
#include <stdio.h>
}
#endif /* WIN32 */
+/**
+ * Wait for the socket to become readable.
+ */
+static int mpd_wait(mpd_Connection *connection)
+{
+ struct timeval tv;
+ fd_set fds;
+ int ret;
+
+ 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(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;
+}
+
+/**
+ * Attempt to read data from the socket into the input buffer.
+ * Returns 0 on success, -1 on error.
+ */
+static int mpd_recv(mpd_Connection *connection)
+{
+ int ret;
+ ssize_t nbytes;
+
+ assert(connection != NULL);
+ assert(connection->buflen <= sizeof(connection->buffer));
+ assert(connection->bufstart <= connection->buflen);
+
+ 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)) {
+ strcpy(connection->errorStr, "buffer overrun");
+ connection->error = MPD_ERROR_BUFFEROVERRUN;
+ connection->doneProcessing = 1;
+ connection->doneListOk = 0;
+ return -1;
+ }
+
+ while (1) {
+ ret = mpd_wait(connection);
+ if (ret < 0) {
+ strcpy(connection->errorStr, "connection timeout");
+ connection->error = MPD_ERROR_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) {
+ strcpy(connection->errorStr, "connection closed");
+ connection->error = MPD_ERROR_CONNCLOSED;
+ connection->doneProcessing = 1;
+ connection->doneListOk = 0;
+ return -1;
+ }
+ }
+}
+
mpd_Connection * mpd_newConnection(const char * host, int port, float timeout) {
int err;
char * rt;
mpd_Connection * connection = malloc(sizeof(mpd_Connection));
- struct timeval tv;
- fd_set fds;
connection->buflen = 0;
connection->bufstart = 0;
@@ -408,43 +513,26 @@ mpd_Connection * mpd_newConnection(const char * host, int port, float timeout) {
if (err < 0)
return connection;
+ err = mpd_wait_connected(connection);
+ if (err == 0) {
+ snprintf(connection->errorStr, sizeof(connection->errorStr),
+ "timeout in attempting to get a response from"
+ " \"%s\" on port %i",host,port);
+ connection->error = MPD_ERROR_NORESPONSE;
+ return connection;
+ } else if (err < 0) {
+ snprintf(connection->errorStr,
+ sizeof(connection->errorStr),
+ "problems connecting to \"%s\" on port %i: %s",
+ host, port, strerror(-err));
+ connection->error = MPD_ERROR_CONNPORT;
+ return connection;
+ }
+
while(!(rt = memchr(connection->buffer, '\n', connection->buflen))) {
- tv.tv_sec = connection->timeout.tv_sec;
- tv.tv_usec = connection->timeout.tv_usec;
- FD_ZERO(&fds);
- FD_SET(connection->sock,&fds);
- if((err = select(connection->sock+1,&fds,NULL,NULL,&tv)) == 1) {
- ssize_t readed;
- readed = recv(connection->sock,
- &(connection->buffer[connection->buflen]),
- sizeof(connection->buffer) - connection->buflen, 0);
- if(readed<=0) {
- snprintf(connection->errorStr, sizeof(connection->errorStr),
- "problems getting a response from"
- " \"%s\" on port %i : %s",host,
- port, strerror(errno));
- connection->error = MPD_ERROR_NORESPONSE;
- return connection;
- }
- connection->buflen+=readed;
- }
- else if(err<0) {
- if (SELECT_ERRNO_IGNORE)
- continue;
- snprintf(connection->errorStr,
- sizeof(connection->errorStr),
- "problems connecting to \"%s\" on port"
- " %i",host,port);
- connection->error = MPD_ERROR_CONNPORT;
+ err = mpd_recv(connection);
+ if (err < 0)
return connection;
- }
- else {
- snprintf(connection->errorStr, sizeof(connection->errorStr),
- "timeout in attempting to get a response from"
- " \"%s\" on port %i",host,port);
- connection->error = MPD_ERROR_NORESPONSE;
- return connection;
- }
}
*rt = '\0';
char * rt = NULL;
char * name = NULL;
char * value = NULL;
- fd_set fds;
- struct timeval tv;
char * tok = NULL;
- ssize_t readed;
- char * bufferCheck = NULL;
int err;
int pos;
return;
}
- bufferCheck = connection->buffer+connection->bufstart;
- while (connection->bufstart >= connection->buflen ||
- !(rt = memchr(bufferCheck, '\n',
- connection->buffer + connection->buflen -
- bufferCheck))) {
- if (connection->buflen >= sizeof(connection->buffer)) {
- memmove(connection->buffer,
- connection->buffer + connection->bufstart,
- connection->buflen - connection->bufstart);
- connection->buflen -= connection->bufstart;
- connection->bufstart = 0;
- }
- if (connection->buflen >= sizeof(connection->buffer)) {
- strcpy(connection->errorStr,"buffer overrun");
- connection->error = MPD_ERROR_BUFFEROVERRUN;
- connection->doneProcessing = 1;
- connection->doneListOk = 0;
+ while (!(rt = memchr(connection->buffer + connection->bufstart, '\n',
+ connection->buflen - connection->bufstart))) {
+ err = mpd_recv(connection);
+ if (err < 0)
return;
- }
- bufferCheck = connection->buffer+connection->buflen;
- tv.tv_sec = connection->timeout.tv_sec;
- tv.tv_usec = connection->timeout.tv_usec;
- FD_ZERO(&fds);
- FD_SET(connection->sock,&fds);
- if((err = select(connection->sock+1,&fds,NULL,NULL,&tv) == 1)) {
- readed = recv(connection->sock,
- connection->buffer+connection->buflen,
- sizeof(connection->buffer) - connection->buflen,
- MSG_DONTWAIT);
- if(readed<0 && SENDRECV_ERRNO_IGNORE) {
- continue;
- }
- if(readed<=0) {
- strcpy(connection->errorStr,"connection"
- " closed");
- connection->error = MPD_ERROR_CONNCLOSED;
- connection->doneProcessing = 1;
- connection->doneListOk = 0;
- return;
- }
- connection->buflen+=readed;
- }
- else if(err<0 && SELECT_ERRNO_IGNORE) continue;
- else {
- strcpy(connection->errorStr,"connection timeout");
- connection->error = MPD_ERROR_TIMEOUT;
- connection->doneProcessing = 1;
- connection->doneListOk = 0;
- return;
- }
}
*rt = '\0';