[evolution-data-server/camel-socks-proxy: 91/94] Do name resolution inside camel_tcp_stream_connect()



commit 253e3552f615a65637e95d74067b45721e57fea0
Author: Federico Mena Quintero <federico novell com>
Date:   Fri Jul 9 14:12:06 2010 -0500

    Do name resolution inside camel_tcp_stream_connect()
    
    This function and the associated vmethod used to take a struct addrinfo *.
    However, this doesn't let us have SOCKS4a or SOCKS5 proxies that do name
    resolution in the proxy.  So, now the main camel_tcp_stream_connect() takes
    a hostname and service name, and implementations do name resolution
    by themselves.  Later we will modify the proxy code to do name resolution
    in the proxy.
    
    We allow passing a fallback port to camel_tcp_stream_connect(), which
    is used by Camel's providers when the system's services database
    (/etc/services) doesn't have an entry for a particular service name.
    If getaddrinfo() can't find the service name, then we use a
    fallback/hardcoded port number.  See bgo#267898
    
    Also, camel_tcp_stream_connect() now returns a CamelException.  This
    will let us properly return errors from the camel_getaddrinfo() stage.
    
    Signed-off-by: Federico Mena Quintero <federico novell com>

 camel/camel-tcp-stream-raw.c |   53 +++++++++++++++++++++++++++++++++--------
 camel/camel-tcp-stream-ssl.c |   53 ++++++++++++++++++++++++++++++++++--------
 camel/camel-tcp-stream.c     |   17 ++++++++----
 camel/camel-tcp-stream.h     |    5 ++-
 4 files changed, 99 insertions(+), 29 deletions(-)
---
diff --git a/camel/camel-tcp-stream-raw.c b/camel/camel-tcp-stream-raw.c
index 89a29e5..0f69050 100644
--- a/camel/camel-tcp-stream-raw.c
+++ b/camel/camel-tcp-stream-raw.c
@@ -61,7 +61,7 @@ static gssize stream_write (CamelStream *stream, const gchar *buffer, gsize n);
 static gint stream_flush  (CamelStream *stream);
 static gint stream_close  (CamelStream *stream);
 
-static gint stream_connect (CamelTcpStream *stream, struct addrinfo *host);
+static gint stream_connect (CamelTcpStream *stream, const char *host, const char *service, gint fallback_port, CamelException *ex);
 static gint stream_getsockopt (CamelTcpStream *stream, CamelSockOptData *data);
 static gint stream_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data);
 static struct sockaddr *stream_get_local_address (CamelTcpStream *stream, socklen_t *len);
@@ -439,7 +439,7 @@ connect_to_socks4_proxy (const gchar *proxy_host, gint proxy_port, struct addrin
 		goto error;
 	}
 
-	g_assert (connect_addr->ai_addr->sa_family == AF_INET); /* FIXME: what to do about IPv6?  Are we just screwed with SOCKS4? */
+	g_assert (connect_addr->ai_addr->sa_family == AF_INET); /* FMQ: check for AF_INET in the caller */
 	sin = (struct sockaddr_in *) connect_addr->ai_addr;
 
 	request[0] = 0x04;				/* SOCKS4 */
@@ -476,29 +476,60 @@ out:
 }
 
 static gint
-stream_connect (CamelTcpStream *stream, struct addrinfo *host)
+stream_connect (CamelTcpStream *stream, const char *host, const char *service, gint fallback_port, CamelException *ex)
 {
 	CamelTcpStreamRaw *raw = CAMEL_TCP_STREAM_RAW (stream);
+	struct addrinfo *addr, *ai;
+	struct addrinfo hints;
+	CamelException my_ex;
+	gint retval;
 	const gchar *proxy_host;
 	gint proxy_port;
 
-	g_return_val_if_fail (host != NULL, -1);
+	memset (&hints, 0, sizeof (hints));
+	hints.ai_socktype = SOCK_STREAM;
+	hints.ai_family = PF_UNSPEC;
+
+	camel_exception_init (&my_ex);
+	addr = camel_getaddrinfo (host, service, &hints, &my_ex);
+	if (addr == NULL && fallback_port != 0 && camel_exception_get_id (&my_ex) != CAMEL_EXCEPTION_USER_CANCEL) {
+		char str_port[16];
+
+		camel_exception_clear (&my_ex);
+		sprintf (str_port, "%d", fallback_port);
+		addr = camel_getaddrinfo (host, str_port, &hints, &my_ex);
+	}
+
+	if (addr == NULL) {
+		camel_exception_xfer (ex, &my_ex);
+		return -1;
+	}
 
 	camel_tcp_stream_peek_socks_proxy (stream, &proxy_host, &proxy_port);
 
-	while (host) {
+	ai = addr;
+
+	while (ai) {
 		if (proxy_host)
-			raw->sockfd = connect_to_socks4_proxy (proxy_host, proxy_port, host);
+			raw->sockfd = connect_to_socks4_proxy (proxy_host, proxy_port, ai);
 		else
-			raw->sockfd = socket_connect (host);
+			raw->sockfd = socket_connect (ai);
 
-		if (raw->sockfd != -1)
-			return 0;
+		if (raw->sockfd != -1) {
+			retval = 0;
+			goto out;
+		}
 
-		host = host->ai_next;
+		ai = ai->ai_next;
 	}
 
-	return -1;
+	retval = -1;
+
+out:
+
+	camel_freeaddrinfo (addr);
+
+	return retval;
 }
 
 static gint
diff --git a/camel/camel-tcp-stream-ssl.c b/camel/camel-tcp-stream-ssl.c
index 132c977..e48fdf0 100644
--- a/camel/camel-tcp-stream-ssl.c
+++ b/camel/camel-tcp-stream-ssl.c
@@ -79,7 +79,7 @@ static gint stream_close  (CamelStream *stream);
 
 static PRFileDesc *enable_ssl (CamelTcpStreamSSL *ssl, PRFileDesc *fd);
 
-static gint stream_connect    (CamelTcpStream *stream, struct addrinfo *host);
+static gint stream_connect    (CamelTcpStream *stream, const char *host, const char *service, gint fallback_port, CamelException *ex);
 static gint stream_getsockopt (CamelTcpStream *stream, CamelSockOptData *data);
 static gint stream_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data);
 static struct sockaddr *stream_get_local_address (CamelTcpStream *stream, socklen_t *len);
@@ -1300,7 +1300,7 @@ connect_to_socks4_proxy (CamelTcpStreamSSL *ssl, const gchar *proxy_host, gint p
 		goto error;
 	}
 
-	g_assert (connect_addr->ai_addr->sa_family == AF_INET); /* FIXME: what to do about IPv6?  Are we just screwed with SOCKS4? */
+	g_assert (connect_addr->ai_addr->sa_family == AF_INET); /* FMQ: check for AF_INET in the caller */
 	sin = (struct sockaddr_in *) connect_addr->ai_addr;
 
 	request[0] = 0x04;				/* SOCKS4 */
@@ -1368,27 +1368,60 @@ out:
 }
 
 static gint
-stream_connect(CamelTcpStream *stream, struct addrinfo *host)
+stream_connect(CamelTcpStream *stream, const char *host, const char *service, gint fallback_port, CamelException *ex)
 {
 	CamelTcpStreamSSL *ssl = CAMEL_TCP_STREAM_SSL (stream);
+	struct addrinfo *addr, *ai;
+	struct addrinfo hints;
+	CamelException my_ex;
+	gint retval;
 	const gchar *proxy_host;
 	gint proxy_port;
 
+	memset (&hints, 0, sizeof (hints));
+	hints.ai_socktype = SOCK_STREAM;
+	hints.ai_family = PF_UNSPEC;
+
+	camel_exception_init (&my_ex);
+	addr = camel_getaddrinfo (host, service, &hints, &my_ex);
+	if (addr == NULL && fallback_port != 0 && camel_exception_get_id (&my_ex) != CAMEL_EXCEPTION_USER_CANCEL) {
+		char str_port[16];
+
+		camel_exception_clear (&my_ex);
+		sprintf (str_port, "%d", fallback_port);
+		addr = camel_getaddrinfo (host, str_port, &hints, &my_ex);
+	}
+
+	if (addr == NULL) {
+		camel_exception_xfer (ex, &my_ex);
+		return -1;
+	}
+
 	camel_tcp_stream_peek_socks_proxy (stream, &proxy_host, &proxy_port);
 
-	while (host) {
+	ai = addr;
+
+	while (ai) {
 		if (proxy_host)
-			ssl->priv->sockfd = connect_to_socks4_proxy (ssl, proxy_host, proxy_port, host);
+			ssl->priv->sockfd = connect_to_socks4_proxy (ssl, proxy_host, proxy_port, ai);
 		else
-			ssl->priv->sockfd = socket_connect (stream, host, TRUE);
+			ssl->priv->sockfd = socket_connect (stream, ai, TRUE);
 
-		if (ssl->priv->sockfd)
-			return 0;
+		if (ssl->priv->sockfd) {
+			retval = 0;
+			goto out;
+		}
 
-		host = host->ai_next;
+		ai = ai->ai_next;
 	}
 
-	return -1;
+	retval = -1;
+
+out:
+
+	camel_freeaddrinfo (addr);
+
+	return retval;
 }
 
 static gint
diff --git a/camel/camel-tcp-stream.c b/camel/camel-tcp-stream.c
index 03707e8..f61e179 100644
--- a/camel/camel-tcp-stream.c
+++ b/camel/camel-tcp-stream.c
@@ -42,7 +42,7 @@ static CamelStreamClass *parent_class = NULL;
 /* Returns the class for a CamelTcpStream */
 #define CTS_CLASS(so) CAMEL_TCP_STREAM_CLASS (CAMEL_OBJECT_GET_CLASS(so))
 
-static gint tcp_connect    (CamelTcpStream *stream, struct addrinfo *host);
+static gint tcp_connect    (CamelTcpStream *stream, const char *host, const char *service, gint fallback_port, CamelException *ex);
 static gint tcp_getsockopt (CamelTcpStream *stream, CamelSockOptData *data);
 static gint tcp_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data);
 static struct sockaddr *tcp_get_local_address (CamelTcpStream *stream, socklen_t *len);
@@ -108,7 +108,7 @@ camel_tcp_stream_get_type (void)
 }
 
 static gint
-tcp_connect (CamelTcpStream *stream, struct addrinfo *host)
+tcp_connect (CamelTcpStream *stream, const char *host, const char *service, gint fallback_port, CamelException *ex)
 {
 	w(g_warning ("CamelTcpStream::connect called on default implementation"));
 	return -1;
@@ -117,19 +117,24 @@ tcp_connect (CamelTcpStream *stream, struct addrinfo *host)
 /**
  * camel_tcp_stream_connect:
  * @stream: a #CamelTcpStream object
- * @host: a linked list of addrinfo structures to try to connect, in
- * the order of most likely to least likely to work.
+ * @host: Hostname for connection
+ * @service: Service name or port number in string form
+ * @fallback_port: Port number to retry if @service is not present in the system's services database, or 0 to avoid retrying.
+ * @ex: a #CamelException
  *
  * Create a socket and connect based upon the data provided.
  *
  * Returns: %0 on success or %-1 on fail
  **/
 gint
-camel_tcp_stream_connect (CamelTcpStream *stream, struct addrinfo *host)
+camel_tcp_stream_connect (CamelTcpStream *stream, const char *host, const char *service, gint fallback_port, CamelException *ex)
 {
 	g_return_val_if_fail (CAMEL_IS_TCP_STREAM (stream), -1);
+	g_return_val_if_fail (host != NULL, -1);
+	g_return_val_if_fail (service != NULL, -1);
+	g_return_val_if_fail (ex == NULL || !camel_exception_is_set (ex), -1);
 
-	return CTS_CLASS (stream)->connect (stream, host);
+	return CTS_CLASS (stream)->connect (stream, host, service, fallback_port, ex);
 }
 
 static gint
diff --git a/camel/camel-tcp-stream.h b/camel/camel-tcp-stream.h
index a02cbb6..b3e5782 100644
--- a/camel/camel-tcp-stream.h
+++ b/camel/camel-tcp-stream.h
@@ -37,6 +37,7 @@
 #endif
 #include <unistd.h>
 
+#include <camel/camel-exception.h>
 #include <camel/camel-stream.h>
 
 #define CAMEL_TCP_STREAM_TYPE     (camel_tcp_stream_get_type ())
@@ -100,7 +101,7 @@ typedef struct {
 	CamelStreamClass parent_class;
 
 	/* Virtual methods */
-	gint (*connect)    (CamelTcpStream *stream, struct addrinfo *host);
+	gint (*connect)    (CamelTcpStream *stream, const char *host, const char *service, gint fallback_port, CamelException *ex);
 	gint (*getsockopt) (CamelTcpStream *stream, CamelSockOptData *data);
 	gint (*setsockopt) (CamelTcpStream *stream, const CamelSockOptData *data);
 
@@ -112,7 +113,7 @@ typedef struct {
 CamelType camel_tcp_stream_get_type (void);
 
 /* public methods */
-gint         camel_tcp_stream_connect    (CamelTcpStream *stream, struct addrinfo *host);
+gint         camel_tcp_stream_connect    (CamelTcpStream *stream, const char *host, const char *service, gint fallback_port, CamelException *ex);
 gint         camel_tcp_stream_getsockopt (CamelTcpStream *stream, CamelSockOptData *data);
 gint         camel_tcp_stream_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data);
 



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