The latest code still blocks when doing sftp_write on Windows. It
happens if it tries to transfer more than about 96MB. I've attached
the script and the trace output is here:
http://dl.dropbox.com/u/6028779/trace3.out
I've not got time to dig into it right now. Better to get it out
there than keep it to myself though.
The CTRL+C at the end is where I terminate it after it blocks. The
block seems to happen the first time it reads 3 rather than 4 and
wants to unlink the packet (whatever that implies).
Alex
--
Swish - Easy SFTP for Windows Explorer (http://www.swish-sftp.org)
/*
* The sample code has default values for host name, user name, password
* and path to copy, but you can specify them on the command line like:
*
* "sftp 192.168.0.1 user password /tmp/secrets -p|-i|-k"
*/
//#define TEST_READ_SIZE 6543210
#define TEST_READ_SIZE 654
#include <libssh2_config.h>
#include <libssh2.h>
#include <libssh2_sftp.h>
#ifdef HAVE_WINSOCK2_H
# include <winsock2.h>
#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif
# ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h>
#endif
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
const char *username="username";
const char *password="password";
const char *sftppath="/tmp/TEST";
const char *localpath="";
static void kbd_callback(const char *name, int name_len,
const char *instruction, int instruction_len, int num_prompts,
const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts,
LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses,
void **abstract)
{
(void)name;
(void)name_len;
(void)instruction;
(void)instruction_len;
if (num_prompts == 1) {
responses[0].text = strdup(password);
responses[0].length = strlen(password);
}
(void)prompts;
(void)abstract;
} /* kbd_callback */
int main(int argc, char *argv[])
{
unsigned long hostaddr;
int sock, i, auth_pw = 0;
struct sockaddr_in sin;
const char *fingerprint;
char *userauthlist;
LIBSSH2_SESSION *session;
int rc;
LIBSSH2_SFTP *sftp_session;
LIBSSH2_SFTP_HANDLE *sftp_handle;
char *mem;
char *ptr;
FILE *fp;
#ifdef WIN32
WSADATA wsadata;
WSAStartup(MAKEWORD(2,0), &wsadata);
#endif
if (argc > 1) {
hostaddr = inet_addr(argv[1]);
} else {
hostaddr = htonl(0x7F000001);
}
if(argc > 2) {
username = argv[2];
}
if(argc > 3) {
password = argv[3];
}
if(argc > 4) {
sftppath = argv[4];
}
if(argc > 5) {
localpath = argv[5];
}
/*
* The application code is responsible for creating the socket
* and establishing the connection
*/
sock = socket(AF_INET, SOCK_STREAM, 0);
sin.sin_family = AF_INET;
sin.sin_port = htons(22);
sin.sin_addr.s_addr = hostaddr;
if (connect(sock, (struct sockaddr*)(&sin),
sizeof(struct sockaddr_in)) != 0) {
fprintf(stderr, "failed to connect!\n");
return -1;
}
/* Create a session instance
*/
session = libssh2_session_init();
if(!session)
return -1;
/* Since we have set non-blocking, tell libssh2 we are blocking */
libssh2_session_set_blocking(session, 1);
/* ... start it up. This will trade welcome banners, exchange keys,
* and setup crypto, compression, and MAC layers
*/
rc = libssh2_session_startup(session, sock);
if(rc) {
fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
return -1;
}
/* At this point we havn't yet authenticated. The first thing to do
* is check the hostkey's fingerprint against our known hosts Your app
* may have it hard coded, may go to a file, may present it to the
* user, that's your call
*/
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5);
fprintf(stderr, "Fingerprint: ");
for(i = 0; i < 16; i++) {
fprintf(stderr, "%02X ", (unsigned char)fingerprint[i]);
}
fprintf(stderr, "\n");
/* check what authentication methods are available */
userauthlist = libssh2_userauth_list(session, username, strlen(username));
printf("Authentication methods: %s\n", userauthlist);
if (strstr(userauthlist, "password") != NULL) {
auth_pw |= 1;
}
if (strstr(userauthlist, "keyboard-interactive") != NULL) {
auth_pw |= 2;
}
/* if we got an 4. argument we set this option if supported */
if(argc > 6) {
if ((auth_pw & 1) && !strcasecmp(argv[6], "-p")) {
auth_pw = 1;
}
if ((auth_pw & 2) && !strcasecmp(argv[6], "-i")) {
auth_pw = 2;
}
}
if (auth_pw & 1) {
/* We could authenticate via password */
fprintf(stderr, "Password: %s\n", password);
if (libssh2_userauth_password(session, username, password)) {
fprintf(stderr, "Authentication by password failed.\n");
goto shutdown;
}
} else if (auth_pw & 2) {
/* Or via keyboard-interactive */
if (libssh2_userauth_keyboard_interactive(session, username, &kbd_callback) ) {
printf("\tAuthentication by keyboard-interactive failed!\n");
goto shutdown;
} else {
printf("\tAuthentication by keyboard-interactive succeeded.\n");
}
} else {
printf("No supported authentication methods found!\n");
goto shutdown;
}
fprintf(stderr, "libssh2_sftp_init()!\n");
sftp_session = libssh2_sftp_init(session);
if (!sftp_session) {
fprintf(stderr, "Unable to init SFTP session\n");
goto shutdown;
}
libssh2_trace(session, (~0) & ~(LIBSSH2_TRACE_TRANS/* | LIBSSH2_TRACE_CONN*/));
/* Open local source file */
fp = fopen(localpath, "rb");
if (!fp) {
fprintf(stderr, "Unable to open local file\n");
goto shutdown;
}
/* Run test */
sftp_handle =
libssh2_sftp_open(
sftp_session, sftppath, LIBSSH2_FXF_WRITE | LIBSSH2_FXF_CREAT,
LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP |
LIBSSH2_SFTP_S_IROTH);
if (!sftp_handle) {
char *msg;
fprintf(stderr, "Unable to open file with SFTP\n");
libssh2_session_last_error(session, &msg, NULL, 0);
fprintf(stderr, "%s\n", msg);
fprintf(stderr, "%s\n", libssh2_version(0));
goto shutdown;
}
for (int i = 60000000; i < 600000000; i+=10000000)
{
size_t nwritten = 0;
fprintf(stderr, "trying to write %d bytes\n", i);
/* Read local data into buffer */
mem = (char *)malloc(i);
fseek(fp, 0, SEEK_SET);
rc = fread(mem, 1, i, fp);
if (rc < i) {
fprintf(stderr, "Unable to read from local file: %d\n", rc);
goto shutdown;
}
/* Write to remote end */
//libssh2_sftp_seek(sftp_handle, 0);
do {
/* write data in a loop until we block */
fprintf(stderr, "written %d bytes of %d\n", nwritten, i);
rc = libssh2_sftp_write(sftp_handle, mem + nwritten, i - nwritten);
if(rc < 0) {
char *msg;
fprintf(stderr, "WRITE FAILED!\n");
libssh2_session_last_error(session, &msg, NULL, 0);
fprintf(stderr, "%s\n", msg);
fprintf(stderr, "%s\n", libssh2_version(0));
break;
}
nwritten += rc;
} while (nwritten < i);
free(mem);
}
rc = libssh2_sftp_close(sftp_handle);
if (rc < 0) {
char *msg;
fprintf(stderr, "libssh2_sftp_close FAILED!\n");
libssh2_session_last_error(session, &msg, NULL, 0);
fprintf(stderr, "%s\n", msg);
fprintf(stderr, "%s\n", libssh2_version(0));
}
fclose(fp);
libssh2_sftp_shutdown(sftp_session);
shutdown:
libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing");
libssh2_session_free(session);
#ifdef WIN32
closesocket(sock);
#else
close(sock);
#endif
fprintf(stderr, "all done\n");
return 0;
}
_______________________________________________
libssh2-devel http://cool.haxx.se/cgi-bin/mailman/listinfo/libssh2-devel