diff --git a/examples/echoserver/echoserver.c b/examples/echoserver/echoserver.c index 4d9b336a..3e50f274 100644 --- a/examples/echoserver/echoserver.c +++ b/examples/echoserver/echoserver.c @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -280,6 +281,8 @@ static int NonBlockSSH_accept(WOLFSSH* ssh) return ret; } +static int quit = 0; +wolfSSL_Mutex doneLock; static THREAD_RETURN WOLFSSH_THREAD server_worker(void* vArgs) { @@ -327,7 +330,9 @@ static THREAD_RETURN WOLFSSH_THREAD server_worker(void* vArgs) fprintf(stderr, "Error [%d] \"%s\" with handling connection.\n", ret, wolfSSH_ErrorToName(ret)); #ifndef WOLFSSH_NO_EXIT - exit(EXIT_FAILURE); + wc_LockMutex(&doneLock); + quit = 1; + wc_UnLockMutex(&doneLock); #endif } @@ -752,6 +757,7 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) } } myoptind = 0; /* reset for test cases */ + wc_InitMutex(&doneLock); #ifdef WOLFSSH_TEST_BLOCK if (!nonBlock) { @@ -930,8 +936,9 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) server_worker(threadCtx); - } while (multipleConnections); + } while (multipleConnections && !quit); + wc_FreeMutex(&doneLock); PwMapListDelete(&pwMapList); wolfSSH_CTX_free(ctx); if (wolfSSH_Cleanup() != WS_SUCCESS) { diff --git a/examples/sftpclient/sftpclient.c b/examples/sftpclient/sftpclient.c index 1e4f6c30..f8566569 100644 --- a/examples/sftpclient/sftpclient.c +++ b/examples/sftpclient/sftpclient.c @@ -31,7 +31,7 @@ #ifdef WOLFSSH_SFTP -int doCmds(void); +int doCmds(func_args* args); /* static so that signal handler can access and interrupt get/put */ @@ -177,7 +177,7 @@ static void clean_path(char* path) } } -const char testString[] = "Hello, wolfSSH!"; +const char sftpTestString[] = "Hello, wolfSSH!"; #define WS_MAX_EXAMPLE_RW 1024 @@ -319,21 +319,51 @@ static int wsUserAuth(byte authType, } +/* returns 0 on success */ +static INLINE int SFTP_FPUTS(func_args* args, const char* msg) +{ + int ret; + + if (args && args->sftp_cb) + ret = args->sftp_cb(msg, NULL, 0); + else + ret = WFPUTS(msg, fout); + + return ret; +} + + +/* returns pointer on success, NULL on failure */ +static INLINE char* SFTP_FGETS(func_args* args, char* msg, int msgSz) +{ + char* ret = NULL; + + if (args && args->sftp_cb) { + if (args->sftp_cb(NULL, msg, msgSz) == 0) + ret = msg; + } + else + ret = WFGETS(msg, msgSz, fin); + + return ret; +} + + /* main loop for handling commands */ -int doCmds() +int doCmds(func_args* args) { byte quit = 0; int ret, err; byte resume = 0; int i; - while (!quit) { + do { char msg[WOLFSSH_MAX_FILENAME * 2]; char* pt; - if (WFPUTS("wolfSSH sftp> ", fout) < 0) + if (SFTP_FPUTS(args, "wolfSSH sftp> ") < 0) err_sys("fputs error"); - if (WFGETS(msg, sizeof(msg) - 1, fin) == NULL) + if (SFTP_FGETS(args, msg, sizeof(msg) - 1) == NULL) err_sys("fgets error"); msg[WOLFSSH_MAX_FILENAME * 2 - 1] = '\0'; @@ -365,11 +395,11 @@ int doCmds() if ((ret = wolfSSH_SFTP_MKDIR(ssh, pt, &atrb)) != WS_SUCCESS) { err = wolfSSH_get_error(ssh); if (ret == WS_PERMISSIONS) { - if (WFPUTS("Insufficient permissions\n", fout) < 0) + if (SFTP_FPUTS(args, "Insufficient permissions\n") < 0) err_sys("fputs error"); } else if (err != WS_WANT_READ && err != WS_WANT_WRITE) { - if (WFPUTS("Error writing directory\n", fout) < 0) + if (SFTP_FPUTS(args, "Error writing directory\n") < 0) err_sys("fputs error"); } } @@ -440,7 +470,7 @@ int doCmds() else { WSNPRINTF(buf, sizeof(buf), "fetching %s to %s\n", pt, to); } - if (WFPUTS(buf, fout) < 0) + if (SFTP_FPUTS(args, buf) < 0) err_sys("fputs error"); } @@ -452,11 +482,11 @@ int doCmds() } while (ret == WS_WANT_READ || ret == WS_WANT_WRITE); if (ret != WS_SUCCESS) { - if (WFPUTS("Error getting file\n", fout) < 0) + if (SFTP_FPUTS(args, "Error getting file\n") < 0) err_sys("fputs error"); } else { - if (WFPUTS("\n", fout) < 0) /* new line after status output */ + if (SFTP_FPUTS(args, "\n") < 0) /* new line after status output */ err_sys("fputs error"); } resume = 0; @@ -525,7 +555,7 @@ int doCmds() else { WSNPRINTF(buf, sizeof(buf), "pushing %s to %s\n", pt, to); } - if (WFPUTS(buf, fout) < 0) + if (SFTP_FPUTS(args, buf) < 0) err_sys("fputs error"); } @@ -536,11 +566,11 @@ int doCmds() } while ((err == WS_WANT_READ || err == WS_WANT_WRITE) && ret != WS_SUCCESS); if (ret != WS_SUCCESS) { - if (WFPUTS("Error pushing file\n", fout) < 0) + if (SFTP_FPUTS(args, "Error pushing file\n") < 0) err_sys("fputs error"); } else { - if (WFPUTS("\n", fout) < 0) /* new line after status output */ + if (SFTP_FPUTS(args, "\n") < 0) /* new line after status output */ err_sys("fputs error"); } resume = 0; @@ -581,7 +611,7 @@ int doCmds() } while ((err == WS_WANT_READ || err == WS_WANT_WRITE) && ret != WS_SUCCESS); if (ret != WS_SUCCESS) { - if (WFPUTS("Error changing directory\n", fout) < 0) + if (SFTP_FPUTS(args, "Error changing directory\n") < 0) err_sys("fputs error"); } @@ -654,7 +684,7 @@ int doCmds() } while ((err == WS_WANT_READ || err == WS_WANT_WRITE) && ret != WS_SUCCESS); if (ret != WS_SUCCESS) { - if (WFPUTS("Unable to change path permissions\n", fout) < 0) + if (SFTP_FPUTS(args, "Unable to change path permissions\n") < 0) err_sys("fputs error"); } @@ -694,11 +724,11 @@ int doCmds() && ret != WS_SUCCESS); if (ret != WS_SUCCESS) { if (ret == WS_PERMISSIONS) { - if (WFPUTS("Insufficient permissions\n", fout) < 0) + if (SFTP_FPUTS(args, "Insufficient permissions\n") < 0) err_sys("fputs error"); } else { - if (WFPUTS("Error writing directory\n", fout) < 0) + if (SFTP_FPUTS(args, "Error writing directory\n") < 0) err_sys("fputs error"); } } @@ -736,11 +766,11 @@ int doCmds() && ret != WS_SUCCESS); if (ret != WS_SUCCESS) { if (ret == WS_PERMISSIONS) { - if (WFPUTS("Insufficient permissions\n", fout) < 0) + if (SFTP_FPUTS(args, "Insufficient permissions\n") < 0) err_sys("fputs error"); } else { - if (WFPUTS("Error writing directory\n", fout) < 0) + if (SFTP_FPUTS(args, "Error writing directory\n") < 0) err_sys("fputs error"); } } @@ -811,7 +841,7 @@ int doCmds() } while ((err == WS_WANT_READ || err == WS_WANT_WRITE) && ret != WS_SUCCESS); if (ret != WS_SUCCESS) { - if (WFPUTS("Error with rename\n", fout) < 0) + if (SFTP_FPUTS(args, "Error with rename\n") < 0) err_sys("fputs error"); } XFREE(f, NULL, DYNAMIC_TYPE_TMP_BUFFER); @@ -831,9 +861,9 @@ int doCmds() && current == NULL && err != WS_SUCCESS); tmp = current; while (tmp != NULL) { - if (WFPUTS(tmp->fName, fout) < 0) + if (SFTP_FPUTS(args, tmp->fName) < 0) err_sys("fputs error"); - if (WFPUTS("\n", fout) < 0) + if (SFTP_FPUTS(args, "\n") < 0) err_sys("fputs error"); tmp = tmp->next; } @@ -843,8 +873,8 @@ int doCmds() /* display current working directory */ if ((pt = WSTRNSTR(msg, "pwd", sizeof(msg))) != NULL) { - if (WFPUTS(workingDir, fout) < 0 || - WFPUTS("\n", fout) < 0) + if (SFTP_FPUTS(args, workingDir) < 0 || + SFTP_FPUTS(args, "\n") < 0) err_sys("fputs error"); continue; } @@ -864,8 +894,8 @@ int doCmds() continue; } - WFPUTS("Unknown command\n", fout); - } + SFTP_FPUTS(args, "Unknown command\n"); + } while (!quit); return WS_SUCCESS; } @@ -1018,7 +1048,7 @@ THREAD_RETURN WOLFSSH_THREAD sftpclient_test(void* args) n = NULL; } - doCmds(); + doCmds(args); XFREE(workingDir, NULL, DYNAMIC_TYPE_TMP_BUFFER); ret = wolfSSH_shutdown(ssh); @@ -1036,7 +1066,8 @@ THREAD_RETURN WOLFSSH_THREAD sftpclient_test(void* args) THREAD_RETURN WOLFSSH_THREAD sftpclient_test(void* args) { printf("Not compiled in!\nPlease recompile with WOLFSSH_SFTP or --enable-sftp"); - return -1; + (void)args; + return 0; } #endif /* WOLFSSH_SFTP */ @@ -1050,6 +1081,7 @@ THREAD_RETURN WOLFSSH_THREAD sftpclient_test(void* args) args.argv = argv; args.return_code = 0; args.user_auth = NULL; + args.sftp_cb = NULL; WSTARTTCP(); diff --git a/tests/include.am b/tests/include.am index bcf2f13f..8545b4cc 100644 --- a/tests/include.am +++ b/tests/include.am @@ -18,11 +18,17 @@ tests_api_test_LDADD = src/libwolfssh.la tests_api_test_DEPENDENCIES = src/libwolfssh.la tests_testsuite_test_SOURCES = tests/testsuite.c \ + tests/sftp.c \ examples/echoserver/echoserver.c \ - examples/client/client.c -tests_testsuite_test_CPPFLAGS = -DNO_MAIN_DRIVER + examples/client/client.c \ + examples/sftpclient/sftpclient.c +tests_testsuite_test_CPPFLAGS = -DNO_MAIN_DRIVER +if BUILD_SFTP +tests_testsuite_test_CPPFLAGS += -DWOLFSSH_SFTP +endif tests_testsuite_test_LDADD = src/libwolfssh.la tests_testsuite_test_DEPENDENCIES = src/libwolfssh.la DISTCLEANFILES+= tests/.libs/unit.test tests/.libs/api.test \ tests/.libs/testsuite.test +EXTRA_DIST += tests/unit.h diff --git a/tests/sftp.c b/tests/sftp.c new file mode 100644 index 00000000..a3f9562f --- /dev/null +++ b/tests/sftp.c @@ -0,0 +1,132 @@ +/* sftp.c + * + * Copyright (C) 2014-2016 wolfSSL Inc. + * + * This file is part of wolfSSH. + * + * wolfSSH is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfSSH. If not, see . + */ + +#include +#include +#include + +#define WOLFSSH_TEST_LOCKING +#define WOLFSSH_TEST_THREADING +#include + +#include "tests/testsuite.h" +#include "examples/echoserver/echoserver.h" +#include "examples/sftpclient/sftpclient.h" + +#if defined(WOLFSSH_SFTP) && !defined(SINGLE_THREADED) + +static const char* cmds[] = { + "ls", + "exit" +}; +static int commandIdx = 0; + +static int commandCb(const char* in, char* out, int outSz) +{ + int ret = 0; + + if (in) { + /* print out */ + } + + /* get command input */ + if (out) { + int sz = WSTRLEN(cmds[commandIdx]); + if (outSz < sz) { + ret = -1; + } + else { + WMEMCPY(out, cmds[commandIdx], sz); + } + commandIdx++; + } + return ret; +} + + +/* test SFTP commands, if flag is set to 1 then use non blocking + * return 0 on success */ +int test_SFTP(int flag) +{ + func_args ser; + func_args cli; + tcp_ready ready; + int ret = 0; + int argsCount; + + const char* args[10]; + char portNumber[8]; + + THREAD_TYPE serThread; + THREAD_TYPE cliThread; + + WMEMSET(&ser, 0, sizeof(func_args)); + WMEMSET(&cli, 0, sizeof(func_args)); + commandIdx = 0; + + argsCount = 0; + args[argsCount++] = "."; + args[argsCount++] = "-1"; +#ifndef USE_WINDOWS_API + args[argsCount++] = "-p"; + args[argsCount++] = "0"; +#endif + if (flag) + args[argsCount++] = "-N"; + + ser.argv = (char**)args; + ser.argc = argsCount; + ser.signal = &ready; + InitTcpReady(ser.signal); + ThreadStart(echoserver_test, (void*)&ser, &serThread); + WaitTcpReady(&ser); + + argsCount = 0; + args[argsCount++] = "."; + args[argsCount++] = "-u"; + args[argsCount++] = "jill"; + args[argsCount++] = "-P"; + args[argsCount++] = "upthehill"; + args[argsCount++] = "-p"; + +#ifndef USE_WINDOWS_API + /* use port that server has found */ + snprintf(portNumber, sizeof(portNumber), "%d", ready.port); + args[argsCount++] = portNumber; +#endif + + if (flag) + args[argsCount++] = "-N"; + + cli.argv = (char**)args; + cli.argc = argsCount; + cli.signal = &ready; + cli.sftp_cb = commandCb; + ThreadStart(sftpclient_test, (void*)&cli, &cliThread); + + + ThreadJoin(serThread); + ThreadJoin(cliThread); + + return ret; +} +#endif /* WOLFSSH_SFTP */ + + diff --git a/tests/testsuite.c b/tests/testsuite.c index b8e1d936..bc289814 100644 --- a/tests/testsuite.c +++ b/tests/testsuite.c @@ -37,7 +37,7 @@ #include #include "examples/echoserver/echoserver.h" #include "examples/client/client.h" - +#include "tests/testsuite.h" #ifndef NO_TESTSUITE_MAIN_DRIVER @@ -141,6 +141,14 @@ int TestsuiteTest(int argc, char** argv) wolfSSH_Cleanup(); FreeTcpReady(&ready); + +#ifdef WOLFSSH_SFTP + printf("testing STP blocking\n"); + test_SFTP(0); + printf("testing STP non blocking\n"); + test_SFTP(1); +#endif + return EXIT_SUCCESS; } diff --git a/wolfssh/test.h b/wolfssh/test.h index 325f3cce..a128d540 100644 --- a/wolfssh/test.h +++ b/wolfssh/test.h @@ -650,12 +650,20 @@ typedef struct tcp_ready { } tcp_ready; +#ifdef WOLFSSH_SFTP +typedef int (*WS_CallbackSftpCommand)(const char* in, char* out, int outSz); +#endif + typedef struct func_args { int argc; char** argv; int return_code; tcp_ready* signal; WS_CallbackUserAuth user_auth; +#ifdef WOLFSSH_SFTP + /* callback for example sftp client commands instead of WFGETS */ + WS_CallbackSftpCommand sftp_cb; +#endif } func_args;