ssh
wolfssh/test.h
- Committer:
- sPymbed
- Date:
- 2019-11-25
- Revision:
- 0:c4152c628df5
File content as of revision 0:c4152c628df5:
/* test.h */ #pragma once #ifndef _WOLFSSH_TEST_H_ #define _WOLFSSH_TEST_H_ #include <stdio.h> /*#include <stdlib.h>*/ #include <ctype.h> /*#include <wolfssh/error.h>*/ #ifdef USE_WINDOWS_API #include <winsock2.h> #include <process.h> #include <assert.h> #ifdef TEST_IPV6 /* don't require newer SDK for IPV4 */ #include <ws2tcpip.h> #include <wspiapi.h> #endif #define SOCKET_T SOCKET #else /* USE_WINDOWS_API */ #include <unistd.h> #include <netdb.h> #include <netinet/in.h> //#include <netinet/tcp.h> #include <arpa/inet.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <pthread.h> #include <fcntl.h> #ifndef SO_NOSIGPIPE // FIX: ESP32 #include <signal.h> /* ignore SIGPIPE */ #endif #define SOCKET_T int #endif /* USE_WINDOWS_API */ /* Socket Handling */ #ifndef WOLFSSH_SOCKET_INVALID #ifdef USE_WINDOWS_API #define WOLFSSH_SOCKET_INVALID ((SOCKET_T)INVALID_SOCKET) #elif defined(WOLFSSH_TIRTOS) #define WOLFSSH_SOCKET_INVALID ((SOCKET_T)-1) #else #define WOLFSSH_SOCKET_INVALID (SOCKET_T)(0) #endif #endif /* WOLFSSH_SOCKET_INVALID */ #ifndef WOLFSSL_SOCKET_IS_INVALID #if defined(USE_WINDOWS_API) || defined(WOLFSSL_TIRTOS) #define WOLFSSL_SOCKET_IS_INVALID(s) ((SOCKET_T)(s) == WOLFSSL_SOCKET_INVALID) #else #define WOLFSSL_SOCKET_IS_INVALID(s) ((SOCKET_T)(s) < WOLFSSL_SOCKET_INVALID) #endif #endif /* WOLFSSL_SOCKET_IS_INVALID */ #if defined(__MACH__) || defined(USE_WINDOWS_API) #ifndef _SOCKLEN_T typedef int socklen_t; #endif #endif #ifdef USE_WINDOWS_API #define WCLOSESOCKET(s) closesocket(s) #define WSTARTTCP() do { WSADATA wsd; WSAStartup(0x0002, &wsd); } while(0) #else #define WCLOSESOCKET(s) close(s) #define WSTARTTCP() #endif #ifdef SINGLE_THREADED typedef unsigned int THREAD_RETURN; typedef void* THREAD_TYPE; #define WOLFSSH_THREAD #else #if defined(_POSIX_THREADS) && !defined(__MINGW32__) typedef void* THREAD_RETURN; typedef pthread_t THREAD_TYPE; #define WOLFSSH_THREAD #define INFINITE -1 #define WAIT_OBJECT_0 0L #else typedef unsigned int THREAD_RETURN; typedef intptr_t THREAD_TYPE; #define WOLFSSH_THREAD __stdcall #endif #endif #ifdef TEST_IPV6 typedef struct sockaddr_in6 SOCKADDR_IN_T; #define AF_INET_V AF_INET6 #else typedef struct sockaddr_in SOCKADDR_IN_T; #define AF_INET_V AF_INET #endif #define serverKeyRsaPemFile "./keys/server-key-rsa.pem" typedef struct tcp_ready { word16 ready; /* predicate */ word16 port; char* srfName; /* server ready file name */ #if defined(_POSIX_THREADS) && !defined(__MINGW32__) pthread_mutex_t mutex; pthread_cond_t cond; #endif } tcp_ready; static INLINE void InitTcpReady(tcp_ready* ready) { ready->ready = 0; ready->port = 0; ready->srfName = NULL; #ifdef SINGLE_THREADED #elif defined(_POSIX_THREADS) && !defined(__MINGW32__) pthread_mutex_init(&ready->mutex, 0); pthread_cond_init(&ready->cond, 0); #endif } static INLINE void FreeTcpReady(tcp_ready* ready) { #ifdef SINGLE_THREADED (void)ready; #elif defined(_POSIX_THREADS) && !defined(__MINGW32__) pthread_mutex_destroy(&ready->mutex); pthread_cond_destroy(&ready->cond); #else (void)ready; #endif } typedef struct func_args { int argc; char** argv; int return_code; tcp_ready* signal; WS_CallbackUserAuth user_auth; } func_args; typedef THREAD_RETURN WOLFSSH_THREAD THREAD_FUNC(void*); void ThreadStart(THREAD_FUNC, void*, THREAD_TYPE*); void ThreadJoin(THREAD_TYPE); void ThreadDetach(THREAD_TYPE); void WaitTcpReady(func_args*); #ifndef TEST_IPV6 static const char* const wolfSshIp = "127.0.0.1"; #else /* TEST_IPV6 */ static const char* const wolfSshIp = "::1"; #endif /* TEST_IPV6 */ static const word16 wolfSshPort = 22222; #ifdef __GNUC__ #define WS_NORETURN __attribute__((noreturn)) #else #define WS_NORETURN #endif static INLINE WS_NORETURN void err_sys(const char* msg) { printf("wolfSSH error: %s\n", msg); #ifndef __GNUC__ /* scan-build (which pretends to be gnuc) can get confused and think the * msg pointer can be null even when hardcoded and then it won't exit, * making null pointer checks above the err_sys() call useless. * We could just always exit() but some compilers will complain about no * possible return, with gcc we know the attribute to handle that with * WS_NORETURN. */ if (msg) #endif { exit(EXIT_FAILURE); } } #define MY_EX_USAGE 2 extern int myoptind; extern char* myoptarg; static INLINE int mygetopt(int argc, char** argv, const char* optstring) { static char* next = NULL; char c; char* cp; if (myoptind == 0) next = NULL; /* we're starting new/over */ if (next == NULL || *next == '\0') { if (myoptind == 0) myoptind++; if (myoptind >= argc || argv[myoptind][0] != '-' || argv[myoptind][1] == '\0') { myoptarg = NULL; if (myoptind < argc) myoptarg = argv[myoptind]; return -1; } if (strcmp(argv[myoptind], "--") == 0) { myoptind++; myoptarg = NULL; if (myoptind < argc) myoptarg = argv[myoptind]; return -1; } next = argv[myoptind]; next++; /* skip - */ myoptind++; } c = *next++; /* The C++ strchr can return a different value */ cp = (char*)strchr(optstring, c); if (cp == NULL || c == ':') return '?'; cp++; if (*cp == ':') { if (*next != '\0') { myoptarg = next; next = NULL; } else if (myoptind < argc) { myoptarg = argv[myoptind]; myoptind++; } else return '?'; } return c; } #ifdef USE_WINDOWS_API #pragma warning(push) #pragma warning(disable:4996) /* For Windows builds, disable compiler warnings for: * - 4996: deprecated function */ #endif static INLINE void build_addr(SOCKADDR_IN_T* addr, const char* peer, word16 port) { int useLookup = 0; (void)useLookup; memset(addr, 0, sizeof(SOCKADDR_IN_T)); #ifndef TEST_IPV6 /* peer could be in human readable form */ if ( ((size_t)peer != INADDR_ANY) && isalpha((int)peer[0])) { #ifdef CYASSL_MDK_ARM int err; struct hostent* entry = gethostbyname(peer, &err); #else struct hostent* entry = gethostbyname(peer); #endif if (entry) { memcpy(&addr->sin_addr.s_addr, entry->h_addr_list[0], entry->h_length); useLookup = 1; } else err_sys("no entry for host"); } #endif #ifndef TEST_IPV6 #if defined(CYASSL_MDK_ARM) addr->sin_family = PF_INET; #else addr->sin_family = AF_INET_V; #endif addr->sin_port = htons(port); if ((size_t)peer == INADDR_ANY) addr->sin_addr.s_addr = INADDR_ANY; else { if (!useLookup) addr->sin_addr.s_addr = inet_addr(peer); } #else addr->sin6_family = AF_INET_V; addr->sin6_port = htons(port); if ((size_t)peer == INADDR_ANY) addr->sin6_addr = in6addr_any; else { #ifdef HAVE_GETADDRINFO struct addrinfo hints; struct addrinfo* answer = NULL; int ret; char strPort[80]; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET_V; hints.ai_socktype = udp ? SOCK_DGRAM : SOCK_STREAM; hints.ai_protocol = udp ? IPPROTO_UDP : IPPROTO_TCP; WSNPRINTF(strPort, sizeof(strPort), "%d", port); strPort[79] = '\0'; ret = getaddrinfo(peer, strPort, &hints, &answer); if (ret < 0 || answer == NULL) err_sys("getaddrinfo failed"); memcpy(addr, answer->ai_addr, answer->ai_addrlen); freeaddrinfo(answer); #else printf("no ipv6 getaddrinfo, loopback only tests/examples\n"); addr->sin6_addr = in6addr_loopback; #endif } #endif } #ifdef USE_WINDOWS_API #pragma warning(pop) #endif static INLINE void tcp_socket(SOCKET_T* sockFd) { *sockFd = socket(AF_INET_V, SOCK_STREAM, 0); #ifdef USE_WINDOWS_API if (*sockFd == INVALID_SOCKET) err_sys("socket failed\n"); #else if (*sockFd < 0) err_sys("socket failed\n"); #endif #ifndef USE_WINDOWS_API #ifdef SO_NOSIGPIPE { int on = 1; socklen_t len = sizeof(on); int res = setsockopt(*sockFd, SOL_SOCKET, SO_NOSIGPIPE, &on, len); if (res < 0) err_sys("setsockopt SO_NOSIGPIPE failed\n"); } #elif defined(CYASSL_MDK_ARM) /* nothing to define */ #else /* no S_NOSIGPIPE */ // signal(SIGPIPE, SIG_IGN); // FIX: ESP32 #endif /* S_NOSIGPIPE */ #if defined(TCP_NODELAY) { int on = 1; socklen_t len = sizeof(on); int res = setsockopt(*sockFd, IPPROTO_TCP, TCP_NODELAY, &on, len); if (res < 0) err_sys("setsockopt TCP_NODELAY failed\n"); } #endif #endif /* USE_WINDOWS_API */ } #ifndef XNTOHS #define XNTOHS(a) ntohs((a)) #endif static INLINE void tcp_listen(SOCKET_T* sockfd, word16* port, int useAnyAddr) { SOCKADDR_IN_T addr; /* don't use INADDR_ANY by default, firewall may block, make user switch on */ build_addr(&addr, (useAnyAddr ? INADDR_ANY : wolfSshIp), *port); tcp_socket(sockfd); #if !defined(USE_WINDOWS_API) && !defined(WOLFSSL_MDK_ARM)\ && !defined(WOLFSSL_KEIL_TCP_NET) { int res, on = 1; socklen_t len = sizeof(on); res = setsockopt(*sockfd, SOL_SOCKET, SO_REUSEADDR, &on, len); if (res < 0) err_sys("setsockopt SO_REUSEADDR failed\n"); } #endif if (bind(*sockfd, (const struct sockaddr*)&addr, sizeof(addr)) != 0) err_sys("tcp bind failed"); if (listen(*sockfd, 5) != 0) err_sys("tcp listen failed"); #if !defined(USE_WINDOWS_API) && !defined(WOLFSSL_TIRTOS) if (*port == 0) { socklen_t len = sizeof(addr); if (getsockname(*sockfd, (struct sockaddr*)&addr, &len) == 0) { #ifndef TEST_IPV6 *port = XNTOHS(addr.sin_port); #else *port = XNTOHS(addr.sin6_port); #endif } } #endif } /* Wolf Root Directory Helper */ /* KEIL-RL File System does not support relative directory */ #if !defined(WOLFSSL_MDK_ARM) && !defined(WOLFSSL_KEIL_FS) && !defined(WOLFSSL_TIRTOS) /* Maximum depth to search for WolfSSL root */ #define MAX_WOLF_ROOT_DEPTH 5 static INLINE int ChangeToWolfSshRoot(void) { #if !defined(NO_FILESYSTEM) int depth, res; WFILE* file; for(depth = 0; depth <= MAX_WOLF_ROOT_DEPTH; depth++) { if (WFOPEN(&file, serverKeyRsaPemFile, "rb") == 0) { WFCLOSE(file); return depth; } #ifdef USE_WINDOWS_API res = SetCurrentDirectoryA("..\\"); #else res = chdir("../"); #endif if (res < 0) { printf("chdir to ../ failed!\n"); break; } } err_sys("wolfSSH root not found"); return -1; #else return 0; #endif } #endif /* !defined(WOLFSSL_MDK_ARM) && !defined(WOLFSSL_KEIL_FS) && !defined(WOL FSSL_TIRTOS) */ #endif /* _WOLFSSH_TEST_H_ */