Skip to content

Commit

Permalink
added resolver library
Browse files Browse the repository at this point in the history
The resolver library provides unified access to all resolvers
(getaddrinfo(), gethostbyname(), Unix domain sockets).  Like
getaddrinfo(), it can return more than one address for a host name.
  • Loading branch information
MaxKellermann committed Nov 26, 2008
1 parent d3a18cc commit f94949d
Show file tree
Hide file tree
Showing 4 changed files with 318 additions and 209 deletions.
1 change: 1 addition & 0 deletions Makefile.am
Expand Up @@ -7,6 +7,7 @@ lib_LTLIBRARIES = src/libmpdclient.la

src_libmpdclient_la_SOURCES = \
src/str_pool.c src/str_pool.h \
src/resolver.c src/resolver.h \
src/song.c src/song.h \
src/libmpdclient.c src/libmpdclient.h

Expand Down
283 changes: 74 additions & 209 deletions src/libmpdclient.c
Expand Up @@ -31,6 +31,7 @@
*/

#include "libmpdclient.h"
#include "resolver.h"
#include "str_pool.h"

#include <assert.h>
Expand Down Expand Up @@ -63,12 +64,6 @@
#define COMMAND_LIST 1
#define COMMAND_LIST_OK 2

#ifndef MPD_NO_GAI
# ifdef AI_ADDRCONFIG
# define MPD_HAVE_GAI
# endif
#endif

#ifndef MSG_DONTWAIT
# define MSG_DONTWAIT 0
#endif
Expand Down Expand Up @@ -132,140 +127,6 @@ static int do_connect_fail(mpd_Connection *connection,
}
#endif /* !WIN32 */

#ifdef MPD_HAVE_GAI
static int mpd_connect(mpd_Connection * connection, const char * host, int port,
float timeout)
{
int error;
char service[INTLEN+1];
struct addrinfo hints;
struct addrinfo *res = NULL;
struct addrinfo *addrinfo = NULL;

/**
* Setup hints
*/
hints.ai_flags = AI_ADDRCONFIG;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_addrlen = 0;
hints.ai_addr = NULL;
hints.ai_canonname = NULL;
hints.ai_next = NULL;

snprintf(service, sizeof(service), "%i", port);

error = getaddrinfo(host, service, &hints, &addrinfo);

if (error) {
snprintf(connection->errorStr, sizeof(connection->errorStr),
"host \"%s\" not found: %s",
host, gai_strerror(error));
connection->error = MPD_ERROR_UNKHOST;
return -1;
}

for (res = addrinfo; res; res = res->ai_next) {
/* create socket */
if (connection->sock >= 0)
closesocket(connection->sock);
connection->sock = socket(res->ai_family, SOCK_STREAM,
res->ai_protocol);
if (connection->sock < 0) {
snprintf(connection->errorStr, sizeof(connection->errorStr),
"problems creating socket: %s",
strerror(errno));
connection->error = MPD_ERROR_SYSTEM;
freeaddrinfo(addrinfo);
return -1;
}

mpd_setConnectionTimeout(connection, timeout);

/* connect stuff */
if (do_connect_fail(connection,
res->ai_addr, res->ai_addrlen)) {
/* try the next address */
closesocket(connection->sock);
connection->sock = -1;
continue;
}

break;
}

freeaddrinfo(addrinfo);

if (connection->sock < 0) {
snprintf(connection->errorStr, sizeof(connection->errorStr),
"problems connecting to \"%s\" on port"
" %i: %s", host, port, strerror(errno));
connection->error = MPD_ERROR_CONNPORT;

return -1;
}

return 0;
}
#else /* !MPD_HAVE_GAI */
static int mpd_connect(mpd_Connection * connection, const char * host, int port,
float timeout)
{
struct hostent * he;
struct sockaddr * dest;
int destlen;
struct sockaddr_in sin;

if(!(he=gethostbyname(host))) {
snprintf(connection->errorStr, sizeof(connection->errorStr),
"host \"%s\" not found",host);
connection->error = MPD_ERROR_UNKHOST;
return -1;
}

memset(&sin,0,sizeof(struct sockaddr_in));
/*dest.sin_family = he->h_addrtype;*/
sin.sin_family = AF_INET;
sin.sin_port = htons(port);

switch(he->h_addrtype) {
case AF_INET:
memcpy((char *)&sin.sin_addr.s_addr,(char *)he->h_addr,
he->h_length);
dest = (struct sockaddr *)&sin;
destlen = sizeof(struct sockaddr_in);
break;
default:
strcpy(connection->errorStr,"address type is not IPv4");
connection->error = MPD_ERROR_SYSTEM;
return -1;
break;
}

if (connection->sock >= 0)
closesocket(connection->sock);
if((connection->sock = socket(dest->sa_family,SOCK_STREAM,0))<0) {
strcpy(connection->errorStr,"problems creating socket");
connection->error = MPD_ERROR_SYSTEM;
return -1;
}

mpd_setConnectionTimeout(connection,timeout);

/* connect stuff */
if (do_connect_fail(connection, dest, destlen)) {
snprintf(connection->errorStr, sizeof(connection->errorStr),
"problems connecting to \"%s\" on port"
" %i", host, port);
connection->error = MPD_ERROR_CONNPORT;
return -1;
}

return 0;
}
#endif /* !MPD_HAVE_GAI */

const char *const mpdTagItemKeys[MPD_TAG_NUM_OF_ITEM_TYPES] =
{
"Artist",
Expand Down Expand Up @@ -361,53 +222,6 @@ static int mpd_parseWelcome(mpd_Connection * connection, const char * host, int
return 0;
}

#ifndef WIN32
static int mpd_connect_un(mpd_Connection * connection,
const char * host, float timeout)
{
int error, flags;
size_t path_length;
struct sockaddr_un sun;

path_length = strlen(host);
if (path_length >= sizeof(sun.sun_path)) {
strcpy(connection->errorStr, "unix socket path is too long");
connection->error = MPD_ERROR_UNKHOST;
return -1;
}

sun.sun_family = AF_UNIX;
memcpy(sun.sun_path, host, path_length + 1);

connection->sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (connection->sock < 0) {
strcpy(connection->errorStr, "problems creating socket");
connection->error = MPD_ERROR_SYSTEM;
return -1;
}

mpd_setConnectionTimeout(connection, timeout);

flags = fcntl(connection->sock, F_GETFL, 0);
fcntl(connection->sock, F_SETFL, flags | O_NONBLOCK);

error = connect(connection->sock, (struct sockaddr*)&sun, sizeof(sun));
if (error < 0) {
/* try the next address family */
close(connection->sock);
connection->sock = 0;

snprintf(connection->errorStr, sizeof(connection->errorStr),
"problems connecting to \"%s\": %s",
host, strerror(errno));
connection->error = MPD_ERROR_CONNPORT;
return -1;
}

return 0;
}
#endif /* WIN32 */

/**
* Wait for the socket to become readable.
*/
Expand Down Expand Up @@ -514,6 +328,76 @@ static int mpd_recv(mpd_Connection *connection)
}
}

static int
mpd_connect(mpd_Connection *connection, const char * host, int port)
{
struct resolver *resolver;
const struct resolver_address *address;
int ret;

resolver = resolver_new(host, port);
if (resolver == NULL) {
snprintf(connection->errorStr, sizeof(connection->errorStr),
"host \"%s\" not found", host);
connection->error = MPD_ERROR_UNKHOST;
return -1;
}

while ((address = resolver_next(resolver)) != NULL) {
connection->sock = socket(address->family, SOCK_STREAM,
address->protocol);
if (connection->sock < 0) {
snprintf(connection->errorStr,
sizeof(connection->errorStr),
"problems creating socket: %s",
strerror(errno));
connection->error = MPD_ERROR_SYSTEM;
continue;
}

ret = do_connect_fail(connection,
address->addr, address->addrlen);
if (ret != 0) {
snprintf(connection->errorStr,
sizeof(connection->errorStr),
"problems connecting to \"%s\" on port"
" %i: %s", host, port, strerror(errno));
connection->error = MPD_ERROR_CONNPORT;

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) {
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;
} else if (ret < 0) {
snprintf(connection->errorStr,
sizeof(connection->errorStr),
"problems connecting to \"%s\" on port %i: %s",
host, port, strerror(-ret));
connection->error = MPD_ERROR_CONNPORT;
}

closesocket(connection->sock);
connection->sock = -1;
}

resolver_free(resolver);
return -1;
}

mpd_Connection * mpd_newConnection(const char * host, int port, float timeout) {
int err;
char * rt;
Expand All @@ -540,30 +424,11 @@ mpd_Connection * mpd_newConnection(const char * host, int port, float timeout) {
if (winsock_dll_error(connection))
return connection;

#ifndef WIN32
if (host[0] == '/')
err = mpd_connect_un(connection, host, timeout);
else
#endif
err = mpd_connect(connection, host, port, timeout);
if (err < 0)
return connection;
mpd_setConnectionTimeout(connection,timeout);

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;
err = mpd_connect(connection, host, port);
if (err < 0)
return connection;
}

while(!(rt = memchr(connection->buffer, '\n', connection->buflen))) {
err = mpd_recv(connection);
Expand Down

0 comments on commit f94949d

Please sign in to comment.