Derive CamelTcpStreamSSL from CamelTcpStreamRaw
authorFederico Mena Quintero <federico@novell.com>
Thu, 15 Jul 2010 21:06:03 +0000 (16:06 -0500)
committerFederico Mena Quintero <federico@novell.com>
Wed, 28 Jul 2010 21:13:40 +0000 (16:13 -0500)
The only overriden vmethod is ::connect(), which starts up SSL on the socket
after the Raw implementation opens the socket and connects.  By this point,
we are already past the SOCKS proxy if it exists.

Signed-off-by: Federico Mena Quintero <federico@novell.com>
camel/camel-tcp-stream-ssl.c
camel/camel-tcp-stream-ssl.h

index 2a495a6..52847df 100644 (file)
        ((obj), CAMEL_TYPE_TCP_STREAM_SSL, CamelTcpStreamSSLPrivate))
 
 struct _CamelTcpStreamSSLPrivate {
-       PRFileDesc *sockfd;
-
        CamelSession *session;
        gchar *expected_host;
        gboolean ssl_mode;
        guint32 flags;
 };
 
-G_DEFINE_TYPE (CamelTcpStreamSSL, camel_tcp_stream_ssl, CAMEL_TYPE_TCP_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;
-       }
-}
+G_DEFINE_TYPE (CamelTcpStreamSSL, camel_tcp_stream_ssl, CAMEL_TYPE_TCP_STREAM_RAW)
 
 static void
 tcp_stream_ssl_dispose (GObject *object)
@@ -170,277 +106,12 @@ tcp_stream_ssl_finalize (GObject *object)
 
        priv = CAMEL_TCP_STREAM_SSL_GET_PRIVATE (object);
 
-       if (priv->sockfd != NULL) {
-               PR_Shutdown (priv->sockfd, PR_SHUTDOWN_BOTH);
-               PR_Close (priv->sockfd);
-       }
-
        g_free (priv->expected_host);
 
        /* Chain up to parent's finalize() method. */
        G_OBJECT_CLASS (camel_tcp_stream_ssl_parent_class)->finalize (object);
 }
 
-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
-tcp_stream_ssl_read (CamelStream *stream,
-                     gchar *buffer,
-                     gsize n,
-                     GError **error)
-{
-       CamelTcpStreamSSL *ssl = CAMEL_TCP_STREAM_SSL (stream);
-       gssize result;
-
-       d (g_print ("SSL stream %p: reading %" G_GSIZE_FORMAT " bytes...\n", ssl, n));
-
-       result = read_from_prfd (ssl->priv->sockfd, buffer, n);
-
-       if (result == -1)
-               g_set_error (
-                       error, G_IO_ERROR,
-                       g_io_error_from_errno (errno),
-                       "%s", g_strerror (errno));
-
-       d (g_print ("SSL stream %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
-tcp_stream_ssl_write (CamelStream *stream,
-                      const gchar *buffer,
-                      gsize n,
-                      GError **error)
-{
-       CamelTcpStreamSSL *ssl = CAMEL_TCP_STREAM_SSL (stream);
-       gssize result;
-
-       d (g_print ("SSL stream %p: writing %" G_GSIZE_FORMAT " bytes...\n", ssl, n));
-
-       result = write_to_prfd (ssl->priv->sockfd, buffer, n);
-
-       if (result == -1)
-               g_set_error (
-                       error, G_IO_ERROR,
-                       g_io_error_from_errno (errno),
-                       "%s", g_strerror (errno));
-
-       d (g_print ("SSL stream %p: wrote %" G_GSSIZE_FORMAT " bytes, errno = %d\n", ssl, result, result == -1 ? errno : 0));
-
-       return result;
-}
-
-static gint
-tcp_stream_ssl_flush (CamelStream *stream,
-                      GError **error)
-{
-       /*return PR_Sync (((CamelTcpStreamSSL *)stream)->priv->sockfd);*/
-       return 0;
-}
-
-static gint
-tcp_stream_ssl_close (CamelStream *stream,
-                      GError **error)
-{
-       d (g_print ("SSL stream %p: closing\n", stream));
-
-       if (((CamelTcpStreamSSL *)stream)->priv->sockfd == NULL) {
-               errno = EINVAL;
-               g_set_error (
-                       error, G_IO_ERROR,
-                       g_io_error_from_errno (errno),
-                       "%s", g_strerror (errno));
-               return -1;
-       }
-
-       PR_Shutdown (((CamelTcpStreamSSL *)stream)->priv->sockfd, PR_SHUTDOWN_BOTH);
-
-       /* FIXME Need to set the GError if this fails. */
-       if (PR_Close (((CamelTcpStreamSSL *)stream)->priv->sockfd) == PR_FAILURE)
-               return -1;
-
-       ((CamelTcpStreamSSL *)stream)->priv->sockfd = NULL;
-
-       return 0;
-}
-
 #if 0
 /* Since this is default implementation, let NSS handle it. */
 static SECStatus
@@ -954,7 +625,9 @@ enable_ssl (CamelTcpStreamSSL *ssl, PRFileDesc *fd)
 {
        PRFileDesc *ssl_fd;
 
-       ssl_fd = SSL_ImportFD (NULL, fd ? fd : ssl->priv->sockfd);
+       g_assert (fd != NULL);
+
+       ssl_fd = SSL_ImportFD (NULL, fd);
        if (!ssl_fd)
                return NULL;
 
@@ -989,8 +662,6 @@ enable_ssl (CamelTcpStreamSSL *ssl, PRFileDesc *fd)
         * SSL_AuthCertificateHook callback so we _don't_ need to install one. */
        SSL_BadCertHook (ssl_fd, ssl_bad_cert, ssl);
 
-       ssl->priv->ssl_mode = TRUE;
-
        return ssl_fd;
 }
 
@@ -1003,7 +674,7 @@ enable_ssl_or_close_fd (CamelTcpStreamSSL *ssl, PRFileDesc *fd)
        if (ssl_fd == NULL) {
                gint errnosave;
 
-               set_errno (PR_GetError ());
+               _set_errno_from_pr_error (PR_GetError ());
                errnosave = errno;
                PR_Shutdown (fd, PR_SHUTDOWN_BOTH);
                PR_Close (fd);
@@ -1015,313 +686,55 @@ enable_ssl_or_close_fd (CamelTcpStreamSSL *ssl, PRFileDesc *fd)
        return ssl_fd;
 }
 
-static gint
-sockaddr_to_praddr(struct sockaddr *s, gint len, PRNetAddr *addr)
-{
-       /* We assume the ip addresses are the same size - they have to be anyway.
-          We could probably just use memcpy *shrug* */
-
-       memset(addr, 0, sizeof(*addr));
-
-       if (s->sa_family == AF_INET) {
-               struct sockaddr_in *sin = (struct sockaddr_in *)s;
-
-               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;
-
-               if (len < sizeof(*sin))
-                       return -1;
-
-               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;
-
-               return 0;
-       }
-#endif
-
-       return -1;
-}
-
-static PRFileDesc *
-tcp_socket_ssl_connect (CamelTcpStream *stream, struct addrinfo *host, gboolean possibly_use_ssl)
-{
-       CamelTcpStreamSSL *ssl = CAMEL_TCP_STREAM_SSL (stream);
-       PRNetAddr netaddr;
-       PRFileDesc *fd, *cancel_fd;
-
-       if (sockaddr_to_praddr(host->ai_addr, host->ai_addrlen, &netaddr) != 0) {
-               errno = EINVAL;
-               return NULL;
-       }
-
-       fd = PR_OpenTCPSocket(netaddr.raw.family);
-       if (fd == NULL) {
-               set_errno (PR_GetError ());
-               return NULL;
-       }
-
-       if (possibly_use_ssl && ssl->priv->ssl_mode) {
-               fd = enable_ssl_or_close_fd (ssl, fd);
-               if (!fd)
-                       return NULL;
-       }
-
-       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;
-               }
-
-               errno = 0;
-       }
-
-       return fd;
-}
-
 static gboolean
 rehandshake_ssl (PRFileDesc *fd)
 {
        if (SSL_ResetHandshake (fd, FALSE) == SECFailure) {
-               set_errno (PR_GetError ());
+               _set_errno_from_pr_error (PR_GetError ());
                return FALSE;
        }
 
        if (SSL_ForceHandshake (fd) == SECFailure) {
-               set_errno (PR_GetError ());
+               _set_errno_from_pr_error (PR_GetError ());
                return FALSE;
        }
 
        return TRUE;
 }
 
-static PRFileDesc *
-connect_to_socks4_proxy (CamelTcpStreamSSL *ssl, const gchar *proxy_host, gint proxy_port, struct addrinfo *connect_addr)
+static gint
+tcp_stream_ssl_connect (CamelTcpStream *stream, const char *host, const char *service, gint fallback_port, CamelException *ex)
 {
-       struct addrinfo *ai, hints;
-       gchar serv[16];
-       PRFileDesc *fd;
-       gchar request[9];
-       struct sockaddr_in *sin;
-       gchar reply[8];
-       gint save_errno;
-
-       g_assert (proxy_host != NULL);
-
-       d (g_print ("SSL stream %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-GError */
-       if (!ai) {
-#ifdef G_OS_WIN32
-               errno = WSAEHOSTUNREACH;
-#else
-               errno = EHOSTUNREACH; /* FIXME: this is not an accurate error; we should translate the GError to an errno */
-#endif
-               d (g_print ("  camel_getaddrinfo() for the proxy failed\n}\n"));
-               return NULL;
-       }
-
-       d (g_print ("  creating socket and connecting\n"));
-
-       fd = tcp_socket_ssl_connect (CAMEL_TCP_STREAM (ssl), ai, FALSE);
-       save_errno = errno;
-
-       camel_freeaddrinfo (ai);
-
-       if (!fd) {
-               errno = save_errno;
-               d (g_print ("  could not connect: %d\n", errno));
-               goto error;
-       }
-
-       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 */
-       request[1] = 0x01;                              /* CONNECT */
-       memcpy (request + 2, &sin->sin_port, 2);        /* port in network byte order */
-       memcpy (request + 4, &sin->sin_addr.s_addr, 4); /* address in network byte order */
-       request[8] = 0x00;                              /* terminator */
+       CamelTcpStreamSSL *ssl = CAMEL_TCP_STREAM_SSL (stream);
+       gint retval;
 
-       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;
-       }
+       retval = CAMEL_TCP_STREAM_CLASS (parent_class)->connect (stream, host, service, fallback_port, ex);
+       if (retval != 0)
+               return retval;
 
-       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 (ssl->priv->ssl_mode) {
+               PRFileDesc *fd;
+               PRFileDesc *ssl_fd;
 
-       if (!(reply[0] == 0             /* first byte of reply is 0 */
-             && reply[1] == 90)) {     /* 90 means "request granted" */
-#ifdef G_OS_WIN32
-               errno = WSAECONNREFUSED;
-#else
-               errno = ECONNREFUSED;
-#endif
-               d (g_print ("  proxy replied with code %d\n", reply[1]));
-               goto error;
-       }
+               d (g_print ("  enabling SSL\n"));
 
-       /* We are now proxied we are ready to send "normal" data through the socket */
+               fd = camel_tcp_stream_get_file_desc (stream);
+               ssl_fd = enable_ssl_or_close_fd (ssl, fd);
+               _camel_tcp_stream_raw_replace_file_desc (CAMEL_TCP_STREAM_RAW (stream), ssl_fd);
 
-       if (ssl->priv->ssl_mode) {
-               d (g_print ("  enabling SSL\n"));
-               fd = enable_ssl_or_close_fd (ssl, fd);
-               if (!fd) {
+               if (!ssl_fd) {
                        d (g_print ("  could not enable SSL\n"));
-                       goto error;
                } else {
                        d (g_print ("  re-handshaking SSL\n"));
-                       if (!rehandshake_ssl (fd)) {
+                       
+                       if (!rehandshake_ssl (ssl_fd)) {
                                d (g_print ("  failed\n"));
-                               goto error;
+                               return -1;
                        }
                }
        }
 
-       d (g_print ("  success\n"));
-
-       goto out;
-
-error:
-       if (fd) {
-               save_errno = errno;
-               PR_Shutdown (fd, PR_SHUTDOWN_BOTH);
-               PR_Close (fd);
-               errno = save_errno;
-               fd = NULL;
-       }
-
-       d (g_print ("  returning errno %d\n", errno));
-
-out:
-
-       d (g_print ("}\n"));
-
-       return fd;
-}
-
-static gint
-tcp_stream_ssl_connect (CamelTcpStream *stream,
-                       const char *host, const char *service, gint fallback_port,
-                        GError **error)
-{
-       CamelTcpStreamSSL *ssl = CAMEL_TCP_STREAM_SSL (stream);
-       struct addrinfo *addr, *ai;
-       struct addrinfo hints;
-       GError *my_error;
-       gint retval;
-       const gchar *proxy_host;
-       gint proxy_port;
-
-       memset (&hints, 0, sizeof (hints));
-       hints.ai_socktype = SOCK_STREAM;
-       hints.ai_family = PF_UNSPEC;
-
-       my_error = NULL;
-       addr = camel_getaddrinfo (host, service, &hints, &my_error);
-       if (addr == NULL && fallback_port != 0 && !g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
-               char str_port[16];
-
-               g_clear_error (&my_error);
-               sprintf (str_port, "%d", fallback_port);
-               addr = camel_getaddrinfo (host, str_port, &hints, &my_error);
-       }
-
-       if (addr == NULL) {
-               g_propagate_error (error, my_error);
-               return -1;
-       }
-
-       camel_tcp_stream_peek_socks_proxy (stream, &proxy_host, &proxy_port);
-
-       ai = addr;
-
-       while (ai) {
-               if (proxy_host)
-                       ssl->priv->sockfd = connect_to_socks4_proxy (ssl, proxy_host, proxy_port, ai);
-               else
-                       ssl->priv->sockfd = socket_connect (stream, ai, TRUE);
-
-               if (ssl->priv->sockfd) {
-                       retval = 0;
-                       goto out;
-               }
-
-               ai = ai->ai_next;
-       }
-
-       retval = -1;
-
-out:
-
-       camel_freeaddrinfo (addr);
-
-       return retval;
+       return 0;
 }
 
 static gint
@@ -1341,93 +754,10 @@ tcp_stream_ssl_getsockopt (CamelTcpStream *stream,
        return 0;
 }
 
-static gint
-tcp_stream_ssl_setsockopt (CamelTcpStream *stream,
-                           const CamelSockOptData *data)
-{
-       PRSocketOptionData sodata;
-
-       memset ((gpointer) &sodata, 0, sizeof (sodata));
-       memcpy ((gpointer) &sodata, (gpointer) data, sizeof (CamelSockOptData));
-
-       if (PR_SetSocketOption (((CamelTcpStreamSSL *)stream)->priv->sockfd, &sodata) == PR_FAILURE)
-               return -1;
-
-       return 0;
-}
-
-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 */
-
-       if (addr->raw.family == PR_AF_INET) {
-               struct sockaddr_in *sin = g_malloc0(sizeof(*sin));
-
-               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 (struct sockaddr *)sin;
-       }
-#endif
-
-       return NULL;
-}
-
-static struct sockaddr *
-tcp_stream_ssl_get_local_address (CamelTcpStream *stream,
-                                  socklen_t *len)
-{
-       PRFileDesc *sockfd = CAMEL_TCP_STREAM_SSL (stream)->priv->sockfd;
-       PRNetAddr addr;
-
-       if (PR_GetSockName(sockfd, &addr) != PR_SUCCESS)
-               return NULL;
-
-       return sockaddr_from_praddr(&addr, len);
-}
-
-static struct sockaddr *
-tcp_stream_ssl_get_remote_address (CamelTcpStream *stream,
-                                   socklen_t *len)
-{
-       PRFileDesc *sockfd = CAMEL_TCP_STREAM_SSL (stream)->priv->sockfd;
-       PRNetAddr addr;
-
-       if (PR_GetPeerName(sockfd, &addr) != PR_SUCCESS)
-               return NULL;
-
-       return sockaddr_from_praddr(&addr, len);
-}
-
-static PRFileDesc *
-tcp_stream_ssl_get_file_desc (CamelTcpStream *stream)
-{
-       CamelTcpStreamSSL *ssl = CAMEL_TCP_STREAM_SSL (stream);
-
-       return ssl->priv->sockfd;
-}
-
 static void
 camel_tcp_stream_ssl_class_init (CamelTcpStreamSSLClass *class)
 {
        GObjectClass *object_class;
-       CamelStreamClass *stream_class;
        CamelTcpStreamClass *tcp_stream_class;
 
        g_type_class_add_private (class, sizeof (CamelTcpStreamSSLPrivate));
@@ -1436,19 +766,8 @@ camel_tcp_stream_ssl_class_init (CamelTcpStreamSSLClass *class)
        object_class->dispose = tcp_stream_ssl_dispose;
        object_class->finalize = tcp_stream_ssl_finalize;
 
-       stream_class = CAMEL_STREAM_CLASS (class);
-       stream_class->read = tcp_stream_ssl_read;
-       stream_class->write = tcp_stream_ssl_write;
-       stream_class->flush = tcp_stream_ssl_flush;
-       stream_class->close = tcp_stream_ssl_close;
-
        tcp_stream_class = CAMEL_TCP_STREAM_CLASS (class);
        tcp_stream_class->connect = tcp_stream_ssl_connect;
-       tcp_stream_class->getsockopt = tcp_stream_ssl_getsockopt;
-       tcp_stream_class->setsockopt = tcp_stream_ssl_setsockopt;
-       tcp_stream_class->get_local_address  = tcp_stream_ssl_get_local_address;
-       tcp_stream_class->get_remote_address = tcp_stream_ssl_get_remote_address;
-       tcp_stream_class->get_file_desc = tcp_stream_ssl_get_file_desc;
 }
 
 static void
@@ -1532,19 +851,22 @@ camel_tcp_stream_ssl_new_raw (CamelSession *session, const gchar *expected_host,
 gint
 camel_tcp_stream_ssl_enable_ssl (CamelTcpStreamSSL *ssl)
 {
-       PRFileDesc *fd;
+       PRFileDesc *fd, *ssl_fd;
 
        g_return_val_if_fail (CAMEL_IS_TCP_STREAM_SSL (ssl), -1);
 
-       if (ssl->priv->sockfd && !ssl->priv->ssl_mode) {
-               if (!(fd = enable_ssl (ssl, NULL))) {
-                       set_errno (PR_GetError ());
+       fd = camel_tcp_stream_get_file_desc (CAMEL_TCP_STREAM (ssl));
+
+       if (fd && !ssl->priv->ssl_mode) {
+               if (!(ssl_fd = enable_ssl (ssl, fd))) {
+                       _set_errno_from_pr_error (PR_GetError ());
                        return -1;
                }
 
-               ssl->priv->sockfd = fd;
+               _camel_tcp_stream_raw_replace_file_desc (CAMEL_TCP_STREAM_RAW (ssl), ssl_fd);
+               ssl->priv->ssl_mode = TRUE;
 
-               if (!rehandshake_ssl (fd))
+               if (!rehandshake_ssl (ssl_fd))
                        return -1;
        }
 
index 6e63579..1ea727b 100644 (file)
@@ -29,8 +29,7 @@
 
 #ifdef HAVE_SSL
 
-#include <camel/camel-tcp-stream.h>
-#include <prio.h>
+#include <camel/camel-tcp-stream-raw.h>
 
 /* Standard GObject macros */
 #define CAMEL_TYPE_TCP_STREAM_SSL \
@@ -64,12 +63,12 @@ typedef struct _CamelTcpStreamSSLClass CamelTcpStreamSSLClass;
 typedef struct _CamelTcpStreamSSLPrivate CamelTcpStreamSSLPrivate;
 
 struct _CamelTcpStreamSSL {
-       CamelTcpStream parent;
+       CamelTcpStreamRaw parent_object;
        CamelTcpStreamSSLPrivate *priv;
 };
 
 struct _CamelTcpStreamSSLClass {
-       CamelTcpStreamClass parent_class;
+       CamelTcpStreamRawClass parent_class;
 };
 
 GType camel_tcp_stream_ssl_get_type (void);