2
0
mirror of https://github.com/KDE/kdeconnect-android synced 2025-08-22 18:07:55 +00:00

Fix discovering myself and too many registrations

This commit is contained in:
Albert Vaca Cintora 2020-07-19 00:52:29 +02:00
parent 826c0a854e
commit ad49e500fa
2 changed files with 59 additions and 75 deletions

View File

@ -53,6 +53,7 @@ import java.net.InetSocketAddress;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
import java.net.SocketException; import java.net.SocketException;
import java.nio.charset.StandardCharsets;
import java.security.cert.Certificate; import java.security.cert.Certificate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@ -61,7 +62,7 @@ import javax.net.SocketFactory;
import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocket;
/** /**
* This BaseLinkProvider creates {@link MulticastLink}s to other devices on the same * This MulticastLinkProvider creates {@link MulticastLink}s to other devices on the same
* WiFi network. The first packet sent over a socket must be an * WiFi network. The first packet sent over a socket must be an
* {@link NetworkPacket#createIdentityPacket(Context)}. * {@link NetworkPacket#createIdentityPacket(Context)}.
* *
@ -73,24 +74,19 @@ public class MulticastLinkProvider extends BaseLinkProvider implements Multicast
static final String SERVICE_TYPE = "_kdeconnect._tcp"; static final String SERVICE_TYPE = "_kdeconnect._tcp";
private NsdManager mNsdManager;
private RegistrationListener mRegistrationListener;
private boolean mServiceRegistered = false;
private final static int MIN_PORT = 1716; private final static int MIN_PORT = 1716;
private final static int MAX_PORT = 1764; private final static int MAX_PORT = 1764;
final static int PAYLOAD_TRANSFER_MIN_PORT = 1739; final static int PAYLOAD_TRANSFER_MIN_PORT = 1739;
private final Context context; private final Context context;
private final HashMap<String, MulticastLink> visibleComputers = new HashMap<>(); //Links by device id private NsdManager mNsdManager;
private RegistrationListener mRegistrationListener;
private NsdManager.DiscoveryListener discoveryListener;
private ServerSocket tcpServer; private ServerSocket tcpServer;
private boolean listening = false; private boolean listening = false;
// To prevent infinte loop between Android < IceCream because both device can only broadcast identity package but cannot connect via TCP private final HashMap<String, MulticastLink> visibleComputers = new HashMap<>(); //Links by device id
private final ArrayList<InetAddress> reverseConnectionBlackList = new ArrayList<>();
@Override // SocketClosedCallback @Override // SocketClosedCallback
public void linkDisconnected(MulticastLink brokenLink) { public void linkDisconnected(MulticastLink brokenLink) {
@ -256,8 +252,8 @@ public class MulticastLinkProvider extends BaseLinkProvider implements Multicast
try { try {
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String message = reader.readLine(); String message = reader.readLine();
Log.e("TcpListener","Received TCP package: "+message);
return NetworkPacket.unserialize(message); return NetworkPacket.unserialize(message);
//Log.e("TcpListener","Received TCP package: "+networkPacket.serialize());
} catch (Exception e) { } catch (Exception e) {
Log.e(LOG_TAG, "Exception while receiving TCP packet", e); Log.e(LOG_TAG, "Exception while receiving TCP packet", e);
return null; return null;
@ -314,7 +310,7 @@ public class MulticastLinkProvider extends BaseLinkProvider implements Multicast
// Save the service name. Android may have changed it in order to // Save the service name. Android may have changed it in order to
// resolve a conflict, so update the name you initially requested // resolve a conflict, so update the name you initially requested
// with the name Android actually used. // with the name Android actually used.
Log.i(LOG_TAG, "Registered " + NsdServiceInfo.getServiceName()); Log.e(LOG_TAG, "Registered " + NsdServiceInfo.getServiceName());
} }
@Override @Override
@ -327,7 +323,7 @@ public class MulticastLinkProvider extends BaseLinkProvider implements Multicast
public void onServiceUnregistered(NsdServiceInfo arg0) { public void onServiceUnregistered(NsdServiceInfo arg0) {
// Service has been unregistered. This only happens when you call // Service has been unregistered. This only happens when you call
// NsdManager.unregisterService() and pass in this listener. // NsdManager.unregisterService() and pass in this listener.
Log.w(LOG_TAG, "Service unregistered: " + arg0); Log.e(LOG_TAG, "Service unregistered: " + arg0);
} }
@Override @Override
@ -339,43 +335,35 @@ public class MulticastLinkProvider extends BaseLinkProvider implements Multicast
} }
@RequiresApi(Build.VERSION_CODES.LOLLIPOP) @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
public void initializeNsdManager(RegistrationListener registrationListener) { public void initializeNsdManager() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
return;
}
mNsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE); mNsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
try {
mNsdManager.unregisterService(registrationListener);
} catch (java.lang.IllegalArgumentException e) {
// not yet registered, but it's fine.
}
NsdServiceInfo serviceInfo = new NsdServiceInfo(); NsdServiceInfo serviceInfo = new NsdServiceInfo();
// It wasn't possible for the device which receives the incoming connection
// to use these attributes (there's no way to correlate the incoming connection
// with a discovered service), so we have to rely on sending this stuff in
// an identity packet like in the LanLink. That's the reason this is commented out.
// These cause the requirement for api level 21.
serviceInfo.setAttribute("id", DeviceHelper.getDeviceId(context));
// The name is subject to change based on conflicts // The name is subject to change based on conflicts
// with other services advertised on the same network. // with other services advertised on the same network.
NetworkPacket myIdentity = NetworkPacket.createIdentityPacket(context); //serviceInfo.setAttribute("name", DeviceHelper.getDeviceName(context));
String did = myIdentity.getString("deviceID"); //serviceInfo.setAttribute("type", DeviceHelper.getDeviceType(context).toString());
String name = myIdentity.getString("deviceName"); //serviceInfo.setAttribute("version", Integer.toString(DeviceHelper.ProtocolVersion));
InetAddress addr = this.tcpServer.getInetAddress();
int port = this.tcpServer.getLocalPort();
// These cause the requirement for api level 21.
serviceInfo.setAttribute("name", myIdentity.getString("deviceName"));
serviceInfo.setAttribute("id", myIdentity.getString("deviceId"));
serviceInfo.setAttribute("type", myIdentity.getString("deviceType"));
serviceInfo.setAttribute("version", myIdentity.getString("protocolVersion"));
// It might be nice to add the capabilities in the mDNS advertisement too, but without // It might be nice to add the capabilities in the mDNS advertisement too, but without
// some kind of encoding that is too large for the TXT record // some kind of encoding that is too large for the TXT record
serviceInfo.setServiceName("KDE Connect on " + myIdentity.getString("deviceName")); serviceInfo.setServiceName("KDE Connect on " + DeviceHelper.getDeviceName(context));
serviceInfo.setServiceType(SERVICE_TYPE); serviceInfo.setServiceType(SERVICE_TYPE);
serviceInfo.setHost(addr); // This gets autodetected if not set
serviceInfo.setPort(port); //serviceInfo.setHost(this.tcpServer.getInetAddress());
serviceInfo.setPort(this.tcpServer.getLocalPort());
//Log.d("KDE/Lan", "service: " + serviceInfo.toString()); //Log.d("KDE/Lan", "service: " + serviceInfo.toString());
mNsdManager.registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, registrationListener); mNsdManager.registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener);
} }
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN) @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
@ -389,7 +377,13 @@ public class MulticastLinkProvider extends BaseLinkProvider implements Multicast
@Override @Override
public void onServiceResolved(NsdServiceInfo serviceInfo) { public void onServiceResolved(NsdServiceInfo serviceInfo) {
Log.i(LOG_TAG, "Successfully resolved " + serviceInfo); Log.e(LOG_TAG, "Successfully resolved " + serviceInfo);
byte[] id = serviceInfo.getAttributes().get("id");
if (id != null && DeviceHelper.getDeviceId(context).equals(new String(id, StandardCharsets.UTF_8))) {
Log.e(LOG_TAG, "Ignoring connection to myself");
return;
}
InetAddress hostname = serviceInfo.getHost(); InetAddress hostname = serviceInfo.getHost();
int remotePort = serviceInfo.getPort(); int remotePort = serviceInfo.getPort();
@ -408,8 +402,8 @@ public class MulticastLinkProvider extends BaseLinkProvider implements Multicast
try { try {
Log.i(LOG_TAG, "Got identity: " + otherIdentity.serialize()); Log.i(LOG_TAG, "Got identity: " + otherIdentity.serialize());
} catch (JSONException e) { } catch (Exception e) {
Log.e(LOG_TAG, "Got identity, but unable to serialize!", e); Log.e(LOG_TAG, "Got identity, but unable to serialize from " + serviceInfo, e);
return; return;
} }
} }
@ -419,7 +413,7 @@ public class MulticastLinkProvider extends BaseLinkProvider implements Multicast
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN) @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
public void initializeDiscoveryListener() { public void initializeDiscoveryListener() {
// Instantiate a new DiscoveryListener // Instantiate a new DiscoveryListener
NsdManager.DiscoveryListener discoveryListener = new NsdManager.DiscoveryListener() { discoveryListener = new NsdManager.DiscoveryListener() {
// Called as soon as service discovery begins. // Called as soon as service discovery begins.
@Override @Override
@ -430,7 +424,7 @@ public class MulticastLinkProvider extends BaseLinkProvider implements Multicast
@Override @Override
public void onServiceFound(NsdServiceInfo service) { public void onServiceFound(NsdServiceInfo service) {
// A service was found! Do something with it. // A service was found! Do something with it.
Log.d(LOG_TAG, "Service discovery success" + service); Log.e(LOG_TAG, "Service discovery success" + service);
mNsdManager.resolveService(service, createResolveListener()); mNsdManager.resolveService(service, createResolveListener());
} }
@ -443,7 +437,7 @@ public class MulticastLinkProvider extends BaseLinkProvider implements Multicast
@Override @Override
public void onDiscoveryStopped(String serviceType) { public void onDiscoveryStopped(String serviceType) {
Log.i(LOG_TAG, "Discovery stopped: " + serviceType); Log.e(LOG_TAG, "Discovery stopped: " + serviceType);
listening = false; listening = false;
} }
@ -463,28 +457,6 @@ public class MulticastLinkProvider extends BaseLinkProvider implements Multicast
mNsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, discoveryListener); mNsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, discoveryListener);
} }
@Override
public void onStart() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
Log.i(LOG_TAG, "MulticastBackend not supported on devices older thab Lollipop");
return;
}
if (!listening) {
listening = true;
// Need to set up TCP before setting up mDNS because we need to know the TCP listening
// address and port
setupTcpListener();
initializeRegistrationListener();
initializeNsdManager(mRegistrationListener);
initializeDiscoveryListener();
}
}
@Override @Override
public void onNetworkChange() { public void onNetworkChange() {
onStop(); onStop();
@ -492,15 +464,27 @@ public class MulticastLinkProvider extends BaseLinkProvider implements Multicast
} }
@Override @Override
public void onStop() { public synchronized void onStart() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { if (!listening) {
// This backend does not work on older Android versions listening = true;
return;
}
mNsdManager.unregisterService(mRegistrationListener); // Need to set up TCP before setting up mDNS because we need to know the TCP listening
tcpServer.close(); // address and port
listening = false; setupTcpListener();
initializeRegistrationListener();
initializeNsdManager();
initializeDiscoveryListener();
}
}
@Override
public synchronized void onStop() {
//if (listening) {
// mNsdManager.stopServiceDiscovery(discoveryListener);
// mNsdManager.unregisterService(mRegistrationListener);
// try { tcpServer.close(); } catch (IOException ignored) { }
// listening = false;
//}
} }
@Override @Override

View File

@ -163,7 +163,7 @@ public class BackgroundService extends Service {
} }
private void registerLinkProviders() { private void registerLinkProviders() {
linkProviders.add(new LanLinkProvider(this)); //linkProviders.add(new LanLinkProvider(this));
linkProviders.add(new MulticastLinkProvider(this)); linkProviders.add(new MulticastLinkProvider(this));
// linkProviders.add(new LoopbackLinkProvider(this)); // linkProviders.add(new LoopbackLinkProvider(this));
// linkProviders.add(new BluetoothLinkProvider(this)); // linkProviders.add(new BluetoothLinkProvider(this));