#282: SCP may read the wrong file if several channels are opened in parallel
-----------------------+--------------------
Reporter: petersohn | Owner:
Type: defect | Status: new
Priority: normal | Milestone: 1.4.3
Component: SCP | Version: 1.4.2
Keywords: | Blocked By:
Blocks: |
-----------------------+--------------------
Attached is a modification of the {{{scp_nonblock.c}}} example that can
reproduce this problem. The modifications are the following:
* Removed Windows specific code for simplicity (tested on SUSE Linux 11).
* Multiple files can be specified on the command line (arguments after
password).
* Multiple files are read in parallel.
* Each file is written to a file of the same name on the local machine.
The problem may not always come up. I tested with 10 files of a size about
2 MB. The problem seems to occur when establishing the channels are
finished in a different order as they are started.
The example works as the following.
* The information for each channel is stored in the {{{descriptor}}}
structure:
{{{
struct descriptor {
char* filename;
struct stat fileinfo;
LIBSSH2_CHANNEL *channel;
int outfd;
off_t got;
};
}}}
* Open the session and authenticate (no change of the algorithm until this
point).
* Enter a main loop with the exit condition specified later (when all
files are read).
{{{
while(1) {
int activeChannels = 0;
}}}
* Now enter an inner loop that iterates through all descriptors. Inside
this loop we do everything we can without waiting for the socket.
{{{
for (i = 0; i < descriptorNum; ++i) {
struct descriptor* desc = &descriptors[i];
int rc;
}}}
* If the channel is not yet established, then try to create it.
{{{
if (!desc->channel) {
desc->channel = libssh2_scp_recv(session, desc->filename,
&desc->fileinfo);
...
++activeChannels;
}}}
* If the channel is already established, then read from it.
{{{
} else {
char mem[1024*24];
fprintf(stderr, "Reading from %s...\n", desc->filename);
do {
...
rc = libssh2_channel_read(desc->channel, mem, amount);
...
} while (rc > 0);
...
if (desc->got < desc->fileinfo.st_size) {
++activeChannels;
}
}
}}}
* After the inner loop, check whether we need to continue. If not, finish
the main loop.
{{{
if (activeChannels > 0) {
waitsocket(sock, session); /* now we wait */
continue;
}
}
}}}
-- Ticket URL: <https://trac.libssh2.org/ticket/282> libssh2 <https://trac.libssh2.org/> C library for writing portable SSH2 clients _______________________________________________ libssh2-devel http://cool.haxx.se/cgi-bin/mailman/listinfo/libssh2-develReceived on 2014-01-08