aboutsummaryrefslogtreecommitdiffstats
path: root/camel/camel-remote-store.c
diff options
context:
space:
mode:
authorNot Zed <NotZed@Ximian.com>2001-01-15 15:55:30 +0800
committerMichael Zucci <zucchi@src.gnome.org>2001-01-15 15:55:30 +0800
commitb64ffc9183d2c94ce6b8fdf10f382904aa8021e8 (patch)
tree701629078be7b75865fe87c9a348e2d5361004c6 /camel/camel-remote-store.c
parentcff9059380f748309b628041b55abad159aab4d6 (diff)
downloadgsoc2013-evolution-b64ffc9183d2c94ce6b8fdf10f382904aa8021e8.tar
gsoc2013-evolution-b64ffc9183d2c94ce6b8fdf10f382904aa8021e8.tar.gz
gsoc2013-evolution-b64ffc9183d2c94ce6b8fdf10f382904aa8021e8.tar.bz2
gsoc2013-evolution-b64ffc9183d2c94ce6b8fdf10f382904aa8021e8.tar.lz
gsoc2013-evolution-b64ffc9183d2c94ce6b8fdf10f382904aa8021e8.tar.xz
gsoc2013-evolution-b64ffc9183d2c94ce6b8fdf10f382904aa8021e8.tar.zst
gsoc2013-evolution-b64ffc9183d2c94ce6b8fdf10f382904aa8021e8.zip
A cancellable connection routine. (remote_send_string): Return cancelled
2001-01-15 Not Zed <NotZed@Ximian.com> * camel-remote-store.c (socket_connect): A cancellable connection routine. (remote_send_string): Return cancelled exception if we were. (remote_send_stream): " (remote_recv_line): " * camel-stream-fs.c (stream_read): First cut at cancellation stuff. Its looking a bit ugly. svn path=/trunk/; revision=7496
Diffstat (limited to 'camel/camel-remote-store.c')
-rw-r--r--camel/camel-remote-store.c134
1 files changed, 117 insertions, 17 deletions
diff --git a/camel/camel-remote-store.c b/camel/camel-remote-store.c
index 8d095244e2..9e7a60e378 100644
--- a/camel/camel-remote-store.c
+++ b/camel/camel-remote-store.c
@@ -25,6 +25,7 @@
#include <config.h>
+#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
@@ -205,6 +206,87 @@ timeout_cb (gpointer data)
return TRUE;
}
+/* this is a 'cancellable' connect, cancellable from camel_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_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_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;
+ long flags;
+
+ fcntl(fd, F_GETFL, &flags);
+ fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+
+ ret = connect(fd, (struct sockaddr *)&sin, sizeof (sin));
+ if (ret == 0)
+ return fd;
+
+ if (errno != EINPROGRESS) {
+ close(fd);
+ return -1;
+ }
+
+ FD_ZERO(&rdset);
+ FD_ZERO(&wrset);
+ FD_SET(fd, &wrset);
+ FD_SET(cancel_fd, &rdset);
+ tv.tv_usec = 0;
+ tv.tv_sec = 30;
+ if (select((fd+cancel_fd)/2+1, &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)
{
@@ -225,6 +307,20 @@ remote_connect (CamelService *service, CamelException *ex)
port = service->url->port;
else
port = store->default_port;
+
+#if 1
+ fd = socket_connect(h, port);
+ if (fd == -1) {
+ if (errno == EINTR)
+ 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));
@@ -240,6 +336,7 @@ remote_connect (CamelService *service, CamelException *ex)
return FALSE;
}
+#endif
/* parent class connect initialization */
if (CAMEL_SERVICE_CLASS (store_class)->connect (service, ex) == FALSE)
@@ -322,9 +419,11 @@ remote_send_string (CamelRemoteStore *store, CamelException *ex, char *fmt, va_l
#endif
if (camel_stream_printf (store->ostream, "%s", cmdbuf) == -1) {
+ if (errno == EINTR)
+ camel_exception_set(ex, CAMEL_EXCEPTION_USER_CANCEL, _("Operation cancelled"));
+ else
+ camel_exception_set(ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, strerror(errno));
g_free (cmdbuf);
- camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
- g_strerror (errno));
camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL);
return -1;
@@ -381,9 +480,11 @@ remote_send_stream (CamelRemoteStore *store, CamelStream *stream, CamelException
d(fprintf (stderr, "(sending stream)\n"));
ret = camel_stream_write_to_stream (stream, store->ostream);
- if (ret < 0) {
- camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
- g_strerror (errno));
+ if (ret == -1) {
+ if (errno == EINTR)
+ camel_exception_set(ex, CAMEL_EXCEPTION_USER_CANCEL, _("Operation cancelled"));
+ else
+ camel_exception_set(ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, strerror(errno));
camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL);
}
@@ -446,23 +547,22 @@ remote_recv_line (CamelRemoteStore *store, char **dest, CamelException *ex)
if (nread > 0)
g_byte_array_append (bytes, buf, nread);
} while (nread == sizeof (buf) - 1);
-
+
+ if (nread == -1) {
+ if (errno == EINTR)
+ camel_exception_set(ex, CAMEL_EXCEPTION_USER_CANCEL, _("Operation cancelled"));
+ else
+ camel_exception_set(ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, strerror(errno));
+ g_byte_array_free(bytes, TRUE);
+ camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL);
+ return -1;
+ }
+
g_byte_array_append (bytes, "", 1);
ret = bytes->data;
nread = bytes->len - 1;
g_byte_array_free (bytes, FALSE);
- if (nread <= 0) {
- g_free (ret);
- ret = NULL;
- camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
- nread ? g_strerror (errno) :
- _("Server disconnected."));
-
- camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL);
- return -1;
- }
-
/* strip off the CRLF sequence */
while (nread > 0 && ret[nread] != '\r')
ret[nread--] = '\0';