Code

mpdclient: try IP connect if default local socket path fails
[ncmpc.git] / src / mpdclient.c
index a7d1ef826aa9da3a251c959208ff252a93775ac0..ffa1a5d84408e86757b82d2dbde1617dbf07c583 100644 (file)
 #include "gidle.h"
 #include "charset.h"
 
+#ifdef ENABLE_ASYNC_CONNECT
+#include "aconnect.h"
+#endif
+
 #include <mpd/client.h>
 
 #include <assert.h>
@@ -149,14 +153,49 @@ mpdclient_handle_error(struct mpdclient *c)
        return false;
 }
 
+#ifdef ENABLE_ASYNC_CONNECT
+#ifndef WIN32
+
+static bool
+is_local_socket(const char *host)
+{
+       return *host == '/' || *host == '@';
+}
+
+static bool
+settings_is_local_socket(const struct mpd_settings *settings)
+{
+       const char *host = mpd_settings_get_host(settings);
+       return host != NULL && is_local_socket(host);
+}
+
+#endif
+#endif
+
 struct mpdclient *
 mpdclient_new(const gchar *host, unsigned port,
              unsigned timeout_ms, const gchar *password)
 {
        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");
+
+#ifndef WIN32
+       c->settings2 = host == NULL && port == 0 &&
+               settings_is_local_socket(c->settings)
+               ? mpd_settings_new(host, 6600, timeout_ms, NULL, NULL)
+               : NULL;
+#endif
+
+#else
        c->host = host;
        c->port = port;
+#endif
+
        c->timeout_ms = timeout_ms;
        c->password = password;
 
@@ -175,9 +214,56 @@ mpdclient_free(struct mpdclient *c)
 
        mpdclient_playlist_free(&c->playlist);
 
+#ifdef ENABLE_ASYNC_CONNECT
+       mpd_settings_free(c->settings);
+
+#ifndef WIN32
+       if (c->settings2 != NULL)
+               mpd_settings_free(c->settings2);
+#endif
+#endif
+
        g_free(c);
 }
 
+static char *
+settings_name(const struct mpd_settings *settings)
+{
+       assert(settings != NULL);
+
+       const char *host = mpd_settings_get_host(settings);
+       if (host == NULL)
+               host = "unknown";
+
+       if (host[0] == '/')
+               return g_strdup(host);
+
+       unsigned port = mpd_settings_get_port(settings);
+       if (port == 0 || port == 6600)
+               return g_strdup(host);
+
+       return g_strdup_printf("%s:%u", host, port);
+}
+
+char *
+mpdclient_settings_name(const struct mpdclient *c)
+{
+       assert(c != NULL);
+
+#ifdef ENABLE_ASYNC_CONNECT
+       return settings_name(c->settings);
+#else
+       struct mpd_settings *settings =
+               mpd_settings_new(c->host, c->port, 0, NULL, NULL);
+       if (settings == NULL)
+               return g_strdup("unknown");
+
+       char *name = settings_name(settings);
+       mpd_settings_free(settings);
+       return name;
+#endif
+}
+
 static void
 mpdclient_status_free(struct mpdclient *c)
 {
@@ -194,6 +280,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 +325,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 +349,78 @@ mpdclient_connected(struct mpdclient *c,
        return true;
 }
 
-bool
+#ifdef ENABLE_ASYNC_CONNECT
+
+static void
+mpdclient_aconnect_start(struct mpdclient *c,
+                        const struct mpd_settings *settings);
+
+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;
+
+#ifndef WIN32
+       if (!c->connecting2 && c->settings2 != NULL) {
+               c->connecting2 = true;
+               mpdclient_aconnect_start(c, c->settings2);
+               return;
+       }
+#endif
+
+       mpdclient_error_callback(message);
+       mpdclient_failed_callback();
+}
+
+static const struct aconnect_handler mpdclient_connect_handler = {
+       .success = mpdclient_connect_success,
+       .error = mpdclient_connect_error,
+};
+
+static void
+mpdclient_aconnect_start(struct mpdclient *c,
+                        const struct mpd_settings *settings)
+{
+       aconnect_start(&c->async_connect,
+                      mpd_settings_get_host(settings),
+                      mpd_settings_get_port(settings),
+                      &mpdclient_connect_handler, c);
+}
+
+#endif
+
+void
 mpdclient_connect(struct mpdclient *c)
 {
        /* close any open connection */
        mpdclient_disconnect(c);
 
+#ifdef ENABLE_ASYNC_CONNECT
+#ifndef WIN32
+       c->connecting2 = false;
+#endif
+       mpdclient_aconnect_start(c, c->settings);
+#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