#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