Finished the rewrite of mDNS

This commit is contained in:
Andrew Hennessy 2013-11-04 19:34:40 -05:00
parent 7038384d36
commit 82aa5730bd
2 changed files with 133 additions and 101 deletions

View File

@ -5,7 +5,7 @@ import java.util.Locale;
import java.util.UUID; import java.util.UUID;
public class NvComputer { public class NvComputer {
private String mDNSResponse; private String hostname;
private InetAddress ipAddress; private InetAddress ipAddress;
private String ipAddressString; private String ipAddressString;
private int state; private int state;
@ -14,15 +14,15 @@ public class NvComputer {
private String mac; private String mac;
private UUID uniqueID; private UUID uniqueID;
private int sessionID; private int sessionID;
private boolean paired; private boolean paired;
private boolean isBusy; private boolean isBusy;
public NvComputer(String hostname, InetAddress ipAddress, int state, int numOfApps, String gpuType, String mac, UUID uniqueID) {
public NvComputer(String mDNSResponse, InetAddress ipAddress, String ipAddressString, int state, int numOfApps, String gpuType, String mac, UUID uniqueID) { this.hostname = hostname;
this.mDNSResponse = mDNSResponse;
this.ipAddress = ipAddress; this.ipAddress = ipAddress;
this.ipAddressString = ipAddressString; this.ipAddressString = this.ipAddress.getHostAddress();
this.state = state; this.state = state;
this.numOfApps = numOfApps; this.numOfApps = numOfApps;
this.gpuType = gpuType; this.gpuType = gpuType;
@ -30,8 +30,8 @@ public class NvComputer {
this.uniqueID = uniqueID; this.uniqueID = uniqueID;
} }
public String getmDNSResponse() { public String getHostname() {
return this.mDNSResponse; return this.hostname;
} }
public InetAddress getIpAddress() { public InetAddress getIpAddress() {
@ -42,10 +42,6 @@ public class NvComputer {
return this.ipAddressString; return this.ipAddressString;
} }
public String getIPAddressString() {
return this.ipAddress.getCanonicalHostName().toLowerCase(Locale.getDefault());
}
public int getState() { public int getState() {
return this.state; return this.state;
} }
@ -97,8 +93,8 @@ public class NvComputer {
StringBuilder returnStringBuilder = new StringBuilder(); StringBuilder returnStringBuilder = new StringBuilder();
returnStringBuilder.append("NvComputer 0x"); returnStringBuilder.append("NvComputer 0x");
returnStringBuilder.append(Integer.toHexString(this.hashCode()).toUpperCase(Locale.getDefault())); returnStringBuilder.append(Integer.toHexString(this.hashCode()).toUpperCase(Locale.getDefault()));
returnStringBuilder.append("\n|- mDNS Hostname: "); returnStringBuilder.append("\n|- Hostname: ");
returnStringBuilder.append(this.mDNSResponse); returnStringBuilder.append(this.hostname);
returnStringBuilder.append("\n|- IP Address: "); returnStringBuilder.append("\n|- IP Address: ");
returnStringBuilder.append(this.ipAddress.toString()); returnStringBuilder.append(this.ipAddress.toString());
returnStringBuilder.append("\n|- Computer State: "); returnStringBuilder.append("\n|- Computer State: ");

View File

@ -33,7 +33,7 @@ public class NvmDNS extends AsyncTask<Void, Integer, Void> {
public static InetAddress MDNS_MULTICAST_ADDRESS; public static InetAddress MDNS_MULTICAST_ADDRESS;
public static final short MDNS_PORT = 5353; public static final short MDNS_PORT = 5353;
public static final int WAIT_MS = 5000; public static final int WAIT_MS = 100;
private HashSet<NvComputer> responses; private HashSet<NvComputer> responses;
private MulticastSocket socket; private MulticastSocket socket;
@ -90,7 +90,7 @@ public class NvmDNS extends AsyncTask<Void, Integer, Void> {
// Convert the message into Network Byte Order // Convert the message into Network Byte Order
byte[] wireQuery = query.toWire(); byte[] wireQuery = query.toWire();
Log.v("NvmDNS Query", query.toString()); Log.i("NvmDNS Query", query.toString());
// Convert our byte array into a Packet // Convert our byte array into a Packet
DatagramPacket transmitPacket = new DatagramPacket(wireQuery, wireQuery.length); DatagramPacket transmitPacket = new DatagramPacket(wireQuery, wireQuery.length);
@ -99,9 +99,9 @@ public class NvmDNS extends AsyncTask<Void, Integer, Void> {
// And (attempt) to send the packet // And (attempt) to send the packet
try { try {
Log.v("NvmDNS Query", "Blocking on this.nvstream_socket.send(transmitPacket)"); Log.d("NvmDNS Query", "Blocking on this.nvstream_socket.send(transmitPacket)");
this.socket.send(transmitPacket); this.socket.send(transmitPacket);
Log.v("NvmDNS Query", "Passed this.nvstream_socket.send(transmitPacket)"); Log.d("NvmDNS Query", "Passed this.nvstream_socket.send(transmitPacket)");
} catch (IOException e) { } catch (IOException e) {
Log.e("NvmDNS Query", "There was an error sending the DNS query."); Log.e("NvmDNS Query", "There was an error sending the DNS query.");
Log.e("NvmDNS Query", e.getMessage()); Log.e("NvmDNS Query", e.getMessage());
@ -124,6 +124,7 @@ public class NvmDNS extends AsyncTask<Void, Integer, Void> {
this.socket.receive(packet); this.socket.receive(packet);
Log.d("NvmDNS Response", "Blocking passed on this.nvstream_query_socket.recieve()"); Log.d("NvmDNS Response", "Blocking passed on this.nvstream_query_socket.recieve()");
message = new Message(packet.getData()); message = new Message(packet.getData());
this.parseRecord(message, packet.getAddress());
} catch (IOException e) { } catch (IOException e) {
if (this.socket.isClosed()) { if (this.socket.isClosed()) {
Log.e("NvmDNS Response", "The socket was closed on us. The timer must have been reached."); Log.e("NvmDNS Response", "The socket was closed on us. The timer must have been reached.");
@ -134,25 +135,31 @@ public class NvmDNS extends AsyncTask<Void, Integer, Void> {
continue; continue;
} }
} }
}
}
private void parseRecord(Message message, InetAddress address) {
// We really only care about the ADDITIONAL section (specifically the text records) // We really only care about the ADDITIONAL section (specifically the text records)
Record[] responses = message.getSectionArray(Section.ADDITIONAL); Record[] responses = message.getSectionArray(Section.ADDITIONAL);
// We only want to process records that actually have a length, have an ANSWER // We only want to process records that actually have a length, have an ANSWER
// section that has stuff in it and that the ANSWER to our query is what we sent // section that has stuff in it and that the ANSWER to our query is what we sent
if (responses.length != 0 && if (responses.length != 0 &&
message.getSectionArray(Section.ANSWER).length != 0 && message.getSectionArray(Section.ANSWER).length != 0 &&
message.getSectionArray(Section.ANSWER)[0].getName().toString().equals(NvmDNS.MDNS_QUERY)) { message.getSectionArray(Section.ANSWER)[0].getName().toString().equals(NvmDNS.MDNS_QUERY)) {
Log.v("NvmDNS Response", "Got a packet from " + packet.getAddress().getCanonicalHostName()); Log.v("NvmDNS Response", "Got a packet from " + address.getCanonicalHostName());
Log.v("NvmDNS Response", "Question: " + message.getSectionArray(Section.ANSWER)[0].getName().toString()); Log.v("NvmDNS Response", "Question: " + message.getSectionArray(Section.ANSWER)[0].getName().toString());
Log.v("NvmDNS Response", "Response: " + responses[0].getName().toString()); Log.v("NvmDNS Response", "Response: " + responses[0].getName().toString());
// The DNS library we are using does not use inferred generics :(
// TODO: The DNS entry we get is "XENITH._nvstream._tcp.local."
// And the .'s in there are not actually periods. Or something.
String hostname = responses[0].getName().toString();
// The records can be returned in any order, so we need to figure out which one is the TXTRecord
// We get three records back: A TXTRecord, a SRVRecord and an ARecord
TXTRecord txtRecord = null; TXTRecord txtRecord = null;
for (Record record : responses) { for (Record record : responses) {
Log.v("NvmDNS Response", "We recieved a DNS repsonse with a " + record.getClass().getName() + " record."); Log.v("NvmDNS Response", "We recieved a DNS repsonse with a " + record.getClass().getName() + " record.");
if (record instanceof TXTRecord) { if (record instanceof TXTRecord) {
@ -162,15 +169,21 @@ public class NvmDNS extends AsyncTask<Void, Integer, Void> {
if (txtRecord == null) { if (txtRecord == null) {
Log.e("NvmDNS Response", "We recieved a malformed DNS repsonse with no TXTRecord"); Log.e("NvmDNS Response", "We recieved a malformed DNS repsonse with no TXTRecord");
continue; return;
} }
this.parseTXTRecord(txtRecord, address, hostname);
}
}
private void parseTXTRecord(TXTRecord txtRecord, InetAddress address, String hostname) {
// The DNS library we are using does not use inferred generics :(
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
ArrayList<?> txtRecordStringList = new ArrayList<Object>(txtRecord.getStrings()); ArrayList<String> txtRecordStringList = new ArrayList<String>(txtRecord.getStrings());
if (txtRecordStringList.size() != 5) { if (txtRecordStringList.size() != 5) {
Log.e("NvmDNS Response", "We recieved a malformed DNS repsonse with the improper amount of TXTRecord Entries."); Log.e("NvmDNS Response", "We recieved a malformed DNS repsonse with the improper amount of TXTRecord Entries.");
continue; return;
} }
// The general format of the text records is: // The general format of the text records is:
@ -181,24 +194,49 @@ public class NvmDNS extends AsyncTask<Void, Integer, Void> {
// SERVICE_UNIQUEID={A Wild UUID Appeared!} // SERVICE_UNIQUEID={A Wild UUID Appeared!}
// Every single record I've seen so far has been in this format // Every single record I've seen so far has been in this format
try { try {
int serviceState = Integer.parseInt(txtRecordStringList.get(0).toString().split("=")[1]); int serviceState = Integer.parseInt(this.parseTXTRecordField(txtRecordStringList.get(0), "SERVICE_STATE"));
int numberOfApps = Integer.parseInt(txtRecordStringList.get(1).toString().split("=")[1]); int numberOfApps = Integer.parseInt(this.parseTXTRecordField(txtRecordStringList.get(1), "SERVICE_NUMOFAPPS"));
String gpuType = txtRecordStringList.get(2).toString().split("=")[1]; String gpuType = this.parseTXTRecordField(txtRecordStringList.get(2), "SERVICE_GPUTYPE");
String mac = txtRecordStringList.get(3).toString().split("=")[1]; String mac = this.parseTXTRecordField(txtRecordStringList.get(3), "SERVICE_MAC");
UUID uniqueID = UUID.fromString(txtRecordStringList.get(4).toString().split("=")[1]); UUID uniqueID = UUID.fromString(this.parseTXTRecordField(txtRecordStringList.get(4), "SERVICE_UNIQUEID"));
// We need to resolve the hostname in this thread so that we can use it in the GUI // We need to resolve the hostname in this thread so that we can use it in the GUI
packet.getAddress().getCanonicalHostName(); address.getCanonicalHostName();
NvComputer computer = new NvComputer(responses[0].getName().toString(), packet.getAddress(), packet.getAddress().getCanonicalHostName(), serviceState, numberOfApps, gpuType, mac, uniqueID); NvComputer computer = new NvComputer(hostname, address, serviceState, numberOfApps, gpuType, mac, uniqueID);
this.responses.add(computer); this.responses.add(computer);
} catch (ArrayIndexOutOfBoundsException e) { } catch (ArrayIndexOutOfBoundsException e) {
Log.e("NvmDNS Response", "We recieved a malformed DNS repsonse."); Log.e("NvmDNS Response", "We recieved a malformed DNS repsonse.");
} }
} }
private String parseTXTRecordField(String field, String key) {
// Make sure that our key=value pair actually has our key in it
if (!field.contains(key)) {
return "";
} }
// Make sure that our key=value pair only has one "=" in it.
if (field.indexOf('=') != field.lastIndexOf('=')) {
return "";
} }
String[] split = field.split("=");
if (split.length != 2) {
return "";
}
return split[1];
}
// What follows is an implementation of Android's AsyncTask.
// The first step is to send our query, then we start our
// RX thread to parse responses. However we only want to accept
// responses for a limited amount of time so we start a new thread
// to kill the socket after a set amount of time
// Then we return control to the foreground thread
@Override @Override
protected Void doInBackground(Void... thisParameterIsUseless) { protected Void doInBackground(Void... thisParameterIsUseless) {
Log.v("NvmDNS ASync", "doInBackground entered"); Log.v("NvmDNS ASync", "doInBackground entered");
@ -223,8 +261,6 @@ public class NvmDNS extends AsyncTask<Void, Integer, Void> {
} }
}).start(); }).start();
this.waitForResponses(); this.waitForResponses();
Log.v("NvmDNS ASync", "doInBackground exit"); Log.v("NvmDNS ASync", "doInBackground exit");