Hi guys, I'm working on a strem library which implements various kind of streams. All SSH based streams are implemented using your great libssh2 library ;) Now I'm trying to implement the SFTP protocol, but I've some problem when uploading large files. This example partially reproduces the problem:
/* * test.c * * Test some sort of buffering mode built upon libssh2 SFtp implementation * */ #include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <fcntl.h> #include <libssh2.h> #include <libssh2_sftp.h> #define DEFAULT_BUFFLEN (1024) int main( int argc, char *argv[] ) { struct sockaddr_in sin; in_addr_t host_addr; LIBSSH2_SESSION *session; LIBSSH2_SFTP *sftp_session; LIBSSH2_SFTP_HANDLE *sftp_handle; int fd, err_no, err_len; int sock, ret_val=0, rd_bytes=0, wr_bytes=0; void *buff, *tmp; int buff_pos=0, buff_size=DEFAULT_BUFFLEN, buff_read_step=DEFAULT_BUFFLEN, \ buff_eof_pos=0; if ( argc != 5 ) { fprintf( stderr, "Usage: %s USER PASSWORD SERVER FILEPATH\n", argv[0] ); return 2; } /* Open file */ fd = open( argv[4], O_RDONLY ); if ( fd == -1 ) { fprintf( stderr, "Unable to open file [%s]\n", argv[4] ); return 1; } /* Init and connect socket */ if ( host_addr = inet_addr( argv[3] ) == INADDR_NONE ) { fprintf( stderr, "Invalid server address specified [%s]\n", argv[3] ); return 1; } sin.sin_family = AF_INET; sin.sin_port = htons(22); sin.sin_addr.s_addr = host_addr; sock = socket( AF_INET, SOCK_STREAM, 0 ); if ( connect( sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in) ) ) { fprintf( stderr, "Unable to connect to [%s:22]\n", argv[3] ); return 1; } /* Create the session instance */ session = libssh2_session_init(); if ( !session ) { fprintf( stderr, "Error initializing SSH session\n" ); return 1; } //libssh2_session_set_blocking(session, 1); if ( libssh2_session_startup( session, sock ) ) { fprintf( stderr, "Error starting SSH session\n" ); return 1; } /* Authenticate via password */ if ( libssh2_userauth_password( session, argv[1], argv[2] ) ) { fprintf( stderr, "Unable to authenticate user [%s]" "(wrong password specified?)\n", argv[1] ); ret_val = 1; goto clear_ssh; } /* Open an SFTP channel */ sftp_session = libssh2_sftp_init( session ); if ( !sftp_session ) { fprintf( stderr, "Unable to open an SFTP channel\n" ); ret_val = 1; goto clear_ssh; } sftp_handle = libssh2_sftp_open( sftp_session, "Test.out", LIBSSH2_FXF_WRITE | LIBSSH2_FXF_CREAT | LIBSSH2_FXF_TRUNC, LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR| LIBSSH2_SFTP_S_IRGRP| LIBSSH2_SFTP_S_IROTH ); if ( !sftp_handle ) { fprintf( stderr, "Unable to open remote file Test.out\n" ); ret_val = 1; goto clear_sftp; } /* Init buffer */ buff = malloc( DEFAULT_BUFFLEN ); /* Fill the buffer: * buff_read_step bytes at time are read from buffer. If buffer capacity limit * is reached, a new buffer with double size is allocated and used */ while ( ( rd_bytes = read( fd, buff+buff_pos, buff_read_step ) ) > 0 ) { if ( rd_bytes == -1 ) { fprintf( stderr, "Error reading local file\n" ); ret_val = 1; libssh2_sftp_close( sftp_handle ); goto clear_sftp; } /* Resize the buffer if needed */ if ( (buff_pos + rd_bytes) >= buff_size ) { fprintf( stdout, "Resize buffer from size [%d] to size [%d]\n", buff_size, buff_size*2 ); tmp = malloc( buff_size ); memcpy( tmp, buff, buff_size ); free( buff ); buff = malloc( buff_size * 2 ); memcpy( buff, tmp, buff_size ); buff_size *= 2; free( tmp ); } buff_pos += rd_bytes; } close( fd ); /* Flush the buffer to remote opened file */ buff_eof_pos = buff_pos; buff_pos = 0; while ( buff_pos < buff_eof_pos ) { /* Try always to write as much bytes as possible */ wr_bytes = libssh2_sftp_write( sftp_handle, buff+buff_pos, buff_eof_pos-buff_pos ); if ( wr_bytes == -1 ) { err_no = libssh2_session_last_error(session, (char**)(&tmp), &err_len, 1); fprintf( stderr, "Error flushing buffer: error [%d], [%s]\n", err_no, tmp ); ret_val = 1; libssh2_sftp_close( sftp_handle ); goto clear_sftp; } fprintf( stdout, "[%d] bytes flushed\n", wr_bytes ); buff_pos += wr_bytes; } libssh2_sftp_close( sftp_handle ); clear_sftp: libssh2_sftp_shutdown( sftp_session ); free( buff ); clear_ssh: libssh2_session_disconnect( session, "Bye bye" ); libssh2_session_free( session ); close( sock ); return ret_val; } What the program does is fill (and, if needed, resize) a buffer with the content of a local file. Then, the buffer is flushed in the remote file "Test.out" in the specified SSH server. With small size files the program works without problems, but with large files the libssh2_sftp_write function always returns -1. The output of the execution is something like this: [dani...@foo libssh2_sftp_test]$ ./test daniele my_pass 192.168.0.66 /home/daniele/a_larg_file.large Start filling buffer Resize buffer from size [1024] to size [2048] Resize buffer from size [2048] to size [4096] Resize buffer from size [4096] to size [8192] Resize buffer from size [8192] to size [16384] Resize buffer from size [16384] to size [32768] Resize buffer from size [32768] to size [65536] Resize buffer from size [65536] to size [131072] Resize buffer from size [131072] to size [262144] Resize buffer from size [262144] to size [524288] Resize buffer from size [524288] to size [1048576] Resize buffer from size [1048576] to size [2097152] Start flushing buffer: [1519424] bytes to flush Error flushing buffer: error [-30], [Timeout waiting for status message] [dani...@foo libssh2_sftp_test]$ In my stream library the implementation of the buffering write strategy is similar to the one used in the above example, but the error returned is libssh2 error code: [-7] description: [Unable to send FXP_READ command] Is there some know problem with large write buffer and sftp protocol implementation? Thanks for any advice, Daniele ------------------------------------------------------------------------------ The NEW KODAK i700 Series Scanners deliver under ANY circumstances! Your production scanning environment may not be a perfect world - but thanks to Kodak, there's a perfect scanner to get the job done! With the NEW KODAK i700 Series Scanner you'll get full speed at 300 dpi even with all image processing features enabled. http://p.sf.net/sfu/kodak-com _______________________________________________ libssh2-devel mailing list libssh2-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/libssh2-devel