[evolution-data-server/camel-socks-proxy] Make CamelTcpStreamRaw use PRFileDesc internally
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server/camel-socks-proxy] Make CamelTcpStreamRaw use PRFileDesc internally
- Date: Thu, 15 Jul 2010 21:15:07 +0000 (UTC)
commit d205d36653199d71071cbf0db5a87a38284bae6a
Author: Federico Mena Quintero <federico novell com>
Date: Thu Jul 15 15:03:25 2010 -0500
Make CamelTcpStreamRaw use PRFileDesc internally
This is cut&pasted from CamelTcpStreamSSL, with the SSL bits removed.
This will let us make CamelTcpStreamSSL actually derive from
CamelTcpStreamRaw and just slap the SSL bits on top.
This also removes camel_tcp_stream_raw_get_fd(), in favor of the general
camel_tcp_stream_get_file_desc(), which only the imapx provider uses.
Signed-off-by: Federico Mena Quintero <federico novell com>
camel/camel-tcp-stream-raw.c | 719 ++++++++++++++++++----------
camel/camel-tcp-stream-raw.h | 2 -
camel/providers/imapx/camel-imapx-server.c | 53 +--
camel/providers/imapx/camel-imapx-server.h | 1 -
4 files changed, 479 insertions(+), 296 deletions(-)
---
diff --git a/camel/camel-tcp-stream-raw.c b/camel/camel-tcp-stream-raw.c
index 851d15a..5c7aae5 100644
--- a/camel/camel-tcp-stream-raw.c
+++ b/camel/camel-tcp-stream-raw.c
@@ -32,32 +32,25 @@
#include <sys/time.h>
#include <sys/types.h>
+#include <nspr.h>
+#include <prio.h>
+#include <prerror.h>
+#include <prerr.h>
+
#include "camel-file-utils.h"
#include "camel-net-utils.h"
#include "camel-operation.h"
#include "camel-tcp-stream-raw.h"
+#define d(x)
+
+#define IO_TIMEOUT (PR_TicksPerSecond() * 4 * 60)
+#define CONNECT_TIMEOUT (PR_TicksPerSecond () * 4 * 60)
+
typedef struct _CamelTcpStreamRawPrivate {
- gint sockfd;
-#ifdef G_OS_WIN32
- gint is_nonblocking;
-#endif
+ PRFileDesc *sockfd;
} CamelTcpStreamRawPrivate;
-#ifndef G_OS_WIN32
-#define SOCKET_ERROR_CODE() errno
-#define SOCKET_CLOSE(fd) close (fd)
-#define SOCKET_ERROR_IS_EINPROGRESS() (errno == EINPROGRESS)
-#define SOCKET_ERROR_IS_EINTR() (errno == EINTR)
-#else
-#define SOCKET_ERROR_CODE() WSAGetLastError ()
-#define SOCKET_CLOSE(fd) closesocket (fd)
-#define SOCKET_ERROR_IS_EINPROGRESS() (WSAGetLastError () == WSAEWOULDBLOCK)
-#define SOCKET_ERROR_IS_EINTR() 0 /* No WSAEINTR in WinSock2 */
-#undef ETIMEDOUT /* In case pthreads-win32's <pthread.h> bogusly defined it */
-#define ETIMEDOUT EAGAIN
-#endif
-
static CamelTcpStreamClass *parent_class = NULL;
/* Returns the class for a CamelTcpStreamRaw */
@@ -73,6 +66,7 @@ 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);
static struct sockaddr *stream_get_remote_address (CamelTcpStream *stream, socklen_t *len);
+static PRFileDesc *stream_get_file_desc (CamelTcpStream *stream);
static void
camel_tcp_stream_raw_class_init (CamelTcpStreamRawClass *camel_tcp_stream_raw_class)
@@ -95,6 +89,7 @@ camel_tcp_stream_raw_class_init (CamelTcpStreamRawClass *camel_tcp_stream_raw_cl
camel_tcp_stream_class->setsockopt = stream_setsockopt;
camel_tcp_stream_class->get_local_address = stream_get_local_address;
camel_tcp_stream_class->get_remote_address = stream_get_remote_address;
+ camel_tcp_stream_class->get_file_desc = stream_get_file_desc;
}
static void
@@ -106,7 +101,7 @@ camel_tcp_stream_raw_init (gpointer object, gpointer klass)
stream->priv = g_new0 (CamelTcpStreamRawPrivate, 1);
priv = stream->priv;
- priv->sockfd = -1;
+ priv->sockfd = NULL;
}
static void
@@ -115,8 +110,10 @@ camel_tcp_stream_raw_finalize (CamelObject *object)
CamelTcpStreamRaw *raw = CAMEL_TCP_STREAM_RAW (object);
CamelTcpStreamRawPrivate *priv = raw->priv;
- if (priv->sockfd != -1)
- SOCKET_CLOSE (priv->sockfd);
+ if (priv->sockfd != NULL) {
+ PR_Shutdown (priv->sockfd, PR_SHUTDOWN_BOTH);
+ PR_Close (priv->sockfd);
+ }
g_free (raw->priv);
raw->priv = NULL;
@@ -259,13 +256,258 @@ camel_tcp_stream_raw_new (void)
return CAMEL_STREAM (stream);
}
+static void
+set_errno (gint code)
+{
+ /* FIXME: this should handle more. */
+ switch (code) {
+ case PR_INVALID_ARGUMENT_ERROR:
+ errno = EINVAL;
+ break;
+ case PR_PENDING_INTERRUPT_ERROR:
+ errno = EINTR;
+ break;
+ case PR_IO_PENDING_ERROR:
+ errno = EAGAIN;
+ break;
+#ifdef EWOULDBLOCK
+ case PR_WOULD_BLOCK_ERROR:
+ errno = EWOULDBLOCK;
+ break;
+#endif
+#ifdef EINPROGRESS
+ case PR_IN_PROGRESS_ERROR:
+ errno = EINPROGRESS;
+ break;
+#endif
+#ifdef EALREADY
+ case PR_ALREADY_INITIATED_ERROR:
+ errno = EALREADY;
+ break;
+#endif
+#ifdef EHOSTUNREACH
+ case PR_NETWORK_UNREACHABLE_ERROR:
+ errno = EHOSTUNREACH;
+ break;
+#endif
+#ifdef ECONNREFUSED
+ case PR_CONNECT_REFUSED_ERROR:
+ errno = ECONNREFUSED;
+ break;
+#endif
+#ifdef ETIMEDOUT
+ case PR_CONNECT_TIMEOUT_ERROR:
+ case PR_IO_TIMEOUT_ERROR:
+ errno = ETIMEDOUT;
+ break;
+#endif
+#ifdef ENOTCONN
+ case PR_NOT_CONNECTED_ERROR:
+ errno = ENOTCONN;
+ break;
+#endif
+#ifdef ECONNRESET
+ case PR_CONNECT_RESET_ERROR:
+ errno = ECONNRESET;
+ break;
+#endif
+ case PR_IO_ERROR:
+ default:
+ errno = EIO;
+ break;
+ }
+}
+
+static gssize
+read_from_prfd (PRFileDesc *fd, gchar *buffer, gsize n)
+{
+ PRFileDesc *cancel_fd;
+ gssize nread;
+
+ if (camel_operation_cancel_check (NULL)) {
+ errno = EINTR;
+ return -1;
+ }
+
+ cancel_fd = camel_operation_cancel_prfd (NULL);
+ if (cancel_fd == NULL) {
+ do {
+ nread = PR_Read (fd, buffer, n);
+ if (nread == -1)
+ set_errno (PR_GetError ());
+ } while (nread == -1 && (PR_GetError () == PR_PENDING_INTERRUPT_ERROR ||
+ PR_GetError () == PR_IO_PENDING_ERROR ||
+ PR_GetError () == PR_WOULD_BLOCK_ERROR));
+ } else {
+ PRSocketOptionData sockopts;
+ PRPollDesc pollfds[2];
+ gboolean nonblock;
+ gint error;
+
+ /* get O_NONBLOCK options */
+ sockopts.option = PR_SockOpt_Nonblocking;
+ PR_GetSocketOption (fd, &sockopts);
+ sockopts.option = PR_SockOpt_Nonblocking;
+ nonblock = sockopts.value.non_blocking;
+ sockopts.value.non_blocking = TRUE;
+ PR_SetSocketOption (fd, &sockopts);
+
+ pollfds[0].fd = fd;
+ pollfds[0].in_flags = PR_POLL_READ;
+ pollfds[1].fd = cancel_fd;
+ pollfds[1].in_flags = PR_POLL_READ;
+
+ do {
+ PRInt32 res;
+
+ pollfds[0].out_flags = 0;
+ pollfds[1].out_flags = 0;
+ nread = -1;
+
+ res = PR_Poll(pollfds, 2, IO_TIMEOUT);
+ if (res == -1)
+ set_errno(PR_GetError());
+ else if (res == 0) {
+#ifdef ETIMEDOUT
+ errno = ETIMEDOUT;
+#else
+ errno = EIO;
+#endif
+ goto failed;
+ } else if (pollfds[1].out_flags == PR_POLL_READ) {
+ errno = EINTR;
+ goto failed;
+ } else {
+ do {
+ nread = PR_Read (fd, buffer, n);
+ if (nread == -1)
+ set_errno (PR_GetError ());
+ } while (nread == -1 && PR_GetError () == PR_PENDING_INTERRUPT_ERROR);
+ }
+ } while (nread == -1 && (PR_GetError () == PR_PENDING_INTERRUPT_ERROR ||
+ PR_GetError () == PR_IO_PENDING_ERROR ||
+ PR_GetError () == PR_WOULD_BLOCK_ERROR));
+
+ /* restore O_NONBLOCK options */
+ failed:
+ error = errno;
+ sockopts.option = PR_SockOpt_Nonblocking;
+ sockopts.value.non_blocking = nonblock;
+ PR_SetSocketOption (fd, &sockopts);
+ errno = error;
+ }
+
+ return nread;
+}
+
static gssize
stream_read (CamelStream *stream, gchar *buffer, gsize n)
{
CamelTcpStreamRaw *raw = CAMEL_TCP_STREAM_RAW (stream);
CamelTcpStreamRawPrivate *priv = raw->priv;
+ gssize result;
+
+ d (g_print ("TcpStreamRaw %p: reading %" G_GSIZE_FORMAT " bytes...\n", ssl, n));
- return camel_read_socket (priv->sockfd, buffer, n);
+ result = read_from_prfd (priv->sockfd, buffer, n);
+
+ d (g_print ("TcpStreamRaw %p: read %" G_GSSIZE_FORMAT " bytes, errno = %d\n", ssl, result, result == -1 ? errno : 0));
+
+ return result;
+}
+
+static gssize
+write_to_prfd (PRFileDesc *fd, const gchar *buffer, gsize n)
+{
+ gssize w, written = 0;
+ PRFileDesc *cancel_fd;
+
+ if (camel_operation_cancel_check (NULL)) {
+ errno = EINTR;
+ return -1;
+ }
+
+ cancel_fd = camel_operation_cancel_prfd (NULL);
+ if (cancel_fd == NULL) {
+ do {
+ do {
+ w = PR_Write (fd, buffer + written, n - written);
+ if (w == -1)
+ set_errno (PR_GetError ());
+ } while (w == -1 && (PR_GetError () == PR_PENDING_INTERRUPT_ERROR ||
+ PR_GetError () == PR_IO_PENDING_ERROR ||
+ PR_GetError () == PR_WOULD_BLOCK_ERROR));
+
+ if (w > 0)
+ written += w;
+ } while (w != -1 && written < n);
+ } else {
+ PRSocketOptionData sockopts;
+ PRPollDesc pollfds[2];
+ gboolean nonblock;
+ gint error;
+
+ /* get O_NONBLOCK options */
+ sockopts.option = PR_SockOpt_Nonblocking;
+ PR_GetSocketOption (fd, &sockopts);
+ sockopts.option = PR_SockOpt_Nonblocking;
+ nonblock = sockopts.value.non_blocking;
+ sockopts.value.non_blocking = TRUE;
+ PR_SetSocketOption (fd, &sockopts);
+
+ pollfds[0].fd = fd;
+ pollfds[0].in_flags = PR_POLL_WRITE;
+ pollfds[1].fd = cancel_fd;
+ pollfds[1].in_flags = PR_POLL_READ;
+
+ do {
+ PRInt32 res;
+
+ pollfds[0].out_flags = 0;
+ pollfds[1].out_flags = 0;
+ w = -1;
+
+ res = PR_Poll (pollfds, 2, IO_TIMEOUT);
+ if (res == -1) {
+ set_errno(PR_GetError());
+ if (PR_GetError () == PR_PENDING_INTERRUPT_ERROR)
+ w = 0;
+ } else if (res == 0) {
+#ifdef ETIMEDOUT
+ errno = ETIMEDOUT;
+#else
+ errno = EIO;
+#endif
+ } else if (pollfds[1].out_flags == PR_POLL_READ) {
+ errno = EINTR;
+ } else {
+ do {
+ w = PR_Write (fd, buffer + written, n - written);
+ if (w == -1)
+ set_errno (PR_GetError ());
+ } while (w == -1 && PR_GetError () == PR_PENDING_INTERRUPT_ERROR);
+
+ if (w == -1) {
+ if (PR_GetError () == PR_IO_PENDING_ERROR ||
+ PR_GetError () == PR_WOULD_BLOCK_ERROR)
+ w = 0;
+ } else
+ written += w;
+ }
+ } while (w != -1 && written < n);
+
+ /* restore O_NONBLOCK options */
+ error = errno;
+ sockopts.option = PR_SockOpt_Nonblocking;
+ sockopts.value.non_blocking = nonblock;
+ PR_SetSocketOption (fd, &sockopts);
+ errno = error;
+ }
+
+ if (w == -1)
+ return -1;
+
+ return written;
}
static gssize
@@ -273,13 +515,26 @@ stream_write (CamelStream *stream, const gchar *buffer, gsize n)
{
CamelTcpStreamRaw *raw = CAMEL_TCP_STREAM_RAW (stream);
CamelTcpStreamRawPrivate *priv = raw->priv;
+ gssize result;
+
+ d (g_print ("TcpStreamRaw %p: writing %" G_GSIZE_FORMAT " bytes...\n", ssl, n));
- return camel_write_socket (priv->sockfd, buffer, n);
+ result = write_to_prfd (priv->sockfd, buffer, n);
+
+ d (g_print ("TcpStreamRaw %p: wrote %" G_GSSIZE_FORMAT " bytes, errno = %d\n", ssl, result, result == -1 ? errno : 0));
+
+ return result;
}
static gint
stream_flush (CamelStream *stream)
{
+#if 0
+ CamelTcpStreamRaw *raw = CAMEL_TCP_STREAM_RAW (stream);
+ CamelTcpStreamRawPrivate *priv = raw->priv;
+
+ return PR_Sync (priv->sockfd);
+#endif
return 0;
}
@@ -289,148 +544,144 @@ stream_close (CamelStream *stream)
CamelTcpStreamRaw *raw = CAMEL_TCP_STREAM_RAW (stream);
CamelTcpStreamRawPrivate *priv = raw->priv;
- if (SOCKET_CLOSE (priv->sockfd) == -1)
+ d (g_print ("TcpStreamRaw %p: closing\n", stream));
+
+ if (priv->sockfd == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ PR_Shutdown (priv->sockfd, PR_SHUTDOWN_BOTH);
+ if (PR_Close (priv->sockfd) == PR_FAILURE)
return -1;
- priv->sockfd = -1;
+ priv->sockfd = NULL;
+
return 0;
}
-/* this is a 'cancellable' connect, cancellable from camel_operation_cancel etc */
-/* returns -1 & errno == EINTR if the connection was cancelled */
static gint
-socket_connect(struct addrinfo *h)
+sockaddr_to_praddr(struct sockaddr *s, gint len, PRNetAddr *addr)
{
- struct timeval tv;
- socklen_t len;
- gint cancel_fd;
- gint errnosav;
- gint ret, fd;
+ /* We assume the ip addresses are the same size - they have to be anyway.
+ We could probably just use memcpy *shrug* */
- /* see if we're cancelled yet */
- if (camel_operation_cancel_check (NULL)) {
- errno = EINTR;
- return -1;
- }
+ memset(addr, 0, sizeof(*addr));
- if (h->ai_socktype != SOCK_STREAM) {
- errno = EINVAL;
- return -1;
- }
+ if (s->sa_family == AF_INET) {
+ struct sockaddr_in *sin = (struct sockaddr_in *)s;
- if ((fd = socket (h->ai_family, SOCK_STREAM, 0)) == -1)
- return -1;
+ if (len < sizeof(*sin))
+ return -1;
+
+ addr->inet.family = PR_AF_INET;
+ addr->inet.port = sin->sin_port;
+ memcpy(&addr->inet.ip, &sin->sin_addr, sizeof(addr->inet.ip));
+
+ return 0;
+ }
+#ifdef ENABLE_IPv6
+ else if (s->sa_family == PR_AF_INET6) {
+ struct sockaddr_in6 *sin = (struct sockaddr_in6 *)s;
- cancel_fd = camel_operation_cancel_fd (NULL);
- if (cancel_fd == -1) {
- if (connect (fd, h->ai_addr, h->ai_addrlen) == -1) {
- /* Yeah, errno is meaningless on Win32 after a
- * Winsock call fails, but I doubt the callers
- * check errno anyway.
- */
- errnosav = errno;
- SOCKET_CLOSE (fd);
- errno = errnosav;
+ if (len < sizeof(*sin))
return -1;
- }
- return fd;
- } else {
-#ifndef G_OS_WIN32
- gint flags;
-#endif
- gint fdmax, status;
- fd_set rdset, wrset;
+ addr->ipv6.family = PR_AF_INET6;
+ addr->ipv6.port = sin->sin6_port;
+ addr->ipv6.flowinfo = sin->sin6_flowinfo;
+ memcpy(&addr->ipv6.ip, &sin->sin6_addr, sizeof(addr->ipv6.ip));
+ addr->ipv6.scope_id = sin->sin6_scope_id;
-#ifndef G_OS_WIN32
- flags = fcntl (fd, F_GETFL);
- fcntl (fd, F_SETFL, flags | O_NONBLOCK);
-#else
- {
- u_long yes = 1;
- ioctlsocket (fd, FIONBIO, &yes);
- }
-#endif
- if (connect (fd, h->ai_addr, h->ai_addrlen) == 0) {
-#ifndef G_OS_WIN32
- fcntl (fd, F_SETFL, flags);
-#else
- {
- u_long no = 0;
- ioctlsocket (fd, FIONBIO, &no);
- }
+ return 0;
+ }
#endif
- return fd;
- }
- if (!SOCKET_ERROR_IS_EINPROGRESS ()) {
- errnosav = errno;
- SOCKET_CLOSE (fd);
- errno = errnosav;
- return -1;
- }
+ return -1;
+}
- do {
- FD_ZERO (&rdset);
- FD_ZERO (&wrset);
- FD_SET (fd, &wrset);
- FD_SET (cancel_fd, &rdset);
- fdmax = MAX (fd, cancel_fd) + 1;
- tv.tv_sec = 60 * 4;
- tv.tv_usec = 0;
-
- status = select (fdmax, &rdset, &wrset, NULL, &tv);
- } while (status == -1 && SOCKET_ERROR_IS_EINTR ());
-
- if (status <= 0) {
- SOCKET_CLOSE (fd);
- errno = ETIMEDOUT;
- return -1;
- }
+static PRFileDesc *
+socket_connect(struct addrinfo *host)
+{
+ PRNetAddr netaddr;
+ PRFileDesc *fd, *cancel_fd;
- if (cancel_fd != -1 && FD_ISSET (cancel_fd, &rdset)) {
- SOCKET_CLOSE (fd);
- errno = EINTR;
- return -1;
- } else {
- len = sizeof (gint);
+ if (sockaddr_to_praddr(host->ai_addr, host->ai_addrlen, &netaddr) != 0) {
+ errno = EINVAL;
+ return NULL;
+ }
- if (getsockopt (fd, SOL_SOCKET, SO_ERROR, (gchar *) &ret, &len) == -1) {
- errnosav = errno;
- SOCKET_CLOSE (fd);
- errno = errnosav;
- return -1;
- }
+ fd = PR_OpenTCPSocket(netaddr.raw.family);
+ if (fd == NULL) {
+ set_errno (PR_GetError ());
+ return NULL;
+ }
- if (ret != 0) {
- SOCKET_CLOSE (fd);
- errno = ret;
- return -1;
- }
- }
-#ifndef G_OS_WIN32
- fcntl (fd, F_SETFL, flags);
-#else
- {
- u_long no = 0;
- ioctlsocket (fd, FIONBIO, &no);
+ cancel_fd = camel_operation_cancel_prfd(NULL);
+
+ if (PR_Connect (fd, &netaddr, cancel_fd?0:CONNECT_TIMEOUT) == PR_FAILURE) {
+ gint errnosave;
+
+ set_errno (PR_GetError ());
+ if (PR_GetError () == PR_IN_PROGRESS_ERROR ||
+ (cancel_fd && (PR_GetError () == PR_CONNECT_TIMEOUT_ERROR ||
+ PR_GetError () == PR_IO_TIMEOUT_ERROR))) {
+ gboolean connected = FALSE;
+ PRPollDesc poll[2];
+
+ poll[0].fd = fd;
+ poll[0].in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
+ poll[1].fd = cancel_fd;
+ poll[1].in_flags = PR_POLL_READ;
+
+ do {
+ poll[0].out_flags = 0;
+ poll[1].out_flags = 0;
+
+ if (PR_Poll (poll, cancel_fd?2:1, CONNECT_TIMEOUT) == PR_FAILURE) {
+ set_errno (PR_GetError ());
+ goto exception;
+ }
+
+ if (poll[1].out_flags == PR_POLL_READ) {
+ errno = EINTR;
+ goto exception;
+ }
+
+ if (PR_ConnectContinue(fd, poll[0].out_flags) == PR_FAILURE) {
+ set_errno (PR_GetError ());
+ if (PR_GetError () != PR_IN_PROGRESS_ERROR)
+ goto exception;
+ } else {
+ connected = TRUE;
+ }
+ } while (!connected);
+ } else {
+ exception:
+ errnosave = errno;
+ PR_Shutdown (fd, PR_SHUTDOWN_BOTH);
+ PR_Close (fd);
+ errno = errnosave;
+
+ return NULL;
}
-#endif
+
+ errno = 0;
}
return fd;
}
/* Returns the FD of a socket, already connected to and validated by the SOCKS4
- * proxy that is configured in the stream. Otherwise returns -1. Assumes that
+ * proxy that is configured in the stream. Otherwise returns NULL. Assumes that
* a proxy *is* configured with camel_tcp_stream_set_socks_proxy().
*/
-static gint
+static PRFileDesc *
connect_to_socks4_proxy (const gchar *proxy_host, gint proxy_port, struct addrinfo *connect_addr)
{
struct addrinfo *ai, hints;
gchar serv[16];
- gint fd;
+ PRFileDesc *fd;
gchar request[9];
struct sockaddr_in *sin;
gchar reply[8];
@@ -438,24 +689,30 @@ connect_to_socks4_proxy (const gchar *proxy_host, gint proxy_port, struct addrin
g_assert (proxy_host != NULL);
+ d (g_print ("TcpStreamRaw %p: connecting to SOCKS4 proxy %s:%d {\n resolving proxy host\n", ssl, proxy_host, proxy_port));
+
sprintf (serv, "%d", proxy_port);
memset (&hints, 0, sizeof (hints));
hints.ai_socktype = SOCK_STREAM;
- ai = camel_getaddrinfo (proxy_host, serv, &hints, NULL); /* NULL-CamelException */
+ ai = camel_getaddrinfo (proxy_host, serv, &hints, NULL); /* NULL-CamelException */
if (!ai) {
errno = EHOSTUNREACH; /* FIXME: this is not an accurate error; we should translate the CamelException to an errno */
- return -1;
+ d (g_print (" camel_getaddrinfo() for the proxy failed\n}\n"));
+ return NULL;
}
+ d (g_print (" creating socket and connecting\n"));
+
fd = socket_connect (ai);
save_errno = errno;
camel_freeaddrinfo (ai);
- if (fd == -1) {
+ if (!fd) {
errno = save_errno;
+ d (g_print (" could not connect: %d\n", errno));
goto error;
}
@@ -468,30 +725,46 @@ connect_to_socks4_proxy (const gchar *proxy_host, gint proxy_port, struct addrin
memcpy (request + 4, &sin->sin_addr.s_addr, 4); /* address in network byte order */
request[8] = 0x00; /* terminator */
- if (camel_write_socket (fd, request, sizeof (request)) != sizeof (request))
+ d (g_print (" writing SOCKS4 request to connect to actual host\n"));
+ if (write_to_prfd (fd, request, sizeof (request)) != sizeof (request)) {
+ d (g_print (" failed: %d\n", errno));
goto error;
+ }
- if (camel_read_socket (fd, reply, sizeof (reply)) != sizeof (reply))
+ d (g_print (" reading SOCKS4 reply\n"));
+ if (read_from_prfd (fd, reply, sizeof (reply)) != sizeof (reply)) {
+ d (g_print (" failed: %d\n", errno));
goto error;
+ }
if (!(reply[0] == 0 /* first byte of reply is 0 */
&& reply[1] == 90)) { /* 90 means "request granted" */
errno = ECONNREFUSED;
+ d (g_print (" proxy replied with code %d\n", reply[1]));
goto error;
}
+ /* We are now proxied; we are ready to send "normal" data through the socket */
+
+ d (g_print (" success\n"));
+
goto out;
error:
- if (fd != -1) {
+ if (fd) {
save_errno = errno;
- SOCKET_CLOSE (fd);
+ PR_Shutdown (fd, PR_SHUTDOWN_BOTH);
+ PR_Close (fd);
errno = save_errno;
- fd = -1;
+ fd = NULL;
}
+ d (g_print (" returning errno %d\n", errno));
+
out:
+ d (g_print ("}\n"));
+
return fd;
}
@@ -536,7 +809,7 @@ stream_connect (CamelTcpStream *stream, const char *host, const char *service, g
else
priv->sockfd = socket_connect (ai);
- if (priv->sockfd != -1) {
+ if (priv->sockfd) {
retval = 0;
goto out;
}
@@ -554,76 +827,21 @@ out:
}
static gint
-get_sockopt_level (const CamelSockOptData *data)
-{
- switch (data->option) {
- case CAMEL_SOCKOPT_MAXSEGMENT:
- case CAMEL_SOCKOPT_NODELAY:
- return IPPROTO_TCP;
- default:
- return SOL_SOCKET;
- }
-}
-
-static gint
-get_sockopt_optname (const CamelSockOptData *data)
-{
- switch (data->option) {
-#ifdef TCP_MAXSEG
- case CAMEL_SOCKOPT_MAXSEGMENT:
- return TCP_MAXSEG;
-#endif
- case CAMEL_SOCKOPT_NODELAY:
- return TCP_NODELAY;
- case CAMEL_SOCKOPT_BROADCAST:
- return SO_BROADCAST;
- case CAMEL_SOCKOPT_KEEPALIVE:
- return SO_KEEPALIVE;
- case CAMEL_SOCKOPT_LINGER:
- return SO_LINGER;
- case CAMEL_SOCKOPT_RECVBUFFERSIZE:
- return SO_RCVBUF;
- case CAMEL_SOCKOPT_SENDBUFFERSIZE:
- return SO_SNDBUF;
- case CAMEL_SOCKOPT_REUSEADDR:
- return SO_REUSEADDR;
- case CAMEL_SOCKOPT_IPTYPEOFSERVICE:
- return SO_TYPE;
- default:
- return -1;
- }
-}
-
-static gint
stream_getsockopt (CamelTcpStream *stream, CamelSockOptData *data)
{
CamelTcpStreamRaw *raw = CAMEL_TCP_STREAM_RAW (stream);
CamelTcpStreamRawPrivate *priv = raw->priv;
- gint optname, optlen;
+ PRSocketOptionData sodata;
- if ((optname = get_sockopt_optname (data)) == -1)
- return -1;
-
- if (data->option == CAMEL_SOCKOPT_NONBLOCKING) {
-#ifndef G_OS_WIN32
- gint flags;
+ memset ((gpointer) &sodata, 0, sizeof (sodata));
+ memcpy ((gpointer) &sodata, (gpointer) data, sizeof (CamelSockOptData));
- flags = fcntl (priv->sockfd, F_GETFL);
- if (flags == -1)
- return -1;
+ if (PR_GetSocketOption (priv->sockfd, &sodata) == PR_FAILURE)
+ return -1;
- data->value.non_blocking = flags & O_NONBLOCK ? TRUE : FALSE;
-#else
- data->value.non_blocking = priv->is_nonblocking;
-#endif
- return 0;
- }
+ memcpy ((gpointer) data, (gpointer) &sodata, sizeof (CamelSockOptData));
- return getsockopt (priv->sockfd,
- get_sockopt_level (data),
- optname,
- (gpointer) &data->value,
- (socklen_t *) &optlen);
+ return 0;
}
static gint
@@ -631,60 +849,61 @@ stream_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data)
{
CamelTcpStreamRaw *raw = CAMEL_TCP_STREAM_RAW (stream);
CamelTcpStreamRawPrivate *priv = raw->priv;
- gint optname;
+ PRSocketOptionData sodata;
- if ((optname = get_sockopt_optname (data)) == -1)
+ memset ((gpointer) &sodata, 0, sizeof (sodata));
+ memcpy ((gpointer) &sodata, (gpointer) data, sizeof (CamelSockOptData));
+
+ if (PR_SetSocketOption (priv->sockfd, &sodata) == PR_FAILURE)
return -1;
- if (data->option == CAMEL_SOCKOPT_NONBLOCKING) {
-#ifndef G_OS_WIN32
- gint flags, set;
+ return 0;
+}
- flags = fcntl (priv->sockfd, F_GETFL);
- if (flags == -1)
- return -1;
+static struct sockaddr *
+sockaddr_from_praddr(PRNetAddr *addr, socklen_t *len)
+{
+ /* We assume the ip addresses are the same size - they have to be anyway */
- set = data->value.non_blocking ? O_NONBLOCK : 0;
- flags = (flags & ~O_NONBLOCK) | set;
+ if (addr->raw.family == PR_AF_INET) {
+ struct sockaddr_in *sin = g_malloc0(sizeof(*sin));
- if (fcntl (priv->sockfd, F_SETFL, flags) == -1)
- return -1;
-#else
- u_long fionbio = data->value.non_blocking ? 1 : 0;
- if (ioctlsocket (priv->sockfd, FIONBIO, &fionbio) == SOCKET_ERROR)
- return -1;
- priv->is_nonblocking = data->value.non_blocking ? 1 : 0;
-#endif
- return 0;
+ sin->sin_family = AF_INET;
+ sin->sin_port = addr->inet.port;
+ memcpy(&sin->sin_addr, &addr->inet.ip, sizeof(sin->sin_addr));
+ *len = sizeof(*sin);
+
+ return (struct sockaddr *)sin;
}
+#ifdef ENABLE_IPv6
+ else if (addr->raw.family == PR_AF_INET6) {
+ struct sockaddr_in6 *sin = g_malloc0(sizeof(*sin));
+
+ sin->sin6_family = AF_INET6;
+ sin->sin6_port = addr->ipv6.port;
+ sin->sin6_flowinfo = addr->ipv6.flowinfo;
+ memcpy(&sin->sin6_addr, &addr->ipv6.ip, sizeof(sin->sin6_addr));
+ sin->sin6_scope_id = addr->ipv6.scope_id;
+ *len = sizeof(*sin);
- return setsockopt (priv->sockfd,
- get_sockopt_level (data),
- optname,
- (gpointer) &data->value,
- sizeof (data->value));
+ return (struct sockaddr *)sin;
+ }
+#endif
+
+ return NULL;
}
static struct sockaddr *
-stream_get_local_address (CamelTcpStream *stream, socklen_t *len)
+stream_get_local_address(CamelTcpStream *stream, socklen_t *len)
{
CamelTcpStreamRaw *raw = CAMEL_TCP_STREAM_RAW (stream);
CamelTcpStreamRawPrivate *priv = raw->priv;
-#ifdef ENABLE_IPv6
- struct sockaddr_in6 sin;
-#else
- struct sockaddr_in sin;
-#endif
- struct sockaddr *saddr = (struct sockaddr *)&sin;
+ PRNetAddr addr;
- *len = sizeof(sin);
- if (getsockname (priv->sockfd, saddr, len) == -1)
+ if (PR_GetSockName(priv->sockfd, &addr) != PR_SUCCESS)
return NULL;
- saddr = g_malloc(*len);
- memcpy(saddr, &sin, *len);
-
- return saddr;
+ return sockaddr_from_praddr(&addr, len);
}
static struct sockaddr *
@@ -692,26 +911,18 @@ stream_get_remote_address (CamelTcpStream *stream, socklen_t *len)
{
CamelTcpStreamRaw *raw = CAMEL_TCP_STREAM_RAW (stream);
CamelTcpStreamRawPrivate *priv = raw->priv;
-#ifdef ENABLE_IPv6
- struct sockaddr_in6 sin;
-#else
- struct sockaddr_in sin;
-#endif
- struct sockaddr *saddr = (struct sockaddr *)&sin;
+ PRNetAddr addr;
- *len = sizeof(sin);
- if (getpeername (priv->sockfd, saddr, len) == -1)
+ if (PR_GetPeerName(priv->sockfd, &addr) != PR_SUCCESS)
return NULL;
- saddr = g_malloc(*len);
- memcpy(saddr, &sin, *len);
-
- return saddr;
+ return sockaddr_from_praddr(&addr, len);
}
-gint
-camel_tcp_stream_raw_get_fd (CamelTcpStreamRaw *raw)
+static PRFileDesc *
+stream_get_file_desc (CamelTcpStream *stream)
{
+ CamelTcpStreamRaw *raw = CAMEL_TCP_STREAM_RAW (stream);
CamelTcpStreamRawPrivate *priv = raw->priv;
return priv->sockfd;
diff --git a/camel/camel-tcp-stream-raw.h b/camel/camel-tcp-stream-raw.h
index 3b9698e..9eba6d9 100644
--- a/camel/camel-tcp-stream-raw.h
+++ b/camel/camel-tcp-stream-raw.h
@@ -52,8 +52,6 @@ CamelType camel_tcp_stream_raw_get_type (void);
/* public methods */
CamelStream *camel_tcp_stream_raw_new (void);
-gint camel_tcp_stream_raw_get_fd (CamelTcpStreamRaw *raw);
-
G_END_DECLS
#endif /* CAMEL_TCP_STREAM_RAW_H */
diff --git a/camel/providers/imapx/camel-imapx-server.c b/camel/providers/imapx/camel-imapx-server.c
index 87ca7ac..5f34378 100644
--- a/camel/providers/imapx/camel-imapx-server.c
+++ b/camel/providers/imapx/camel-imapx-server.c
@@ -2512,14 +2512,11 @@ imapx_connect_to_server (CamelIMAPXServer *is, CamelException *ex)
}
tcp_stream = camel_tcp_stream_ssl_new(is->session, is->url->host, SSL_PORT_FLAGS);
}
- is->is_ssl_stream = TRUE;
} else {
tcp_stream = camel_tcp_stream_raw_new ();
- is->is_ssl_stream = FALSE;
}
#else
tcp_stream = camel_tcp_stream_raw_new ();
- is->is_ssl_stream = FALSE;
#endif /* HAVE_SSL */
camel_session_get_socks_proxy (is->session, &socks_host, &socks_port);
@@ -4232,29 +4229,6 @@ imapx_parser_thread (gpointer d)
while (!camel_exception_is_set (&ex) && is->stream) {
camel_operation_uncancel (op);
-#ifdef HAVE_SSL
- if (is->is_ssl_stream) {
- PRPollDesc pollfds[2] = { };
- gint res;
-
- pollfds[0].fd = camel_tcp_stream_get_file_desc (CAMEL_TCP_STREAM (is->stream->source));
- pollfds[0].in_flags = PR_POLL_READ;
- pollfds[1].fd = camel_operation_cancel_prfd (op);
- pollfds[1].in_flags = PR_POLL_READ;
-
-#include <prio.h>
-
- res = PR_Poll(pollfds, 2, PR_MillisecondsToInterval (30 * 1000));
- if (res == -1)
- g_usleep(1) /* ?? */ ;
- else if (res == 0) {
- /* timed out */
- } else if ((pollfds[0].out_flags & PR_POLL_READ)) {
- parse_contents (is, &ex);
- } else if (pollfds[1].out_flags & PR_POLL_READ)
- errno = EINTR;
- }
-#endif
#ifndef G_OS_WIN32
if (is->is_process_stream) {
GPollFD fds[2] = { {0, 0, 0}, {0, 0, 0} };
@@ -4273,26 +4247,27 @@ imapx_parser_thread (gpointer d)
parse_contents (is, &ex);
} else if (fds[1].revents & G_IO_IN)
errno = EINTR;
- }
+ } else
#endif
-
- if (!is->is_ssl_stream && !is->is_process_stream) {
- GPollFD fds[2] = { {0, 0, 0}, {0, 0, 0} };
+ {
+ PRPollDesc pollfds[2] = { };
gint res;
- fds[0].fd = camel_tcp_stream_raw_get_fd ((CamelTcpStreamRaw *) is->stream->source);
- fds[0].events = G_IO_IN;
- fds[1].fd = camel_operation_cancel_fd (op);
- fds[1].events = G_IO_IN;
+ pollfds[0].fd = camel_tcp_stream_get_file_desc (CAMEL_TCP_STREAM (is->stream->source));
+ pollfds[0].in_flags = PR_POLL_READ;
+ pollfds[1].fd = camel_operation_cancel_prfd (op);
+ pollfds[1].in_flags = PR_POLL_READ;
- res = g_poll(fds, 2, 1000*30);
+#include <prio.h>
+
+ res = PR_Poll(pollfds, 2, PR_MillisecondsToInterval (30 * 1000));
if (res == -1)
g_usleep(1) /* ?? */ ;
- else if (res == 0)
- /* timed out */;
- else if (fds[0].revents & G_IO_IN) {
+ else if (res == 0) {
+ /* timed out */
+ } else if ((pollfds[0].out_flags & PR_POLL_READ)) {
parse_contents (is, &ex);
- } else if (fds[1].revents & G_IO_IN)
+ } else if (pollfds[1].out_flags & PR_POLL_READ)
errno = EINTR;
}
diff --git a/camel/providers/imapx/camel-imapx-server.h b/camel/providers/imapx/camel-imapx-server.h
index 502769d..22bd7da 100644
--- a/camel/providers/imapx/camel-imapx-server.h
+++ b/camel/providers/imapx/camel-imapx-server.h
@@ -51,7 +51,6 @@ struct _CamelIMAPXServer {
struct _CamelURL *url;
struct _CamelIMAPXStream *stream;
struct _capability_info *cinfo;
- gboolean is_ssl_stream;
gboolean is_process_stream;
CamelIMAPXNamespaceList *nsl;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]