This commit is contained in:
Ryan Tharp 2018-10-02 23:11:44 +00:00
commit 4b3b09736b
52 changed files with 2744 additions and 3657 deletions

View File

@ -13,22 +13,14 @@ endmacro(add_cxxflags)
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
if (MSVC)
CHECK_CXX_COMPILER_FLAG("/std:c++17" COMPILER_SUPPORTS_CXX17)
else()
CHECK_CXX_COMPILER_FLAG("-std=c++17" COMPILER_SUPPORTS_CXX17)
endif()
option(HAVE_CXX17_FILESYSTEM "Disable if your C++ compiler and runtime library lacks std::[experimental::]filesystem" ON)
if(COMPILER_SUPPORTS_CXX11 AND NOT HAVE_CXX17_FILESYSTEM)
add_cxxflags("-std=c++11")
elseif(COMPILER_SUPPORTS_CXX17 AND HAVE_CXX17_FILESYSTEM)
if (MSVC)
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.")
@ -36,30 +28,26 @@ endif()
add_cxxflags("-fpermissive")
if (WOW64_CROSS_COMPILE OR WIN64_CROSS_COMPILE)
if (USING_CLANG)
add_cxxflags("-Wno-unused-command-line-argument -Wno-c++11-narrowing")
add_cflags("-Wno-unused-command-line-argument")
# because clang is insane enough to inline whole sections of the C++ library!
# May have been fixed in llvm-7.
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--allow-multiple-definition --rtlib=libgcc")
endif(USING_CLANG)
endif()
if(DEBIAN)
add_definitions(-DDEBIAN)
endif()
if(ANDROID)
set(THREAD_LIB "-pthread")
# finally removed pthread dependency for MSC++
elseif(MSVC)
set(THREAD_LIB)
else()
set(THREAD_LIB pthread)
endif()
if(MSVC)
option (BUILD_AVX2 "Enable AVX2 FPU vector instructions." OFF)
if (BUILD_AVX2)
add_cflags("/arch:AVX2")
add_cxxflags("/arch:AVX2")
else()
add_cflags("/arch:SSE2")
add_cxxflags("/arch:SSE2")
endif(BUILD_AVX2)
endif()
if(STATIC_LINK)
add_cflags("-static -Wl,--whole-archive -lpthread -Wl,--no-whole-archive")
add_cxxflags("-static -Wl,--whole-archive -lpthread -Wl,--no-whole-archive")
@ -75,18 +63,11 @@ else()
set(WITH_STATIC ON)
endif()
if (NOT MSVC)
add_cflags("-Wall")
add_cxxflags("-Wall")
endif()
if (MSVC)
set(OPTIMIZE_FLAGS "-Od")
set(DEBUG_FLAGS "-ZI")
else()
set(OPTIMIZE_FLAGS "-O0")
set(DEBUG_FLAGS "-g")
endif()
set(OPTIMIZE_FLAGS "-O3")
set(DEBUG_FLAGS "-O0 -g3")
if(ASAN)
set(DEBUG_FLAGS "${DEBUG_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
@ -112,19 +93,15 @@ if(SHADOW)
include_directories(${SHADOW_ROOT}/include)
endif()
if (MSVC)
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]")
set(OPTIMIZE_FLAGS "")
add_cflags("${DEBUG_FLAGS}")
add_cxxflags("${DEBUG_FLAGS}")
endif()
add_cflags("-Wall -Wno-deprecated-declarations ${OPTIMIZE_FLAGS}")
add_cxxflags("-Wall -Wno-deprecated-declarations ${OPTIMIZE_FLAGS}")
if(SHADOW)
add_cflags("-fPIC")
add_cxxflags("-fPIC")
@ -156,6 +133,11 @@ else()
)
endif()
# HeapAlloc(2) on Windows was significantly revamped in 2009
# but the old algorithm isn't too bad either
# this is _the_ system allocator on BSD UNIX
# openbsd replaced it with a secure/randomised malloc not too
# long ago
if(JEMALLOC)
set(MALLOC_LIB jemalloc)
endif()
@ -210,16 +192,12 @@ set(LIBTUNTAP_SRC_BASE
${LIBTUNTAP_IMPL})
if (UNIX)
set(LIBTUNTAP_SRC
set(LIBTUNTAP_SRC
${TT_ROOT}/tuntap-unix.c
${LIBTUNTAP_SRC_BASE})
endif()
#if(BACKPORT)
#else()
#set(CPP_BACKPORT_SRC "")
#endif()
else()
set(LIBTUNTAP_SRC ${LIBTUNTAP_SRC_BASE})
endif(UNIX)
set(CPP_BACKPORT_SRC
vendor/cppbackport-master/lib/fs/rename.cpp
vendor/cppbackport-master/lib/fs/filestatus.cpp
@ -248,7 +226,6 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set(ISOLATE_PROC_SRC llarp/linux/netns.cpp)
endif()
set(LIB_PLATFORM_SRC
# for outpug
llarp/logger.cpp
@ -270,11 +247,9 @@ set(LIB_PLATFORM_SRC
${ISOLATE_PROC_SRC}
# tun
${LIBTUNTAP_SRC}
# win32 inline procs
# win32 inline code
llarp/win32_inet.c
llarp/win32_intrnl.c
contrib/msc/getopt.c
contrib/msc/getopt1.c
)
set(NTRU_AVX_SRC
@ -332,7 +307,6 @@ set(UTP_SRC
libutp/utp_hash.cpp
)
if(WIN32)
set(UTP_SRC ${UTP_SRC} libutp/libutp_inet_ntop.cpp)
endif()
@ -456,10 +430,6 @@ include_directories(vendor/cppbackport-master/lib)
include_directories(/usr/local/include)
include_directories(${sodium_INCLUDE_DIR})
if (MSVC)
include_directories(contrib/msc/include)
endif()
set(RC_EXE rcutil)
set(DNS_EXE dns)
@ -469,22 +439,14 @@ add_shadow_plugin(shadow-plugin-${SHARED_LIB} ${EXE_SRC} ${LIB_SRC} ${LIB_PLATFO
target_link_libraries(shadow-plugin-${SHARED_LIB} ${LIBS})
install(TARGETS shadow-plugin-${SHARED_LIB} DESTINATION plugins)
else()
add_executable(${RC_EXE} ${RC_SRC})
add_executable(${RC_EXE} ${RC_SRC})
add_executable(${EXE} ${EXE_SRC})
add_executable(${CLIENT_EXE} ${CLIENT_SRC})
add_executable(${DNS_EXE} ${DNS_SRC})
add_executable(${DNS_EXE} ${DNS_SRC})
add_subdirectory(${GTEST_DIR})
include_directories(${GTEST_DIR}/include ${GTEST_DIR})
add_executable(${TEST_EXE} ${TEST_SRC})
if (MSVC)
target_link_libraries(${TEST_EXE} ${STATIC_LINK_LIBS} gtest_main ${STATIC_LIB} ws2_32 iphlpapi)
elseif (MINGW)
target_link_libraries(${TEST_EXE} ${STATIC_LINK_LIBS} gtest_main ${STATIC_LIB} stdc++fs iphlpapi ws2_32)
else()
target_link_libraries(${TEST_EXE} ${STATIC_LINK_LIBS} gtest_main ${STATIC_LIB})
endif(MSVC)
if(WITH_STATIC)
add_library(${STATIC_LIB} STATIC ${LIB_SRC})
if(NOT HAVE_CXX17_FILESYSTEM)
@ -505,34 +467,28 @@ if(WITH_STATIC)
target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${BACKPORT_LIB} ${PLATFORM_LIB})
target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${BACKPORT_LIB} ${PLATFORM_LIB})
target_link_libraries(${RC_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${BACKPORT_LIB} ${PLATFORM_LIB})
if (MINGW)
target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${BACKPORT_LIB} ${PLATFORM_LIB} ws2_32 stdc++fs iphlpapi)
target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${BACKPORT_LIB} ${PLATFORM_LIB} ws2_32 stdc++fs iphlpapi)
target_link_libraries(${RC_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${BACKPORT_LIB} ${PLATFORM_LIB} ws2_32 stdc++fs iphlpapi)
elseif(MSVC)
target_link_libraries(${TEST_EXE} ${STATIC_LINK_LIBS} gtest_main ${STATIC_LIB} ${BACKPORT_LIB} ${PLATFORM_LIB})
if (WIN32)
target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${BACKPORT_LIB} ${PLATFORM_LIB} ws2_32 iphlpapi)
target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${BACKPORT_LIB} ${PLATFORM_LIB} ws2_32 iphlpapi)
target_link_libraries(${RC_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${BACKPORT_LIB} ${PLATFORM_LIB} ws2_32 iphlpapi)
endif(MINGW)
target_link_libraries(${TEST_EXE} ${STATIC_LINK_LIBS} gtest_main ${STATIC_LIB} ${BACKPORT_LIB} ${PLATFORM_LIB} ws2_32 iphlpapi)
endif(WIN32)
else()
target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB})
target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB})
target_link_libraries(${RC_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB})
if (MINGW)
target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB} ws2_32 stdc++fs iphlpapi)
target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB} ws2_32 stdc++fs iphlpapi)
target_link_libraries(${RC_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB} ws2_32 stdc++fs iphlpapi)
elseif(MSVC)
target_link_libraries(${TEST_EXE} ${STATIC_LINK_LIBS} gtest_main ${STATIC_LIB} ${PLATFORM_LIB})
if (WIN32)
target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB} ws2_32 iphlpapi)
target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB} ws2_32 iphlpapi)
target_link_libraries(${RC_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB} ws2_32 iphlpapi)
endif(MINGW)
target_link_libraries(${TEST_EXE} ${STATIC_LINK_LIBS} gtest_main ${STATIC_LIB} ${PLATFORM_LIB} ws2_32 iphlpapi)
endif(WIN32)
endif(NOT HAVE_CXX17_FILESYSTEM)
if (MINGW)
target_link_libraries(${DNS_EXE} ${STATIC_LIB} ${PLATFORM_LIB} ${THREAD_LIB} ws2_32 stdc++fs iphlpapi)
elseif(WIN32)
if (WIN32)
target_link_libraries(${DNS_EXE} ${STATIC_LIB} ${PLATFORM_LIB} ${THREAD_LIB} ws2_32 iphlpapi)
endif(MINGW)
endif(WIN32)
target_link_libraries(${DNS_EXE} ${STATIC_LIB} ${PLATFORM_LIB} ${THREAD_LIB})
endif(NOT WITH_SHARED)
endif(WITH_STATIC)
@ -546,11 +502,9 @@ if(WITH_STATIC)
set(LIB_SRC ${LIB_SRC} ${CPP_BACKPORT_SRC})
endif(HAVE_CXX17_FILESYSTEM)
add_library(${SHARED_LIB} SHARED ${LIB_SRC} ${LIB_PLATFORM_SRC})
if (MINGW)
set(${LIBS} ${LIBS} ws2_32 stdc++fs iphlpapi)
elseif(MSVC)
if (WIN32)
set(${LIBS} ${LIBS} ws2_32 iphlpapi)
endif(MINGW)
endif(WIN32)
target_link_libraries(${SHARED_LIB} ${LIBS} ${THREAD_LIB})
target_link_libraries(${EXE} ${SHARED_LIB})
target_link_libraries(${RC_EXE} ${SHARED_LIB})

File diff suppressed because it is too large Load Diff

View File

@ -1,190 +0,0 @@
#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 <config.h>
#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 <stdio.h>
/* 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 <gnu-versions.h>
#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 <stdlib.h>
#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 <stdio.h>
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 */

View File

@ -1,157 +0,0 @@
#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 */

View File

@ -4,7 +4,9 @@
#include <getopt.h>
#include <string>
#include <iostream>
#ifndef _MSC_VER
#include <libgen.h>
#endif
#include "fs.hpp"
#include "config.hpp" // for ensure_config
@ -29,6 +31,25 @@ printHelp(const char *argv0, int code = 1)
return code;
}
#ifdef _WIN32
int
startWinsock()
{
WSADATA wsockd;
int err;
// We used to defer starting winsock until
// we got to the iocp event loop
// but getaddrinfo(3) requires that winsock be in core already
err = ::WSAStartup(MAKEWORD(2, 2), &wsockd);
if(err)
{
perror("Failed to start Windows Sockets");
return err;
}
return 0;
}
#endif
int
main(int argc, char *argv[])
{
@ -39,6 +60,11 @@ main(int argc, char *argv[])
multiThreaded = false;
}
#ifdef _WIN32
if(startWinsock())
return -1;
#endif
int opt = 0;
bool genconfigOnly = false;
bool asRouter = true;
@ -106,7 +132,9 @@ main(int argc, char *argv[])
fs::path fpath = basepath / "lokinet.ini";
std::error_code ec;
if(!fs::create_directories(basepath, ec))
// These paths are guaranteed to exist - $APPDATA or $HOME
// so only create .lokinet/*
if(!fs::create_directory(basepath, ec))
{
if(ec)
{
@ -136,6 +164,9 @@ main(int argc, char *argv[])
code = llarp_main_run(ctx);
llarp_main_free(ctx);
}
#ifdef _WIN32
::WSACleanup();
#endif
exit(code);
return code;
}

View File

@ -7,7 +7,9 @@
#include <string>
#include <vector>
#ifndef _WIN32
#include <sys/socket.h>
#endif
#include <llarp/net.hpp> // for llarp::Addr

View File

@ -5,13 +5,13 @@
#include <llarp/net.hpp>
#ifndef _WIN32
// unix, linux
#include <sys/types.h> // FreeBSD needs this for uchar for ip.h
#include <netinet/in.h>
#include <netinet/ip.h>
#else
// windows nt
#include <winsock2.h>
// Apparently this does not seem to be located _anywhere_ in the windows sdk???
// -despair86
typedef struct ip_hdr
{
unsigned char
@ -46,16 +46,7 @@ typedef struct ip_hdr
#include <memory>
#if !defined(__linux__) && !defined(_WIN32) && !defined(__APPLE__) \
&& !defined(__FreeBSD__)
#define iphdr ip
#define saddr ip_src.s_addr
#define daddr ip_dst.s_addr
#define ip_version ip_v
#define check ip_sum
#define ihl ip_hl
#endif
// anything not win32
struct ip_header
{
#if __BYTE_ORDER == __LITTLE_ENDIAN

View File

@ -10,9 +10,16 @@
#include <stdlib.h> // for itoa
// for addrinfo
#ifndef _WIN32
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#else
#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
#define inet_aton(x, y) inet_pton(AF_INET, x, y)
#endif
bool
operator==(const sockaddr& a, const sockaddr& b);
@ -466,7 +473,7 @@ namespace llarp
isOneSevenPrivate(uint32_t byte)
{
uint8_t byte1 = byte >> 24 & 0xff;
uint8_t byte2 = (0x00ff0000 & byte >> 16);
uint8_t byte2 = (0x00ff0000 & byte) >> 16;
return byte1 == 172 && (byte2 >= 16 || byte2 <= 31);
}
@ -474,7 +481,7 @@ namespace llarp
isOneNinePrivate(uint32_t byte)
{
uint8_t byte1 = byte >> 24 & 0xff;
uint8_t byte2 = (0x00ff0000 & byte >> 16);
uint8_t byte2 = (0x00ff0000 & byte) >> 16;
return byte1 == 192 && byte2 == 168;
}

View File

@ -136,6 +136,11 @@ namespace llarp
llarp_time_t lifetime = DEFAULT_PATH_LIFETIME;
llarp_proto_version_t version;
bool IsEndpoint(const RouterID & us) const
{
return info.upstream == us;
}
llarp_time_t
ExpireTime() const;
llarp::routing::InboundMessageParser m_MessageParser;

View File

@ -113,6 +113,12 @@ namespace llarp
Path*
GetPathByID(const PathID_t& id) const;
bool
GetCurrentIntroductionsWithFilter(
std::set< llarp::service::Introduction >& intros,
std::function< bool(const llarp::service::Introduction&) > filter)
const;
bool
GetCurrentIntroductions(
std::set< llarp::service::Introduction >& intros) const;

View File

@ -10,6 +10,7 @@
#include <llarp/service/tag.hpp>
#include <vector>
#include <algorithm>
namespace llarp
{
@ -60,6 +61,7 @@ namespace llarp
IntroSet&
operator=(const IntroSet& other)
{
I.clear();
A = other.A;
I = other.I;
K = other.K;

View File

@ -31,6 +31,9 @@ namespace llarp
llarp_tun_io *
getRange();
bool
AddDefaultEndpoint(const std::string & ifaddr, const std::string & ifname);
/// hint at possible path usage and trigger building early
bool
Prefetch(const llarp::service::Address &addr);

View File

@ -187,6 +187,7 @@ namespace llarp
llarp::SharedSecret sharedKey;
ServiceInfo remoteIdent;
Introduction remoteIntro;
ConvoTag currentConvoTag;
PathSet* m_PathSet;
IDataHandler* m_DataHandler;
Endpoint* m_Endpoint;
@ -351,7 +352,7 @@ namespace llarp
protected:
void
RegenAndPublishIntroSet(llarp_time_t now);
RegenAndPublishIntroSet(llarp_time_t now, bool forceRebuild = false);
IServiceLookup*
GenerateLookupByTag(const Tag& tag);

View File

@ -32,7 +32,7 @@ namespace llarp
/// determine if this request has timed out
bool
IsTimedOut(llarp_time_t now, llarp_time_t timeout = 5000) const
IsTimedOut(llarp_time_t now, llarp_time_t timeout = 10000) const
{
if(now <= m_created)
return false;

View File

@ -92,7 +92,7 @@ typedef struct in6_addr t_tun_in6_addr;
* Windows helpers
*/
#if defined Windows
#define strncat(x, y, z) strncat_s((x), _countof(x), (y), (z));
//#define strncat(x, y, z) strncat_s((x), _countof(x), (y), (z));
#define strdup(x) _strdup(x)
#endif
@ -119,10 +119,12 @@ typedef struct in6_addr t_tun_in6_addr;
/* Handle Windows symbols export */
#if defined Windows
#if defined(tuntap_EXPORTS) /* CMake generated goo */
#if defined(tuntap_EXPORTS) && defined(_USRDLL) /* CMake generated goo */
#define TUNTAP_EXPORT __declspec(dllexport)
#else
#elif defined(tuntap_EXPORTS)
#define TUNTAP_EXPORT __declspec(dllimport)
#else
#define TUNTAP_EXPORT extern
#endif
#else /* Unix */
#define TUNTAP_EXPORT extern

View File

@ -30,19 +30,21 @@
// we already have our own definition of these
// -despair
namespace {
extern "C" {
const char* inet_ntop(int af, const void *src, char *dst, size_t size);
int inet_pton(int af, const char *src, void *dst);
}
}
//######################################################################
const char *libutp::inet_ntop(int af, const void *src, char *dest, size_t length)
{
return inet_ntop(af, src, dest, length);
return ::inet_ntop(af, src, dest, length);
}
//######################################################################
int libutp::inet_pton(int af, const char* src, void* dest)
{
return inet_pton(af, src, dest);
return ::inet_pton(af, src, dest);
}

View File

@ -4,7 +4,7 @@
bool
bencode_write_bytestring(llarp_buffer_t* buff, const void* data, size_t sz)
{
if(!llarp_buffer_writef(buff, "%ld:", sz))
if(!llarp_buffer_writef(buff, "%zu:", sz))
return false;
return llarp_buffer_write(buff, data, sz);
}
@ -12,7 +12,7 @@ bencode_write_bytestring(llarp_buffer_t* buff, const void* data, size_t sz)
bool
bencode_write_uint64(llarp_buffer_t* buff, uint64_t i)
{
return llarp_buffer_writef(buff, "i%lu", i)
return llarp_buffer_writef(buff, "i%llu", i)
&& llarp_buffer_write(buff, "e", 1);
}
@ -59,7 +59,7 @@ bencode_read_integer(struct llarp_buffer_t* buffer, uint64_t* result)
buffer->cur++;
numbuf[len] = 0;
*result = strtoul(numbuf, nullptr, 10);
*result = strtoull(numbuf, nullptr, 10);
return true;
}

View File

@ -65,7 +65,11 @@ llarp_ensure_config(const char *fname, const char *basedir, bool overwrite,
if(basedir)
{
basepath = basedir;
#ifndef _WIN32
basepath += "/";
#else
basepath += "\\";
#endif
}
// abort if client.ini already exists
@ -94,7 +98,7 @@ llarp_ensure_config(const char *fname, const char *basedir, bool overwrite,
llarp_generic_ensure_config(f, basepath);
if(asRouter)
{
llarp_ensure_router_config(f);
llarp_ensure_router_config(f, basepath);
}
else
{
@ -164,24 +168,41 @@ llarp_generic_ensure_config(std::ofstream &f, std::string basepath)
}
void
llarp_ensure_router_config(std::ofstream &f)
llarp_ensure_router_config(std::ofstream &f, std::string basepath)
{
f << "# ROUTERS ONLY: router settings block" << std::endl;
f << "# router settings block" << std::endl;
f << "[router]" << std::endl;
f << "# uncomment these to manually set public address and port" << std::endl;
f << "# uncomment these to manually set public address and port"
<< std::endl;
f << "# this is required on providers like AWS because of their firewall "
"rules"
<< std::endl;
f << "# public-address=your.ip.goes.here" << std::endl;
f << "# public-port=1090" << std::endl;
f << std::endl;
f << "# number of crypto worker threads " << std::endl;
f << "threads=4" << std::endl;
f << "# path to store signed RC" << std::endl;
f << "contact-file=" << basepath << "self.signed" << std::endl;
f << "# path to store transport private key" << std::endl;
f << "transport-privkey=" << basepath << "transport.private" << std::endl;
f << "# path to store identity signing key" << std::endl;
f << "ident-privkey=" << basepath << "identity.private" << std::endl;
f << "# encryption key for onion routing" << std::endl;
f << "encryption-privkey=" << basepath << "encryption.private" << std::endl;
f << std::endl;
f << "# uncomment following line to set router nickname to 'lokinet'"
<< std::endl;
f << "# nickname=lokinet" << std::endl;
f << std::endl << std::endl;
f << "# ROUTERS ONLY: publish network interfaces for handling inbound traffic"
<< std::endl;
f << "[bind]" << std::endl;
// get ifname
std::string ifname;
if(llarp::GetBestNetIF(ifname, AF_INET))
f << ifname << "=1090" << std::endl;
else
@ -195,17 +216,32 @@ bool
llarp_ensure_client_config(std::ofstream &f, std::string basepath)
{
f << "# ROUTERS ONLY: router settings block" << std::endl;
f << "# router settings block" << std::endl;
f << "[router]" << std::endl;
f << "# uncomment these to manually set public address and port" << std::endl;
f << "# uncomment these to manually set public address and port"
<< std::endl;
f << "# this is required on providers like AWS because of their firewall "
"rules"
<< std::endl;
f << "# public-address=your.ip.goes.here" << std::endl;
f << "# public-port=1090" << std::endl;
f << "#public-address=your.ip.goes.here" << std::endl;
f << "#public-port=1090" << std::endl;
f << std::endl;
f << "# ROUTERS ONLY: publish network interfaces for handling inbound traffic"
f << "# number of crypto worker threads " << std::endl;
f << "#threads=4" << std::endl;
f << "# path to store signed RC" << std::endl;
f << "#contact-file=" << basepath << "self.signed" << std::endl;
f << "# path to store transport private key" << std::endl;
f << "#transport-privkey=" << basepath << "transport.private" << std::endl;
f << "# path to store identity signing key" << std::endl;
f << "#ident-privkey=" << basepath << "identity.private" << std::endl;
f << "# encryption key for onion routing" << std::endl;
f << "#encryption-privkey=" << basepath << "encryption.private" << std::endl;
f << std::endl;
f << "# uncomment following line to set router nickname to 'lokinet'"
<< std::endl;
f << "#nickname=lokinet" << std::endl;
f << std::endl << std::endl;
f << "[bind]" << std::endl;
std::string ifname;
@ -220,6 +256,13 @@ llarp_ensure_client_config(std::ofstream &f, std::string basepath)
f << "client=" << basepath << "client.ini" << std::endl;
f << std::endl;
f << "# network settings " << std::endl;
f << "[network]" << std::endl;
#ifndef __linux__
f << "# ";
#endif
/*
// done with fname.ini
// start client.ini
// write fname ini
@ -231,6 +274,7 @@ llarp_ensure_client_config(std::ofstream &f, std::string basepath)
}
clientini_f << "[client-hidden-service-name]" << std::endl;
clientini_f << "keyfile=client-keyfile.private" << std::endl;
*/
// pick ip
struct privatesInUse ifsInUse = llarp_getPrivateIfs();
@ -255,7 +299,7 @@ llarp_ensure_client_config(std::ofstream &f, std::string basepath)
}
llarp::LogDebug("Detected " + ip
+ " is available for use, configuring as such");
clientini_f << "ifaddr=" << ip << std::endl;
//clientini_f << "ifaddr=" << ip << std::endl;
// pick interface name
uint8_t num = 0;
while(num < 255)
@ -276,12 +320,18 @@ llarp_ensure_client_config(std::ofstream &f, std::string basepath)
llarp::LogError("Could not find any free lokitun interface names");
return false;
}
/*
clientini_f << "ifname=lokinum" << std::to_string(num) << std::endl;
// prefetch-tags=test
// enable netns?
llarp::LogInfo("Generated hidden service client as " + basepath
+ "client.ini");
*/
f << "ifname=lokinum" << std::to_string(num) << std::endl;
f << "ifaddr=" << ip << std::endl;
return true;
}

View File

@ -45,7 +45,7 @@ void
llarp_generic_ensure_config(std::ofstream &f, std::string basepath);
void
llarp_ensure_router_config(std::ofstream &f);
llarp_ensure_router_config(std::ofstream &f, std::string basepath);
bool
llarp_ensure_client_config(std::ofstream &f, std::string basepath);

View File

@ -471,8 +471,8 @@ raw_resolve_host(struct dnsc_context *dnsc, const char *url,
llarp::LogInfo("Waiting for recv");
// Timeout?
ret = recvfrom(sockfd, buffer, DNC_BUF_SIZE, 0, (struct sockaddr *)&addr,
&size);
ret = recvfrom(sockfd, (char *)buffer, DNC_BUF_SIZE, 0,
(struct sockaddr *)&addr, &size);
llarp::LogInfo("recv done ", size);
if(ret < 0)
{

View File

@ -121,5 +121,5 @@ bool
llarp_ev_tun_async_write(struct llarp_tun_io *tun, const void *pkt, size_t sz)
{
// TODO: queue write
return static_cast< llarp::ev_io * >(tun->impl)->do_write((void*)pkt, sz);
return static_cast< llarp::ev_io * >(tun->impl)->do_write((void *)pkt, sz);
}

View File

@ -1,8 +1,10 @@
#ifndef LLARP_EV_HPP
#define LLARP_EV_HPP
#include <llarp/ev.h>
// witev
// writev
#ifndef _WIN32
#include <sys/uio.h>
#endif
#ifndef _MSC_VER
#include <unistd.h>
@ -42,104 +44,98 @@ namespace llarp
sendto(const sockaddr* dst, const void* data, size_t sz) = 0;
/// used for tun interface
bool
virtual bool
do_write(void* data, size_t sz)
{
iovec vecs[2];
// TODO: IPV6
uint32_t t = htonl(AF_INET);
vecs[0].iov_base = &t;
vecs[0].iov_len = sizeof(t);
vecs[1].iov_base = data;
vecs[1].iov_len = sz;
return writev(fd, vecs, 2) != -1;
#ifndef _WIN32
return write(fd, data, sz) != -1;
#else
return WriteFile((void*)fd, data, sz, nullptr, nullptr);
#endif
}
/// called in event loop when fd is ready for writing
/// requeues anything not written
/// this assumes fd is set to non blocking
virtual void
flush_write()
{
m_writeq.Process([&](WriteBuffer& buffer) {
// todo: wtf???
#ifndef _WIN32
do_write(buffer.buf, buffer.bufsz);
// if we would block we save the entries for later
// discard entry
#else
// writefile
/// called in event loop when fd is ready for writing
/// requeues anything not written
/// this assumes fd is set to non blocking
virtual void
flush_write()
{
m_writeq.Process([&](WriteBuffer& buffer) {
do_write(buffer.buf, buffer.bufsz);
// if we would block we save the entries for later
// discard entry
});
/// reset errno
errno = 0;
#if _WIN32
SetLastError(0);
#endif
});
/// reset errno
errno = 0;
}
struct WriteBuffer
{
llarp_time_t timestamp = 0;
size_t bufsz;
byte_t buf[1500];
WriteBuffer() = default;
WriteBuffer(const void* ptr, size_t sz)
{
if(sz <= sizeof(buf))
{
bufsz = sz;
memcpy(buf, ptr, bufsz);
}
else
bufsz = 0;
}
struct WriteBuffer
struct GetTime
{
llarp_time_t
operator()(const WriteBuffer& w) const
{
llarp_time_t timestamp = 0;
size_t bufsz;
byte_t buf[1500];
WriteBuffer() = default;
WriteBuffer(const void* ptr, size_t sz)
{
if(sz <= sizeof(buf))
{
bufsz = sz;
memcpy(buf, ptr, bufsz);
}
else
bufsz = 0;
}
struct GetTime
{
llarp_time_t
operator()(const WriteBuffer& w) const
{
return w.timestamp;
}
};
struct PutTime
{
void
operator()(WriteBuffer& w) const
{
w.timestamp = llarp_time_now_ms();
}
};
struct Compare
{
bool
operator()(const WriteBuffer& left, const WriteBuffer& right) const
{
return left.timestamp < right.timestamp;
}
};
};
llarp::util::CoDelQueue< WriteBuffer, WriteBuffer::GetTime,
WriteBuffer::PutTime, WriteBuffer::Compare,
llarp::util::NullMutex, llarp::util::NullLock >
m_writeq;
virtual ~ev_io()
{
#ifndef _WIN32
::close(fd);
#else
closesocket(fd);
#endif
};
return w.timestamp;
}
};
}; // namespace llarp
struct PutTime
{
void
operator()(WriteBuffer& w) const
{
w.timestamp = llarp_time_now_ms();
}
};
struct Compare
{
bool
operator()(const WriteBuffer& left, const WriteBuffer& right) const
{
return left.timestamp < right.timestamp;
}
};
};
llarp::util::CoDelQueue< WriteBuffer, WriteBuffer::GetTime,
WriteBuffer::PutTime, WriteBuffer::Compare,
llarp::util::NullMutex, llarp::util::NullLock >
m_writeq;
virtual ~ev_io()
{
#ifndef _WIN32
::close(fd);
#else
closesocket(fd);
#endif
};
}
;
}
; // namespace llarp
struct llarp_ev_loop
{

View File

@ -96,10 +96,10 @@ namespace llarp
read(void* buf, size_t sz)
{
ssize_t ret = tuntap_read(tunif, buf, sz);
if(ret > 4 && t->recvpkt)
if(ret > 0 && t->recvpkt)
{
// don't include packet info
t->recvpkt(t, ((byte_t*)buf) + 4, ret - 4);
// does not have pktinfo
t->recvpkt(t, buf, ret);
}
return ret;
}

View File

@ -94,6 +94,19 @@ namespace llarp
return -1;
}
bool
do_write(void* buf, size_t sz)
{
iovec vecs[2];
// TODO: IPV6
uint32_t t = htonl(AF_INET);
vecs[0].iov_base = &t;
vecs[0].iov_len = sizeof(t);
vecs[1].iov_base = buf;
vecs[1].iov_len = sz;
return writev(fd, vecs, 2) != -1;
}
void
flush_write()
{
@ -109,7 +122,7 @@ namespace llarp
{
ssize_t ret = tuntap_read(tunif, buf, sz);
if(ret > 4 && t->recvpkt)
t->recvpkt(t, ((byte_t *)buf) + 4, ret - 4);
t->recvpkt(t, ((byte_t*)buf) + 4, ret - 4);
return ret;
}

View File

@ -85,6 +85,80 @@ namespace llarp
return 0;
}
};
struct tun : public ev_io
{
llarp_tun_io* t;
device* tunif;
tun(llarp_tun_io* tio)
: ev_io(-1)
, t(tio)
, tunif(tuntap_init())
{
};
int
sendto(const sockaddr* to, const void* data, size_t sz)
{
return -1;
}
void
flush_write()
{
if(t->before_write)
{
t->before_write(t);
}
ev_io::flush_write();
}
int
read(void* buf, size_t sz)
{
ssize_t ret = tuntap_read(tunif, buf, sz);
if(ret > 4 && t->recvpkt)
// should have pktinfo
t->recvpkt(t, ((byte_t*)buf) + 4, ret - 4);
return ret;
}
bool
setup()
{
llarp::LogDebug("set ifname to ", t->ifname);
strncpy(tunif->if_name, t->ifname, sizeof(tunif->if_name));
if(tuntap_start(tunif, TUNTAP_MODE_TUNNEL, 0) == -1)
{
llarp::LogWarn("failed to start interface");
return false;
}
if(tuntap_up(tunif) == -1)
{
llarp::LogWarn("failed to put interface up: ", strerror(errno));
return false;
}
if(tuntap_set_ip(tunif, t->ifaddr, t->ifaddr, t->netmask) == -1)
{
llarp::LogWarn("failed to set ip");
return false;
}
fd = (SOCKET)tunif->tun_fd;
if(fd == -1)
return false;
// set non blocking
int on = 1;
return ioctlsocket(fd, FIONBIO, (u_long*)&on) != -1;
}
~tun()
{
}
};
}; // namespace llarp
struct llarp_win32_loop : public llarp_ev_loop
@ -93,22 +167,12 @@ struct llarp_win32_loop : public llarp_ev_loop
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
@ -287,7 +351,10 @@ struct llarp_win32_loop : public llarp_ev_loop
llarp::ev_io*
create_tun(llarp_tun_io* tun)
{
// TODO implement me
llarp::tun* t = new llarp::tun(tun);
if(t->setup())
return t;
delete t;
return nullptr;
}

View File

@ -1,6 +1,7 @@
#ifndef LLARP_FS_HPP
#define LLARP_FS_HPP
#include <functional>
#if defined(WIN32) || defined(_WIN32)
#define PATH_SEP "\\"
#else
@ -8,21 +9,13 @@
#endif
#include "filesystem.h"
#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) || defined(__sun)
namespace fs = std::experimental::filesystem;
#else
namespace fs = std::experimental::filesystem;
#endif // end win32
#else
// not CPP17 needs this
// openbsd needs this
// linux gcc 7.2 needs this
namespace fs = cpp17::filesystem;
#endif
#include <dirent.h>
namespace llarp

View File

@ -3,8 +3,10 @@
#include <llarp/handlers/tun.hpp>
#include "router.hpp"
#include <sys/types.h>
#ifndef _WIN32
#include <sys/socket.h>
#include <netdb.h>
#endif
#ifndef DNS_PORT
#define DNS_PORT (53)
@ -102,11 +104,11 @@ namespace llarp
strncpy(tunif.ifaddr, addr.c_str(), sizeof(tunif.ifaddr) - 1);
// set up address in dotLokiLookup
struct sockaddr_in s_addr;
s_addr.sin_addr.s_addr = inet_addr(tunif.ifaddr);
s_addr.sin_family = AF_INET;
struct sockaddr_in source_addr;
source_addr.sin_addr.s_addr = inet_addr(tunif.ifaddr);
source_addr.sin_family = AF_INET;
llarp::Addr tunIp(s_addr);
llarp::Addr tunIp(source_addr);
// related to dns_iptracker_setup_dotLokiLookup(&this->dll, tunIp);
dns_iptracker_setup(tunIp); // claim GW IP to make sure it's not inuse
return true;

View File

@ -14,6 +14,12 @@
#include <netinet/ip_icmp.h>
#endif
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
#endif
namespace llarp
{
namespace utp
@ -342,8 +348,8 @@ namespace llarp
static_cast< LinkLayer* >(utp_context_get_userdata(arg->context));
llarp::LogDebug("utp_sendto ", Addr(*arg->address), " ", arg->len,
" bytes");
if(sendto(l->m_udp.fd, arg->buf, arg->len, arg->flags, arg->address,
arg->address_len)
if(::sendto(l->m_udp.fd, (char*)arg->buf, arg->len, arg->flags,
arg->address, arg->address_len)
== -1)
{
llarp::LogError("sendto failed: ", strerror(errno));

View File

@ -118,7 +118,9 @@ _llarp_nt_heap_free(void* mem)
int
llarp_nt_sockaddr_pton(const char* src, struct sockaddr* dst)
{
struct addrinfo hints = {0}, *result = nullptr;
struct addrinfo hints;
struct addrinfo* result = nullptr;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_TCP;
@ -261,6 +263,10 @@ _llarp_nt_getadaptersinfo(struct llarp_nt_ifaddrs_t** ifap)
ift->_ifa.ifa_next = (struct llarp_nt_ifaddrs_t*)(ift + 1);
ift = (struct _llarp_nt_ifaddrs_t*)(ift->_ifa.ifa_next);
}
else
{
ift->_ifa.ifa_next = nullptr;
}
}
}
@ -866,7 +872,7 @@ namespace llarp
if(i->ifa_addr->sa_family == af)
{
llarp::Addr a(*i->ifa_addr);
if(!(a.isPrivate() || a.isLoopback()))
if(!(a.isPrivate() || a.isLoopback() || (a.getHostLong() == 0)))
{
ifname = i->ifa_name;
found = true;

View File

@ -96,7 +96,7 @@ struct llarp_nodedb
llarp::LogDebug("saving RC.pubkey ", filepath);
std::ofstream ofs(
filepath,
std::ofstream::out & std::ofstream::binary & std::ofstream::trunc);
std::ofstream::out | std::ofstream::binary | std::ofstream::trunc);
ofs.write((char *)buf.base, buf.sz);
ofs.close();
if(!ofs)
@ -313,7 +313,7 @@ llarp_nodedb_ensure_dir(const char *dir)
std::error_code ec;
if(!fs::exists(dir, ec))
fs::create_directories(path, ec);
fs::create_directory(path, ec);
if(ec)
return false;

View File

@ -165,6 +165,26 @@ namespace llarp
" rx=", path->RXID());
}
bool
PathSet::GetCurrentIntroductionsWithFilter(
std::set< llarp::service::Introduction >& intros,
std::function< bool(const llarp::service::Introduction&) > filter) const
{
intros.clear();
size_t count = 0;
auto itr = m_Paths.begin();
while(itr != m_Paths.end())
{
if(itr->second->IsReady() && filter(itr->second->intro))
{
intros.insert(itr->second->intro);
++count;
}
++itr;
}
return count > 0;
}
bool
PathSet::GetCurrentIntroductions(
std::set< llarp::service::Introduction >& intros) const

View File

@ -760,6 +760,9 @@ llarp_router::Run()
return;
}
// generate default hidden service
if(!CreateDefaultHiddenService())
return;
// delayed connect all for clients
uint64_t delay = ((llarp_randint() % 10) * 500) + 500;
llarp_logic_call_later(logic, {delay, this, &ConnectAll});
@ -855,6 +858,12 @@ llarp_router::InitOutboundLink()
return false;
}
bool
llarp_router::CreateDefaultHiddenService()
{
return hiddenServiceContext.AddDefaultEndpoint(defaultIfAddr, defaultIfName);
}
bool
llarp_router::HasPendingConnectJob(const llarp::RouterID &remote)
{
@ -1054,6 +1063,17 @@ namespace llarp
llarp::LogError("Failed to set up curvecp link");
}
}
else if(StrEq(section, "network"))
{
if(StrEq(key, "ifaddr"))
{
self->defaultIfAddr = val;
}
if(StrEq(key, "ifname"))
{
self->defaultIfAddr = val;
}
}
else if(StrEq(section, "services"))
{
if(self->LoadHiddenServiceConfig(val))

View File

@ -93,6 +93,13 @@ struct llarp_router
llarp::service::Context hiddenServiceContext;
std::string defaultIfAddr = "10.200.0.1/24";
std::string defaultIfName = "lokitun0";
bool
CreateDefaultHiddenService();
std::unique_ptr< llarp::ILinkLayer > outboundLink;
std::vector< std::unique_ptr< llarp::ILinkLayer > > inboundLinks;

View File

@ -106,6 +106,12 @@ namespace llarp
return tunEndpoint->MapAddress(addr, ip);
}
bool
Context::AddDefaultEndpoint(const std::string & ifaddr, const std::string & ifname)
{
return AddEndpoint({ "default", {{"type", "tun"}, {"ifaddr", ifaddr}, {"ifname", ifname}}});
}
bool
Context::AddEndpoint(const Config::section_t &conf)
{

View File

@ -91,22 +91,25 @@ namespace llarp
}
void
Endpoint::RegenAndPublishIntroSet(llarp_time_t now)
Endpoint::RegenAndPublishIntroSet(llarp_time_t now, bool forceRebuild)
{
std::set< Introduction > I;
if(!GetCurrentIntroductions(I))
if(!GetCurrentIntroductionsWithFilter(
I, [now](const service::Introduction& intro) -> bool {
return now < intro.expiresAt
&& intro.expiresAt - now > (2 * 60 * 1000);
}))
{
llarp::LogWarn("could not publish descriptors for endpoint ", Name(),
" because we couldn't get any introductions");
if(ShouldBuildMore())
" because we couldn't get enough valid introductions");
if(ShouldBuildMore() || forceRebuild)
ManualRebuild(1);
return;
}
m_IntroSet.I.clear();
for(const auto& intro : I)
{
if(now < intro.expiresAt && intro.expiresAt - now > 60000)
m_IntroSet.I.push_back(intro);
m_IntroSet.I.push_back(intro);
}
if(m_IntroSet.I.size() == 0)
{
@ -760,6 +763,7 @@ namespace llarp
if(MarkCurrentIntroBad(llarp_time_now_ms()))
llarp::LogInfo(Name(), " switched intros to ", remoteIntro.router,
" via ", remoteIntro.pathID);
UpdateIntroSet();
}
return true;
}
@ -815,7 +819,7 @@ namespace llarp
Endpoint::HandlePathDead(void* user)
{
Endpoint* self = static_cast< Endpoint* >(user);
self->RegenAndPublishIntroSet(llarp_time_now_ms());
self->RegenAndPublishIntroSet(llarp_time_now_ms(), true);
}
bool
@ -918,10 +922,18 @@ namespace llarp
{
if(markedBad)
return true;
if(i && currentIntroSet.T < i->T)
if(i)
{
if(currentIntroSet.T >= i->T)
{
llarp::LogInfo("introset is old, dropping");
return true;
}
currentIntroSet = *i;
ShiftIntroduction();
if(!ShiftIntroduction())
{
llarp::LogWarn("failed to pick new intro during introset update");
}
if(GetPathByRouter(remoteIntro.router) == nullptr)
BuildOneAlignedTo(remoteIntro.router);
}
@ -1013,42 +1025,13 @@ namespace llarp
}
++itr;
}
llarp::LogWarn("No path ready to send yet");
// all paths are not ready?
return false;
}
// no converstation
auto itr = m_PendingTraffic.find(remote);
if(itr == m_PendingTraffic.end())
{
m_PendingTraffic.insert(std::make_pair(remote, PendingBufferQueue()));
EnsurePathToService(
remote,
[&](Address addr, OutboundContext* ctx) {
if(ctx)
{
auto itr = m_PendingTraffic.find(addr);
if(itr != m_PendingTraffic.end())
{
while(itr->second.size())
{
auto& front = itr->second.front();
ctx->AsyncEncryptAndSendTo(front.Buffer(), front.protocol);
itr->second.pop();
}
}
}
else
{
llarp::LogWarn("failed to obtain outbound context to ", addr,
" within timeout");
}
m_PendingTraffic.erase(addr);
},
10000);
}
m_PendingTraffic[remote].emplace(data, t);
return true;
EnsurePathToService(remote, [](Address, OutboundContext*) {}, 5000);
return false;
}
bool
@ -1090,9 +1073,51 @@ namespace llarp
Endpoint::OutboundContext::MarkCurrentIntroBad(llarp_time_t now)
{
// insert bad intro
m_BadIntros.insert(std::make_pair(remoteIntro, now));
// shift
return ShiftIntroduction();
m_BadIntros[remoteIntro] = now;
// unconditional shift
bool shiftedRouter = false;
bool shiftedIntro = false;
// try same router
for(const auto& intro : currentIntroSet.I)
{
llarp::LogInfo("have intro: ", intro);
if(intro.ExpiresSoon(now))
{
llarp::LogInfo("skipping intro, expires soon");
continue;
}
auto itr = m_BadIntros.find(intro);
if(itr == m_BadIntros.end() && intro.router == remoteIntro.router)
{
shiftedIntro = true;
remoteIntro = intro;
break;
}
}
if(!shiftedIntro)
{
// try any router
for(const auto& intro : currentIntroSet.I)
{
if(intro.ExpiresSoon(now))
continue;
auto itr = m_BadIntros.find(intro);
if(itr == m_BadIntros.end())
{
// TODO: this should always be true but idk if it really is
shiftedRouter = remoteIntro.router != intro.router;
shiftedIntro = true;
remoteIntro = intro;
break;
}
}
}
if(shiftedRouter)
{
lastShift = now;
ManualRebuild(1);
}
return shiftedIntro;
}
bool
@ -1167,11 +1192,13 @@ namespace llarp
Introduction remoteIntro;
std::function< void(ProtocolFrame&) > hook;
IDataHandler* handler;
ConvoTag tag;
AsyncKeyExchange(llarp_logic* l, llarp_crypto* c, const ServiceInfo& r,
const Identity& localident,
const PQPubKey& introsetPubKey,
const Introduction& remote, IDataHandler* h)
const Introduction& remote, IDataHandler* h,
const ConvoTag& t)
: logic(l)
, crypto(c)
, remote(r)
@ -1179,6 +1206,7 @@ namespace llarp
, introPubKey(introsetPubKey)
, remoteIntro(remote)
, handler(h)
, tag(t)
{
}
@ -1215,8 +1243,8 @@ namespace llarp
// H (K + PKE(A, B, N))
self->crypto->shorthash(self->sharedKey,
llarp::StackBuffer< decltype(tmp) >(tmp));
// randomize tag
self->msg.tag.Randomize();
// set tag
self->msg.tag = self->tag;
// set sender
self->msg.sender = self->m_LocalIdentity.pub;
// set version
@ -1238,9 +1266,7 @@ namespace llarp
void
Endpoint::EnsureReplyPath(const ServiceInfo& ident)
{
auto itr = m_AddressToService.find(ident.Addr());
if(itr == m_AddressToService.end())
m_AddressToService.insert(std::make_pair(ident.Addr(), ident));
m_AddressToService[ident.Addr()] = ident;
}
void
@ -1259,13 +1285,15 @@ namespace llarp
return;
}
}
currentConvoTag.Randomize();
AsyncKeyExchange* ex = new AsyncKeyExchange(
m_Endpoint->RouterLogic(), m_Endpoint->Crypto(), remoteIdent,
m_Endpoint->GetIdentity(), currentIntroSet.K, remoteIntro,
m_DataHandler, currentConvoTag);
AsyncKeyExchange* ex =
new AsyncKeyExchange(m_Endpoint->RouterLogic(), m_Endpoint->Crypto(),
remoteIdent, m_Endpoint->GetIdentity(),
currentIntroSet.K, remoteIntro, m_DataHandler);
ex->hook = std::bind(&Endpoint::OutboundContext::Send, this,
std::placeholders::_1);
ex->msg.PutBuffer(payload);
ex->msg.introReply = path->intro;
llarp_threadpool_queue_job(m_Endpoint->Worker(),
@ -1426,18 +1454,12 @@ namespace llarp
Endpoint::SendContext::EncryptAndSendTo(llarp_buffer_t payload,
ProtocolType t)
{
std::set< ConvoTag > tags;
if(!m_DataHandler->GetConvoTagsForService(remoteIdent, tags))
{
llarp::LogError("no open converstations with remote endpoint?");
return;
}
auto crypto = m_Endpoint->Router()->crypto;
const byte_t* shared = nullptr;
routing::PathTransferMessage msg;
ProtocolFrame& f = msg.T;
f.N.Randomize();
f.T = *tags.begin();
f.T = currentConvoTag;
f.S = m_Endpoint->GetSeqNoForConvo(f.T);
auto now = llarp_time_now_ms();
@ -1486,8 +1508,8 @@ namespace llarp
++sequenceNo;
if(path->SendRoutingMessage(&msg, m_Endpoint->Router()))
{
llarp::LogInfo("sent message via ", remoteIntro.pathID, " on ",
remoteIntro.router);
llarp::LogDebug("sent message via ", remoteIntro.pathID, " on ",
remoteIntro.router);
}
else
{

View File

@ -1,28 +1,31 @@
#include <llarp/time.h>
#include <chrono>
namespace llarp
{
typedef std::chrono::system_clock clock_t;
template < typename Res, typename IntType >
static IntType
time_since_epoch()
{
return std::chrono::duration_cast< Res >(
llarp::clock_t::now().time_since_epoch())
.count();
}
} // namespace llarp
#include <time.h>
#include <sys/time.h>
// these _should_ be 32-bit safe...
llarp_time_t
llarp_time_now_ms()
{
return llarp::time_since_epoch< std::chrono::milliseconds, llarp_time_t >();
struct timeval tv;
struct timezone z;
z.tz_minuteswest = 0;
time_t t = time(nullptr);
z.tz_dsttime = gmtime(&t)->tm_isdst;
gettimeofday(&tv, &z);
llarp_time_t timeNow =
(llarp_time_t)(tv.tv_sec) * 1000 + (llarp_time_t)(tv.tv_usec) / 1000;
return timeNow;
}
llarp_seconds_t
llarp_time_now_sec()
{
return llarp::time_since_epoch< std::chrono::seconds, llarp_seconds_t >();
struct timeval tv;
struct timezone z;
z.tz_minuteswest = 0;
time_t t = time(nullptr);
z.tz_dsttime = gmtime(&t)->tm_isdst;
gettimeofday(&tv, &z);
llarp_time_t timeNow = tv.tv_sec;
return timeNow;
}

View File

@ -15,7 +15,7 @@ namespace llarp
bool
TransitHop::Expired(llarp_time_t now) const
{
return now - started > lifetime;
return now > ExpireTime();
}
llarp_time_t
@ -54,7 +54,9 @@ namespace llarp
TransitHop::SendRoutingMessage(llarp::routing::IMessage* msg,
llarp_router* r)
{
byte_t tmp[MAX_LINK_MSG_SIZE - 1024];
if(!IsEndpoint(r->pubkey()))
return false;
byte_t tmp[MAX_LINK_MSG_SIZE - 128];
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
if(!msg->BEncode(&buf))
{
@ -64,12 +66,14 @@ namespace llarp
TunnelNonce N;
N.Randomize();
buf.sz = buf.cur - buf.base;
// pad smaller messages
if(buf.sz < MESSAGE_PAD_SIZE)
// pad to nearest MESSAGE_PAD_SIZE bytes
auto dlt = buf.sz % MESSAGE_PAD_SIZE;
if(dlt)
{
dlt = MESSAGE_PAD_SIZE - dlt;
// randomize padding
r->crypto.randbytes(buf.cur, MESSAGE_PAD_SIZE - buf.sz);
buf.sz = MESSAGE_PAD_SIZE;
r->crypto.randbytes(buf.cur, dlt);
buf.sz += dlt;
}
buf.cur = buf.base;
return HandleDownstream(buf, N, r);
@ -94,7 +98,7 @@ namespace llarp
llarp_router* r)
{
r->crypto.xchacha20(buf, pathKey, Y);
if(info.upstream == RouterID(r->pubkey()))
if(IsEndpoint(r->pubkey()))
{
return m_MessageParser.ParseMessageBuffer(buf, this, info.rxID, r);
}
@ -166,7 +170,6 @@ namespace llarp
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
// send
llarp::LogInfo("Transfer ", buf.sz, " bytes", " to ", msg->P);
return path->HandleDownstream(buf, msg->Y, r);
}

View File

@ -20,12 +20,11 @@ option(gtest_build_tests "Build all of gtest's own tests." OFF)
option(gtest_build_samples "Build gtest's sample programs." OFF)
if (NOT WIN32)
option(gtest_disable_pthreads "Disable uses of pthreads in gtest." OFF)
# use native windows nt threading even in gcc or clang
if (WIN32)
option(gtest_disable_pthreads ON)
endif(WIN32)
else()
option(gtest_disable_pthreads "Disable uses of pthreads in gtest." ON)
endif(NOT WIN32)
option(
gtest_hide_internal_symbols

View File

@ -30,7 +30,7 @@
#ifndef PBL_CPP_FILESYSTEM_H
#define PBL_CPP_FILESYSTEM_H
#if _MSC_VER >= 1910
#if _MSC_VER >= 1900
#define CPP17
#define CPP11
#define CPP14
@ -39,13 +39,8 @@
#include "version.h"
#if defined(CPP17) && defined(USE_CXX17_FILESYSTEM)
#if defined(__MINGW32__) || defined(_MSC_VER) || defined(__sun)
// win32 needs experimental
#include <experimental/filesystem>
#else
#include <experimental/filesystem>
#endif
#else
// OpenBSD needs this
// MacOS llvm 3.8 needs this
#include "fs/absolute.h"

View File

@ -1,30 +1,31 @@
/* Copyright (c) 2014, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include "basename.h"
@ -33,168 +34,174 @@
namespace
{
// the position following the previous occurrence of c (relative to position j),
// or 0 if not. In this file, the first letter of a path component.
std::size_t after_last(
const std::string& s,
char c,
std::size_t j
)
{
std::size_t i = s.find_last_of(c, j);
// the position following the previous occurrence of c (relative to position
// j), or 0 if not. In this file, the first letter of a path component.
std::size_t
after_last(const std::string& s, char c, std::size_t j)
{
std::size_t i = s.find_last_of(c, j);
return i == std::string::npos ? 0 : i + 1;
}
return i == std::string::npos ? 0 : i + 1;
}
// (first character, length) of last path component in s or (0,0) for "."
// or (npos, 0) if error
std::pair< std::size_t, std::size_t > locate_last_path_component(const std::string& s)
{
if ( s.empty() )
{
// (first character, length) of last path component in s or (0,0) for "."
// or (npos, 0) if error
std::pair< std::size_t, std::size_t >
locate_last_path_component(const std::string& s)
{
if(s.empty())
{
// error
return std::pair< std::size_t, std::size_t >(std::string::npos, 0);
}
// error
return std::pair< std::size_t, std::size_t >(std::string::npos, 0);
}
// j points to the last character in a component
std::size_t j = s.find_last_not_of('/');
unsigned depth = 0;
// j points to the last character in a component
std::size_t j = s.find_last_not_of('/');
unsigned depth = 0;
while(j != std::string::npos)
{
// i points to first character of a component
// i <= j, because j never points to a '/'
const std::size_t i = after_last(s, '/', j);
while ( j != std::string::npos )
{
// i points to first character of a component
// i <= j, because j never points to a '/'
const std::size_t i = after_last(s, '/', j);
if(j - i + 1 == 1 && s[i] == '.')
{
// component is ".", basically ignore this component
}
else if(j - i + 1 == 2 && s[i] == '.' && s[i + 1] == '.')
{
// component is "..", ignore the next component
++depth;
}
else
{
// found a "normal" path component
if(depth == 0)
{
return std::pair< std::size_t, std::size_t >(i, j - i + 1);
}
if ( j - i + 1 == 1 && s[i] == '.' )
{
// component is ".", basically ignore this component
}
else if ( j - i + 1 == 2 && s[i] == '.' && s[i + 1] == '.' )
{
// component is "..", ignore the next component
++depth;
}
else
{
// found a "normal" path component
if ( depth == 0 )
{
return std::pair< std::size_t, std::size_t >(i, j - i + 1);
}
// ..but we're ignoring it
--depth;
}
// ..but we're ignoring it
--depth;
}
if(i == 0)
{
if(depth == 0)
{
// "."
return std::pair< std::size_t, std::size_t >(0, 0);
}
else
{
// error, path is malformed
return std::pair< std::size_t, std::size_t >(std::string::npos, 0);
}
}
if ( i == 0 )
{
if ( depth == 0 )
{
j = s.find_last_not_of('/', i - 1);
}
// "."
return std::pair< std::size_t, std::size_t >(0, 0);
}
else
{
// all slashes
return std::pair< std::size_t, std::size_t >(0, 1);
}
// error, path is malformed
return std::pair< std::size_t, std::size_t >(std::string::npos, 0);
}
}
std::string
basename_posix(const std::string& s)
{
const std::pair< std::size_t, std::size_t > range =
locate_last_path_component(s);
j = s.find_last_not_of('/', i - 1);
}
if(range.first == std::string::npos)
{
return std::string();
}
// all slashes
return std::pair< std::size_t, std::size_t >(0, 1);
}
if(range.first == 0 && range.second == 0)
{
return ".";
}
std::string basename_posix(const std::string& s)
{
const std::pair< std::size_t, std::size_t > range = locate_last_path_component(s);
return s.substr(range.first, range.second);
}
std::string
dirname_posix(const std::string& s)
{
const std::pair< std::size_t, std::size_t > range =
locate_last_path_component(s);
if ( range.first == std::string::npos )
{
return std::string();
}
// path was malformed
if(range.first == std::string::npos)
{
return std::string();
}
if ( range.first == 0 && range.second == 0 )
{
return ".";
}
if(range.first == 0)
{
if(range.second == 0)
{
return "..";
}
return s.substr(range.first, range.second);
}
// could be '/', or could be a unpathed filename
if(s[0] == '/')
{
return "/";
}
std::string dirname_posix(const std::string& s)
{
const std::pair< std::size_t, std::size_t > range = locate_last_path_component(s);
return ".";
}
else
{
// leading directory
return s.substr(0, range.first);
}
}
// path was malformed
if ( range.first == std::string::npos )
{
return std::string();
}
if ( range.first == 0 )
{
if ( range.second == 0 )
{
return "..";
}
// could be '/', or could be a unpathed filename
if ( s[0] == '/' )
{
return "/";
}
return ".";
}
else
{
// leading directory
return s.substr(0, range.first);
}
}
}
} // namespace
namespace cpp17
{
namespace filesystem
{
// Calls the basename_xxx appropriate for this platform
std::string basename(const std::string& s)
{
#ifdef OS_POSIX
namespace filesystem
{
// Calls the basename_xxx appropriate for this platform
std::string
basename(const std::string& s)
{
#ifdef OS_POSIX
return basename_posix(s);
#else
std::string t;
char fname[_MAX_FNAME], ext[_MAX_EXT];
_splitpath(s.c_str(), nullptr, nullptr, fname, ext);
t = fname;
t += ext;
return t;
#endif
}
return basename_posix(s);
std::string
dirname(const std::string& s)
{
#ifdef OS_POSIX
const std::string& t = dirname_posix(s);
#else
#error "No implementation of basename is available for this platform"
#endif
}
if(t == ".")
{
return t;
}
std::string dirname(const std::string& s)
{
#ifdef OS_POSIX
const std::string& t = dirname_posix(s);
return cleanpath(t);
if ( t == "." )
{
return t;
}
#else
std::string t;
char _dirname[_MAX_DIR];
_splitpath(s.c_str(), nullptr, _dirname, nullptr, nullptr);
t = _dirname;
return t;
#endif
}
return cleanpath(t);
#else
#error "No implementation of dirname is available for this platform"
#endif
}
}
}
} // namespace filesystem
} // namespace cpp17

View File

@ -1,138 +1,144 @@
/* Copyright (c) 2014, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include "cleanpath.h"
#include <algorithm>
#if defined(_WIN32) && !defined(NOMINMAX)
#define NOMINMAX
#endif
namespace cpp17
{
namespace filesystem
{
/// @todo Probably belongs in path.cpp
std::string cleanpath(const std::string& s)
{
std::string t;
namespace filesystem
{
/// @todo Probably belongs in path.cpp
std::string
cleanpath(const std::string& s)
{
std::string t;
if ( s.empty() )
{
if(s.empty())
{
// error
return t;
}
// error
return t;
}
const std::size_t n = s.length();
const std::size_t n = s.length();
for(std::size_t i = 0; i < n;)
{
if(s[i] == '/')
{
// directory separator
t.push_back('/');
i = s.find_first_not_of('/', i);
}
else
{
// path component
const std::size_t j = std::min(s.find('/', i), n);
for ( std::size_t i = 0; i < n;)
{
if ( s[i] == '/' )
{
// directory separator
t.push_back('/');
i = s.find_first_not_of('/', i);
}
else
{
// path component
const std::size_t j = std::min(s.find('/', i), n);
if(s.compare(i, j - i, ".", 1) == 0)
{
// handle dot
if(j < n)
{
i = s.find_first_not_of('/', j);
}
else
{
i = n;
}
}
else if(s.compare(i, j - i, "..", 2) == 0)
{
// handle dot-dot
const std::size_t l = t.length();
if ( s.compare(i, j - i, ".", 1) == 0 )
{
// handle dot
if ( j < n )
{
i = s.find_first_not_of('/', j);
}
else
{
i = n;
}
}
else if ( s.compare(i, j - i, "..", 2) == 0 )
{
// handle dot-dot
const std::size_t l = t.length();
if(l == 0)
{
// no previous component (ex., "../src")
t.assign("..", 2);
i = j;
}
else
{
// remove previously copied component (unless root)
if(l >= 2)
{
const std::size_t k = t.find_last_of('/', l - 2);
if ( l == 0 )
{
// no previous component (ex., "../src")
t.assign("..", 2);
i = j;
}
else
{
// remove previously copied component (unless root)
if ( l >= 2 )
{
const std::size_t k = t.find_last_of('/', l - 2);
if(k == std::string::npos)
{
t.clear();
}
else
{
t.resize(k + 1);
}
}
if ( k == std::string::npos )
{
t.clear();
}
else
{
t.resize(k + 1);
}
}
if(j < n)
{
i = s.find_first_not_of('/', j);
}
else
{
i = n;
}
}
}
else
{
// append path component
t.append(s, i, j - i);
i = j;
}
}
}
if ( j < n )
{
i = s.find_first_not_of('/', j);
}
else
{
i = n;
}
}
}
else
{
// append path component
t.append(s, i, j - i);
i = j;
}
}
}
if(t.empty())
{
return ".";
}
if ( t.empty() )
{
return ".";
}
// drop trailing slashes
const std::size_t i = t.find_last_not_of('/');
// drop trailing slashes
const std::size_t i = t.find_last_not_of('/');
if(i != std::string::npos)
{
t.resize(i + 1);
}
if ( i != std::string::npos )
{
t.resize(i + 1);
}
return t;
}
return t;
}
}
}
} // namespace filesystem
} // namespace cpp17

View File

@ -1,30 +1,31 @@
/* Copyright (c) 2015, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef PBL_CPP_FS_CLEANPATH_H
#define PBL_CPP_FS_CLEANPATH_H
@ -33,29 +34,31 @@
namespace cpp17
{
namespace filesystem
{
/** Return a simplified version of path
*
* @param path A file system path
*
* Collapses multiple path separators (ex., as in "/home//user"); replaces
* "name/." with "name" and "parent/child/.." with "parent"; removes trailing
* slashes.
*
* The returned path is equivalent to the original path in the sense that it
* identifies the same file system object. Specifically, relative paths are
* preserved (ex., no simplification is done to the dot-dot in "../here").
*
* If the path is malformed, the empty string is returned. For this function,
* really only the empty string itself is "malformed".
*
* @note This is a textual operation. It does not validate the string against
* the file system or otherwise touch the file system.
* @bug foo/bar/../baz may not point to /foo/baz if bar symlinks to flip/flop
*/
std::string cleanpath(const std::string& path);
}
}
namespace filesystem
{
/** Return a simplified version of path
*
* @param path A file system path
*
* Collapses multiple path separators (ex., as in "/home//user"); replaces
* "name/." with "name" and "parent/child/.." with "parent"; removes
* trailing slashes.
*
* The returned path is equivalent to the original path in the sense that it
* identifies the same file system object. Specifically, relative paths are
* preserved (ex., no simplification is done to the dot-dot in "../here").
*
* If the path is malformed, the empty string is returned. For this
* function, really only the empty string itself is "malformed".
*
* @note This is a textual operation. It does not validate the string
* against the file system or otherwise touch the file system.
* @bug foo/bar/../baz may not point to /foo/baz if bar symlinks to
* flip/flop
*/
std::string
cleanpath(const std::string& path);
} // namespace filesystem
} // namespace cpp17
#endif // PBL_FS_CLEANPATH_H
#endif // PBL_FS_CLEANPATH_H

View File

@ -1,30 +1,31 @@
/* Copyright (c) 2016, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include "create_directory.h"
@ -33,37 +34,43 @@
#include "perms.h"
#include "filestatus.h"
#ifdef _WIN32
#include <direct.h>
#define mkdir(x, y) mkdir(x)
#endif
namespace cpp17
{
namespace filesystem
{
namespace filesystem
{
bool
create_directory(const path& s, std::error_code& ec)
{
if(s.empty())
{
return false;
}
bool create_directory(const path& s, std::error_code& ec)
{
if ( s.empty() )
{
return false;
}
return ::mkdir(s.c_str(), static_cast< int >(perms::all)) == 0;
}
return ::mkdir( s.c_str(), static_cast< int >( perms::all ) ) == 0;
}
bool
create_directories(const path& s, std::error_code& ec)
{
path p = s.parent_path();
bool create_directories(const path& s, std::error_code& ec)
{
path p = s.parent_path();
if ( !p.empty() )
{
if(!p.empty())
{
std::error_code ec, ec2;
if ( !exists(p, ec) && !create_directories(p, ec2) )
{
return false;
}
}
std::error_code ec3;
return create_directory(s, ec3);
}
if(!exists(p, ec) && !create_directories(p, ec2))
{
return false;
}
}
}
}
std::error_code ec3;
return create_directory(s, ec3);
}
} // namespace filesystem
} // namespace cpp17

View File

@ -1,81 +1,87 @@
/* Copyright (c) 2016, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include "current_path.h"
#include <cerrno>
#ifndef _MSC_VER
#include <unistd.h>
#else
#include <direct.h>
#endif
namespace cpp17
{
namespace filesystem
{
path current_path()
{
char buf[4096];
namespace filesystem
{
path
current_path()
{
char buf[4096];
if ( ::getcwd( buf, sizeof( buf ) ) )
{
return buf;
}
if(::getcwd(buf, sizeof(buf)))
{
return buf;
}
// Dynamically allocate larger buffers until cwd fits
std::size_t size = 2 * sizeof( buf );
// Dynamically allocate larger buffers until cwd fits
std::size_t size = 2 * sizeof(buf);
while ( true )
{
char* q = new char[size];
while(true)
{
char* q = new char[size];
if ( ::getcwd(q, size) )
{
path p = q;
delete[] q;
if(::getcwd(q, size))
{
path p = q;
delete[] q;
return p;
}
else
{
if ( errno == ERANGE )
{
delete[] q;
size *= 2;
}
else
{
delete[] q;
break;
}
}
}
return p;
}
else
{
if(errno == ERANGE)
{
delete[] q;
size *= 2;
}
else
{
delete[] q;
break;
}
}
}
return path();
}
return path();
}
}
}
} // namespace filesystem
} // namespace cpp17

View File

@ -1,30 +1,31 @@
/* Copyright (c) 2014, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include "diriter.h"
@ -33,442 +34,473 @@
#include <climits>
#include <dirent.h>
#ifdef _WIN32
#include <io.h>
#endif
#include "direntry.h"
#include "path.h"
namespace cpp17
{
namespace filesystem
{
/// @todo Could save the malloc/free (of e) if we mark end-of-directory
class directory_iterator::impl
{
public:
impl()
: p(), d(0), e(0), info(), valid_info(false)
{
//printf("directory_iterator::impl::cstr\n");
namespace filesystem
{
/// @todo Could save the malloc/free (of e) if we mark end-of-directory
class directory_iterator::impl
{
public:
impl() : p(), d(0), e(0), info(), valid_info(false)
{
// printf("directory_iterator::impl::cstr\n");
pos = 0;
}
}
explicit impl(const path& path_)
: p(path_), d(0), e(0), info(), valid_info(false)
{
//printf("directory_iterator::impl::cstr path[%s]\n", path_.c_str());
explicit impl(const path& path_)
: p(path_), d(0), e(0), info(), valid_info(false)
{
// printf("directory_iterator::impl::cstr path[%s]\n", path_.c_str());
this->cPath = path_;
d = ::opendir( path_.c_str() );
d = ::opendir(path_.c_str());
if ( d )
{
e = acquire();
next();
}
}
~impl()
{
//printf("directory_iterator::impl::dstr [%s]\n", this->cPath.c_str());
if ( d )
{
release(); // free e
::closedir(d);
d = 0;
}
}
void rewind() {
//printf("directory_iterator::impl::rewind\n");
if ( d )
if(d)
{
release();
::closedir(d);
e = acquire();
next();
}
d = ::opendir( this->cPath.c_str() );
}
~impl()
{
// printf("directory_iterator::impl::dstr [%s]\n", this->cPath.c_str());
if(d)
{
release(); // free e
::closedir(d);
d = 0;
}
}
void
rewind()
{
// printf("directory_iterator::impl::rewind\n");
if(d)
{
release();
::closedir(d);
}
d = ::opendir(this->cPath.c_str());
pos = 0;
if ( d )
if(d)
{
e = acquire();
next();
e = acquire();
next();
}
}
void seek(size_t seekPos) {
//printf("directory_iterator::impl::seek\n");
}
void
seek(size_t seekPos)
{
// printf("directory_iterator::impl::seek\n");
this->rewind();
for(size_t i = 0; i < seekPos; i++) {
this->next();
for(size_t i = 0; i < seekPos; i++)
{
this->next();
}
}
/** Test if this is an end iterator
*/
bool is_end() const
{
//printf("directory_iterator::impl::is_end\n");
return !e;
}
}
bool next()
{
//printf("directory_iterator::impl::next\n");
if ( d )
{
valid_info = false;
/** Test if this is an end iterator
*/
bool
is_end() const
{
// printf("directory_iterator::impl::is_end\n");
return !e;
}
do
{
dirent* ptr = 0;
bool
next()
{
// printf("directory_iterator::impl::next\n");
if(d)
{
valid_info = false;
const int res = ::readdir_r(d, e, &ptr);
do
{
dirent* ptr = 0;
if ( res != 0 || ptr == 0 )
{
// error, or end of directory
pos = 0;
release();
const int res = ::readdir_r(d, e, &ptr);
return false;
}
}
while ( std::strcmp(e->d_name, ".") == 0 || std::strcmp(e->d_name, "..") == 0 );
if(res != 0 || ptr == 0)
{
// error, or end of directory
pos = 0;
release();
pos++;
return true;
}
return false;
}
} while(std::strcmp(e->d_name, ".") == 0
|| std::strcmp(e->d_name, "..") == 0);
return false;
}
pos++;
path get_path() const
{
//printf("directory_iterator::impl::get_path\n");
return e ? ( p / e->d_name ) : path();
}
return true;
}
file_type type() const
{
//printf("directory_iterator::impl::type\n");
if ( e )
{
switch ( e->d_type )
{
case DT_FIFO:
return false;
}
return file_type::fifo;
path
get_path() const
{
// printf("directory_iterator::impl::get_path\n");
return e ? (p / e->d_name) : path();
}
case DT_CHR:
file_type
type() const
{
// printf("directory_iterator::impl::type\n");
if(e)
{
switch(e->d_type)
{
case DT_FIFO:
return file_type::character;
return file_type::fifo;
case DT_DIR:
case DT_CHR:
return file_type::directory;
return file_type::character;
case DT_BLK:
case DT_DIR:
return file_type::block;
return file_type::directory;
case DT_REG:
case DT_BLK:
return file_type::regular;
return file_type::block;
case DT_LNK:
case DT_REG:
return file_type::symlink;
return file_type::regular;
case DT_SOCK:
case DT_LNK:
return file_type::socket;
return file_type::symlink;
default:
break;
} // switch
case DT_SOCK:
}
return file_type::socket;
return file_type::unknown;
}
default:
break;
} // switch
}
const directory_entry& get_reference()
{
//printf("directory_iterator::impl::get_reference\n");
update();
return file_type::unknown;
}
return info;
}
const directory_entry&
get_reference()
{
// printf("directory_iterator::impl::get_reference\n");
update();
const directory_entry* get_pointer()
{
//printf("directory_iterator::impl::get_pointer\n");
update();
return info;
}
return &info;
}
const directory_entry*
get_pointer()
{
// printf("directory_iterator::impl::get_pointer\n");
update();
/// Position
size_t pos;
return &info;
}
// Path to directory
path p;
private:
void update()
{
//printf("directory_iterator::impl::update\n");
if ( !valid_info && e )
{
const path q = p / e->d_name;
/// Position
size_t pos;
info.assign(q);
valid_info = true;
}
}
// Path to directory
path p;
static dirent* acquire()
{
//printf("directory_iterator::impl::acquire\n");
/* dirent::d_name is required to be at least NAME_MAX + 1 bytes.
* However, some implementations use the struct hack and make d_name
* 1 byte. Watch for this scenario and adjust accordingly.
*/
if ( sizeof( static_cast< dirent* >( 0 )->d_name ) < NAME_MAX + 1 )
{
return static_cast< dirent* >( ::malloc(sizeof( dirent ) + NAME_MAX + 1) );
}
else
{
return static_cast< dirent* >( ::malloc( sizeof( dirent ) ) );
}
}
private:
void
update()
{
// printf("directory_iterator::impl::update\n");
if(!valid_info && e)
{
const path q = p / e->d_name;
void release()
{
//printf("directory_iterator::impl::release\n");
::free(e);
e = 0;
}
info.assign(q);
valid_info = true;
}
}
// constructor path
path cPath;
static dirent*
acquire()
{
// printf("directory_iterator::impl::acquire\n");
/* dirent::d_name is required to be at least NAME_MAX + 1 bytes.
* However, some implementations use the struct hack and make d_name
* 1 byte. Watch for this scenario and adjust accordingly.
*/
if(sizeof(static_cast< dirent* >(0)->d_name) < NAME_MAX + 1)
{
return static_cast< dirent* >(
::malloc(sizeof(dirent) + NAME_MAX + 1));
}
else
{
return static_cast< dirent* >(::malloc(sizeof(dirent)));
}
}
/// Platform information
DIR* d;
void
release()
{
// printf("directory_iterator::impl::release\n");
::free(e);
e = 0;
}
/// Platform information
dirent* e;
directory_entry info;
// constructor path
path cPath;
bool valid_info; // info has been populated
};
/// Platform information
DIR* d;
directory_iterator::directory_iterator()
: pimpl(new impl)
{
}
/// Platform information
dirent* e;
directory_iterator::directory_iterator(const path& path_)
: pimpl( new impl(path_) )
{
}
// is this right
directory_iterator::directory_iterator(directory_iterator const &src)
{
//printf("directory_iterator::directory_iterator copy - pimpl[%x] from[%s]\n", pimpl, src->path().c_str());
if (pimpl)
directory_entry info;
bool valid_info; // info has been populated
};
directory_iterator::directory_iterator() : pimpl(new impl)
{
//delete pimpl;
}
pimpl = new impl(src.pimpl->p.c_str());
pimpl->seek(src.pimpl->pos);
}
directory_iterator::~directory_iterator()
{
delete pimpl;
}
directory_iterator::directory_iterator(directory_iterator const &src, int pos) {
//printf("directory_iterator::directory_iterator copy at pos - pimpl[%x] from[%s]\n", pimpl, src->path().c_str());
pimpl = new impl(src.pimpl->p.c_str());
pimpl->seek(pos);
}
bool directory_iterator::operator==(const directory_iterator& i) const
{
// only equal if both are end iterators
return pimpl->is_end() && i.pimpl->is_end();
}
bool directory_iterator::operator!=(const directory_iterator& i) const
{
return !( pimpl->is_end() && i.pimpl->is_end() );
}
directory_iterator& directory_iterator::operator++()
{
pimpl->next();
return *this;
}
const directory_entry& directory_iterator::operator*() const
{
return pimpl->get_reference();
}
const directory_entry* directory_iterator::operator->() const
{
return pimpl->get_pointer();
}
file_type directory_iterator::type() const
{
return pimpl->type();
}
void directory_iterator::swap(directory_iterator& d)
{
std::swap(pimpl, d.pimpl);
}
// FIXME: this isn't right
directory_iterator directory_iterator::begin() {
return directory_iterator( *this, 0 );
/*
printf("directory_iterator::directory_iterator::begin - start\n");
size_t cur = pimpl->pos; // backup state
printf("directory_iterator::directory_iterator::begin - was at [%zu][%s]\n", cur, this->pimpl->get_path().c_str());
pimpl->rewind();
directory_iterator *ret = new directory_iterator(*this); // copy ourself
pimpl->seek(cur); // restore state
printf("directory_iterator::directory_iterator::begin - end\n");
return *ret;
*/
}
directory_iterator directory_iterator::end() {
//return *(directory_iterator *)endPtr;
//printf("directory_iterator::directory_iterator::end - start\n");
size_t cur = pimpl->pos; // backup state
//printf("directory_iterator::directory_iterator::end - was at [%zu][%s]\n", cur, this->pimpl->get_path().c_str());
// spool to the end
size_t finalPos = pimpl->pos;
while( !pimpl->is_end() )
directory_iterator::directory_iterator(const path& path_)
: pimpl(new impl(path_))
{
if (pimpl->next()) {
finalPos = pimpl->pos;
}
// is this right
directory_iterator::directory_iterator(directory_iterator const& src)
{
// printf("directory_iterator::directory_iterator copy - pimpl[%x]
// from[%s]\n", pimpl, src->path().c_str());
if(pimpl)
{
// delete pimpl;
}
pimpl = new impl(src.pimpl->p.c_str());
pimpl->seek(src.pimpl->pos);
}
directory_iterator::~directory_iterator()
{
delete pimpl;
}
directory_iterator::directory_iterator(directory_iterator const& src,
int pos)
{
// printf("directory_iterator::directory_iterator copy at pos - pimpl[%x]
// from[%s]\n", pimpl, src->path().c_str());
pimpl = new impl(src.pimpl->p.c_str());
pimpl->seek(pos);
}
bool
directory_iterator::operator==(const directory_iterator& i) const
{
// only equal if both are end iterators
return pimpl->is_end() && i.pimpl->is_end();
}
bool
directory_iterator::operator!=(const directory_iterator& i) const
{
return !(pimpl->is_end() && i.pimpl->is_end());
}
directory_iterator&
directory_iterator::operator++()
{
pimpl->next();
return *this;
}
const directory_entry& directory_iterator::operator*() const
{
return pimpl->get_reference();
}
const directory_entry* directory_iterator::operator->() const
{
return pimpl->get_pointer();
}
file_type
directory_iterator::type() const
{
return pimpl->type();
}
void
directory_iterator::swap(directory_iterator& d)
{
std::swap(pimpl, d.pimpl);
}
// FIXME: this isn't right
directory_iterator
directory_iterator::begin()
{
return directory_iterator(*this, 0);
/*
printf("directory_iterator::directory_iterator::begin - start\n");
size_t cur = pimpl->pos; // backup state
printf("directory_iterator::directory_iterator::begin - was at
[%zu][%s]\n", cur, this->pimpl->get_path().c_str()); pimpl->rewind();
directory_iterator *ret = new directory_iterator(*this); // copy ourself
pimpl->seek(cur); // restore state
printf("directory_iterator::directory_iterator::begin - end\n");
return *ret;
*/
}
directory_iterator
directory_iterator::end()
{
// return *(directory_iterator *)endPtr;
// printf("directory_iterator::directory_iterator::end - start\n");
size_t cur = pimpl->pos; // backup state
// printf("directory_iterator::directory_iterator::end - was at
// [%zu][%s]\n", cur, this->pimpl->get_path().c_str());
// spool to the end
size_t finalPos = pimpl->pos;
while(!pimpl->is_end())
{
if(pimpl->next())
{
finalPos = pimpl->pos;
}
}
// directory_iterator *ret = new directory_iterator(*this); // copy
// ourself printf("directory_iterator::directory_iterator::end - now at
// [%zu][%s]\n", pimpl->pos, this->pimpl->get_path().c_str());
pimpl->seek(cur); // restore state
return directory_iterator(*this, finalPos);
// printf("directory_iterator::directory_iterator::end - end\n");
// return *ret;
}
//
// recursive_directory_iterator
//
recursive_directory_iterator::recursive_directory_iterator()
{
}
recursive_directory_iterator::recursive_directory_iterator(const path& p)
{
descend(p);
}
recursive_directory_iterator::~recursive_directory_iterator()
{
while(!stack.empty())
{
ascend();
}
}
//directory_iterator *ret = new directory_iterator(*this); // copy ourself
//printf("directory_iterator::directory_iterator::end - now at [%zu][%s]\n", pimpl->pos, this->pimpl->get_path().c_str());
pimpl->seek(cur); // restore state
return directory_iterator( *this, finalPos);
//printf("directory_iterator::directory_iterator::end - end\n");
//return *ret;
}
//
// recursive_directory_iterator
//
recursive_directory_iterator::recursive_directory_iterator()
{
}
bool
recursive_directory_iterator::descend(const path& p)
{
directory_iterator it(p), end;
recursive_directory_iterator::recursive_directory_iterator(const path& p)
{
descend(p);
}
if(it != end)
{
directory_iterator* jt = new directory_iterator();
jt->swap(it);
stack.push(jt);
recursive_directory_iterator::~recursive_directory_iterator()
{
while ( !stack.empty() )
{
ascend();
}
}
return true;
}
bool recursive_directory_iterator::descend(const path& p)
{
directory_iterator it(p), end;
return false;
}
if ( it != end )
{
directory_iterator* jt = new directory_iterator();
jt->swap(it);
stack.push(jt);
void
recursive_directory_iterator::ascend()
{
delete stack.top();
stack.pop();
}
return true;
}
const directory_entry& recursive_directory_iterator::operator*() const
{
return *(*stack.top());
}
return false;
}
const directory_entry* recursive_directory_iterator::operator->() const
{
return stack.top()->operator->();
}
void recursive_directory_iterator::ascend()
{
delete stack.top();
stack.pop();
}
recursive_directory_iterator&
recursive_directory_iterator::operator++()
{
if(stack.top()->type() == file_type::directory)
{
// go to directory's first child (if any)
if(descend((*stack.top())->path()))
{
return *this;
}
}
const directory_entry& recursive_directory_iterator::operator*() const
{
return *( *stack.top() );
}
do
{
// move to sibling
stack.top()->operator++();
const directory_entry* recursive_directory_iterator::operator->() const
{
return stack.top()->operator->();
}
directory_iterator end;
recursive_directory_iterator& recursive_directory_iterator::operator++()
{
if ( stack.top()->type() == file_type::directory )
{
// go to directory's first child (if any)
if ( descend( ( *stack.top() )->path() ) )
{
return *this;
}
}
if(*(stack.top()) != end)
{
return *this;
}
do
{
// move to sibling
stack.top()->operator++();
// move to parent
ascend();
} while(!stack.empty());
directory_iterator end;
return *this;
}
if ( *( stack.top() ) != end )
{
return *this;
}
bool
recursive_directory_iterator::operator==(
const recursive_directory_iterator& i) const
{
return stack.empty() && i.stack.empty();
}
// move to parent
ascend();
}
while ( !stack.empty() );
bool
recursive_directory_iterator::operator!=(
const recursive_directory_iterator& i) const
{
return !(stack.empty() && i.stack.empty());
}
return *this;
}
bool recursive_directory_iterator::operator==(const recursive_directory_iterator& i) const
{
return stack.empty() && i.stack.empty();
}
bool recursive_directory_iterator::operator!=(const recursive_directory_iterator& i) const
{
return !( stack.empty() && i.stack.empty() );
}
}
}
} // namespace filesystem
} // namespace cpp17

View File

@ -30,7 +30,9 @@
#include <sys/types.h>
#include <sys/stat.h>
#ifndef _MSC_VER
#include <unistd.h>
#endif
namespace cpp17
{

View File

@ -1,281 +1,404 @@
/* Copyright (c) 2015, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include "filestatus.h"
#include <iostream>
#ifndef _MSC_VER
#include <unistd.h>
#endif
#include <sys/stat.h>
#include <sys/types.h>
#include "path.h"
#ifdef _MSC_VER
#include <Windows.h>
#include <stdint.h>
#include <io.h>
typedef unsigned short mode_t;
typedef uint32_t id_t; /* Internal uids/gids are 32-bits */
typedef SSIZE_T ssize_t;
#ifndef _OFF_T_DEFINED
typedef DWORD64 off_t;
#endif
typedef uint32_t uid_t; /* [???] user IDs */
#ifndef S_IFIFO
#define S_IFIFO 0010000 /* [XSI] named pipe (fifo) */
#endif
#ifndef S_IFBLK
#define S_IFBLK 0060000 /* [XSI] block special */
#endif
#ifndef S_IFLNK
#define S_IFLNK 0120000 /* [XSI] symbolic link */
#endif
#ifndef S_IFSOCK
#define S_IFSOCK 0140000 /* [XSI] socket */
#endif
#ifndef S_ISBLK
#define S_ISBLK(m) (((m)&S_IFMT) == S_IFBLK) /* block special */
#endif
#ifndef S_ISCHR
#define S_ISCHR(m) (((m)&S_IFMT) == S_IFCHR) /* char special */
#endif
#ifndef S_ISDIR
#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) /* directory */
#endif
#ifndef S_ISFIFO
#define S_ISFIFO(m) (((m)&S_IFMT) == S_IFIFO) /* fifo or socket */
#endif
#ifndef S_ISREG
#define S_ISREG(m) (((m)&S_IFMT) == S_IFREG) /* regular file */
#endif
#ifndef S_ISLNK
#define S_ISLNK(m) (((m)&S_IFMT) == S_IFLNK) /* symbolic link */
#endif
#ifndef S_ISSOCK
#define S_ISSOCK(m) (((m)&S_IFMT) == S_IFSOCK) /* socket */
#endif
#ifndef makedev
#define makedev(x, y) ((dev_t)(((x) << 24) | (y)))
#endif
#ifndef DT_UNKNOWN
#define DT_UNKNOWN 0
#endif
#ifndef DT_FIFO
#define DT_FIFO 1
#endif
#ifndef DT_CHR
#define DT_CHR 2
#endif
#ifndef DT_DIR
#define DT_DIR 4
#endif
#ifndef DT_BLK
#define DT_BLK 6
#endif
#ifndef DT_REG
#define DT_REG 8
#endif
#ifndef DT_LNK
#define DT_LNK 10
#endif
#ifndef DT_SOCK
#define DT_SOCK 12
#endif
#ifndef DT_WHT
#define DT_WHT 14
#endif
#endif
namespace
{
::cpp17::filesystem::file_status from_mode_t(mode_t m)
{
::cpp17::filesystem::perms p = static_cast< ::cpp17::filesystem::perms >( m & 0xFFF );
::cpp17::filesystem::file_status
from_mode_t(mode_t m)
{
::cpp17::filesystem::perms p =
static_cast<::cpp17::filesystem::perms >(m & 0xFFF);
::cpp17::filesystem::file_type t = file_type::unknown;
::cpp17::filesystem::file_type t = file_type::unknown;
if ( S_ISREG(m) )
{
t = file_type::regular;
}
else if ( S_ISDIR(m) )
{
t = file_type::directory;
}
else if ( S_ISCHR(m) )
{
t = file_type::character;
}
else if ( S_ISBLK(m) )
{
t = file_type::block;
}
else if ( S_ISFIFO(m) )
{
t = file_type::fifo;
}
if(S_ISREG(m))
{
t = file_type::regular;
}
else if(S_ISDIR(m))
{
t = file_type::directory;
}
else if(S_ISCHR(m))
{
t = file_type::character;
}
else if(S_ISBLK(m))
{
t = file_type::block;
}
else if(S_ISFIFO(m))
{
t = file_type::fifo;
}
#ifndef _WIN32 // these only work on cygnus or msys2!
else if(S_ISLNK(m))
{
t = file_type::symlink;
}
else if ( S_ISSOCK(m) )
{
t = file_type::socket;
}
else if(S_ISLNK(m))
{
t = file_type::symlink;
}
else if(S_ISSOCK(m))
{
t = file_type::socket;
}
#endif
return ::cpp17::filesystem::file_status(t, p);
}
return ::cpp17::filesystem::file_status(t, p);
}
}
} // namespace
namespace cpp17
{
namespace filesystem
{
file_status::file_status(const file_status& s)
: t(s.t), p(s.p)
{
namespace filesystem
{
file_status::file_status(const file_status& s) : t(s.t), p(s.p)
{
}
}
file_status::file_status(file_type t_, perms p_) : t(t_), p(p_)
{
}
file_status::file_status(
file_type t_,
perms p_
)
: t(t_), p(p_)
{
file_status&
file_status::operator=(const file_status& s)
{
t = s.t;
p = s.p;
}
return *this;
}
file_status& file_status::operator=(const file_status& s)
{
t = s.t;
p = s.p;
file_type
file_status::type() const
{
return t;
}
return *this;
}
void
file_status::type(file_type t_)
{
t = t_;
}
file_type file_status::type() const
{
return t;
}
perms
file_status::permissions() const
{
return p;
}
void file_status::type(file_type t_)
{
t = t_;
}
void
file_status::permissions(perms p_)
{
p = p_;
}
perms file_status::permissions() const
{
return p;
}
std::ostream&
operator<<(std::ostream& os, const file_status& fs)
{
os << fs.type() << "; " << fs.permissions();
void file_status::permissions(perms p_)
{
p = p_;
}
return os;
}
std::ostream& operator<<(
std::ostream& os,
const file_status& fs
)
{
os << fs.type() << "; " << fs.permissions();
file_status
status(const path& path_)
{
if(!path_.empty())
{
struct stat st;
return os;
}
if(::stat(path_.c_str(), &st) == 0)
{
return from_mode_t(st.st_mode);
}
}
file_status status(const path& path_)
{
if ( !path_.empty() )
{
struct stat st;
return file_status();
}
if ( ::stat(path_.c_str(), &st) == 0 )
{
return from_mode_t(st.st_mode);
}
}
return file_status();
}
file_status symlink_status(const path& path_)
{
if ( !path_.empty() )
{
struct stat st;
file_status
symlink_status(const path& path_)
{
if(!path_.empty())
{
struct stat st;
#ifndef _WIN32
if(::lstat(path_.c_str(), &st) == 0)
if(::lstat(path_.c_str(), &st) == 0)
#else
if(::stat(path_.c_str(), &st) == 0)
if(::stat(path_.c_str(), &st) == 0)
#endif
{
return from_mode_t(st.st_mode);
}
}
return file_status();
}
{
return from_mode_t(st.st_mode);
}
}
return file_status();
}
bool status_known(file_status s)
{
return s.type() != file_type::none;
}
bool
status_known(file_status s)
{
return s.type() != file_type::none;
}
bool exists(file_status s)
{
return status_known(s) && s.type() != file_type::not_found;
}
bool
exists(file_status s)
{
return status_known(s) && s.type() != file_type::not_found;
}
bool exists(const path& p, std::error_code& ec)
{
return exists( status(p) );
}
bool
exists(const path& p, std::error_code& ec)
{
return exists(status(p));
}
bool is_block_file(file_status s)
{
return s.type() == file_type::block;
}
bool
is_block_file(file_status s)
{
return s.type() == file_type::block;
}
bool is_block_file(const path& p)
{
return is_block_file( status(p) );
}
bool
is_block_file(const path& p)
{
return is_block_file(status(p));
}
bool is_character_file(file_status s)
{
return s.type() == file_type::character;
}
bool
is_character_file(file_status s)
{
return s.type() == file_type::character;
}
bool is_character_file(const path& p)
{
return is_character_file( status(p) );
}
bool
is_character_file(const path& p)
{
return is_character_file(status(p));
}
bool is_fifo(file_status s)
{
return s.type() == file_type::fifo;
}
bool
is_fifo(file_status s)
{
return s.type() == file_type::fifo;
}
bool is_fifo(const path& p)
{
return is_fifo( status(p) );
}
bool
is_fifo(const path& p)
{
return is_fifo(status(p));
}
bool is_other(file_status s)
{
return exists(s) && !is_regular_file(s) && !is_directory(s) && !is_symlink(s);
}
bool
is_other(file_status s)
{
return exists(s) && !is_regular_file(s) && !is_directory(s)
&& !is_symlink(s);
}
bool is_other(const path& p)
{
return is_other( status(p) );
}
bool
is_other(const path& p)
{
return is_other(status(p));
}
bool is_regular_file(file_status s)
{
return s.type() == file_type::regular;
}
bool
is_regular_file(file_status s)
{
return s.type() == file_type::regular;
}
bool is_regular_file(const path& p)
{
return is_regular_file( status(p) );
}
bool
is_regular_file(const path& p)
{
return is_regular_file(status(p));
}
bool is_socket(file_status s)
{
return s.type() == file_type::socket;
}
bool
is_socket(file_status s)
{
return s.type() == file_type::socket;
}
bool is_socket(const path& p)
{
return is_socket( status(p) );
}
bool
is_socket(const path& p)
{
return is_socket(status(p));
}
bool is_symlink(file_status s)
{
return s.type() == file_type::symlink;
}
bool
is_symlink(file_status s)
{
return s.type() == file_type::symlink;
}
bool is_symlink(const path& p)
{
return is_symlink( status(p) );
}
bool
is_symlink(const path& p)
{
return is_symlink(status(p));
}
bool is_directory(file_status s)
{
return s.type() == file_type::directory;
}
bool
is_directory(file_status s)
{
return s.type() == file_type::directory;
}
bool is_directory(const path& p)
{
return is_directory( status(p) );
}
bool
is_directory(const path& p)
{
return is_directory(status(p));
}
std::size_t file_size(const path& p)
{
if ( !p.empty() )
{
struct stat st;
std::size_t
file_size(const path& p)
{
if(!p.empty())
{
struct stat st;
if ( ::stat(p.c_str(), &st) == 0 )
{
return st.st_size;
}
}
if(::stat(p.c_str(), &st) == 0)
{
return st.st_size;
}
}
return std::size_t(-1);
}
}
}
return std::size_t(-1);
}
} // namespace filesystem
} // namespace cpp17

File diff suppressed because it is too large Load Diff

View File

@ -72,7 +72,7 @@ tuntap_sys_start(struct device *dev, int mode, int tun)
tuntap_log(TUNTAP_LOG_ERR, "Invalid parameter 'mode'");
return -1;
}
// ifr.ifr_flags |= IFF_NO_PI;
ifr.ifr_flags |= IFF_NO_PI;
if(tun < 0)
{

View File

@ -135,7 +135,6 @@ tuntap_sys_start(struct device *dev, int mode, int tun) {
"Can't get link-layer address");
return fd;
}
(void)memcpy(dev->hwaddr, &addr, ETHER_ADDR_LEN);
}
return fd;
}

View File

@ -21,353 +21,427 @@
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <strsafe.h>
/*#include <strsafe.h>*/
#include "tuntap.h"
// DDK macros
#define CTL_CODE(DeviceType, Function, Method, Access) \
(((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
#define FILE_DEVICE_UNKNOWN 0x00000022
#define FILE_ANY_ACCESS 0x00000000
#define METHOD_BUFFERED 0
/* From OpenVPN tap driver, common.h */
#define TAP_CONTROL_CODE(request,method) CTL_CODE(FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
#define TAP_IOCTL_GET_MAC TAP_CONTROL_CODE (1, METHOD_BUFFERED)
#define TAP_IOCTL_GET_VERSION TAP_CONTROL_CODE (2, METHOD_BUFFERED)
#define TAP_IOCTL_GET_MTU TAP_CONTROL_CODE (3, METHOD_BUFFERED)
#define TAP_IOCTL_GET_INFO TAP_CONTROL_CODE (4, METHOD_BUFFERED)
#define TAP_IOCTL_CONFIG_POINT_TO_POINT TAP_CONTROL_CODE (5, METHOD_BUFFERED)
#define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE (6, METHOD_BUFFERED)
#define TAP_IOCTL_CONFIG_DHCP_MASQ TAP_CONTROL_CODE (7, METHOD_BUFFERED)
#define TAP_IOCTL_GET_LOG_LINE TAP_CONTROL_CODE (8, METHOD_BUFFERED)
#define TAP_IOCTL_CONFIG_DHCP_SET_OPT TAP_CONTROL_CODE (9, METHOD_BUFFERED)
#define TAP_IOCTL_CONFIG_TUN TAP_CONTROL_CODE (10, METHOD_BUFFERED)
#define TAP_CONTROL_CODE(request, method) \
CTL_CODE(FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
#define TAP_IOCTL_GET_MAC TAP_CONTROL_CODE(1, METHOD_BUFFERED)
#define TAP_IOCTL_GET_VERSION TAP_CONTROL_CODE(2, METHOD_BUFFERED)
#define TAP_IOCTL_GET_MTU TAP_CONTROL_CODE(3, METHOD_BUFFERED)
#define TAP_IOCTL_GET_INFO TAP_CONTROL_CODE(4, METHOD_BUFFERED)
#define TAP_IOCTL_CONFIG_POINT_TO_POINT TAP_CONTROL_CODE(5, METHOD_BUFFERED)
#define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE(6, METHOD_BUFFERED)
#define TAP_IOCTL_CONFIG_DHCP_MASQ TAP_CONTROL_CODE(7, METHOD_BUFFERED)
#define TAP_IOCTL_GET_LOG_LINE TAP_CONTROL_CODE(8, METHOD_BUFFERED)
#define TAP_IOCTL_CONFIG_DHCP_SET_OPT TAP_CONTROL_CODE(9, METHOD_BUFFERED)
#define TAP_IOCTL_CONFIG_TUN TAP_CONTROL_CODE(10, METHOD_BUFFERED)
/* Windows registry crap */
#define MAX_KEY_LENGTH 255
#define MAX_VALUE_NAME 16383
#define NETWORK_ADAPTERS "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
#define NETWORK_ADAPTERS \
"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-" \
"08002BE10318}"
#define ETHER_ADDR_LEN 6
/* From OpenVPN tap driver, proto.h */
typedef unsigned long IPADDR;
/* This one is from Fabien Pichot, in the tNETacle source code */
static LPWSTR
formated_error(LPWSTR pMessage, DWORD m, ...) {
LPWSTR pBuffer = NULL;
formated_error(LPWSTR pMessage, DWORD m, ...)
{
LPWSTR pBuffer = NULL;
va_list args = NULL;
va_start(args, pMessage);
va_list args = NULL;
va_start(args, pMessage);
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_ALLOCATE_BUFFER,
pMessage,
m,
0,
(LPSTR)&pBuffer,
0,
&args);
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
pMessage, m, 0, (LPSTR)&pBuffer, 0, &args);
va_end(args);
va_end(args);
return pBuffer;
return pBuffer;
}
/* TODO: Rework to be more generic and allow arbitrary key modification (MTU and stuff) */
/* TODO: Rework to be more generic and allow arbitrary key modification (MTU and
* stuff) */
static char *
reg_query(char *key_name) {
HKEY adapters, adapter;
DWORD i, ret, len;
char *deviceid = NULL;
DWORD sub_keys = 0;
reg_query(char *key_name)
{
HKEY adapters, adapter;
DWORD i, ret, len;
char *deviceid = NULL;
DWORD sub_keys = 0;
ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(key_name), 0, KEY_READ, &adapters);
if (ret != ERROR_SUCCESS) {
tuntap_log(TUNTAP_LOG_ERR, (const char *)formated_error(L"%1%0", ret));
return NULL;
}
ret =
RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(key_name), 0, KEY_READ, &adapters);
if(ret != ERROR_SUCCESS)
{
tuntap_log(TUNTAP_LOG_ERR, (const char *)formated_error(L"%1%0", ret));
return NULL;
}
ret = RegQueryInfoKey(adapters, NULL, NULL, NULL, &sub_keys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
if (ret != ERROR_SUCCESS) {
tuntap_log(TUNTAP_LOG_ERR, (const char *)formated_error(L"%1%0", ret));
return NULL;
}
ret = RegQueryInfoKey(adapters, NULL, NULL, NULL, &sub_keys, NULL, NULL, NULL,
NULL, NULL, NULL, NULL);
if(ret != ERROR_SUCCESS)
{
tuntap_log(TUNTAP_LOG_ERR, (const char *)formated_error(L"%1%0", ret));
return NULL;
}
if (sub_keys <= 0) {
tuntap_log(TUNTAP_LOG_DEBUG, "Wrong registry key");
return NULL;
}
if(sub_keys <= 0)
{
tuntap_log(TUNTAP_LOG_DEBUG, "Wrong registry key");
return NULL;
}
/* Walk througt all adapters */
for (i = 0; i < sub_keys; i++) {
char new_key[MAX_KEY_LENGTH];
char data[256];
TCHAR key[MAX_KEY_LENGTH];
DWORD keylen = MAX_KEY_LENGTH;
/* Walk througt all adapters */
for(i = 0; i < sub_keys; i++)
{
char new_key[MAX_KEY_LENGTH];
char data[256];
TCHAR key[MAX_KEY_LENGTH];
DWORD keylen = MAX_KEY_LENGTH;
/* Get the adapter key name */
ret = RegEnumKeyEx(adapters, i, key, &keylen, NULL, NULL, NULL, NULL);
if (ret != ERROR_SUCCESS) {
continue;
}
/* Append it to NETWORK_ADAPTERS and open it */
snprintf(new_key, sizeof new_key, "%s\\%s", key_name, key);
ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(new_key), 0, KEY_READ, &adapter);
if (ret != ERROR_SUCCESS) {
continue;
}
/* Get the adapter key name */
ret = RegEnumKeyEx(adapters, i, key, &keylen, NULL, NULL, NULL, NULL);
if(ret != ERROR_SUCCESS)
{
continue;
}
/* Check its values */
len = sizeof data;
ret = RegQueryValueEx(adapter, "ComponentId", NULL, NULL, (LPBYTE)data, &len);
if (ret != ERROR_SUCCESS) {
/* This value doesn't exist in this adaptater tree */
goto clean;
}
/* If its a tap adapter, its all good */
if (strncmp(data, "tap", 3) == 0) {
DWORD type;
/* Append it to NETWORK_ADAPTERS and open it */
snprintf(new_key, sizeof new_key, "%s\\%s", key_name, key);
ret =
RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(new_key), 0, KEY_READ, &adapter);
if(ret != ERROR_SUCCESS)
{
continue;
}
len = sizeof data;
ret = RegQueryValueEx(adapter, "NetCfgInstanceId", NULL, &type, (LPBYTE)data, &len);
if (ret != ERROR_SUCCESS) {
tuntap_log(TUNTAP_LOG_INFO, (const char *)formated_error(L"%1", ret));
goto clean;
}
deviceid = strdup(data);
break;
}
clean:
RegCloseKey(adapter);
}
RegCloseKey(adapters);
return deviceid;
/* Check its values */
len = sizeof data;
ret =
RegQueryValueEx(adapter, "ComponentId", NULL, NULL, (LPBYTE)data, &len);
if(ret != ERROR_SUCCESS)
{
/* This value doesn't exist in this adaptater tree */
goto clean;
}
/* If its a tap adapter, its all good */
if(strncmp(data, "tap", 3) == 0)
{
DWORD type;
len = sizeof data;
ret = RegQueryValueEx(adapter, "NetCfgInstanceId", NULL, &type,
(LPBYTE)data, &len);
if(ret != ERROR_SUCCESS)
{
tuntap_log(TUNTAP_LOG_INFO, (const char *)formated_error(L"%1", ret));
goto clean;
}
deviceid = strdup(data);
break;
}
clean:
RegCloseKey(adapter);
}
RegCloseKey(adapters);
return deviceid;
}
void
tuntap_sys_destroy(struct device *dev) {
(void)dev;
return;
tuntap_sys_destroy(struct device *dev)
{
(void)dev;
return;
}
int
tuntap_start(struct device *dev, int mode, int tun) {
HANDLE tun_fd;
char *deviceid;
char buf[60];
tuntap_start(struct device *dev, int mode, int tun)
{
HANDLE tun_fd;
char *deviceid;
char buf[60];
/* Don't re-initialise a previously started device */
if (dev->tun_fd != TUNFD_INVALID_VALUE) {
return -1;
}
/* Don't re-initialise a previously started device */
if(dev->tun_fd != TUNFD_INVALID_VALUE)
{
return -1;
}
/* Shift the persistence bit */
if (mode & TUNTAP_MODE_PERSIST) {
mode &= ~TUNTAP_MODE_PERSIST;
}
/* Shift the persistence bit */
if(mode & TUNTAP_MODE_PERSIST)
{
mode &= ~TUNTAP_MODE_PERSIST;
}
if (mode == TUNTAP_MODE_TUNNEL) {
tuntap_log(TUNTAP_LOG_NOTICE, "Layer 3 tunneling is not implemented");
return -1;
}
else if (mode != TUNTAP_MODE_ETHERNET) {
tuntap_log(TUNTAP_LOG_ERR, "Invalid parameter 'mode'");
return -1;
}
if(mode == TUNTAP_MODE_TUNNEL)
{
tuntap_log(TUNTAP_LOG_NOTICE, "Layer 3 tunneling is not implemented");
return -1;
}
else if(mode != TUNTAP_MODE_ETHERNET)
{
tuntap_log(TUNTAP_LOG_ERR, "Invalid parameter 'mode'");
return -1;
}
deviceid = reg_query(NETWORK_ADAPTERS);
snprintf(buf, sizeof buf, "\\\\.\\Global\\%s.tap", deviceid);
tun_fd = CreateFile(buf, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM|FILE_FLAG_OVERLAPPED, 0);
if (tun_fd == TUNFD_INVALID_VALUE) {
int errcode = GetLastError();
deviceid = reg_query(NETWORK_ADAPTERS);
snprintf(buf, sizeof buf, "\\\\.\\Global\\%s.tap", deviceid);
tun_fd = CreateFile(buf, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING,
FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
if(tun_fd == TUNFD_INVALID_VALUE)
{
int errcode = GetLastError();
tuntap_log(TUNTAP_LOG_ERR, (const char *)formated_error(L"%1%0", errcode));
return -1;
}
tuntap_log(TUNTAP_LOG_ERR, (const char *)formated_error(L"%1%0", errcode));
return -1;
}
dev->tun_fd = tun_fd;
return 0;
dev->tun_fd = tun_fd;
return 0;
}
void
tuntap_release(struct device *dev) {
(void)CloseHandle(dev->tun_fd);
free(dev);
tuntap_release(struct device *dev)
{
(void)CloseHandle(dev->tun_fd);
free(dev);
}
char *
tuntap_get_hwaddr(struct device *dev) {
static unsigned char hwaddr[ETHER_ADDR_LEN];
DWORD len;
tuntap_get_hwaddr(struct device *dev)
{
static unsigned char hwaddr[ETHER_ADDR_LEN];
DWORD len;
if (DeviceIoControl(dev->tun_fd, TAP_IOCTL_GET_MAC, &hwaddr, sizeof(hwaddr), &hwaddr, sizeof(hwaddr), &len, NULL) == 0) {
int errcode = GetLastError();
if(DeviceIoControl(dev->tun_fd, TAP_IOCTL_GET_MAC, &hwaddr, sizeof(hwaddr),
&hwaddr, sizeof(hwaddr), &len, NULL)
== 0)
{
int errcode = GetLastError();
tuntap_log(TUNTAP_LOG_ERR, (const char *)formated_error(L"%1%0", errcode));
return NULL;
} else {
char buf[128];
(void)_snprintf_s(buf, sizeof buf, sizeof buf, "MAC address: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
hwaddr[0],hwaddr[1],hwaddr[2],hwaddr[3],hwaddr[4],hwaddr[5]);
tuntap_log(TUNTAP_LOG_DEBUG, buf);
}
return (char *)hwaddr;
tuntap_log(TUNTAP_LOG_ERR, (const char *)formated_error(L"%1%0", errcode));
return NULL;
}
else
{
char buf[128];
(void)_snprintf(buf, sizeof buf,
"MAC address: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x", hwaddr[0],
hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);
tuntap_log(TUNTAP_LOG_DEBUG, buf);
}
return (char *)hwaddr;
}
int
tuntap_set_hwaddr(struct device *dev, const char *hwaddr) {
tuntap_log(TUNTAP_LOG_NOTICE, "Your system does not support tuntap_set_hwaddr()");
return -1;
tuntap_set_hwaddr(struct device *dev, const char *hwaddr)
{
tuntap_log(TUNTAP_LOG_NOTICE,
"Your system does not support tuntap_set_hwaddr()");
return -1;
}
static int
tuntap_sys_set_updown(struct device *dev, ULONG flag) {
DWORD len;
tuntap_sys_set_updown(struct device *dev, ULONG flag)
{
DWORD len;
if (DeviceIoControl(dev->tun_fd, TAP_IOCTL_SET_MEDIA_STATUS, &flag, sizeof(flag), &flag, sizeof(flag), &len, NULL) == 0) {
int errcode = GetLastError();
if(DeviceIoControl(dev->tun_fd, TAP_IOCTL_SET_MEDIA_STATUS, &flag,
sizeof(flag), &flag, sizeof(flag), &len, NULL)
== 0)
{
int errcode = GetLastError();
tuntap_log(TUNTAP_LOG_ERR, (const char *)formated_error(L"%1%0", errcode));
return -1;
} else {
char buf[32];
tuntap_log(TUNTAP_LOG_ERR, (const char *)formated_error(L"%1%0", errcode));
return -1;
}
else
{
char buf[32];
(void)_snprintf_s(buf, sizeof buf, sizeof buf, "Status: %s", flag ? "Up" : "Down");
tuntap_log(TUNTAP_LOG_DEBUG, buf);
return 0;
}
(void)_snprintf(buf, sizeof buf, "Status: %s",
flag ? "Up" : "Down");
tuntap_log(TUNTAP_LOG_DEBUG, buf);
return 0;
}
}
int
tuntap_up(struct device *dev) {
ULONG flag;
tuntap_up(struct device *dev)
{
ULONG flag;
flag = 1;
return tuntap_sys_set_updown(dev, flag);
flag = 1;
return tuntap_sys_set_updown(dev, flag);
}
int
tuntap_down(struct device *dev) {
ULONG flag;
tuntap_down(struct device *dev)
{
ULONG flag;
flag = 0;
return tuntap_sys_set_updown(dev, flag);
flag = 0;
return tuntap_sys_set_updown(dev, flag);
}
int
tuntap_get_mtu(struct device *dev) {
ULONG mtu;
DWORD len;
tuntap_get_mtu(struct device *dev)
{
ULONG mtu;
DWORD len;
if (DeviceIoControl(dev->tun_fd, TAP_IOCTL_GET_MTU, &mtu, sizeof(mtu), &mtu, sizeof(mtu), &len, NULL) == 0) {
int errcode = GetLastError();
if(DeviceIoControl(dev->tun_fd, TAP_IOCTL_GET_MTU, &mtu, sizeof(mtu), &mtu,
sizeof(mtu), &len, NULL)
== 0)
{
int errcode = GetLastError();
tuntap_log(TUNTAP_LOG_ERR, (const char *)formated_error(L"%1%0", errcode));
return -1;
}
return 0;
tuntap_log(TUNTAP_LOG_ERR, (const char *)formated_error(L"%1%0", errcode));
return -1;
}
return 0;
}
int
tuntap_set_mtu(struct device *dev, int mtu) {
(void)dev;
(void)mtu;
tuntap_log(TUNTAP_LOG_NOTICE, "Your system does not support tuntap_set_mtu()");
return -1;
tuntap_set_mtu(struct device *dev, int mtu)
{
(void)dev;
(void)mtu;
tuntap_log(TUNTAP_LOG_NOTICE,
"Your system does not support tuntap_set_mtu()");
return -1;
}
int
tuntap_sys_set_ipv4(struct device *dev, t_tun_in_addr *s, uint32_t mask) {
IPADDR psock[4];
DWORD len;
tuntap_sys_set_ipv4(struct device *dev, t_tun_in_addr *s, uint32_t mask)
{
IPADDR psock[4];
DWORD len;
/* Address + Netmask */
psock[0] = s->S_un.S_addr;
psock[1] = mask;
/* DHCP server address (We don't want it) */
psock[2] = 0;
/* DHCP lease time */
psock[3] = 0;
/* Address + Netmask */
psock[0] = s->S_un.S_addr;
psock[1] = mask;
/* DHCP server address (We don't want it) */
psock[2] = 0;
/* DHCP lease time */
psock[3] = 0;
if (DeviceIoControl(dev->tun_fd, TAP_IOCTL_CONFIG_DHCP_MASQ, &psock, sizeof(psock), &psock, sizeof(psock), &len, NULL) == 0) {
int errcode = GetLastError();
if(DeviceIoControl(dev->tun_fd, TAP_IOCTL_CONFIG_DHCP_MASQ, &psock,
sizeof(psock), &psock, sizeof(psock), &len, NULL)
== 0)
{
int errcode = GetLastError();
tuntap_log(TUNTAP_LOG_ERR, (const char *)formated_error(L"%1%0", errcode));
return -1;
}
return 0;
tuntap_log(TUNTAP_LOG_ERR, (const char *)formated_error(L"%1%0", errcode));
return -1;
}
return 0;
}
int
tuntap_sys_set_ipv6(struct device *dev, t_tun_in6_addr *s, uint32_t mask) {
(void)dev;
(void)s;
(void)mask;
tuntap_log(TUNTAP_LOG_NOTICE, "Your system does not support tuntap_sys_set_ipv6()");
return -1;
tuntap_sys_set_ipv6(struct device *dev, t_tun_in6_addr *s, uint32_t mask)
{
(void)dev;
(void)s;
(void)mask;
tuntap_log(TUNTAP_LOG_NOTICE,
"Your system does not support tuntap_sys_set_ipv6()");
return -1;
}
int
tuntap_read(struct device *dev, void *buf, size_t size) {
DWORD len;
tuntap_read(struct device *dev, void *buf, size_t size)
{
DWORD len;
if (ReadFile(dev->tun_fd, buf, (DWORD)size, &len, NULL) == 0) {
int errcode = GetLastError();
if(ReadFile(dev->tun_fd, buf, (DWORD)size, &len, NULL) == 0)
{
int errcode = GetLastError();
tuntap_log(TUNTAP_LOG_ERR, (const char *)formated_error(L"%1%0", errcode));
return -1;
}
tuntap_log(TUNTAP_LOG_ERR, (const char *)formated_error(L"%1%0", errcode));
return -1;
}
return 0;
return 0;
}
int
tuntap_write(struct device *dev, void *buf, size_t size) {
DWORD len;
tuntap_write(struct device *dev, void *buf, size_t size)
{
DWORD len;
if (WriteFile(dev->tun_fd, buf, (DWORD)size, &len, NULL) == 0) {
int errcode = GetLastError();
if(WriteFile(dev->tun_fd, buf, (DWORD)size, &len, NULL) == 0)
{
int errcode = GetLastError();
tuntap_log(TUNTAP_LOG_ERR, (const char *)formated_error(L"%1%0", errcode));
return -1;
}
tuntap_log(TUNTAP_LOG_ERR, (const char *)formated_error(L"%1%0", errcode));
return -1;
}
return 0;
return 0;
}
int
tuntap_get_readable(struct device *dev) {
(void)dev;
tuntap_log(TUNTAP_LOG_NOTICE, "Your system does not support tuntap_get_readable()");
return -1;
tuntap_get_readable(struct device *dev)
{
(void)dev;
tuntap_log(TUNTAP_LOG_NOTICE,
"Your system does not support tuntap_get_readable()");
return -1;
}
int
tuntap_set_nonblocking(struct device *dev, int set) {
(void)dev;
(void)set;
tuntap_log(TUNTAP_LOG_NOTICE, "Your system does not support tuntap_set_nonblocking()");
return -1;
tuntap_set_nonblocking(struct device *dev, int set)
{
(void)dev;
(void)set;
tuntap_log(TUNTAP_LOG_NOTICE,
"Your system does not support tuntap_set_nonblocking()");
return -1;
}
int
tuntap_set_debug(struct device *dev, int set) {
(void)dev;
(void)set;
tuntap_log(TUNTAP_LOG_NOTICE, "Your system does not support tuntap_set_debug()");
return -1;
tuntap_set_debug(struct device *dev, int set)
{
(void)dev;
(void)set;
tuntap_log(TUNTAP_LOG_NOTICE,
"Your system does not support tuntap_set_debug()");
return -1;
}
int
tuntap_set_descr(struct device *dev, const char *descr) {
(void)dev;
(void)descr;
tuntap_log(TUNTAP_LOG_NOTICE, "Your system does not support tuntap_set_descr()");
return -1;
tuntap_set_descr(struct device *dev, const char *descr)
{
(void)dev;
(void)descr;
tuntap_log(TUNTAP_LOG_NOTICE,
"Your system does not support tuntap_set_descr()");
return -1;
}
int
tuntap_set_ifname(struct device *dev, const char *name) {
/* TODO: Check Windows API to know how to rename an interface */
(void)dev;
(void)name;
tuntap_log(TUNTAP_LOG_NOTICE, "Your system does not support tuntap_set_ifname()");
return -1;
tuntap_set_ifname(struct device *dev, const char *name)
{
/* TODO: Check Windows API to know how to rename an interface */
(void)dev;
(void)name;
tuntap_log(TUNTAP_LOG_NOTICE,
"Your system does not support tuntap_set_ifname()");
return -1;
}

View File

@ -31,6 +31,12 @@
#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
#ifndef _MSC_VER
extern "C" int
inet_pton(int af, const char *src, void *dst);
extern "C" const char *
inet_ntop(int af, const void *src, char *dst, size_t size);
#endif
#else
#include <arpa/inet.h>
#include <netinet/in.h>