Files
openvpn3/javacli/OpenVPNClientThread.java
James Yonan a79f88aebd Android:
* Implement a simple DNS cache to work around issue with
  Seamless Tunnel --  When Seamless Tunnel is enabled,
  reconnections are unable to send DNS requests because
  the internet is blocked.  This fix caches the IP address
  used for the initial connection, then reuses it
  over the lifetime of the Seamless Tunnel.

* Try to ensure that connections properly pause on device
  sleep (when sleep on screen blanking is NOT enabled) so
  that they will survive until wakeup.

iOS:

* Don't choke on foreign profiles (such as VPN On Demand) that are
  imported onto the device but lack critical info such as a
  config file.
2012-10-23 13:10:39 +00:00

346 lines
9.0 KiB
Java

//
// OpenVPNClientThread.java
// OpenVPN
//
// Copyright (c) 2012 OpenVPN Technologies, Inc. All rights reserved.
//
// 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);
// When a connection is close to timeout, the core will call this
// method. If it returns false, the core will disconnect with a
// CONNECTION_TIMEOUT event. If true, the core will enter a PAUSE
// state.
boolean pause_on_connection_timeout();
// 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.
// Methods documented in openvpn/tun/builder/base.hpp
boolean tun_builder_set_remote_address(String address, boolean ipv6);
boolean tun_builder_add_address(String address, int prefix_length, boolean ipv6);
boolean tun_builder_reroute_gw(String server_address, boolean server_address_ipv6, boolean ipv6);
boolean tun_builder_add_route(String address, int prefix_length, boolean ipv6);
boolean tun_builder_exclude_route(String address, int prefix_length, boolean ipv6);
boolean tun_builder_add_dns_server(String address, boolean ipv6, boolean reroute_dns);
boolean tun_builder_add_search_domain(String domain, boolean reroute_dns);
boolean tun_builder_set_mtu(int mtu);
boolean tun_builder_set_session_name(String name);
int tun_builder_establish();
void tun_builder_teardown();
}
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().
// This method will give the thread one second to
// exit and will abandon it after this time.
public void wait_thread_short() {
final int wait_millisecs = 5000; // 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();
status.setError(true);
status.setMessage("CORE_THREAD_ABANDONED");
call_done(status);
}
}
}
// Wait for worker thread to complete; to stop thread,
// first call super stop() method then wait_thread().
// This method will wait forever for the thread to exit.
public void wait_thread_long() {
if (thread != null) {
boolean interrupted;
do {
interrupted = false;
try {
thread.join();
}
catch (InterruptedException e) {
interrupted = true;
super.stop(); // send thread a stop message
}
} while (interrupted);
}
}
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 boolean pause_on_connection_timeout() {
EventReceiver p = parent;
if (p != null)
return p.pause_on_connection_timeout();
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_set_remote_address(String address, boolean ipv6) {
TunBuilder tb = tun_builder;
if (tb != null)
return tb.tun_builder_set_remote_address(address, ipv6);
else
return false;
}
@Override
public boolean tun_builder_add_address(String address, int prefix_length, boolean ipv6) {
TunBuilder tb = tun_builder;
if (tb != null)
return tb.tun_builder_add_address(address, prefix_length, ipv6);
else
return false;
}
@Override
public boolean tun_builder_reroute_gw(String server_address, boolean server_address_ipv6, boolean ipv6) {
TunBuilder tb = tun_builder;
if (tb != null)
return tb.tun_builder_reroute_gw(server_address, server_address_ipv6, ipv6);
else
return false;
}
@Override
public boolean tun_builder_add_route(String address, int prefix_length, boolean ipv6) {
TunBuilder tb = tun_builder;
if (tb != null)
return tb.tun_builder_add_route(address, prefix_length, ipv6);
else
return false;
}
@Override
public boolean tun_builder_exclude_route(String address, int prefix_length, boolean ipv6) {
TunBuilder tb = tun_builder;
if (tb != null)
return tb.tun_builder_exclude_route(address, prefix_length, ipv6);
else
return false;
}
@Override
public boolean tun_builder_add_dns_server(String address, boolean ipv6, boolean reroute_dns) {
TunBuilder tb = tun_builder;
if (tb != null)
return tb.tun_builder_add_dns_server(address, ipv6, reroute_dns);
else
return false;
}
@Override
public boolean tun_builder_add_search_domain(String domain, boolean reroute_dns)
{
TunBuilder tb = tun_builder;
if (tb != null)
return tb.tun_builder_add_search_domain(domain, reroute_dns);
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;
}
@Override
public void tun_builder_teardown() {
TunBuilder tb = tun_builder;
if (tb != null)
tb.tun_builder_teardown();
}
}