diff --git a/testapp/build.gradle b/testapp/build.gradle index 4470e2770e73416522b78db99d354bbe89978174..366a76733bf10dbb66571cfc28f42bf18104eb70 100644 --- a/testapp/build.gradle +++ b/testapp/build.gradle @@ -47,7 +47,7 @@ android { } dependencies { - implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation fileTree(include: ['*.jar'], dir: '../ebclibrary/libs') androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) diff --git a/testapp/libs/protobuf-java-3.4.1.jar b/testapp/libs/protobuf-java-3.4.1.jar deleted file mode 100644 index d8ea87e4b687af4c85b061b0410167b364688c73..0000000000000000000000000000000000000000 Binary files a/testapp/libs/protobuf-java-3.4.1.jar and /dev/null differ diff --git a/testapp/src/main/java/org/mpisws/testapp/MainActivity.java b/testapp/src/main/java/org/mpisws/testapp/MainActivity.java index 65bf8228df8835958a4d475da84d871eef2b61d8..97ed39f2cbd1b54cf035784a95784a3bca3706f6 100644 --- a/testapp/src/main/java/org/mpisws/testapp/MainActivity.java +++ b/testapp/src/main/java/org/mpisws/testapp/MainActivity.java @@ -24,7 +24,9 @@ import org.mpisws.messaging.ReceivedMessageWrapper; import org.mpisws.testapp.googleauth.GoogleNativeAuthenticator; import org.mpisws.testapp.googleauth.GoogleToken; import org.mpisws.testapp.simulator.SimulationClient; +import org.mpisws.testapp.simulator.SimulationClientBT; import org.mpisws.testapp.simulator.SimulationServer; +import org.mpisws.testapp.simulator.SimulationServerBT; import java.util.List; @@ -54,7 +56,6 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe findViewById(R.id.signIn).setOnClickListener(this); findViewById(R.id.signOut).setOnClickListener(this); findViewById(R.id.deleteAccount).setOnClickListener(this); - findViewById(R.id.testESFunctions).setOnClickListener(this); findViewById(R.id.testSendMessages).setOnClickListener(this); findViewById(R.id.testReceiveMessages).setOnClickListener(this); findViewById(R.id.simulateEncounterFormationAndConfirmationClient).setOnClickListener(this); @@ -95,11 +96,12 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe /***************************** ES AND SDDR TESTS **********************/ case R.id.simulateEncounterFormationAndConfirmationClient: if (!isSignedIn()) throw new SecurityException("Not signed in"); - new SimulationClient(this).sendDataToSimulationServerAndStartCore(); + new SimulationClientBT(this).startClient(); break; case R.id.simulateEncounterFormationAndConfirmationServer: if (!isSignedIn()) throw new SecurityException("Not signed in"); - new SimulationServer(this).startServer(); + Log.d(TAG, "Starting simulation server!"); + new SimulationServerBT(this).startServer(); break; case R.id.testSendMessages: ebc.getSDDRClient().updateDatabaseOnAgent(); diff --git a/testapp/src/main/java/org/mpisws/testapp/simulator/SimulationClient.java b/testapp/src/main/java/org/mpisws/testapp/simulator/SimulationClient.java index e18d408f6e669fed775fb0fd99c0d3df837bf9b4..400ad3c6b351407c96a3b35dbeeaaa07619bc631 100644 --- a/testapp/src/main/java/org/mpisws/testapp/simulator/SimulationClient.java +++ b/testapp/src/main/java/org/mpisws/testapp/simulator/SimulationClient.java @@ -35,8 +35,8 @@ public class SimulationClient { protected static List mSharedSecrets = new ArrayList<>(NUM_SIMULATED_DEVICES*NUM_SIMULATED_EPOCHS); protected static int CURRENT_EPOCH = 0; - static private String mServiceName = "EbCSimulator"; - static private String mServiceType = "_ebcsimulator._tcp"; + static protected String mServiceName = "EbCSimulation"; + static protected String mServiceType = "_http._tcp"; private NsdManager.DiscoveryListener mDiscoveryListener; private NsdManager mNsdManager; @@ -99,7 +99,7 @@ public class SimulationClient { // Service type is the string containing the protocol and // transport layer for this service. Log.d(TAG, "Unknown Service Type: " + service.getServiceType()); - } else if (service.getServiceName().contains("EbCSimulator")){ + } else if (service.getServiceName().contains(mServiceName)){ mNsdManager.resolveService(service, mResolveListener); } } diff --git a/testapp/src/main/java/org/mpisws/testapp/simulator/SimulationClientBT.java b/testapp/src/main/java/org/mpisws/testapp/simulator/SimulationClientBT.java new file mode 100644 index 0000000000000000000000000000000000000000..37dfa76012893035a1d5c540491f1c91ced228a0 --- /dev/null +++ b/testapp/src/main/java/org/mpisws/testapp/simulator/SimulationClientBT.java @@ -0,0 +1,163 @@ +package org.mpisws.testapp.simulator; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothSocket; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.util.Log; + +import org.mpisws.encounters.encounterformation.SDDR_Native; +import org.mpisws.helpers.Identifier; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.util.List; +import java.util.UUID; + +import static org.mpisws.testapp.simulator.SimulationClient.NUM_SIMULATED_DEVICES; +import static org.mpisws.testapp.simulator.SimulationClient.NUM_SIMULATED_EPOCHS; +import static org.mpisws.testapp.simulator.SimulationClient.mDHFullKeys; +import static org.mpisws.testapp.simulator.SimulationClient.mDHNonces; +import static org.mpisws.testapp.simulator.SimulationClient.mDHPubKeys; +import static org.mpisws.testapp.simulator.SimulationClient.mSharedSecrets; +import static org.mpisws.testapp.simulator.SimulationClient.otherDHFullKeys; +import static org.mpisws.testapp.simulator.SimulationClient.otherDHNonces; +import static org.mpisws.testapp.simulator.SimulationClient.otherDHPubKeys; + +/** + * This class does all the work for setting up and managing Bluetooth + * connections with other devices. It has a thread that listens for + * incoming connections, a thread for connecting with a device, and a + * thread for performing data transmissions when connected. + */ +public class SimulationClientBT { + Context context; + private static final String TAG = SimulationClientBT.class.getSimpleName(); + private static final UUID MY_UUID = UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66"); + private final BluetoothAdapter mAdapter; + static private SimulatorEncounterFormationCore core; + + public SimulationClientBT(Context context) { + this.context = context; + mAdapter = BluetoothAdapter.getDefaultAdapter(); + IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); + context.registerReceiver(mReceiver, filter); + core = new SimulatorEncounterFormationCore(context); + initializeSimulatedAdverts(); + } + + public void startClient() { + mAdapter.cancelDiscovery(); + Log.d(TAG, "Starting discovery"); + mAdapter.startDiscovery(); + } + + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (BluetoothDevice.ACTION_FOUND.equals(action)) { + BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + Log.d(TAG, "Device found: " + device.getName() + "; MAC " + device.getAddress()); + if (device.getName() != null && device.getName().contains("Xperia")) { + connect(device); + context.unregisterReceiver(mReceiver); + mAdapter.cancelDiscovery(); + } + } + } + }; + + private void connect(BluetoothDevice device) { + new Thread( () -> { + BluetoothSocket sock; + try { + sock = device.createRfcommSocketToServiceRecord(MY_UUID); + sock.connect(); + Log.d(TAG, "Connected, sending DH keys over socket"); + sendDHKeysOverSocket(sock); + sock.close(); + } catch (IOException e) { + Log.d(TAG, "Exception: " + e); + } + }).start(); + } + + private void initializeSimulatedAdverts() { + for (int i = 0; i < NUM_SIMULATED_EPOCHS*NUM_SIMULATED_DEVICES; i++) { + SDDR_Native.c_changeEpoch(); + otherDHPubKeys.add(new Identifier(SDDR_Native.c_getAdvertDHPubKey())); + otherDHFullKeys.add(new Identifier(SDDR_Native.c_getAdvertDHKey())); + otherDHNonces.add(new Identifier(SDDR_Native.c_getMyAdvert())); + } + for (int i = 0; i < NUM_SIMULATED_EPOCHS; i++) { + SDDR_Native.c_changeEpoch(); + mDHPubKeys.add(new Identifier(SDDR_Native.c_getAdvertDHPubKey())); + mDHFullKeys.add(new Identifier(SDDR_Native.c_getAdvertDHKey())); + mDHNonces.add(new Identifier(SDDR_Native.c_getMyAdvert())); + + for (int j = 0; j < NUM_SIMULATED_DEVICES; j++) { + Identifier sharedSecret = new Identifier(SDDR_Native.c_computeSecretKeyWithSHA( + otherDHFullKeys.get(j+(NUM_SIMULATED_DEVICES*i)).getBytes(), + mDHNonces.get(i).getBytes(), + mDHPubKeys.get(i).getBytes())); + mSharedSecrets.add(sharedSecret); + } + } + } + + private void sendDHKeysOverSocket(BluetoothSocket sock) { + try { + if (sock == null) return; + + String serializedSecrets; + String serializedNonces; + String serializedPubKeys; + + // serialize + OutputStream os = sock.getOutputStream(); + try { + serializedSecrets = serializeList(mSharedSecrets); + serializedNonces = serializeList(otherDHNonces); + serializedPubKeys = serializeList(otherDHPubKeys); + } catch (Exception e) { + System.out.println(e); + return; + } + + PrintWriter pw = new PrintWriter(os, true); + pw.println(serializedSecrets + serializedNonces + serializedPubKeys + "\r\n"); + Log.d(TAG, "Lengths: " + serializedSecrets.length() + ", " + serializedNonces.length() + "," + serializedPubKeys.length()); + Log.d(TAG, "Sent data over socket!"); + + BufferedReader in = new BufferedReader(new InputStreamReader(sock.getInputStream())); + String line = in.readLine(); + Log.d(TAG, "Got response: " + line); + + in.close(); + pw.close(); + sock.close(); + } catch (IOException e) { + e.printStackTrace(); + } + // run the simulator core + Log.d(TAG, "Running simulator core!"); + new Thread(core).start(); + } + + private String serializeList(List list) throws IOException { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + ObjectOutputStream so = new ObjectOutputStream(bo); + so.writeObject(mSharedSecrets); + so.flush(); + Log.d(TAG, "Serialized string to " + bo.toString()); + return bo.toString(); + } +} diff --git a/testapp/src/main/java/org/mpisws/testapp/simulator/SimulationServer.java b/testapp/src/main/java/org/mpisws/testapp/simulator/SimulationServer.java index a0047c452deb30a0303b5250b019c5837241384b..b6790663fcd35ff9fc95a0f8de5393ed377f89e2 100644 --- a/testapp/src/main/java/org/mpisws/testapp/simulator/SimulationServer.java +++ b/testapp/src/main/java/org/mpisws/testapp/simulator/SimulationServer.java @@ -29,12 +29,12 @@ import static org.mpisws.encounters.EncounterBasedCommunication.CHANGE_EPOCH_TIM import static org.mpisws.helpers.Utils.SHA1; import static org.mpisws.testapp.simulator.SimulationClient.NUM_SIMULATED_DEVICES; import static org.mpisws.testapp.simulator.SimulationClient.NUM_SIMULATED_EPOCHS; +import static org.mpisws.testapp.simulator.SimulationClient.mServiceName; +import static org.mpisws.testapp.simulator.SimulationClient.mServiceType; public class SimulationServer { private static final String TAG = SimulationServer.class.getSimpleName(); static private int port; - static private String mServiceName = "EbCSimulator"; - static private String mServiceType = "_ebcsimulator._tcp"; private int currentEpoch = 0; private ServerSocket mServerSocket; @@ -53,37 +53,13 @@ public class SimulationServer { // Initialize a server socket on the next available port. try { mServerSocket = new ServerSocket(0); - - // Store the chosen port. - port = mServerSocket.getLocalPort(); - registerService(port); - - Socket sock = mServerSocket.accept(); - BufferedReader in = new BufferedReader(new InputStreamReader(sock.getInputStream())); - List lines = new ArrayList<>(); - String line; - while ((line = in.readLine()) != null) { - lines.add(line); - } - - PrintStream output = new PrintStream(sock.getOutputStream()); - output.println("Finished"); - - Utils.myAssert(lines.size() == 3); - sharedSecrets = deserializeIDList(lines.get(0)); - nonces = deserializeIDList(lines.get(1)); - pubKeys = deserializeIDList(lines.get(2)); - if (sharedSecrets == null || nonces == null || pubKeys == null) { - return; - } - output.close(); - in.close(); - sock.close(); - - processData(); - } catch (ClassNotFoundException | IOException e) { + } catch (IOException e) { e.printStackTrace(); } + // Store the chosen port. + port = mServerSocket.getLocalPort(); + Log.d(TAG, "Simulation Server opened on port " + port); + registerService(port); }).start(); } @@ -150,12 +126,13 @@ public class SimulationServer { serviceInfo.setPort(port); initializeRegistrationListener(); + Log.d(TAG, "Registering service"); mNsdManager.registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener); } private void initializeRegistrationListener() { + Log.d(TAG, "Initializing registration listener"); mRegistrationListener = new NsdManager.RegistrationListener() { - @Override public void onServiceRegistered(NsdServiceInfo NsdServiceInfo) { // Save the service name. Android may have changed it in order to @@ -163,6 +140,36 @@ public class SimulationServer { // with the name Android actually used. mServiceName = NsdServiceInfo.getServiceName(); Log.d(TAG, "Registration success " + mServiceName); + + try { + Socket sock = mServerSocket.accept(); + Log.d(TAG, "Accepted sock connection"); + BufferedReader in = new BufferedReader(new InputStreamReader(sock.getInputStream())); + List lines = new ArrayList<>(); + String line; + while ((line = in.readLine()) != null) { + lines.add(line); + } + + PrintStream output = new PrintStream(sock.getOutputStream()); + output.println("Finished"); + + Utils.myAssert(lines.size() == 3); + sharedSecrets = deserializeIDList(lines.get(0)); + nonces = deserializeIDList(lines.get(1)); + pubKeys = deserializeIDList(lines.get(2)); + if (sharedSecrets == null || nonces == null || pubKeys == null) { + return; + } + output.close(); + in.close(); + sock.close(); + + mNsdManager.unregisterService(this); + processData(); + } catch (ClassNotFoundException | IOException e) { + e.printStackTrace(); + } } @Override @@ -172,13 +179,14 @@ public class SimulationServer { @Override public void onServiceUnregistered(NsdServiceInfo arg0) { + Log.d(TAG, "Registration listener unregistered"); // Service has been unregistered. This only happens when you call // NsdManager.unregisterService() and pass in this listener. } @Override public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) { - // Unregistration failed. Put debugging code here to determine why. + Log.d(TAG, "UnRegistration listener failed " + errorCode); } }; } diff --git a/testapp/src/main/java/org/mpisws/testapp/simulator/SimulationServerBT.java b/testapp/src/main/java/org/mpisws/testapp/simulator/SimulationServerBT.java new file mode 100644 index 0000000000000000000000000000000000000000..17375a59f400758c5bd049ccad71684ad10fc64d --- /dev/null +++ b/testapp/src/main/java/org/mpisws/testapp/simulator/SimulationServerBT.java @@ -0,0 +1,165 @@ +package org.mpisws.testapp.simulator; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothServerSocket; +import android.bluetooth.BluetoothSocket; +import android.content.Context; +import android.content.Intent; +import android.os.Handler; +import android.util.Log; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; +import org.mpisws.embeddedsocial.ESClient; +import org.mpisws.embeddedsocial.ESMessage; +import org.mpisws.helpers.Identifier; +import org.mpisws.helpers.Utils; +import org.mpisws.messaging.EpochLinkMessage; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.ObjectInputStream; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import static org.mpisws.encounters.EncounterBasedCommunication.CHANGE_EPOCH_TIME; +import static org.mpisws.helpers.Utils.SHA1; +import static org.mpisws.testapp.simulator.SimulationClient.NUM_SIMULATED_DEVICES; +import static org.mpisws.testapp.simulator.SimulationClient.NUM_SIMULATED_EPOCHS; + +/** + * This class does all the work for setting up and managing Bluetooth + * connections with other devices. It has a thread that listens for + * incoming connections, a thread for connecting with a device, and a + * thread for performing data transmissions when connected. + */ +public class SimulationServerBT { + private static final String TAG = SimulationServerBT.class.getSimpleName(); + private static final String NAME = "SimulationServerBT"; + private static final UUID MY_UUID = UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66"); + private final BluetoothAdapter mAdapter; + private Context context; + + private int currentEpoch = 0; + private List nonces; + private List sharedSecrets; + private List pubKeys; + + /** + */ + public SimulationServerBT(Context context) { + mAdapter = BluetoothAdapter.getDefaultAdapter(); + this.context = context; + } + + public void startServer() { + Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); + discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300); + context.startActivity(discoverableIntent); + + new Thread( () -> { + Log.d(TAG, "start"); + BluetoothSocket socket; + // Create a new listening server socket + try { + BluetoothServerSocket serversocket = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID); + Log.d(TAG, "accepting"); + socket = serversocket.accept(); + Log.d(TAG, "accepted"); + serversocket.close(); + // If a connection was accepted + if (socket != null) { + DataInputStream in = new DataInputStream(socket.getInputStream()); + byte[] messageByte = new byte[1000]; + boolean end = false; + String dataString = ""; + + while(true) + { + int bytesRead = in.read(messageByte); + dataString += new String(messageByte, 0, bytesRead); + Log.d(TAG, dataString); + if (dataString.contains(java.util.regex.Pattern.quote("\r\n"))) { + break; + } + } + dataString.substring(0, dataString.indexOf(java.util.regex.Pattern.quote("\r\n"))); + sharedSecrets = deserializeIDList(dataString.substring(0, dataString.length()/3)); + nonces = deserializeIDList(dataString.substring(dataString.length()/3, 2*dataString.length()/3)); + pubKeys = deserializeIDList(dataString.substring(2*dataString.length()/3)); + if (sharedSecrets == null || nonces == null || pubKeys == null) { + return; + } + PrintWriter pw = new PrintWriter(socket.getOutputStream(), true); + pw.println("Finished"); + + pw.close(); + in.close(); + socket.close(); + processData(); + } else { + Log.d(TAG, "Socket was null"); + } + } catch (IOException | ClassNotFoundException e) { + Log.e(TAG, "IO exception trying to accept and read " + e.getMessage()); + } + }).start(); + } + + private List deserializeIDList(String serializedObject) throws IOException, ClassNotFoundException { + byte b[] = serializedObject.getBytes(); + ByteArrayInputStream bi = new ByteArrayInputStream(b); + ObjectInputStream si = new ObjectInputStream(bi); + List obj = (List) si.readObject(); + return obj; + } + private void processData() { + // Create all topics you'll ever have to create + List> topicsToCreate = new ArrayList<>(); + for (int i=0; i < nonces.size(); i++) { + topicsToCreate.add(new ImmutablePair<>(nonces.get(i), pubKeys.get(i))); + } + for (Identifier ss : sharedSecrets) { + topicsToCreate.add(new ImmutablePair<>(ss, ss)); + } + Log.d(TAG, "Creating topics: " + topicsToCreate.size()); + ESClient.getInstance().createTopics(topicsToCreate); + + // Every "epoch" or so try to post link messages to the prior "epoch" ss for each "device" + // Let's try and post to the prior 3 epochs + new Handler().postDelayed(() -> { + int lowEpoch = currentEpoch > 3 ? currentEpoch - 3 : 0; + List sses = sharedSecrets.subList(lowEpoch*NUM_SIMULATED_DEVICES, currentEpoch*NUM_SIMULATED_DEVICES); + List topicHandles = ESClient.getInstance().getTopicHandles(sses); + + List msgsToSend = new ArrayList<>(); + for (int i = 0; i < NUM_SIMULATED_DEVICES; i++) { + for (int j = currentEpoch+1; j > lowEpoch+1; j--) { + int oldIndex = (j-1-lowEpoch)*NUM_SIMULATED_DEVICES + i; + int newIndex = (j-lowEpoch)*NUM_SIMULATED_DEVICES + i; + if (topicHandles.get(oldIndex) == null || topicHandles.get(oldIndex).compareTo("") == 0) { + continue; + } + EpochLinkMessage epochLinkMessage = new EpochLinkMessage.EpochLinkMessageBuilder() + .addOldNonce(nonces.get((lowEpoch*NUM_SIMULATED_DEVICES) + oldIndex).toString()) + .addNewNonce(nonces.get((lowEpoch*NUM_SIMULATED_DEVICES) + newIndex).toString()) + .build(); + msgsToSend.add(new ESMessage(epochLinkMessage.toSendMessageText(sses.get(oldIndex).getBytes()), + new Identifier(SHA1(sharedSecrets.get(i).getBytes())).toString(), + topicHandles.get(oldIndex), + true, null, true, -1)); + } + } + ESClient.getInstance().sendMsgs(msgsToSend); + currentEpoch++; + // heh hack + if (currentEpoch == NUM_SIMULATED_EPOCHS) currentEpoch--; + }, CHANGE_EPOCH_TIME); + } +} diff --git a/testapp/src/main/java/org/mpisws/testapp/simulator/SimulatorScannerProcessor.java b/testapp/src/main/java/org/mpisws/testapp/simulator/SimulatorScannerProcessor.java index fa4051fe74dd0c617cb394dc7fa38a7cc1d887a6..5fe32493170559685411f1cad4abc1155266b3e8 100644 --- a/testapp/src/main/java/org/mpisws/testapp/simulator/SimulatorScannerProcessor.java +++ b/testapp/src/main/java/org/mpisws/testapp/simulator/SimulatorScannerProcessor.java @@ -45,6 +45,7 @@ import java.util.LinkedList; import java.util.List; import static android.bluetooth.le.ScanSettings.SCAN_MODE_LOW_POWER; +import static org.mpisws.encounters.EncounterBasedCommunication.SCAN_BATCH_INTERVAL; import static org.mpisws.testapp.simulator.SimulationClient.CURRENT_EPOCH; import static org.mpisws.testapp.simulator.SimulationClient.NUM_SIMULATED_DEVICES; import static org.mpisws.testapp.simulator.SimulationClient.otherDHNonces; @@ -105,6 +106,7 @@ public class SimulatorScannerProcessor { private ScanSettings buildScanSettings() { ScanSettings.Builder builder = new ScanSettings.Builder(); builder.setScanMode(SCAN_MODE_LOW_POWER); + builder.setReportDelay(SCAN_BATCH_INTERVAL); return builder.build(); }