Skip to content

Commit

Permalink
MainService: Now service is stopped if interface goes down
Browse files Browse the repository at this point in the history
I was capable of implementing an all-Java solution.
For some reason though, I was not capable of making it work with VPNs (needs more testing, I think).
  • Loading branch information
elluisian committed Sep 1, 2024
1 parent 600d9ea commit 434bea0
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@

import android.content.res.Resources;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;

import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
Expand All @@ -43,6 +46,7 @@ private static class ViewHolder {
}

// Data to be shown with the adapter
private ArrayList<String> dataStr;
private ArrayList<NetworkInterfaceTester.NetIfData> data;
private int dataSize;

Expand All @@ -52,6 +56,9 @@ private static class ViewHolder {
private LayoutInflater mInflater;


// UI related
private Handler handler;



public ListenIfAdapter(NetworkInterfaceTester nit, Context context) {
Expand All @@ -60,8 +67,10 @@ public ListenIfAdapter(NetworkInterfaceTester nit, Context context) {
this.mContext = context;
this.mInflater = LayoutInflater.from(this.mContext);

this.handler = new Handler(Looper.getMainLooper());

nit.addOnNetworkStateChangedListener(this);
this.onNetworkStateChanged(nit, null, false);
this.onNetworkStateChanged(nit, null, 0, false);
}


Expand All @@ -80,9 +89,19 @@ public int getItemPositionByIfName(String ifName) {



@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
return this.handleViewRecreation(position, convertView, parent);
}


@Override
public View getView(int position, View convertView, ViewGroup parent) {
return this.handleViewRecreation(position, convertView, parent);
}


private View handleViewRecreation(int position, View convertView, ViewGroup parent) {
if (convertView == null) { // Check if view must be recreated using the famous ViewHolder pattern
convertView = this.mInflater.inflate(R.layout.spinner_row, parent, false);

Expand All @@ -92,13 +111,14 @@ public View getView(int position, View convertView, ViewGroup parent) {
}

ViewHolder vh = (ViewHolder)convertView.getTag();
NetworkInterfaceTester.NetIfData nid = this.getItem(position);
vh.txtLabel.setText(nid.toString());
String label = this.dataStr.get(position);
vh.txtLabel.setText(label);

return convertView;
}



@Override
public NetworkInterfaceTester.NetIfData getItem(int position) {
if (0 <= position && position < this.getCount()) {
Expand All @@ -108,15 +128,35 @@ public NetworkInterfaceTester.NetIfData getItem(int position) {
}



@Override
public int getCount() {
return this.dataSize;
}



public void onNetworkStateChanged(NetworkInterfaceTester nit, NetworkInterface iface, boolean enabled) {
public void onNetworkStateChanged(NetworkInterfaceTester nit, NetworkInterface iface, int i, boolean enabled) {
this.data = nit.getAvailableInterfaces();
this.dataSize = this.data.size();

this.dataStr = new ArrayList<>();
for (NetworkInterfaceTester.NetIfData nid : this.data) {
String actualName = " (" + nid.getName() + ")";
String displayName = nid.getDisplayName();

if (nid.getName().equals("0.0.0.0")) {
displayName = this.mContext.getResources().getString(R.string.main_activity_settings_listenif_spin_any);
}

this.dataStr.add(displayName + actualName);
}

// update Spinner
this.handler.post(new Runnable() {
public void run() {
ListenIfAdapter.this.notifyDataSetChanged();
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ protected void onCreate(Bundle savedInstanceState) {
});


NetworkInterfaceTester nit = new NetworkInterfaceTester(this);
NetworkInterfaceTester nit = NetworkInterfaceTester.getInstance(this);
ListenIfAdapter lsif = new ListenIfAdapter(nit, this);
final Spinner listenInterfaceSpin = findViewById(R.id.settings_listening_interface);
listenInterfaceSpin.setAdapter(lsif);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

public class MainService extends Service {
public class MainService extends Service implements NetworkInterfaceTester.OnNetworkStateChangedListener {

private static final String TAG = "MainService";
static final int NOTIFICATION_ID = 11;
Expand Down Expand Up @@ -188,6 +188,7 @@ public void onCreate() {
Log.d(TAG, "onCreate");

instance = this;
NetworkInterfaceTester.getInstance(this).addOnNetworkStateChangedListener(this);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
/*
Expand Down Expand Up @@ -926,4 +927,18 @@ static Notification getCurrentNotification() {
return null;
}
}




public void onNetworkStateChanged(NetworkInterfaceTester nit, NetworkInterface iface, int i, boolean enabled) {

if (isServerActive()) {
if (nit.getItem(i).getName().equals(getListenInterface())) {
if (!nit.isEnabled(i)) {
this.stopSelf();
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,21 @@
public class NetworkInterfaceTester extends ConnectivityManager.NetworkCallback {
public static final String TAG = "NetworkInterfaceTester";

private static NetworkInterfaceTester INSTANCE;



public synchronized static NetworkInterfaceTester getInstance(Context context) {
if (NetworkInterfaceTester.INSTANCE == null) {
NetworkInterfaceTester.INSTANCE = new NetworkInterfaceTester(context);
}
return NetworkInterfaceTester.INSTANCE;
}



public static interface OnNetworkStateChangedListener {
public void onNetworkStateChanged(NetworkInterfaceTester nit, NetworkInterface iface, boolean enabled);
public void onNetworkStateChanged(NetworkInterfaceTester nit, NetworkInterface iface, int i, boolean enabled);
}


Expand All @@ -52,16 +65,16 @@ public static class NetIfData {
private String displayName;
private String friendlyName;

private NetIfData(Context context) {
this(null, context);
private NetIfData() {
this(null);
}

private NetIfData(NetworkInterface nic, Context context) {
private NetIfData(NetworkInterface nic) {
this.nic = nic;

if (nic == null) {
this.name = "0.0.0.0";
this.displayName = context.getResources().getString(R.string.main_activity_settings_listenif_spin_any);
this.displayName = "Any";

} else {
this.name = this.nic.getName();
Expand All @@ -70,15 +83,15 @@ private NetIfData(NetworkInterface nic, Context context) {
}
}

public static NetIfData getAnyOption(Context context) {
public static NetIfData getAnyOption() {
if (NetworkInterfaceTester.IF_ANY == null) {
NetworkInterfaceTester.IF_ANY = new NetIfData(context);
NetworkInterfaceTester.IF_ANY = new NetIfData();
}
return NetworkInterfaceTester.IF_ANY;
}

public static NetIfData getOptionForNic(NetworkInterface nic, Context context) {
return new NetIfData(nic, context);
public static NetIfData getOptionForNic(NetworkInterface nic) {
return new NetIfData(nic);
}


Expand Down Expand Up @@ -113,10 +126,9 @@ public String toString() {



public NetworkInterfaceTester(Context context) {
this.context = context;

private NetworkInterfaceTester(Context context) {
this.netIf = Utils.getAvailableNICs();

this.netIfSize = this.netIf.size();

this.netIfEnabled = new ArrayList<>();
Expand Down Expand Up @@ -146,14 +158,13 @@ public NetworkInterfaceTester(Context context) {




public ArrayList<NetIfData> getAvailableInterfaces() {
ArrayList<NetIfData> ls = new ArrayList<>();

ls.add(NetIfData.getAnyOption(this.context));
ls.add(NetIfData.getAnyOption());
for (int i = 0; i < this.netIfSize; i++) {
if (this.netIfEnabled.get(i)) {
NetIfData nid = NetIfData.getOptionForNic(this.netIf.get(i), this.context);
NetIfData nid = NetIfData.getOptionForNic(this.netIf.get(i));
ls.add(nid);
}
}
Expand All @@ -167,32 +178,64 @@ public ArrayList<NetIfData> getAvailableInterfaces() {
@Override
public void onAvailable(Network network) {
super.onAvailable(network);
int i = this.storeNetworkHashCode(network);
this.setEnabled(i, true);
this.updateListener(i, true);
int i = this.storeNetwork(network);
if (i != -1) {
this.setEnabled(i, true);
this.updateListener(i, true);
}
}


@Override
public void onLost(Network network) {
super.onLost(network);
int i = this.getFromNetworkHashCode(network);
this.setEnabled(i, false);
this.updateListener(i, false);
int i = this.getFromNetwork(network);
if (i != -1) {
this.setEnabled(i, false);
this.updateListener(i, false);
}
}


@Override
public void onLosing(Network network, int maxMsToLive) {
Log.d(TAG, "onLosing " + network);
}


private int storeNetworkHashCode(Network network) {

@Override
public void onBlockedStatusChanged(Network network, boolean blocked) {
Log.d(TAG, "onBlockedStatusChagned " + network);
}


@Override
public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) {
Log.d(TAG, "onLinkPropertiesChanged " + network);
}


/*
* The idea is simple: during onLost, LinkProperties attributes are lost
* inside Network, so, memorize a reference to the Network instance, this way,
* we'll be able to understand what exact interface was lost.
*/
private int storeNetwork(Network network) {
LinkProperties prop = this.manager.getLinkProperties(network);

NetworkInterface iface = null;
try {
iface = NetworkInterface.getByName(prop.getInterfaceName());

} catch (SocketException ex) {
// unused
Log.d(TAG, "Socket exception has occurred, return -1");
return -1;

}


// No socket exception occurred, let's see if the interface is available
int i = 0;
boolean found = false;
for (i = 0; !found && i < this.netIfSize; i++) {
Expand All @@ -203,18 +246,25 @@ private int storeNetworkHashCode(Network network) {
}
}

if (found) {
Log.d(TAG, "Added network " + iface.getName());
} else {
Log.d(TAG, "No network found");

if (!found) { // if not found, it means that it has been created recently, add to list
this.netIf.add(iface);
this.networks.add(network);
this.netIfSize++;
}

return found ? i : -1;
Log.d(TAG, "Added network " + iface.getName());

return i;
}


public NetIfData getItem(int i) {
return i == 0 ? NetIfDat.getAnyOption() : NetIfData.getOptionForNic(this.netIf.get(i));
}

private int getFromNetworkHashCode(Network network) {

private int getFromNetwork(Network network) {
int i = this.networks.indexOf(network);

if (i != -1) {
Expand All @@ -233,6 +283,11 @@ private void setEnabled(int i, boolean enabled) {
}


public boolean isEnabled(int i) {
return this.netIfEnabled.get(i);
}




public void addOnNetworkStateChangedListener(OnNetworkStateChangedListener onscl) {
Expand All @@ -244,7 +299,7 @@ public void addOnNetworkStateChangedListener(OnNetworkStateChangedListener onscl

private void updateListener(int i, boolean enabled) {
for (OnNetworkStateChangedListener onscl : this.listeners) {
onscl.onNetworkStateChanged(this, this.netIf.get(i), enabled);
onscl.onNetworkStateChanged(this, this.netIf.get(i), i, enabled);
}
}
}
2 changes: 1 addition & 1 deletion app/src/main/java/net/christianbeier/droidvnc_ng/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ object Utils {

@JvmStatic
fun getAvailableNICs(): ArrayList<NetworkInterface> {
return getAvailableNICs(true, true);
return getAvailableNICs(false, true);
}


Expand Down

0 comments on commit 434bea0

Please sign in to comment.