0
0
mirror of https://github.com/OpenVPN/openvpn3.git synced 2024-09-19 19:52:15 +02:00
openvpn3/javacli/OpenVPNClientThread.java

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

360 lines
9.8 KiB
Java
Raw Normal View History

// 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-2022 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
// package OPENVPN_PACKAGE
import java.util.HashSet;
public class OpenVPNClientThread extends ClientAPI_OpenVPNClient implements Runnable {
2012-02-15 16:13:35 +01:00
private EventReceiver parent;
private TunBuilder tun_builder;
private Thread thread;
private ClientAPI_Status m_connect_status;
private boolean connect_called = false;
2012-02-24 20:50:14 +01:00
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 {
}
2012-02-15 16:13:35 +01:00
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();
2012-03-06 07:06:54 +01:00
// 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, String gateway, boolean ipv6, boolean net30);
boolean tun_builder_reroute_gw(boolean ipv4, boolean ipv6, long flags);
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 tun_builder_add_search_domain(String domain);
boolean tun_builder_set_mtu(int mtu);
boolean tun_builder_set_session_name(String name);
int tun_builder_establish();
void tun_builder_teardown(boolean disconnect);
2012-02-15 16:13:35 +01:00
}
public OpenVPNClientThread() {
2012-02-24 20:50:14 +01:00
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() {
This is a general pre-release fine-tuning of both Android and iOS clients. Versioning: iOS -- 1.0 Beta 23 Android -- 1.1.0 (build 6) Both clients: * Bundled IPv6 test profile as provided by Gert Doering. Modified iOS beta testing notes with info on this profile. * Fixed issue where profile import might fail if profile filename ended in .OVPN (i.e. all-caps extension). Android client: * General UI cleanup: 1. Added status icon, 2. eliminated long "Connected" line that wrapped badly on phone-sized devices, 3. reorganized connection details, 4. include all stats that are provided by the core, including "last packet received n seconds ago". * Fixed issue where importing profiles via web browser would not ultimately land on the OpenVPN main page after import completion. * Added profile rename (select via long-touch on profile name). * Added "Auto Keyboard" preference similar to iOS. * Turn on full compression by default (can be modified via a preference), just as it is for iOS. * Disable spell-checker on all input fields. * Wait a maximum of 5 seconds (formerly 3) after Disconnect button press before abandoning core thread. * Added versionName and versionCode to AndroidManifest.xml for Google play submission. * Revamped OpenVPNService event model for profile management events, to fix some corner-case issues. Android API changes: This release includes some minor changes to the OpenVPN Service API: 1. Added enable_trust_error_dialog boolean parameter to OpenVPNClientBase.importProfileRemote. This should be set to false for Private Tunnel client. 2. Changed the way that profile import events signal back to the UI layer. OpenVPNClientBase.get_priority_profile_name has been removed, and profile signaling events are now performed completely via the standard event stream.
2012-10-10 13:04:34 +02:00
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();
Fixed a race condition issue with "hot connect", i.e. sending a connect intent to service when already connected. One of the ramifications of the "hot connect" fix above is that OpenVPNClientBase.is_active() will now return a value that is instantaneously up-to-date, whereas events might lag because of the mechanics of inter-thread message posting. Keep this in mind when correlating received events to is_active() values. For C++ core threads, increased allowed thread-stop delay to 2.5 seconds before thread is marked as unresponsive and abandoned. Previous delay was 1 second. This delay can't be made too long, otherwise Android will tell the user that the app is unresponsive and invite them to kill it. When closing out an abandoned core thread, indicate this condition with a new event type called CORE_THREAD_ABANDONED. If the thread is abandoned due to lack of response to a disconnect request, then the CORE_THREAD_ABANDONED event will occur followed by CORE_THREAD_INACTIVE. For core threads that properly exit, the DISCONNECTED event will be followed by CORE_THREAD_INACTIVE. Added save_as_filename parameter to importProfileRemote method for controlling the filename that the imported profile is saved as. This parameter may be set to null to have the method choose an appropriate name. To have an imported profile replace an existing profile, the filenames much match. Added UI_OVERLOADED debugging constant to OpenVPNClient to allow the UI to connect to a profile when already connected to another profile in order to test "hot connect". Added new events CLIENT_HALT and CLIENT_RESTART for compatibility with an Access Server feature that allows the server to remotely kill or restart the client. When connecting a profile, the core will now automatically fill in the username if it is not specified for userlocked profiles. Version 0.902.
2012-03-31 18:08:20 +02:00
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);
}
}
2012-02-24 20:50:14 +01:00
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);
}
2012-03-06 07:06:54 +01:00
@Override
public void external_pki_cert_request(ClientAPI_ExternalPKICertRequest req) {
EventReceiver p = parent;
if (p != null)
p.external_pki_cert_request(req);
2012-03-06 07:06:54 +01:00
}
@Override
public void external_pki_sign_request(ClientAPI_ExternalPKISignRequest req) {
EventReceiver p = parent;
if (p != null)
p.external_pki_sign_request(req);
2012-03-06 07:06:54 +01:00
}
// 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, String gateway, boolean ipv6, boolean net30) {
TunBuilder tb = tun_builder;
if (tb != null)
return tb.tun_builder_add_address(address, prefix_length, gateway, ipv6, net30);
else
return false;
}
@Override
public boolean tun_builder_reroute_gw(boolean ipv4, boolean ipv6, long flags) {
TunBuilder tb = tun_builder;
if (tb != null)
return tb.tun_builder_reroute_gw(ipv4, ipv6, flags);
else
return false;
}
@Override
public boolean tun_builder_add_route(String address, int prefix_length, int metric, 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, int metric, 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) {
TunBuilder tb = tun_builder;
if (tb != null)
return tb.tun_builder_add_dns_server(address, ipv6);
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;
}
@Override
public void tun_builder_teardown(boolean disconnect) {
TunBuilder tb = tun_builder;
if (tb != null)
tb.tun_builder_teardown(disconnect);
}
}