Commit 720914dd authored by Matthijs Tijink's avatar Matthijs Tijink

Use connection multiplexer in bluetooth link provider

parent bfd8ea92
......@@ -21,6 +21,7 @@
package org.kde.kdeconnect.Backends.BluetoothBackend;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
......@@ -43,7 +44,10 @@ import java.nio.charset.Charset;
import java.util.UUID;
public class BluetoothLink extends BaseLink {
private final BluetoothSocket socket;
private final ConnectionMultiplexer connection;
private final InputStream input;
private final OutputStream output;
private final BluetoothDevice remoteAddress;
private final BluetoothLinkProvider linkProvider;
private boolean continueAccepting = true;
......@@ -53,7 +57,7 @@ public class BluetoothLink extends BaseLink {
public void run() {
StringBuilder sb = new StringBuilder();
try {
Reader reader = new InputStreamReader(socket.getInputStream(), "UTF-8");
Reader reader = new InputStreamReader(input, "UTF-8");
char[] buf = new char[512];
while (continueAccepting) {
while (sb.indexOf("\n") == -1 && continueAccepting) {
......@@ -61,7 +65,12 @@ public class BluetoothLink extends BaseLink {
if ((charsRead = reader.read(buf)) > 0) {
sb.append(buf, 0, charsRead);
}
if (charsRead < 0) {
disconnect();
return;
}
}
if (!continueAccepting) break;
int endIndex = sb.indexOf("\n");
if (endIndex != -1) {
......@@ -71,7 +80,7 @@ public class BluetoothLink extends BaseLink {
}
}
} catch (IOException e) {
Log.e("BluetoothLink/receiving", "Connection to " + socket.getRemoteDevice().getAddress() + " likely broken.", e);
Log.e("BluetoothLink/receiving", "Connection to " + remoteAddress.getAddress() + " likely broken.", e);
disconnect();
}
}
......@@ -86,19 +95,11 @@ public class BluetoothLink extends BaseLink {
}
if (np.hasPayloadTransferInfo()) {
BluetoothSocket transferSocket = null;
try {
UUID transferUuid = UUID.fromString(np.getPayloadTransferInfo().getString("uuid"));
transferSocket = socket.getRemoteDevice().createRfcommSocketToServiceRecord(transferUuid);
transferSocket.connect();
np.setPayload(new NetworkPacket.Payload(transferSocket.getInputStream(), np.getPayloadSize()));
InputStream payloadInputStream = connection.getChannelInputStream(transferUuid);
np.setPayload(new NetworkPacket.Payload(payloadInputStream, np.getPayloadSize()));
} catch (Exception e) {
if (transferSocket != null) {
try {
transferSocket.close();
} catch (IOException ignored) {
}
}
Log.e("BluetoothLink/receiving", "Unable to get payload", e);
}
}
......@@ -107,9 +108,12 @@ public class BluetoothLink extends BaseLink {
}
});
public BluetoothLink(Context context, BluetoothSocket socket, String deviceId, BluetoothLinkProvider linkProvider) {
public BluetoothLink(Context context, ConnectionMultiplexer connection, InputStream input, OutputStream output, BluetoothDevice remoteAddress, String deviceId, BluetoothLinkProvider linkProvider) {
super(context, deviceId, linkProvider);
this.socket = socket;
this.connection = connection;
this.input = input;
this.output = output;
this.remoteAddress = remoteAddress;
this.linkProvider = linkProvider;
}
......@@ -128,22 +132,21 @@ public class BluetoothLink extends BaseLink {
}
public void disconnect() {
if (socket == null) {
if (connection == null) {
return;
}
continueAccepting = false;
try {
socket.close();
connection.close();
} catch (IOException ignored) {
}
linkProvider.disconnectedLink(this, getDeviceId(), socket);
linkProvider.disconnectedLink(this, getDeviceId(), remoteAddress);
}
private void sendMessage(NetworkPacket np) throws JSONException, IOException {
byte[] message = np.serialize().getBytes(Charset.forName("UTF-8"));
OutputStream socket = this.socket.getOutputStream();
Log.i("BluetoothLink", "Beginning to send message");
socket.write(message);
output.write(message);
Log.i("BluetoothLink", "Finished sending message");
}
......@@ -157,11 +160,9 @@ public class BluetoothLink extends BaseLink {
}*/
try {
BluetoothServerSocket serverSocket = null;
UUID transferUuid = null;
if (np.hasPayload()) {
UUID transferUuid = UUID.randomUUID();
serverSocket = BluetoothAdapter.getDefaultAdapter()
.listenUsingRfcommWithServiceRecord("KDE Connect Transfer", transferUuid);
transferUuid = connection.newChannel();
JSONObject payloadTransferInfo = new JSONObject();
payloadTransferInfo.put("uuid", transferUuid.toString());
np.setPayloadTransferInfo(payloadTransferInfo);
......@@ -169,28 +170,22 @@ public class BluetoothLink extends BaseLink {
sendMessage(np);
if (serverSocket != null) {
try (BluetoothSocket transferSocket = serverSocket.accept()) {
serverSocket.close();
if (transferUuid != null) {
try (OutputStream payloadStream = connection.getChannelOutputStream(transferUuid)) {
int BUFFER_LENGTH = 1024;
byte[] buffer = new byte[BUFFER_LENGTH];
int idealBufferLength = 4096;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
&& transferSocket.getMaxReceivePacketSize() > 0) {
idealBufferLength = transferSocket.getMaxReceivePacketSize();
}
byte[] buffer = new byte[idealBufferLength];
int bytesRead;
long progress = 0;
InputStream stream = np.getPayload().getInputStream();
while ((bytesRead = stream.read(buffer)) != -1) {
progress += bytesRead;
transferSocket.getOutputStream().write(buffer, 0, bytesRead);
payloadStream.write(buffer, 0, bytesRead);
if (np.getPayloadSize() > 0) {
callback.onProgressChanged((int) (100 * progress / np.getPayloadSize()));
}
}
transferSocket.getOutputStream().flush();
stream.close();
payloadStream.flush();
} catch (Exception e) {
callback.onFailure(e);
return false;
......
......@@ -38,6 +38,7 @@ import org.kde.kdeconnect.Device;
import org.kde.kdeconnect.NetworkPacket;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
......@@ -132,8 +133,8 @@ public class BluetoothLinkProvider extends BaseLinkProvider {
return "BluetoothLinkProvider";
}
public void disconnectedLink(BluetoothLink link, String deviceId, BluetoothSocket socket) {
sockets.remove(socket.getRemoteDevice());
public void disconnectedLink(BluetoothLink link, String deviceId, BluetoothDevice remoteAddress) {
sockets.remove(remoteAddress);
visibleComputers.remove(deviceId);
connectionLost(link);
}
......@@ -164,57 +165,75 @@ public class BluetoothLinkProvider extends BaseLinkProvider {
return;
}
if (continueProcessing) {
while (continueProcessing) {
try {
BluetoothSocket socket = serverSocket.accept();
connect(socket);
} catch (Exception ignored) {
} catch (Exception e) {
Log.e("BTLinkProvider/Server", "Bluetooth error", e);
}
}
}
private void connect(BluetoothSocket socket) throws Exception {
//socket.connect();
OutputStream outputStream = socket.getOutputStream();
if (sockets.containsKey(socket.getRemoteDevice())) {
Log.i("BTLinkProvider/Server", "Received duplicate connection from " + socket.getRemoteDevice().getAddress());
socket.close();
return;
} else {
sockets.put(socket.getRemoteDevice(), socket);
synchronized (sockets) {
if (sockets.containsKey(socket.getRemoteDevice())) {
Log.i("BTLinkProvider/Server", "Received duplicate connection from " + socket.getRemoteDevice().getAddress());
socket.close();
return;
} else {
sockets.put(socket.getRemoteDevice(), socket);
}
}
Log.i("BTLinkProvider/Server", "Received connection from " + socket.getRemoteDevice().getAddress());
ConnectionMultiplexer connection = null;
try {
Log.i("BTLinkProvider/Server", "Received connection from " + socket.getRemoteDevice().getAddress());
NetworkPacket np = NetworkPacket.createIdentityPacket(context);
byte[] message = np.serialize().getBytes("UTF-8");
outputStream.write(message);
//Delay to let bluetooth initialize stuff correctly
Thread.sleep(500);
Log.i("BTLinkProvider/Server", "Sent identity package");
connection = new ConnectionMultiplexer(socket);
OutputStream outputStream = connection.getDefaultOutputStream();
InputStream inputStream = connection.getDefaultInputStream();
// Listen for the response
StringBuilder sb = new StringBuilder();
Reader reader = new InputStreamReader(socket.getInputStream(), "UTF-8");
int charsRead;
char[] buf = new char[512];
while (sb.lastIndexOf("\n") == -1 && (charsRead = reader.read(buf)) != -1) {
sb.append(buf, 0, charsRead);
}
NetworkPacket np = NetworkPacket.createIdentityPacket(context);
byte[] message = np.serialize().getBytes("UTF-8");
outputStream.write(message);
outputStream.flush();
String response = sb.toString();
final NetworkPacket identityPacket = NetworkPacket.unserialize(response);
Log.i("BTLinkProvider/Server", "Sent identity package");
if (!identityPacket.getType().equals(NetworkPacket.PACKET_TYPE_IDENTITY)) {
Log.e("BTLinkProvider/Server", "2 Expecting an identity package");
return;
}
// Listen for the response
StringBuilder sb = new StringBuilder();
Reader reader = new InputStreamReader(inputStream, "UTF-8");
int charsRead;
char[] buf = new char[512];
while (sb.lastIndexOf("\n") == -1 && (charsRead = reader.read(buf)) != -1) {
sb.append(buf, 0, charsRead);
}
Log.i("BTLinkProvider/Server", "Received identity package");
String response = sb.toString();
final NetworkPacket identityPacket = NetworkPacket.unserialize(response);
BluetoothLink link = new BluetoothLink(context, socket,
identityPacket.getString("deviceId"), BluetoothLinkProvider.this);
if (!identityPacket.getType().equals(NetworkPacket.PACKET_TYPE_IDENTITY)) {
Log.e("BTLinkProvider/Server", "2 Expecting an identity package");
return;
}
Log.i("BTLinkProvider/Server", "Received identity package");
addLink(identityPacket, link);
BluetoothLink link = new BluetoothLink(context, connection,
inputStream, outputStream, socket.getRemoteDevice(),
identityPacket.getString("deviceId"), BluetoothLinkProvider.this);
addLink(identityPacket, link);
} catch (Exception e) {
synchronized (sockets) {
sockets.remove(socket.getRemoteDevice());
if (connection != null) connection.close();
}
throw e;
}
}
}
......@@ -234,7 +253,7 @@ public class BluetoothLinkProvider extends BaseLinkProvider {
context.registerReceiver(this, filter);
}
while (continueProcessing) {
if (continueProcessing) {
connectToDevices();
try {
Thread.sleep(15000);
......@@ -328,9 +347,15 @@ public class BluetoothLinkProvider extends BaseLinkProvider {
Log.i("BTLinkProvider/Client", "Connected to " + device.getAddress());
try {
//Delay to let bluetooth initialize stuff correctly
Thread.sleep(500);
ConnectionMultiplexer connection = new ConnectionMultiplexer(socket);
OutputStream outputStream = connection.getDefaultOutputStream();
InputStream inputStream = connection.getDefaultInputStream();
int character;
StringBuilder sb = new StringBuilder();
while (sb.lastIndexOf("\n") == -1 && (character = socket.getInputStream().read()) != -1) {
while (sb.lastIndexOf("\n") == -1 && (character = inputStream.read()) != -1) {
sb.append((char) character);
}
......@@ -348,7 +373,7 @@ public class BluetoothLinkProvider extends BaseLinkProvider {
String myId = NetworkPacket.createIdentityPacket(context).getString("deviceId");
if (identityPacket.getString("deviceId").equals(myId)) {
// Probably won't happen, but just to be safe
socket.close();
connection.close();
return;
}
......@@ -358,8 +383,8 @@ public class BluetoothLinkProvider extends BaseLinkProvider {
Log.i("BTLinkProvider/Client", "Identity package received, creating link");
final BluetoothLink link = new BluetoothLink(context, socket,
identityPacket.getString("deviceId"), BluetoothLinkProvider.this);
final BluetoothLink link = new BluetoothLink(context, connection, inputStream, outputStream,
socket.getRemoteDevice(), identityPacket.getString("deviceId"), BluetoothLinkProvider.this);
NetworkPacket np2 = NetworkPacket.createIdentityPacket(context);
link.sendPacket(np2, new Device.SendPacketStatusCallback() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment