Re: Patch: avoid closing nss stream before all scheduled reads end
- From: José Dapena Paz <jdapena igalia com>
- To: Philip Van Hoof <spam pvanhoof be>, tinymail-devel-list <tinymail-devel-list gnome org>
- Subject: Re: Patch: avoid closing nss stream before all scheduled reads end
- Date: Tue, 06 May 2008 16:29:03 +0200
El mar, 06-05-2008 a las 14:50 +0200, Philip Van Hoof escribió:
> On IRC we discussed added some comments to the new functionality. Once
> the comments are added, this is approved.
New patch with the changes proposed.
--
José Dapena Paz <jdapena igalia com>
Igalia
Index: libtinymail-camel/camel-lite/camel/camel-tcp-stream-ssl.c
===================================================================
--- libtinymail-camel/camel-lite/camel/camel-tcp-stream-ssl.c (revision 3640)
+++ libtinymail-camel/camel-lite/camel/camel-tcp-stream-ssl.c (working copy)
@@ -86,7 +86,11 @@
static ssize_t stream_read_nb (CamelTcpStream *stream, char *buffer, size_t n);
static int stream_gettimeout (CamelTcpStream *stream);
+static gboolean begin_read (CamelTcpStreamSSL *stream);
+static void end_read (CamelTcpStreamSSL *stream);
+static gint ssl_close (CamelTcpStreamSSL *stream);
+
struct _CamelTcpStreamSSLPrivate {
PRFileDesc *sockfd;
@@ -96,9 +100,83 @@
guint32 flags;
gboolean accepted;
CamelService *service;
+ guint reads;
+ GMutex *reads_lock;
+ gboolean scheduled_close;
};
+/*
+ * This method is used for making sure we don't close the ssl socket
+ * before all the scheduled reads are finished. It also rejects read
+ * if we have a pending close.
+ *
+ * The return value is FALSE when we didn't accept the request to begin
+ * a read operation. In this case we shouldn't call end_read.
+ */
+static inline gboolean
+begin_read (CamelTcpStreamSSL *stream)
+{
+ gboolean retval = TRUE;
+ g_mutex_lock (stream->priv->reads_lock);
+ if (stream->priv->scheduled_close) {
+ retval = FALSE;
+ } else {
+ stream->priv->reads ++;
+ camel_object_ref (stream);
+ }
+ g_mutex_unlock (stream->priv->reads_lock);
+ return retval;
+}
+
+/*
+ * This ends a read request started succesfully in begin_read. Then, if that
+ * method returns FALSE, we shouldn't call this.
+ *
+ * It checks if there's a close call delayed because of reads pending. It it's
+ * so, then it closes the socket and sets the sock reference to NULL.
+ */
+static inline void
+end_read (CamelTcpStreamSSL *stream)
+{
+ gboolean close;
+ g_mutex_lock (stream->priv->reads_lock);
+ stream->priv->reads --;
+ close = ((stream->priv->reads == 0) && (stream->priv->scheduled_close));
+ g_mutex_unlock (stream->priv->reads_lock);
+ if (close) {
+ PR_Shutdown (stream->priv->sockfd, PR_SHUTDOWN_BOTH);
+ PR_Close (stream->priv->sockfd);
+ stream->priv->sockfd = NULL;
+ }
+ camel_object_unref (stream);
+}
+
+
+/*
+ * Closes the stream ssl socket, in case there are no reads pending, or sets
+ * this as requested.
+ */
+static gint
+ssl_close (CamelTcpStreamSSL *stream)
+{
+ gboolean close;
+ g_mutex_lock (stream->priv->reads_lock);
+ close = ((stream->priv->reads == 0) && (stream->priv->sockfd != NULL));
+ if (stream->priv->sockfd != NULL)
+ stream->priv->scheduled_close = TRUE;
+ g_mutex_unlock (stream->priv->reads_lock);
+ if (close) {
+ PR_Shutdown (stream->priv->sockfd, PR_SHUTDOWN_BOTH);
+ if (PR_Close (stream->priv->sockfd) == PR_FAILURE) {
+ stream->priv->sockfd = NULL;
+ return -1;
+ }
+ stream->priv->sockfd = NULL;
+ }
+ return 0;
+}
+
static void
ssl_enable_compress (CamelTcpStream *stream)
{
@@ -144,6 +222,7 @@
CamelTcpStreamSSL *stream = CAMEL_TCP_STREAM_SSL (object);
stream->priv = g_new0 (struct _CamelTcpStreamSSLPrivate, 1);
+ stream->priv->reads_lock = g_mutex_new ();
}
static void
@@ -152,13 +231,14 @@
CamelTcpStreamSSL *stream = CAMEL_TCP_STREAM_SSL (object);
if (stream->priv->sockfd != NULL) {
- PR_Shutdown (stream->priv->sockfd, PR_SHUTDOWN_BOTH);
- PR_Close (stream->priv->sockfd);
+ ssl_close (stream);
}
if (stream->priv->session)
camel_object_unref(stream->priv->session);
+ g_mutex_free (stream->priv->reads_lock);
+
g_free (stream->priv->expected_host);
g_free (stream->priv);
@@ -220,6 +300,7 @@
str = g_strdup (g_get_tmp_dir ());
NSS_InitReadWrite (str);
has_init = TRUE;
+ g_free (str);
}
camel_object_ref(service->session);
@@ -361,7 +442,11 @@
return -1;
}
+ g_mutex_lock (ssl->priv->reads_lock);
ssl->priv->sockfd = fd;
+ ssl->priv->scheduled_close = FALSE;
+ ssl->priv->reads = 0;
+ g_mutex_unlock (ssl->priv->reads_lock);
if (SSL_ResetHandshake (fd, FALSE) == SECFailure) {
set_errno (PR_GetError ());
@@ -424,8 +509,11 @@
} else {
do {
nread = -1;
- if (PR_Available (tcp_stream_ssl->priv->sockfd) != 0)
- nread = PR_Read (tcp_stream_ssl->priv->sockfd, buffer, n);
+ if (begin_read (tcp_stream_ssl)) {
+ if (PR_Available (tcp_stream_ssl->priv->sockfd) != 0)
+ nread = PR_Read (tcp_stream_ssl->priv->sockfd, buffer, n);
+ end_read (tcp_stream_ssl);
+ }
if (nread == -1)
set_errno (PR_GetError ());
} while (0 && (nread == -1 && PR_GetError () == PR_PENDING_INTERRUPT_ERROR));
@@ -490,9 +578,13 @@
#endif
} else {
do {
- nread = PR_Read (tcp_stream_ssl->priv->sockfd, buffer, n);
- if (nread == -1)
- set_errno (PR_GetError ());
+ nread = -1;
+ if (begin_read (tcp_stream_ssl)) {
+ nread = PR_Read (tcp_stream_ssl->priv->sockfd, buffer, n);
+ if (nread == -1)
+ set_errno (PR_GetError ());
+ end_read (tcp_stream_ssl);
+ }
} while (nread == -1 && PR_GetError () == PR_PENDING_INTERRUPT_ERROR);
}
} while (nread == -1 && (PR_GetError () == PR_PENDING_INTERRUPT_ERROR ||
@@ -547,9 +639,13 @@
goto failed;
} else {
do {
- nread = PR_Read (tcp_stream_ssl->priv->sockfd, buffer, n);
- if (nread == -1)
- set_errno (PR_GetError ());
+ nread = -1;
+ if (begin_read (tcp_stream_ssl)) {
+ nread = PR_Read (tcp_stream_ssl->priv->sockfd, buffer, n);
+ if (nread == -1)
+ set_errno (PR_GetError ());
+ end_read (tcp_stream_ssl);
+ }
} while (nread == -1 && PR_GetError () == PR_PENDING_INTERRUPT_ERROR);
}
} while (nread == -1 && (PR_GetError () == PR_PENDING_INTERRUPT_ERROR ||
@@ -618,9 +714,13 @@
#endif
} else {
do {
- w = PR_Write (tcp_stream_ssl->priv->sockfd, buffer + written, n - written);
- if (w == -1)
- set_errno (PR_GetError ());
+ w = -1;
+ if (begin_read (tcp_stream_ssl)) {
+ w = PR_Write (tcp_stream_ssl->priv->sockfd, buffer + written, n - written);
+ if (w == -1)
+ set_errno (PR_GetError ());
+ end_read (tcp_stream_ssl);
+ }
} while (w == -1 && PR_GetError () == PR_PENDING_INTERRUPT_ERROR);
if (w == -1) {
@@ -680,9 +780,13 @@
errno = EINTR;
} else {
do {
- w = PR_Write (tcp_stream_ssl->priv->sockfd, buffer + written, n - written);
- if (w == -1)
- set_errno (PR_GetError ());
+ w = -1;
+ if (begin_read (tcp_stream_ssl)) {
+ w = PR_Write (tcp_stream_ssl->priv->sockfd, buffer + written, n - written);
+ if (w == -1)
+ set_errno (PR_GetError ());
+ end_read (tcp_stream_ssl);
+ }
} while (w == -1 && PR_GetError () == PR_PENDING_INTERRUPT_ERROR);
if (w == -1) {
@@ -723,9 +827,7 @@
return -1;
}
- PR_Shutdown (((CamelTcpStreamSSL *)stream)->priv->sockfd, PR_SHUTDOWN_BOTH);
- if (PR_Close (((CamelTcpStreamSSL *)stream)->priv->sockfd) == PR_FAILURE)
- return -1;
+ ssl_close ((CamelTcpStreamSSL *) stream);
((CamelTcpStreamSSL *)stream)->priv->sockfd = NULL;
@@ -1388,7 +1490,6 @@
errnosave = errno;
PR_Shutdown (fd, PR_SHUTDOWN_BOTH);
PR_Close (fd);
- ssl->priv->sockfd = NULL;
errno = errnosave;
return -1;
@@ -1397,7 +1498,11 @@
errno = 0;
}
+ g_mutex_lock (ssl->priv->reads_lock);
+ ssl->priv->reads = 0;
+ ssl->priv->scheduled_close = FALSE;
ssl->priv->sockfd = fd;
+ g_mutex_unlock (ssl->priv->reads_lock);
return 0;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]