#250: libssh2_channel_send_eof() sometimes fails when used in non-blocking mode -------------------------------------------+-------------------- Reporter: jfriesne | Owner: Type: defect | Status: new Priority: normal | Milestone: 1.4.3 Component: API | Version: 1.4.2 Keywords: non-blocking channel_send_eof | Blocked By: Blocks: | -------------------------------------------+-------------------- Hi there libssh2 developers,
I think I've found a bug in the libssh2_channel_send_eof() function, when it is used in conjunction with libssh's non-blocking mode. The symptom for me is this: I have a program that uses libssh2 1.4.2 to upload multiple files at once. Each upload is handled by a different thread with its own (non-shared) libssh2 session object. Under Windows 7, about 80% of the time one or more of the uploads (at random) would fail with libssh2_channel_send_eof() returning error -7 (aka LIBSSH2_ERROR_SOCKET_SEND). I did some investigation and found found that the call to _libssh2_transport_write() inside channel_send_eof() was failing, with error code -39 (aka LIBSSH2_ERROR_BAD_USE), which AFAIK should never occur. A little more investigation revealed what is happening: sometimes channel_send_eof()'s first call to _libssh2_transport_write() would result in LIBSSH2_ERROR_EAGAIN, because the socket's output buffer has no more space. This is fine, but the problem is that the pointer passed in to _libssh2_transport_write() gets recorded into libssh2's transportpacket data structure, and then the next time _libssh2_transport_write() is called, it calls send_existing() and send_existing() checks to make sure that the pointer passed in on the second attempt is the same as the pointer that was passed in on the first attempt. That would all be fine, except that the 5-byte char array being sent by channel_send_eof() is located on the stack: static int channel_send_eof(LIBSSH2_CHANNEL *channel) { LIBSSH2_SESSION *session = channel->session; unsigned char packet[5]; /* packet_type(1) + channelno(4) */ int rc; [...] rc = _libssh2_transport_write(session, packet, 5); [...] .... which means that the memory location pointed to by (packet) may be different each time channel_send_eof() is called, even if the data pointed to by (packet) is the same. This is what triggers the LIBSSH2_ERROR_BAD_USE error inside send_existing(), which in turn causes libssh2_channel_send_eof() to fail. In my local copy of libssh2 I was able to resolve the problem by moving unsigned char packet[5]; /* packet_type(1) + channelno(4) */ from the stack of the channel_send_eof() function into the LIBSSH2_CHANNEL object instead (i.e. as a member variable). That way the memory location of (packet) will always be the same for a given channel object, and thus the false-positive error detection is avoided. I hope that all made sense -- if not, feel free to email me (j...@meyersound.com). -Jeremy -- Ticket URL: <https://trac.libssh2.org/ticket/250> libssh2 <https://trac.libssh2.org/> C library for writing portable SSH2 clients _______________________________________________ libssh2-devel http://cool.haxx.se/cgi-bin/mailman/listinfo/libssh2-devel