[Goodies-commits] r5247 - xfce4-mailwatch-plugin/trunk/libmailwatch-core

Brian Tarricone kelnos at xfce.org
Sat Aug 16 10:50:28 CEST 2008


Author: kelnos
Date: 2008-08-16 08:50:28 +0000 (Sat, 16 Aug 2008)
New Revision: 5247

Modified:
   xfce4-mailwatch-plugin/trunk/libmailwatch-core/mailwatch-net-conn.c
Log:
do some serious refactoring, and use non-blocking sockets for everything

Modified: xfce4-mailwatch-plugin/trunk/libmailwatch-core/mailwatch-net-conn.c
===================================================================
--- xfce4-mailwatch-plugin/trunk/libmailwatch-core/mailwatch-net-conn.c	2008-08-16 08:50:17 UTC (rev 5246)
+++ xfce4-mailwatch-plugin/trunk/libmailwatch-core/mailwatch-net-conn.c	2008-08-16 08:50:28 UTC (rev 5247)
@@ -83,6 +83,11 @@
                                   ) \
                              )
 
+#define RECV_TIMEOUT            30  /* seconds */
+#define TIMER_INIT              time_t __timer_start
+#define TIMER_START             __timer_start = time(NULL)
+#define TIMER_EXPIRED(endtime)  (time(NULL) - __timer_start >= (endtime))
+
 struct _XfceMailwatchNetConn
 {
     gchar *hostname;
@@ -106,7 +111,15 @@
     gpointer should_continue_user_data;
 };
 
+typedef enum
+{
+    XFCE_MAILWATCH_NET_CONN_SUCCESS = 0,
+    XFCE_MAILWATCH_NET_CONN_FATAL,
+    XFCE_MAILWATCH_NET_CONN_ERROR,
+} XfceMailwatchNetConnStatus;
 
+
+
 #ifdef HAVE_SSL_SUPPORT
 
 /* missing from 1.2.0? */
@@ -185,6 +198,163 @@
 #endif  /* defined(HAVE_SSL_SUPPORT) */
 
 
+
+static gboolean
+xfce_mailwatch_net_conn_tls_handshake(XfceMailwatchNetConn *net_conn,
+                                      GError **error)
+{
+    gint ret;
+    TIMER_INIT;
+
+    TIMER_START;
+    do {
+        ret = gnutls_handshake(net_conn->gt_session);
+    } while((GNUTLS_E_AGAIN == ret || GNUTLS_E_INTERRUPTED == ret)
+            && !TIMER_EXPIRED(RECV_TIMEOUT) && SHOULD_CONTINUE(net_conn));
+
+    if(ret != GNUTLS_E_SUCCESS) {
+        gint code = XFCE_MAILWATCH_ERROR_FAILED;
+        const gchar *reason;
+
+        if(!SHOULD_CONTINUE(net_conn)) {
+            code = XFCE_MAILWATCH_ERROR_ABORTED;
+            reason = _("Operation aborted");
+        } else if(GNUTLS_E_AGAIN == ret || GNUTLS_E_INTERRUPTED == ret)
+            reason = strerror(ETIMEDOUT);
+        else
+            reason = gnutls_strerror(ret);
+        if(error)
+            g_set_error(error, XFCE_MAILWATCH_ERROR, code, reason);
+        g_critical("XfceMailwatch: TLS handshake failed: %s", reason);
+
+        return FALSE;
+    }
+
+    DBG("TLS handshake succeeded");
+
+    return TRUE;
+}
+
+static XfceMailwatchNetConnStatus
+xfce_mailwatch_net_conn_do_connect(XfceMailwatchNetConn *net_conn,
+                                   struct sockaddr *addr,
+                                   size_t addrlen,
+                                   GError **error)
+{
+    gint ret;
+    TIMER_INIT;
+
+    TIMER_START;
+    do {
+        ret = connect(net_conn->fd, addr, addrlen);
+    } while(ret < 0 && (EINTR == errno || EAGAIN == errno)
+            && !TIMER_EXPIRED(RECV_TIMEOUT) && SHOULD_CONTINUE(net_conn));
+
+    if(!ret || (ret < 0 && EINPROGRESS == errno))  /* we're done here */
+        return XFCE_MAILWATCH_NET_CONN_SUCCESS;
+
+    /* this is a little different.  the only 'fatal' error at this
+     * point in the overall connect operation is if SHOULD_CONTINUE
+     * is false.  in that case, we set |error| and return _FATAL.
+     * if the timer expired or another error occurred, we just
+     * return a non-fatal _ERROR without setting |error|. */
+    if(!SHOULD_CONTINUE(net_conn)) {
+        if(error) {
+            g_set_error(error, XFCE_MAILWATCH_ERROR,
+                        XFCE_MAILWATCH_ERROR_ABORTED,
+                        _("Operation aborted"));
+        }
+
+        return XFCE_MAILWATCH_NET_CONN_FATAL;
+    }
+
+    return XFCE_MAILWATCH_NET_CONN_ERROR;
+}
+
+static XfceMailwatchNetConnStatus
+xfce_mailwatch_net_conn_get_connect_status(XfceMailwatchNetConn *net_conn,
+                                           struct sockaddr *addr,
+                                           GError **error)
+{
+    TIMER_INIT;
+
+    TIMER_START;
+    do {
+        fd_set wfd;
+        struct timeval tv = { 1, 0 };
+        int sock_err = 0;
+        socklen_t sock_err_len = sizeof(int);
+
+        FD_ZERO(&wfd);
+        FD_SET(net_conn->fd, &wfd);
+
+        DBG("checking for a connection...");
+
+        /* wait until the connect attempt finishes */
+        if(select(FD_SETSIZE, NULL, &wfd, NULL, &tv) < 0) {
+            if(EINTR == errno)
+                continue;
+            /* FIXME: should a select() failure actually be fatal? */
+            return XFCE_MAILWATCH_NET_CONN_ERROR;
+        }
+
+        /* check to see if it finished, and, if so, if there was an
+         * error, or if it completed successfully */
+        if(!FD_ISSET(net_conn->fd, &wfd))
+            continue;
+
+        if(!getsockopt(net_conn->fd, SOL_SOCKET, SO_ERROR,
+                       &sock_err, &sock_err_len)
+           && !sock_err)
+        {
+            DBG("    connection succeeded");
+
+            /* figure out the actual port */
+            switch(addr->sa_family) {
+#ifdef ENABLE_IPV6_SUPPORT
+                case AF_INET6:
+                {
+                    struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)addr;
+                    net_conn->actual_port = ntohs(addr_in6->sin6_port);
+                    break;
+                }
+#endif
+                case AF_INET:
+                {
+                    struct sockaddr_in *addr_in = (struct sockaddr_in *)addr;
+                    net_conn->actual_port = ntohs(addr_in->sin_port);
+                    break;
+                }
+
+                default:
+                    g_warning("Unable to determine socket type to get real port number");
+                    break;
+            }
+
+            errno = 0;
+            return XFCE_MAILWATCH_NET_CONN_SUCCESS;
+        } else {
+            DBG("    connection failed: sock_err is (%d) %s",
+                sock_err, strerror(sock_err));
+            errno = sock_err;
+            return XFCE_MAILWATCH_NET_CONN_ERROR;
+        }
+    } while(!TIMER_EXPIRED(RECV_TIMEOUT) && SHOULD_CONTINUE(net_conn));
+
+    if(!SHOULD_CONTINUE(net_conn)) {
+        if(error) {
+            g_set_error(error, XFCE_MAILWATCH_ERROR,
+                        XFCE_MAILWATCH_ERROR_ABORTED, _("Operation aborted"));
+        }
+
+        return XFCE_MAILWATCH_NET_CONN_FATAL;
+    }
+
+    return XFCE_MAILWATCH_NET_CONN_ERROR;
+}
+
+
+
 void
 xfce_mailwatch_net_conn_init()
 {
@@ -331,7 +501,6 @@
 xfce_mailwatch_net_conn_connect(XfceMailwatchNetConn *net_conn,
                                 GError **error)
 {
-    gboolean connect_succeeded = FALSE;
     struct addrinfo *addresses = NULL, *ai;
     
     g_return_val_if_fail(net_conn && (!error || !*error), FALSE);
@@ -345,8 +514,6 @@
     }
     
     for(ai = addresses; ai; ai = ai->ai_next) {
-        gint ret;
-
         net_conn->fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
         if(net_conn->fd < 0)
             continue;
@@ -354,139 +521,63 @@
         if(fcntl(net_conn->fd, F_SETFL,
                  fcntl(net_conn->fd, F_GETFL) | O_NONBLOCK))
         {
-            g_warning(_("Unable to set socket to non-blocking mode.  If the connect attempt hangs, the panel may hang on close."));
+            g_warning(_("Unable to set socket to non-blocking mode. Things may not work properly from here on out."));
         }
         
-        do {
-            ret = connect(net_conn->fd, ai->ai_addr, ai->ai_addrlen);
+        switch(xfce_mailwatch_net_conn_do_connect(net_conn, ai->ai_addr,
+                                                  ai->ai_addrlen, error))
+        {
+            case XFCE_MAILWATCH_NET_CONN_FATAL:
+                goto out_err;
+            case XFCE_MAILWATCH_NET_CONN_ERROR:
+                close(net_conn->fd);
+                net_conn->fd = -1;
+                continue;
+            case XFCE_MAILWATCH_NET_CONN_SUCCESS:
+                break;
+        }
 
-            if(ret < 0 && !SHOULD_CONTINUE(net_conn)) {
-                if(error) {
-                    g_set_error(error, XFCE_MAILWATCH_ERROR,
-                                XFCE_MAILWATCH_ERROR_ABORTED, NULL);
-                    goto out_err;
+        switch(xfce_mailwatch_net_conn_get_connect_status(net_conn,
+                                                          ai->ai_addr,
+                                                          error))
+        {
+            case XFCE_MAILWATCH_NET_CONN_FATAL:
+                goto out_err;
+            case XFCE_MAILWATCH_NET_CONN_ERROR:
+                close(net_conn->fd);
+                net_conn->fd = -1;
+                continue;
+            case XFCE_MAILWATCH_NET_CONN_SUCCESS:
+#if 0  /* let's use non-blocking sockets.  this can potentially hide
+        * bugs in my implementation, though */
+                if(fcntl(net_conn->fd, F_SETFL,
+                         fcntl(net_conn->fd, F_GETFL) & ~(O_NONBLOCK)))
+                {
+                    g_warning(_("Unable to return socket to blocking mode.  Data may not be retreived correctly."));
                 }
-            }
-        } while(ret < 0 && (EINTR == errno || EAGAIN == errno));
-
-        if(ret < 0 && EINPROGRESS == errno) {
-            gint iters_left;
-
-            for(iters_left = 45; iters_left >= 0; iters_left--) {
-                fd_set wfd;
-                struct timeval tv = { 1, 0 };
-                int sock_err = 0;
-                socklen_t sock_err_len = sizeof(int);
-                
-                FD_ZERO(&wfd);
-                FD_SET(net_conn->fd, &wfd);
-                
-                DBG("checking for a connection...");
-
-                /* check the main thread to see if we're supposed to quit */
-                if(!SHOULD_CONTINUE(net_conn)) {
-                    if(error) {
-                        g_set_error(error, XFCE_MAILWATCH_ERROR,
-                                    XFCE_MAILWATCH_ERROR_ABORTED, NULL);
-                    }
-                    goto out_err;
-                }
-                
-                /* wait until the connect attempt finishes */
-                if(select(FD_SETSIZE, NULL, &wfd, NULL, &tv) < 0) {
-                    if(EINTR == errno || EAGAIN == errno)
-                        continue;
-                    else
-                        break;
-                }
-                
-                /* check to see if it finished, and, if so, if there was an
-                 * error, or if it completed successfully */
-                if(FD_ISSET(net_conn->fd, &wfd)) {
-                    if(!getsockopt(net_conn->fd, SOL_SOCKET, SO_ERROR,
-                                   &sock_err, &sock_err_len)
-                       && !sock_err)
-                    {
-                        DBG("    connection succeeded");
-                        connect_succeeded = TRUE;
-                        errno = 0;
-
-                        /* figure out the actual port */
-                        switch(ai->ai_addr->sa_family) {
-#ifdef ENABLE_IPV6_SUPPORT
-                            case AF_INET6:
-                            {
-                                struct sockaddr_in6 *addr = (struct sockaddr_in6 *)ai->ai_addr;
-                                net_conn->actual_port = ntohs(addr->sin6_port);
-                                break;
-                            }
 #endif
-                            case AF_INET:
-                            {
-                                struct sockaddr_in *addr = (struct sockaddr_in *)ai->ai_addr;
-                                net_conn->actual_port = ntohs(addr->sin_port);
-                                break;
-                            }
-
-                            default:
-                                g_warning("Unable to determine socket type to get real port number");
-                                break;
-                        }
-                    } else {
-                        DBG("    connection failed: sock_err is (%d) %s",
-                            sock_err, strerror(sock_err));
-                        errno = sock_err;
-                    }
-                    break;
-                } else
-                    errno = ETIMEDOUT;
-            }
+                freeaddrinfo(addresses);
+                return TRUE;
         }
-        
-        if(connect_succeeded) {
-            if(fcntl(net_conn->fd, F_SETFL,
-                     fcntl(net_conn->fd, F_GETFL) & ~(O_NONBLOCK)))
-            {
-                g_warning(_("Unable to return socket to blocking mode.  Data may not be retreived correctly."));
-            }
-            break;
-        } else {
-            DBG("failed to connect");
-            if(net_conn->fd != -1) {
-                close(net_conn->fd);
-                net_conn->fd = -1;
-            }
-        }
-        
-        if(!SHOULD_CONTINUE(net_conn)) {
-            if(error) {
-                g_set_error(error, XFCE_MAILWATCH_ERROR,
-                            XFCE_MAILWATCH_ERROR_ABORTED, NULL);
-            }
-            goto out_err;
-        }
     }
-    
-    if(!connect_succeeded) {
-        if(error) {
-            g_set_error(error, XFCE_MAILWATCH_ERROR, 0,
-                        _("Failed to connect to server \"%s\": %s"),
-                        net_conn->hostname, strerror(errno));
-        }
-    }
 
 out_err:
     
-    if(!connect_succeeded && net_conn->fd != -1) {  /* needed for the gotos */
-        shutdown(net_conn->fd, SHUT_RDWR);
+    if(net_conn->fd >= 0) {
         close(net_conn->fd);
         net_conn->fd = -1;
     }
 
+    if(error && !*error) {
+        g_set_error(error, XFCE_MAILWATCH_ERROR, 0,
+                    _("Failed to connect to server \"%s\": %s"),
+                    net_conn->hostname, strerror(errno));
+    }
+
     if(addresses)
         freeaddrinfo(addresses);
 
-    return connect_succeeded;
+    return FALSE;
 }
 
 gboolean
@@ -494,7 +585,6 @@
                                     GError **error)
 {
 #ifdef HAVE_SSL_SUPPORT
-    gint gt_ret;
     const int cert_type_prio[2] = { GNUTLS_CRT_X509, 0 };
 #endif
 
@@ -517,47 +607,28 @@
                            net_conn->gt_creds);
     gnutls_transport_set_ptr(net_conn->gt_session,
                              (gnutls_transport_ptr_t)net_conn->fd);
+    if(fcntl(net_conn->fd, F_GETFL) & O_NONBLOCK)
+        gnutls_transport_set_lowat(net_conn->gt_session, 0);
     
-    do {
-        gt_ret = gnutls_handshake(net_conn->gt_session);
+    if(!xfce_mailwatch_net_conn_tls_handshake(net_conn, error)) {
+#if 0
+        gnutls_bye(net_conn->gt_session, GNUTLS_SHUT_RDWR);
+#endif
+        gnutls_deinit(net_conn->gt_session);
+        gnutls_certificate_free_credentials(net_conn->gt_creds);
 
-        if(gt_ret != GNUTLS_E_SUCCESS && !SHOULD_CONTINUE(net_conn)) {
-            if(error) {
-                g_set_error(error, XFCE_MAILWATCH_ERROR,
-                            XFCE_MAILWATCH_ERROR_ABORTED, NULL);
-            }
-            goto out_err;
-        }
-    } while(gt_ret == GNUTLS_E_AGAIN || gt_ret == GNUTLS_E_INTERRUPTED);
-
-    if(gt_ret != GNUTLS_E_SUCCESS) {
-        if(error) {
-            g_set_error(error, XFCE_MAILWATCH_ERROR, 0,
-                        gnutls_strerror(gt_ret));
-        }
-        g_critical(_("XfceMailwatch: TLS handshake failed: %s"), gnutls_strerror(gt_ret));
-        goto out_err;
+        return FALSE;
     }
 
-    DBG("TLS handshake succeeded");
     net_conn->is_secure = TRUE;
 
     return TRUE;
-
-out_err:
-#if 0
-    gnutls_bye(net_conn->gt_session, GNUTLS_SHUT_RDWR);
-#endif
-    gnutls_deinit(net_conn->gt_session);
-    gnutls_certificate_free_credentials(net_conn->gt_creds);
-
-    return FALSE;
 #else
     if(error) {
         g_set_error(error, XFCE_MAILWATCH_ERROR, 0,
                     _("Not compiled with SSL/TLS support"));
     }
-    g_critical(_("XfceMailwatch: TLS handshake failed: not compiled with SSL support."));
+    g_critical("XfceMailwatch: TLS handshake failed: not compiled with SSL support.");
     
     return FALSE;
 #endif
@@ -570,6 +641,7 @@
                                   GError **error)
 {
     gint bout = 0;
+    TIMER_INIT;
 
     g_return_val_if_fail(net_conn && (!error || !*error), -1);
     g_return_val_if_fail(net_conn->fd != -1, -1);
@@ -581,54 +653,41 @@
     if(net_conn->is_secure) {
         gint ret = 0, totallen = buf_len;
         gint bytesleft = totallen;
-        
+
         while(bytesleft > 0) {
+            TIMER_START;
             do {
                 ret = gnutls_record_send(net_conn->gt_session,
                                          buf + totallen - bytesleft,
                                          bytesleft);
 
-                if(GNUTLS_E_SUCCESS != ret && !SHOULD_CONTINUE(net_conn)) {
-                    if(error) {
-                        g_set_error(error, XFCE_MAILWATCH_ERROR,
-                                    XFCE_MAILWATCH_ERROR_ABORTED, NULL);
-                    }
-                    return -1;
+                if(GNUTLS_E_REHANDSHAKE == ret) {
+                    if(!xfce_mailwatch_net_conn_tls_handshake(net_conn, error))
+                        return -1;
+                    ret = GNUTLS_E_AGAIN;
                 }
-            } while(GNUTLS_E_INTERRUPTED == ret || GNUTLS_E_AGAIN == ret);
-            
-            if(GNUTLS_E_REHANDSHAKE == ret) {
-                /* server has requested a new handshake */
-                do {
-                    ret = gnutls_handshake(net_conn->gt_session);
+            } while((GNUTLS_E_INTERRUPTED == ret || GNUTLS_E_AGAIN == ret)
+                    && !TIMER_EXPIRED(RECV_TIMEOUT) && SHOULD_CONTINUE(net_conn));
 
-                    if(GNUTLS_E_SUCCESS != ret && !SHOULD_CONTINUE(net_conn)) {
-                        if(error) {
-                            g_set_error(error, XFCE_MAILWATCH_ERROR,
-                                        XFCE_MAILWATCH_ERROR_ABORTED, NULL);
-                        }
-                        return -1;
-                    }
-                } while(GNUTLS_E_AGAIN == ret || GNUTLS_E_INTERRUPTED == ret);
-                
-                if(GNUTLS_E_SUCCESS != ret) {
-                    if(error) {
-                        g_set_error(error, XFCE_MAILWATCH_ERROR, 0,
-                                    _("TLS handshake failed (%d): %s"), ret,
-                                    gnutls_strerror(ret));
-                    }
-                    return -1;
-                }
-            } else if(ret < 0) {
+            if(ret < 0) {
+                gint code = XFCE_MAILWATCH_ERROR_FAILED;
+                const gchar *reason;
+
+                if(!SHOULD_CONTINUE(net_conn)) {
+                    code = XFCE_MAILWATCH_ERROR_ABORTED;
+                    reason = _("Operation aborted");
+                } else if(TIMER_EXPIRED(RECV_TIMEOUT))
+                    reason = strerror(ETIMEDOUT);
+                else
+                    reason = gnutls_strerror(ret);
                 if(error) {
-                    g_set_error(error, XFCE_MAILWATCH_ERROR, 0,
-                                _("Failed to send encrypted data (%d): %s"),
-                                ret, gnutls_strerror(ret));
+                    g_set_error(error, XFCE_MAILWATCH_ERROR, code,
+                                _("Failed to send encrypted data: %s"),
+                                reason);
                 }
-                DBG("gnutls_record_send() failed (%d): %s", ret,
-                    gnutls_strerror(ret));
+                DBG("gnutls_record_send() failed (%d): %s", ret, reason);
                 return -1;
-            } else if(ret > 0) {
+            } else {
                 bout += ret;
                 bytesleft -= ret;
             }
@@ -636,24 +695,27 @@
     } else
 #endif
     {
+        TIMER_START;
         do {
             bout = send(net_conn->fd, buf, buf_len, MSG_NOSIGNAL);
-
-            if(bout < 0 && !SHOULD_CONTINUE(net_conn)) {
-                if(error) {
-                    g_set_error(error, XFCE_MAILWATCH_ERROR,
-                                XFCE_MAILWATCH_ERROR_ABORTED, NULL);
-                }
-                return -1;
-            }
-        } while(bout < 0 && (EINTR == errno || EAGAIN == errno));
+        } while(bout < 0 && (EINTR == errno || EAGAIN == errno)
+                && !TIMER_EXPIRED(RECV_TIMEOUT) && SHOULD_CONTINUE(net_conn));
     }
 
-    if(bout < 0) {
-        if(error) {
-            g_set_error(error, XFCE_MAILWATCH_ERROR, 0,
-                        _("Failed to send data: %s"), strerror(errno));
-        }
+    if(bout < 0 && error) {
+        gint code = XFCE_MAILWATCH_ERROR_FAILED;
+        const gchar *reason;
+
+        if(!SHOULD_CONTINUE(net_conn)) {
+            code = XFCE_MAILWATCH_ERROR_ABORTED;
+            reason = _("Operation aborted");
+        } else if(EINTR == errno || EAGAIN == errno)
+            reason = strerror(ETIMEDOUT);
+        else
+            reason = strerror(errno);
+
+        g_set_error(error, XFCE_MAILWATCH_ERROR, code,
+                    _("Failed to send data: %s"), reason);
     }
 
     return bout;
@@ -666,113 +728,111 @@
                                       gboolean block,
                                       GError **error)
 {
-    gint bin = 0;
-    gint tries_left;
-    gboolean data_ready = FALSE;
+    gint ret, bin = 0, code = XFCE_MAILWATCH_ERROR_FAILED;
+    const gchar *reason;
+    TIMER_INIT;
 
-    for(tries_left = 45; tries_left >= 0; --tries_left) {
+    TIMER_START;
+    do {
         fd_set rfd;
-        struct timeval tv;
+        struct timeval tv = { 1, 0 };
 
-        if(!SHOULD_CONTINUE(net_conn)) {
-            if(error) {
-                g_set_error(error, XFCE_MAILWATCH_ERROR,
-                            XFCE_MAILWATCH_ERROR_ABORTED, NULL);
-            }
-            return -1;
-        }
-
         FD_ZERO(&rfd);
         FD_SET(net_conn->fd, &rfd);
-        if(block)
-            tv.tv_sec = 1;
-        else
+        if(!block)
             tv.tv_sec = 0;
-        tv.tv_usec = 0;
 
-        if(select(FD_SETSIZE, &rfd, NULL, NULL, &tv) < 0)
-            continue;
-
-        if(FD_ISSET(net_conn->fd, &rfd)) {
-            data_ready = TRUE;
+        ret = select(FD_SETSIZE, &rfd, NULL, NULL, &tv);
+        if(ret > 0 && FD_ISSET(net_conn->fd, &rfd))
             break;
+        else if(ret < 0 && EINTR != errno) {
+            g_set_error(error, XFCE_MAILWATCH_ERROR,
+                        XFCE_MAILWATCH_ERROR_FAILED, strerror(errno));
+            return -1;
         } else if(!block)
             return 0;
+    } while(ret < 0 && EINTR == errno && !TIMER_EXPIRED(RECV_TIMEOUT)
+            && SHOULD_CONTINUE(net_conn));
+
+    if(!SHOULD_CONTINUE(net_conn)) {
+        if(error) {
+            g_set_error(error, XFCE_MAILWATCH_ERROR,
+                        XFCE_MAILWATCH_ERROR_ABORTED, _("Operation aborted"));
+        }
+        return -1;
+    } else if(TIMER_EXPIRED(RECV_TIMEOUT)) {
+        if(error) {
+            g_set_error(error, XFCE_MAILWATCH_ERROR,
+                        XFCE_MAILWATCH_ERROR_FAILED, strerror(ETIMEDOUT));
+        }
+        return -1;
     }
 
-    if(!data_ready)
-        return 0;
-
 #ifdef HAVE_SSL_SUPPORT
     if(net_conn->is_secure) {
         gint ret;
+        code = XFCE_MAILWATCH_ERROR_FAILED;
 
+        TIMER_START;
         do {
             ret = gnutls_record_recv(net_conn->gt_session, buf, buf_len);
 
             if(GNUTLS_E_REHANDSHAKE == ret) {
-                do {
-                    ret = gnutls_handshake(net_conn->gt_session);
-
-                    if(GNUTLS_E_SUCCESS != ret && !SHOULD_CONTINUE(net_conn)) {
-                        if(error) {
-                            g_set_error(error, XFCE_MAILWATCH_ERROR,
-                                        XFCE_MAILWATCH_ERROR_ABORTED, NULL);
-                        }
-                        return -1;
-                    }
-                } while(GNUTLS_E_AGAIN == ret || GNUTLS_E_INTERRUPTED == ret);
-
-                if(ret != GNUTLS_E_SUCCESS) {
-                    if(error) {
-                        g_set_error(error, XFCE_MAILWATCH_ERROR, 0,
-                                    _("TLS handshake failed (%d): %s"), ret,
-                                    gnutls_strerror(ret));
-                    }
+                if(!xfce_mailwatch_net_conn_tls_handshake(net_conn, error))
                     return -1;
-                }
-
                 ret = GNUTLS_E_AGAIN;
             }
-        } while(GNUTLS_E_INTERRUPTED == ret || GNUTLS_E_AGAIN == ret);
+        } while((GNUTLS_E_INTERRUPTED == ret || GNUTLS_E_AGAIN == ret)
+                && !TIMER_EXPIRED(RECV_TIMEOUT) && SHOULD_CONTINUE(net_conn));
         
         if(ret < 0) {
             if(error) {
-                g_set_error(error, XFCE_MAILWATCH_ERROR, 0,
-                            _("Failed to receive encrypted data (%d): %s"),
-                            ret, gnutls_strerror(ret));
+                if(!SHOULD_CONTINUE(net_conn)) {
+                    code = XFCE_MAILWATCH_ERROR_ABORTED;
+                    reason = _("Operation aborted");
+                } else if(TIMER_EXPIRED(RECV_TIMEOUT))
+                    reason = strerror(ETIMEDOUT);
+                else
+                    reason = gnutls_strerror(ret);
+
+                g_set_error(error, XFCE_MAILWATCH_ERROR, code,
+                            _("Failed to receive encrypted data: %s"),
+                            reason);
             }
-            return -1;
+
+            bin = -1;
         } else
             bin = ret;
     } else
 #endif
     {
         gint ret;
+        code = XFCE_MAILWATCH_ERROR_FAILED;
 
+        TIMER_START;
         do {
             ret = recv(net_conn->fd, buf, buf_len, MSG_NOSIGNAL);
+        } while(ret < 0 && (EINTR == errno || EAGAIN == errno)
+                && !TIMER_EXPIRED(RECV_TIMEOUT) && SHOULD_CONTINUE(net_conn));
 
-            if(ret < 0 && !SHOULD_CONTINUE(net_conn)) {
-                if(error) {
-                    g_set_error(error, XFCE_MAILWATCH_ERROR,
-                                XFCE_MAILWATCH_ERROR_ABORTED, NULL);
-                }
-                return -1;
+        if(ret < 0) {
+            if(error) {
+                if(!SHOULD_CONTINUE(net_conn)) {
+                    code = XFCE_MAILWATCH_ERROR_ABORTED;
+                    reason = _("Operation aborted");
+                } else if(TIMER_EXPIRED(RECV_TIMEOUT))
+                    reason = strerror(ETIMEDOUT);
+                else
+                    reason = strerror(errno);
+
+                g_set_error(error, XFCE_MAILWATCH_ERROR, code,
+                            _("Failed to receive data: %s"), reason);
             }
-        } while(ret < 0 && (EINTR == errno || EAGAIN == errno));
-
-        if(ret > 0)
+            bin = -1;
+        } else
             bin = ret;
     }
 
-    if(bin < 0) {
-        if(error) {
-            g_set_error(error, XFCE_MAILWATCH_ERROR, 0,
-                        _("Failed to receive data: %s"), strerror(errno));
-        }
-    }
-
     return bin;
 }
 




More information about the Goodies-commits mailing list