cURL / Mailing Lists / curl-library / Single Mail

curl-library

Re: code hangs with sftp downloads, solved

From: E L <crc1021_at_gmail.com>
Date: Fri, 12 Sep 2008 10:18:27 -0500

On Fri, Sep 12, 2008 at 7:59 AM, E L <crc1021_at_gmail.com> wrote:
> I am using libcurl (7.19.0) with libssh2 (0.19.0-20080825) to do
> downloads on windows XP, the downloading takes place in a separate
> thread than the gui code. I'm testing on two computers, one computer
> will get hung on a download and just busy-wait.
...
> When I run it in gdb, I can see that the lowest level calls always
> return PACKET_EAGAIN,

The libssh2 code is not getting the real socket errors in most cases.
After calling send() or recv(), it is assuming errno will be set, but
Windows does not set errno for socket functions. If the connection
gets reset, the call to send() or recv() will fail, but there is a
good chance errno will still be set to EAGAIN, so the code will keep
trying indefinititely.

patch is included below to set errno for all send() and recv()

diff -ur libssh2-0.19.0-20080912/src/libssh2_priv.h libssh2/src/libssh2_priv.h
--- libssh2-0.19.0-20080912/src/libssh2_priv.h Thu Jul 3 21:02:06 2008
+++ libssh2/src/libssh2_priv.h Fri Sep 12 08:32:26 2008
@@ -1066,6 +1066,12 @@
                                    waiting for more data to arrive */
 int libssh2_waitsocket(LIBSSH2_SESSION * session, long seconds);

+/* windows sockets functions do not set errno, convert a few errors
to posix style errno */
+#ifdef WIN32
+void libssh2_set_socket_errno();
+#else
+#define libssh2_set_socket_errno() /* */
+#endif

 /* CAUTION: some of these error codes are returned in the public API and is
    there known with other #defined names from the public header file. They
diff -ur libssh2-0.19.0-20080912/src/misc.c libssh2/src/misc.c
--- libssh2-0.19.0-20080912/src/misc.c Fri Mar 7 21:02:44 2008
+++ libssh2/src/misc.c Fri Sep 12 09:58:48 2008
@@ -36,9 +36,47 @@
  */

 #include "libssh2_priv.h"
+#include <errno.h>
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
+
+/* {{{ libssh2_set_errno
+ * windows sockets functions do not set errno, convert a few errors
to posix style errno
+ * this should only be called after a socket error
+ */
+#ifdef WIN32
+void
+libssh2_set_socket_errno()
+{
+ /* assign value to a variable so it can be shown in debugger easily */
+ switch (WSAGetLastError()) {
+ case WSAEWOULDBLOCK:
+ errno = EAGAIN;
+ break;
+
+ case WSAENOTSOCK:
+ errno = EBADF;
+ break;
+
+ case WSAENOTCONN:
+ case WSAECONNABORTED:
+ errno = WSAENOTCONN;
+ break;
+
+ case WSAEINTR:
+ errno = EINTR;
+ break;
+
+ default:
+ /* FIXME could add more error codes, but for libssh2 */
+ /* it is most important to ensure errno does not stay at
EAGAIN when a different error occurs */
+ errno = EIO;
+ }
+}
+#endif
+
+/* }}} */

 /* {{{ libssh2_ntohu32
  */
diff -ur libssh2-0.19.0-20080912/src/session.c libssh2/src/session.c
--- libssh2-0.19.0-20080912/src/session.c Wed Jan 2 21:02:06 2008
+++ libssh2/src/session.c Fri Sep 12 08:29:25 2008
@@ -112,26 +112,7 @@
                  LIBSSH2_SOCKET_RECV_FLAGS(session));

         if (ret < 0) {
-#ifdef WIN32
- switch (WSAGetLastError()) {
- case WSAEWOULDBLOCK:
- errno = EAGAIN;
- break;
-
- case WSAENOTSOCK:
- errno = EBADF;
- break;
-
- case WSAENOTCONN:
- case WSAECONNABORTED:
- errno = WSAENOTCONN;
- break;
-
- case WSAEINTR:
- errno = EINTR;
- break;
- }
-#endif /* WIN32 */
+ libssh2_set_socket_errno();
             if (errno == EAGAIN) {
                 session->banner_TxRx_total_send = banner_len;
                 return PACKET_EAGAIN;
@@ -233,6 +214,8 @@
              LIBSSH2_SOCKET_SEND_FLAGS(session));

     if (ret != (banner_len - session->banner_TxRx_total_send)) {
+ if (ret < 0)
+ libssh2_set_socket_errno();
         if ((ret > 0) || ((ret == -1) && (errno == EAGAIN))) {
             /* the whole packet could not be sent, save the what was */
             session->banner_TxRx_total_send += ret;
diff -ur libssh2-0.19.0-20080912/src/transport.c libssh2/src/transport.c
--- libssh2-0.19.0-20080912/src/transport.c Thu Jul 3 21:02:06 2008
+++ libssh2/src/transport.c Fri Sep 12 08:32:00 2008
@@ -364,26 +364,7 @@
             if (nread <= 0) {
                 /* check if this is due to EAGAIN and return the special
                    return code if so, error out normally otherwise */
-#ifdef WIN32
- switch (WSAGetLastError()) {
- case WSAEWOULDBLOCK:
- errno = EAGAIN;
- break;
-
- case WSAENOTSOCK:
- errno = EBADF;
- break;
-
- case WSAENOTCONN:
- case WSAECONNABORTED:
- errno = WSAENOTCONN;
- break;
-
- case WSAEINTR:
- errno = EINTR;
- break;
- }
-#endif /* WIN32 */
+ libssh2_set_socket_errno();
                 if ((nread < 0) && (errno == EAGAIN)) {
                     return PACKET_EAGAIN;
                 }
@@ -629,6 +610,7 @@
         p->outbuf = NULL;
         p->ototal_num = 0;
     } else if (rc < 0) {
+ libssh2_set_socket_errno();
         /* nothing was sent */
         if (errno != EAGAIN) {
             /* send failure! */
@@ -784,6 +766,8 @@
         debugdump(session, "libssh2_packet_write send()", p->outbuf, ret);
     }
     if (ret != total_length) {
+ if (ret < 0)
+ libssh2_set_socket_errno();
         if ((ret > 0) || ((ret == -1) && (errno == EAGAIN))) {
             /* the whole packet could not be sent, save the rest */
             p->odata = orgdata;
Received on 2008-09-12