summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: d007e2d)
raw | patch | inline | side by side (parent: d007e2d)
author | Max Kellermann <max.kellermann@gmail.com> | |
Fri, 17 Mar 2017 14:53:09 +0000 (15:53 +0100) | ||
committer | Max Kellermann <max.kellermann@gmail.com> | |
Sun, 19 Mar 2017 12:58:17 +0000 (13:58 +0100) |
This way, the user can really cancel the connection attempt at any
time, and does not need to wait for a timeout.
This duplicates some code from libmpdclient, but unfortunately
libmpdclient doesn't expose a usable API for connecting asynchronously
yet.
time, and does not need to wait for a timeout.
This duplicates some code from libmpdclient, but unfortunately
libmpdclient doesn't expose a usable API for connecting asynchronously
yet.
16 files changed:
Makefile.am | patch | blob | history | |
NEWS | patch | blob | history | |
configure.ac | patch | blob | history | |
src/aconnect.c | [new file with mode: 0644] | patch | blob |
src/aconnect.h | [new file with mode: 0644] | patch | blob |
src/mpdclient.c | patch | blob | history | |
src/mpdclient.h | patch | blob | history | |
src/net/async_connect.c | [new file with mode: 0644] | patch | blob |
src/net/async_connect.h | [new file with mode: 0644] | patch | blob |
src/net/async_rconnect.c | [new file with mode: 0644] | patch | blob |
src/net/async_rconnect.h | [new file with mode: 0644] | patch | blob |
src/net/resolver.c | [new file with mode: 0644] | patch | blob |
src/net/resolver.h | [new file with mode: 0644] | patch | blob |
src/net/socket.c | [new file with mode: 0644] | patch | blob |
src/net/socket.h | [new file with mode: 0644] | patch | blob |
src/net/types.h | [new file with mode: 0644] | patch | blob |
diff --git a/Makefile.am b/Makefile.am
index cc8431bb48522aabc6114849f0e349084fabe0ac..5f1abbae1fff8761fffa86b55046303a8303aae0 100644 (file)
--- a/Makefile.am
+++ b/Makefile.am
src/strfsong.c src/strfsong.h \
src/utils.c src/utils.h
+if ENABLE_ASYNC_CONNECT
+src_ncmpc_SOURCES += \
+ src/net/types.h \
+ src/net/socket.c src/net/socket.h \
+ src/net/resolver.c src/net/resolver.h \
+ src/net/async_connect.c src/net/async_connect.h \
+ src/net/async_rconnect.c src/net/async_rconnect.h \
+ src/aconnect.c src/aconnect.h
+endif
+
#
# Windows resource file
#
index 58f1b88327ea0b7042d0bb817bf1d20429e0e443..be34c1262e213f0b8cf03d2850d17c9b75d28127 100644 (file)
--- a/NEWS
+++ b/NEWS
* adapt to lirc 0.9.4
* lyricswiki: update regex
* screen_song: show "f" and "dsd" formats
+* connect asynchronously
* fix gcc 7 warnings
ncmpc 0.25 - (2016-08-18)
diff --git a/configure.ac b/configure.ac
index cbd3989de985d45eb8f82df69448d31ac88f1f6a..2a78958598272c5e0c1dac6d9c585c647768b07a 100644 (file)
--- a/configure.ac
+++ b/configure.ac
AM_PO_SUBDIRS
fi
+dnl Networking
+
+AC_ARG_ENABLE(tcp,
+ AS_HELP_STRING([--disable-tcp],
+ [Disable TCP support @<:@default=enabled@:>@]),,
+ [enable_tcp=$disable_mini])
+if test "x$enable_tcp" = xyes; then
+ AC_DEFINE([ENABLE_TCP], 1, [Define to enable TCP support])
+ AC_SEARCH_LIBS([gethostbyname], [nsl])
+ AC_CHECK_FUNCS([getaddrinfo])
+fi
+
+AC_ARG_ENABLE([async-connect],
+ AS_HELP_STRING([--enable-async-connect],
+ [Disable asynchronous connect @<:@default=yes@:>@]),,
+ [enable_async_connect=$disable_mini])
+AM_CONDITIONAL(ENABLE_ASYNC_CONNECT, test x$enable_async_connect = xyes)
+if test "x$enable_async_connect" = xyes; then
+ AC_DEFINE([ENABLE_ASYNC_CONNECT], [1], [Enable asynchronous connect?])
+fi
+
dnl enable colors
AC_ARG_ENABLE([colors],
AS_HELP_STRING([--enable-colors],
diff --git a/src/aconnect.c b/src/aconnect.c
--- /dev/null
+++ b/src/aconnect.c
@@ -0,0 +1,164 @@
+/* ncmpc (Ncurses MPD Client)
+ (c) 2004-2017 The Music Player Daemon Project
+ Project homepage: http://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 "aconnect.h"
+#include "net/async_rconnect.h"
+#include "net/socket.h"
+#include "Compiler.h"
+
+#include <mpd/client.h>
+#include <mpd/async.h>
+
+#include <glib.h>
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/socket.h>
+
+struct aconnect {
+ const struct aconnect_handler *handler;
+ void *handler_ctx;
+
+ struct async_rconnect *rconnect;
+
+ int fd;
+ guint source_id;
+};
+
+static gboolean
+aconnect_source_callback(gcc_unused GIOChannel *source,
+ gcc_unused GIOCondition condition,
+ gpointer data)
+{
+ struct aconnect *ac = data;
+ assert(ac->source_id != 0);
+ ac->source_id = 0;
+
+ char buffer[256];
+ ssize_t nbytes = recv(ac->fd, buffer, sizeof(buffer) - 1, 0);
+ if (nbytes < 0) {
+ snprintf(buffer, sizeof(buffer),
+ "Failed to receive from MPD: %s",
+ strerror(errno));
+ close_socket(ac->fd);
+ ac->handler->error(buffer, ac->handler_ctx);
+ g_free(ac);
+ return false;
+ }
+
+ if (nbytes == 0) {
+ close_socket(ac->fd);
+ ac->handler->error("MPD closed the connection",
+ ac->handler_ctx);
+ g_free(ac);
+ return false;
+ }
+
+ buffer[nbytes] = 0;
+
+ struct mpd_async *async = mpd_async_new(ac->fd);
+ if (async == NULL) {
+ close_socket(ac->fd);
+ ac->handler->error("Out of memory", ac->handler_ctx);
+ g_free(ac);
+ return false;
+ }
+
+ struct mpd_connection *c = mpd_connection_new_async(async, buffer);
+ if (c == NULL) {
+ mpd_async_free(async);
+ ac->handler->error("Out of memory", ac->handler_ctx);
+ g_free(ac);
+ return false;
+ }
+
+ ac->handler->success(c, ac->handler_ctx);
+ g_free(ac);
+ return false;
+}
+
+static void
+aconnect_rconnect_success(int fd, void *ctx)
+{
+ struct aconnect *ac = ctx;
+ assert(ac->rconnect != NULL);
+ ac->rconnect = NULL;
+
+ ac->fd = fd;
+
+ GIOChannel *channel = g_io_channel_unix_new(fd);
+ ac->source_id = g_io_add_watch(channel, G_IO_IN,
+ aconnect_source_callback, ac);
+ g_io_channel_unref(channel);
+}
+
+static void
+aconnect_rconnect_error(const char *message, void *ctx)
+{
+ struct aconnect *ac = ctx;
+ assert(ac->rconnect != NULL);
+ ac->rconnect = NULL;
+
+ ac->handler->error(message, ac->handler_ctx);
+ g_free(ac);
+}
+
+static const struct async_rconnect_handler aconnect_rconnect_handler = {
+ .success = aconnect_rconnect_success,
+ .error = aconnect_rconnect_error,
+};
+
+void
+aconnect_start(struct aconnect **acp,
+ const char *host, unsigned port,
+ const struct aconnect_handler *handler, void *ctx)
+{
+ struct aconnect *ac = g_new(struct aconnect, 1);
+ ac->handler = handler;
+ ac->handler_ctx = ctx;
+
+ async_rconnect_start(&ac->rconnect, host, port,
+ &aconnect_rconnect_handler, ac);
+
+ *acp = ac;
+}
+
+void
+aconnect_cancel(struct aconnect *ac)
+{
+ if (ac->rconnect != NULL)
+ async_rconnect_cancel(ac->rconnect);
+ else {
+ g_source_remove(ac->source_id);
+ close_socket(ac->fd);
+ }
+
+ g_free(ac);
+}
diff --git a/src/aconnect.h b/src/aconnect.h
--- /dev/null
+++ b/src/aconnect.h
@@ -0,0 +1,50 @@
+/* ncmpc (Ncurses MPD Client)
+ (c) 2004-2017 The Music Player Daemon Project
+ Project homepage: http://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 ACONNECT_H
+#define ACONNECT_H
+
+#include <mpd/client.h>
+
+struct mpd_connection;
+struct aconnect;
+
+struct aconnect_handler {
+ void (*success)(struct mpd_connection *c, void *ctx);
+ void (*error)(const char *message, void *ctx);
+};
+
+void
+aconnect_start(struct aconnect **acp,
+ const char *host, unsigned port,
+ const struct aconnect_handler *handler, void *ctx);
+
+void
+aconnect_cancel(struct aconnect *ac);
+
+#endif
diff --git a/src/mpdclient.c b/src/mpdclient.c
index a7d1ef826aa9da3a251c959208ff252a93775ac0..5903f1430fb3c9288c1c99d1fe208db07990e76f 100644 (file)
--- a/src/mpdclient.c
+++ b/src/mpdclient.c
#include "gidle.h"
#include "charset.h"
+#ifdef ENABLE_ASYNC_CONNECT
+#include "aconnect.h"
+#endif
+
#include <mpd/client.h>
#include <assert.h>
{
struct mpdclient *c = g_new0(struct mpdclient, 1);
+#ifdef ENABLE_ASYNC_CONNECT
+ c->settings = mpd_settings_new(host, port, timeout_ms,
+ NULL, NULL);
+ if (c->settings == NULL)
+ g_error("Out of memory");
+#else
c->host = host;
c->port = port;
+#endif
+
c->timeout_ms = timeout_ms;
c->password = password;
mpdclient_playlist_free(&c->playlist);
+#ifdef ENABLE_ASYNC_CONNECT
+ mpd_settings_free(c->settings);
+#endif
+
g_free(c);
}
void
mpdclient_disconnect(struct mpdclient *c)
{
+#ifdef ENABLE_ASYNC_CONNECT
+ if (c->async_connect != NULL) {
+ aconnect_cancel(c->async_connect);
+ c->async_connect = NULL;
+ }
+#endif
+
mpdclient_cancel_enter_idle(c);
if (c->source != NULL) {
return false;
}
+#ifdef ENABLE_ASYNC_CONNECT
+ if (c->timeout_ms > 0)
+ mpd_connection_set_timeout(connection, c->timeout_ms);
+#endif
+
/* send password */
if (c->password != NULL &&
!mpd_run_password(connection, c->password)) {
return true;
}
-bool
+#ifdef ENABLE_ASYNC_CONNECT
+
+static void
+mpdclient_connect_success(struct mpd_connection *connection, void *ctx)
+{
+ struct mpdclient *c = ctx;
+ assert(c->async_connect != NULL);
+ c->async_connect = NULL;
+
+ mpdclient_connected(c, connection);
+}
+
+static void
+mpdclient_connect_error(const char *message, void *ctx)
+{
+ struct mpdclient *c = ctx;
+ assert(c->async_connect != NULL);
+ c->async_connect = NULL;
+
+ mpdclient_error_callback(message);
+ mpdclient_failed_callback();
+}
+
+static const struct aconnect_handler mpdclient_connect_handler = {
+ .success = mpdclient_connect_success,
+ .error = mpdclient_connect_error,
+};
+
+#endif
+
+void
mpdclient_connect(struct mpdclient *c)
{
/* close any open connection */
mpdclient_disconnect(c);
+#ifdef ENABLE_ASYNC_CONNECT
+ aconnect_start(&c->async_connect,
+ mpd_settings_get_host(c->settings),
+ mpd_settings_get_port(c->settings),
+ &mpdclient_connect_handler, c);
+#else
/* connect to MPD */
struct mpd_connection *connection =
mpd_connection_new(c->host, c->port, c->timeout_ms);
if (connection == NULL)
g_error("Out of memory");
- return mpdclient_connected(c, connection);
+ mpdclient_connected(c, connection);
+#endif
}
bool
diff --git a/src/mpdclient.h b/src/mpdclient.h
index bac33383ab1bc33ccb34a614b5091fda8080f2cf..b00709748eff7d99436d46d6675feb10a8535dd4 100644 (file)
--- a/src/mpdclient.h
+++ b/src/mpdclient.h
#ifndef MPDCLIENT_H
#define MPDCLIENT_H
+#include "config.h"
#include "playlist.h"
#include "Compiler.h"
struct filelist;
struct mpdclient {
+#ifdef ENABLE_ASYNC_CONNECT
+ struct mpd_settings *settings;
+#else
const char *host;
unsigned port;
+#endif
unsigned timeout_ms;
/* playlist */
struct mpdclient_playlist playlist;
+#ifdef ENABLE_ASYNC_CONNECT
+ struct aconnect *async_connect;
+#endif
+
struct mpd_connection *connection;
/**
static inline bool
mpdclient_is_dead(const struct mpdclient *c)
{
- return c->connection == NULL;
+ return c->connection == NULL
+#ifdef ENABLE_ASYNC_CONNECT
+ && c->async_connect == NULL
+#endif
+ ;
}
gcc_pure
: NULL;
}
-bool
+void
mpdclient_connect(struct mpdclient *c);
void
diff --git a/src/net/async_connect.c b/src/net/async_connect.c
--- /dev/null
+++ b/src/net/async_connect.c
@@ -0,0 +1,128 @@
+/* ncmpc (Ncurses MPD Client)
+ (c) 2004-2017 The Music Player Daemon Project
+ Project homepage: http://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 "async_connect.h"
+#include "../Compiler.h"
+
+#include <glib.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+struct async_connect {
+ const struct async_connect_handler *handler;
+ void *handler_ctx;
+
+ socket_t fd;
+
+ guint source_id;
+};
+
+static gboolean
+async_connect_source_callback(gcc_unused GIOChannel *source,
+ gcc_unused GIOCondition condition,
+ gpointer data)
+{
+ struct async_connect *ac = data;
+
+ const int fd = ac->fd;
+ const struct async_connect_handler *const handler = ac->handler;
+ void *const ctx = ac->handler_ctx;
+ g_free(ac);
+
+ int s_err = 0;
+ socklen_t s_err_size = sizeof(s_err);
+
+ if (getsockopt(fd, SOL_SOCKET, SO_ERROR,
+ (char*)&s_err, &s_err_size) < 0)
+ s_err = -last_socket_error();
+
+ if (s_err == 0) {
+ handler->success(fd, ctx);
+ } else {
+ close_socket(fd);
+ char msg[256];
+ snprintf(msg, sizeof(msg), "Failed to connect socket: %s",
+ strerror(-s_err));
+ handler->error(msg, ctx);
+ }
+
+ return false;
+}
+
+void
+async_connect_start(struct async_connect **acp,
+ const struct sockaddr *address, size_t address_size,
+ const struct async_connect_handler *handler, void *ctx)
+{
+ socket_t fd = create_socket(address->sa_family, SOCK_STREAM, 0);
+ if (fd == INVALID_SOCKET) {
+ char msg[256];
+ snprintf(msg, sizeof(msg), "Failed to create socket: %s",
+ strerror(errno));
+ handler->error(msg, ctx);
+ return;
+ }
+
+ if (connect(fd, address, address_size) == 0) {
+ handler->success(fd, ctx);
+ return;
+ }
+
+ const int e = last_socket_error();
+ if (!would_block(e)) {
+ close_socket(fd);
+ char msg[256];
+ snprintf(msg, sizeof(msg), "Failed to connect socket: %s",
+ strerror(e));
+ handler->error(msg, ctx);
+ return;
+ }
+
+ struct async_connect *ac = g_new(struct async_connect, 1);
+ ac->handler = handler;
+ ac->handler_ctx = ctx;
+ ac->fd = fd;
+
+ GIOChannel *channel = g_io_channel_unix_new(fd);
+ ac->source_id = g_io_add_watch(channel, G_IO_OUT,
+ async_connect_source_callback, ac);
+ g_io_channel_unref(channel);
+
+ *acp = ac;
+}
+
+void
+async_connect_cancel(struct async_connect *ac)
+{
+ g_source_remove(ac->source_id);
+ close_socket(ac->fd);
+ g_free(ac);
+}
diff --git a/src/net/async_connect.h b/src/net/async_connect.h
--- /dev/null
+++ b/src/net/async_connect.h
@@ -0,0 +1,56 @@
+/* ncmpc (Ncurses MPD Client)
+ (c) 2004-2017 The Music Player Daemon Project
+ Project homepage: http://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 NET_ASYNC_CONNECT_H
+#define NET_ASYNC_CONNECT_H
+
+#include "socket.h"
+
+#include <stddef.h>
+
+struct sockaddr;
+struct async_connect;
+
+struct async_connect_handler {
+ void (*success)(socket_t fd, void *ctx);
+ void (*error)(const char *message, void *ctx);
+};
+
+/**
+ * Create a socket and connect it to the given address.
+ */
+void
+async_connect_start(struct async_connect **acp,
+ const struct sockaddr *address,
+ size_t address_size,
+ const struct async_connect_handler *handler, void *ctx);
+
+void
+async_connect_cancel(struct async_connect *ac);
+
+#endif
diff --git a/src/net/async_rconnect.c b/src/net/async_rconnect.c
--- /dev/null
+++ b/src/net/async_rconnect.c
@@ -0,0 +1,145 @@
+/* ncmpc (Ncurses MPD Client)
+ (c) 2004-2017 The Music Player Daemon Project
+ Project homepage: http://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 "async_rconnect.h"
+#include "async_connect.h"
+#include "resolver.h"
+#include "../Compiler.h"
+
+#include <glib.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+struct async_rconnect {
+ const struct async_rconnect_handler *handler;
+ void *handler_ctx;
+
+ const char *host;
+ struct resolver *resolver;
+
+ struct async_connect *connect;
+
+ char *last_error;
+};
+
+static void
+async_rconnect_next(struct async_rconnect *rc);
+
+static void
+async_rconnect_success(socket_t fd, void *ctx)
+{
+ struct async_rconnect *rc = ctx;
+
+ rc->handler->success(fd, rc->handler_ctx);
+ g_free(rc->last_error);
+ resolver_free(rc->resolver);
+ g_free(rc);
+}
+
+static void
+async_rconnect_error(const char *message, void *ctx)
+{
+ struct async_rconnect *rc = ctx;
+
+ g_free(rc->last_error);
+ rc->last_error = g_strdup(message);
+
+ async_rconnect_next(rc);
+}
+
+static const struct async_connect_handler async_rconnect_connect_handler = {
+ .success = async_rconnect_success,
+ .error = async_rconnect_error,
+};
+
+static void
+async_rconnect_next(struct async_rconnect *rc)
+{
+ const struct resolver_address *a = resolver_next(rc->resolver);
+ if (a == NULL) {
+ char msg[256];
+
+ if (rc->last_error == 0) {
+ snprintf(msg, sizeof(msg),
+ "Host '%s' has no address",
+ rc->host);
+ } else {
+ snprintf(msg, sizeof(msg),
+ "Failed to connect to host '%s': %s",
+ rc->host, rc->last_error);
+ g_free(rc->last_error);
+ }
+
+ rc->handler->error(msg, rc->handler_ctx);
+ resolver_free(rc->resolver);
+ g_free(rc);
+ return;
+ }
+
+ async_connect_start(&rc->connect, a->addr, a->addrlen,
+ &async_rconnect_connect_handler, rc);
+}
+
+void
+async_rconnect_start(struct async_rconnect **rcp,
+ const char *host, unsigned port,
+ const struct async_rconnect_handler *handler, void *ctx)
+{
+ struct resolver *r = resolver_new(host, port);
+ if (host == NULL)
+ host = "[default]";
+
+ if (r == NULL) {
+ char msg[256];
+ snprintf(msg, sizeof(msg), "Failed to resolve host '%s'",
+ host);
+ handler->error(msg, ctx);
+ return;
+ }
+
+ struct async_rconnect *rc = g_new(struct async_rconnect, 1);
+ rc->handler = handler;
+ rc->handler_ctx = ctx;
+ rc->host = host;
+ rc->resolver = r;
+ rc->last_error = NULL;
+ *rcp = rc;
+
+ async_rconnect_next(rc);
+}
+
+void
+async_rconnect_cancel(struct async_rconnect *rc)
+{
+ g_free(rc->last_error);
+ async_connect_cancel(rc->connect);
+ resolver_free(rc->resolver);
+ g_free(rc);
+}
diff --git a/src/net/async_rconnect.h b/src/net/async_rconnect.h
--- /dev/null
+++ b/src/net/async_rconnect.h
@@ -0,0 +1,52 @@
+/* ncmpc (Ncurses MPD Client)
+ (c) 2004-2017 The Music Player Daemon Project
+ Project homepage: http://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 NET_ASYNC_RCONNECT_H
+#define NET_ASYNC_RCONNECT_H
+
+#include <mpd/client.h>
+
+struct async_rconnect;
+
+struct async_rconnect_handler {
+ void (*success)(int fd, void *ctx);
+ void (*error)(const char *message, void *ctx);
+};
+
+/**
+ * Resolve a host name and connect to it asynchronously.
+ */
+void
+async_rconnect_start(struct async_rconnect **rcp,
+ const char *host, unsigned port,
+ const struct async_rconnect_handler *handler, void *ctx);
+
+void
+async_rconnect_cancel(struct async_rconnect *rc);
+
+#endif
diff --git a/src/net/resolver.c b/src/net/resolver.c
--- /dev/null
+++ b/src/net/resolver.c
@@ -0,0 +1,200 @@
+/* libmpdclient
+ (c) 2003-2017 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 "resolver.h"
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef WIN32
+# include <winsock2.h>
+# include <ws2tcpip.h>
+#else
+# include <sys/socket.h>
+# include <sys/un.h>
+#ifdef ENABLE_TCP
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# include <netdb.h>
+#endif
+#endif
+
+struct resolver {
+ enum {
+ TYPE_ZERO, TYPE_ONE, TYPE_ANY
+ } type;
+
+#ifdef ENABLE_TCP
+#ifdef HAVE_GETADDRINFO
+ struct addrinfo *ai;
+ const struct addrinfo *next;
+#else
+ struct sockaddr_in sin;
+#endif
+#endif
+
+ struct resolver_address current;
+
+#ifndef WIN32
+ struct sockaddr_un saun;
+#endif
+};
+
+struct resolver *
+resolver_new(const char *host, unsigned port)
+{
+ struct resolver *resolver;
+
+ resolver = malloc(sizeof(*resolver));
+ if (resolver == NULL)
+ return NULL;
+
+ if (host[0] == '/' || host[0] == '@') {
+#ifndef WIN32
+ size_t path_length = strlen(host);
+ if (path_length >= sizeof(resolver->saun.sun_path)) {
+ free(resolver);
+ return NULL;
+ }
+
+ resolver->saun.sun_family = AF_UNIX;
+ memcpy(resolver->saun.sun_path, host, path_length + 1);
+
+ if (host[0] == '@')
+ /* abstract socket */
+ resolver->saun.sun_path[0] = 0;
+
+ resolver->current.family = PF_UNIX;
+ resolver->current.protocol = 0;
+ resolver->current.addrlen = sizeof(resolver->saun);
+ resolver->current.addr = (const struct sockaddr *)&resolver->saun;
+ resolver->type = TYPE_ONE;
+#else /* WIN32 */
+ /* there are no UNIX domain sockets on Windows */
+ free(resolver);
+ return NULL;
+#endif /* WIN32 */
+ } else {
+#ifdef ENABLE_TCP
+#ifdef HAVE_GETADDRINFO
+ struct addrinfo hints;
+ char service[20];
+ int ret;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+
+ snprintf(service, sizeof(service), "%d", port);
+
+ ret = getaddrinfo(host, service, &hints, &resolver->ai);
+ if (ret != 0) {
+ free(resolver);
+ return NULL;
+ }
+
+ resolver->next = resolver->ai;
+ resolver->type = TYPE_ANY;
+#else
+ const struct hostent *he;
+
+ he = gethostbyname(host);
+ if (he == NULL) {
+ free(resolver);
+ return NULL;
+ }
+
+ if (he->h_addrtype != AF_INET) {
+ free(resolver);
+ return NULL;
+ }
+
+
+ memset(&resolver->sin, 0, sizeof(resolver->sin));
+ resolver->sin.sin_family = AF_INET;
+ resolver->sin.sin_port = htons(port);
+ memcpy((char *)&resolver->sin.sin_addr.s_addr,
+ (char *)he->h_addr, he->h_length);
+
+ resolver->current.family = PF_INET;
+ resolver->current.protocol = 0;
+ resolver->current.addrlen = sizeof(resolver->sin);
+ resolver->current.addr = (const struct sockaddr *)&resolver->sin;
+
+ resolver->type = TYPE_ONE;
+#endif
+#else /* !ENABLE_TCP */
+ (void)port;
+ free(resolver);
+ return NULL;
+#endif
+ }
+
+ return resolver;
+}
+
+void
+resolver_free(struct resolver *resolver)
+{
+#if defined(ENABLE_TCP) && defined(HAVE_GETADDRINFO)
+ if (resolver->type == TYPE_ANY)
+ freeaddrinfo(resolver->ai);
+#endif
+ free(resolver);
+}
+
+const struct resolver_address *
+resolver_next(struct resolver *resolver)
+{
+ if (resolver->type == TYPE_ZERO)
+ return NULL;
+
+ if (resolver->type == TYPE_ONE) {
+ resolver->type = TYPE_ZERO;
+ return &resolver->current;
+ }
+
+#if defined(ENABLE_TCP) && defined(HAVE_GETADDRINFO)
+ if (resolver->next == NULL)
+ return NULL;
+
+ resolver->current.family = resolver->next->ai_family;
+ resolver->current.protocol = resolver->next->ai_protocol;
+ resolver->current.addrlen = resolver->next->ai_addrlen;
+ resolver->current.addr = resolver->next->ai_addr;
+
+ resolver->next = resolver->next->ai_next;
+
+ return &resolver->current;
+#else
+ return NULL;
+#endif
+}
diff --git a/src/net/resolver.h b/src/net/resolver.h
--- /dev/null
+++ b/src/net/resolver.h
@@ -0,0 +1,52 @@
+/* libmpdclient
+ (c) 2003-2017 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 LIBMPDCLIENT_RESOLVER_H
+#define LIBMPDCLIENT_RESOLVER_H
+
+#include <stddef.h>
+
+struct resolver;
+
+struct resolver_address {
+ int family;
+ int protocol;
+ size_t addrlen;
+ const struct sockaddr *addr;
+};
+
+struct resolver *
+resolver_new(const char *host, unsigned port);
+
+void
+resolver_free(struct resolver *resolver);
+
+const struct resolver_address *
+resolver_next(struct resolver *resolver);
+
+#endif
diff --git a/src/net/socket.c b/src/net/socket.c
--- /dev/null
+++ b/src/net/socket.c
@@ -0,0 +1,76 @@
+/* ncmpc (Ncurses MPD Client)
+ (c) 2004-2017 The Music Player Daemon Project
+ Project homepage: http://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"
+
+#ifndef WIN32
+#include <fcntl.h>
+#endif
+
+static void
+socket_set_cloexec(socket_t fd)
+{
+#ifndef WIN32
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+#else
+ (void)fd;
+#endif
+}
+
+static void
+socket_set_nonblock(socket_t fd)
+{
+#ifdef WIN32
+ u_long val = 1;
+ ioctlsocket(fd, FIONBIO, &val);
+#else
+ int flags = fcntl(fd, F_GETFL);
+ if (flags >= 0)
+ fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+#endif
+}
+
+socket_t
+create_socket(int domain, int type, int protocol)
+{
+ socket_t fd;
+
+#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
+ fd = socket(domain, type | SOCK_CLOEXEC | SOCK_NONBLOCK, protocol);
+ if (fd != INVALID_SOCKET || errno != EINVAL)
+ return fd;
+#endif
+
+ fd = socket(domain, type, protocol);
+ if (fd != INVALID_SOCKET) {
+ socket_set_cloexec(fd);
+ socket_set_nonblock(fd);
+ }
+
+ return fd;
+}
diff --git a/src/net/socket.h b/src/net/socket.h
--- /dev/null
+++ b/src/net/socket.h
@@ -0,0 +1,75 @@
+/* ncmpc (Ncurses MPD Client)
+ (c) 2004-2017 The Music Player Daemon Project
+ Project homepage: http://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 NET_SOCKET_H
+#define NET_SOCKET_H
+
+#include "types.h"
+
+#include <stdbool.h>
+
+#ifndef WIN32
+#include <errno.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#endif
+
+socket_t
+create_socket(int domain, int type, int protocol);
+
+static inline void
+close_socket(socket_t s)
+{
+#ifdef WIN32
+ closesocket(s);
+#else
+ close(s);
+#endif
+}
+
+static inline int
+last_socket_error(void)
+{
+#ifdef WIN32
+ return WSAGetLastError();
+#else
+ return errno;
+#endif
+}
+
+static inline bool
+would_block(int e)
+{
+#ifdef WIN32
+ return e == WSAEINPROGRESS || e == WSAEWOULDBLOCK;
+#else
+ return e == EINPROGRESS || e == EAGAIN;
+#endif
+}
+
+#endif
diff --git a/src/net/types.h b/src/net/types.h
--- /dev/null
+++ b/src/net/types.h
@@ -0,0 +1,44 @@
+/* ncmpc (Ncurses MPD Client)
+ (c) 2004-2017 The Music Player Daemon Project
+ Project homepage: http://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 NET_TYPES_H
+#define NET_TYPES_H
+
+#ifdef WIN32
+
+#include <winsock2.h>
+typedef SOCKET socket_t;
+
+#else
+
+typedef int socket_t;
+#define INVALID_SOCKET -1
+
+#endif
+
+#endif