Code

mpdclient: connect to MPD asynchronously
authorMax Kellermann <max.kellermann@gmail.com>
Fri, 17 Mar 2017 14:53:09 +0000 (15:53 +0100)
committerMax 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.

16 files changed:
Makefile.am
NEWS
configure.ac
src/aconnect.c [new file with mode: 0644]
src/aconnect.h [new file with mode: 0644]
src/mpdclient.c
src/mpdclient.h
src/net/async_connect.c [new file with mode: 0644]
src/net/async_connect.h [new file with mode: 0644]
src/net/async_rconnect.c [new file with mode: 0644]
src/net/async_rconnect.h [new file with mode: 0644]
src/net/resolver.c [new file with mode: 0644]
src/net/resolver.h [new file with mode: 0644]
src/net/socket.c [new file with mode: 0644]
src/net/socket.h [new file with mode: 0644]
src/net/types.h [new file with mode: 0644]

index cc8431bb48522aabc6114849f0e349084fabe0ac..5f1abbae1fff8761fffa86b55046303a8303aae0 100644 (file)
@@ -61,6 +61,16 @@ src_ncmpc_SOURCES = \
        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
 #
diff --git a/NEWS b/NEWS
index 58f1b88327ea0b7042d0bb817bf1d20429e0e443..be34c1262e213f0b8cf03d2850d17c9b75d28127 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,7 @@ ncmpc 0.26 - not yet released
 * 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)
index cbd3989de985d45eb8f82df69448d31ac88f1f6a..2a78958598272c5e0c1dac6d9c585c647768b07a 100644 (file)
@@ -149,6 +149,27 @@ else
   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
new file mode 100644 (file)
index 0000000..345bc52
--- /dev/null
@@ -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
new file mode 100644 (file)
index 0000000..7c62e32
--- /dev/null
@@ -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
index a7d1ef826aa9da3a251c959208ff252a93775ac0..5903f1430fb3c9288c1c99d1fe208db07990e76f 100644 (file)
 #include "gidle.h"
 #include "charset.h"
 
+#ifdef ENABLE_ASYNC_CONNECT
+#include "aconnect.h"
+#endif
+
 #include <mpd/client.h>
 
 #include <assert.h>
@@ -155,8 +159,16 @@ mpdclient_new(const gchar *host, unsigned port,
 {
        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;
 
@@ -175,6 +187,10 @@ mpdclient_free(struct mpdclient *c)
 
        mpdclient_playlist_free(&c->playlist);
 
+#ifdef ENABLE_ASYNC_CONNECT
+       mpd_settings_free(c->settings);
+#endif
+
        g_free(c);
 }
 
@@ -194,6 +210,13 @@ mpdclient_status_free(struct mpdclient *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) {
@@ -232,6 +255,11 @@ mpdclient_connected(struct mpdclient *c,
                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)) {
@@ -251,19 +279,56 @@ mpdclient_connected(struct mpdclient *c,
        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
index bac33383ab1bc33ccb34a614b5091fda8080f2cf..b00709748eff7d99436d46d6675feb10a8535dd4 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef MPDCLIENT_H
 #define MPDCLIENT_H
 
+#include "config.h"
 #include "playlist.h"
 #include "Compiler.h"
 
@@ -9,8 +10,12 @@
 struct filelist;
 
 struct mpdclient {
+#ifdef ENABLE_ASYNC_CONNECT
+       struct mpd_settings *settings;
+#else
        const char *host;
        unsigned port;
+#endif
 
        unsigned timeout_ms;
 
@@ -19,6 +24,10 @@ struct mpdclient {
        /* playlist */
        struct mpdclient_playlist playlist;
 
+#ifdef ENABLE_ASYNC_CONNECT
+       struct aconnect *async_connect;
+#endif
+
        struct mpd_connection *connection;
 
        /**
@@ -112,7 +121,11 @@ gcc_pure
 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
@@ -133,7 +146,7 @@ mpdclient_get_current_song(const struct mpdclient *c)
                : NULL;
 }
 
-bool
+void
 mpdclient_connect(struct mpdclient *c);
 
 void
diff --git a/src/net/async_connect.c b/src/net/async_connect.c
new file mode 100644 (file)
index 0000000..c375ea3
--- /dev/null
@@ -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
new file mode 100644 (file)
index 0000000..f56868c
--- /dev/null
@@ -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
new file mode 100644 (file)
index 0000000..8986daa
--- /dev/null
@@ -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
new file mode 100644 (file)
index 0000000..47db3a9
--- /dev/null
@@ -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
new file mode 100644 (file)
index 0000000..952c2c9
--- /dev/null
@@ -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
new file mode 100644 (file)
index 0000000..1e3ec78
--- /dev/null
@@ -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
new file mode 100644 (file)
index 0000000..f47770b
--- /dev/null
@@ -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
new file mode 100644 (file)
index 0000000..099fcaa
--- /dev/null
@@ -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
new file mode 100644 (file)
index 0000000..bd22f9e
--- /dev/null
@@ -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