diff options
-rw-r--r-- | camel/ChangeLog | 20 | ||||
-rw-r--r-- | camel/Makefile.am | 4 | ||||
-rw-r--r-- | camel/camel-remote-store.c | 141 | ||||
-rw-r--r-- | camel/camel-tcp-stream-raw.c | 109 | ||||
-rw-r--r-- | camel/camel-tcp-stream-ssl.c | 4 | ||||
-rw-r--r-- | camel/camel-tcp-stream.h | 9 | ||||
-rw-r--r-- | camel/camel-types.h | 2 |
7 files changed, 163 insertions, 126 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog index 9fea64d53c..dcf2d2117e 100644 --- a/camel/ChangeLog +++ b/camel/ChangeLog @@ -1,5 +1,25 @@ 2001-03-13 Jeffrey Stedfast <fejj@ximian.com> + * camel-tcp-stream-ssl.c (camel_tcp_stream_ssl_get_type): + Oops. Make this a subclass of CamelTcpStream, not CamelStream. + + * camel-types.h: Add the defs for CamelTcpStream and + CamelTcpStreamRaw + + * Makefile.am: Add camel-tcp-stream and camel-tcp-stream-raw to + the build. + + * camel-remote-store.c (remote_connect): Update to use + CamelTcpStreams. + + * camel-tcp-stream-raw.c (stream_connect): Made cancellable by + copying the currently used code in camel-remote-store.c. + (stream_setsockopt): Oops, flags = fcntl (..., GET_FL); + (camel_tcp_stream_raw_get_type): Oops. Make this a subclass of + CamelTcpStream, not CamelStream. + +2001-03-13 Jeffrey Stedfast <fejj@ximian.com> + * camel.c (camel_init): Since all of the Mozilla libs (including NSPR and NSS) correctly handle reinitializations, we might as well init both NSPR and NSS in camel_init so we can be sure of that diff --git a/camel/Makefile.am b/camel/Makefile.am index da1bc24c43..9b3390d53d 100644 --- a/camel/Makefile.am +++ b/camel/Makefile.am @@ -68,6 +68,8 @@ libcamel_la_SOURCES = \ camel-stream-mem.c \ camel-stream-null.c \ camel-stream.c \ + camel-tcp-stream-raw.c \ + camel-tcp-stream.c \ camel-transport.c \ camel-uid-cache.c \ camel-url.c \ @@ -132,6 +134,8 @@ libcamelinclude_HEADERS = \ camel-stream-mem.h \ camel-stream-null.h \ camel-stream.h \ + camel-tcp-stream-raw.h \ + camel-tcp-stream.h \ camel-transport.h \ camel-types.h \ camel-uid-cache.h \ diff --git a/camel/camel-remote-store.c b/camel/camel-remote-store.c index f756eb5ac8..681aca0113 100644 --- a/camel/camel-remote-store.c +++ b/camel/camel-remote-store.c @@ -42,7 +42,12 @@ #include "camel-session.h" #include "camel-stream.h" #include "camel-stream-buffer.h" -#include "camel-stream-fs.h" +#include "camel-tcp-stream.h" +#include "camel-tcp-stream-raw.h" +#if HAVE_NSS +#include "camel-tcp-stream-ssl.h" +#endif + #include "camel-url.h" #include "string-utils.h" @@ -194,147 +199,51 @@ timeout_cb (gpointer data) return TRUE; } -/* this is a 'cancellable' connect, cancellable from camel_operation_cancel etc */ -/* returns -1 & errno == EINTR if the connection was cancelled */ -static int socket_connect(struct hostent *h, int port) -{ - struct sockaddr_in sin; - int fd; - int ret; - socklen_t len; - struct timeval tv; - int cancel_fd; - - /* see if we're cancelled yet */ - if (camel_operation_cancel_check(NULL)) { - errno = EINTR; - return -1; - } - - /* setup connect, we do it using a nonblocking socket so we can poll it */ - sin.sin_port = htons(port); - sin.sin_family = h->h_addrtype; - memcpy (&sin.sin_addr, h->h_addr, sizeof (sin.sin_addr)); - - fd = socket (h->h_addrtype, SOCK_STREAM, 0); - - cancel_fd = camel_operation_cancel_fd(NULL); - if (cancel_fd == -1) { - ret = connect(fd, (struct sockaddr *)&sin, sizeof (sin)); - if (ret == -1) { - close(fd); - return -1; - } - return fd; - } else { - fd_set rdset, wrset; - int flags, fdmax; - - flags = fcntl(fd, F_GETFL); - fcntl(fd, F_SETFL, flags | O_NONBLOCK); - - ret = connect(fd, (struct sockaddr *)&sin, sizeof (sin)); - if (ret == 0) { - fcntl(fd, F_SETFL, flags); - return fd; - } - - if (errno != EINPROGRESS) { - close(fd); - return -1; - } - - FD_ZERO(&rdset); - FD_ZERO(&wrset); - FD_SET(fd, &wrset); - FD_SET(cancel_fd, &rdset); - fdmax = MAX(fd, cancel_fd)+1; - tv.tv_usec = 0; - tv.tv_sec = 60*4; - if (select(fdmax, &rdset, &wrset, 0, &tv) == 0) { - close(fd); - errno = ETIMEDOUT; - return -1; - } - if (cancel_fd != -1 && FD_ISSET(cancel_fd, &rdset)) { - close(fd); - errno = EINTR; - return -1; - } else { - len = sizeof(int); - if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &ret, &len) == -1) { - close(fd); - return -1; - } - if (ret != 0) { - close(fd); - errno = ret; - return -1; - } - } - fcntl(fd, F_SETFL, flags); - } - - return fd; -} - static gboolean remote_connect (CamelService *service, CamelException *ex) { CamelRemoteStore *store = CAMEL_REMOTE_STORE (service); + CamelStream *tcp_stream; struct hostent *h; - struct sockaddr_in sin; - gint fd; - gint port; + gint ret, port; h = camel_service_gethost (service, ex); if (!h) return FALSE; - /* connect to the server */ - sin.sin_family = h->h_addrtype; - if (service->url->port) port = service->url->port; else port = store->default_port; - -#if 1 - fd = socket_connect(h, port); - if (fd == -1) { + +#ifdef HAVE_NSS + if (store->use_ssl) + tcp_stream = camel_tcp_stream_ssl_new (); + else + tcp_stream = camel_tcp_stream_raw_new (); +#else + tcp_stream = camel_tcp_stream_raw_new (); +#endif /* HAVE_NSS */ + + ret = camel_tcp_stream_connect (CAMEL_TCP_STREAM (tcp_stream), h, port); + if (ret == -1) { if (errno == EINTR) - camel_exception_set(ex, CAMEL_EXCEPTION_USER_CANCEL, _("Connection cancelled")); + camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, + _("Connection cancelled")); else camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, _("Could not connect to %s (port %d): %s"), service->url->host ? service->url->host : _("(unknown host)"), - port, strerror (errno)); - return FALSE; - } -#else - sin.sin_port = htons (port); - - memcpy (&sin.sin_addr, h->h_addr, sizeof (sin.sin_addr)); - - fd = socket (h->h_addrtype, SOCK_STREAM, 0); - if (fd == -1 || connect (fd, (struct sockaddr *)&sin, sizeof (sin)) == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Could not connect to %s (port %d): %s"), - service->url->host ? service->url->host : _("(unknown host)"), - port, g_strerror (errno)); - if (fd > -1) - close (fd); - + port, g_strerror (errno)); return FALSE; } -#endif /* parent class connect initialization */ if (CAMEL_SERVICE_CLASS (store_class)->connect (service, ex) == FALSE) return FALSE; - store->ostream = camel_stream_fs_new_with_fd (fd); - store->istream = camel_stream_buffer_new (store->ostream, CAMEL_STREAM_BUFFER_READ); + store->ostream = tcp_stream; + store->istream = camel_stream_buffer_new (tcp_stream, CAMEL_STREAM_BUFFER_READ); /* Okay, good enough for us */ CAMEL_SERVICE (store)->connected = TRUE; diff --git a/camel/camel-tcp-stream-raw.c b/camel/camel-tcp-stream-raw.c index 6467eed5da..bc9223a267 100644 --- a/camel/camel-tcp-stream-raw.c +++ b/camel/camel-tcp-stream-raw.c @@ -23,9 +23,11 @@ #include <config.h> #include "camel-tcp-stream-raw.h" -#include <unistd.h> +#include "camel-operation.h" +#include <sys/time.h> #include <sys/types.h> #include <sys/stat.h> +#include <unistd.h> #include <fcntl.h> #include <errno.h> #include <string.h> @@ -52,7 +54,7 @@ camel_tcp_stream_raw_class_init (CamelTcpStreamRawClass *camel_tcp_stream_raw_cl CamelStreamClass *camel_stream_class = CAMEL_STREAM_CLASS (camel_tcp_stream_raw_class); - parent_class = CAMEL_STREAM_CLASS (camel_type_get_global_classfuncs (camel_tcp_stream_get_type ())); + parent_class = CAMEL_TCP_STREAM_CLASS (camel_type_get_global_classfuncs (camel_tcp_stream_get_type ())); /* virtual method overload */ camel_stream_class->read = stream_read; @@ -89,7 +91,7 @@ camel_tcp_stream_raw_get_type (void) static CamelType type = CAMEL_INVALID_TYPE; if (type == CAMEL_INVALID_TYPE) { - type = camel_type_register (camel_stream_get_type (), + type = camel_type_register (camel_tcp_stream_get_type (), "CamelTcpStreamRaw", sizeof (CamelTcpStreamRaw), sizeof (CamelTcpStreamRawClass), @@ -165,16 +167,114 @@ stream_close (CamelStream *stream) return 0; } +/* this is a 'cancellable' connect, cancellable from camel_operation_cancel etc */ +/* returns -1 & errno == EINTR if the connection was cancelled */ +static int +socket_connect (struct hostent *h, int port) +{ + struct sockaddr_in sin; + int fd; + int ret; + socklen_t len; + struct timeval tv; + int cancel_fd; + + /* see if we're cancelled yet */ + if (camel_operation_cancel_check (NULL)) { + errno = EINTR; + return -1; + } + + /* setup connect, we do it using a nonblocking socket so we can poll it */ + sin.sin_port = htons (port); + sin.sin_family = h->h_addrtype; + memcpy (&sin.sin_addr, h->h_addr, sizeof (sin.sin_addr)); + + fd = socket (h->h_addrtype, SOCK_STREAM, 0); + + cancel_fd = camel_operation_cancel_fd (NULL); + if (cancel_fd == -1) { + ret = connect (fd, (struct sockaddr *)&sin, sizeof (sin)); + if (ret == -1) { + close (fd); + return -1; + } + + return fd; + } else { + fd_set rdset, wrset; + int flags, fdmax; + + flags = fcntl (fd, F_GETFL); + fcntl (fd, F_SETFL, flags | O_NONBLOCK); + + ret = connect (fd, (struct sockaddr *)&sin, sizeof (sin)); + if (ret == 0) { + fcntl (fd, F_SETFL, flags); + return fd; + } + + if (errno != EINPROGRESS) { + close (fd); + return -1; + } + + FD_ZERO (&rdset); + FD_ZERO (&wrset); + FD_SET (fd, &wrset); + FD_SET (cancel_fd, &rdset); + fdmax = MAX (fd, cancel_fd) + 1; + tv.tv_usec = 0; + tv.tv_sec = 60 * 4; + + if (select (fdmax, &rdset, &wrset, 0, &tv) == 0) { + close (fd); + errno = ETIMEDOUT; + return -1; + } + + if (cancel_fd != -1 && FD_ISSET (cancel_fd, &rdset)) { + close (fd); + errno = EINTR; + return -1; + } else { + len = sizeof (int); + + if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &len) == -1) { + close (fd); + return -1; + } + + if (ret != 0) { + close (fd); + errno = ret; + return -1; + } + } + + fcntl (fd, F_SETFL, flags); + } + + return fd; +} +#define DIVINE_INTERVENTION static int stream_connect (CamelTcpStream *stream, struct hostent *host, int port) { CamelTcpStreamRaw *raw = CAMEL_TCP_STREAM_RAW (stream); +#ifndef DIVINE_INTERVENTION struct sockaddr_in sin; +#endif int fd; g_return_val_if_fail (host != NULL, -1); +#ifdef DIVINE_INTERVENTION + fd = socket_connect (host, port); + if (fd == -1) + return -1; +#else sin.sin_family = host->h_addrtype; sin.sin_port = htons (port); @@ -188,6 +288,7 @@ stream_connect (CamelTcpStream *stream, struct hostent *host, int port) return -1; } +#endif raw->sockfd = fd; @@ -272,7 +373,7 @@ stream_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data) if (data->option == CAMEL_SOCKOPT_NONBLOCKING) { int flags, set; - fcntl (((CamelTcpStreamRaw *)stream)->sockfd, F_GETFL); + flags = fcntl (((CamelTcpStreamRaw *)stream)->sockfd, F_GETFL); if (flags == -1) return -1; diff --git a/camel/camel-tcp-stream-ssl.c b/camel/camel-tcp-stream-ssl.c index 14e26bc706..15b907845a 100644 --- a/camel/camel-tcp-stream-ssl.c +++ b/camel/camel-tcp-stream-ssl.c @@ -62,7 +62,7 @@ camel_tcp_stream_ssl_class_init (CamelTcpStreamSSLClass *camel_tcp_stream_ssl_cl CamelStreamClass *camel_stream_class = CAMEL_STREAM_CLASS (camel_tcp_stream_ssl_class); - parent_class = CAMEL_STREAM_CLASS (camel_type_get_global_classfuncs (camel_tcp_stream_get_type ())); + parent_class = CAMEL_TCP_STREAM_CLASS (camel_type_get_global_classfuncs (camel_tcp_stream_get_type ())); /* virtual method overload */ camel_stream_class->read = stream_read; @@ -104,7 +104,7 @@ camel_tcp_stream_ssl_get_type (void) static CamelType type = CAMEL_INVALID_TYPE; if (type == CAMEL_INVALID_TYPE) { - type = camel_type_register (camel_stream_get_type (), + type = camel_type_register (camel_tcp_stream_get_type (), "CamelTcpStreamSSL", sizeof (CamelTcpStreamSSL), sizeof (CamelTcpStreamSSLClass), diff --git a/camel/camel-tcp-stream.h b/camel/camel-tcp-stream.h index 56afa7a1fd..79d3f90f08 100644 --- a/camel/camel-tcp-stream.h +++ b/camel/camel-tcp-stream.h @@ -35,6 +35,7 @@ extern "C" { #include <sys/socket.h> #include <netinet/in.h> #include <netinet/tcp.h> +#include <netdb.h> #include <unistd.h> #define CAMEL_TCP_STREAM_TYPE (camel_tcp_stream_get_type ()) @@ -99,16 +100,16 @@ typedef struct { int (*connect) (CamelTcpStream *stream, struct hostent *host, int port); int (*getsockopt) (CamelTcpStream *stream, CamelSockOptData *data); int (*setsockopt) (CamelTcpStream *stream, const CamelSockOptData *data); - + } CamelTcpStreamClass; /* Standard Camel function */ CamelType camel_tcp_stream_get_type (void); /* public methods */ -int camel_tcp_stream_connect (CamelTcpStream *stream, struct hostent *host, int port); -int camel_tcp_stream_getsockopt (CamelTcpStream *stream, CamelSockOptData *data); -int camel_tcp_stream_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data); +int camel_tcp_stream_connect (CamelTcpStream *stream, struct hostent *host, int port); +int camel_tcp_stream_getsockopt (CamelTcpStream *stream, CamelSockOptData *data); +int camel_tcp_stream_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data); #ifdef __cplusplus } diff --git a/camel/camel-types.h b/camel/camel-types.h index 8cf64d17ff..eed0ff99a6 100644 --- a/camel/camel-types.h +++ b/camel/camel-types.h @@ -64,6 +64,8 @@ typedef struct _CamelStreamDataWrapper CamelStreamDataWrapper; typedef struct _CamelStreamFilter CamelStreamFilter; typedef struct _CamelStreamFs CamelStreamFs; typedef struct _CamelStreamMem CamelStreamMem; +typedef struct _CamelTcpStream CamelTcpStream; +typedef struct _CamelTcpStreamRaw CamelTcpStreamRaw; typedef struct _CamelTransport CamelTransport; #ifdef __cplusplus |