fix ssl deadlock, when peer closes connection
[claws.git] / src / socket.c
index dc08c1bf2f12ceda77c29d1b64f7ee36c35de268..e0b5f20131ecf96930504bb5feb7cfb786d730a7 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999,2000 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2001 Hiroyuki Yamamoto
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -41,6 +41,9 @@
 #endif
 
 #include "socket.h"
+#if USE_SSL
+#  include "ssl.h"
+#endif
 
 #if USE_GIO
 #error USE_GIO is currently not supported
@@ -258,46 +261,6 @@ static gint sock_connect_by_getaddrinfo(const gchar *hostname, gushort     port)
 }
 #endif /* !INET6 */
 
-SockInfo *sock_connect_nb(const gchar *hostname, gushort port)
-{
-       gint sock;
-       gint ret;
-       SockInfo *sockinfo;
-
-#ifdef INET6
-       if ((sock = sock_connect_by_getaddrinfo(hostname, port)) < 0)
-               return NULL;
-       if (set_nonblocking_mode(sock, TRUE) < 0) return NULL;
-       ret = sock;
-#else
-       if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
-               perror("socket");
-               return NULL;
-       }
-
-       if (set_nonblocking_mode(sock, TRUE) < 0) return NULL;
-
-       ret = sock_connect_by_hostname(sock, hostname, port);
-
-       if (ret < 0 && errno != EINPROGRESS) {
-               if (errno != 0) perror("connect");
-               close(sock);
-               return NULL;
-       }
-#endif /* INET6 */
-
-       sockinfo = g_new0(SockInfo, 1);
-       sockinfo->sock = sock;
-       sockinfo->hostname = g_strdup(hostname);
-       sockinfo->port = port;
-       sockinfo->state = CONN_LOOKUPSUCCESS;
-
-       if (ret < 0 && errno == EINPROGRESS) return sockinfo;
-
-       sockinfo->state = CONN_ESTABLISHED;
-       return sockinfo;
-}
-
 SockInfo *sock_connect(const gchar *hostname, gushort port)
 {
        gint sock;
@@ -395,6 +358,10 @@ gint sock_read(SockInfo *sock, gchar *buf, gint len)
 {
        g_return_val_if_fail(sock != NULL, -1);
 
+#if USE_SSL
+       if (sock->ssl)
+               return ssl_read(sock->ssl, buf, len);
+#endif
        return fd_read(sock->sock, buf, len);
 }
 
@@ -403,10 +370,21 @@ gint fd_read(gint fd, gchar *buf, gint len)
        return read(fd, buf, len);
 }
 
+#if USE_SSL
+gint ssl_read(SSL *ssl, gchar *buf, gint len)
+{
+       return SSL_read(ssl, buf, len);
+}
+#endif
+
 gint sock_write(SockInfo *sock, const gchar *buf, gint len)
 {
        g_return_val_if_fail(sock != NULL, -1);
 
+#if USE_SSL
+       if (sock->ssl)
+               return ssl_write(sock->ssl, buf, len);
+#endif
        return fd_write(sock->sock, buf, len);
 }
 
@@ -426,6 +404,24 @@ gint fd_write(gint fd, const gchar *buf, gint len)
        return wrlen;
 }
 
+#if USE_SSL
+gint ssl_write(SSL *ssl, const gchar *buf, gint len)
+{
+       gint n, wrlen = 0;
+
+       while (len) {
+               n = SSL_write(ssl, buf, len);
+               if (n <= 0)
+                       return -1;
+               len -= n;
+               wrlen += n;
+               buf += n;
+       }
+
+       return wrlen;
+}
+#endif
+
 gint fd_gets(gint fd, gchar *buf, gint len)
 {
        gchar *newline, *bp = buf;
@@ -448,13 +444,96 @@ gint fd_gets(gint fd, gchar *buf, gint len)
        return bp - buf;
 }
 
+#if USE_SSL
+gint ssl_gets(SSL *ssl, gchar *buf, gint len)
+{
+       gchar *bp = buf;
+       gboolean newline = FALSE;
+       gint n;
+
+       if (--len < 1)
+               return -1;
+       while (len > 0 && !newline) {
+               *bp = '\0';
+               if ((n = SSL_read(ssl, bp, 1)) <= 0)
+                       return -1;
+               if (*bp == '\n')
+                       newline = TRUE;
+               bp += n;
+       }
+
+       *bp = '\0';
+       return bp - buf;
+}
+#endif
+
 gint sock_gets(SockInfo *sock, gchar *buf, gint len)
 {
        g_return_val_if_fail(sock != NULL, -1);
 
+#if USE_SSL
+       if (sock->ssl)
+               return ssl_gets(sock->ssl, buf, len);
+#endif
        return fd_gets(sock->sock, buf, len);
 }
-               
+
+gchar *fd_getline(gint fd)
+{
+       gchar buf[BUFFSIZE];
+       gchar *str = NULL;
+       gint len;
+       gulong size = 1;
+
+       while ((len = fd_gets(fd, buf, sizeof(buf))) > 0) {
+               size += len;
+               if (!str)
+                       str = g_strdup(buf);
+               else {
+                       str = g_realloc(str, size);
+                       strcat(str, buf);
+               }
+               if (buf[len - 1] == '\n')
+                       break;
+       }
+
+       return str;
+}
+
+#if USE_SSL
+gchar *ssl_getline(SSL *ssl)
+{
+       gchar buf[BUFFSIZE];
+       gchar *str = NULL;
+       gint len;
+       gulong size = 1;
+
+       while ((len = ssl_gets(ssl, buf, sizeof(buf))) > 0) {
+               size += len;
+               if (!str)
+                       str = g_strdup(buf);
+               else {
+                       str = g_realloc(str, size);
+                       strcat(str, buf);
+               }
+               if (buf[len - 1] == '\n')
+                       break;
+       }
+
+       return str;
+}
+#endif
+
+gchar *sock_getline(SockInfo *sock)
+{
+       g_return_val_if_fail(sock != NULL, NULL);
+
+#if USE_SSL
+       if (sock->ssl)
+               return ssl_getline(sock->ssl);
+#endif
+       return fd_getline(sock->sock);
+}
 
 gint sock_puts(SockInfo *sock, const gchar *buf)
 {
@@ -481,15 +560,20 @@ gint sock_peek(SockInfo *sock)
 
 gint sock_close(SockInfo *sock)
 {
-       gint rc;
+       gint ret;
 
        if (!sock)
                return 0;
 
-       rc = fd_close(sock->sock); 
+#if USE_SSL
+       if (sock->ssl)
+               ssl_done_socket(sock);
+#endif
+       ret = fd_close(sock->sock); 
        g_free(sock->hostname);
        g_free(sock);
-       return rc;
+
+       return ret;
 }
 
 gint fd_close(gint fd)
@@ -498,9 +582,9 @@ gint fd_close(gint fd)
 }
 
 gint sock_gdk_input_add(SockInfo *sock,
-                        GdkInputCondition condition,
-                        GdkInputFunction function,
-                        gpointer data)
+                       GdkInputCondition condition,
+                       GdkInputFunction function,
+                       gpointer data)
 {
        g_return_val_if_fail(sock != NULL, -1);