#240: Unhandled Z_BUF_ERROR inflating compressed stream
----------------------+--------------------
Reporter: steven | Owner:
Type: defect | Status: new
Priority: normal | Milestone: 1.5.0
Component: protocol | Version: 1.4.1
Keywords: | Blocked By:
Blocks: |
----------------------+--------------------
When using libssh2 to perform an SFTP file transfer from the "JSCAPE MFT
Server" (http://www.jscape.com) the transfer failed. The default JSCAPE
configuration is to enforce zlib compression on SSH2 sessions so the
session was compressed. The relevant part of the debug trace contained:
{{{
[libssh2] 1.052750 Transport: unhandled zlib error -5
[libssh2] 1.052750 Failure Event: -29 - decompression failure
}}}
The trace comes from comp_method_zlib_decomp() in comp.c. The "unhandled
zlib error -5" is the status returned from the zlib function inflate().
The -5 status corresponds to "Z_BUF_ERROR".
The inflate() function takes a pointer to a z_stream structure and
"inflates" (decompresses) as much as it can. The relevant fields of the
z_stream structure are:
* next_in - pointer to the input buffer containing compressed data
* avail_in - the number of bytes available at next_in
* next_out - pointer to the output buffer to be filled with uncompressed
data
* avail_out - how much space available at next_out
So, to decompress data you set up a z_stream struct with the relevant
fields filled in and pass it to inflate(). On return the fields will have
been updated so next_in and avail_in show how much compressed data is yet
to be processed and next_out and avail_out show how much space is left in
the output buffer.
If the supplied output buffer is too small then on return there will be
compressed data yet to be processed (avail_in != 0) and inflate() will
return Z_OK. In this case the output buffer must be grown, avail_out
updated and inflate() called again.
If the supplied output buffer was big enough then on return the compressed
data will have been exhausted (avail_in == 0) and inflate() will return
Z_OK, so the data has all been uncompressed.
There is a corner case where inflate() makes no progress. That is, there
may be unprocessed compressed data and space available in the output
buffer and yet the function does nothing. In this case inflate() will
return Z_BUF_ERROR. From the zlib documentation and the source code it is
not clear under what circumstances this happens. It could be that it needs
to write multiple bytes (all in one go) from its internal state to the
output buffer before processing the next chunk of input but but can't
because there is not enough space (though my guesses as to the cause are
not really relevant). Recovery from Z_BUF_ERROR is pretty simple - just
grow the output buffer, update avail_out and call inflate() again.
The comp_method_zlib_decomp() function does not handle the case when
inflate() returns Z_BUF_ERROR. It treats it as a non-recoverable error and
basically aborts the session.
I've attached a patch to comp.c to the ticket that contains a proposed
solution.
-- Ticket URL: <http://trac.libssh2.org/ticket/240> libssh2 <http://trac.libssh2.org/> C library for writing portable SSH2 clients _______________________________________________ libssh2-devel http://cool.haxx.se/cgi-bin/mailman/listinfo/libssh2-develReceived on 2012-06-13