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

Re-use existing link instead of creating a new one

This commit is contained in:
Albert Vaca
2016-03-02 11:39:49 -08:00
parent baee1771f5
commit c0d21e986c
6 changed files with 110 additions and 105 deletions

View File

@@ -34,10 +34,6 @@ public abstract class BaseLink {
protected final Context context;
public enum ConnectionStarted {
Locally, Remotely;
};
public interface PackageReceiver {
void onPackageReceived(NetworkPackage np);
}
@@ -47,16 +43,10 @@ public abstract class BaseLink {
private final ArrayList<PackageReceiver> receivers = new ArrayList<>();
protected PrivateKey privateKey;
protected ConnectionStarted connectionSource; // If the other device sent me a broadcast,
// I should not close the connection with it
// because it's probably trying to find me and
// potentially ask for pairing.
protected BaseLink(Context context, String deviceId, BaseLinkProvider linkProvider, ConnectionStarted connectionSource) {
protected BaseLink(Context context, String deviceId, BaseLinkProvider linkProvider) {
this.context = context;
this.linkProvider = linkProvider;
this.deviceId = deviceId;
this.connectionSource = connectionSource;
}
/* To be implemented by each link for pairing handlers */
@@ -75,8 +65,9 @@ public abstract class BaseLink {
return linkProvider;
}
public ConnectionStarted getConnectionSource() {
return connectionSource;
//The daemon will periodically destroy unpaired links if this returns false
public boolean linkShouldBeKeptAlive() {
return false;
}
public void addPackageReceiver(PackageReceiver pr) {

View File

@@ -21,6 +21,7 @@
package org.kde.kdeconnect.Backends.LanBackend;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
import org.json.JSONObject;
@@ -50,17 +51,32 @@ import io.netty.channel.ChannelFuture;
public class LanLink extends BaseLink {
public enum ConnectionStarted {
Locally, Remotely;
};
protected ConnectionStarted connectionSource; // If the other device sent me a broadcast,
// I should not close the connection with it
// because it's probably trying to find me and
// potentially ask for pairing.
private Channel channel = null;
private boolean onSsl = false;
// Using time stamp, because if both devices emit their identity package at the same time, both the links tends to cancel each other
private long startTime = 0;
@Override
public void disconnect() {
closeSocket();
}
//Returns the old channel
public Channel reset(Channel channel, ConnectionStarted connectionSource, boolean onSsl) {
Channel oldChannel = this.channel;
this.channel = channel;
this.connectionSource = connectionSource;
return oldChannel;
}
public void closeSocket() {
if (channel == null) {
Log.e("KDE/LanLink", "Not yet connected");
@@ -69,19 +85,11 @@ public class LanLink extends BaseLink {
channel.close();
}
public void setOnSsl(boolean value) {
this.onSsl = value;
public LanLink(Context context, String deviceId, BaseLinkProvider linkProvider, Channel channel, ConnectionStarted connectionSource, boolean onSsl) {
super(context, deviceId, linkProvider);
reset(channel, connectionSource, onSsl);
}
public LanLink(Context context,Channel channel, String deviceId, BaseLinkProvider linkProvider, ConnectionStarted connectionSource) {
super(context, deviceId, linkProvider, connectionSource);
this.channel = channel;
this.startTime = System.currentTimeMillis();
}
public long getStartTime() {
return startTime;
}
@Override
public String getName() {
@@ -306,4 +314,22 @@ public class LanLink extends BaseLink {
return candidateServer;
}
@Override
public boolean linkShouldBeKeptAlive() {
//We keep the remotely initiated connections, since the remotes require them if they want to request
//pairing to us, or connections that are already paired. TODO: Keep connections in the process of pairing
if (connectionSource == ConnectionStarted.Remotely) {
return true;
}
SharedPreferences preferences = context.getSharedPreferences("trusted_devices", Context.MODE_PRIVATE);
if (preferences.contains(getDeviceId())) {
return true; //Already paired
}
return false;
}
}

View File

@@ -40,6 +40,7 @@ import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.security.cert.Certificate;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Timer;
@@ -167,9 +168,8 @@ public class LanLinkProvider extends BaseLinkProvider {
Log.i("KDE/LanLinkProvider", "Identity package received from " + np.getString("deviceName"));
final LanLink link = new LanLink(context, ctx.channel(), np.getString("deviceId"), LanLinkProvider.this, BaseLink.ConnectionStarted.Locally);
nioLinks.put(ctx.channel().hashCode(), link);
//Log.i("KDE/LanLinkProvider","nioLinks.size(): " + nioLinks.size());
final Channel channel = ctx.channel();
final LanLink.ConnectionStarted connectionStarted = LanLink.ConnectionStarted.Locally;
// Add ssl handler if device uses new protocol
try {
@@ -185,8 +185,7 @@ public class LanLinkProvider extends BaseLinkProvider {
Log.i("KDE/LanLinkProvider","Handshake successful with " + np.getString("deviceName") + " secured with " + sslEngine.getSession().getCipherSuite());
Certificate certificate = sslEngine.getSession().getPeerCertificates()[0];
np.set("certificate", Base64.encodeToString(certificate.getEncoded(), 0));
link.setOnSsl(true);
addLink(np, link);
addLink(np, channel, connectionStarted, true);
} else {
// Unpair if handshake failed
Log.e("KDE/LanLinkProvider", "Handshake failed with " + np.getString("deviceName"));
@@ -206,7 +205,7 @@ public class LanLinkProvider extends BaseLinkProvider {
}
});
} else {
addLink(np, link);
addLink(np, channel, connectionStarted, false);
}
} catch (Exception e) {
e.printStackTrace();
@@ -286,61 +285,52 @@ public class LanLinkProvider extends BaseLinkProvider {
channel.pipeline().addFirst(sslHandler);
}
final LanLink link = new LanLink(context, channel, identityPackage.getString("deviceId"), LanLinkProvider.this, BaseLink.ConnectionStarted.Remotely);
final LanLink.ConnectionStarted connectionStarted = LanLink.ConnectionStarted.Remotely;
NetworkPackage np2 = NetworkPackage.createIdentityPackage(context);
link.sendPackage(np2,new Device.SendPackageStatusCallback() {
@Override
protected void onSuccess() {
nioLinks.put(channel.hashCode(), link);
Log.i("KDE/LanLinkProvider", "nioLinks.size(): " + nioLinks.size());
// If ssl handler is in channel, add link after handshake is completed
final SslHandler sslHandler = channel.pipeline().get(SslHandler.class);
if (sslHandler != null) {
sslHandler.handshakeFuture().addListener(new GenericFutureListener<Future<? super Channel>>() {
@Override
public void operationComplete(Future<? super Channel> future) throws Exception {
if (future.isSuccess()) {
try {
Log.i("KDE/LanLinkProvider", "Handshake successfully completed with " + identityPackage.getString("deviceName") + ", session secured with " + sslHandler.engine().getSession().getCipherSuite());
Certificate certificate = sslHandler.engine().getSession().getPeerCertificates()[0];
identityPackage.set("certificate", Base64.encodeToString(certificate.getEncoded(), 0));
link.setOnSsl(true);
addLink(identityPackage, link);
} catch (Exception e){
e.printStackTrace();
}
} else {
// Unpair if handshake failed
// Any exception or handshake exception ?
Log.e("KDE/LanLinkProvider", "Handshake failed with " + identityPackage.getString("deviceName"));
future.cause().printStackTrace();
if (future.cause() instanceof SSLHandshakeException) {
BackgroundService.RunCommand(context, new BackgroundService.InstanceCallback() {
@Override
public void onServiceStart(BackgroundService service) {
Device device = service.getDevice(identityPackage.getString("deviceId"));
if (device == null) return;
device.unpair();
}
});
}
}
ChannelFuture future2 = channel.writeAndFlush(np2.serialize()).sync();
if (!future2.isSuccess()) {
Log.e("KDE/LanLinkProvider", "Connection failed: could not send identity package back");
return;
}
// If ssl handler is in channel, add link after handshake is completed
final SslHandler sslHandler = channel.pipeline().get(SslHandler.class);
if (sslHandler != null) {
sslHandler.handshakeFuture().addListener(new GenericFutureListener<Future<? super Channel>>() {
@Override
public void operationComplete(Future<? super Channel> future) throws Exception {
if (future.isSuccess()) {
try {
Log.i("KDE/LanLinkProvider", "Handshake successfully completed with " + identityPackage.getString("deviceName") + ", session secured with " + sslHandler.engine().getSession().getCipherSuite());
Certificate certificate = sslHandler.engine().getSession().getPeerCertificates()[0];
identityPackage.set("certificate", Base64.encodeToString(certificate.getEncoded(), 0));
addLink(identityPackage, channel, connectionStarted, true);
} catch (Exception e){
e.printStackTrace();
}
});
} else {
addLink(identityPackage, link);
} else {
// Unpair if handshake failed
// Any exception or handshake exception ?
Log.e("KDE/LanLinkProvider", "Handshake failed with " + identityPackage.getString("deviceName"));
future.cause().printStackTrace();
if (future.cause() instanceof SSLHandshakeException) {
BackgroundService.RunCommand(context, new BackgroundService.InstanceCallback() {
@Override
public void onServiceStart(BackgroundService service) {
Device device = service.getDevice(identityPackage.getString("deviceId"));
if (device == null) return;
device.unpair();
}
});
}
}
}
}
@Override
protected void onFailure(Throwable e) {
Log.e("KDE/LanLinkProvider", "Connection failed: could not send identity package back");
}
});
});
} else {
addLink(identityPackage, channel, connectionStarted, false);
}
}
});
@@ -369,28 +359,26 @@ public class LanLinkProvider extends BaseLinkProvider {
}
}
private void addLink(NetworkPackage identityPackage, LanLink link) {
private void addLink(NetworkPackage identityPackage, Channel channel, LanLink.ConnectionStarted connectionOrigin, boolean useSsl) {
String deviceId = identityPackage.getString("deviceId");
Log.i("KDE/LanLinkProvider","addLink to "+deviceId);
LanLink oldLink = visibleComputers.get(deviceId);
if (oldLink == link) {
Log.e("KDE/LanLinkProvider", "oldLink == link. This should not happen!");
LanLink currentLink = visibleComputers.get(deviceId);
if (currentLink != null) {
Log.e("KDE/LanLinkProvider", "Reusing same link for device " + deviceId);
Channel oldChannel = currentLink.reset(channel, connectionOrigin, useSsl);
nioLinks.remove(oldChannel.hashCode());
nioLinks.put(channel.hashCode(), currentLink);
return;
}
//Let's create the link
LanLink link = new LanLink(context, deviceId, this, channel, connectionOrigin, useSsl);
nioLinks.put(channel.hashCode(), link);
visibleComputers.put(deviceId, link);
connectionAccepted(identityPackage, link);
if (oldLink != null) {
if (link.getStartTime() < oldLink.getStartTime()) {
// New link is not so new, it just took more time to be establish successfully and get here
link.closeSocket();
connectionLost(link);
} else {
Log.i("KDE/LanLinkProvider", "Removing old connection to same device");
oldLink.closeSocket();
connectionLost(oldLink);
}
}
}
public LanLinkProvider(Context context) {

View File

@@ -35,7 +35,7 @@ import java.util.ArrayList;
public class LoopbackLink extends BaseLink {
public LoopbackLink(Context context, BaseLinkProvider linkProvider) {
super(context, "loopback", linkProvider, ConnectionStarted.Remotely);
super(context, "loopback", linkProvider);
}
@Override

View File

@@ -163,7 +163,7 @@ public class BackgroundService extends Service {
private void cleanDevices() {
for(Device d : devices.values()) {
if (!d.isPaired() && !d.isPairRequested() && !d.isPairRequestedByPeer() && d.getConnectionSource() == BaseLink.ConnectionStarted.Remotely) {
if (!d.isPaired() && !d.isPairRequested() && !d.isPairRequestedByPeer() && !d.deviceShouldBeKeptAlive()) {
d.disconnect();
}
}
@@ -184,7 +184,7 @@ public class BackgroundService extends Service {
Log.i("KDE/BackgroundService", "addLink,unknown device: " + deviceId);
device = new Device(BackgroundService.this, identityPackage, link);
if (device.isPaired() || device.isPairRequested() || device.isPairRequestedByPeer()
|| link.getConnectionSource() == BaseLink.ConnectionStarted.Locally
|| link.linkShouldBeKeptAlive()
||!discoveryModeAcquisitions.isEmpty() )
{
devices.put(deviceId, device);

View File

@@ -874,13 +874,13 @@ public class Device implements BaseLink.PackageReceiver {
}
}
public BaseLink.ConnectionStarted getConnectionSource() {
public boolean deviceShouldBeKeptAlive() {
for(BaseLink l : links) {
if (l.getConnectionSource() == BaseLink.ConnectionStarted.Locally) {
return BaseLink.ConnectionStarted.Locally;
if (l.linkShouldBeKeptAlive()) {
return true;
}
}
return BaseLink.ConnectionStarted.Remotely;
return false;
}
}