From bdc54835c2ec6ef556bc36dcd89677c1fa1ac175 Mon Sep 17 00:00:00 2001 From: despair86 Date: Sun, 29 Jul 2018 23:38:14 -0500 Subject: [PATCH] initial windows server port. Requires Windows 2000 Server or later. - updated CMake build script - builds with Microsoft C++ 19.1x. such builds require Windows 8.1 or later unless you have the .NET Server 2003-toolset (v141_xp) - windows port requires a C++17 compiler since cpp17::filesystem is POSIX-only - HAVE_CXX17_FILESYSTEM manual toggle in CMake. You must manually specify where std::[experimental::]filesystem is defined in LDFLAGS or CMAKE_x_LINKER_FLAGS. - IPv6 support can be added at any time, and the windows sdk still has that inline getaddrinfo(3) if it can't find a suitable IPv6 stack. - inline code for mingw-w64: there's a few bits and pieces still missing simply because mingw-w64 derives its windows sdk from wine and reactos, and then writing all the newer stuff into it by hand straight from the MSDN manpages. - misc. C++11 stuff (nullptr and friends) - Internal file handling code takes UTF-8 or plain 8-bit text, NTFS is UTF-16, so std::filesystem::path::c_str() is wchar_t. That's no good unless you first call std::filesystem::path::string(). - implemented getifaddrs(3) and if_nametoindex(3) on top of GetAdapters[Info|Addresses](2). - updated readme with new info BONUS: may implement Solaris/illumos IOCP someday... -despair86 --- CMakeLists.txt | 113 +- contrib/msc/getopt.c | 1050 +++++++++++++++++ contrib/msc/getopt1.c | 190 +++ contrib/msc/include/getopt.h | 157 +++ daemon/dns.cpp | 17 + daemon/main.cpp | 5 + daemon/rcutil.cpp | 25 +- include/llarp/codel.hpp | 4 + include/llarp/dns.h | 5 + include/llarp/endian.h | 28 +- include/llarp/ev.h | 14 +- include/llarp/logger.hpp | 16 +- include/llarp/net.h | 21 +- include/llarp/net.hpp | 20 +- include/llarp/threading.hpp | 2 +- llarp/address_info.cpp | 16 + llarp/buffer.cpp | 3 + llarp/context.cpp | 240 ++-- llarp/crypto_libsodium.cpp | 2 +- llarp/dns.cpp | 4 + llarp/dnsc.cpp | 42 +- llarp/dnsd.cpp | 9 + llarp/ev.cpp | 18 +- llarp/ev.hpp | 11 + llarp/ev_kqueue.hpp | 19 +- llarp/ev_win32.hpp | 214 ++++ llarp/exit_info.cpp | 3 + llarp/exit_route.cpp | 3 + llarp/fs.hpp | 13 +- llarp/ini.hpp | 7 +- llarp/iwp/frame_state.cpp | 5 + llarp/iwp/session.cpp | 4 + llarp/mem.hpp | 2 +- llarp/net.cpp | 703 ++++++++++- llarp/nodedb.cpp | 18 +- llarp/router.cpp | 79 +- llarp/service.cpp | 4 + llarp/threadpool.cpp | 12 +- llarp/win32_inet.c | 312 +++++ llarp/win32_intrnl.c | 534 +++++++++ llarp/win32_intrnl.h | 111 ++ readme.md | 58 +- vendor/cppbackport-master/lib/filesystem.h | 17 +- .../cppbackport-master/lib/fs/filestatus.cpp | 14 +- 44 files changed, 3900 insertions(+), 244 deletions(-) create mode 100644 contrib/msc/getopt.c create mode 100644 contrib/msc/getopt1.c create mode 100644 contrib/msc/include/getopt.h create mode 100644 llarp/ev_win32.hpp create mode 100644 llarp/win32_inet.c create mode 100644 llarp/win32_intrnl.c create mode 100644 llarp/win32_intrnl.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f1a17f21..c77e61f88 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,21 +13,32 @@ endmacro(add_cxxflags) include(CheckCXXCompilerFlag) CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11) +if (WIN32 AND NOT MINGW) +CHECK_CXX_COMPILER_FLAG("/std:c++17" COMPILER_SUPPORTS_CXX17) +else() CHECK_CXX_COMPILER_FLAG("-std=c++17" COMPILER_SUPPORTS_CXX17) -if(COMPILER_SUPPORTS_CXX11 AND NOT COMPILER_SUPPORTS_CXX17 OR ${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD") +endif() + +option(HAVE_CXX17_FILESYSTEM "Enable if your C++ compiler and runtime library implements std::[experimental::]filesystem" OFF) + +if(COMPILER_SUPPORTS_CXX11 AND NOT HAVE_CXX17_FILESYSTEM) add_cxxflags("-std=c++11") -elseif(COMPILER_SUPPORTS_CXX17) +elseif(COMPILER_SUPPORTS_CXX17 AND HAVE_CXX17_FILESYSTEM) + if (WIN32 AND NOT MINGW) + add_cxxflags("/std:c++17") + else() add_cxxflags("-std=c++17") + endif() + add_definitions(-DUSE_CXX17_FILESYSTEM) else() message(ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++11 or C++17 support. Please use a different C++ compiler.") endif() -# attempting to fix linux gcc 7.2 which COMPILER_SUPPORTS_CXX17 but doesn't have filesystem.h -include(CheckIncludeFileCXX) -CHECK_INCLUDE_FILE_CXX(filesystem.h HAVE_STD_FS) - if(ANDROID) set(THREAD_LIB "-pthread") +# finally removed pthread dependency for MSC++ +elseif(WIN32 AND NOT MINGW) +set(THREAD_LIB) else() set(THREAD_LIB pthread) endif() @@ -44,11 +55,18 @@ else() set(WITH_STATIC ON) endif() +if (UNIX OR MINGW OR APPLE) add_cflags("-Wall") add_cxxflags("-Wall") +endif() -set(DEBUG_FLAGS "-g") +if (WIN32 AND NOT MINGW) +set(OPTIMIZE_FLAGS "-Od") +set(DEBUG_FLAGS "-ZI") +else() set(OPTIMIZE_FLAGS "-O0") +set(DEBUG_FLAGS "-g") +endif() if(ASAN) set(DEBUG_FLAGS "${DEBUG_FLAGS} -fsanitize=address -fno-omit-frame-pointer") @@ -69,14 +87,18 @@ if(SHADOW) include(ShadowTools) add_cxxflags("-fno-inline -fno-strict-aliasing") add_cflags("-fno-inline -fno-strict-aliasing") - add_definitions(-DTESTNET=true) add_definitions(-DSHADOW_TESTNET) include_directories(${SHADOW_ROOT}/include) endif() +if (WIN32 AND NOT MINGW) +add_cflags("-wd4996 -wd4244 -MP ${OPTIMIZE_FLAGS}") +add_cxxflags("-wd4996 -wd4244 -MP ${OPTIMIZE_FLAGS}") +else() add_cflags("-Wall -Wno-deprecated-declarations ${OPTIMIZE_FLAGS}") add_cxxflags("-Wall -Wno-deprecated-declarations ${OPTIMIZE_FLAGS}") +endif() if(CMAKE_BUILD_TYPE MATCHES "[Dd][Ee][Bb][Uu][Gg]") add_cflags("${DEBUG_FLAGS}") @@ -116,14 +138,18 @@ endif() set(LIBS ${SODIUM_LIB} ${THREAD_LIB}) -set(LIB llarp) +set(LIB lokinet) set(SHARED_LIB ${LIB}) set(STATIC_LIB ${LIB}-static) set(TT_ROOT vendor/libtuntap-master) add_definitions(-D${CMAKE_SYSTEM_NAME}) + +if (UNIX) add_definitions(-DUNIX) +endif() + if(UNIX) if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") set(LIBTUNTAP_IMPL ${TT_ROOT}/tuntap-unix-linux.c) @@ -131,22 +157,26 @@ if(UNIX) set(LIBTUNTAP_IMPL ${TT_ROOT}/tuntap-unix-openbsd.c ${TT_ROOT}/tuntap-unix-bsd.c) elseif (${CMAKE_SYSTEM_NAME} MATCHES "NetBSD") set(LIBTUNTAP_IMPL ${TT_ROOT}/tuntap-unix-netbsd.c ${TT_ROOT}/tuntap-unix-bsd.c) - elseif (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") + elseif (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD" or ${CMAKE_SYSTEM_NAME} MATCHES "DragonFly") set(LIBTUNTAP_IMPL ${TT_ROOT}/tuntap-unix-freebsd.c ${TT_ROOT}/tuntap-unix-bsd.c) elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set(LIBTUNTAP_IMPL ${TT_ROOT}/tuntap-unix-darwin.c ${TT_ROOT}/tuntap-unix-bsd.c) - elseif (${CMAKE_SYSTEM_NAME} MATCHES "DragonFly") - set(LIBTUNTAP_IMPL ${TT_ROOT}/tuntap-unix-freebsd.c ${TT_ROOT}/tuntap-unix-bsd.c) else() message(FATAL_ERROR "Your operating system is not supported yet") endif() +elseif(WIN32 OR MINGW) + set(LIBTUNTAP_IMPL ${TT_ROOT}/tuntap-windows.c) +else() + message(FATAL_ERROR "What operating system _are_ you building on/for?") endif(UNIX) if(TUNTAP) set(LIBTUNTAP_SRC ${TT_ROOT}/tuntap.c ${TT_ROOT}/tuntap_log.c + if (UNIX) ${TT_ROOT}/tuntap-unix.c + endif() ${LIBTUNTAP_IMPL}) else() set(LIBTUNTAP_SRC "") @@ -198,6 +228,11 @@ set(LIB_PLATFORM_SRC llarp/threadpool.cpp # for android shim ${ANDROID_PLATFORM_SRC} +# win32 inline procs + llarp/win32_inet.c + llarp/win32_intrnl.c + contrib/msc/getopt.c + contrib/msc/getopt1.c ) @@ -303,12 +338,16 @@ set(STATIC_LIB ${LIB}-static) # TODO: exclude this from includes and expose stuff properly for rcutil include_directories(llarp) - include_directories(include) include_directories(vendor/cppbackport-master/lib) #include_directories(/usr/local/include) include_directories(${sodium_INCLUDE_DIR}) +if (WIN32 AND NOT MINGW) +include_directories(contrib/msc/include) +link_directories(contrib/msc/lib) +endif() + if(SHADOW) add_shadow_plugin(shadow-plugin-${SHARED_LIB} ${EXE_SRC} ${LIB_SRC}) target_link_libraries(shadow-plugin-${SHARED_LIB} ${LIBS}) @@ -330,62 +369,62 @@ else() if(WITH_STATIC) add_library(${STATIC_LIB} STATIC ${LIB_SRC}) - if(COMPILER_SUPPORTS_CXX11 AND NOT COMPILER_SUPPORTS_CXX17 OR ${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD" OR NOT HAVE_STD_FS) + if(NOT HAVE_CXX17_FILESYSTEM) add_library(backport-static STATIC ${CPP_BACKPORT_SRC}) - endif(COMPILER_SUPPORTS_CXX11 AND NOT COMPILER_SUPPORTS_CXX17 OR ${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD" OR NOT HAVE_STD_FS) + endif(NOT HAVE_CXX17_FILESYSTEM) add_library(llarpplatform-static STATIC ${LIB_PLATFORM_SRC}) target_link_libraries(llarpplatform-static ${THREAD_LIB}) - if(COMPILER_SUPPORTS_CXX11 AND NOT COMPILER_SUPPORTS_CXX17 OR ${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD" OR NOT HAVE_STD_FS) + if(NOT HAVE_CXX17_FILESYSTEM) target_link_libraries(${STATIC_LIB} ${LIBS} backport-static llarpplatform-static) else() target_link_libraries(${STATIC_LIB} ${LIBS} llarpplatform-static) - endif(COMPILER_SUPPORTS_CXX11 AND NOT COMPILER_SUPPORTS_CXX17 OR ${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD" OR NOT HAVE_STD_FS) + endif(NOT HAVE_CXX17_FILESYSTEM) if(NOT WITH_SHARED) - if(COMPILER_SUPPORTS_CXX11 AND NOT COMPILER_SUPPORTS_CXX17 OR ${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD" OR NOT HAVE_STD_FS) + if(NOT HAVE_CXX17_FILESYSTEM) target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} backport-static llarpplatform-static) target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} backport-static llarpplatform-static) target_link_libraries(rcutil ${STATIC_LINK_LIBS} ${STATIC_LIB} backport-static llarpplatform-static) if (MINGW) - target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} backport-static llarpplatform-static ws2_32 stdc++fs) - target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} backport-static llarpplatform-static ws2_32 stdc++fs) - target_link_libraries(rcutil ${STATIC_LINK_LIBS} ${STATIC_LIB} backport-static llarpplatform-static ws2_32 stdc++fs) + target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} backport-static llarpplatform-static ws2_32 stdc++fs iphlpapi) + target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} backport-static llarpplatform-static ws2_32 stdc++fs iphlpapi) + target_link_libraries(rcutil ${STATIC_LINK_LIBS} ${STATIC_LIB} backport-static llarpplatform-static ws2_32 stdc++fs iphlpapi) elseif(WIN32) - target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} backport-static llarpplatform-static ws2_32) - target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} backport-static llarpplatform-static ws2_32) - target_link_libraries(rcutil ${STATIC_LINK_LIBS} ${STATIC_LIB} backport-static llarpplatform-static ws2_32) + target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} backport-static llarpplatform-static ws2_32 iphlpapi) + target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} backport-static llarpplatform-static ws2_32 iphlpapi) + target_link_libraries(rcutil ${STATIC_LINK_LIBS} ${STATIC_LIB} backport-static llarpplatform-static ws2_32 iphlpapi) endif(MINGW) else() target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} llarpplatform-static) target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} llarpplatform-static) target_link_libraries(rcutil ${STATIC_LINK_LIBS} ${STATIC_LIB} llarpplatform-static) if (MINGW) - target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} llarpplatform-static ws2_32 stdc++fs) - target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} llarpplatform-static ws2_32 stdc++fs) - target_link_libraries(rcutil ${STATIC_LINK_LIBS} ${STATIC_LIB} llarpplatform-static ws2_32 stdc++fs) + target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} llarpplatform-static ws2_32 stdc++fs iphlpapi) + target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} llarpplatform-static ws2_32 stdc++fs iphlpapi) + target_link_libraries(rcutil ${STATIC_LINK_LIBS} ${STATIC_LIB} llarpplatform-static ws2_32 stdc++fs iphlpapi) elseif(WIN32) - target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} llarpplatform-static ws2_32) - target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} llarpplatform-static ws2_32) - target_link_libraries(rcutil ${STATIC_LINK_LIBS} ${STATIC_LIB} llarpplatform-static ws2_32) + target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} llarpplatform-static ws2_32 iphlpapi) + target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} llarpplatform-static ws2_32 iphlpapi) + target_link_libraries(rcutil ${STATIC_LINK_LIBS} ${STATIC_LIB} llarpplatform-static ws2_32 iphlpapi) endif(MINGW) - endif(COMPILER_SUPPORTS_CXX11 AND NOT COMPILER_SUPPORTS_CXX17 OR ${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD" OR NOT HAVE_STD_FS) + endif(NOT HAVE_CXX17_FILESYSTEM) if (MINGW) - target_link_libraries(dns ${STATIC_LIB} llarpplatform-static ${THREAD_LIB} ws2_32 stdc++fs) + target_link_libraries(dns ${STATIC_LIB} llarpplatform-static ${THREAD_LIB} ws2_32 stdc++fs iphlpapi) elseif(WIN32) - target_link_libraries(dns ${STATIC_LIB} llarpplatform-static ${THREAD_LIB} ws2_32) + target_link_libraries(dns ${STATIC_LIB} llarpplatform-static ${THREAD_LIB} ws2_32 iphlpapi) endif(MINGW) target_link_libraries(dns ${STATIC_LIB} llarpplatform-static ${THREAD_LIB}) endif(NOT WITH_SHARED) endif(WITH_STATIC) if(WITH_SHARED) - if(COMPILER_SUPPORTS_CXX11 AND NOT COMPILER_SUPPORTS_CXX17 OR ${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD" OR NOT HAVE_STD_FS) + if(HAVE_CXX17_FILESYSTEM) set(LIB_SRC ${LIB_SRC} ${CPP_BACKPORT_SRC}) - endif(COMPILER_SUPPORTS_CXX11 AND NOT COMPILER_SUPPORTS_CXX17 OR ${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD" OR NOT HAVE_STD_FS) + endif(HAVE_CXX17_FILESYSTEM) add_library(${SHARED_LIB} SHARED ${LIB_SRC} ${LIB_PLATFORM_SRC}) if (MINGW) - set(${LIBS} ${LIBS} ws2_32 stdc++fs) + set(${LIBS} ${LIBS} ws2_32 stdc++fs iphlpapi) elseif(WIN32) - set(${LIBS} ${LIBS} ws2_32) + set(${LIBS} ${LIBS} ws2_32 iphlpapi) endif(MINGW) target_link_libraries(${SHARED_LIB} ${LIBS} ${THREAD_LIB}) target_link_libraries(${EXE} ${SHARED_LIB}) diff --git a/contrib/msc/getopt.c b/contrib/msc/getopt.c new file mode 100644 index 000000000..8f9e40c75 --- /dev/null +++ b/contrib/msc/getopt.c @@ -0,0 +1,1050 @@ +/* force empty if not compiler with Microsoft C */ +#ifdef _MSC_VER +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to drepper@gnu.org + before changing it! + + Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99 + Free Software Foundation, Inc. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* This tells Alpha OSF/1 not to define a getopt prototype in . + Ditto for AIX 3.2 and . */ +#ifndef _NO_PROTO +# define _NO_PROTO +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if !defined __STDC__ || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +# ifndef const +# define const +# endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +# include +# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +# define ELIDE_CODE +# endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +# include +# include +#endif /* GNU C library. */ + +#ifdef VMS +# include +# if HAVE_STRING_H - 0 +# include +# endif +#endif + +#ifndef _ +/* This is for other GNU distributions with internationalized messages. + When compiling libc, the _ macro is predefined. */ +# ifdef HAVE_LIBINTL_H +# include +# define _(msgid) gettext (msgid) +# else +# define _(msgid) (msgid) +# endif +#endif + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt.h" + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* 1003.2 says this must be 1 before any call. */ +int optind = 1; + +/* Formerly, initialization of getopt depended on optind==0, which + causes problems with re-calling getopt as programs generally don't + know that. */ + +int __getopt_initialized; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + +int optopt = '?'; + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return -1 with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +/* Value of POSIXLY_CORRECT environment variable. */ +static char *posixly_correct; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries + because there are many ways it can cause trouble. + On some systems, it contains special magic macros that don't work + in GCC. */ +# include +# define my_index strchr +#else + +#include + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +#ifndef getenv +extern char *getenv (); +#endif + +static char * +my_index (str, chr) + const char *str; + int chr; +{ + while (*str) + { + if (*str == chr) + return (char *) str; + str++; + } + return 0; +} + +/* If using GCC, we can safely declare strlen this way. + If not using GCC, it is ok not to declare it. */ +#ifdef __GNUC__ +/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. + That was relevant to code that was here before. */ +# if (!defined __STDC__ || !__STDC__) && !defined strlen +/* gcc with -traditional declares the built-in strlen to return int, + and has done so at least since version 2.4.5. -- rms. */ +extern int strlen (const char *); +# endif /* not __STDC__ */ +#endif /* __GNUC__ */ + +#endif /* not __GNU_LIBRARY__ */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +#ifdef _LIBC +/* Bash 2.0 gives us an environment variable containing flags + indicating ARGV elements that should not be considered arguments. */ + +/* Defined in getopt_init.c */ +extern char *__getopt_nonoption_flags; + +static int nonoption_flags_max_len; +static int nonoption_flags_len; + +static int original_argc; +static char *const *original_argv; + +/* Make sure the environment variable bash 2.0 puts in the environment + is valid for the getopt call we must make sure that the ARGV passed + to getopt is that one passed to the process. */ +static void +__attribute__ ((unused)) +store_args_and_env (int argc, char *const *argv) +{ + /* XXX This is no good solution. We should rather copy the args so + that we can compare them later. But we must not use malloc(3). */ + original_argc = argc; + original_argv = argv; +} +# ifdef text_set_element +text_set_element (__libc_subinit, store_args_and_env); +# endif /* text_set_element */ + +# define SWAP_FLAGS(ch1, ch2) \ + if (nonoption_flags_len > 0) \ + { \ + char __tmp = __getopt_nonoption_flags[ch1]; \ + __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ + __getopt_nonoption_flags[ch2] = __tmp; \ + } +#else /* !_LIBC */ +# define SWAP_FLAGS(ch1, ch2) +#endif /* _LIBC */ + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +#if defined __STDC__ && __STDC__ +static void exchange (char **); +#endif + +static void +exchange (argv) + char **argv; +{ + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ + +#ifdef _LIBC + /* First make sure the handling of the `__getopt_nonoption_flags' + string can work normally. Our top argument must be in the range + of the string. */ + if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) + { + /* We must extend the array. The user plays games with us and + presents new arguments. */ + char *new_str = malloc (top + 1); + if (new_str == NULL) + nonoption_flags_len = nonoption_flags_max_len = 0; + else + { + memset (__mempcpy (new_str, __getopt_nonoption_flags, + nonoption_flags_max_len), + '\0', top + 1 - nonoption_flags_max_len); + nonoption_flags_max_len = top + 1; + __getopt_nonoption_flags = new_str; + } + } +#endif + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + SWAP_FLAGS (bottom + i, middle + i); + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/* Initialize the internal data when the first call is made. */ + +#if defined __STDC__ && __STDC__ +static const char *_getopt_initialize (int, char *const *, const char *); +#endif +static const char * +_getopt_initialize (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + first_nonopt = last_nonopt = optind; + + nextchar = NULL; + + posixly_correct = getenv ("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (posixly_correct != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + +#ifdef _LIBC + if (posixly_correct == NULL + && argc == original_argc && argv == original_argv) + { + if (nonoption_flags_max_len == 0) + { + if (__getopt_nonoption_flags == NULL + || __getopt_nonoption_flags[0] == '\0') + nonoption_flags_max_len = -1; + else + { + const char *orig_str = __getopt_nonoption_flags; + int len = nonoption_flags_max_len = strlen (orig_str); + if (nonoption_flags_max_len < argc) + nonoption_flags_max_len = argc; + __getopt_nonoption_flags = + (char *) malloc (nonoption_flags_max_len); + if (__getopt_nonoption_flags == NULL) + nonoption_flags_max_len = -1; + else + memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), + '\0', nonoption_flags_max_len - len); + } + } + nonoption_flags_len = nonoption_flags_max_len; + } + else + nonoption_flags_len = 0; +#endif + + return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns -1. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +_getopt_internal (argc, argv, optstring, longopts, longind, long_only) + int argc; + char *const *argv; + const char *optstring; + const struct option *longopts; + int *longind; + int long_only; +{ + optarg = NULL; + + if (optind == 0 || !__getopt_initialized) + { + if (optind == 0) + optind = 1; /* Don't scan ARGV[0], the program name. */ + optstring = _getopt_initialize (argc, argv, optstring); + __getopt_initialized = 1; + } + + /* Test whether ARGV[optind] points to a non-option argument. + Either it does not have option syntax, or there is an environment flag + from the shell indicating it is not an option. The later information + is only used when the used in the GNU libc. */ +#ifdef _LIBC +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ + || (optind < nonoption_flags_len \ + && __getopt_nonoption_flags[optind] == '1')) +#else +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') +#endif + + if (nextchar == NULL || *nextchar == '\0') + { + /* Advance to the next ARGV-element. */ + + /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been + moved back by the user (who may also have changed the arguments). */ + if (last_nonopt > optind) + last_nonopt = optind; + if (first_nonopt > optind) + first_nonopt = optind; + + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc && NONOPTION_P) + optind++; + last_nonopt = optind; + } + + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp (argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return -1; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if (NONOPTION_P) + { + if (ordering == REQUIRE_ORDER) + return -1; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if (longopts != NULL + && (argv[optind][1] == '-' + || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = -1; + int option_index; + + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) + == (unsigned int) strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, _("%s: option `%s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + optopt = 0; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (opterr) + { + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + _("%s: option `--%s' doesn't allow an argument\n"), + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + _("%s: option `%c%s' doesn't allow an argument\n"), + argv[0], argv[optind - 1][0], pfound->name); + } + + nextchar += strlen (nextchar); + + optopt = pfound->val; + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' + || my_index (optstring, *nextchar) == NULL) + { + if (opterr) + { + if (argv[optind][1] == '-') + /* --option */ + fprintf (stderr, _("%s: unrecognized option `--%s'\n"), + argv[0], nextchar); + else + /* +option or -option */ + fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), + argv[0], argv[optind][0], nextchar); + } + nextchar = (char *) ""; + optind++; + optopt = 0; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (opterr) + { + if (posixly_correct) + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: illegal option -- %c\n"), + argv[0], c); + else + fprintf (stderr, _("%s: invalid option -- %c\n"), + argv[0], c); + } + optopt = c; + return '?'; + } + /* Convenience. Treat POSIX -W foo same as long option --foo */ + if (temp[0] == 'W' && temp[1] == ';') + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = 0; + int option_index; + + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + return c; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + + /* optarg is now the argument, see if it's in the + table of longopts. */ + + for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + return '?'; + } + if (pfound != NULL) + { + option_index = indfound; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (opterr) + fprintf (stderr, _("\ +%s: option `-W %s' doesn't allow an argument\n"), + argv[0], pfound->name); + + nextchar += strlen (nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + nextchar = NULL; + return 'W'; /* Let the application handle it. */ + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = NULL; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, + _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +getopt (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); +} + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == -1) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ +#endif /* _MSC_VER */ \ No newline at end of file diff --git a/contrib/msc/getopt1.c b/contrib/msc/getopt1.c new file mode 100644 index 000000000..b9c2bc0bc --- /dev/null +++ b/contrib/msc/getopt1.c @@ -0,0 +1,190 @@ +#ifdef _MSC_VER +/* getopt_long and getopt_long_only entry points for GNU getopt. + Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "getopt.h" + +#if !defined __STDC__ || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +#include +#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +#define ELIDE_CODE +#endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +#include +#endif + +#ifndef NULL +#define NULL 0 +#endif + +int +getopt_long (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 0); +} + +/* Like getopt_long, but '-' as well as '--' can indicate a long option. + If an option that starts with '-' (not '--') doesn't match a long option, + but does match a short option, it is parsed as a short option + instead. */ + +int +getopt_long_only (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 1); +} + + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +#include + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = + { + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 0, 0, 0}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "abc:d:0123456789", + long_options, &option_index); + if (c == -1) + break; + + switch (c) + { + case 0: + printf ("option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case 'd': + printf ("option d with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ +#endif /* _MSC_VER */ \ No newline at end of file diff --git a/contrib/msc/include/getopt.h b/contrib/msc/include/getopt.h new file mode 100644 index 000000000..66f9538f8 --- /dev/null +++ b/contrib/msc/include/getopt.h @@ -0,0 +1,157 @@ +#ifdef _MSC_VER +/* Declarations for getopt. + Copyright (C) 1989,90,91,92,93,94,96,97,98 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _GETOPT_H + +#ifndef __need_getopt +# define _GETOPT_H 1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; + +#ifndef __need_getopt +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ +# if defined __STDC__ && __STDC__ + const char *name; +# else + char *name; +# endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +# define no_argument 0 +# define required_argument 1 +# define optional_argument 2 +#endif /* need getopt */ + + +/* Get definitions and prototypes for functions to process the + arguments in ARGV (ARGC of them, minus the program name) for + options given in OPTS. + + Return the option character from OPTS just read. Return -1 when + there are no more options. For unrecognized options, or options + missing arguments, `optopt' is set to the option letter, and '?' is + returned. + + The OPTS string is a list of characters which are recognized option + letters, optionally followed by colons, specifying that that letter + takes an argument, to be placed in `optarg'. + + If a letter in OPTS is followed by two colons, its argument is + optional. This behavior is specific to the GNU `getopt'. + + The argument `--' causes premature termination of argument + scanning, explicitly telling `getopt' that there are no more + options. + + If OPTS begins with `--', then non-option arguments are treated as + arguments to the option '\0'. This behavior is specific to the GNU + `getopt'. */ + +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int __argc, char *const *__argv, const char *__shortopts); + +# ifndef __need_getopt +extern int getopt_long (int __argc, char *const *__argv, const char *__shortopts, + const struct option *__longopts, int *__longind); +extern int getopt_long_only (int __argc, char *const *__argv, + const char *__shortopts, + const struct option *__longopts, int *__longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (int __argc, char *const *__argv, + const char *__shortopts, + const struct option *__longopts, int *__longind, + int __long_only); +# endif + +#ifdef __cplusplus +} +#endif + +/* Make sure we later can get all the definitions and declarations. */ +#undef __need_getopt + +#endif /* getopt.h */ +#endif /* _MSC_VER */ \ No newline at end of file diff --git a/daemon/dns.cpp b/daemon/dns.cpp index c9c97dc7a..333931f87 100644 --- a/daemon/dns.cpp +++ b/daemon/dns.cpp @@ -1,7 +1,9 @@ #include #include #include /* fprintf, printf */ +#ifndef _MSC_VER #include +#endif #include #include @@ -13,6 +15,16 @@ #include // for multithreaded version #include +// keep this once jeff reenables concurrency +#ifdef _MSC_VER +extern "C" void +SetThreadName(DWORD dwThreadID, LPCSTR szThreadName); +#endif + +#ifdef _WIN32 +#define uint UINT +#endif + #if(__FreeBSD__) || (__OpenBSD__) || (__NetBSD__) #include #endif @@ -122,6 +134,7 @@ main(int argc, char *argv[]) logic = llarp_init_single_process_logic(worker); llarp_ev_loop_run_single_process(netloop, worker, logic); llarp::LogInfo("singlethread end"); + llarp_ev_loop_free(&netloop); } else @@ -150,7 +163,11 @@ main(int argc, char *argv[]) struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 100 * 1000; // 1 sec +#ifndef _WIN32 if(setsockopt(m_sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) +#else + if(setsockopt(m_sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv)) < 0) +#endif { perror("Error"); } diff --git a/daemon/main.cpp b/daemon/main.cpp index b424ab0ff..36c63acc3 100644 --- a/daemon/main.cpp +++ b/daemon/main.cpp @@ -3,6 +3,11 @@ #include #include +#ifdef _WIN32 +#define wmin(x, y) (((x) < (y)) ? (x) : (y)) +#define MIN wmin +#endif + struct llarp_main *ctx = 0; void diff --git a/daemon/rcutil.cpp b/daemon/rcutil.cpp index faaf0530b..6a57c7a94 100644 --- a/daemon/rcutil.cpp +++ b/daemon/rcutil.cpp @@ -1,8 +1,8 @@ +#include #include #include #include "logger.hpp" -#include #include #include @@ -278,14 +278,23 @@ main(int argc, char *argv[]) // "encryption.key") fs::path encryption_keyfile = "encryption.key"; llarp::SecretKey encryption; - llarp_findOrCreateEncryption(&crypt, encryption_keyfile.c_str(), +#ifdef _WIN32 + llarp_findOrCreateEncryption(&crypt, encryption_keyfile.string().c_str(), &encryption); +#else + llarp_findOrCreateEncryption(&crypt, encryption_keyfile.c_str(), + &encryption); +#endif llarp_rc_set_pubenckey(&tmp, llarp::seckey_topublic(encryption)); // get identity public sig key fs::path ident_keyfile = "identity.key"; byte_t identity[SECKEYSIZE]; +#ifdef _WIN32 + llarp_findOrCreateIdentity(&crypt, ident_keyfile.string().c_str(), identity); +#else llarp_findOrCreateIdentity(&crypt, ident_keyfile.c_str(), identity); +#endif llarp_rc_set_pubsigkey(&tmp, llarp::seckey_topublic(identity)); // this causes a segfault @@ -293,7 +302,11 @@ main(int argc, char *argv[]) // set filename fs::path our_rc_file = rcfname; // write file +#ifdef _WIN32 + llarp_rc_write(&tmp, our_rc_file.string().c_str()); +#else llarp_rc_write(&tmp, our_rc_file.c_str()); +#endif // release memory for tmp lists llarp_rc_free(&tmp); } @@ -311,7 +324,11 @@ main(int argc, char *argv[]) llarp_crypto_libsodium_init(&crypt); fs::path ident_keyfile = "identity.key"; byte_t identity[SECKEYSIZE]; +#ifdef _WIN32 + llarp_findOrCreateIdentity(&crypt, ident_keyfile.string().c_str(), identity); +#else llarp_findOrCreateIdentity(&crypt, ident_keyfile.c_str(), identity); +#endif // get identity public key uint8_t *pubkey = llarp::seckey_topublic(identity); llarp_rc_set_pubsigkey(&rc, pubkey); @@ -320,7 +337,11 @@ main(int argc, char *argv[]) // set filename fs::path our_rc_file_out = "update_debug.rc"; // write file +#ifdef _WIN32 + llarp_rc_write(&tmp, our_rc_file_out.string().c_str()); +#else llarp_rc_write(&tmp, our_rc_file_out.c_str()); +#endif } if(listMode) { diff --git a/include/llarp/codel.hpp b/include/llarp/codel.hpp index c3545632e..0c1520324 100644 --- a/include/llarp/codel.hpp +++ b/include/llarp/codel.hpp @@ -1,9 +1,13 @@ #ifndef LLARP_CODEL_QUEUE_HPP #define LLARP_CODEL_QUEUE_HPP +#ifdef _MSC_VER +#define NOMINMAX +#endif #include #include #include +#include #include #include diff --git a/include/llarp/dns.h b/include/llarp/dns.h index 2da74166a..232b2ce09 100644 --- a/include/llarp/dns.h +++ b/include/llarp/dns.h @@ -5,6 +5,11 @@ #include // for uint & ssize_t #include // for udp DNS tracker +/* non-cygnus does not have this type */ +#ifdef _WIN32 +#define uint UINT +#endif + #ifdef __cplusplus extern "C" { diff --git a/include/llarp/endian.h b/include/llarp/endian.h index a1036a7e6..8e33bbd62 100644 --- a/include/llarp/endian.h +++ b/include/llarp/endian.h @@ -6,15 +6,12 @@ #include #include -#if defined(__FreeBSD__) || defined(__NetBSD__) +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) #include -#elif defined(__linux__) || defined(__FreeBSD_kernel__) \ - || defined(__OpenBSD__) || defined(__GLIBC__) +#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__GLIBC__) #include #elif defined(__APPLE__) && defined(__MACH__) - #include - #define htobe16(x) OSSwapHostToBigInt16(x) #define htole16(x) OSSwapHostToLittleInt16(x) #define be16toh(x) OSSwapBigToHostInt16(x) @@ -29,7 +26,26 @@ #define htole64(x) OSSwapHostToLittleInt64(x) #define be64toh(x) OSSwapBigToHostInt64(x) #define le64toh(x) OSSwapLittleToHostInt64(x) - +#elif defined(_WIN32) +#include +#define htobe16(x) htons(x) +#define htole16(x) (x) +#define be16toh(x) ntohs(x) +#define le16toh(x) (x) + +#define htobe32(x) htonl(x) +#define htole32(x) (x) +#define be32toh(x) ntohl(x) +#define le32toh(x) (x) + +#define htobe64(x) \ + (((uint64_t)htonl(((uint32_t)(((uint64_t)(x)) >> 32)))) \ + | (((uint64_t)htonl(((uint32_t)(x)))) << 32)) +#define htole64(x) (x) +#define be64toh(x) \ + (((uint64_t)ntohl(((uint32_t)(((uint64_t)(x)) >> 32)))) \ + | (((uint64_t)ntohl(((uint32_t)(x)))) << 32)) +#define le64toh(x) (x) #else #define NEEDS_LOCAL_ENDIAN #include diff --git a/include/llarp/ev.h b/include/llarp/ev.h index 6b086789c..544b8faaa 100644 --- a/include/llarp/ev.h +++ b/include/llarp/ev.h @@ -1,8 +1,12 @@ #ifndef LLARP_EV_H #define LLARP_EV_H -#if defined(__MINGW32__) +#if defined(__MINGW32__) || defined(_WIN32) #include #include +#include +#ifndef ssize_t +#define ssize_t long +#endif #else #include #include @@ -12,10 +16,10 @@ #include /** - * ev.h - * - * event handler (cross platform high performance event system for IO) - */ + * ev.h + * + * event handler (cross platform high performance event system for IO) + */ // forward declare struct llarp_threadpool; diff --git a/include/llarp/logger.hpp b/include/llarp/logger.hpp index 2cf46fc61..5084f85e7 100644 --- a/include/llarp/logger.hpp +++ b/include/llarp/logger.hpp @@ -1,6 +1,5 @@ #ifndef LLARP_LOGGER_HPP #define LLARP_LOGGER_HPP - #include #include #include @@ -8,6 +7,11 @@ #include #include #include +#ifdef _WIN32 +#define VC_EXTRALEAN +#define WIN32_LEAN_AND_MEAN +#include +#endif namespace llarp { @@ -28,6 +32,14 @@ namespace llarp std::mutex access; Logger() : Logger(std::cout, "unnamed") { +#ifdef _WIN32 + DWORD mode_flags; + HANDLE fd1 = GetStdHandle(STD_OUTPUT_HANDLE); + GetConsoleMode(fd1, &mode_flags); + // since release SDKs don't have ANSI escape support yet + mode_flags |= 0x0004; + SetConsoleMode(fd1, mode_flags); +#endif } Logger(std::ostream& o, const std::string& name) : nodeName(name), out(o) @@ -108,7 +120,6 @@ namespace llarp _Log(llarp::eLogWarn, LOG_TAG, __LINE__, x, ##__VA_ARGS__) #define LogError(x, ...) \ _Log(llarp::eLogError, LOG_TAG, __LINE__, x, ##__VA_ARGS__) - #define LogDebugTag(tag, x, ...) \ _Log(llarp::eLogDebug, tag, __LINE__, x, ##__VA_ARGS__) #define LogInfoTag(tag, x, ...) \ @@ -121,5 +132,4 @@ namespace llarp #ifndef LOG_TAG #define LOG_TAG "default" #endif - #endif diff --git a/include/llarp/net.h b/include/llarp/net.h index d5cfd7d64..255a72bcf 100644 --- a/include/llarp/net.h +++ b/include/llarp/net.h @@ -1,8 +1,27 @@ #ifndef LLARP_NET_H #define LLARP_NET_H -#if defined(__MINGW32__) +#if defined(_WIN32) || defined(__MINGW32__) #include #include +#include +// because this shit is not defined for Windows NT reeeee +#ifndef _MSC_VER +#ifdef __cplusplus +extern "C" { +#endif +const char* +inet_ntop(int af, const void* src, char* dst, size_t size); +int +inet_pton(int af, const char* src, void* dst); +#ifdef __cplusplus +} +#endif +#endif +#ifndef ssize_t +#define ssize_t long +#endif +typedef unsigned short in_port_t; +typedef unsigned int in_addr_t; #else #include #include diff --git a/include/llarp/net.hpp b/include/llarp/net.hpp index 2014a8a8c..5c8549525 100644 --- a/include/llarp/net.hpp +++ b/include/llarp/net.hpp @@ -121,7 +121,11 @@ namespace llarp sz = sizeof(sockaddr_in); ptr = a.addr4(); } +#ifndef _MSC_VER if(inet_ntop(a.af(), ptr, tmp, sz)) +#else + if(inet_ntop(a.af(), (void*)ptr, tmp,sz)) +#endif { out << tmp; if(a.af() == AF_INET6) @@ -148,22 +152,22 @@ namespace llarp switch(af()) { case AF_INET: - dst = (void*)&((sockaddr_in*)other)->sin_addr.s_addr; - src = (void*)&_addr.sin6_addr.s6_addr[12]; - ptr = &((sockaddr_in*)other)->sin_port; + dst = (void*)&((sockaddr_in*)other)->sin_addr.s_addr; + src = (void*)&_addr.sin6_addr.s6_addr[12]; + ptr = &((sockaddr_in*)other)->sin_port; slen = sizeof(in_addr); break; case AF_INET6: - dst = (void*)((sockaddr_in6*)other)->sin6_addr.s6_addr; - src = (void*)_addr.sin6_addr.s6_addr; - ptr = &((sockaddr_in6*)other)->sin6_port; + dst = (void*)((sockaddr_in6*)other)->sin6_addr.s6_addr; + src = (void*)_addr.sin6_addr.s6_addr; + ptr = &((sockaddr_in6*)other)->sin6_port; slen = sizeof(in6_addr); break; default: return; } memcpy(dst, src, slen); - *ptr = htons(port()); + *ptr = htons(port()); other->sa_family = af(); } @@ -216,7 +220,7 @@ namespace llarp isPrivate() { in_addr_t addr = this->addr4()->s_addr; - unsigned byte = ntohl(addr); + unsigned byte = ntohl(addr); unsigned byte1 = byte >> 24 & 0xff; unsigned byte2 = (0x00ff0000 & byte >> 16); return (byte1 == 10 || (byte1 == 192 && byte2 == 168) diff --git a/include/llarp/threading.hpp b/include/llarp/threading.hpp index b7158916b..60515c1b9 100644 --- a/include/llarp/threading.hpp +++ b/include/llarp/threading.hpp @@ -1,7 +1,7 @@ #ifndef LLARP_THREADING_HPP #define LLARP_THREADING_HPP #include -#if defined(__MINGW32__) +#if defined(__MINGW32__) && !defined(_GLIBCXX_HAS_GTHREADS) #include #include #include diff --git a/llarp/address_info.cpp b/llarp/address_info.cpp index 621e1a6eb..cecabd2bf 100644 --- a/llarp/address_info.cpp +++ b/llarp/address_info.cpp @@ -1,5 +1,7 @@ #include "address_info.hpp" +#ifndef _WIN32 #include +#endif #include #include #include @@ -120,8 +122,12 @@ llarp_ai_list_iter_bencode(struct llarp_ai_list_iter *iter, struct llarp_ai *ai) bool llarp_ai_bdecode(struct llarp_ai *ai, llarp_buffer_t *buff) { +#ifndef _MSC_VER struct dict_reader reader = { .buffer = nullptr, .user = ai, .on_key = &llarp_ai_decode_key}; +#else + struct dict_reader reader = { nullptr, ai, &llarp_ai_decode_key }; +#endif return bencode_read_dict(buff, &reader); } @@ -174,8 +180,13 @@ llarp_ai_list_bencode(struct llarp_ai_list *l, llarp_buffer_t *buff) { if(!bencode_start_list(buff)) return false; +#ifndef _MSC_VER struct llarp_ai_list_iter ai_itr = { .user = buff, .list = nullptr, .visit = &llarp_ai_list_iter_bencode}; +#else + struct llarp_ai_list_iter ai_itr = {buff, nullptr, + &llarp_ai_list_iter_bencode}; +#endif llarp_ai_list_iterate(l, &ai_itr); return bencode_end(buff); } @@ -255,7 +266,12 @@ llarp_ai_list_index(struct llarp_ai_list *l, ssize_t idx, struct llarp_ai *dst) bool llarp_ai_list_bdecode(struct llarp_ai_list *l, llarp_buffer_t *buff) { +#ifndef _MSC_VER struct list_reader r = { .buffer = nullptr, .user = l, .on_item = &llarp_ai_list_bdecode_item}; +#else + struct list_reader r = { + nullptr, l, &llarp_ai_list_bdecode_item}; +#endif return bencode_read_list(buff, &r); } diff --git a/llarp/buffer.cpp b/llarp/buffer.cpp index 411306e30..09e60a51f 100644 --- a/llarp/buffer.cpp +++ b/llarp/buffer.cpp @@ -3,6 +3,9 @@ #include #include +#ifndef ssize_t +#define ssize_t long +#endif size_t llarp_buffer_size_left(llarp_buffer_t buff) { diff --git a/llarp/context.cpp b/llarp/context.cpp index faf1a2518..7a979dc46 100644 --- a/llarp/context.cpp +++ b/llarp/context.cpp @@ -2,7 +2,9 @@ #include #include #include +#ifndef _MSC_VER #include // for MIN +#endif #include #include "logger.hpp" #include "math.h" @@ -12,6 +14,16 @@ #include #endif +// keep this once jeff reenables concurrency +#ifdef _MSC_VER +extern "C" void +SetThreadName(DWORD dwThreadID, LPCSTR szThreadName); +#endif + +#ifdef _WIN32 +#define wmin(x, y) (((x) < (y)) ? (x) : (y)) +#define MIN wmin +#endif namespace llarp { @@ -188,6 +200,7 @@ namespace llarp } else { + llarp::LogInfo("running mainloop"); return llarp_ev_loop_run(mainloop, logic); } @@ -202,11 +215,14 @@ namespace llarp llarp::LogInfo("SIGINT"); SigINT(); } + // TODO(despair): implement hot-reloading config on NT +#ifndef _WIN32 if(sig == SIGHUP) { llarp::LogInfo("SIGHUP"); ReloadConfig(); } +#endif } void @@ -289,194 +305,194 @@ extern "C" struct llarp_main * llarp_main_init(const char *fname, bool multiProcess) { - if(!fname) - fname = "daemon.ini"; - char *var = getenv("LLARP_DEBUG"); - if(var && *var == '1') - { - cSetLogLevel(eLogDebug); - } - llarp_main *m = new llarp_main; - m->ctx.reset(new llarp::Context()); - m->ctx->singleThreaded = !multiProcess; - if(!m->ctx->LoadConfig(fname)) - { - m->ctx->Close(); - delete m; - return nullptr; - } - return m; + if(!fname) + fname = "daemon.ini"; + char *var = getenv("LLARP_DEBUG"); + if(var && *var == '1') + { + cSetLogLevel(eLogDebug); + } + llarp_main *m = new llarp_main; + m->ctx.reset(new llarp::Context()); + m->ctx->singleThreaded = !multiProcess; + if(!m->ctx->LoadConfig(fname)) + { + m->ctx->Close(); + delete m; + return nullptr; + } + return m; } void llarp_main_signal(struct llarp_main *ptr, int sig) { - ptr->ctx->HandleSignal(sig); + ptr->ctx->HandleSignal(sig); } int llarp_main_setup(struct llarp_main *ptr) { - return ptr->ctx->Setup(); + return ptr->ctx->Setup(); } int llarp_main_run(struct llarp_main *ptr) { - return ptr->ctx->Run(); + return ptr->ctx->Run(); } void llarp_main_abort(struct llarp_main *ptr) { - llarp_logic_stop_timer(ptr->ctx->router->logic); + llarp_logic_stop_timer(ptr->ctx->router->logic); } int llarp_main_loadDatabase(struct llarp_main *ptr) { - return ptr->ctx->LoadDatabase(); + return ptr->ctx->LoadDatabase(); } int llarp_main_iterateDatabase(struct llarp_main *ptr, struct llarp_nodedb_iter i) { - return ptr->ctx->IterateDatabase(i); + return ptr->ctx->IterateDatabase(i); } bool llarp_main_putDatabase(struct llarp_main *ptr, struct llarp_rc *rc) { - return ptr->ctx->PutDatabase(rc); + return ptr->ctx->PutDatabase(rc); } struct llarp_rc * llarp_main_getDatabase(struct llarp_main *ptr, byte_t *pk) { - return ptr->ctx->GetDatabase(pk); + return ptr->ctx->GetDatabase(pk); } struct llarp_rc * llarp_main_getLocalRC(struct llarp_main *ptr) { - // - /* - llarp_config_iterator iter; - iter.user = this; - iter.visit = &iter_config; - llarp_config_iter(ctx->config, &iter); - */ - llarp_rc *rc = new llarp_rc; - llarp_rc_new(rc); - llarp::LogInfo("Loading ", ptr->ctx->conatctFile); - if(llarp_rc_read(ptr->ctx->conatctFile, rc)) - return rc; - else - return nullptr; + // + /* + llarp_config_iterator iter; + iter.user = this; + iter.visit = &iter_config; + llarp_config_iter(ctx->config, &iter); + */ + llarp_rc *rc = new llarp_rc; + llarp_rc_new(rc); + llarp::LogInfo("Loading ", ptr->ctx->conatctFile); + if(llarp_rc_read(ptr->ctx->conatctFile, rc)) + return rc; + else + return nullptr; } void llarp_main_checkOnline(void *u, uint64_t orig, uint64_t left) { - // llarp::LogInfo("checkOnline - check ", left); - if(left) - return; - struct check_online_request *request = - static_cast< struct check_online_request * >(u); - // llarp::LogDebug("checkOnline - running"); - // llarp::LogInfo("checkOnline - DHT nodes ", - // request->ptr->ctx->router->dht->impl.nodes->nodes.size()); - request->online = false; - request->nodes = request->ptr->ctx->router->dht->impl.nodes->nodes.size(); - if(request->ptr->ctx->router->dht->impl.nodes->nodes.size()) - { - // llarp::LogInfo("checkOnline - Going to say we're online"); - request->online = true; - } - request->hook(request); - // reschedue our self - llarp_main_queryDHT(request); + // llarp::LogInfo("checkOnline - check ", left); + if(left) + return; + struct check_online_request *request = + static_cast< struct check_online_request * >(u); + // llarp::LogDebug("checkOnline - running"); + // llarp::LogInfo("checkOnline - DHT nodes ", + // request->ptr->ctx->router->dht->impl.nodes->nodes.size()); + request->online = false; + request->nodes = request->ptr->ctx->router->dht->impl.nodes->nodes.size(); + if(request->ptr->ctx->router->dht->impl.nodes->nodes.size()) + { + // llarp::LogInfo("checkOnline - Going to say we're online"); + request->online = true; + } + request->hook(request); + // reschedue our self + llarp_main_queryDHT(request); } void llarp_main_queryDHT_online(struct check_online_request *request) { - // Info("llarp_main_queryDHT_online: ", request->online ? "online" : - // "offline"); - if(request->online && !request->first) - { - request->first = true; - llarp::LogInfo("llarp_main_queryDHT_online - We're online"); - llarp::LogInfo("llarp_main_queryDHT_online - Querying DHT"); - llarp_dht_lookup_router(request->ptr->ctx->router->dht, request->job); - } + // Info("llarp_main_queryDHT_online: ", request->online ? "online" : + // "offline"); + if(request->online && !request->first) + { + request->first = true; + llarp::LogInfo("llarp_main_queryDHT_online - We're online"); + llarp::LogInfo("llarp_main_queryDHT_online - Querying DHT"); + llarp_dht_lookup_router(request->ptr->ctx->router->dht, request->job); + } } void llarp_main_queryDHT(struct check_online_request *request) { - // llarp::LogInfo("llarp_main_queryDHT - setting up timer"); - request->hook = &llarp_main_queryDHT_online; - llarp_logic_call_later(request->ptr->ctx->router->logic, - {1000, request, &llarp_main_checkOnline}); - // llarp_dht_lookup_router(ptr->ctx->router->dht, job); + // llarp::LogInfo("llarp_main_queryDHT - setting up timer"); + request->hook = &llarp_main_queryDHT_online; + llarp_logic_call_later(request->ptr->ctx->router->logic, + {1000, request, &llarp_main_checkOnline}); + // llarp_dht_lookup_router(ptr->ctx->router->dht, job); } void llarp_main_free(struct llarp_main *ptr) { - delete ptr; + delete ptr; } const char * handleBaseCmdLineArgs(int argc, char *argv[]) { - const char *conffname = "daemon.ini"; - int c; - while(1) + const char *conffname = "daemon.ini"; + int c; + while(1) + { + static struct option long_options[] = { + {"config", required_argument, 0, 'c'}, + {"logLevel", required_argument, 0, 'o'}, + {0, 0, 0, 0}}; + int option_index = 0; + c = getopt_long(argc, argv, "c:o:", long_options, &option_index); + if(c == -1) + break; + switch(c) { - static struct option long_options[] = { - {"config", required_argument, 0, 'c'}, - {"logLevel", required_argument, 0, 'o'}, - {0, 0, 0, 0}}; - int option_index = 0; - c = getopt_long(argc, argv, "c:o:", long_options, &option_index); - if(c == -1) + case 0: break; - switch(c) - { - case 0: - break; - case 'c': - conffname = optarg; - break; - case 'o': + case 'c': + conffname = optarg; + break; + case 'o': if(strncmp(optarg, "debug", MIN(strlen(optarg), (unsigned long)5)) == 0) - { - cSetLogLevel(eLogDebug); - } - else if(strncmp(optarg, "info", MIN(strlen(optarg), (unsigned long)4)) - == 0) - { - cSetLogLevel(eLogInfo); - } - else if(strncmp(optarg, "warn", MIN(strlen(optarg), (unsigned long)4)) - == 0) - { - cSetLogLevel(eLogWarn); - } + { + cSetLogLevel(eLogDebug); + } + else if(strncmp(optarg, "info", MIN(strlen(optarg), (unsigned long)4)) + == 0) + { + cSetLogLevel(eLogInfo); + } + else if(strncmp(optarg, "warn", MIN(strlen(optarg), (unsigned long)4)) + == 0) + { + cSetLogLevel(eLogWarn); + } else if(strncmp(optarg, "error", MIN(strlen(optarg), (unsigned long)5)) - == 0) - { - cSetLogLevel(eLogError); - } - break; - default: - break; - } + == 0) + { + cSetLogLevel(eLogError); + } + break; + default: + break; } - return conffname; + } + return conffname; } } diff --git a/llarp/crypto_libsodium.cpp b/llarp/crypto_libsodium.cpp index d1ee26046..3e6f51935 100644 --- a/llarp/crypto_libsodium.cpp +++ b/llarp/crypto_libsodium.cpp @@ -26,7 +26,7 @@ namespace llarp if(crypto_scalarmult_curve25519(shared, usSec, themPub)) return false; - crypto_generichash_init(&h, NULL, 0U, outsz); + crypto_generichash_init(&h, nullptr, 0U, outsz); crypto_generichash_update(&h, client_pk, 32); crypto_generichash_update(&h, server_pk, 32); crypto_generichash_update(&h, shared, 32); diff --git a/llarp/dns.cpp b/llarp/dns.cpp index 32c1c1533..2c3ccbd4e 100644 --- a/llarp/dns.cpp +++ b/llarp/dns.cpp @@ -2,6 +2,10 @@ #include "dnsd.hpp" // for llarp_handle_dnsd_recvfrom, dnsc #include "logger.hpp" +#ifdef _WIN32 +#define uint UINT +#endif + extern "C" { uint16_t diff --git a/llarp/dnsc.cpp b/llarp/dnsc.cpp index bad453583..b695d3648 100644 --- a/llarp/dnsc.cpp +++ b/llarp/dnsc.cpp @@ -2,15 +2,19 @@ #include #include "buffer.hpp" -#include /* getaddrinfo, getnameinfo */ +#ifndef _WIN32 +#include +#include /* getaddrinfo, getnameinfo */ +#include +#include +#endif + #include /* exit */ #include /* memset */ -#include #include +#ifndef _MSC_VER #include /* close */ - -#include -#include +#endif #include @@ -75,7 +79,7 @@ build_dns_packet(char *url, uint16_t id, uint16_t reqType) { dnsQuery->request[dnsQuery->length++] = word[i]; } - word = strtok(NULL, "."); + word = strtok(nullptr, "."); } dnsQuery->request[dnsQuery->length++] = 0x00; // End of the host name @@ -130,7 +134,7 @@ raw_resolve_host(const char *url) { dnsQuery.request[dnsQuery.length++] = word[i]; } - word = strtok(NULL, "."); + word = strtok(nullptr, "."); } dnsQuery.request[dnsQuery.length++] = 0x00; // End of the host name @@ -162,7 +166,11 @@ raw_resolve_host(const char *url) // uint16_t RDLENGTH; // The length of the RDATA field // uint16_t MSGID; +#ifndef _WIN32 int sockfd; +#else + SOCKET sockfd; +#endif sockfd = socket(AF_INET, SOCK_DGRAM, 0); if(sockfd < 0) @@ -179,8 +187,13 @@ raw_resolve_host(const char *url) size = sizeof(addr); // hexdump("sending packet", &dnsQuery.request, dnsQuery.length); +#ifdef _WIN32 + ret = sendto(sockfd, (const char *)dns_packet->request, dns_packet->length, 0, + (struct sockaddr *)&addr, size); +#else ret = sendto(sockfd, dns_packet->request, dns_packet->length, 0, (struct sockaddr *)&addr, size); +#endif delete dns_packet; if(ret < 0) { @@ -190,8 +203,13 @@ raw_resolve_host(const char *url) // llarp::LogInfo("Sent\n"); memset(&buffer, 0, DNC_BUF_SIZE); - ret = recvfrom(sockfd, buffer, DNC_BUF_SIZE, 0, (struct sockaddr *)&addr, - &size); +#ifdef _WIN32 + ret = recvfrom(sockfd, (char *)buffer, DNC_BUF_SIZE, 0, + (struct sockaddr *)&addr, &size); +#else + ret = recvfrom(sockfd, buffer, DNC_BUF_SIZE, 0, + (struct sockaddr *)&addr, &size); +#endif if(ret < 0) { llarp::LogWarn("Error Receiving Response"); @@ -200,7 +218,11 @@ raw_resolve_host(const char *url) // hexdump("received packet", &buffer, ret); +#ifndef _WIN32 close(sockfd); +#else + closesocket(sockfd); +#endif rcode = (buffer[3] & 0x0F); @@ -210,7 +232,7 @@ raw_resolve_host(const char *url) // printf("%0x %0x %0x %0x\n", buffer[4], buffer[5], tempBuf[0], tempBuf[1]); - // QDCOUNT = (uint16_t) strtol(tempBuf, NULL, 16); + // QDCOUNT = (uint16_t) strtol(tempBuf, nullptr, 16); QDCOUNT = (uint16_t)buffer[4] * 0x100 + buffer[5]; llarp::LogDebug("entries in question section: %u\n", QDCOUNT); ANCOUNT = (uint16_t)buffer[6] * 0x100 + buffer[7]; diff --git a/llarp/dnsd.cpp b/llarp/dnsd.cpp index 5e128a72d..fb39adec9 100644 --- a/llarp/dnsd.cpp +++ b/llarp/dnsd.cpp @@ -5,6 +5,11 @@ #include "llarp/net.hpp" #include "logger.hpp" +#ifdef _WIN32 +#define wmin(x, y) (((x) < (y)) ? (x) : (y)) +#define MIN wmin +#endif + dns_tracker dns_udp_tracker; ssize_t @@ -14,7 +19,11 @@ raw_sendto_dns_hook_func(void *sock, const struct sockaddr *from, int *fd = (int *)sock; // how do we get to these?? socklen_t addrLen = sizeof(struct sockaddr_in); +#ifdef _WIN32 + return sendto(*fd, (const char *)buffer, length, 0, from, addrLen); +#else return sendto(*fd, buffer, length, 0, from, addrLen); +#endif } ssize_t diff --git a/llarp/ev.cpp b/llarp/ev.cpp index 5599a36de..7b9957233 100644 --- a/llarp/ev.cpp +++ b/llarp/ev.cpp @@ -5,11 +5,11 @@ #ifdef __linux__ #include "ev_epoll.hpp" #endif -#if(__APPLE__ && __MACH__) +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || (__APPLE__ && __MACH__) #include "ev_kqueue.hpp" #endif -#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) -#include "ev_kqueue.hpp" +#if defined(_WIN32) || defined(_WIN64) || defined(__NT__) +#include "ev_win32.hpp" #endif void @@ -18,11 +18,17 @@ llarp_ev_loop_alloc(struct llarp_ev_loop **ev) #ifdef __linux__ *ev = new llarp_epoll_loop; #endif -#if(__APPLE__ && __MACH__) +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || (__APPLE__ && __MACH__) *ev = new llarp_kqueue_loop; #endif -#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) - *ev = new llarp_kqueue_loop; +#if defined(_WIN32) || defined(_WIN64) || defined(__NT__) + *ev = new llarp_win32_loop; +#endif + // a) I assume that the libre fork of Solaris is still + // 5.10, and b) the current commercial version is 5.11, naturally. + // -despair86 +#if defined(__SunOS_5_10) || defined(__SunOS_5_11) + *ev = new llarp_sun_iocp_loop; #endif (*ev)->init(); } diff --git a/llarp/ev.hpp b/llarp/ev.hpp index 6beba78bb..8a421fc8c 100644 --- a/llarp/ev.hpp +++ b/llarp/ev.hpp @@ -2,15 +2,22 @@ #define LLARP_EV_HPP #include +#ifndef _MSC_VER #include +#endif #include namespace llarp { struct ev_io { +#ifndef _WIN32 int fd; ev_io(int f) : fd(f){}; +#else + SOCKET fd; + ev_io(SOCKET f) : fd(f){}; +#endif virtual int read(void* buf, size_t sz) = 0; @@ -18,7 +25,11 @@ namespace llarp sendto(const sockaddr* dst, const void* data, size_t sz) = 0; virtual ~ev_io() { +#ifndef _WIN32 ::close(fd); +#else + closesocket(fd); +#endif }; }; }; // namespace llarp diff --git a/llarp/ev_kqueue.hpp b/llarp/ev_kqueue.hpp index 0b504db1b..6c7473757 100644 --- a/llarp/ev_kqueue.hpp +++ b/llarp/ev_kqueue.hpp @@ -3,13 +3,7 @@ #include #include -#if __FreeBSD__ || __OpenBSD__ || __NetBSD__ -// kqueue / kevent -#include -#include -#endif - -#if(__APPLE__ && __MACH__) +#if __FreeBSD__ || __OpenBSD__ || __NetBSD__ || (__APPLE && __MACH__) // kqueue / kevent #include #include @@ -111,7 +105,7 @@ struct llarp_kqueue_loop : public llarp_ev_loop struct kevent events[1024]; int result; byte_t readbuf[2048]; - result = kevent(kqueuefd, NULL, 0, events, 1024, NULL); + result = kevent(kqueuefd, nullptr, 0, events, 1024, nullptr); // result: 0 is a timeout if(result > 0) { @@ -145,7 +139,7 @@ struct llarp_kqueue_loop : public llarp_ev_loop byte_t readbuf[2048]; do { - result = kevent(kqueuefd, NULL, 0, events, 1024, NULL); + result = kevent(kqueuefd, nullptr, 0, events, 1024, nullptr); // result: 0 is a timeout if(result > 0) { @@ -241,9 +235,8 @@ struct llarp_kqueue_loop : public llarp_ev_loop bool close_ev(llarp::ev_io* ev) { - // printf("closing_ev [%x] fd[%d]\n", ev, ev->fd); - EV_SET(&change, ev->fd, EVFILT_READ, EV_DELETE, 0, 0, NULL); - return kevent(kqueuefd, &change, 1, NULL, 0, NULL) == -1; + EV_SET(&change, ev->fd, EVFILT_READ, EV_DELETE, 0, 0, nullptr); + return kevent(kqueuefd, &change, 1, nullptr, 0, nullptr) == -1; } bool @@ -255,7 +248,7 @@ struct llarp_kqueue_loop : public llarp_ev_loop llarp::udp_listener* listener = new llarp::udp_listener(fd, l); EV_SET(&change, fd, EVFILT_READ, EV_ADD, 0, 0, listener); - if(kevent(kqueuefd, &change, 1, NULL, 0, NULL) == -1) + if(kevent(kqueuefd, &change, 1, nullptr, 0, nullptr) == -1) { l->impl = nullptr; delete listener; diff --git a/llarp/ev_win32.hpp b/llarp/ev_win32.hpp new file mode 100644 index 000000000..f0c4fb26d --- /dev/null +++ b/llarp/ev_win32.hpp @@ -0,0 +1,214 @@ +#ifndef EV_WIN32_HPP +#define EV_WIN32_HPP +#include +#include +#include +#include +#include "ev.hpp" +#include "logger.hpp" +#include + +namespace llarp +{ + struct udp_listener : public ev_io + { + llarp_udp_io* udp; + + // we receive queued data in the OVERLAPPED data field, + // much like the pipefds in the UNIX kqueue and loonix + // epoll handles + // 0 is the read port, 1 is the write port + WSAOVERLAPPED portfds[2] = {0}; + + udp_listener(SOCKET fd, llarp_udp_io* u) : ev_io(fd), udp(u){}; + + ~udp_listener() + { + } + + virtual int + read(void* buf, size_t sz) + { + sockaddr_in6 src; + socklen_t slen = sizeof(sockaddr_in6); + sockaddr* addr = (sockaddr*)&src; + WSABUF wbuf = {sz, static_cast< char* >(buf)}; + // WSARecvFrom + int ret = + ::WSARecvFrom(fd, &wbuf, sz, nullptr, 0, addr, &slen, &portfds[0], nullptr); + if(ret == -1) + return -1; + udp->recvfrom(udp, addr, buf, ret); + return 0; + } + + virtual int + sendto(const sockaddr* to, const void* data, size_t sz) + { + socklen_t slen; + WSABUF wbuf = {sz, (char*)data}; + switch(to->sa_family) + { + case AF_INET: + slen = sizeof(struct sockaddr_in); + break; + case AF_INET6: + slen = sizeof(struct sockaddr_in6); + break; + default: + return -1; + } + // WSASendTo + ssize_t sent = + ::WSASendTo(fd, &wbuf, sz, nullptr, 0, to, slen, &portfds[1], nullptr); + if(sent == -1) + { + llarp::LogWarn(strerror(errno)); + } + return sent; + } + }; +}; // namespace llarp + +struct llarp_win32_loop : public llarp_ev_loop +{ + HANDLE iocpfd; + + llarp_win32_loop() : iocpfd(INVALID_HANDLE_VALUE) + { + WSADATA wsockd; + int err; + // So, what I was told last time was that we can defer + // loading winsock2 up to this point, as we reach this ctor + // early on during daemon startup. + err = ::WSAStartup(MAKEWORD(2, 2), &wsockd); + if(err) + perror("Failed to start Windows Sockets"); + } + + ~llarp_win32_loop() + { + if(iocpfd != INVALID_HANDLE_VALUE) + ::CloseHandle(iocpfd); + + ::WSACleanup(); + } + + bool + init() + { + if(iocpfd == INVALID_HANDLE_VALUE) + iocpfd = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 0); + + if(iocpfd != INVALID_HANDLE_VALUE) + return true; // we don't have a socket to attach to this IOCP yet + + return false; + } + + int + tick(int ms) + { + return 0; + } + + int + run() + { + return 0; + } + + SOCKET + udp_bind(const sockaddr* addr) + { + socklen_t slen; + switch(addr->sa_family) + { + case AF_INET: + slen = sizeof(struct sockaddr_in); + break; + case AF_INET6: + slen = sizeof(struct sockaddr_in6); + break; + default: + return INVALID_SOCKET; + } + SOCKET fd = ::WSASocket(addr->sa_family, SOCK_DGRAM, 0, nullptr, 0, + WSA_FLAG_OVERLAPPED); + if(fd == INVALID_SOCKET) + { + perror("WSASocket()"); + return -1; + } + + if(addr->sa_family == AF_INET6) + { + // enable dual stack explicitly + int dual = 1; + if(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&dual, sizeof(dual))== -1) + { + // failed + perror("setsockopt()"); + closesocket(fd); + return INVALID_SOCKET; + } + } + llarp::Addr a(*addr); + llarp::LogDebug("bind to ", a); + if(bind(fd, addr, slen) == -1) + { + perror("bind()"); + closesocket(fd); + return INVALID_SOCKET; + } + return fd; + } + + bool + close_ev(llarp::ev_io* ev) + { + // On Windows, just close the socket to decrease the iocp refcount + return closesocket(ev->fd) == 0; + } + + bool + udp_listen(llarp_udp_io* l, const sockaddr* src) + { + SOCKET fd = udp_bind(src); + if(fd == INVALID_SOCKET) + return false; + llarp::udp_listener* listener = new llarp::udp_listener(fd, l); + if(!::CreateIoCompletionPort(reinterpret_cast< HANDLE >(fd), iocpfd, 0, 0)) + { + delete listener; + return false; + } + l->impl = listener; + udp_listeners.push_back(l); + return true; + } + + bool + udp_close(llarp_udp_io* l) + { + bool ret = false; + llarp::udp_listener* listener = + static_cast< llarp::udp_listener* >(l->impl); + if(listener) + { + ret = close_ev(listener); + l->impl = nullptr; + delete listener; + udp_listeners.remove(l); + } + return ret; + } + + void + stop() + { + // do nothing, we dispose of the IOCP in destructor + } +}; + +#endif diff --git a/llarp/exit_info.cpp b/llarp/exit_info.cpp index 7983cdf9b..3d85b2f89 100644 --- a/llarp/exit_info.cpp +++ b/llarp/exit_info.cpp @@ -1,4 +1,7 @@ +#ifndef _WIN32 #include +#endif + #include #include #include diff --git a/llarp/exit_route.cpp b/llarp/exit_route.cpp index 013907359..94e89bf79 100644 --- a/llarp/exit_route.cpp +++ b/llarp/exit_route.cpp @@ -1,4 +1,7 @@ +#ifndef _WIN32 #include +#endif + #include #include #include diff --git a/llarp/fs.hpp b/llarp/fs.hpp index c6b998d63..ad6d06dd3 100644 --- a/llarp/fs.hpp +++ b/llarp/fs.hpp @@ -8,15 +8,20 @@ #endif #include "filesystem.h" - -// mingw32 in the only one that doesn't use cpp17::filesystem -#if defined(__MINGW32__) +#if defined(CPP17) && defined(USE_CXX17_FILESYSTEM) +// win32 is the only one that doesn't use cpp17::filesystem +// because cpp17::filesystem is unimplemented for Windows +// -despair86 +#if defined(__MINGW32__) || defined(_MSC_VER) namespace fs = std::experimental::filesystem; #else +namespace fs = std::filesystem; +#endif // end win32 +#else // not CPP17 needs this // openbsd needs this // linux gcc 7.2 needs this namespace fs = cpp17::filesystem; -#endif // end mingw32 +#endif #endif // end LLARP_FS_HPP diff --git a/llarp/ini.hpp b/llarp/ini.hpp index cb3c69710..60275420a 100644 --- a/llarp/ini.hpp +++ b/llarp/ini.hpp @@ -40,7 +40,7 @@ namespace ini { struct Level { - Level() : parent(NULL), depth(0) + Level() : parent(nullptr), depth(0) { } Level(Level *p) : parent(p), depth(0) @@ -156,7 +156,7 @@ namespace ini Parser::err(const char *s) { char buf[256]; - sprintf(buf, "%s on line #%ld", s, ln_); + sprintf(buf, "%s on line #%d", s, ln_); throw std::runtime_error(buf); } @@ -210,8 +210,7 @@ namespace ini size_t depth; std::string sname; parseSLine(sname, depth); - - Level *lp = NULL; + Level *lp = nullptr; Level *parent = &l; if(depth > l.depth + 1) err("section with wrong depth"); diff --git a/llarp/iwp/frame_state.cpp b/llarp/iwp/frame_state.cpp index 0a138bb97..303081576 100644 --- a/llarp/iwp/frame_state.cpp +++ b/llarp/iwp/frame_state.cpp @@ -1,3 +1,7 @@ +#ifdef _MSC_VER +#define NOMINMAX +#endif + #include "llarp/iwp/frame_state.hpp" #include "buffer.hpp" #include "llarp/crypto.hpp" @@ -7,6 +11,7 @@ #include "llarp/logger.hpp" #include "mem.hpp" #include "router.hpp" +#include llarp_router * frame_state::Router() diff --git a/llarp/iwp/session.cpp b/llarp/iwp/session.cpp index db37b3713..959232c94 100644 --- a/llarp/iwp/session.cpp +++ b/llarp/iwp/session.cpp @@ -1,3 +1,6 @@ +#ifdef _MSC_VER +#define NOMINMAX +#endif #include #include #include @@ -6,6 +9,7 @@ #include "buffer.hpp" #include "link/encoder.hpp" #include "llarp/ev.h" // for handle_frame_encrypt +#include static void handle_crypto_outbound(void *u) diff --git a/llarp/mem.hpp b/llarp/mem.hpp index ba104d850..ec2db9eb1 100644 --- a/llarp/mem.hpp +++ b/llarp/mem.hpp @@ -28,7 +28,7 @@ namespace llarp DumpBuffer(const T &buff) { size_t idx = 0; - printf("buffer of size %ld\n", buff.sz); + printf("buffer of size %u\n", buff.sz); while(idx < buff.sz) { if(buff.base + idx == buff.cur) diff --git a/llarp/net.cpp b/llarp/net.cpp index 56673e379..549ceb412 100644 --- a/llarp/net.cpp +++ b/llarp/net.cpp @@ -2,13 +2,12 @@ #include "str.hpp" #ifdef ANDROID #include "android/ifaddrs.h" -#else -#include #endif - +#ifndef _WIN32 +#include #include - #include +#endif #include #include "logger.hpp" @@ -42,6 +41,692 @@ operator<(const in6_addr& a, const in6_addr& b) return memcmp(&a, &b, sizeof(in6_addr)) < 0; } +#ifdef _WIN32 +#include +#include +#include +#include + +// current strategy: mingw 32-bit builds call an inlined version of the function +// microsoft c++ and mingw 64-bit builds call the normal function +#define DEFAULT_BUFFER_SIZE 15000 + +// the inline monkey patch for downlevel platforms +#ifndef _MSC_VER +extern "C" DWORD FAR PASCAL +_GetAdaptersAddresses(ULONG Family, ULONG Flags, PVOID Reserved, + PIP_ADAPTER_ADDRESSES pAdapterAddresses, + PULONG pOutBufLen); +#endif + +// in any case, we still need to implement some form of +// getifaddrs(3) with compatible semantics on NT... +// daemon.ini section [bind] will have something like +// [bind] +// Ethernet=1090 +// inside, since that's what we use in windows to refer to +// network interfaces +struct llarp_nt_ifaddrs_t +{ + struct llarp_nt_ifaddrs_t* ifa_next; /* Pointer to the next structure. */ + char* ifa_name; /* Name of this network interface. */ + unsigned int ifa_flags; /* Flags as from SIOCGIFFLAGS ioctl. */ + struct sockaddr* ifa_addr; /* Network address of this interface. */ + struct sockaddr* ifa_netmask; /* Netmask of this interface. */ +}; + +// internal struct +struct _llarp_nt_ifaddrs_t +{ + struct llarp_nt_ifaddrs_t _ifa; + char _name[256]; + struct sockaddr_storage _addr; + struct sockaddr_storage _netmask; +}; + +static inline void* +_llarp_nt_heap_alloc(const size_t n_bytes) +{ + /* Does not appear very safe with re-entrant calls on XP */ + return HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, n_bytes); +} + +static inline void +_llarp_nt_heap_free(void* mem) +{ + HeapFree(GetProcessHeap(), 0, mem); +} +#define llarp_nt_new0(struct_type, n_structs) \ + ((struct_type*)malloc((size_t)sizeof(struct_type) * (size_t)(n_structs))) + +int +llarp_nt_sockaddr_pton(const char* src, struct sockaddr* dst) +{ + struct addrinfo hints = {0}, *result = nullptr; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_flags = AI_NUMERICHOST; + const int status = getaddrinfo(src, nullptr, &hints, &result); + if(!status) + { + memcpy(dst, result->ai_addr, result->ai_addrlen); + freeaddrinfo(result); + return 1; + } + return 0; +} + +/* NB: IP_ADAPTER_INFO size varies size due to sizeof (time_t), the API assumes + * 4-byte datatype whilst compiler uses an 8-byte datatype. Size can be forced + * with -D_USE_32BIT_TIME_T with side effects to everything else. + * + * Only supports IPv4 addressing similar to SIOCGIFCONF socket option. + * + * Interfaces that are not "operationally up" will return the address 0.0.0.0, + * this includes adapters with static IP addresses but with disconnected cable. + * This is documented under the GetIpAddrTable API. Interface status can only + * be determined by the address, a separate flag is introduced with the + * GetAdapterAddresses API. + * + * The IPv4 loopback interface is not included. + * + * Available in Windows 2000 and Wine 1.0. + */ +static bool +_llarp_nt_getadaptersinfo(struct llarp_nt_ifaddrs_t** ifap) +{ + DWORD dwRet; + ULONG ulOutBufLen = DEFAULT_BUFFER_SIZE; + PIP_ADAPTER_INFO pAdapterInfo = nullptr; + PIP_ADAPTER_INFO pAdapter = nullptr; + + /* loop to handle interfaces coming online causing a buffer overflow + * between first call to list buffer length and second call to enumerate. + */ + for(unsigned i = 3; i; i--) + { +#ifdef DEBUG + fprintf(stderr, "IP_ADAPTER_INFO buffer length %lu bytes.\n", ulOutBufLen); +#endif + pAdapterInfo = (IP_ADAPTER_INFO*)_llarp_nt_heap_alloc(ulOutBufLen); + dwRet = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen); + if(ERROR_BUFFER_OVERFLOW == dwRet) + { + _llarp_nt_heap_free(pAdapterInfo); + pAdapterInfo = nullptr; + } + else + { + break; + } + } + + switch(dwRet) + { + case ERROR_SUCCESS: /* NO_ERROR */ + break; + case ERROR_BUFFER_OVERFLOW: + errno = ENOBUFS; + if(pAdapterInfo) + _llarp_nt_heap_free(pAdapterInfo); + return false; + default: + errno = dwRet; +#ifdef DEBUG + fprintf(stderr, "system call failed: %lu\n", GetLastError()); +#endif + if(pAdapterInfo) + _llarp_nt_heap_free(pAdapterInfo); + return false; + } + + /* count valid adapters */ + int n = 0, k = 0; + for(pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next) + { + for(IP_ADDR_STRING* pIPAddr = &pAdapter->IpAddressList; pIPAddr; + pIPAddr = pIPAddr->Next) + { + /* skip null adapters */ + if(strlen(pIPAddr->IpAddress.String) == 0) + continue; + ++n; + } + } + +#ifdef DEBUG + fprintf(stderr, "GetAdaptersInfo() discovered %d interfaces.\n", n); +#endif + + /* contiguous block for adapter list */ + struct _llarp_nt_ifaddrs_t* ifa = + llarp_nt_new0(struct _llarp_nt_ifaddrs_t, n); + struct _llarp_nt_ifaddrs_t* ift = ifa; + + /* now populate list */ + for(pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next) + { + for(IP_ADDR_STRING* pIPAddr = &pAdapter->IpAddressList; pIPAddr; + pIPAddr = pIPAddr->Next) + { + /* skip null adapters */ + if(strlen(pIPAddr->IpAddress.String) == 0) + continue; + + /* address */ + ift->_ifa.ifa_addr = (struct sockaddr*)&ift->_addr; + assert(1 == llarp_nt_sockaddr_pton(pIPAddr->IpAddress.String,ift->_ifa.ifa_addr)); + + /* name */ +#ifdef DEBUG + fprintf(stderr, "name:%s IPv4 index:%lu\n", pAdapter->AdapterName, + pAdapter->Index); +#endif + ift->_ifa.ifa_name = ift->_name; + StringCchCopyN(ift->_ifa.ifa_name, 128, pAdapter->AdapterName, 128); + + /* flags: assume up, broadcast and multicast */ + ift->_ifa.ifa_flags = IFF_UP | IFF_BROADCAST | IFF_MULTICAST; + if(pAdapter->Type == MIB_IF_TYPE_LOOPBACK) + ift->_ifa.ifa_flags |= IFF_LOOPBACK; + + /* netmask */ + ift->_ifa.ifa_netmask = (sockaddr*)&ift->_netmask; + assert(1 == llarp_nt_sockaddr_pton(pIPAddr->IpMask.String, ift->_ifa.ifa_netmask)); + + /* next */ + if(k++ < (n - 1)) + { + ift->_ifa.ifa_next = (struct llarp_nt_ifaddrs_t*)(ift + 1); + ift = (struct _llarp_nt_ifaddrs_t*)(ift->_ifa.ifa_next); + } + } + } + + if(pAdapterInfo) + _llarp_nt_heap_free(pAdapterInfo); + *ifap = (struct llarp_nt_ifaddrs_t*)ifa; + return true; +} + +/* Supports both IPv4 and IPv6 addressing. The size of IP_ADAPTER_ADDRESSES + * changes between Windows XP, XP SP1, and Vista with additional members. + * + * Interfaces that are not "operationally up" will typically return a host + * IP address with the defined IPv4 link-local prefix 169.254.0.0/16. + * Adapters with a static configured IP address but down will return both + * the IPv4 link-local prefix and the static address. + * + * It is easier to say "not up" rather than "down" as this API returns six + * effective down status values: down, testing, unknown, dormant, not present, + * and lower layer down. + * + * Available in Windows XP and Wine 1.3. + * + * NOTE(despair): an inline implementation is provided, much like + * getaddrinfo(3) for old hosts. See "win32_intrnl.*" + */ +#ifdef _MSC_VER +static bool +_llarp_nt_getadaptersaddresses(struct llarp_nt_ifaddrs_t** ifap) +{ + DWORD dwSize = DEFAULT_BUFFER_SIZE, dwRet; + IP_ADAPTER_ADDRESSES *pAdapterAddresses = nullptr, *adapter; + + /* loop to handle interfaces coming online causing a buffer overflow + * between first call to list buffer length and second call to enumerate. + */ + for(unsigned i = 3; i; i--) + { +#ifdef DEBUG + fprintf(stderr, "IP_ADAPTER_ADDRESSES buffer length %lu bytes.\n", dwSize); +#endif + pAdapterAddresses = (IP_ADAPTER_ADDRESSES*)_llarp_nt_heap_alloc(dwSize); +#if defined(_MSC_VER) || defined(_WIN64) + dwRet = GetAdaptersAddresses(AF_UNSPEC, + /* requires Windows XP SP1 */ + GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST + | GAA_FLAG_SKIP_DNS_SERVER + | GAA_FLAG_SKIP_FRIENDLY_NAME + | GAA_FLAG_SKIP_MULTICAST, + nullptr, pAdapterAddresses, &dwSize); +#else + dwRet = _GetAdaptersAddresses( + AF_UNSPEC, + GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST + | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME + | GAA_FLAG_SKIP_MULTICAST, + nullptr, pAdapterAddresses, &dwSize); +#endif + if(ERROR_BUFFER_OVERFLOW == dwRet) + { + _llarp_nt_heap_free(pAdapterAddresses); + pAdapterAddresses = nullptr; + } + else + { + break; + } + } + + switch(dwRet) + { + case ERROR_SUCCESS: + break; + case ERROR_BUFFER_OVERFLOW: + errno = ENOBUFS; + if(pAdapterAddresses) + _llarp_nt_heap_free(pAdapterAddresses); + return FALSE; + default: + errno = _doserrno; + if(pAdapterAddresses) + _llarp_nt_heap_free(pAdapterAddresses); + return FALSE; + } + + /* count valid adapters */ + int n = 0, k = 0; + for(adapter = pAdapterAddresses; adapter; adapter = adapter->Next) + { + for(IP_ADAPTER_UNICAST_ADDRESS* unicast = adapter->FirstUnicastAddress; + unicast; unicast = unicast->Next) + { + /* ensure IP adapter */ + if(AF_INET != unicast->Address.lpSockaddr->sa_family + && AF_INET6 != unicast->Address.lpSockaddr->sa_family) + { + continue; + } + + ++n; + } + } + + /* contiguous block for adapter list */ + struct _llarp_nt_ifaddrs_t* ifa = + llarp_nt_new0(struct _llarp_nt_ifaddrs_t, n); + struct _llarp_nt_ifaddrs_t* ift = ifa; + + /* now populate list */ + for(adapter = pAdapterAddresses; adapter; adapter = adapter->Next) + { + int unicastIndex = 0; + for(IP_ADAPTER_UNICAST_ADDRESS *unicast = adapter->FirstUnicastAddress; + unicast; unicast = unicast->Next, ++unicastIndex) + { + /* ensure IP adapter */ + if(AF_INET != unicast->Address.lpSockaddr->sa_family + && AF_INET6 != unicast->Address.lpSockaddr->sa_family) + { + continue; + } + + /* address */ + ift->_ifa.ifa_addr = (sockaddr*)&ift->_addr; + memcpy(ift->_ifa.ifa_addr, unicast->Address.lpSockaddr, + unicast->Address.iSockaddrLength); + + /* name */ +#ifdef DEBUG + fprintf(stderr, "name:%s IPv4 index:%lu IPv6 index:%lu\n", + adapter->AdapterName, adapter->IfIndex, adapter->Ipv6IfIndex); +#endif + ift->_ifa.ifa_name = ift->_name; + StringCchCopyN(ift->_ifa.ifa_name, 256, adapter->AdapterName, 256); + + /* flags */ + ift->_ifa.ifa_flags = 0; + if(IfOperStatusUp == adapter->OperStatus) + ift->_ifa.ifa_flags |= IFF_UP; + if(IF_TYPE_SOFTWARE_LOOPBACK == adapter->IfType) + ift->_ifa.ifa_flags |= IFF_LOOPBACK; + if(!(adapter->Flags & IP_ADAPTER_NO_MULTICAST)) + ift->_ifa.ifa_flags |= IFF_MULTICAST; + + /* netmask */ + ift->_ifa.ifa_netmask = (sockaddr*)&ift->_netmask; + + /* pre-Vista must hunt for matching prefix in linked list, otherwise use + * OnLinkPrefixLength from IP_ADAPTER_UNICAST_ADDRESS structure. + * FirstPrefix requires Windows XP SP1, from SP1 to pre-Vista provides a + * single adapter prefix for each IP address. Vista and later provides + * host IP address prefix, subnet IP address, and subnet broadcast IP + * address. In addition there is a multicast and broadcast address + * prefix. + */ + ULONG prefixLength = 0; + +#if defined(_WIN32) && (_WIN32_WINNT >= 0x0600) + /* For a unicast IPv4 address, any value greater than 32 is an illegal + * value. For a unicast IPv6 address, any value greater than 128 is an + * illegal value. A value of 255 is commonly used to represent an illegal + * value. + * + * Windows 7 SP1 returns 64 for Teredo links which is incorrect. + */ + +#define IN6_IS_ADDR_TEREDO(addr) \ + (((const uint32_t*)(addr))[0] == ntohl(0x20010000)) + + if(AF_INET6 == unicast->Address.lpSockaddr->sa_family && + /* TunnelType only applies to one interface on the adapter and no + * convenient method is provided to determine which. + */ + TUNNEL_TYPE_TEREDO == adapter->TunnelType && + /* Test the interface with the known Teredo network prefix. + */ + IN6_IS_ADDR_TEREDO( + &((struct sockaddr_in6*)(unicast->Address.lpSockaddr))->sin6_addr) + && + /* Test that this version is actually wrong, subsequent releases from + * Microsoft may resolve the issue. + */ + 32 != unicast->OnLinkPrefixLength) + { +#ifdef DEBUG + fprintf(stderr, + "IPv6 Teredo tunneling adapter %s prefix length is an " + "illegal value %lu, overriding to 32.\n", + adapter->AdapterName, unicast->OnLinkPrefixLength); +#endif + prefixLength = 32; + } + else + prefixLength = unicast->OnLinkPrefixLength; +#else + /* The order of linked IP_ADAPTER_UNICAST_ADDRESS structures pointed to by + * the FirstUnicastAddress member does not have any relationship with the + * order of linked IP_ADAPTER_PREFIX structures pointed to by the + * FirstPrefix member. + * + * Example enumeration: + * [ no subnet ] + * ::1/128 - address + * ff00::%1/8 - multicast (no IPv6 broadcast) + * 127.0.0.0/8 - subnet + * 127.0.0.1/32 - address + * 127.255.255.255/32 - subnet broadcast + * 224.0.0.0/4 - multicast + * 255.255.255.255/32 - broadcast + * + * Which differs from most adapters listing three IPv6: + * fe80::%10/64 - subnet + * fe80::51e9:5fe5:4202:325a%10/128 - address + * ff00::%10/8 - multicast + * + * !IfOperStatusUp IPv4 addresses are skipped: + * fe80::%13/64 - subnet + * fe80::d530:946d:e8df:8c91%13/128 - address + * ff00::%13/8 - multicast + * [ no subnet ] + * [ no address ] + * 224.0.0.0/4 - multicast + * 255.255.255.255/32 - broadcast + * + * On PTP links no multicast or broadcast addresses are returned: + * [ no subnet ] + * fe80::5efe:10.203.9.30/128 - address + * [ no multicast ] + * [ no multicast ] + * [ no broadcast ] + * + * Active primary IPv6 interfaces are a bit overloaded: + * ::/0 - default route + * 2001::/32 - global subnet + * 2001:0:4137:9e76:2443:d6:ba87:1a2a/128 - global address + * fe80::/64 - link-local subnet + * fe80::2443:d6:ba87:1a2a/128 - link-local address + * ff00::/8 - multicast + */ + +#define IN_LINKLOCAL(a) ((((uint32_t)(a)) & 0xaffff0000) == 0xa9fe0000) + + for(IP_ADAPTER_PREFIX* prefix = adapter->FirstPrefix; prefix; + prefix = prefix->Next) + { + LPSOCKADDR lpSockaddr = prefix->Address.lpSockaddr; + if(lpSockaddr->sa_family != unicast->Address.lpSockaddr->sa_family) + continue; + /* special cases */ + /* RFC2863: IPv4 interface not up */ + if(AF_INET == lpSockaddr->sa_family + && adapter->OperStatus != IfOperStatusUp) + { + /* RFC3927: link-local IPv4 always has 16-bit CIDR */ + if(IN_LINKLOCAL( + ntohl(((struct sockaddr_in*)(unicast->Address.lpSockaddr)) + ->sin_addr.s_addr))) + { +#ifdef DEBUG + fprintf(stderr, + "Assuming 16-bit prefix length for link-local IPv4 " + "adapter %s.\n", + adapter->AdapterName); +#endif + prefixLength = 16; + } + else + { +#ifdef DEBUG + fprintf(stderr, "Prefix length unavailable for IPv4 adapter %s.\n", + adapter->AdapterName); +#endif + } + break; + } + /* default IPv6 route */ + if(AF_INET6 == lpSockaddr->sa_family && 0 == prefix->PrefixLength + && IN6_IS_ADDR_UNSPECIFIED( + &((struct sockaddr_in6*)(lpSockaddr))->sin6_addr)) + { +#ifdef DEBUG + fprintf(stderr, + "Ingoring unspecified address prefix on IPv6 adapter %s.\n", + adapter->AdapterName); +#endif + continue; + } + /* Assume unicast address for first prefix of operational adapter */ + if(AF_INET == lpSockaddr->sa_family) + assert(!IN_MULTICAST( + ntohl(((struct sockaddr_in*)(lpSockaddr))->sin_addr.s_addr))); + if(AF_INET6 == lpSockaddr->sa_family) + assert(!IN6_IS_ADDR_MULTICAST( + &((struct sockaddr_in6*)(lpSockaddr))->sin6_addr)); + /* Assume subnet or host IP address for XP backward compatibility */ + + prefixLength = prefix->PrefixLength; + break; + } +#endif /* defined( _WIN32 ) && ( _WIN32_WINNT >= 0x0600 ) */ + + /* map prefix to netmask */ + ift->_ifa.ifa_netmask->sa_family = unicast->Address.lpSockaddr->sa_family; + switch(unicast->Address.lpSockaddr->sa_family) + { + case AF_INET: + if(0 == prefixLength || prefixLength > 32) + { +#ifdef DEBUG + fprintf(stderr, + "IPv4 adapter %s prefix length is an illegal value " + "%lu, overriding to 32.\n", + adapter->AdapterName, prefixLength); +#endif + prefixLength = 32; + } + /* NB: left-shift of full bit-width is undefined in C standard. */ + ((struct sockaddr_in*)ift->_ifa.ifa_netmask)->sin_addr.s_addr = + htonl(0xffffffffU << (32 - prefixLength)); + break; + + case AF_INET6: + if(0 == prefixLength || prefixLength > 128) + { +#ifdef DEBUG + fprintf(stderr, + "IPv6 adapter %s prefix length is an illegal value " + "%lu, overriding to 128.\n", + adapter->AdapterName, prefixLength); +#endif + prefixLength = 128; + } + for(LONG i = prefixLength, j = 0; i > 0; i -= 8, ++j) + { + ((struct sockaddr_in6*)ift->_ifa.ifa_netmask) + ->sin6_addr.s6_addr[j] = + i >= 8 ? 0xff : (ULONG)((0xffU << (8 - i)) & 0xffU); + } + break; + } + + /* next */ + if(k++ < (n - 1)) + { + ift->_ifa.ifa_next = (struct llarp_nt_ifaddrs_t*)(ift + 1); + ift = (struct _llarp_nt_ifaddrs_t*)(ift->_ifa.ifa_next); + } + } + } + + if(pAdapterAddresses) + _llarp_nt_heap_free(pAdapterAddresses); + *ifap = (struct llarp_nt_ifaddrs_t*)ifa; + return TRUE; +} +#endif + +// an implementation of if_nametoindex(3) based on GetAdapterIndex(2) +// with a fallback to GetAdaptersAddresses(2) commented out for now +// unless it becomes evident that the first codepath fails in certain +// edge cases? +static unsigned +_llarp_nt_getadaptersaddresses_nametoindex(const char* ifname) +{ + ULONG ifIndex; + DWORD /* dwSize = 4096,*/ dwRet; + // IP_ADAPTER_ADDRESSES *pAdapterAddresses = nullptr, *adapter; + char szAdapterName[256]; + + if(!ifname) + return 0; + + StringCchCopyN(szAdapterName, sizeof(szAdapterName), ifname, 256); + dwRet = GetAdapterIndex((LPWSTR)szAdapterName, &ifIndex); + + if(!dwRet) + return ifIndex; + else + return 0; + +#if 0 + /* fallback to finding index via iterating adapter list */ + + /* loop to handle interfaces coming online causing a buffer overflow + * between first call to list buffer length and second call to enumerate. + */ + for(unsigned i = 3; i; i--) + { + pAdapterAddresses = (IP_ADAPTER_ADDRESSES*)_llarp_nt_heap_alloc(dwSize); +#ifdef _MSC_VER + dwRet = GetAdaptersAddresses( + AF_UNSPEC, + GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER + | GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_SKIP_MULTICAST, + nullptr, pAdapterAddresses, &dwSize); +#else + dwRet = _GetAdaptersAddresses( + AF_UNSPEC, + GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER + | GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_SKIP_MULTICAST, + nullptr, pAdapterAddresses, &dwSize); +#endif + + if(ERROR_BUFFER_OVERFLOW == dwRet) + { + _llarp_nt_heap_free(pAdapterAddresses); + pAdapterAddresses = nullptr; + } + else + { + break; + } + } + + switch(dwRet) + { + case ERROR_SUCCESS: + break; + case ERROR_BUFFER_OVERFLOW: + errno = ENOBUFS; + if(pAdapterAddresses) + _llarp_nt_heap_free(pAdapterAddresses); + return 0; + default: + errno = _doserrno; + if(pAdapterAddresses) + _llarp_nt_heap_free(pAdapterAddresses); + return 0; + } + + for(adapter = pAdapterAddresses; adapter; adapter = adapter->Next) + { + if(0 == strcmp(szAdapterName, adapter->AdapterName)) + { + //ifIndex = AF_INET6 == iffamily ? adapter->Ipv6IfIndex : adapter->IfIndex; + _llarp_nt_heap_free(pAdapterAddresses); + return ifIndex; + } + } + + if(pAdapterAddresses) + _llarp_nt_heap_free(pAdapterAddresses); + return 0; +#endif +} + +// the emulated getifaddrs(3) itself. +static bool +llarp_nt_getifaddrs(struct llarp_nt_ifaddrs_t** ifap) +{ + assert(nullptr != ifap); +#ifdef DEBUG + fprintf(stderr, "llarp_nt_getifaddrs (ifap:%p error:%p)\n", (void*)ifap,(void*)errno); +#endif +#ifdef _MSC_VER + return _llarp_nt_getadaptersaddresses(ifap); +#else + return _llarp_nt_getadaptersinfo(ifap); +#endif +} + +static void +llarp_nt_freeifaddrs(struct llarp_nt_ifaddrs_t* ifa) +{ + if(!ifa) + return; + free(ifa); +} + +// emulated if_nametoindex(3) +static unsigned +llarp_nt_if_nametoindex(const char* ifname) +{ + if(!ifname) + return 0; + return _llarp_nt_getadaptersaddresses_nametoindex(ifname); +} + +// fix up names for win32 +#define ifaddrs llarp_nt_ifaddrs_t +#define getifaddrs llarp_nt_getifaddrs +#define freeifaddrs llarp_nt_freeifaddrs +#define if_nametoindex llarp_nt_if_nametoindex +#endif + +// jeff's original code bool llarp_getifaddr(const char* ifname, int af, struct sockaddr* addr) { @@ -51,7 +736,11 @@ llarp_getifaddr(const char* ifname, int af, struct sockaddr* addr) if(af == AF_INET) sl = sizeof(sockaddr_in); +#ifndef _WIN32 if(getifaddrs(&ifa) == -1) +#else + if(!getifaddrs(&ifa)) +#endif return false; ifaddrs* i = ifa; while(i) @@ -86,7 +775,6 @@ llarp_getifaddr(const char* ifname, int af, struct sockaddr* addr) freeifaddrs(ifa); return found; } - namespace llarp { bool @@ -94,8 +782,11 @@ namespace llarp { ifaddrs* ifa = nullptr; bool found = false; - +#ifndef _WIN32 if(getifaddrs(&ifa) == -1) +#else + if(!getifaddrs(&ifa)) +#endif return false; ifaddrs* i = ifa; while(i) diff --git a/llarp/nodedb.cpp b/llarp/nodedb.cpp index 83e991436..777521515 100644 --- a/llarp/nodedb.cpp +++ b/llarp/nodedb.cpp @@ -109,7 +109,11 @@ struct llarp_nodedb const char *hexname = llarp::HexEncode< llarp::PubKey, decltype(ftmp) >(pubkey, ftmp); std::string hexString(hexname); +#ifdef _WIN32 + std::string filepath = nodePath.string(); +#else std::string filepath = nodePath; +#endif filepath.append(PATH_SEP); filepath.append(&hexString[hexString.length() - 1]); filepath.append(PATH_SEP); @@ -182,7 +186,7 @@ struct llarp_nodedb { ssize_t sz = 0; fs::directory_iterator i(dir); -#if __has_include() && !defined(__OpenBSD__) +#if defined(CPP17) && defined(USE_CXX17_FILESYSTEM) auto itr = fs::begin(i); while(itr != fs::end(i)) #else @@ -190,7 +194,7 @@ struct llarp_nodedb while(itr != itr.end()) #endif { - if(fs::is_regular_file(itr->symlink_status()) && loadfile(*itr)) + if(fs::is_regular_file(itr->path()) && loadfile(*itr)) sz++; ++itr; @@ -210,7 +214,11 @@ struct llarp_nodedb #endif llarp_rc rc; llarp_rc_clear(&rc); +#ifdef _WIN32 + if(!llarp_rc_read(fpath.string().c_str(), &rc)) +#else if(!llarp_rc_read(fpath.c_str(), &rc)) +#endif { llarp::LogError("Signature read failed", fpath); return false; @@ -348,6 +356,7 @@ llarp_nodedb_ensure_dir(const char *dir) { fs::path path(dir); std::error_code ec; + if(!fs::exists(dir, ec)) fs::create_directories(path, ec); @@ -359,6 +368,11 @@ llarp_nodedb_ensure_dir(const char *dir) for(const char &ch : skiplist_subdirs) { + // this seems to be a problem on all targets + // perhaps cpp17::fs is just as screwed-up + // attempting to create a folder with no name + if(!ch) + return true; std::string p; p += ch; fs::path sub = path / p; diff --git a/llarp/router.cpp b/llarp/router.cpp index 015476adc..9e99b76f6 100644 --- a/llarp/router.cpp +++ b/llarp/router.cpp @@ -1,10 +1,10 @@ -#include "router.hpp" #include #include #include #include "llarp/iwp/establish_job.hpp" #include "llarp/iwp/server.hpp" #include "llarp/iwp/session.hpp" +#include "router.hpp" #include "buffer.hpp" #include "encode.hpp" @@ -166,7 +166,11 @@ llarp_router::try_connect(fs::path rcfile) { llarp_rc remote; llarp_rc_new(&remote); +#ifdef _WIN32 + if(!llarp_rc_read(rcfile.string().c_str(), &remote)) +#else if(!llarp_rc_read(rcfile.c_str(), &remote)) +#endif { llarp::LogError("failure to decode or verify of remote RC"); return; @@ -196,14 +200,24 @@ llarp_router::EnsureIdentity() { if(!EnsureEncryptionKey()) return false; +#ifdef _WIN32 + return llarp_findOrCreateIdentity(&crypto, ident_keyfile.string().c_str(), + identity); +#else return llarp_findOrCreateIdentity(&crypto, ident_keyfile.c_str(), identity); +#endif } bool llarp_router::EnsureEncryptionKey() { +#ifdef _WIN32 + return llarp_findOrCreateEncryption( + &crypto, encryption_keyfile.string().c_str(), &this->encryption); +#else return llarp_findOrCreateEncryption(&crypto, encryption_keyfile.c_str(), &this->encryption); +#endif } void @@ -233,7 +247,11 @@ llarp_router::SaveRC() if(llarp_rc_bencode(&rc, &buf)) { +#ifdef _WIN32 + std::ofstream f(our_rc_file.string()); +#else std::ofstream f(our_rc_file); +#endif if(f.is_open()) { f.write((char *)buf.base, buf.cur - buf.base); @@ -754,7 +772,15 @@ llarp_router::InitOutboundLink() { if(outboundLink) return true; - +#ifdef __MINGW32__ + llarp_iwp_args args = { + .crypto = &crypto, + .logic = logic, + .cryptoworker = tp, + .router = this, + .keyfile = transport_keyfile.string().c_str(), + }; +#elif !defined(_MSC_VER) llarp_iwp_args args = { .crypto = &crypto, .logic = logic, @@ -762,6 +788,11 @@ llarp_router::InitOutboundLink() .router = this, .keyfile = transport_keyfile.c_str(), }; +#else + llarp_iwp_args args = { + &crypto, logic, tp, this, transport_keyfile.string().c_str(), + }; +#endif auto link = new(std::nothrow) llarp_link(args); @@ -913,7 +944,11 @@ llarp_rc_read(const char *fpath, llarp_rc *result) printf("File[%s] not found\n", fpath); return false; } +#ifdef _WIN32 + std::ifstream f(our_rc_file.string(), std::ios::binary); +#else std::ifstream f(our_rc_file, std::ios::binary); +#endif if(!f.is_open()) { printf("Can't open file [%s]\n", fpath); @@ -933,7 +968,7 @@ llarp_rc_read(const char *fpath, llarp_rc *result) llarp::Zero(result, sizeof(llarp_rc)); if(!llarp_rc_bdecode(result, &buf)) { - printf("Can't decode [%s]\n", fpath); + llarp::LogError("Can't decode ", fpath); return false; } return true; @@ -967,7 +1002,11 @@ llarp_rc_write(struct llarp_rc *rc, const char *fpath) if(llarp_rc_bencode(rc, &buf)) { +#ifdef _WIN32 + std::ofstream f(our_rc_file.string(), std::ios::binary); +#else std::ofstream f(our_rc_file, std::ios::binary); +#endif if(f.is_open()) { f.write((char *)buf.base, buf.cur - buf.base); @@ -1039,13 +1078,21 @@ llarp_findOrCreateIdentity(llarp_crypto *crypto, const char *fpath, { llarp::LogInfo("generating new identity key"); crypto->identity_keygen(secretkey); +#ifdef _WIN32 + std::ofstream f(path.string(), std::ios::binary); +#else std::ofstream f(path, std::ios::binary); +#endif if(f.is_open()) { f.write((char *)secretkey, SECKEYSIZE); } } +#ifdef _WIN32 + std::ifstream f(path.string(), std::ios::binary); +#else std::ifstream f(path, std::ios::binary); +#endif if(f.is_open()) { f.read((char *)secretkey, SECKEYSIZE); @@ -1067,13 +1114,21 @@ llarp_findOrCreateEncryption(llarp_crypto *crypto, const char *fpath, { llarp::LogInfo("generating new encryption key"); crypto->encryption_keygen(*encryption); +#ifdef _WIN32 + std::ofstream f(path.string(), std::ios::binary); +#else std::ofstream f(path, std::ios::binary); +#endif if(f.is_open()) { f.write((char *)encryption, SECKEYSIZE); } } +#ifdef _WIN32 + std::ifstream f(path.string(), std::ios::binary); +#else std::ifstream f(path, std::ios::binary); +#endif if(f.is_open()) { f.read((char *)encryption, SECKEYSIZE); @@ -1130,6 +1185,15 @@ namespace llarp if(!StrEq(key, "*")) { llarp::LogInfo("interface specific binding activated"); +#ifdef __MINGW32__ + llarp_iwp_args args = { + .crypto = &self->crypto, + .logic = self->logic, + .cryptoworker = self->tp, + .router = self, + .keyfile = self->transport_keyfile.string().c_str(), + }; +#elif !defined(_MSC_VER) llarp_iwp_args args = { .crypto = &self->crypto, .logic = self->logic, @@ -1137,6 +1201,15 @@ namespace llarp .router = self, .keyfile = self->transport_keyfile.c_str(), }; +#else + llarp_iwp_args args = { + &self->crypto, + self->logic, + self->tp, + self, + self->transport_keyfile.string().c_str(), + }; +#endif link = new(std::nothrow) llarp_link(args); diff --git a/llarp/service.cpp b/llarp/service.cpp index d2c68cceb..720408ab2 100644 --- a/llarp/service.cpp +++ b/llarp/service.cpp @@ -1,3 +1,7 @@ +#ifdef _MSC_VER +#define NOMINMAX +#endif + #include #include "buffer.hpp" #include "fs.hpp" diff --git a/llarp/threadpool.cpp b/llarp/threadpool.cpp index 87e2806ff..ae166b40b 100644 --- a/llarp/threadpool.cpp +++ b/llarp/threadpool.cpp @@ -1,5 +1,7 @@ #include "threadpool.hpp" +#ifndef _MSC_VER #include +#endif #include #include @@ -11,6 +13,12 @@ #include #endif +#ifdef _MSC_VER +#include +extern "C" void +SetThreadName(DWORD dwThreadID, LPCSTR szThreadName); +#endif + namespace llarp { namespace thread @@ -27,8 +35,10 @@ namespace llarp pthread_setname_np(name); #elif(__FreeBSD__) || (__OpenBSD__) || (__NetBSD__) pthread_set_name_np(pthread_self(), name); -#else +#elif !defined(_MSC_VER) || !defined(_WIN32) pthread_setname_np(pthread_self(), name); +#else + SetThreadName(GetCurrentThreadId(),name); #endif } for(;;) diff --git a/llarp/win32_inet.c b/llarp/win32_inet.c new file mode 100644 index 000000000..e62bcf823 --- /dev/null +++ b/llarp/win32_inet.c @@ -0,0 +1,312 @@ +#if defined(__MINGW32__) && !defined(_WIN64) +/* + * Contains routines missing from WS2_32.DLL until 2006, if yer using + * Microsoft C/C++, then this code is irrelevant, as the official + * Platform SDK already links against these routines in the correct + * libraries. + * + * -despair86 30/07/18 + */ +#include +#include +#include +#include +#include "win32_intrnl.h" + +const char * +inet_ntop(int af, const void *src, char *dst, size_t size) +{ + int address_length; + DWORD string_length = size; + struct sockaddr_storage sa; + struct sockaddr_in *sin = (struct sockaddr_in *)&sa; + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&sa; + + memset(&sa, 0, sizeof(sa)); + switch(af) + { + case AF_INET: + address_length = sizeof(struct sockaddr_in); + sin->sin_family = af; + memcpy(&sin->sin_addr, src, sizeof(struct in_addr)); + break; + + case AF_INET6: + address_length = sizeof(struct sockaddr_in6); + sin6->sin6_family = af; + memcpy(&sin6->sin6_addr, src, sizeof(struct in6_addr)); + break; + + default: + return NULL; + } + + if(WSAAddressToString((LPSOCKADDR)&sa, address_length, NULL, dst, + &string_length) + == 0) + { + return dst; + } + + return NULL; +} + +int +inet_pton(int af, const char *src, void *dst) +{ + int address_length; + struct sockaddr_storage sa; + struct sockaddr_in *sin = (struct sockaddr_in *)&sa; + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&sa; + + switch(af) + { + case AF_INET: + address_length = sizeof(struct sockaddr_in); + break; + + case AF_INET6: + address_length = sizeof(struct sockaddr_in6); + break; + + default: + return -1; + } + + if(WSAStringToAddress((LPTSTR)src, af, NULL, (LPSOCKADDR)&sa, &address_length) + == 0) + { + switch(af) + { + case AF_INET: + memcpy(dst, &sin->sin_addr, sizeof(struct in_addr)); + break; + + case AF_INET6: + memcpy(dst, &sin6->sin6_addr, sizeof(struct in6_addr)); + break; + } + return 1; + } + + return 0; +} + +typedef struct _InterfaceIndexTable +{ + DWORD numIndexes; + IF_INDEX indexes[1]; +} InterfaceIndexTable; + +// windows 2000 +// todo(despair86): implement IPv6 detection using +// the ipv6 preview stack/adv net pack from 1999/2001 +DWORD FAR PASCAL +_GetAdaptersAddresses(ULONG Family, ULONG Flags, PVOID Reserved, + PIP_ADAPTER_ADDRESSES pAdapterAddresses, + PULONG pOutBufLen) +{ + InterfaceIndexTable *indexTable; + IFInfo ifInfo; + int i; + ULONG ret, requiredSize = 0; + PIP_ADAPTER_ADDRESSES currentAddress; + PUCHAR currentLocation; + HANDLE tcpFile; + + if(!pOutBufLen) + return ERROR_INVALID_PARAMETER; + if(Reserved) + return ERROR_INVALID_PARAMETER; + + indexTable = getInterfaceIndexTable(); + if(!indexTable) + return ERROR_NOT_ENOUGH_MEMORY; + + ret = openTcpFile(&tcpFile, FILE_READ_DATA); + if(!NT_SUCCESS(ret)) + return ERROR_NO_DATA; + + for(i = indexTable->numIndexes; i >= 0; i--) + { + if(NT_SUCCESS( + getIPAddrEntryForIf(tcpFile, NULL, indexTable->indexes[i], &ifInfo))) + { + /* The whole struct */ + requiredSize += sizeof(IP_ADAPTER_ADDRESSES); + + /* Friendly name */ + if(!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME)) + requiredSize += + strlen((char *)ifInfo.if_info.ent.if_descr) + 1; // FIXME + + /* Adapter name */ + requiredSize += strlen((char *)ifInfo.if_info.ent.if_descr) + 1; + + /* Unicast address */ + if(!(Flags & GAA_FLAG_SKIP_UNICAST)) + requiredSize += sizeof(IP_ADAPTER_UNICAST_ADDRESS); + + /* FIXME: Implement multicast, anycast, and dns server stuff */ + + /* FIXME: Implement dns suffix and description */ + requiredSize += 2 * sizeof(WCHAR); + + /* We're only going to implement what's required for XP SP0 */ + } + } +#ifdef DEBUG + fprintf(stderr, "size: %ld, requiredSize: %ld\n", *pOutBufLen, requiredSize); +#endif + if(!pAdapterAddresses || *pOutBufLen < requiredSize) + { + *pOutBufLen = requiredSize; + closeTcpFile(tcpFile); + free(indexTable); + return ERROR_BUFFER_OVERFLOW; + } + + RtlZeroMemory(pAdapterAddresses, requiredSize); + + /* Let's set up the pointers */ + currentAddress = pAdapterAddresses; + for(i = indexTable->numIndexes; i >= 0; i--) + { + if(NT_SUCCESS( + getIPAddrEntryForIf(tcpFile, NULL, indexTable->indexes[i], &ifInfo))) + { + currentLocation = + (PUCHAR)currentAddress + (ULONG_PTR)sizeof(IP_ADAPTER_ADDRESSES); + + /* FIXME: Friendly name */ + if(!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME)) + { + currentAddress->FriendlyName = (PVOID)currentLocation; + currentLocation += sizeof(WCHAR); + } + + /* Adapter name */ + currentAddress->AdapterName = (PVOID)currentLocation; + currentLocation += strlen((char *)ifInfo.if_info.ent.if_descr) + 1; + + /* Unicast address */ + if(!(Flags & GAA_FLAG_SKIP_UNICAST)) + { + currentAddress->FirstUnicastAddress = (PVOID)currentLocation; + currentLocation += sizeof(IP_ADAPTER_UNICAST_ADDRESS); + currentAddress->FirstUnicastAddress->Address.lpSockaddr = + (PVOID)currentLocation; + currentLocation += sizeof(struct sockaddr); + } + + /* FIXME: Implement multicast, anycast, and dns server stuff */ + + /* FIXME: Implement dns suffix and description */ + currentAddress->DnsSuffix = (PVOID)currentLocation; + currentLocation += sizeof(WCHAR); + + currentAddress->Description = (PVOID)currentLocation; + currentLocation += sizeof(WCHAR); + + currentAddress->Next = (PVOID)currentLocation; + /* Terminate the last address correctly */ + if(i == 0) + currentAddress->Next = NULL; + + /* We're only going to implement what's required for XP SP0 */ + + currentAddress = currentAddress->Next; + } + } + + /* Now again, for real this time */ + + currentAddress = pAdapterAddresses; + for(i = indexTable->numIndexes; i >= 0; i--) + { + if(NT_SUCCESS( + getIPAddrEntryForIf(tcpFile, NULL, indexTable->indexes[i], &ifInfo))) + { + /* Make sure we're not looping more than we hoped for */ + assert(currentAddress); + + /* Alignment information */ + currentAddress->Length = sizeof(IP_ADAPTER_ADDRESSES); + currentAddress->IfIndex = indexTable->indexes[i]; + + /* Adapter name */ + strcpy(currentAddress->AdapterName, (char *)ifInfo.if_info.ent.if_descr); + + if(!(Flags & GAA_FLAG_SKIP_UNICAST)) + { + currentAddress->FirstUnicastAddress->Length = + sizeof(IP_ADAPTER_UNICAST_ADDRESS); + currentAddress->FirstUnicastAddress->Flags = 0; // FIXME + currentAddress->FirstUnicastAddress->Next = + NULL; // FIXME: Support more than one address per adapter + currentAddress->FirstUnicastAddress->Address.lpSockaddr->sa_family = + AF_INET; + memcpy(currentAddress->FirstUnicastAddress->Address.lpSockaddr->sa_data, + &ifInfo.ip_addr.iae_addr, sizeof(ifInfo.ip_addr.iae_addr)); + currentAddress->FirstUnicastAddress->Address.iSockaddrLength = + sizeof(ifInfo.ip_addr.iae_addr) + sizeof(USHORT); + currentAddress->FirstUnicastAddress->PrefixOrigin = + IpPrefixOriginOther; // FIXME + currentAddress->FirstUnicastAddress->SuffixOrigin = + IpPrefixOriginOther; // FIXME + currentAddress->FirstUnicastAddress->DadState = + IpDadStatePreferred; // FIXME + currentAddress->FirstUnicastAddress->ValidLifetime = + 0xFFFFFFFF; // FIXME + currentAddress->FirstUnicastAddress->PreferredLifetime = + 0xFFFFFFFF; // FIXME + currentAddress->FirstUnicastAddress->LeaseLifetime = + 0xFFFFFFFF; // FIXME + } + + /* FIXME: Implement multicast, anycast, and dns server stuff */ + currentAddress->FirstAnycastAddress = NULL; + currentAddress->FirstMulticastAddress = NULL; + currentAddress->FirstDnsServerAddress = NULL; + + /* FIXME: Implement dns suffix, description, and friendly name */ + currentAddress->DnsSuffix[0] = UNICODE_NULL; + currentAddress->Description[0] = UNICODE_NULL; + currentAddress->FriendlyName[0] = UNICODE_NULL; + + /* Physical Address */ + memcpy(currentAddress->PhysicalAddress, ifInfo.if_info.ent.if_physaddr, + ifInfo.if_info.ent.if_physaddrlen); + currentAddress->PhysicalAddressLength = ifInfo.if_info.ent.if_physaddrlen; + + /* Flags */ + currentAddress->Flags = 0; // FIXME + + /* MTU */ + currentAddress->Mtu = ifInfo.if_info.ent.if_mtu; + + /* Interface type */ + currentAddress->IfType = ifInfo.if_info.ent.if_type; + + /* Operational status */ + if(ifInfo.if_info.ent.if_operstatus >= IF_OPER_STATUS_CONNECTING) + currentAddress->OperStatus = IfOperStatusUp; + else + currentAddress->OperStatus = IfOperStatusDown; + + /* We're only going to implement what's required for XP SP0 */ + + /* Move to the next address */ + currentAddress = currentAddress->Next; + } + } + + closeTcpFile(tcpFile); + free(indexTable); + + return NO_ERROR; +} +#elif _MSC_VER +/* just a comment */ +static void* unused; +#endif \ No newline at end of file diff --git a/llarp/win32_intrnl.c b/llarp/win32_intrnl.c new file mode 100644 index 000000000..8524d0223 --- /dev/null +++ b/llarp/win32_intrnl.c @@ -0,0 +1,534 @@ +#if defined(__MINGW32__) && !defined(_WIN64) +/* + * All the user-mode scaffolding necessary to backport GetAdaptersAddresses(2)) + * to the NT 5.x series. See further comments for any limitations. + * + * -despair86 30/07/18 + */ +#include +#include + +#include +#include +#include +#include "win32_intrnl.h" + +const PWCHAR TcpFileName = L"\\Device\\Tcp"; + +// from ntdll.dll +typedef void(FAR PASCAL *pRtlInitUString)(UNICODE_STRING *, const WCHAR *); +typedef NTSTATUS(FAR PASCAL *pNTOpenFile)(HANDLE *, ACCESS_MASK, + OBJECT_ATTRIBUTES *, + IO_STATUS_BLOCK *, ULONG, ULONG); +typedef NTSTATUS(FAR PASCAL *pNTClose)(HANDLE); + +#define FSCTL_TCP_BASE FILE_DEVICE_NETWORK + +#define _TCP_CTL_CODE(Function, Method, Access) \ +CTL_CODE(FSCTL_TCP_BASE, Function, Method, Access) + +#define IOCTL_TCP_QUERY_INFORMATION_EX \ +_TCP_CTL_CODE(0, METHOD_NEITHER, FILE_ANY_ACCESS) + +typedef struct _InterfaceIndexTable +{ + DWORD numIndexes; + DWORD numAllocated; + DWORD indexes[1]; +} InterfaceIndexTable; + +NTSTATUS +tdiGetMibForIfEntity(HANDLE tcpFile, TDIEntityID *ent, + IFEntrySafelySized *entry) +{ + TCP_REQUEST_QUERY_INFORMATION_EX req = {{{0}}}; + NTSTATUS status = 0; + DWORD returnSize; + + #ifdef DEBUG + fprintf(stderr, "TdiGetMibForIfEntity(tcpFile %x,entityId %x)\n", (int)tcpFile, + (int)ent->tei_instance); + #endif + + req.ID.toi_class = INFO_CLASS_PROTOCOL; + req.ID.toi_type = INFO_TYPE_PROVIDER; + req.ID.toi_id = 1; + req.ID.toi_entity = *ent; + + status = + DeviceIoControl(tcpFile, IOCTL_TCP_QUERY_INFORMATION_EX, &req, + sizeof(req), entry, sizeof(*entry), &returnSize, NULL); + + if(!status) + { + perror("IOCTL Failed\n"); + return 0xc0000001; + } + + fprintf(stderr, + "TdiGetMibForIfEntity() => {\n" + " if_index ....................... %lx\n" + " if_type ........................ %lx\n" + " if_mtu ......................... %ld\n" + " if_speed ....................... %lx\n" + " if_physaddrlen ................. %ld\n", + entry->ent.if_index, entry->ent.if_type, entry->ent.if_mtu, + entry->ent.if_speed, entry->ent.if_physaddrlen); + fprintf(stderr, + " if_physaddr .................... %02x:%02x:%02x:%02x:%02x:%02x\n" + " if_descr ....................... %s\n", + entry->ent.if_physaddr[0] & 0xff, entry->ent.if_physaddr[1] & 0xff, + entry->ent.if_physaddr[2] & 0xff, entry->ent.if_physaddr[3] & 0xff, + entry->ent.if_physaddr[4] & 0xff, entry->ent.if_physaddr[5] & 0xff, + entry->ent.if_descr); + fprintf(stderr, "} status %08lx\n", status); + + return 0; +} + +static NTSTATUS +tdiGetSetOfThings(HANDLE tcpFile, DWORD toiClass, DWORD toiType, DWORD toiId, + DWORD teiEntity, DWORD teiInstance, DWORD fixedPart, + DWORD entrySize, PVOID *tdiEntitySet, PDWORD numEntries) +{ + TCP_REQUEST_QUERY_INFORMATION_EX req = {{{0}}}; + PVOID entitySet = 0; + NTSTATUS status = 0; + DWORD allocationSizeForEntityArray = entrySize * MAX_TDI_ENTITIES, + arraySize = entrySize * MAX_TDI_ENTITIES; + + req.ID.toi_class = toiClass; + req.ID.toi_type = toiType; + req.ID.toi_id = toiId; + req.ID.toi_entity.tei_entity = teiEntity; + req.ID.toi_entity.tei_instance = teiInstance; + + /* There's a subtle problem here... + * If an interface is added at this exact instant, (as if by a PCMCIA + * card insertion), the array will still not have enough entries after + * have allocated it after the first DeviceIoControl call. + * + * We'll get around this by repeating until the number of interfaces + * stabilizes. + */ + do + { + status = + DeviceIoControl(tcpFile, IOCTL_TCP_QUERY_INFORMATION_EX, &req, + sizeof(req), 0, 0, &allocationSizeForEntityArray, NULL); + + if(!status) + return 0xc0000001; + + arraySize = allocationSizeForEntityArray; + entitySet = HeapAlloc(GetProcessHeap(), 0, arraySize); + + if(!entitySet) + { + status = ((NTSTATUS)0xC000009A); + return status; + } + + status = DeviceIoControl(tcpFile, IOCTL_TCP_QUERY_INFORMATION_EX, &req, + sizeof(req), entitySet, arraySize, + &allocationSizeForEntityArray, NULL); + + /* This is why we have the loop -- we might have added an adapter */ + if(arraySize == allocationSizeForEntityArray) + break; + + HeapFree(GetProcessHeap(), 0, entitySet); + entitySet = 0; + + if(!status) + return 0xc0000001; + } while(TRUE); /* We break if the array we received was the size we + * expected. Therefore, we got here because it wasn't */ + + *numEntries = (arraySize - fixedPart) / entrySize; + *tdiEntitySet = entitySet; + + return 0; +} + +static NTSTATUS +tdiGetEntityIDSet(HANDLE tcpFile, TDIEntityID **entitySet, + PDWORD numEntities) +{ + NTSTATUS status = tdiGetSetOfThings(tcpFile, + INFO_CLASS_GENERIC, + INFO_TYPE_PROVIDER, + ENTITY_LIST_ID, + GENERIC_ENTITY, + 0, + 0, + sizeof(TDIEntityID), + (PVOID *)entitySet, + numEntities); + return status; +} + +NTSTATUS +tdiGetIpAddrsForIpEntity(HANDLE tcpFile, TDIEntityID *ent, IPAddrEntry **addrs, + PDWORD numAddrs) +{ + NTSTATUS status; + + fprintf(stderr,"TdiGetIpAddrsForIpEntity(tcpFile 0x%p, entityId 0x%lx)\n", tcpFile, + ent->tei_instance); + + status = tdiGetSetOfThings(tcpFile, INFO_CLASS_PROTOCOL, INFO_TYPE_PROVIDER, + 0x102, CL_NL_ENTITY, + ent->tei_instance, 0, sizeof(IPAddrEntry), + (PVOID *)addrs, numAddrs); + + return status; +} + +static VOID +tdiFreeThingSet(PVOID things) +{ + HeapFree(GetProcessHeap(), 0, things); +} + +NTSTATUS +openTcpFile(PHANDLE tcpFile, ACCESS_MASK DesiredAccess) +{ + UNICODE_STRING fileName; + OBJECT_ATTRIBUTES objectAttributes; + IO_STATUS_BLOCK ioStatusBlock; + NTSTATUS status; + pRtlInitUString _RtlInitUnicodeString; + pNTOpenFile _NTOpenFile; + HANDLE ntdll; + + ntdll = GetModuleHandle("ntdll.dll"); + _RtlInitUnicodeString = (pRtlInitUString)GetProcAddress(ntdll, "RtlInitUnicodeString"); + _NTOpenFile = (pNTOpenFile)GetProcAddress(ntdll, "NtOpenFile"); + _RtlInitUnicodeString(&fileName, TcpFileName); + InitializeObjectAttributes(&objectAttributes, &fileName, OBJ_CASE_INSENSITIVE, + NULL, NULL); + status = _NTOpenFile(tcpFile, DesiredAccess | SYNCHRONIZE, &objectAttributes, + &ioStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_SYNCHRONOUS_IO_NONALERT); + /* String does not need to be freed: it points to the constant + * string we provided */ + if(!NT_SUCCESS(status)) + *tcpFile = INVALID_HANDLE_VALUE; + return status; +} +VOID +closeTcpFile(HANDLE h) +{ + pNTClose _NTClose; + HANDLE ntdll = GetModuleHandle("ntdll.dll"); + _NTClose = (pNTClose)GetProcAddress(ntdll, "NtClose"); + assert(h != INVALID_HANDLE_VALUE); + _NTClose(h); +} + +BOOL +isLoopback(HANDLE tcpFile, TDIEntityID *loop_maybe) +{ + IFEntrySafelySized entryInfo; + NTSTATUS status; + + status = tdiGetMibForIfEntity(tcpFile, loop_maybe, &entryInfo); + + return NT_SUCCESS(status) + && (entryInfo.ent.if_type == IFENT_SOFTWARE_LOOPBACK); +} + +BOOL +isIpEntity(HANDLE tcpFile, TDIEntityID *ent) +{ + return (ent->tei_entity == CL_NL_ENTITY || ent->tei_entity == CO_NL_ENTITY); +} + +NTSTATUS +getNthIpEntity(HANDLE tcpFile, DWORD index, TDIEntityID *ent) +{ + DWORD numEntities = 0; + DWORD numRoutes = 0; + TDIEntityID *entitySet = 0; + NTSTATUS status = tdiGetEntityIDSet(tcpFile, &entitySet, &numEntities); + int i; + + if(!NT_SUCCESS(status)) + return status; + + for(i = 0; i < numEntities; i++) + { + if(isIpEntity(tcpFile, &entitySet[i])) + { + fprintf(stderr, "Entity %d is an IP Entity\n", i); + if(numRoutes == index) + break; + else + numRoutes++; + } + } + + if(numRoutes == index && i < numEntities) + { + fprintf(stderr,"Index %lu is entity #%d - %04lx:%08lx\n", index, i, + entitySet[i].tei_entity, entitySet[i].tei_instance); + memcpy(ent, &entitySet[i], sizeof(*ent)); + tdiFreeThingSet(entitySet); + return 0; + } + else + { + tdiFreeThingSet(entitySet); + return 0xc000001; + } +} + +BOOL +isInterface(TDIEntityID *if_maybe) +{ + return if_maybe->tei_entity == IF_ENTITY; +} + +NTSTATUS +getInterfaceInfoSet(HANDLE tcpFile, IFInfo **infoSet, PDWORD numInterfaces) +{ + DWORD numEntities; + TDIEntityID *entIDSet = NULL; + NTSTATUS status = tdiGetEntityIDSet(tcpFile, &entIDSet, &numEntities); + IFInfo *infoSetInt = 0; + int curInterf = 0, i; + + if(!NT_SUCCESS(status)) + { + fprintf(stderr, "getInterfaceInfoSet: tdiGetEntityIDSet() failed: 0x%lx\n", status); + return status; + } + + infoSetInt = HeapAlloc(GetProcessHeap(), 0, sizeof(IFInfo) * numEntities); + + if(infoSetInt) + { + for(i = 0; i < numEntities; i++) + { + if(isInterface(&entIDSet[i])) + { + infoSetInt[curInterf].entity_id = entIDSet[i]; + status = tdiGetMibForIfEntity(tcpFile, &entIDSet[i], + &infoSetInt[curInterf].if_info); + fprintf(stderr, "tdiGetMibForIfEntity: %08lx\n", status); + if(NT_SUCCESS(status)) + { + DWORD numAddrs; + IPAddrEntry *addrs; + TDIEntityID ip_ent; + int j; + + status = getNthIpEntity(tcpFile, curInterf, &ip_ent); + if(NT_SUCCESS(status)) + status = + tdiGetIpAddrsForIpEntity(tcpFile, &ip_ent, &addrs, &numAddrs); + for(j = 0; NT_SUCCESS(status) && j < numAddrs; j++) + { + fprintf(stderr, "ADDR %d: index %ld (target %ld)\n", j, addrs[j].iae_index, + infoSetInt[curInterf].if_info.ent.if_index); + if(addrs[j].iae_index == infoSetInt[curInterf].if_info.ent.if_index) + { + memcpy(&infoSetInt[curInterf].ip_addr, &addrs[j], + sizeof(addrs[j])); + curInterf++; + break; + } + } + if(NT_SUCCESS(status)) + tdiFreeThingSet(addrs); + } + } + } + + tdiFreeThingSet(entIDSet); + + if(NT_SUCCESS(status)) + { + *infoSet = infoSetInt; + *numInterfaces = curInterf; + } + else + { + HeapFree(GetProcessHeap(), 0, infoSetInt); + } + + return status; + } + else + { + tdiFreeThingSet(entIDSet); + return ((NTSTATUS)0xC000009A); + } +} + +NTSTATUS +getInterfaceInfoByName(HANDLE tcpFile, char *name, IFInfo *info) +{ + IFInfo *ifInfo; + DWORD numInterfaces; + int i; + NTSTATUS status = getInterfaceInfoSet(tcpFile, &ifInfo, &numInterfaces); + + if(NT_SUCCESS(status)) + { + for(i = 0; i < numInterfaces; i++) + { + if(!strcmp((PCHAR)ifInfo[i].if_info.ent.if_descr, name)) + { + memcpy(info, &ifInfo[i], sizeof(*info)); + break; + } + } + + HeapFree(GetProcessHeap(), 0, ifInfo); + + return i < numInterfaces ? 0 : 0xc0000001; + } + + return status; +} + +NTSTATUS +getInterfaceInfoByIndex(HANDLE tcpFile, DWORD index, IFInfo *info) +{ + IFInfo *ifInfo; + DWORD numInterfaces; + NTSTATUS status = getInterfaceInfoSet(tcpFile, &ifInfo, &numInterfaces); + int i; + + if(NT_SUCCESS(status)) + { + for(i = 0; i < numInterfaces; i++) + { + if(ifInfo[i].if_info.ent.if_index == index) + { + memcpy(info, &ifInfo[i], sizeof(*info)); + break; + } + } + + HeapFree(GetProcessHeap(), 0, ifInfo); + + return i < numInterfaces ? 0 : 0xc0000001; + } + + return status; +} + +NTSTATUS +getIPAddrEntryForIf(HANDLE tcpFile, char *name, DWORD index, IFInfo *ifInfo) +{ + NTSTATUS status = name ? getInterfaceInfoByName(tcpFile, name, ifInfo) + : getInterfaceInfoByIndex(tcpFile, index, ifInfo); + + if(!NT_SUCCESS(status)) + { + fprintf(stderr,"getIPAddrEntryForIf returning %lx\n", status); + } + + return status; +} + +InterfaceIndexTable * +getInterfaceIndexTableInt(BOOL nonLoopbackOnly) +{ + DWORD numInterfaces, curInterface = 0; + int i; + IFInfo *ifInfo; + InterfaceIndexTable *ret = 0; + HANDLE tcpFile; + NTSTATUS status = openTcpFile(&tcpFile, FILE_READ_DATA); + + if(NT_SUCCESS(status)) + { + status = getInterfaceInfoSet(tcpFile, &ifInfo, &numInterfaces); + + fprintf(stderr,"InterfaceInfoSet: %08lx, %04lx:%08lx\n", status, + ifInfo->entity_id.tei_entity, ifInfo->entity_id.tei_instance); + + if(NT_SUCCESS(status)) + { + ret = (InterfaceIndexTable *)calloc( + 1, sizeof(InterfaceIndexTable) + (numInterfaces - 1) * sizeof(DWORD)); + + if(ret) + { + ret->numAllocated = numInterfaces; + fprintf(stderr,"NumInterfaces = %ld\n", numInterfaces); + + for(i = 0; i < numInterfaces; i++) + { + fprintf(stderr,"Examining interface %d\n", i); + if(!nonLoopbackOnly || !isLoopback(tcpFile, &ifInfo[i].entity_id)) + { + fprintf(stderr,"Interface %d matches (%ld)\n", i, curInterface); + ret->indexes[curInterface++] = ifInfo[i].if_info.ent.if_index; + } + } + + ret->numIndexes = curInterface; + } + + tdiFreeThingSet(ifInfo); + } + closeTcpFile(tcpFile); + } + + return ret; +} + +InterfaceIndexTable * +getInterfaceIndexTable(void) +{ + return getInterfaceIndexTableInt(FALSE); +} + +#endif + +/* + * We need this in the Microsoft C/C++ port, as we're not using Pthreads, and jeff insists + * on naming the threads at runtime. + * Apparently throwing exception 1080890248 is only visible when running under a machine + * code monitor. + * + * -despair86 30/07/18 + */ +#ifdef _MSC_VER +#include +#define EXCEPTION_SET_THREAD_NAME ((DWORD)0x406D1388) +typedef struct _THREADNAME_INFO +{ + DWORD dwType; /* must be 0x1000 */ + LPCSTR szName; /* pointer to name (in user addr space) */ + DWORD dwThreadID; /* thread ID (-1=caller thread) */ + DWORD dwFlags; /* reserved for future use, must be zero */ +} THREADNAME_INFO; + +void +SetThreadName(DWORD dwThreadID, LPCSTR szThreadName) +{ + THREADNAME_INFO info; + DWORD infosize; + + info.dwType = 0x1000; + info.szName = szThreadName; + info.dwThreadID = dwThreadID; + info.dwFlags = 0; + + infosize = sizeof(info) / sizeof(DWORD); + + __try + { + RaiseException(EXCEPTION_SET_THREAD_NAME, 0, infosize, (DWORD *)&info); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + } +} +#endif \ No newline at end of file diff --git a/llarp/win32_intrnl.h b/llarp/win32_intrnl.h new file mode 100644 index 000000000..616afdd8e --- /dev/null +++ b/llarp/win32_intrnl.h @@ -0,0 +1,111 @@ +#ifndef WIN32_INTRNL_H +#define WIN32_INTRNL_H +/* if yer using Microsoft C++, then downlevel platforms are irrelevant to you */ +#if defined(__MINGW32__) && !defined(_WIN64) +#ifndef NT_SUCCESS +#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) +#endif +#include + +typedef unsigned long ulong; +typedef unsigned short ushort; +typedef unsigned char uchar; +typedef unsigned int uint; + +/* forward declare, each module has their own idea of what this is */ +typedef struct _InterfaceIndexTable InterfaceIndexTable; + +typedef struct IFEntry +{ + ulong if_index; + ulong if_type; + ulong if_mtu; + ulong if_speed; + ulong if_physaddrlen; + uchar if_physaddr[8]; + ulong if_adminstatus; + ulong if_operstatus; + ulong if_lastchange; + ulong if_inoctets; + ulong if_inucastpkts; + ulong if_innucastpkts; + ulong if_indiscards; + ulong if_inerrors; + ulong if_inunknownprotos; + ulong if_outoctets; + ulong if_outucastpkts; + ulong if_outnucastpkts; + ulong if_outdiscards; + ulong if_outerrors; + ulong if_outqlen; + ulong if_descrlen; + uchar if_descr[1]; +} IFEntry; + +typedef struct IPAddrEntry +{ + ulong iae_addr; + ulong iae_index; + ulong iae_mask; + ulong iae_bcastaddr; + ulong iae_reasmsize; + ushort iae_context; + ushort iae_pad; +} IPAddrEntry; + +typedef union _IFEntrySafelySized { + CHAR MaxSize[sizeof(DWORD) + sizeof(IFEntry) + 128 + 1]; + IFEntry ent; +} IFEntrySafelySized; + +#ifndef IFENT_SOFTWARE_LOOPBACK +#define IFENT_SOFTWARE_LOOPBACK 24 /* This is an SNMP constant from rfc1213 */ +#endif /*IFENT_SOFTWARE_LOOPBACK*/ + +/* Encapsulates information about an interface */ +typedef struct _IFInfo +{ + TDIEntityID entity_id; + IFEntrySafelySized if_info; + IPAddrEntry ip_addr; +} IFInfo; + +/* functions */ +NTSTATUS +openTcpFile(PHANDLE tcpFile, ACCESS_MASK DesiredAccess); + +VOID +closeTcpFile(HANDLE h); + +BOOL +isLoopback(HANDLE tcpFile, TDIEntityID* loop_maybe); + +BOOL +isIpEntity(HANDLE tcpFile, TDIEntityID* ent); + +NTSTATUS +getNthIpEntity(HANDLE tcpFile, DWORD index, TDIEntityID* ent); + +BOOL +isInterface(TDIEntityID* if_maybe); + +NTSTATUS +getInterfaceInfoSet(HANDLE tcpFile, IFInfo** infoSet, PDWORD numInterfaces); + +NTSTATUS +getInterfaceInfoByName(HANDLE tcpFile, char* name, IFInfo* info); + +NTSTATUS +getInterfaceInfoByIndex(HANDLE tcpFile, DWORD index, IFInfo* info); + +NTSTATUS +getIPAddrEntryForIf(HANDLE tcpFile, char* name, DWORD index, IFInfo* ifInfo); + +InterfaceIndexTable* +getInterfaceIndexTableInt(BOOL nonLoopbackOnly); + +InterfaceIndexTable* +getInterfaceIndexTable(void); +#endif + +#endif \ No newline at end of file diff --git a/readme.md b/readme.md index ec4d0c9ac..8ac672604 100644 --- a/readme.md +++ b/readme.md @@ -3,31 +3,79 @@ Lokinet is a private, decentralized and Sybil resistant overlay network for the internet, it uses a new routing protocol called LLARP (Low latency anonymous routing protocol) You can learn more about the high level design of LLARP [here](doc/high-level.txt) + And you can read the LLARP protocol specification [here](doc/proto_v0.txt) ## Building + # or your OS or distro's package manager $ sudo apt install build-essential libtool autoconf cmake git $ git clone --recursive https://github.com/loki-project/lokinet-builder $ cd lokinet-builder $ make +## Building on Windows (mingw-w64 native, or wow64/linux/unix cross-compiler) + + #i686 or x86_64 + #if cross-compiling from anywhere other than wow64, export CC and CXX to + #$ARCH-w64-mingw32-g[cc++] respectively + $ pacman -Sy base-devel mingw-w64-$ARCH-toolchain git libtool autoconf cmake + $ git clone --recursive https://github.com/loki-project/lokinet-builder + $ cd lokinet-builder + $ make ensure sodium + $ cd build + $ cmake ../deps/llarp -DSODIUM_LIBRARIES=./prefix/lib/libsodium.a -DSODIUM_INCLUDE_DIR=./prefix/include -G "Unix Makefiles" -DHAVE_CXX17_FILESYSTEM=ON + $ make + $ cp llarpd ../lokinet.exe + +## Building on Windows using Microsoft C/C++ (Visual Studio 2017) + +* clone https://github.com/loki-project/lokinet-builder from git-bash or whatever git browser you use +* open `%CLONE_PATH%/lokinet-builder/deps/sodium/builds/msvc/vs2017/libsodium.sln` and build one of the targets +* create a `build` folder in `%CLONE_PATH%/lokinet-builder` +* run cmake-gui from `%CLONE_PATH%/lokinet-builder/deps/llarp` as the source directory + * define `SODIUM_LIB` to `%CLONE_PATH%/lokinet-builder/deps/sodium/bin/win32/%CONFIG%/%TOOLSET%/%TARGET%/libsodium.lib` + * define `SODIUM_INCLUDE_DIR` to `%CLONE_PATH%/lokinet-builder/deps/sodium/src/libsodium/include` + * define `HAVE_CXX17_FILESYSTEM` to `TRUE` + * select `Visual Studio 2017 15 %ARCH%` as the generator + * enter a custom toolset if desired (usually `v141_xp`) +* generate the developer studio project files and open in the IDE +* select a configuration +* press F7 to build everything + ## Running $ ./lokinet +or press `Debug`/`Local Windows Debugger` in the visual studio standard toolbar + ### Development -Please note development builds are likely to be unstable +Please note development builds are likely to be unstable. -Build requirements: +##### Build requirements: * CMake -* ninja -* libsodium >= 1.0.14 +* ninja (for unit testing with Google Tests) +* libsodium >= 1.0.14 (included here) * c++ 11 capable C++ compiler +* if you have C++17 `` or `` declared and defined in your platform's C++ toolchain, re-run CMake (in `lokinet-builder/build`) with `-DHAVE_CXX17_FILESYSTEM=ON`. +* since each platform seems to have its own idea of where `std::[experimental::]filesystem` is defined, you will need to manually specify its library in `LDFLAGS` or `CMAKE_x_LINKER_FLAGS` as well. + +##### Windows: +* Mingw-w64 is recommended for 32 or 64-bit builds. +* It *is* possible to compile with Microsoft C++ (v19 or later from VS2015+). +* `cpp17::filesystem` in `vendor/cppbackport-master` is not available for Windows. + +#### Boxed warning +
+

Inbound sessions are unsupported on Windows Server systems.

+

Ignore this warning at your own peril.

+
-Building a debug build: +##### Building a debug build: + #in lokinet-builder/ + $ cd build $ make \ No newline at end of file diff --git a/vendor/cppbackport-master/lib/filesystem.h b/vendor/cppbackport-master/lib/filesystem.h index 8b96f9a09..9d925f2a0 100644 --- a/vendor/cppbackport-master/lib/filesystem.h +++ b/vendor/cppbackport-master/lib/filesystem.h @@ -30,18 +30,21 @@ #ifndef PBL_CPP_FILESYSTEM_H #define PBL_CPP_FILESYSTEM_H -#include "version.h" +#if _MSC_VER >= 1910 +#define CPP17 +#define CPP11 +#define CPP14 +#endif -// linux gcc 7.2 has CPP17 but doesn't have filesystem.h -#if defined(CPP17) && !defined(__OpenBSD__) && __has_include() +#include "version.h" -#if defined(__MINGW32__) -// mingw32 needs experimental +#if defined(CPP17) && defined(USE_CXX17_FILESYSTEM) +#if defined(__MINGW32__) || defined(_MSC_VER) +// win32 needs experimental #include #else #include #endif - #else // OpenBSD needs this // MacOS llvm 3.8 needs this @@ -61,6 +64,6 @@ #include "fs/remove.h" #include "fs/rename.h" #include "fs/tempdir.h" -#endif // if not cpp17 and not openbsd +#endif // if not cpp17 and not openbsd #endif // PBL_CPP_FILESYSTEM_H diff --git a/vendor/cppbackport-master/lib/fs/filestatus.cpp b/vendor/cppbackport-master/lib/fs/filestatus.cpp index 3477138c3..dcece95b1 100644 --- a/vendor/cppbackport-master/lib/fs/filestatus.cpp +++ b/vendor/cppbackport-master/lib/fs/filestatus.cpp @@ -64,7 +64,8 @@ namespace { t = file_type::fifo; } - else if ( S_ISLNK(m) ) +#ifndef _WIN32 // these only work on cygnus or msys2! + else if(S_ISLNK(m)) { t = file_type::symlink; } @@ -72,9 +73,8 @@ namespace { t = file_type::socket; } - +#endif return ::cpp17::filesystem::file_status(t, p); - } } @@ -156,13 +156,15 @@ file_status symlink_status(const path& path_) if ( !path_.empty() ) { struct stat st; - - if ( ::lstat(path_.c_str(), &st) == 0 ) +#ifndef _WIN32 + if(::lstat(path_.c_str(), &st) == 0) +#else + if(::stat(path_.c_str(), &st) == 0) +#endif { return from_mode_t(st.st_mode); } } - return file_status(); }