Merge branch 'feature/update-dependencies' into develop

This commit is contained in:
Sergey Abramchuk
2017-04-15 12:15:07 +03:00
39 changed files with 773 additions and 223 deletions

View File

@@ -83,7 +83,7 @@
// on Android and iOS, use TunBuilderBase abstraction
#include <openvpn/common/platform.hpp>
#if (defined(OPENVPN_PLATFORM_ANDROID) || defined(OPENVPN_PLATFORM_IPHONE)) && !defined(OPENVPN_FORCE_TUN_NULL) && !defined(OPENVPN_CUSTOM_TUN_FACTORY)
#if (defined(OPENVPN_PLATFORM_ANDROID) || defined(OPENVPN_PLATFORM_IPHONE)) && !defined(OPENVPN_FORCE_TUN_NULL) && !defined(OPENVPN_EXTERNAL_TUN_FACTORY)
#define USE_TUN_BUILDER
#endif
@@ -92,6 +92,7 @@
#include <openvpn/common/platform_string.hpp>
#include <openvpn/common/count.hpp>
#include <openvpn/asio/asiostop.hpp>
#include <openvpn/time/asiotimer.hpp>
#include <openvpn/client/cliconnect.hpp>
#include <openvpn/client/cliopthelper.hpp>
#include <openvpn/options/merge.hpp>
@@ -205,7 +206,8 @@ namespace openvpn {
// save connected event
if (event->id() == ClientEvent::CONNECTED)
last_connected = std::move(event);
else if (event->id() == ClientEvent::DISCONNECTED)
parent->on_disconnect();
parent->event(ev);
}
}
@@ -341,6 +343,51 @@ namespace openvpn {
OpenVPNClient* parent = nullptr;
};
class MyClockTick
{
public:
MyClockTick(openvpn_io::io_context& io_context,
OpenVPNClient* parent_arg,
const unsigned int ms)
: timer(io_context),
parent(parent_arg),
period(Time::Duration::milliseconds(ms))
{
}
void cancel()
{
timer.cancel();
}
void detach_from_parent()
{
parent = nullptr;
}
void schedule()
{
timer.expires_after(period);
timer.async_wait([this](const openvpn_io::error_code& error)
{
if (!parent || error)
return;
try {
parent->clock_tick();
}
catch (...)
{
}
schedule();
});
}
private:
AsioTimer timer;
OpenVPNClient* parent;
const Time::Duration period;
};
namespace Private {
class ClientState
{
@@ -355,6 +402,7 @@ namespace openvpn {
MySessionStats::Ptr stats;
MyClientEvents::Ptr events;
ClientConnect::Ptr session;
std::unique_ptr<MyClockTick> clock_tick;
// extra settings submitted by API client
std::string server_override;
@@ -376,6 +424,7 @@ namespace openvpn {
ProtoContextOptions::Ptr proto_context_options;
PeerInfo::Set::Ptr extra_peer_info;
HTTPProxyTransport::Options::Ptr http_proxy_options;
unsigned int clock_tick_ms = 0;
#ifdef OPENVPN_GREMLIN
Gremlin::Config::Ptr gremlin_config;
#endif
@@ -429,6 +478,8 @@ namespace openvpn {
socket_protect.detach_from_parent();
reconnect_notify.detach_from_parent();
remote_override.detach_from_parent();
if (clock_tick)
clock_tick->detach_from_parent();
if (stats)
stats->detach_from_parent();
if (events)
@@ -474,6 +525,13 @@ namespace openvpn {
async_stop_local_.stop();
}
// disconnect
void on_disconnect()
{
if (clock_tick)
clock_tick->cancel();
}
private:
ClientState(const ClientState&) = delete;
ClientState& operator=(const ClientState&) = delete;
@@ -596,6 +654,7 @@ namespace openvpn {
state->dco = config.dco;
state->echo = config.echo;
state->info = config.info;
state->clock_tick_ms = config.clockTickMS;
if (!config.gremlinConfig.empty())
{
#ifdef OPENVPN_GREMLIN
@@ -755,7 +814,9 @@ namespace openvpn {
OPENVPN_CLIENT_EXPORT Status OpenVPNClient::connect()
{
#if !defined(OPENVPN_OVPNCLI_SINGLE_THREAD)
openvpn_io::detail::signal_blocker signal_blocker; // signals should be handled by parent thread
#endif
#if defined(OPENVPN_LOG_LOGTHREAD_H) && !defined(OPENVPN_LOG_LOGBASE_H)
#ifdef OPENVPN_LOG_GLOBAL
#error ovpn3 core logging object only supports thread-local scope
@@ -815,6 +876,9 @@ namespace openvpn {
cc.socket_protect = &state->socket_protect;
cc.builder = this;
#endif
#if defined(OPENVPN_EXTERNAL_TUN_FACTORY)
cc.extern_tun_factory = this;
#endif
// force Session ID use and disable password cache if static challenge is enabled
if (state->creds
@@ -864,6 +928,13 @@ namespace openvpn {
// instantiate top-level client session
state->session.reset(new ClientConnect(*state->io_context(), client_options));
// convenience clock tick
if (state->clock_tick_ms)
{
state->clock_tick.reset(new MyClockTick(*state->io_context(), this, state->clock_tick_ms));
state->clock_tick->schedule();
}
// raise an exception if app has expired
check_app_expired();
@@ -1142,7 +1213,7 @@ namespace openvpn {
{
ClientConnect* session = state->session.get();
if (session)
state->session->thread_safe_resume();
session->thread_safe_resume();
}
}
@@ -1152,7 +1223,7 @@ namespace openvpn {
{
ClientConnect* session = state->session.get();
if (session)
state->session->thread_safe_reconnect(seconds);
session->thread_safe_reconnect(seconds);
}
}
@@ -1162,10 +1233,19 @@ namespace openvpn {
{
ClientConnect* session = state->session.get();
if (session)
state->session->thread_safe_post_cc_msg(msg);
session->thread_safe_post_cc_msg(msg);
}
}
OPENVPN_CLIENT_EXPORT void OpenVPNClient::clock_tick()
{
}
OPENVPN_CLIENT_EXPORT void OpenVPNClient::on_disconnect()
{
state->on_disconnect();
}
OPENVPN_CLIENT_EXPORT std::string OpenVPNClient::crypto_self_test()
{
return SelfTest::crypto_self_test();

View File

@@ -29,6 +29,7 @@
#include <utility>
#include <openvpn/tun/builder/base.hpp>
#include <openvpn/tun/extern/fw.hpp>
#include <openvpn/pki/epkibase.hpp>
namespace openvpn {
@@ -269,6 +270,11 @@ namespace openvpn {
// pass through control channel INFO notifications via "INFO" event
bool info = false;
// Periodic convenience clock tick in milliseconds.
// Will call clock_tick() at a frequency defined by this parameter.
// Set to 0 to disable.
unsigned int clockTickMS = 0;
// Gremlin configuration (requires that the core is built with OPENVPN_GREMLIN)
std::string gremlinConfig;
};
@@ -403,7 +409,11 @@ namespace openvpn {
};
// Top-level OpenVPN client class.
class OpenVPNClient : public TunBuilderBase, public LogReceiver, private ExternalPKIBase {
class OpenVPNClient : public TunBuilderBase, // expose tun builder virtual methods
public LogReceiver, // log message notification
public ExternalTun::Factory, // low-level tun override
private ExternalPKIBase
{
public:
OpenVPNClient();
virtual ~OpenVPNClient();
@@ -523,6 +533,9 @@ namespace openvpn {
virtual bool remote_override_enabled();
virtual void remote_override(RemoteOverride&);
// Periodic convenience clock tick, controlled by Config::clock_tick_ms
virtual void clock_tick();
// Do a crypto library self test
static std::string crypto_self_test();
@@ -561,6 +574,9 @@ namespace openvpn {
void check_app_expired();
static MergeConfig build_merge_config(const ProfileMerge&);
friend class MyClientEvents;
void on_disconnect();
// from ExternalPKIBase
virtual bool sign(const std::string& data, std::string& sig);

View File

@@ -12,8 +12,9 @@
#include "ovpncli.hpp"
%}
// ignore ClientAPI::OpenVPNClient bases other than TunBuilderBase
// ignore these ClientAPI::OpenVPNClient bases
%ignore openvpn::ClientAPI::LogReceiver;
%ignore openvpn::ExternalTun::Factory;
// modify exported C++ class names to incorporate their enclosing namespace
%rename(ClientAPI_OpenVPNClient) OpenVPNClient;
@@ -47,4 +48,5 @@ namespace std {
// interface to be bridged between C++ and target language
%include "openvpn/pki/epkibase.hpp"
%include "openvpn/tun/builder/base.hpp"
%import "openvpn/tun/extern/fw.hpp" // ignored
%include "ovpncli.hpp"

View File

@@ -26,13 +26,11 @@
#include <iostream>
#include <sstream>
#include <algorithm>
#include <utility>
#include <exception>
#include <CoreFoundation/CoreFoundation.h>
#include <openvpn/common/size.hpp>
#include <openvpn/common/exception.hpp>
#include <openvpn/buffer/buffer.hpp>
// Wrapper classes for Apple Core Foundation objects.
#define OPENVPN_CF_WRAP(cls, castmeth, cftype, idmeth) \
@@ -52,7 +50,7 @@
{ \
CFTypeRef o = Type<cftype>::cast(obj); \
if (o) \
return cls(cftype(o), BORROW); \
return cls(cftype(o), GET); \
else \
return cls(); \
}
@@ -60,9 +58,9 @@
namespace openvpn {
namespace CF
{
enum Own {
OWN,
BORROW
enum Rule {
CREATE, // create rule
GET // get rule
};
template <typename T> struct Type {};
@@ -73,10 +71,9 @@ namespace openvpn {
public:
Wrap() : obj_(nullptr) {}
// Set own=BORROW if we don't currently own the object
explicit Wrap(T obj, const Own own=OWN)
explicit Wrap(T obj, const Rule rule=CREATE)
{
if (own == BORROW && obj)
if (rule == GET && obj)
CFRetain(obj);
obj_ = obj;
}
@@ -118,9 +115,9 @@ namespace openvpn {
std::swap(obj_, other.obj_);
}
void reset(T obj=nullptr, const Own own=OWN)
void reset(T obj=nullptr, const Rule rule=CREATE)
{
if (own == BORROW && obj)
if (rule == GET && obj)
CFRetain(obj);
if (obj_)
CFRelease(obj_);
@@ -129,15 +126,20 @@ namespace openvpn {
bool defined() const { return obj_ != nullptr; }
explicit operator bool() const noexcept
{
return defined();
}
T operator()() const { return obj_; }
CFTypeRef generic() const { return (CFTypeRef)obj_; }
static T cast(CFTypeRef obj) { return T(Type<T>::cast(obj)); }
static Wrap from_generic(CFTypeRef obj, const Own own=OWN)
static Wrap from_generic(CFTypeRef obj, const Rule rule=CREATE)
{
return Wrap(cast(obj), own);
return Wrap(cast(obj), rule);
}
T release()
@@ -155,7 +157,7 @@ namespace openvpn {
}
// Intended for use with Core Foundation methods that require
// a T* for saving a (non-borrowed) return value
// a T* for saving a create-rule return value
T* mod_ref()
{
if (obj_)
@@ -181,14 +183,11 @@ namespace openvpn {
}
private:
Wrap& operator=(T obj); // prevent use because no way to pass ownership parameter
Wrap& operator=(T obj) = delete; // prevent use because no way to pass rule parameter
T obj_;
};
// essentially a vector of void *, used as source for array and dictionary constructors
typedef BufferAllocatedType<CFTypeRef> SrcList;
// common CF types
OPENVPN_CF_WRAP(String, string_cast, CFStringRef, CFStringGetTypeID)
@@ -207,7 +206,7 @@ namespace openvpn {
inline Generic generic_cast(CFTypeRef obj)
{
return Generic(obj, BORROW);
return Generic(obj, GET);
}
// constructors
@@ -219,7 +218,7 @@ namespace openvpn {
inline String string(CFStringRef str)
{
return String(str, BORROW);
return String(str, GET);
}
inline String string(const String& str)
@@ -267,11 +266,6 @@ namespace openvpn {
return Array(CFArrayCreate(kCFAllocatorDefault, values, numValues, &kCFTypeArrayCallBacks));
}
inline Array array(const SrcList& values)
{
return array((const void **)values.c_data(), values.size());
}
inline Dict dict(const void **keys, const void **values, CFIndex numValues)
{
return Dict(CFDictionaryCreate(kCFAllocatorDefault,
@@ -282,19 +276,14 @@ namespace openvpn {
&kCFTypeDictionaryValueCallBacks));
}
inline Dict dict(const SrcList& keys, const SrcList& values)
{
return dict((const void **)keys.c_data(), (const void **)values.c_data(), std::min(keys.size(), values.size()));
}
inline Dict const_dict(MutableDict& mdict)
{
return Dict(mdict(), CF::BORROW);
return Dict(mdict(), CF::GET);
}
inline Array const_array(MutableArray& marray)
{
return Array(marray(), CF::BORROW);
return Array(marray(), CF::GET);
}
inline Dict empty_dict()
@@ -374,7 +363,13 @@ namespace openvpn {
// string methods
OPENVPN_SIMPLE_EXCEPTION(cppstring_error);
struct cppstring_error : public std::exception
{
virtual const char* what() const throw()
{
return "cppstring_error";
}
};
inline std::string cppstring(CFStringRef str)
{

View File

@@ -22,7 +22,8 @@
#ifndef OPENVPN_APPLECRYPTO_CF_CFHELPER_H
#define OPENVPN_APPLECRYPTO_CF_CFHELPER_H
#include <openvpn/applecrypto/cf/cf.hpp>
#include <openvpn/buffer/buffer.hpp>
#include <openvpn/apple/cf/cf.hpp>
// These methods build on the Wrapper classes for Apple Core Foundation objects
// defined in cf.hpp. They add additional convenience methods, such as dictionary
@@ -31,6 +32,19 @@
namespace openvpn {
namespace CF {
// essentially a vector of void *, used as source for array and dictionary constructors
typedef BufferAllocatedType<CFTypeRef> SrcList;
inline Array array(const SrcList& values)
{
return array((const void **)values.c_data(), values.size());
}
inline Dict dict(const SrcList& keys, const SrcList& values)
{
return dict((const void **)keys.c_data(), (const void **)values.c_data(), std::min(keys.size(), values.size()));
}
inline CFTypeRef mutable_dict_new()
{
return CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);

View File

@@ -0,0 +1,33 @@
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License Version 3
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
#ifndef OPENVPN_APPLECRYPTO_CF_CFHOST_H
#define OPENVPN_APPLECRYPTO_CF_CFHOST_H
#include <openvpn/apple/cf/cf.hpp>
namespace openvpn {
namespace CF {
OPENVPN_CF_WRAP(Host, host_cast, CFHostRef, CFHostGetTypeID)
}
}
#endif

View File

@@ -19,14 +19,14 @@
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
#ifndef OPENVPN_APPLE_RUNLOOP_H
#define OPENVPN_APPLE_RUNLOOP_H
#ifndef OPENVPN_APPLECRYPTO_CF_CFRUNLOOP_H
#define OPENVPN_APPLECRYPTO_CF_CFRUNLOOP_H
#include <openvpn/applecrypto/cf/cf.hpp>
#include <openvpn/apple/cf/cf.hpp>
namespace openvpn {
namespace CF {
OPENVPN_CF_WRAP(RunLoop, runloop_cast, CFRunLoopRef, CFRunLoopGetTypeID);
OPENVPN_CF_WRAP(RunLoop, runloop_cast, CFRunLoopRef, CFRunLoopGetTypeID)
OPENVPN_CF_WRAP(RunLoopSource, runloop_source_cast, CFRunLoopSourceRef, CFRunLoopSourceGetTypeID);
}
}

View File

@@ -36,7 +36,7 @@
#include <openvpn/common/size.hpp>
#include <openvpn/common/exception.hpp>
#include <openvpn/applecrypto/cf/cf.hpp>
#include <openvpn/apple/cf/cf.hpp>
// Define C++ wrappings for Apple security-related objects.

View File

@@ -0,0 +1,33 @@
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License Version 3
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
#ifndef OPENVPN_APPLECRYPTO_CF_CFSTREAM_H
#define OPENVPN_APPLECRYPTO_CF_CFSTREAM_H
#include <openvpn/apple/cf/cf.hpp>
namespace openvpn {
namespace CF {
OPENVPN_CF_WRAP(Socket, socket_cast, CFSocketRef, CFSocketGetTypeID)
}
}
#endif

View File

@@ -0,0 +1,34 @@
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License Version 3
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
#ifndef OPENVPN_APPLECRYPTO_CF_CFSTREAM_H
#define OPENVPN_APPLECRYPTO_CF_CFSTREAM_H
#include <openvpn/apple/cf/cf.hpp>
namespace openvpn {
namespace CF {
OPENVPN_CF_WRAP(ReadStream, read_stream_cast, CFReadStreamRef, CFReadStreamGetTypeID)
OPENVPN_CF_WRAP(WriteStream, write_stream_cast, CFWriteStreamRef, CFWriteStreamGetTypeID)
}
}
#endif

View File

@@ -22,7 +22,7 @@
#ifndef OPENVPN_APPLECRYPTO_CF_CFTIMER_H
#define OPENVPN_APPLECRYPTO_CF_CFTIMER_H
#include <openvpn/applecrypto/cf/cf.hpp>
#include <openvpn/apple/cf/cf.hpp>
namespace openvpn {
namespace CF {

View File

@@ -21,7 +21,7 @@
#include <string>
#include <openvpn/applecrypto/util/reach.hpp>
#include <openvpn/apple/reach.hpp>
#include <openvpn/netconf/enumiface.hpp>
#ifndef OPENVPN_APPLECRYPTO_UTIL_IOSACTIVEIFACE_H

View File

@@ -28,11 +28,11 @@
#include <thread>
#include <openvpn/log/logthread.hpp>
#include <openvpn/applecrypto/cf/cftimer.hpp>
#include <openvpn/applecrypto/cf/cfhelper.hpp>
#include <openvpn/applecrypto/util/reachable.hpp>
#include <openvpn/apple/cf/cftimer.hpp>
#include <openvpn/apple/cf/cfhelper.hpp>
#include <openvpn/apple/cf/cfrunloop.hpp>
#include <openvpn/apple/reachable.hpp>
#include <openvpn/client/clilife.hpp>
#include <openvpn/apple/runloop.hpp>
#include <openvpn/apple/macsleep.hpp>
#include <openvpn/apple/scdynstore.hpp>
@@ -126,7 +126,7 @@ namespace openvpn {
void thread_func()
{
runloop.reset(CFRunLoopGetCurrent(), CF::BORROW);
runloop.reset(CFRunLoopGetCurrent(), CF::GET);
Log::Context logctx(logwrap);
try {
// set up dynamic store query object

View File

@@ -77,8 +77,8 @@
#include <memory>
#include <openvpn/common/socktypes.hpp>
#include <openvpn/applecrypto/cf/cf.hpp>
#include <openvpn/applecrypto/util/reach.hpp>
#include <openvpn/apple/cf/cf.hpp>
#include <openvpn/apple/reach.hpp>
namespace openvpn {
namespace CF {

View File

@@ -24,7 +24,7 @@
#include <SystemConfiguration/SCDynamicStore.h>
#include <openvpn/applecrypto/cf/cf.hpp>
#include <openvpn/apple/cf/cf.hpp>
namespace openvpn {
namespace CF {

View File

@@ -36,7 +36,7 @@
#include <openvpn/common/string.hpp>
#include <openvpn/crypto/static_key.hpp>
#include <openvpn/crypto/cryptoalgs.hpp>
#include <openvpn/applecrypto/cf/error.hpp>
#include <openvpn/apple/cf/error.hpp>
namespace openvpn {
namespace AppleCrypto {

View File

@@ -34,7 +34,7 @@
#include <openvpn/common/exception.hpp>
#include <openvpn/common/string.hpp>
#include <openvpn/crypto/cryptoalgs.hpp>
#include <openvpn/applecrypto/cf/error.hpp>
#include <openvpn/apple/cf/error.hpp>
#define OPENVPN_DIGEST_CONTEXT(TYPE) CC_##TYPE##_CTX TYPE##_ctx

View File

@@ -47,8 +47,8 @@
#include <openvpn/frame/frame.hpp>
#include <openvpn/frame/memq_stream.hpp>
#include <openvpn/pki/epkibase.hpp>
#include <openvpn/applecrypto/cf/cfsec.hpp>
#include <openvpn/applecrypto/cf/error.hpp>
#include <openvpn/apple/cf/cfsec.hpp>
#include <openvpn/apple/cf/error.hpp>
#include <openvpn/ssl/tlsver.hpp>
#include <openvpn/ssl/sslconsts.hpp>
#include <openvpn/ssl/sslapi.hpp>

View File

@@ -139,7 +139,9 @@ namespace openvpn {
#if !defined(OPENVPN_PLATFORM_WIN)
virtual void set_cloexec() override
{
SockOpt::set_cloexec(socket.native_handle());
const int fd = socket.native_handle();
if (fd >= 0)
SockOpt::set_cloexec(fd);
}
#endif
@@ -207,7 +209,9 @@ namespace openvpn {
virtual void set_cloexec() override
{
SockOpt::set_cloexec(socket.native_handle());
const int fd = socket.native_handle();
if (fd >= 0)
SockOpt::set_cloexec(fd);
}
virtual void close() override

View File

@@ -156,6 +156,9 @@ namespace openvpn {
ClientEvent::Base::Ptr ev = new ClientEvent::Disconnected();
client_options->events().add_event(std::move(ev));
#ifdef OPENVPN_IO_REQUIRES_STOP
io_context.stop();
#endif
}
}
@@ -214,7 +217,7 @@ namespace openvpn {
OPENVPN_LOG("Client terminated, reconnecting in " << seconds << "...");
server_poll_timer.cancel();
client_options->remote_reset_cache_item();
restart_wait_timer.expires_at(Time::now() + Time::Duration::seconds(seconds));
restart_wait_timer.expires_after(Time::Duration::seconds(seconds));
restart_wait_timer.async_wait([self=Ptr(this), gen=generation](const openvpn_io::error_code& error)
{
self->restart_wait_callback(gen, error);
@@ -345,7 +348,7 @@ namespace openvpn {
{
if (!conn_timer_pending && conn_timeout > 0)
{
conn_timer.expires_at(Time::now() + Time::Duration::seconds(conn_timeout));
conn_timer.expires_after(Time::Duration::seconds(conn_timeout));
conn_timer.async_wait([self=Ptr(this), gen=generation](const openvpn_io::error_code& error)
{
self->conn_timer_callback(gen, error);
@@ -393,7 +396,7 @@ namespace openvpn {
server_poll_timer.cancel();
interim_finalize();
client_options->remote_reset_cache_item();
restart_wait_timer.expires_at(Time::now() + Time::Duration::milliseconds(delay_ms));
restart_wait_timer.expires_after(Time::Duration::milliseconds(delay_ms));
restart_wait_timer.async_wait([self=Ptr(this), gen=generation](const openvpn_io::error_code& error)
{
self->restart_wait_callback(gen, error);
@@ -589,7 +592,7 @@ namespace openvpn {
restart_wait_timer.cancel();
if (client_options->server_poll_timeout_enabled())
{
server_poll_timer.expires_at(Time::now() + client_options->server_poll_timeout());
server_poll_timer.expires_after(client_options->server_poll_timeout());
server_poll_timer.async_wait([self=Ptr(this), gen=generation](const openvpn_io::error_code& error)
{
self->server_poll_callback(gen, error);

View File

@@ -66,8 +66,9 @@
#include <openvpn/client/cliemuexr.hpp>
#endif
#if defined(OPENVPN_CUSTOM_TUN_FACTORY)
// includer of this file must define OPENVPN_CUSTOM_TUN_FACTORY class
#if defined(OPENVPN_EXTERNAL_TUN_FACTORY)
// requires that client implements ExternalTun::Factory::new_tun_factory
#include <openvpn/tun/extern/config.hpp>
#elif defined(USE_TUN_BUILDER)
#include <openvpn/tun/builder/client.hpp>
#elif defined(OPENVPN_PLATFORM_LINUX) && !defined(OPENVPN_FORCE_TUN_NULL)
@@ -151,6 +152,10 @@ namespace openvpn {
#if defined(USE_TUN_BUILDER)
TunBuilderBase* builder = nullptr;
#endif
#if defined(OPENVPN_EXTERNAL_TUN_FACTORY)
ExternalTun::Factory* extern_tun_factory = nullptr;
#endif
};
ClientOptions(const OptionList& opt, // only needs to remain in scope for duration of constructor call
@@ -191,7 +196,7 @@ namespace openvpn {
rng.reset(new SSLLib::RandomAPI(false));
prng.reset(new SSLLib::RandomAPI(true));
#if defined(ENABLE_DCO) && !defined(OPENVPN_FORCE_TUN_NULL) && !defined(OPENVPN_CUSTOM_TUN_FACTORY)
#if defined(ENABLE_DCO) && !defined(OPENVPN_FORCE_TUN_NULL) && !defined(OPENVPN_EXTERNAL_TUN_FACTORY)
if (config.dco)
dco = DCOTransport::new_controller();
#else
@@ -292,17 +297,22 @@ namespace openvpn {
}
else
{
#if defined(OPENVPN_CUSTOM_TUN_FACTORY)
#if defined(OPENVPN_EXTERNAL_TUN_FACTORY)
{
OPENVPN_CUSTOM_TUN_FACTORY::Ptr tunconf = OPENVPN_CUSTOM_TUN_FACTORY::new_obj();
tunconf->tun_prop.session_name = session_name;
tunconf->tun_prop.google_dns_fallback = config.google_dns_fallback;
ExternalTun::Config tunconf;
tunconf.tun_prop.layer = layer;
tunconf.tun_prop.session_name = session_name;
tunconf.tun_prop.google_dns_fallback = config.google_dns_fallback;
if (tun_mtu)
tunconf->tun_prop.mtu = tun_mtu;
tunconf->frame = frame;
tunconf->stats = cli_stats;
tunconf->tun_prop.remote_list = remote_list;
tun_factory = tunconf;
tunconf.tun_prop.mtu = tun_mtu;
tunconf.frame = frame;
tunconf.stats = cli_stats;
tunconf.tun_prop.remote_list = remote_list;
tunconf.tun_persist = config.tun_persist;
tunconf.stop = config.stop;
tun_factory.reset(config.extern_tun_factory->new_tun_factory(tunconf, opt));
if (!tun_factory)
throw option_error("OPENVPN_EXTERNAL_TUN_FACTORY: no tun factory");
}
#elif defined(USE_TUN_BUILDER)
{
@@ -448,7 +458,7 @@ namespace openvpn {
// IPv6
{
const unsigned int n = push_base->singleton.extend(opt, "block-ipv6");
if (!n && config.ipv6() == IPv6Setting::NO)
if (!n && config.ipv6() == IPv6Setting::No)
push_base->singleton.emplace_back("block-ipv6");
}
}
@@ -463,9 +473,9 @@ namespace openvpn {
PeerInfo::Set::Ptr pi(new PeerInfo::Set);
// IPv6
if (config.ipv6() == IPv6Setting::NO)
if (config.ipv6() == IPv6Setting::No)
pi->emplace_back("IV_IPv6", "0");
else if (config.ipv6() == IPv6Setting::YES)
else if (config.ipv6() == IPv6Setting::Yes)
pi->emplace_back("IV_IPv6", "1");
// autologin sessions

View File

@@ -777,7 +777,7 @@ namespace openvpn {
{
if (!received_options.partial())
{
push_request_timer.expires_at(now() + dur);
push_request_timer.expires_after(dur);
push_request_timer.async_wait([self=Ptr(this), dur](const openvpn_io::error_code& error)
{
self->send_push_request_callback(dur, error);
@@ -865,7 +865,7 @@ namespace openvpn {
void schedule_inactive_timer()
{
inactive_timer.expires_at(now() + inactive_duration);
inactive_timer.expires_after(inactive_duration);
inactive_timer.async_wait([self=Ptr(this)](const openvpn_io::error_code& error)
{
self->inactive_callback(error);
@@ -955,7 +955,7 @@ namespace openvpn {
void schedule_info_hold_callback()
{
Base::update_now();
info_hold_timer.expires_at(now() + Time::Duration::seconds(1));
info_hold_timer.expires_after(Time::Duration::seconds(1));
info_hold_timer.async_wait([self=Ptr(this)](const openvpn_io::error_code& error)
{
self->info_hold_callback(error);

View File

@@ -24,36 +24,72 @@
#ifndef OPENVPN_COMMON_FUNCTION_H
#define OPENVPN_COMMON_FUNCTION_H
#include <cstddef> // for std::size_t
#include <utility> // for std::move
#include <new>
#include <utility>
namespace openvpn {
template <typename F>
// F -- function type (usually a lambda expression)
// N (default=3) -- max size of functor in void* machine words before we overflow to dynamic allocation
// INTERN_ONLY (default=false) -- if true, throw a static assertion if functor cannot be stored internally
template <typename F, std::size_t N=3, bool INTERN_ONLY=false>
class Function;
template <typename R, typename ... A>
class Function<R(A...)>
template <typename R, typename ... A, std::size_t N, bool INTERN_ONLY>
class Function<R(A...), N, INTERN_ONLY>
{
public:
static constexpr size_t N = 3; // max size of functor in machine words
Function() noexcept
{
methods = nullptr;
}
template <typename T>
Function(T&& functor) noexcept
{
static_assert(sizeof(Intern<T>) <= sizeof(data), "Functor too large");
setup_methods<T>();
new (data) Intern<T>(std::move(functor));
construct(std::move(functor));
}
Function(Function&& f) noexcept
Function(Function&& other) noexcept
{
methods = f.methods;
methods->move(data, f.data);
methods = other.methods;
other.methods = nullptr;
if (methods)
methods->move(data, other.data);
}
Function& operator=(Function&& other) noexcept
{
if (methods)
methods->destruct(data);
methods = other.methods;
other.methods = nullptr;
if (methods)
methods->move(data, other.data);
return *this;
}
~Function()
{
methods->destruct(data);
if (methods)
methods->destruct(data);
}
template <typename T>
void reset(T&& functor) noexcept
{
if (methods)
methods->destruct(data);
construct(std::move(functor));
}
void reset() noexcept
{
if (methods)
{
methods->destruct(data);
methods = nullptr;
}
}
R operator()(A... args)
@@ -61,7 +97,33 @@ namespace openvpn {
return methods->invoke(data, args...);
}
explicit operator bool() const noexcept
{
return methods != nullptr;
}
private:
template <typename T>
void construct(T&& functor) noexcept
{
constexpr bool is_intern = (sizeof(Intern<T>) <= sizeof(data));
static_assert(!INTERN_ONLY || is_intern, "Function: Intern<T> doesn't fit in data[] and INTERN_ONLY=true");
static_assert(sizeof(Extern<T>) <= sizeof(data), "Function: Extern<T> doesn't fit in data[]");
if (is_intern)
{
// store functor internally (in data)
setup_methods_intern<T>();
new (data) Intern<T>(std::move(functor));
}
else
{
// store functor externally (using new)
setup_methods_extern<T>();
new (data) Extern<T>(std::move(functor));
}
}
struct Methods
{
R (*invoke)(void *, A...);
@@ -70,7 +132,7 @@ namespace openvpn {
};
template <typename T>
void setup_methods()
void setup_methods_intern()
{
static const struct Methods m = {
&Intern<T>::invoke,
@@ -80,15 +142,22 @@ namespace openvpn {
methods = &m;
}
template <typename T>
void setup_methods_extern()
{
static const struct Methods m = {
&Extern<T>::invoke,
&Extern<T>::move,
&Extern<T>::destruct,
};
methods = &m;
}
// store functor internally (in data)
template <typename T>
class Intern
{
public:
Intern(Intern&& obj) noexcept
: functor_(std::move(obj.functor_))
{
}
Intern(T&& functor) noexcept
: functor_(std::move(functor))
{
@@ -116,6 +185,40 @@ namespace openvpn {
T functor_;
};
// store functor externally (using new)
template <typename T>
class Extern
{
public:
Extern(T&& functor) noexcept
: functor_(new T(std::move(functor)))
{
}
static R invoke(void *ptr, A... args)
{
Extern* self = reinterpret_cast<Extern<T>*>(ptr);
return (*self->functor_)(args...);
}
static void move(void *dest, void *src)
{
Extern* d = reinterpret_cast<Extern<T>*>(dest);
Extern* s = reinterpret_cast<Extern<T>*>(src);
d->functor_ = s->functor_;
// no need to set s->functor_=nullptr because parent will not destruct src after move
}
static void destruct(void *ptr)
{
Extern* self = reinterpret_cast<Extern<T>*>(ptr);
delete self->functor_;
}
private:
T* functor_;
};
const Methods* methods;
void* data[N];
};

View File

@@ -152,12 +152,18 @@ namespace openvpn {
{
if (!argv.empty())
{
RedirectPipe::InOut inout;
os << to_string() << std::endl;
#ifdef OPENVPN_PROCESS_AVOID_PIPES
const int status = system_cmd(argv[0], argv);
if (status < 0)
os << "Error: command failed to execute" << std::endl;
#else
RedirectPipe::InOut inout;
const int status = system_cmd(argv[0], argv, nullptr, inout, true);
if (status < 0)
os << "Error: command failed to execute" << std::endl;
os << inout.out;
#endif
}
else
os << "Error: command called with empty argv" << std::endl;

View File

@@ -123,7 +123,7 @@ namespace openvpn {
signal_rearm();
#ifdef OPENVPN_EXIT_IN
exit_timer.expires_at(Time::now() + Time::Duration::seconds(OPENVPN_EXIT_IN));
exit_timer.expires_after(Time::Duration::seconds(OPENVPN_EXIT_IN));
exit_timer.async_wait([self=Ptr(this)](const openvpn_io::error_code& error)
{
if (!error)

View File

@@ -54,6 +54,11 @@ namespace openvpn {
{
return time_point(duration(t.raw()));
}
static duration to_duration(const Time::Duration& d)
{
return duration(d.raw());
}
};
class AsioTimer : public openvpn_io::basic_waitable_timer<AsioClock>
@@ -67,7 +72,12 @@ namespace openvpn {
std::size_t expires_at(const Time& t)
{
return openvpn_io::basic_waitable_timer<AsioClock>::expires_at(AsioClock::to_time_point(t));
}
}
std::size_t expires_after(const Time::Duration& d)
{
return openvpn_io::basic_waitable_timer<AsioClock>::expires_after(AsioClock::to_duration(d));
}
};
}

View File

@@ -0,0 +1,45 @@
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License Version 3
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
#ifndef OPENVPN_TUN_EXTERN_CONFIG_H
#define OPENVPN_TUN_EXTERN_CONFIG_H
// These includes are also intended to resolve forward references in fw.hpp
#include <openvpn/common/options.hpp>
#include <openvpn/tun/client/tunbase.hpp>
#include <openvpn/tun/client/tunprop.hpp>
#include <openvpn/frame/frame.hpp>
#include <openvpn/log/sessionstats.hpp>
#include <openvpn/common/stop.hpp>
namespace openvpn {
namespace ExternalTun {
struct Config
{
TunProp::Config tun_prop;
Frame::Ptr frame;
SessionStats::Ptr stats;
Stop* stop = nullptr;
bool tun_persist = false;
};
}
}
#endif

View File

@@ -0,0 +1,49 @@
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License Version 3
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
#ifndef OPENVPN_TUN_EXTERN_FW_H
#define OPENVPN_TUN_EXTERN_FW_H
namespace openvpn {
#if defined(OPENVPN_EXTERNAL_TUN_FACTORY)
struct TunClientFactory;
class OptionList;
namespace ExternalTun {
struct Config; // defined in config.hpp
struct Factory
{
virtual TunClientFactory* new_tun_factory(const Config& conf, const OptionList& opt) = 0;
virtual ~Factory() {}
};
}
#else
namespace ExternalTun {
struct Factory {};
}
#endif
}
#endif

View File

@@ -29,9 +29,9 @@ namespace openvpn {
{
public:
enum Type {
NO,
YES,
DEFAULT,
No,
Yes,
Default,
};
IPv6Setting()
@@ -49,11 +49,11 @@ namespace openvpn {
{
switch (type_)
{
case NO:
case No:
return "no";
case YES:
case Yes:
return "yes";
case DEFAULT:
case Default:
default:
return "default";
}
@@ -62,11 +62,11 @@ namespace openvpn {
static IPv6Setting parse(const std::string& str)
{
if (str == "no")
return IPv6Setting(NO);
return IPv6Setting(No);
else if (str == "yes")
return IPv6Setting(YES);
return IPv6Setting(Yes);
else if (str == "default")
return IPv6Setting(DEFAULT);
return IPv6Setting(Default);
else
throw Exception("IPv6Setting: unrecognized setting: '" + str + '\'');
}
@@ -82,7 +82,7 @@ namespace openvpn {
}
private:
Type type_ = DEFAULT;
Type type_ = Default;
};
}

View File

@@ -26,8 +26,10 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/route.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <cstring>

View File

@@ -34,7 +34,7 @@
#include <openvpn/common/process.hpp>
#include <openvpn/apple/macver.hpp>
#include <openvpn/apple/scdynstore.hpp>
#include <openvpn/applecrypto/cf/cfhelper.hpp>
#include <openvpn/apple/cf/cfhelper.hpp>
#include <openvpn/tun/builder/capture.hpp>
namespace openvpn {

View File

@@ -29,8 +29,8 @@
#include <openvpn/log/logthread.hpp>
#include <openvpn/common/action.hpp>
#include <openvpn/applecrypto/cf/cftimer.hpp>
#include <openvpn/apple/runloop.hpp>
#include <openvpn/apple/cf/cftimer.hpp>
#include <openvpn/apple/cf/cfrunloop.hpp>
#include <openvpn/tun/mac/macdns.hpp>
namespace openvpn {
@@ -183,7 +183,7 @@ namespace openvpn {
// as well.
void thread_func()
{
runloop.reset(CFRunLoopGetCurrent(), CF::BORROW);
runloop.reset(CFRunLoopGetCurrent(), CF::GET);
Log::Context logctx(logwrap);
try {

View File

@@ -28,7 +28,7 @@
#include <openvpn/common/exception.hpp>
#include <openvpn/addr/ip.hpp>
#include <openvpn/apple/scdynstore.hpp>
#include <openvpn/applecrypto/cf/cfhelper.hpp>
#include <openvpn/apple/cf/cfhelper.hpp>
namespace openvpn {
struct MacGWInfo

View File

@@ -22,6 +22,8 @@
#ifndef OPENVPN_TUN_PERSIST_TUNWRAPASIO_H
#define OPENVPN_TUN_PERSIST_TUNWRAPASIO_H
#include <utility>
namespace openvpn {
// This object supports that subset of the Asio stream
@@ -48,17 +50,14 @@ namespace openvpn {
// subset of methods used by TunIO).
// Prototypes from asio/windows/basic_stream_handle.hpp
template <typename MutableBufferSequence, typename ReadHandler>
ASIO_INITFN_RESULT_TYPE(ReadHandler,
void (openvpn_io::error_code, std::size_t))
async_read_some(const MutableBufferSequence& buffers,
ASIO_MOVE_ARG(ReadHandler) handler)
template <typename MUTABLE_BUFFER, typename HANDLER>
void async_read_some(const MUTABLE_BUFFER& buffers, HANDLER&& handler)
{
return tun_wrap->obj()->async_read_some(buffers, handler);
return tun_wrap->obj()->async_read_some(buffers, std::move(handler));
}
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers)
template <typename CONST_BUFFER>
std::size_t write_some(const CONST_BUFFER& buffers)
{
return tun_wrap->obj()->write_some(buffers);
}

View File

@@ -388,7 +388,7 @@ namespace openvpn {
void layer_2_schedule_timer(const unsigned int seconds)
{
l2_timer.expires_at(Time::now() + Time::Duration::seconds(seconds));
l2_timer.expires_after(Time::Duration::seconds(seconds));
l2_timer.async_wait([self=Ptr(this)](const openvpn_io::error_code& error)
{
if (!error && !self->halt)

View File

@@ -292,13 +292,9 @@ fi
# Construct command
if [ "$OBJC" == "1" ]; then
FLAGS="$FLAGS -fobjc-arc"
CPPFLAGS=""
CPPFLAGS="$CPPFLAGS -I$O3/cliobjc"
CPPFLAGS="$CPPFLAGS -I$O3/clilib/dist-static-$PLATFORM/include"
LIBDIRS="-L$O3/clilib/dist-static-$PLATFORM/lib"
LIBS="-lovpncli -framework Foundation $LIBS"
SRC="$1.m $O3/cliobjc/ovpncli.mm "
CMD="$GPP_CMD $FLAGS $GCC_EXTRA $CPPFLAGS $LIBDIRS $SRC $EXTRA_SRC_OBJ $OUTPUT $LIBS"
LIBS="-framework Foundation $LIBS"
SRC="$1.mm"
CMD="$GPP_CMD $FLAGS $GCC_EXTRA $CPPFLAGS $LIBDIRS $SRC $EXTRA_CPP $EXTRA_SRC_OBJ $OUTPUT $LIBS"
else
CMD="$GPP_CMD $FLAGS $GCC_EXTRA $CPPFLAGS $LIBDIRS $1.cpp $EXTRA_CPP $EXTRA_SRC_OBJ $OUTPUT $LIBS"
fi

View File

@@ -85,6 +85,15 @@ namespace {
class Client : public ClientAPI::OpenVPNClient
{
public:
enum ClockTickAction {
CT_UNDEF,
CT_STOP,
CT_RECONNECT,
CT_PAUSE,
CT_RESUME,
CT_STATS,
};
bool is_dynamic_challenge() const
{
return !dc_cookie.empty();
@@ -101,14 +110,33 @@ public:
MbedTLSPKI::PKContext epki_ctx; // external PKI context
#endif
void set_clock_tick_action(const ClockTickAction action)
{
clock_tick_action = action;
}
void print_stats()
{
const int n = stats_n();
std::vector<long long> stats = stats_bundle();
std::cout << "STATS:" << std::endl;
for (int i = 0; i < n; ++i)
{
const long long value = stats[i];
if (value)
std::cout << " " << stats_name(i) << " : " << value << std::endl;
}
}
private:
virtual bool socket_protect(int socket)
virtual bool socket_protect(int socket) override
{
std::cout << "*** socket_protect " << socket << std::endl;
return true;
}
virtual void event(const ClientAPI::Event& ev)
virtual void event(const ClientAPI::Event& ev) override
{
std::cout << date_time() << " EVENT: " << ev.name;
if (!ev.info.empty())
@@ -155,13 +183,45 @@ private:
}
}
virtual void log(const ClientAPI::LogInfo& log)
virtual void log(const ClientAPI::LogInfo& log) override
{
std::lock_guard<std::mutex> lock(log_mutex);
std::cout << date_time() << ' ' << log.text << std::flush;
}
virtual void external_pki_cert_request(ClientAPI::ExternalPKICertRequest& certreq)
virtual void clock_tick() override
{
const ClockTickAction action = clock_tick_action;
clock_tick_action = CT_UNDEF;
switch (action)
{
case CT_STOP:
std::cout << "signal: CT_STOP" << std::endl;
stop();
break;
case CT_RECONNECT:
std::cout << "signal: CT_RECONNECT" << std::endl;
reconnect(0);
break;
case CT_PAUSE:
std::cout << "signal: CT_PAUSE" << std::endl;
pause("clock-tick pause");
break;
case CT_RESUME:
std::cout << "signal: CT_RESUME" << std::endl;
resume();
break;
case CT_STATS:
std::cout << "signal: CT_STATS" << std::endl;
print_stats();
break;
default:
break;
}
}
virtual void external_pki_cert_request(ClientAPI::ExternalPKICertRequest& certreq) override
{
if (!epki_cert.empty())
{
@@ -175,7 +235,7 @@ private:
}
}
virtual void external_pki_sign_request(ClientAPI::ExternalPKISignRequest& signreq)
virtual void external_pki_sign_request(ClientAPI::ExternalPKISignRequest& signreq) override
{
#if defined(USE_MBEDTLS)
if (epki_ctx.defined())
@@ -239,7 +299,7 @@ private:
return self->rng->rand_bytes_noexcept(data, len) ? 0 : -1; // using -1 as a general-purpose mbed TLS error code
}
virtual bool pause_on_connection_timeout()
virtual bool pause_on_connection_timeout() override
{
return false;
}
@@ -247,13 +307,16 @@ private:
std::mutex log_mutex;
std::string dc_cookie;
RandomAPI::Ptr rng; // random data source for epki
volatile ClockTickAction clock_tick_action = CT_UNDEF;
};
static Client *the_client = nullptr; // GLOBAL
static void worker_thread()
{
#if !defined(OPENVPN_OVPNCLI_SINGLE_THREAD)
openvpn_io::detail::signal_blocker signal_blocker; // signals should be handled by parent thread
#endif
try {
std::cout << "Thread starting..." << std::endl;
ClientAPI::Status connect_status = the_client->connect();
@@ -272,21 +335,117 @@ static void worker_thread()
std::cout << "Thread finished" << std::endl;
}
static void print_stats(const Client& client)
static std::string read_profile(const char *fn, const std::string* profile_content)
{
const int n = client.stats_n();
std::vector<long long> stats = client.stats_bundle();
std::cout << "STATS:" << std::endl;
for (int i = 0; i < n; ++i)
if (!string::strcasecmp(fn, "http") && profile_content && !profile_content->empty())
return *profile_content;
else
{
const long long value = stats[i];
if (value)
std::cout << " " << client.stats_name(i) << " : " << value << std::endl;
ProfileMerge pm(fn, "ovpn", "", ProfileMerge::FOLLOW_FULL,
ProfileParseLimits::MAX_LINE_SIZE, ProfileParseLimits::MAX_PROFILE_SIZE);
if (pm.status() != ProfileMerge::MERGE_SUCCESS)
OPENVPN_THROW_EXCEPTION("merge config error: " << pm.status_string() << " : " << pm.error());
return pm.profile_content();
}
}
#if !defined(OPENVPN_PLATFORM_WIN)
#if defined(OPENVPN_PLATFORM_WIN)
static void start_thread(Client& client)
{
// Set Windows title bar
const std::string title_text = "F2:Stats F3:Reconnect F4:Stop F5:Pause";
Win::Console::Title title(ClientAPI::OpenVPNClient::platform() + " " + title_text);
Win::Console::Input console;
// start connect thread
std::unique_ptr<std::thread> thread;
volatile bool thread_exit = false;
the_client = &client;
thread.reset(new std::thread([&thread_exit]() {
worker_thread();
thread_exit = true;
}));
// wait for connect thread to exit, also check for keypresses
while (!thread_exit)
{
while (true)
{
const unsigned int c = console.get();
if (!c)
break;
else if (c == 0x3C) // F2
the_client->print_stats();
else if (c == 0x3D) // F3
the_client->reconnect(0);
else if (c == 0x3E) // F4
the_client->stop();
else if (c == 0x3F) // F5
the_client->pause("user-pause");
}
Sleep(1000);
}
// wait for connect thread to exit
thread->join();
the_client = nullptr;
}
#elif defined(OPENVPN_OVPNCLI_SINGLE_THREAD)
static void handler(int signum)
{
switch (signum)
{
case SIGTERM:
case SIGINT:
if (the_client)
the_client->set_clock_tick_action(Client::CT_STOP);
break;
case SIGHUP:
if (the_client)
the_client->set_clock_tick_action(Client::CT_RECONNECT);
break;
case SIGUSR1:
if (the_client)
the_client->set_clock_tick_action(Client::CT_STATS);
break;
case SIGUSR2:
{
// toggle pause/resume
static bool hup = false;
if (the_client)
{
if (hup)
the_client->set_clock_tick_action(Client::CT_RESUME);
else
the_client->set_clock_tick_action(Client::CT_PAUSE);
hup = !hup;
}
}
break;
default:
break;
}
}
static void start_thread(Client& client)
{
the_client = &client;
// capture signals that might occur while we're in worker_thread
Signal signal(handler, Signal::F_SIGINT|Signal::F_SIGTERM|Signal::F_SIGHUP|Signal::F_SIGUSR1|Signal::F_SIGUSR2);
// run the client
worker_thread();
the_client = nullptr;
}
#else
static void handler(int signum)
{
switch (signum)
@@ -304,7 +463,7 @@ static void handler(int signum)
break;
case SIGUSR1:
if (the_client)
print_stats(*the_client);
the_client->print_stats();
break;
case SIGUSR2:
{
@@ -326,22 +485,29 @@ static void handler(int signum)
break;
}
}
#endif
static std::string read_profile(const char *fn, const std::string* profile_content)
static void start_thread(Client& client)
{
if (!string::strcasecmp(fn, "http") && profile_content && !profile_content->empty())
return *profile_content;
else
{
ProfileMerge pm(fn, "ovpn", "", ProfileMerge::FOLLOW_FULL,
ProfileParseLimits::MAX_LINE_SIZE, ProfileParseLimits::MAX_PROFILE_SIZE);
if (pm.status() != ProfileMerge::MERGE_SUCCESS)
OPENVPN_THROW_EXCEPTION("merge config error: " << pm.status_string() << " : " << pm.error());
return pm.profile_content();
}
std::unique_ptr<std::thread> thread;
// start connect thread
the_client = &client;
thread.reset(new std::thread([]() {
worker_thread();
}));
{
// catch signals that might occur while we're in join()
Signal signal(handler, Signal::F_SIGINT|Signal::F_SIGTERM|Signal::F_SIGHUP|Signal::F_SIGUSR1|Signal::F_SIGUSR2);
// wait for connect thread to exit
thread->join();
}
the_client = nullptr;
}
#endif
int openvpn_client(int argc, char *argv[], const std::string* profile_content)
{
static const struct option longopts[] = {
@@ -388,7 +554,6 @@ int openvpn_client(int argc, char *argv[], const std::string* profile_content)
auto cleanup = Cleanup([]() {
the_client = nullptr;
});
std::unique_ptr<std::thread> thread;
try {
if (argc >= 2)
@@ -618,6 +783,9 @@ int openvpn_client(int argc, char *argv[], const std::string* profile_content)
config.tunPersist = tunPersist;
config.gremlinConfig = gremlin;
config.info = true;
#if defined(OPENVPN_OVPNCLI_SINGLE_THREAD)
config.clockTickMS = 250;
#endif
if (!epki_cert_fn.empty())
config.externalPkiAlias = "epki"; // dummy string
@@ -694,60 +862,8 @@ int openvpn_client(int argc, char *argv[], const std::string* profile_content)
std::cout << "CONNECTING..." << std::endl;
#if !defined(OPENVPN_PLATFORM_WIN)
// start connect thread
the_client = &client;
thread.reset(new std::thread([]() {
worker_thread();
}));
{
// catch signals that might occur while we're in join()
Signal signal(handler, Signal::F_SIGINT|Signal::F_SIGTERM|Signal::F_SIGHUP|Signal::F_SIGUSR1|Signal::F_SIGUSR2);
// wait for connect thread to exit
thread->join();
}
the_client = nullptr;
#else
// Set Windows title bar
const std::string title_text = "F2:Stats F3:Reconnect F4:Stop F5:Pause";
Win::Console::Title title(ClientAPI::OpenVPNClient::platform() + " " + title_text);
Win::Console::Input console;
// start connect thread
volatile bool thread_exit = false;
the_client = &client;
thread.reset(new std::thread([&thread_exit]() {
worker_thread();
thread_exit = true;
}));
// wait for connect thread to exit, also check for keypresses
while (!thread_exit)
{
while (true)
{
const unsigned int c = console.get();
if (!c)
break;
else if (c == 0x3C) // F2
print_stats(*the_client);
else if (c == 0x3D) // F3
the_client->reconnect(0);
else if (c == 0x3E) // F4
the_client->stop();
else if (c == 0x3F) // F5
the_client->pause("user-pause");
}
Sleep(1000);
}
// wait for connect thread to exit
thread->join();
the_client = nullptr;
#endif
// start the client thread
start_thread(client);
// Get dynamic challenge response
if (client.is_dynamic_challenge())
@@ -763,7 +879,7 @@ int openvpn_client(int argc, char *argv[], const std::string* profile_content)
else
{
// print closing stats
print_stats(client);
client.print_stats();
}
}
} while (retry);