Skip to content

Commit

Permalink
code cleanup and documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
obiltschnig committed Oct 5, 2023
1 parent 1b4baff commit a2fcd9e
Show file tree
Hide file tree
Showing 6 changed files with 243 additions and 110 deletions.
14 changes: 8 additions & 6 deletions WebTunnel/WebTunnelAgentLib/README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
# macchina.io REMOTE Agent Library (*libWebTunnelAgent*)

`libWebTunnelAgent` provides a C API for connecting a device to a macchina.io REMOTE server.
This is what the [`WebTunnelAgent`](../WebTunnelAgent/README.md) is doing,
This is what the [`WebTunnelAgent`](../WebTunnelAgent/README.md) program does,
but provided as a library for easy inclusion into applications (not written in C++).
C++ applications can also use the `Poco::WebTunnel::RemotePortForwarder` class
in the `WebTunnel` library.
in the `WebTunnel` library directly.

Please see the [webtunnelagent.h](include/webtunnelagent.h) header file for
a description of the available types and functions.

Basic usage:
- `webtunnelagent_init()` must be called before any other functions.
- `webtunnelagent_cleanup()` must be called as last function when the library
- `webtunnel_agent_init()` must be called before any other functions.
- `webtunnel_agent_cleanup()` must be called as last function when the library
is no longer used in the program, to clean up internal state and resources.
- `webtunnelagent_create()` is used to create a connection from to a macchina.io REMOTE server.
- `webtunnelagent_destroy()` stops the local TCP server for the tunnel connection.
- `webtunnel_agent_configure_timeouts()` and `webtunnel_agent_configure_tls()` are used
for basic configuration of connection timeouts and TLS parameters.
- `webtunnel_agent_create()` is used to create a tunnel from the device to a macchina.io REMOTE server.
- `webtunnel_agent_destroy()` stops the local TCP server for the tunnel connection.

86 changes: 59 additions & 27 deletions WebTunnel/WebTunnelAgentLib/include/webtunnelagent.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//
// The WebTunnel Agent C API
//
// Copyright (c) 2013-2023, Applied Informatics Software Engineering GmbH.
// Copyright (c) 2023, Applied Informatics Software Engineering GmbH.
// All rights reserved.
//
// SPDX-License-Identifier: BSL-1.0
Expand Down Expand Up @@ -68,6 +68,15 @@ typedef enum webtunnel_agent_result
} webtunnel_agent_result;


typedef enum webtunnel_agent_tls_version
{
webtunnel_agent_tls_1_0 = 0,
webtunnel_agent_tls_1_1 = 1,
webtunnel_agent_tls_1_2 = 2,
webtunnel_agent_tls_1_3 = 3
} webtunnel_agent_tls_version;


typedef enum webtunnel_agent_status
{
webtunnel_agent_status_disconnected = 0,
Expand Down Expand Up @@ -103,9 +112,10 @@ typedef void* webtunnel_agent;
// webtunnel_agent_init
//
// Initialize webtunnel agent library.
//
// Must be called before any other functions.
// Returns webunnel_agent_ok if successful, or
// webtunnel_agent_error otherwise.
// Returns webunnel_agent_result_ok if successful, or
// webtunnel_agent_result_error otherwise.
*/
int WebTunnelAgent_API webtunnel_agent_init(void);

Expand All @@ -114,8 +124,9 @@ int WebTunnelAgent_API webtunnel_agent_init(void);
// webtunnel_agent_cleanup
//
// Cleanup webtunnel agent library.
//
// Should be called when the library is no longer being used
// to cleanup internal state.
// to cleanup internal state and resources.
*/
void WebTunnelAgent_API webtunnel_agent_cleanup(void);

Expand All @@ -125,14 +136,13 @@ void WebTunnelAgent_API webtunnel_agent_cleanup(void);
//
// Configure timeouts for WebTunnel connections.
//
// All timeouts are in seconds.
// All timeouts are given in seconds.
//
// connect_timeout is the timeout for setting up the initial HTTP connection
// to the reflector server.
// connect_timeout is the timeout for connecting to a forwarded local port.
//
// remote_timeout specifies the timeout of the tunnel connection to the reflector service.
// If no data has been received for this period, the client will send a PING
// message to the server. If the server does not reply to the PING, the connection
// If no data has been received for this period, the agent will send a PING
// message to the server. If the server does not respond to the PING, the connection
// will be closed.
//
// local_timeout specifies the timeout of the local socket connection.
Expand Down Expand Up @@ -162,16 +172,18 @@ int WebTunnelAgent_API webtunnel_agent_configure_timeouts(int connect_timeout, i
// the CA/root certificates. Can be NULL to use the built-in root
// certificates.
//
// Returns webtunnel_agent_ok if successful, or webtunnel_client_error if an error
// occured, or webtunnel_agent_not_supported if no SSL/TLS support is available.
// minimum_protocol specifies the minimum TLS protocol version (see webtunnel_agent_tls_version).
//
// Returns webtunnel_agent_result_ok if successful, or webtunnel_agent_result_error if an error
// occured, or webtunnel_agent_result_not_supported if no SSL/TLS support is available.
*/
int WebTunnelAgent_API webtunnel_agent_configure_tls(bool accept_unknown_cert, bool extended_verification, const char* ciphers, const char* ca_location);
int WebTunnelAgent_API webtunnel_agent_configure_tls(bool accept_unknown_cert, bool extended_verification, const char* ciphers, const char* ca_location, int minimum_protocol);


/*
// webtunnel_agent_configure_proxy
//
// Sets up parameters for connecting through a proxy server.
// Sets up parameters for connecting to the reflector server through a web proxy.
//
// If enable_proxy is true, the connection to the reflector server
// will be attempted through a proxy server.
Expand All @@ -186,8 +198,8 @@ int WebTunnelAgent_API webtunnel_agent_configure_tls(bool accept_unknown_cert, b
// proxy_password contains the password for authenticating against the
// proxy server. If NULL, no authentication will be performed.
//
// Returns webtunnel_client_ok if successful, or webtunnel_client_error if an error
// occured.
// Returns webtunnel_agent_result_ok if successful, or webtunnel_agent_result_error
// if an error occured.
*/
int WebTunnelAgent_API webtunnel_agent_configure_proxy(bool enable_proxy, const char* proxy_host, unsigned short proxy_port, const char* proxy_username, const char* proxy_password);

Expand All @@ -197,39 +209,59 @@ int WebTunnelAgent_API webtunnel_agent_configure_proxy(bool enable_proxy, const
//
// Creates a tunnel connection to the reflector service.
//
// remote_uri contains the URI of the remote machine, using the http
// or https URI scheme.
// Example: " https://0a72da53-9de5-44c8-9adf-f3d916304be6.my-devices.net"
// reflector_uri contains the URL of the reflector server, e.g. "https://remote.macchina.io".
//
// target_host contains the IP address or host name of the target host, which is usually
// "localhost" (or 127.0.0.1), but can also be a different host.
//
// device_id contains the ID (usually a UUID) of the device on the reflector server.
//
// username and password are used for authentication against the reflector
// server.
// device_password contains an optional device password, or NULL if no password is required.
//
// local_addr can be NULL (defaults to 127.0.0.1) or a string containing
// an IP address or host name ("localhost").
// domain_id contains the domain ID (UUID) of the device on the reflector server.
//
// Returns NULL in case of an error.
// tenant_id contains the ID of the tenant the device is associated with, or NULL if the
// devices is not associated with a tenant.
//
// ports and ports_len specify a list of device port numbers to be made available remotely
// through the reflector server. For each port, a port type can also be specified. Note that
// for each port type, except webtunnel_port_other, at most one instance must be given.
// These two parameters are required. ports_len specifies the number of entries in the array.
//
// custom_config_path specifies the path to a custom configuration file in properties format
// that replaces the built-in default configuration. This allows for specifying additional
// configuration parameters that are not exposed through the API. If a custom configuration
// file is not required, NULL can be specified.
//
// Returns an opaque webtunnel_agent handle, or NULL in case of an error.
*/
webtunnel_agent WebTunnelAgent_API webtunnel_agent_create(const char* reflector_uri, const char* target_host, const char* device_id, const char* device_password, const char* domain_id, const char* tenant_id, const webtunnel_agent_port_spec* ports, unsigned ports_len, const char* custom_config_path);


/*
// webtunnel_agent_get_status
//
// Returns the status of the given tunnel connection
// (see webtunnel_agent_status).
*/
int WebTunnelAgent_API webtunnel_agent_get_status(webtunnel_agent wt);


/*
// webtunnel_client_destroy
// webtunnel_agent_destroy
//
// Closes the given web tunnel connection.
// Closes and destroys the given web tunnel connection.
*/
void WebTunnelAgent_API webtunnel_agent_destroy(webtunnel_agent wt);


/*
// webtunnel_agent_last_error_text
// webtunnel_agent_get_last_error_text
//
// Returns a text describing the last encountered error.
// Can be NULL if no descriptive text is available.
*/
const char WebTunnelAgent_API * webtunnel_agent_last_error_text(webtunnel_agent wt);
const char WebTunnelAgent_API * webtunnel_agent_get_last_error_text(webtunnel_agent wt);


#ifdef __cplusplus
Expand Down
89 changes: 65 additions & 24 deletions WebTunnel/WebTunnelAgentLib/src/webtunnelagent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ logging.channels.console.pattern = %Y-%m-%d %H:%M:%S.%i [%p] %s<%I>: %t
throw Poco::InvalidArgumentException(prefix + ".verification", vModeStr);

Poco::Net::Context::Protocols minProto = Poco::Net::Context::PROTO_TLSV1_2;
if (tlsMinVersion == "tlsv1")
if (tlsMinVersion == "tlsv1" or tlsMinVersion == "tlsv1_0")
minProto = Poco::Net::Context::PROTO_TLSV1;
else if (tlsMinVersion == "tlsv1_1")
minProto = Poco::Net::Context::PROTO_TLSV1_1;
Expand Down Expand Up @@ -178,6 +178,24 @@ logging.channels.console.pattern = %Y-%m-%d %H:%M:%S.%i [%p] %s<%I>: %t
#endif // defined(WEBTUNNEL_ENABLE_TLS)


int error(const std::string& error)
{
lastError = error;
return webtunnel_agent_result_error;
}

int error(const Poco::Exception& exc)
{
return error(exc.displayText());
}

int success()
{
lastError.clear();
return webtunnel_agent_result_ok;
}


} // namespace


Expand All @@ -194,11 +212,11 @@ int WebTunnelAgent_API webtunnel_agent_init(void)

pTimer = new Poco::Util::Timer;

return webtunnel_agent_result_ok;
return success();
}
catch (...)
catch (Poco::Exception& exc)
{
return webtunnel_agent_result_error;
return error(exc);
}
}

Expand All @@ -222,7 +240,7 @@ void WebTunnelAgent_API webtunnel_agent_cleanup(void)
}


int WebTunnelAgent_API webtunnel_agent_configure_tls(bool accept_unknown_cert, bool extended_verification, const char* ciphers, const char* ca_location)
int WebTunnelAgent_API webtunnel_agent_configure_tls(bool accept_unknown_cert, bool extended_verification, const char* ciphers, const char* ca_location, int minimum_protocol)
{
#if defined(WEBTUNNEL_ENABLE_TLS)
try
Expand All @@ -242,20 +260,35 @@ int WebTunnelAgent_API webtunnel_agent_configure_tls(bool accept_unknown_cert, b
pCertificateHandler = new Poco::Net::RejectCertificateHandler(false);

#if defined(POCO_NETSSL_WIN)
Poco::Net::Context::Ptr pContext = new Poco::Net::Context(Poco::Net::Context::TLSV1_CLIENT_USE, "", Poco::Net::Context::VERIFY_RELAXED);
Poco::Net::Context::Ptr pContext = new Poco::Net::Context(Poco::Net::Context::TLS_CLIENT_USE, ""s, Poco::Net::Context::VERIFY_RELAXED);
#else
Poco::Net::Context::Ptr pContext = new Poco::Net::Context(Poco::Net::Context::TLSV1_CLIENT_USE, "", "", caLocation, Poco::Net::Context::VERIFY_RELAXED, 5, true, cipherList);
Poco::Net::Context::Ptr pContext = new Poco::Net::Context(Poco::Net::Context::TLS_CLIENT_USE, ""s, ""s, caLocation, Poco::Net::Context::VERIFY_RELAXED, 5, true, cipherList);
#endif

switch (minimum_protocol)
{
case webtunnel_agent_tls_1_0:
pContext->requireMinimumProtocol(Poco::Net::Context::PROTO_TLSV1);
break;
case webtunnel_agent_tls_1_1:
pContext->requireMinimumProtocol(Poco::Net::Context::PROTO_TLSV1_1);
break;
case webtunnel_agent_tls_1_2:
pContext->requireMinimumProtocol(Poco::Net::Context::PROTO_TLSV1_2);
break;
case webtunnel_agent_tls_1_3:
pContext->requireMinimumProtocol(Poco::Net::Context::PROTO_TLSV1_3);
break;
}

pContext->enableExtendedCertificateVerification(extended_verification);
Poco::Net::SSLManager::instance().initializeClient(nullptr, pCertificateHandler, pContext);

lastError.clear();
return webtunnel_agent_result_ok;
return success();
}
catch (Poco::Exception& exc)
{
lastError = exc.displayText();
return webtunnel_agent_result_error;
return error(exc);
}
#else
return webtunnel_agent_not_supported;
Expand All @@ -265,17 +298,24 @@ int WebTunnelAgent_API webtunnel_agent_configure_tls(bool accept_unknown_cert, b

int WebTunnelAgent_API webtunnel_agent_configure_proxy(bool enable_proxy, const char* proxy_host, unsigned short proxy_port, const char* proxy_username, const char* proxy_password)
{
Poco::Net::HTTPClientSession::ProxyConfig proxyConfig;
if (enable_proxy)
try
{
if (!proxy_host) return webtunnel_agent_result_error;
proxyConfig.host = proxy_host;
proxyConfig.port = proxy_port;
if (proxy_username) proxyConfig.username = proxy_username;
if (proxy_password) proxyConfig.password = proxy_password;
Poco::Net::HTTPClientSession::ProxyConfig proxyConfig;
if (enable_proxy)
{
if (!proxy_host) return webtunnel_agent_result_error;
proxyConfig.host = proxy_host;
proxyConfig.port = proxy_port;
if (proxy_username) proxyConfig.username = proxy_username;
if (proxy_password) proxyConfig.password = proxy_password;
}
Poco::Net::HTTPClientSession::setGlobalProxyConfig(proxyConfig);
return success();
}
catch (Poco::Exception& exc)
{
return error(exc);
}
Poco::Net::HTTPClientSession::setGlobalProxyConfig(proxyConfig);
return webtunnel_agent_result_ok;
}


Expand All @@ -286,9 +326,9 @@ int WebTunnelAgent_API webtunnel_agent_configure_timeouts(int connect_timeout, i
connectTimeout = connect_timeout;
remoteTimeout = remote_timeout;
localTimeout = local_timeout;
return webtunnel_agent_result_ok;
return success();
}
else return webtunnel_agent_result_error;
else return error("bad parameters"s);
}


Expand Down Expand Up @@ -388,11 +428,12 @@ webtunnel_agent WebTunnelAgent_API webtunnel_agent_create(const char* reflector_
}

auto pTunnel = std::make_unique<WebTunnelAgentLib::Tunnel>(deviceId, pTimer, pDispatcher, pConfig, pSocketFactory);
(void) success();
return new Holder(std::move(pTunnel));
}
catch (Poco::Exception& exc)
{
lastError = exc.displayText();
(void) error(exc);
return NULL;
}
}
Expand Down Expand Up @@ -430,7 +471,7 @@ void WebTunnelAgent_API webtunnel_agent_destroy(webtunnel_agent wt)
}


const char WebTunnelAgent_API* webtunnel_agent_last_error_text(webtunnel_agent wt)
const char WebTunnelAgent_API* webtunnel_agent_get_last_error_text(webtunnel_agent wt)
{
Holder* pHolder = reinterpret_cast<Holder*>(wt);
if (pHolder && pHolder->signature == Holder::SIGNATURE)
Expand Down
4 changes: 2 additions & 2 deletions WebTunnel/WebTunnelClientLib/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

`libWebTunnelClient` provides a C API for creating a tunnel connection from
a local TCP port to a port on a remote device connected to macchina.io REMOTE.
This is what the [`remote-client`](../WebTunnelClient/README.md) is doing,
This is what the [`remote-client`](../WebTunnelClient/README.md) does,
but provided as a library for easy inclusion into applications (not written in C++).
C++ applications can also use the `Poco::WebTunnel::LocalPortForwarder` class
in the `WebTunnel` library.
Expand All @@ -23,4 +23,4 @@ Basic usage:
- `webtunnel_client_create_jwt()` can be used instead of `webtunnel_client_create()` if a token
(JWT) should be used for authentication.
- `webtunnel_client_destroy()` stops the local TCP server for the tunnel connection.


Loading

0 comments on commit a2fcd9e

Please sign in to comment.