1 package com.example.imsmediatestingapp; 2 3 import android.content.SharedPreferences; 4 import android.util.Log; 5 6 import java.io.ByteArrayInputStream; 7 import java.io.IOException; 8 import java.io.ObjectInputStream; 9 import java.net.DatagramPacket; 10 import java.net.DatagramSocket; 11 12 /** 13 * The HandshakeReceiver handles and stores information about incoming packets 14 * during the 15 * handshake process. 16 */ 17 public class HandshakeReceiver implements Runnable { 18 19 private static final int MAX_UDP_DATAGRAM_LEN = 65527; 20 private final String HANDSHAKE_PORT_PREF = "HANDSHAKE_PORT_OPEN"; 21 private final String CONFIRMATION_MESSAGE = "CONNECTED"; 22 private static final String LOG_PREFIX = HandshakeReceiver.class.getName(); 23 private boolean running = true; 24 private boolean isConfirmationReceived = false; 25 private boolean isHandshakeReceived = false; 26 private DeviceInfo receivedDeviceInfo; 27 DatagramSocket socket = null; 28 SharedPreferences.Editor editor; 29 HandshakeReceiver(SharedPreferences preferences)30 public HandshakeReceiver(SharedPreferences preferences) { 31 editor = preferences.edit(); 32 } 33 run()34 public void run() { 35 DeviceInfo deviceInfo = null; 36 String confirmation = null; 37 byte[] buffer = new byte[MAX_UDP_DATAGRAM_LEN]; 38 DatagramPacket packet = new DatagramPacket(buffer, buffer.length); 39 40 try { 41 socket = new DatagramSocket(); 42 socket.setReuseAddress(true); 43 44 editor.putBoolean(HANDSHAKE_PORT_PREF, true).apply(); 45 46 while (running) { 47 socket.receive(packet); 48 Object dataReceived = deserializePacket(packet.getData()); 49 50 if (dataReceived instanceof DeviceInfo && !isHandshakeReceived) { 51 deviceInfo = (DeviceInfo) dataReceived; 52 if (verifyHandshakePacket(deviceInfo)) { 53 isHandshakeReceived = true; 54 receivedDeviceInfo = deviceInfo; 55 Log.d(LOG_PREFIX, "RECEIVED: Device Info"); 56 } 57 58 } else if (dataReceived instanceof String && !isConfirmationReceived) { 59 confirmation = (String) dataReceived; 60 if (verifyConfirmationPacket(confirmation)) { 61 isConfirmationReceived = true; 62 Log.d(LOG_PREFIX, "RECEIVED: Confirmation"); 63 running = false; 64 65 } 66 } 67 68 } 69 } catch (Throwable e) { 70 System.out.println(e.getLocalizedMessage()); 71 } 72 } 73 74 /** 75 * Reads the data into a ByteArrayInputStream and ObjectInputStream to determine 76 * the type of the data, then casts it to the correct type and returns it 77 * @param data byte array from the packet received from the DatagramSocket 78 * @param <T> either a String or DeviceInfo 79 * @return string value of hte conformation string, or the DeviceInfo 80 */ 81 @SuppressWarnings("TypeParameterUnusedInFormals") deserializePacket(byte[] data)82 private <T> T deserializePacket(byte[] data) { 83 DeviceInfo deviceInfo = null; 84 String confirmationMessage = null; 85 ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data); 86 try { 87 ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); 88 Object readObject = objectInputStream.readObject(); 89 if (readObject instanceof DeviceInfo) { 90 deviceInfo = (DeviceInfo) readObject; 91 return (T) deviceInfo; 92 93 } else if (readObject instanceof String) { 94 confirmationMessage = (String) readObject; 95 return (T) confirmationMessage; 96 } 97 98 } catch (IOException | ClassNotFoundException e) { 99 Log.e(LOG_PREFIX, "Exception: " + e.toString()); 100 Log.d(LOG_PREFIX, new String(data)); 101 return (T) new String(data); 102 } 103 return null; 104 } 105 getBoundSocket()106 public int getBoundSocket() { 107 return socket.getLocalPort(); 108 } 109 close()110 public void close() { 111 Log.d("", "Closing the socket on port: " + socket.getLocalPort()); 112 running = false; 113 socket.close(); 114 editor.putBoolean(HANDSHAKE_PORT_PREF, false).apply(); 115 } 116 117 /** 118 * Verifies that the incoming DeviceInfo has all valid port numbers. 119 * @param deviceInfo device info to verify 120 * @return boolean if the DeviceInfo has all the right info 121 */ verifyHandshakePacket(DeviceInfo deviceInfo)122 private boolean verifyHandshakePacket(DeviceInfo deviceInfo) { 123 if (deviceInfo.getHandshakePort() == -1 || deviceInfo.getAudioRtpPort() == -1) { 124 Log.d(LOG_PREFIX, 125 "One or more of the ports sent in the handshake have not been opened."); 126 return false; 127 } 128 129 return true; 130 } 131 verifyConfirmationPacket(String confirmation)132 private boolean verifyConfirmationPacket(String confirmation) { 133 return confirmation.equals(CONFIRMATION_MESSAGE); 134 } 135 isConfirmationReceived()136 public boolean isConfirmationReceived() { 137 return isConfirmationReceived; 138 } 139 isHandshakeReceived()140 public boolean isHandshakeReceived() { 141 return isHandshakeReceived; 142 } 143 getReceivedDeviceInfo()144 public DeviceInfo getReceivedDeviceInfo() { 145 return receivedDeviceInfo; 146 } 147 } 148