mirror of
https://github.com/amnezia-vpn/openvpn3.git
synced 2026-05-30 15:20:27 +03:00
* Implemented connection timeout. * Implemented show raw stats page. * Work around issue where sometimes core doesn't stop when stop() method is called, because of delays in canceling Asio DNS resolution thread.
278 lines
6.8 KiB
Java
278 lines
6.8 KiB
Java
// package OPENVPN_PACKAGE
|
|
|
|
import java.util.HashSet;
|
|
|
|
public class OpenVPNClientThread extends ClientAPI_OpenVPNClient implements Runnable {
|
|
private EventReceiver parent;
|
|
private TunBuilder tun_builder;
|
|
private Thread thread;
|
|
private ClientAPI_Status m_connect_status;
|
|
private boolean connect_called = false;
|
|
|
|
private int bytes_in_index = -1;
|
|
private int bytes_out_index = -1;
|
|
|
|
// thrown if instantiator attempts to call connect more than once
|
|
public static class ConnectCalledTwice extends RuntimeException {
|
|
}
|
|
|
|
public interface EventReceiver {
|
|
// Called with events from core
|
|
void event(ClientAPI_Event event);
|
|
|
|
// Called with log text from core
|
|
void log(ClientAPI_LogInfo loginfo);
|
|
|
|
// Called when connect() thread exits
|
|
void done(ClientAPI_Status status);
|
|
|
|
// Called to "protect" a socket from being routed through the tunnel
|
|
boolean socket_protect(int socket);
|
|
|
|
// Callback to construct a new tun builder
|
|
TunBuilder tun_builder_new();
|
|
|
|
// Callback to get a certificate
|
|
void external_pki_cert_request(ClientAPI_ExternalPKICertRequest req);
|
|
|
|
// Callback to sign data
|
|
void external_pki_sign_request(ClientAPI_ExternalPKISignRequest req);
|
|
}
|
|
|
|
public interface TunBuilder {
|
|
// Tun builder methods. All methods returning boolean use the return
|
|
// value to indicate success (true) or fail (false).
|
|
|
|
// Callback to to add network address to VPN interface
|
|
boolean tun_builder_add_address(String address, int prefix_length);
|
|
|
|
// Callback to add route to VPN interface
|
|
boolean tun_builder_add_route(String address, int prefix_length);
|
|
|
|
// Callback to add DNS server to VPN interface
|
|
boolean tun_builder_add_dns_server(String address);
|
|
|
|
// Callback to add search domain to DNS resolver
|
|
boolean tun_builder_add_search_domain(String domain);
|
|
|
|
// Callback to set MTU of the VPN interface
|
|
boolean tun_builder_set_mtu(int mtu);
|
|
|
|
// Callback to set the session name
|
|
boolean tun_builder_set_session_name(String name);
|
|
|
|
// Callback to establish the VPN tunnel, returning a file descriptor
|
|
// to the tunnel, which the caller will henceforth own. Returns -1
|
|
// if the tunnel could not be established.
|
|
int tun_builder_establish();
|
|
}
|
|
|
|
public OpenVPNClientThread() {
|
|
final int n = stats_n();
|
|
for (int i = 0; i < n; ++i)
|
|
{
|
|
String name = stats_name(i);
|
|
if (name.equals("BYTES_IN"))
|
|
bytes_in_index = i;
|
|
if (name.equals("BYTES_OUT"))
|
|
bytes_out_index = i;
|
|
}
|
|
}
|
|
|
|
// start connect session in worker thread
|
|
public void connect(EventReceiver parent_arg) {
|
|
if (connect_called)
|
|
throw new ConnectCalledTwice();
|
|
connect_called = true;
|
|
|
|
// direct client callbacks to parent
|
|
parent = parent_arg;
|
|
|
|
// clear status
|
|
m_connect_status = null;
|
|
|
|
// execute client in a worker thread
|
|
thread = new Thread(this, "OpenVPNClientThread");
|
|
thread.start();
|
|
}
|
|
|
|
// wait for worker thread to complete; to stop thread,
|
|
// first call super stop() method then wait_thread()
|
|
public void wait_thread() {
|
|
final int wait_millisecs = 1000; // max time that we will wait for thread to exit
|
|
Thread th = thread;
|
|
if (th != null) {
|
|
try {
|
|
th.join(wait_millisecs);
|
|
}
|
|
catch (InterruptedException e) {
|
|
}
|
|
|
|
// thread failed to stop?
|
|
if (th.isAlive()) {
|
|
// abandon thread and deliver our own status object to instantiator.
|
|
ClientAPI_Status status = new ClientAPI_Status();
|
|
call_done(status);
|
|
}
|
|
}
|
|
}
|
|
|
|
public long bytes_in()
|
|
{
|
|
return super.stats_value(bytes_in_index);
|
|
}
|
|
|
|
public long bytes_out()
|
|
{
|
|
return super.stats_value(bytes_out_index);
|
|
}
|
|
|
|
private void call_done(ClientAPI_Status status)
|
|
{
|
|
EventReceiver p = finalize_thread(status);
|
|
if (p != null)
|
|
p.done(m_connect_status);
|
|
}
|
|
|
|
private synchronized EventReceiver finalize_thread(ClientAPI_Status connect_status)
|
|
{
|
|
EventReceiver p = parent;
|
|
if (p != null) {
|
|
// save thread connection status
|
|
m_connect_status = connect_status;
|
|
|
|
// disassociate client callbacks from parent
|
|
parent = null;
|
|
tun_builder = null;
|
|
thread = null;
|
|
}
|
|
return p;
|
|
}
|
|
|
|
// Runnable overrides
|
|
|
|
@Override
|
|
public void run() {
|
|
// Call out to core to start connection.
|
|
// Doesn't return until connection has terminated.
|
|
ClientAPI_Status status = super.connect();
|
|
call_done(status);
|
|
}
|
|
|
|
// ClientAPI_OpenVPNClient (C++ class) overrides
|
|
|
|
@Override
|
|
public boolean socket_protect(int socket) {
|
|
EventReceiver p = parent;
|
|
if (p != null)
|
|
return p.socket_protect(socket);
|
|
else
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public void event(ClientAPI_Event event) {
|
|
EventReceiver p = parent;
|
|
if (p != null)
|
|
p.event(event);
|
|
}
|
|
|
|
@Override
|
|
public void log(ClientAPI_LogInfo loginfo) {
|
|
EventReceiver p = parent;
|
|
if (p != null)
|
|
p.log(loginfo);
|
|
}
|
|
|
|
@Override
|
|
public void external_pki_cert_request(ClientAPI_ExternalPKICertRequest req) {
|
|
EventReceiver p = parent;
|
|
if (p != null)
|
|
p.external_pki_cert_request(req);
|
|
}
|
|
|
|
@Override
|
|
public void external_pki_sign_request(ClientAPI_ExternalPKISignRequest req) {
|
|
EventReceiver p = parent;
|
|
if (p != null)
|
|
p.external_pki_sign_request(req);
|
|
}
|
|
|
|
// TunBuilderBase (C++ class) overrides
|
|
|
|
@Override
|
|
public boolean tun_builder_new() {
|
|
EventReceiver p = parent;
|
|
if (p != null) {
|
|
tun_builder = p.tun_builder_new();
|
|
return tun_builder != null;
|
|
} else
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean tun_builder_add_address(String address, int prefix_length) {
|
|
TunBuilder tb = tun_builder;
|
|
if (tb != null)
|
|
return tb.tun_builder_add_address(address, prefix_length);
|
|
else
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean tun_builder_add_route(String address, int prefix_length) {
|
|
TunBuilder tb = tun_builder;
|
|
if (tb != null)
|
|
return tb.tun_builder_add_route(address, prefix_length);
|
|
else
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean tun_builder_add_dns_server(String address) {
|
|
TunBuilder tb = tun_builder;
|
|
if (tb != null)
|
|
return tb.tun_builder_add_dns_server(address);
|
|
else
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean tun_builder_add_search_domain(String domain)
|
|
{
|
|
TunBuilder tb = tun_builder;
|
|
if (tb != null)
|
|
return tb.tun_builder_add_search_domain(domain);
|
|
else
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean tun_builder_set_mtu(int mtu) {
|
|
TunBuilder tb = tun_builder;
|
|
if (tb != null)
|
|
return tb.tun_builder_set_mtu(mtu);
|
|
else
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean tun_builder_set_session_name(String name)
|
|
{
|
|
TunBuilder tb = tun_builder;
|
|
if (tb != null)
|
|
return tb.tun_builder_set_session_name(name);
|
|
else
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public int tun_builder_establish() {
|
|
TunBuilder tb = tun_builder;
|
|
if (tb != null)
|
|
return tb.tun_builder_establish();
|
|
else
|
|
return -1;
|
|
}
|
|
}
|