aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--camel/ChangeLog13
-rw-r--r--camel/camel-operation.c40
-rw-r--r--camel/camel-operation.h3
-rw-r--r--camel/camel-tcp-stream-ssl.c165
4 files changed, 201 insertions, 20 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog
index d3913173d6..78386adf70 100644
--- a/camel/ChangeLog
+++ b/camel/ChangeLog
@@ -1,3 +1,16 @@
+2002-11-21 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-tcp-stream-ssl.c (stream_read): Use the new
+ camel_operation_cancel_prfd() function to get the cancellation fd
+ so we can poll on it for cancellation stuff.
+ (stream_write): Same.
+
+2002-11-22 Not Zed <NotZed@Ximian.com>
+
+ * camel-operation.c (camel_operation_cancel_prfd): Implement, gets
+ a nspr pr filedesc to poll/wait on
+ (struct _CamelOperation): include a pr filedesc.
+
2002-11-21 Not Zed <NotZed@Ximian.com>
* providers/imap/camel-imap-store-summary.c
diff --git a/camel/camel-operation.c b/camel/camel-operation.c
index 6c490df73f..8befacce19 100644
--- a/camel/camel-operation.c
+++ b/camel/camel-operation.c
@@ -5,6 +5,9 @@
#include <stdio.h>
#ifdef ENABLE_THREADS
#include <pthread.h>
+#ifdef HAVE_NSS
+#include <nspr.h>
+#endif
#endif
#include <sys/time.h>
@@ -42,6 +45,9 @@ struct _CamelOperation {
#ifdef ENABLE_THREADS
EMsgPort *cancel_port;
int cancel_fd;
+#ifdef HAVE_NSS
+ PRFileDesc *cancel_prfd;
+#endif
#endif
};
@@ -436,6 +442,40 @@ int camel_operation_cancel_fd(CamelOperation *cc)
return cc->cancel_fd;
}
+#ifdef HAVE_NSS
+/**
+ * camel_operation_cancel_prfd:
+ * @cc:
+ *
+ * Retrieve a file descriptor that can be waited on (select, or poll)
+ * for read, to asynchronously detect cancellation.
+ *
+ * Return value: The fd, or NULL if cancellation is not available
+ * (blocked, or has not been registered for this thread).
+ **/
+PRFileDesc *camel_operation_cancel_prfd(CamelOperation *cc)
+{
+ CAMEL_ACTIVE_LOCK();
+
+ if (cc == NULL && operation_active) {
+ cc = g_hash_table_lookup(operation_active, (void *)pthread_self());
+ }
+
+ if (cc == NULL
+ || cc->blocked) {
+ CAMEL_ACTIVE_UNLOCK();
+ return NULL;
+ }
+
+ if (cc->cancel_prfd == NULL)
+ cc->cancel_prfd = e_msgport_prfd(cc->cancel_port);
+
+ CAMEL_ACTIVE_UNLOCK();
+
+ return cc->cancel_prfd;
+}
+#endif /* HAVE_NSS */
+
/**
* camel_operation_start:
* @cc:
diff --git a/camel/camel-operation.h b/camel/camel-operation.h
index 08da410b68..367d916b67 100644
--- a/camel/camel-operation.h
+++ b/camel/camel-operation.h
@@ -52,6 +52,9 @@ void camel_operation_cancel_block(CamelOperation *cc);
void camel_operation_cancel_unblock(CamelOperation *cc);
int camel_operation_cancel_check(CamelOperation *cc);
int camel_operation_cancel_fd(CamelOperation *cc);
+#ifdef HAVE_NSS
+struct PRFileDesc *camel_operation_cancel_prfd(CamelOperation *cc);
+#endif
/* return the registered operation for this thread, if there is one */
CamelOperation *camel_operation_registered(void);
diff --git a/camel/camel-tcp-stream-ssl.c b/camel/camel-tcp-stream-ssl.c
index 3aa841d9df..b20b6d255e 100644
--- a/camel/camel-tcp-stream-ssl.c
+++ b/camel/camel-tcp-stream-ssl.c
@@ -299,18 +299,71 @@ static ssize_t
stream_read (CamelStream *stream, char *buffer, size_t n)
{
CamelTcpStreamSSL *tcp_stream_ssl = CAMEL_TCP_STREAM_SSL (stream);
+ PRFileDesc *cancel_fd;
ssize_t nread;
- do {
- if (camel_operation_cancel_check (NULL)) {
- errno = EINTR;
- return -1;
- }
+ 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 (tcp_stream_ssl->priv->sockfd, buffer, n);
+ if (nread == -1)
+ set_errno (PR_GetError ());
+ } while (nread == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
+ } else {
+ PRSocketOptionData sockopts;
+ PRPollDesc pollfds[2];
+ gboolean nonblock;
+ int error;
- nread = PR_Read (tcp_stream_ssl->priv->sockfd, buffer, n);
- if (nread == -1)
- set_errno (PR_GetError ());
- } while (nread == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
+ /* get O_NONBLOCK options */
+ sockopts.option = PR_SockOpt_Nonblocking;
+ PR_GetSocketOption (tcp_stream_ssl->priv->sockfd, &sockopts);
+ sockopts.option = PR_SockOpt_Nonblocking;
+ nonblock = sockopts.value.non_blocking;
+ sockopts.value.non_blocking = TRUE;
+ PR_SetSocketOption (tcp_stream_ssl->priv->sockfd, &sockopts);
+
+ pollfds[0].fd = tcp_stream_ssl->priv->sockfd;
+ pollfds[0].in_flags = PR_POLL_READ;
+ pollfds[1].fd = cancel_fd;
+ pollfds[1].in_flags = PR_POLL_READ;
+
+ do {
+ pollfds[0].out_flags = 0;
+ pollfds[1].out_flags = 0;
+
+ nread = -1;
+ if (PR_Poll (pollfds, 2, -1) != -1) {
+ if (pollfds[1].out_flags == PR_POLL_READ) {
+ sockopts.option = PR_SockOpt_Nonblocking;
+ sockopts.value.non_blocking = nonblock;
+ PR_SetSocketOption (tcp_stream_ssl->priv->sockfd, &sockopts);
+ errno = EINTR;
+ return -1;
+ }
+
+ do {
+ nread = PR_Read (tcp_stream_ssl->priv->sockfd, buffer, n);
+ if (nread == -1)
+ set_errno (PR_GetError ());
+ } while (nread == -1 && errno == EINTR);
+ } else {
+ errno = EAGAIN;
+ }
+ } while (nread == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
+
+ /* restore O_NONBLOCK options */
+ error = errno;
+ sockopts.option = PR_SockOpt_Nonblocking;
+ sockopts.value.non_blocking = nonblock;
+ PR_SetSocketOption (tcp_stream_ssl->priv->sockfd, &sockopts);
+ errno = error;
+ }
return nread;
}
@@ -320,22 +373,94 @@ stream_write (CamelStream *stream, const char *buffer, size_t n)
{
CamelTcpStreamSSL *tcp_stream_ssl = CAMEL_TCP_STREAM_SSL (stream);
ssize_t w, written = 0;
+ PRFileDesc *cancel_fd;
- do {
- if (camel_operation_cancel_check (NULL)) {
- errno = EINTR;
- return -1;
- }
+ 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 (tcp_stream_ssl->priv->sockfd, buffer + written, n - written);
+ if (w == -1)
+ set_errno (PR_GetError ());
+ } while (w == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
+
+ if (w > 0)
+ written += w;
+ } while (w != -1 && written < n);
+ } else {
+ PRSocketOptionData sockopts;
+ PRPollDesc pollfds[2];
+ gboolean nonblock;
+ int error;
+
+ /* get O_NONBLOCK options */
+ sockopts.option = PR_SockOpt_Nonblocking;
+ PR_GetSocketOption (tcp_stream_ssl->priv->sockfd, &sockopts);
+ sockopts.option = PR_SockOpt_Nonblocking;
+ nonblock = sockopts.value.non_blocking;
+ sockopts.value.non_blocking = TRUE;
+ PR_SetSocketOption (tcp_stream_ssl->priv->sockfd, &sockopts);
+
+ pollfds[0].fd = tcp_stream_ssl->priv->sockfd;
+ pollfds[0].in_flags = PR_POLL_WRITE;
+ pollfds[1].fd = cancel_fd;
+ pollfds[1].in_flags = PR_POLL_READ;
do {
- w = PR_Write (tcp_stream_ssl->priv->sockfd, buffer + written, n - written);
- if (w == -1)
+ pollfds[0].out_flags = 0;
+ pollfds[1].out_flags = 0;
+
+ w = -1;
+ if (PR_Poll (pollfds, 2, -1) != -1) {
+ if (pollfds[1].out_flags == PR_POLL_READ) {
+ sockopts.option = PR_SockOpt_Nonblocking;
+ sockopts.value.non_blocking = nonblock;
+ PR_SetSocketOption (tcp_stream_ssl->priv->sockfd, &sockopts);
+ errno = EINTR;
+ return -1;
+ }
+
+ do {
+ w = PR_Write (tcp_stream_ssl->priv->sockfd, buffer + written, n - written);
+ if (w == -1)
+ set_errno (PR_GetError ());
+ } while (w == -1 && errno == EINTR);
+
+ if (w == -1) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ w = 0;
+ } else {
+ error = errno;
+ sockopts.option = PR_SockOpt_Nonblocking;
+ sockopts.value.non_blocking = nonblock;
+ PR_SetSocketOption (tcp_stream_ssl->priv->sockfd, &sockopts);
+ errno = error;
+ return -1;
+ }
+ } else
+ written += w;
+ } else {
set_errno (PR_GetError ());
- } while (w == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
+ if (errno == EINTR)
+ w = 0;
+ }
+ } while (w != -1 && written < n);
- if (w > 0)
- 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 (tcp_stream_ssl->priv->sockfd, &sockopts);
+ errno = error;
+ }
+
+ if (w == -1)
+ return -1;
return written;
}