Deal with EAGAIN and GnuTLS channels
authorMarcel Holtmann <marcel@holtmann.org>
Sun, 7 Nov 2010 11:33:23 +0000 (12:33 +0100)
committerMarcel Holtmann <marcel@holtmann.org>
Sun, 7 Nov 2010 11:33:23 +0000 (12:33 +0100)
gweb/giognutls.c

index e6c1bde..06eff4a 100644 (file)
@@ -44,6 +44,7 @@ struct _GIOGnuTLSChannel {
        gnutls_certificate_credentials_t cred;
        gnutls_session session;
        gboolean established;
+       gboolean again;
 };
 
 struct _GIOGnuTLSWatch {
@@ -68,15 +69,18 @@ static GIOStatus check_handshake(GIOChannel *channel, GError **err)
 
        DBG("channel %p", channel);
 
-again:
        if (gnutls_channel->established == TRUE)
                return G_IO_STATUS_NORMAL;
 
+again:
        result = gnutls_handshake(gnutls_channel->session);
 
        if (result == GNUTLS_E_INTERRUPTED || result == GNUTLS_E_AGAIN) {
                GIOFlags flags = g_io_channel_get_flags(channel);
 
+               if (gnutls_channel->again == TRUE)
+                       return G_IO_STATUS_AGAIN;
+
                if (flags & G_IO_FLAG_NONBLOCK)
                        return G_IO_STATUS_AGAIN;
 
@@ -124,6 +128,9 @@ again:
        if (result == GNUTLS_E_INTERRUPTED || result == GNUTLS_E_AGAIN) {
                GIOFlags flags = g_io_channel_get_flags(channel);
 
+               if (gnutls_channel->again == TRUE)
+                       return G_IO_STATUS_AGAIN;
+
                if (flags & G_IO_FLAG_NONBLOCK)
                        return G_IO_STATUS_AGAIN;
 
@@ -172,6 +179,9 @@ again:
        if (result == GNUTLS_E_INTERRUPTED || result == GNUTLS_E_AGAIN) {
                GIOFlags flags = g_io_channel_get_flags(channel);
 
+               if (gnutls_channel->again == TRUE)
+                       return G_IO_STATUS_AGAIN;
+
                if (flags & G_IO_FLAG_NONBLOCK)
                        return G_IO_STATUS_AGAIN;
 
@@ -352,6 +362,11 @@ static ssize_t g_io_gnutls_push_func(gnutls_transport_ptr_t transport_data,
 
        result = write(fd, buf, count);
 
+       if (result < 0 && errno == EAGAIN)
+               gnutls_channel->again = TRUE;
+       else
+               gnutls_channel->again = FALSE;
+
        DBG("result %zd", result);
 
        return result;
@@ -370,6 +385,11 @@ static ssize_t g_io_gnutls_pull_func(gnutls_transport_ptr_t transport_data,
 
        result = read(fd, buf, count);
 
+       if (result < 0 && errno == EAGAIN)
+               gnutls_channel->again = TRUE;
+       else
+               gnutls_channel->again = FALSE;
+
        DBG("result %zd", result);
 
        return result;