[PATCH] Switch over to use GIO for socket connections / DNS resolution



GIO provides GSocket and GResolver classes that can replace all
current use of POSIX sockets / DNS resolution APIs. This gives
cross platform portability for free, removing the need to use
gnulib for socket portability

* configure.ac: Check for GIO
* src/Makefile.am: Link to GIO
* src/vncconnection.c: Switch to using GSocket & friends
* src/vncdisplay.c: Remove winsock initialization code
---
 configure.ac        |    8 +-
 src/Makefile.am     |    2 +
 src/vncconnection.c |  397 +++++++++++++++++++++++++--------------------------
 src/vncdisplay.c    |   53 -------
 4 files changed, 204 insertions(+), 256 deletions(-)

diff --git a/configure.ac b/configure.ac
index 13fe807..7d074da 100644
--- a/configure.ac
+++ b/configure.ac
@@ -28,6 +28,8 @@ dnl ****************************************************************************
 
 GOBJECT_REQUIRED=2.10.0
 AC_SUBST(GOBJECT_REQUIRED)
+GIO_REQUIRED=2.10.0
+AC_SUBST(GIO_REQUIRED)
 GDK_PIXBUF_REQUIRED=2.10.0
 AC_SUBST(GDK_PIXBUF_REQUIRED)
 GNUTLS_REQUIRED=1.4.0
@@ -99,7 +101,7 @@ AC_SUBST([GTK_VNC_API_VERSION])
 AM_CONDITIONAL([HAVE_GTK_2],[test "$with_gtk" = "2.0"])
 AM_CONDITIONAL([HAVE_GTK_3],[test "$with_gtk" = "3.0"])
 
-AC_CHECK_HEADERS([pwd.h winsock2.h termios.h])
+AC_CHECK_HEADERS([pwd.h termios.h])
 
 AC_ARG_WITH(python,
 [  --with-python           build python bindings],
@@ -158,6 +160,10 @@ PKG_CHECK_MODULES(GOBJECT, gobject-2.0 >= $GOBJECT_REQUIRED)
 AC_SUBST(GOBJECT_CFLAGS)
 AC_SUBST(GOBJECT_LIBS)
 
+PKG_CHECK_MODULES(GIO, gio-2.0 >= $GIO_REQUIRED)
+AC_SUBST(GIO_CFLAGS)
+AC_SUBST(GIO_LIBS)
+
 PKG_CHECK_MODULES(GDK_PIXBUF, gdk-pixbuf-2.0 >= $GDK_PIXBUF_REQUIRED)
 AC_SUBST(GDK_PIXBUF_CFLAGS)
 AC_SUBST(GDK_PIXBUF_LIBS)
diff --git a/src/Makefile.am b/src/Makefile.am
index 0a94954..5c423c0 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -23,6 +23,7 @@ endif
 
 libgvnc_1_0_la_LIBADD = \
 			@GOBJECT_LIBS@ \
+			@GIO_LIBS@ \
 			@GTHREAD_LIBS@ \
 			@GDK_PIXBUF_LIBS@ \
 			@GNUTLS_LIBS@ \
@@ -30,6 +31,7 @@ libgvnc_1_0_la_LIBADD = \
 			../gnulib/lib/libgnu.la
 libgvnc_1_0_la_CFLAGS = \
 			@GOBJECT_CFLAGS@ \
+			@GIO_CFLAGS@ \
 			@GTHREAD_CFLAGS@ \
 			@GDK_PIXBUF_CFLAGS@ \
 			@GNUTLS_CFLAGS@ \
diff --git a/src/vncconnection.c b/src/vncconnection.c
index 027a7f1..3abec29 100644
--- a/src/vncconnection.c
+++ b/src/vncconnection.c
@@ -26,10 +26,6 @@
 #include "vncmarshal.h"
 #include "vncutil.h"
 
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
 #include <string.h>
 #include <unistd.h>
 #include <stdio.h>
@@ -58,16 +54,8 @@
 
 #include <zlib.h>
 
-#include "getaddrinfo.h"
 #include "dh.h"
 
-/* AI_ADDRCONFIG is missing on some systems and gnulib won't provide it
-   even if its emulated getaddrinfo() for us . */
-#ifndef AI_ADDRCONFIG
-# define AI_ADDRCONFIG 0
-#endif
-
-
 struct wait_queue
 {
 	gboolean waiting;
@@ -112,7 +100,7 @@ struct _VncConnectionPrivate
 {
 	struct coroutine coroutine;
 	guint open_id;
-	GIOChannel *channel;
+	GSocket *sock;
 	int fd;
 	char *host;
 	char *port;
@@ -228,7 +216,7 @@ static guint signals[VNC_LAST_SIGNAL] = { 0, 0, 0, 0,
 #define niblo(a) ((a) & 0x0F)
 
 /* Main loop helper functions */
-static gboolean g_io_wait_helper(GIOChannel *channel G_GNUC_UNUSED,
+static gboolean g_io_wait_helper(GSocket *sock G_GNUC_UNUSED,
 				 GIOCondition cond,
 				 gpointer data)
 {
@@ -237,26 +225,33 @@ static gboolean g_io_wait_helper(GIOChannel *channel G_GNUC_UNUSED,
 	return FALSE;
 }
 
-static GIOCondition g_io_wait(GIOChannel *channel, GIOCondition cond)
+static GIOCondition g_io_wait(GSocket *sock, GIOCondition cond)
 {
 	GIOCondition *ret;
-
-	g_io_add_watch(channel, cond | G_IO_HUP | G_IO_ERR | G_IO_NVAL, g_io_wait_helper, coroutine_self());
+	GSource *src = g_socket_create_source(sock,
+					      cond | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+					      NULL);
+	g_source_set_callback(src, (GSourceFunc)g_io_wait_helper, coroutine_self(), NULL);
+	g_source_attach(src, NULL);
 	ret = coroutine_yield(NULL);
 	return *ret;
 }
 
 
 static GIOCondition g_io_wait_interruptable(struct wait_queue *wait,
-					    GIOChannel *channel,
+					    GSocket *sock,
 					    GIOCondition cond)
 {
 	GIOCondition *ret;
 	gint id;
 
 	wait->context = coroutine_self();
-	id = g_io_add_watch(channel, cond | G_IO_HUP | G_IO_ERR | G_IO_NVAL, g_io_wait_helper, wait->context);
-
+	GSource *src = g_socket_create_source(sock,
+					      cond | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+					      NULL);
+	g_source_set_callback(src, (GSourceFunc)g_io_wait_helper,
+			      wait->context, NULL);
+	id = g_source_attach(src, NULL);
 	wait->waiting = TRUE;
 	ret = coroutine_yield(NULL);
 	wait->waiting = FALSE;
@@ -606,36 +601,46 @@ static int vnc_connection_read_wire(VncConnection *conn, void *data, size_t len)
 {
 	VncConnectionPrivate *priv = conn->priv;
 	int ret;
+	gboolean blocking = FALSE;
 
  reread:
 	if (priv->tls_session) {
 		ret = gnutls_read(priv->tls_session, data, len);
 		if (ret < 0) {
 			if (ret == GNUTLS_E_AGAIN)
-				errno = EAGAIN;
-			else
-				errno = EIO;
+				blocking = TRUE;
 			ret = -1;
 		}
-	} else
-		ret = recv (priv->fd, data, len, 0);
+	} else {
+		GError *error = NULL;
+		ret = g_socket_receive(priv->sock,
+				       data, len,
+				       NULL, &error);
+		if (ret < 0) {
+			if (error) {
+				if (error->code == G_IO_ERROR_WOULD_BLOCK)
+					blocking = TRUE;
+				g_error_free(error);
+			} else {
+				VNC_DEBUG("Read error %s", error->message);
+			}
+			ret = -1;
+		}
+	}
 
 	if (ret == -1) {
-		switch (errno) {
-		case EWOULDBLOCK:
+		if (blocking) {
 			if (priv->wait_interruptable) {
 				if (!g_io_wait_interruptable(&priv->wait,
-							     priv->channel, G_IO_IN)) {
+							     priv->sock, G_IO_IN)) {
 					//VNC_DEBUG("Read blocking interrupted %d", priv->has_error);
 					return -EAGAIN;
 				}
-			} else
-				g_io_wait(priv->channel, G_IO_IN);
-		case EINTR:
+			} else {
+				g_io_wait(priv->sock, G_IO_IN);
+			}
 			goto reread;
-
-		default:
-			VNC_DEBUG("Closing the connection: vnc_connection_read() - errno=%d", errno);
+		} else {
 			priv->has_error = TRUE;
 			return -errno;
 		}
@@ -791,6 +796,7 @@ static void vnc_connection_flush_wire(VncConnection *conn,
 	//VNC_DEBUG("Flush write %p %d", data, datalen);
 	while (offset < datalen) {
 		int ret;
+		gboolean blocking = FALSE;
 
 		if (priv->tls_session) {
 			ret = gnutls_write(priv->tls_session,
@@ -798,22 +804,28 @@ static void vnc_connection_flush_wire(VncConnection *conn,
 					   datalen-offset);
 			if (ret < 0) {
 				if (ret == GNUTLS_E_AGAIN)
-					errno = EAGAIN;
-				else
-					errno = EIO;
+					blocking = TRUE;
 				ret = -1;
 			}
-		} else
-			ret = send (priv->fd,
-				    ptr+offset,
-				    datalen-offset, 0);
+		} else {
+			GError *error = NULL;
+			ret = g_socket_send(priv->sock,
+					    ptr+offset,
+					    datalen-offset,
+					    NULL, &error);
+			if (ret < 0) {
+				if (error) {
+					if (error->code == G_IO_ERROR_WOULD_BLOCK)
+						blocking = TRUE;
+					g_error_free(error);
+				}
+				ret = -1;
+			}
+		}
 		if (ret == -1) {
-			switch (errno) {
-			case EWOULDBLOCK:
-				g_io_wait(priv->channel, G_IO_OUT);
-			case EINTR:
-				continue;
-			default:
+			if (blocking) {
+				g_io_wait(priv->sock, G_IO_OUT);
+			} else {
 				VNC_DEBUG("Closing the connection: vnc_connection_flush %d", errno);
 				priv->has_error = TRUE;
 				return;
@@ -920,12 +932,17 @@ static ssize_t vnc_connection_tls_push(gnutls_transport_ptr_t transport,
 	VncConnection *conn = transport;
 	VncConnectionPrivate *priv = conn->priv;
 	int ret;
+	GError *error = NULL;
 
- retry:
-	ret = write(priv->fd, data, len);
+	ret = g_socket_send(priv->sock, data, len, NULL, &error);
 	if (ret < 0) {
-		if (errno == EINTR)
-			goto retry;
+		if (error) {
+			if (error->code == G_IO_ERROR_WOULD_BLOCK)
+				errno = EAGAIN; /* For gnutls compat */
+			else
+				VNC_DEBUG("Read error %s", error->message);
+			g_error_free(error);
+		}
 		return -1;
 	}
 	return ret;
@@ -938,12 +955,17 @@ static ssize_t vnc_connection_tls_pull(gnutls_transport_ptr_t transport,
 	VncConnection *conn = transport;
 	VncConnectionPrivate *priv = conn->priv;
 	int ret;
+	GError *error = NULL;
 
- retry:
-	ret = read(priv->fd, data, len);
+	ret = g_socket_receive(priv->sock, data, len, NULL, &error);
 	if (ret < 0) {
-		if (errno == EINTR)
-			goto retry;
+		if (error) {
+			if (error->code == G_IO_ERROR_WOULD_BLOCK)
+				errno = EAGAIN; /* For gnutls compat */
+			else
+				VNC_DEBUG("Read error %s", error->message);
+			g_error_free(error);
+		}
 		return -1;
 	}
 	return ret;
@@ -996,7 +1018,7 @@ static guint16 vnc_connection_read_u16(VncConnection *conn)
 {
 	guint16 value = 0;
 	vnc_connection_read(conn, &value, sizeof(value));
-	return ntohs(value);
+	return g_ntohs(value);
 }
 
 /*
@@ -1006,7 +1028,7 @@ static guint32 vnc_connection_read_u32(VncConnection *conn)
 {
 	guint32 value = 0;
 	vnc_connection_read(conn, &value, sizeof(value));
-	return ntohl(value);
+	return g_ntohl(value);
 }
 
 /*
@@ -1016,7 +1038,7 @@ static gint32 vnc_connection_read_s32(VncConnection *conn)
 {
 	gint32 value = 0;
 	vnc_connection_read(conn, &value, sizeof(value));
-	return ntohl(value);
+	return g_ntohl(value);
 }
 
 /*
@@ -1032,7 +1054,7 @@ static void vnc_connection_write_u8(VncConnection *conn, guint8 value)
  */
 static void vnc_connection_write_u16(VncConnection *conn, guint16 value)
 {
-	value = htons(value);
+	value = g_htons(value);
 	vnc_connection_write(conn, &value, sizeof(value));
 }
 
@@ -1041,7 +1063,7 @@ static void vnc_connection_write_u16(VncConnection *conn, guint16 value)
  */
 static void vnc_connection_write_u32(VncConnection *conn, guint32 value)
 {
-	value = htonl(value);
+	value = g_htonl(value);
 	vnc_connection_write(conn, &value, sizeof(value));
 }
 
@@ -1380,7 +1402,7 @@ static void vnc_connection_buffered_write_u8(VncConnection *conn, guint8 value)
  */
 static void vnc_connection_buffered_write_u16(VncConnection *conn, guint16 value)
 {
-	value = htons(value);
+	value = g_htons(value);
 	vnc_connection_buffered_write(conn, &value, 2);
 }
 
@@ -1389,7 +1411,7 @@ static void vnc_connection_buffered_write_u16(VncConnection *conn, guint16 value
  */
 static void vnc_connection_buffered_write_u32(VncConnection *conn, guint32 value)
 {
-	value = htonl(value);
+	value = g_htonl(value);
 	vnc_connection_buffered_write(conn, &value, 4);
 }
 
@@ -1398,7 +1420,7 @@ static void vnc_connection_buffered_write_u32(VncConnection *conn, guint32 value
  */
 static void vnc_connection_buffered_write_s32(VncConnection *conn, gint32 value)
 {
-	value = htonl(value);
+	value = g_htonl(value);
 	vnc_connection_buffered_write(conn, &value, 4);
 }
 
@@ -3012,26 +3034,22 @@ static gboolean vnc_connection_perform_auth_mslogon(VncConnection *conn)
 /*
  * NB, keep in sync with similar method in qemud/remote.c
  */
-static char *vnc_connection_addr_to_string(struct sockaddr_storage *sa, socklen_t salen)
+static char *vnc_connection_addr_to_string(GSocketAddress *addr)
 {
-	char host[NI_MAXHOST], port[NI_MAXSERV];
-	char *addr;
-	int err;
+	GInetSocketAddress *iaddr = G_INET_SOCKET_ADDRESS(addr);
+	guint16 port;
+	GInetAddress *host;
+	gchar *hoststr;
+	gchar *ret;
 
-	if ((err = getnameinfo((struct sockaddr *)sa, salen,
-			       host, sizeof(host),
-			       port, sizeof(port),
-			       NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
-		VNC_DEBUG("Cannot resolve address %d: %s",
-			   err, gai_strerror(err));
-		return NULL;
-	}
+	host = g_inet_socket_address_get_address(iaddr);
+	port = g_inet_socket_address_get_port(iaddr);
+	hoststr = g_inet_address_to_string(host);
+
+	ret = g_strdup_printf("%s;%hu", hoststr, port);
+	g_free(hoststr);
 
-	addr = g_malloc0(strlen(host) + 1 + strlen(port) + 1);
-	strcpy(addr, host);
-	strcat(addr, ";");
-	strcat(addr, port);
-	return addr;
+	return ret;
 }
 
 
@@ -3144,8 +3162,6 @@ static gboolean vnc_connection_perform_auth_sasl(VncConnection *conn)
 	char *serverin = NULL;
 	unsigned int clientoutlen, serverinlen;
 	int err, complete;
-	struct sockaddr_storage sa;
-	socklen_t salen;
 	char *localAddr = NULL, *remoteAddr = NULL;
 	const void *val;
 	sasl_ssf_t ssf;
@@ -3160,6 +3176,7 @@ static gboolean vnc_connection_perform_auth_sasl(VncConnection *conn)
         char *mechlist;
 	const char *mechname;
 	gboolean ret;
+	GSocketAddress *addr;
 
 	/* Sets up the SASL library as a whole */
 	err = sasl_client_init(NULL);
@@ -3171,31 +3188,26 @@ static gboolean vnc_connection_perform_auth_sasl(VncConnection *conn)
 	}
 
 	/* Get local address in form  IPADDR:PORT */
-	salen = sizeof(sa);
-	if (getsockname(priv->fd, (struct sockaddr*)&sa, &salen) < 0) {
-		VNC_DEBUG("failed to get sock address %d (%s)",
-			   errno, strerror(errno));
+	addr = g_socket_get_local_address(priv->sock, NULL);
+	if (!addr) {
+		VNC_DEBUG("failed to get local address");
 		goto error;
 	}
-	if ((sa.ss_family == AF_INET ||
-	     sa.ss_family == AF_INET6) &&
-	    (localAddr = vnc_connection_addr_to_string(&sa, salen)) == NULL)
+	if ((g_socket_address_get_family(addr) == G_SOCKET_FAMILY_IPV4 ||
+	     g_socket_address_get_family(addr) == G_SOCKET_FAMILY_IPV6) &&
+	    (localAddr = vnc_connection_addr_to_string(addr)) == NULL)
 		goto error;
 
 	/* Get remote address in form  IPADDR:PORT */
-	salen = sizeof(sa);
-	if (getpeername(priv->fd, (struct sockaddr*)&sa, &salen) < 0) {
-		VNC_DEBUG("failed to get peer address %d (%s)",
-			   errno, strerror(errno));
-		g_free(localAddr);
+	addr = g_socket_get_remote_address(priv->sock, NULL);
+	if (!addr) {
+		VNC_DEBUG("failed to get peer address");
 		goto error;
 	}
-	if ((sa.ss_family == AF_INET ||
-	     sa.ss_family == AF_INET6) &&
-	    (remoteAddr = vnc_connection_addr_to_string(&sa, salen)) == NULL) {
-		g_free(localAddr);
+	if ((g_socket_address_get_family(addr) == G_SOCKET_FAMILY_IPV4 ||
+	     g_socket_address_get_family(addr) == G_SOCKET_FAMILY_IPV6) &&
+	    (remoteAddr = vnc_connection_addr_to_string(addr)) == NULL)
 		goto error;
-	}
 
 	VNC_DEBUG("Client SASL new host:'%s' local:'%s' remote:'%s'", priv->host, localAddr, remoteAddr);
 
@@ -3567,9 +3579,9 @@ static gboolean vnc_connection_start_tls(VncConnection *conn, int anonTLS)
 		if (!gnutls_error_is_fatal(ret)) {
 			VNC_DEBUG("Handshake was blocking");
 			if (!gnutls_record_get_direction(priv->tls_session))
-				g_io_wait(priv->channel, G_IO_IN);
+				g_io_wait(priv->sock, G_IO_IN);
 			else
-				g_io_wait(priv->channel, G_IO_OUT);
+				g_io_wait(priv->sock, G_IO_OUT);
 			goto retry;
 		}
 		VNC_DEBUG("Handshake failed %s", gnutls_strerror(ret));
@@ -4167,14 +4179,12 @@ static void vnc_connection_close(VncConnection *conn)
 		sasl_dispose (&priv->saslconn);
 #endif
 
-	if (priv->channel) {
-		g_io_channel_unref(priv->channel);
-		priv->channel = NULL;
+	if (priv->sock) {
+		g_object_unref(priv->sock);
+		priv->sock = NULL;
 	}
-	if (priv->fd != -1) {
-		close(priv->fd);
+	if (priv->fd != -1)
 		priv->fd = -1;
-	}
 
 	if (priv->host) {
 		g_free(priv->host);
@@ -4239,7 +4249,9 @@ void vnc_connection_shutdown(VncConnection *conn)
 		priv->open_id = 0;
 	}
 
-	close(priv->fd);
+	g_socket_close(priv->sock, NULL);
+	g_object_unref(priv->sock);
+	priv->sock = NULL;
 	priv->fd = -1;
 	priv->has_error = 1;
 	VNC_DEBUG("Waking up couroutine to shutdown gracefully");
@@ -4255,6 +4267,8 @@ gboolean vnc_connection_is_open(VncConnection *conn)
 
 	if (priv->fd != -1)
 		return TRUE;
+	if (priv->sock != NULL)
+		return TRUE;
 	if (priv->host)
 		return TRUE;
 	return FALSE;
@@ -4363,124 +4377,103 @@ static gboolean vnc_connection_initialize(VncConnection *conn)
 	return !vnc_connection_has_error(conn);
 }
 
-static gboolean vnc_connection_set_nonblock(int fd)
+
+static gboolean vnc_connection_open_fd_internal(VncConnection *conn)
 {
-#ifndef WIN32
-	int flags;
-	if ((flags = fcntl(fd, F_GETFL)) < 0) {
-		VNC_DEBUG ("Failed to fcntl()");
-		return FALSE;
-	}
-	flags |= O_NONBLOCK;
-	if (fcntl(fd, F_SETFL, flags) < 0) {
-		VNC_DEBUG ("Failed to fcntl()");
-		return FALSE;
-	}
+	VncConnectionPrivate *priv = conn->priv;
 
-#else /* WIN32 */
-	unsigned long flag = 1;
+	VNC_DEBUG("Connecting to FD %d", priv->fd);
 
-	/* This is actually Gnulib's replacement rpl_ioctl function.
-	 * We can't call ioctlsocket directly in any case.
-	 */
-	if (ioctl (fd, FIONBIO, (void *) &flag) == -1) {
-		VNC_DEBUG ("Failed to set nonblocking flag, winsock error = %d",
-			    WSAGetLastError ());
+	if (!(priv->sock = g_socket_new_from_fd(priv->fd, NULL))) {
+		VNC_DEBUG("Failed to open socket from fd %d", priv->fd);
 		return FALSE;
 	}
-#endif /* WIN32 */
 
-	return TRUE;
+	g_socket_set_blocking(priv->sock, FALSE);
+
+	return !vnc_connection_has_error(conn);
 }
 
-static gboolean vnc_connection_open_fd_internal(VncConnection *conn)
+static GSocket *vnc_connection_connect_socket(GSocketAddress *sockaddr,
+					      GError **error)
 {
-	VncConnectionPrivate *priv = conn->priv;
+	GSocket *sock = g_socket_new(g_socket_address_get_family(sockaddr),
+				     G_SOCKET_TYPE_STREAM,
+				     G_SOCKET_PROTOCOL_DEFAULT,
+				     error);
 
-	VNC_DEBUG("Connecting to FD %d", priv->fd);
-
-	if (!vnc_connection_set_nonblock(priv->fd))
-		return FALSE;
+	if (!sock)
+		return NULL;
 
-	if (!(priv->channel =
-#ifdef WIN32
-	      g_io_channel_win32_new_socket(_get_osfhandle(priv->fd))
-#else
-	      g_io_channel_unix_new(priv->fd)
-#endif
-	      )) {
-		VNC_DEBUG ("Failed to g_io_channel_unix_new()");
-		return FALSE;
+	g_socket_set_blocking(sock, FALSE);
+	if (!g_socket_connect(sock, sockaddr, NULL, error)) {
+		if (*error && (*error)->code == G_IO_ERROR_PENDING) {
+			g_error_free(*error);
+			*error = NULL;
+			VNC_DEBUG("Socket pending");
+                        g_io_wait(sock, G_IO_OUT|G_IO_ERR|G_IO_HUP);
+
+			if (!g_socket_check_connect_result(sock, error)) {
+				VNC_DEBUG("Failed to connect %s", (*error)->message);
+				g_object_unref(sock);
+				return NULL;
+			}
+		} else {
+			VNC_DEBUG("Socket error: %s", *error ? (*error)->message : "unknown");
+			g_object_unref(sock);
+			return NULL;
+		}
 	}
 
-	return !vnc_connection_has_error(conn);
+	VNC_DEBUG("Finally connected");
+
+	return sock;
 }
 
 static gboolean vnc_connection_open_host_internal(VncConnection *conn)
 {
 	VncConnectionPrivate *priv = conn->priv;
-        struct addrinfo *ai, *runp, hints;
-        int ret;
+	GSocketConnectable *addr;
+	GSocketAddressEnumerator *enumerator;
+	GSocketAddress *sockaddr;
+	GError *conn_error = NULL;
+	GSocket *sock = NULL;
+	int port = atoi(priv->port);
 
         VNC_DEBUG("Resolving host %s %s", priv->host, priv->port);
-        memset (&hints, '\0', sizeof (hints));
-        hints.ai_flags = AI_ADDRCONFIG;
-        hints.ai_socktype = SOCK_STREAM;
-        hints.ai_protocol = IPPROTO_TCP;
 
-        if ((ret = getaddrinfo(priv->host, priv->port, &hints, &ai)) != 0) {
-		VNC_DEBUG ("Failed to resolve hostname");
-		return FALSE;
-	}
+	addr = g_network_address_new(priv->host, port);
 
-        runp = ai;
-        while (runp != NULL) {
-                int fd;
-                GIOChannel *chan;
+	enumerator = g_socket_connectable_enumerate (addr);
+	g_object_unref (addr);
 
-		if ((fd = socket(runp->ai_family, runp->ai_socktype,
-				 runp->ai_protocol)) < 0) {
-			VNC_DEBUG ("Failed to socket()");
-			break;
-		}
-
-                VNC_DEBUG("Trying socket %d", fd);
-		if (!vnc_connection_set_nonblock(fd))
-			break;
+	/* Try each sockaddr until we succeed. Record the first
+	 * connection error, but not any further ones (since they'll probably
+	 * be basically the same as the first).
+	 */
+	while (!sock &&
+	       (sockaddr = g_socket_address_enumerator_next(enumerator, NULL, &conn_error))) {
+		VNC_DEBUG("Trying one socket");
+		sock = vnc_connection_connect_socket(sockaddr, &conn_error);
+		g_object_unref(sockaddr);
+	}
+	g_object_unref(enumerator);
+	if (sock) {
+		/* We couldn't connect to the first address, but we succeeded
+		 * in connecting to a later address.
+		 */
+		if (conn_error)
+			g_error_free (conn_error);
+		priv->sock = sock;
+		return TRUE;
+	} else if (conn_error) {
+		/* Either the initial lookup failed, or else the caller
+		 * cancelled us.
+		 */
+		if (conn_error)
+			g_error_free (conn_error);
+	}
 
-                if (!(chan =
-#ifdef WIN32
-		      g_io_channel_win32_new_socket(_get_osfhandle(fd))
-#else
-		      g_io_channel_unix_new(fd)
-#endif
-		      )) {
-                        close(fd);
-                        VNC_DEBUG ("Failed to g_io_channel_unix_new()");
-                        break;
-                }
-
-        reconnect:
-                /* FIXME: Better handle EINPROGRESS/EISCONN return values,
-                   as explained in connect(2) man page */
-                if ((connect(fd, runp->ai_addr, runp->ai_addrlen) == 0) ||
-		    errno == EISCONN) {
-                        priv->channel = chan;
-                        priv->fd = fd;
-                        freeaddrinfo(ai);
-                        return !vnc_connection_has_error(conn);
-                }
-                if (errno == EINPROGRESS ||
-                    errno == EWOULDBLOCK) {
-                        g_io_wait(chan, G_IO_OUT|G_IO_ERR|G_IO_HUP);
-                        goto reconnect;
-                }
-                VNC_DEBUG ("Connect failed with errno = %d, try next addr", errno);
-                close(fd);
-                g_io_channel_unref(chan);
-                runp = runp->ai_next;
-        }
-        freeaddrinfo (ai);
 	return FALSE;
 }
 
diff --git a/src/vncdisplay.c b/src/vncdisplay.c
index 175456a..a6b9467 100644
--- a/src/vncdisplay.c
+++ b/src/vncdisplay.c
@@ -40,13 +40,6 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
-#ifdef HAVE_WINSOCK2_H
-#include <winsock2.h>
-#endif
-
-static void winsock_startup (void);
-static void winsock_cleanup (void);
-
 #define VNC_DISPLAY_GET_PRIVATE(obj) \
       (G_TYPE_INSTANCE_GET_PRIVATE((obj), VNC_TYPE_DISPLAY, VncDisplayPrivate))
 
@@ -259,7 +252,6 @@ vnc_display_set_property (GObject      *object,
 
 GtkWidget *vnc_display_new(void)
 {
-	winsock_startup ();
 	return GTK_WIDGET(g_object_new(VNC_TYPE_DISPLAY, NULL));
 }
 
@@ -1527,8 +1519,6 @@ static void vnc_display_finalize (GObject *obj)
 	vnc_display_keyval_free_entries();
 
 	G_OBJECT_CLASS (vnc_display_parent_class)->finalize (obj);
-
-	winsock_cleanup();
 }
 
 static void vnc_display_class_init(VncDisplayClass *klass)
@@ -2224,49 +2214,6 @@ vnc_display_request_update(VncDisplay *obj)
 							 vnc_connection_get_width(obj->priv->conn));
 }
 
-#ifdef WIN32
-
-/* On Windows, we must call WSAStartup before using any sockets and we
- * must call WSACleanup afterwards.  And we have to balance any calls
- * to WSAStartup with a corresponding call to WSACleanup.
- *
- * Note that Wine lets you do socket calls anyway, but real Windows
- * doesn't. (http://bugs.winehq.org/show_bug.cgi?id=11965)
- */
-
-static void
-winsock_startup (void)
-{
-	WORD winsock_version, err;
-	WSADATA winsock_data;
-
-	/* http://msdn2.microsoft.com/en-us/library/ms742213.aspx */
-	winsock_version = MAKEWORD (2, 2);
-	err = WSAStartup (winsock_version, &winsock_data);
-	if (err != 0)
-		VNC_DEBUG ("ignored error %d from WSAStartup", err);
-}
-
-static void
-winsock_cleanup (void)
-{
-	WSACleanup ();
-}
-
-#else /* !WIN32 */
-
-static void
-winsock_startup (void)
-{
-}
-
-static void
-winsock_cleanup (void)
-{
-}
-
-#endif /* !WIN32 */
-
 /*
  * Local variables:
  *  c-indent-level: 8
-- 
1.7.1.1



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]