Subject: [libssh2] #282: SCP may read the wrong file if several channels are opened in parallel

[libssh2] #282: SCP may read the wrong file if several channels are opened in parallel

From: libssh2 Trac <trac_at_libssh2.stuge.se>
Date: Wed, 08 Jan 2014 10:37:02 -0000

#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-devel
Received on 2014-01-08