Sto cercando di implementare una semplice libreria in grado di rilevare il router tramite il protocollo UPnP se l'applicazione è in esecuzione in un ambiente NAT. Ho provato due modi, multi-cast e datagramma, per inviare il pacchetto di scoperta al router e provare ad ascoltare la porta 1901 per la risposta dal router. Tuttavia, ho alcuni problemi con i codici. Ho provato i seguenti tre tipi di modi, e solo il terzo può ricevere correttamente la risposta dal router. Non ho idea del perché non funzioni sul primo e sul secondo modo.La ricerca del router tramite l'invio di pacchetti broadcast tramite UPnP non funziona
Il primo: invia il pacchetto multi-cast e ascolta la porta 1901 per la risposta.
Codici:
public void discovery() throws IOException {
// SSDP port
final int SSDP_PORT = 1900;
final int SSDP_SEARCH_PORT = 1901;
// Broadcast address for finding routers.
final String SSDP_IP = "239.255.255.250";
// Time out of the connection.
int TIMEOUT = 5000;
// Localhost address.
InetAddress localhost = InetAddress.getLocalHost();
// Send from localhost:1901
InetSocketAddress srcAddress = new InetSocketAddress(localhost, SSDP_SEARCH_PORT);
// Send to 239.255.255.250:1900
InetSocketAddress dstAddress = new InetSocketAddress(InetAddress.getByName(SSDP_IP), SSDP_PORT);
// ----------------------------------------- //
// Construct the request packet. //
// ----------------------------------------- //
StringBuffer discoveryMessage = new StringBuffer();
discoveryMessage.append("M-SEARCH * HTTP/1.1\r\n");
discoveryMessage.append("HOST: " + SSDP_IP + ":" + SSDP_PORT + "\r\n");
discoveryMessage.append("ST: urn:schemas-upnp-org:device:InternetGatewayDevice:1\r\n");
// ST: urn:schemas-upnp-org:service:WANIPConnection:1\r\n
discoveryMessage.append("MAN: \"ssdp:discover\"\r\n");
discoveryMessage.append("MX: 2\r\n");
discoveryMessage.append("\r\n");
// System.out.println("Request: " + discoveryMessage.toString() + "\n");
byte[] discoveryMessageBytes = discoveryMessage.toString().getBytes();
DatagramPacket discoveryPacket = new DatagramPacket(discoveryMessageBytes, discoveryMessageBytes.length, dstAddress);
// ----------------------------------- //
// Send multi-cast packet. //
// ----------------------------------- //
MulticastSocket multicast = null;
try {
multicast = new MulticastSocket(null);
multicast.bind(srcAddress);
multicast.setTimeToLive(4);
System.out.println("Send multicast request.");
// ----- Sending multi-cast packet ----- //
multicast.send(discoveryPacket);
} finally {
System.out.println("Multicast ends. Close connection.");
multicast.disconnect();
multicast.close();
}
// -------------------------------------------------- //
// Listening to response from the router. //
// -------------------------------------------------- //
DatagramSocket wildSocket = null;
DatagramPacket receivePacket = null;
try {
wildSocket = new DatagramSocket(SSDP_SEARCH_PORT);
wildSocket.setSoTimeout(TIMEOUT);
while (true) {
try {
System.out.println("Receive ssdp.");
receivePacket = new DatagramPacket(new byte[1536], 1536);
wildSocket.receive(receivePacket);
String message = new String(receivePacket.getData());
System.out.println("Recieved messages:");
System.out.println(message);
} catch (SocketTimeoutException e) {
System.err.print("Time out.");
break;
}
}
} finally {
if (wildSocket != null) {
wildSocket.disconnect();
wildSocket.close();
}
}
}
Risultato: Il router fa pacchetto di risposta (sniffered da Wireshark, come la schermata seguente), ma il codice non recieve nulla. code 1 http://img705.imageshack.us/img705/6531/ssdp1.png
risultato Codice:
Send multicast request.
Multicast ends. Close connection.
Receive ssdp.
Time out.
Il secondo: inviare datagram di pacchetti, e in ascolto sulla porta 1901 per la risposta.
Codici:
public void discovery() throws IOException {
// Ignore this part of the codes since they are the same as the first one.
..............
// -------------------------------------------------- //
// Listening to response from the router. //
// -------------------------------------------------- //
DatagramSocket wildSocket = null;
DatagramPacket receivePacket = null;
try {
wildSocket = new DatagramSocket(SSDP_SEARCH_PORT);
wildSocket.setSoTimeout(TIMEOUT);
// ----- Sending datagram packet ----- //
System.out.println("Send datagram packet.");
wildSocket.send(discoveryPacket);
while (true) {
try {
System.out.println("Receive ssdp.");
receivePacket = new DatagramPacket(new byte[1536], 1536);
wildSocket.receive(receivePacket);
String message = new String(receivePacket.getData());
System.out.println("Recieved messages:");
System.out.println(message);
} catch (SocketTimeoutException e) {
System.err.print("Time out.");
break;
}
}
} finally {
if (wildSocket != null) {
wildSocket.disconnect();
wildSocket.close();
}
}
}
Risultato: Wireshark non ottiene nulla. Nessun pacchetto viene sniffered sulla porta 1900 e il 1901.
risultato Codice:
Send datagram packet.
Receive ssdp.
Time out.
Il terzo: inviare multi-Cast e datagramma pacchetti, e in ascolto sulla porta 1901 per la risposta.
Codici:
public void discovery() throws IOException {
// Ignore this part of the codes since they are the same as the first one.
..............
// ----------------------------------- //
// Send multi-cast packet. //
// ----------------------------------- //
MulticastSocket multicast = null;
try {
multicast = new MulticastSocket(null);
multicast.bind(srcAddress);
multicast.setTimeToLive(4);
System.out.println("Send multicast request.");
// ----- Sending multi-cast packet ----- //
multicast.send(discoveryPacket);
} finally {
System.out.println("Multicast ends. Close connection.");
multicast.disconnect();
multicast.close();
}
// -------------------------------------------------- //
// Listening to response from the router. //
// -------------------------------------------------- //
DatagramSocket wildSocket = null;
DatagramPacket receivePacket = null;
try {
wildSocket = new DatagramSocket(SSDP_SEARCH_PORT);
wildSocket.setSoTimeout(TIMEOUT);
// ----- Sending datagram packet ----- //
System.out.println("Send datagram packet.");
wildSocket.send(discoveryPacket);
while (true) {
try {
System.out.println("Receive ssdp.");
receivePacket = new DatagramPacket(new byte[1536], 1536);
wildSocket.receive(receivePacket);
String message = new String(receivePacket.getData());
System.out.println("Recieved messages:");
System.out.println(message);
} catch (SocketTimeoutException e) {
System.err.print("Time out.");
break;
}
}
} finally {
if (wildSocket != null) {
wildSocket.disconnect();
wildSocket.close();
}
}
}
risultati: inviare due pacchetti di broadcast successo, e ottenere due risposte da router. code 1 http://img707.imageshack.us/img707/1607/ssdp3.png
risultato Codice:
Send multicast request.
Multicast ends. Close connection.
Send datagram packet.
Receive ssdp.
Recieved messages:
HTTP/1.1 200 OK
Cache-Control: max-age=300
Date: Wed, 06 Mar 2013 05:15:43 GMT
Ext:
Location: http://192.168.1.1:1780/InternetGatewayDevice.xml
Server: POSIX UPnP/1.0 DD-WRT Linux/V24
ST: urn:schemas-upnp-org:device:InternetGatewayDevice:1
USN: uuid:C42C1F3F-6E63-7FFC-F982-035B355D6E76::urn:schemas-upnp-org:device:InternetGatewayDevice:1
Receive ssdp.
Recieved messages:
HTTP/1.1 200 OK
Cache-Control: max-age=300
Date: Wed, 06 Mar 2013 05:15:43 GMT
Ext:
Location: http://192.168.1.1:1780/InternetGatewayDevice.xml
Server: POSIX UPnP/1.0 DD-WRT Linux/V24
ST: urn:schemas-upnp-org:device:InternetGatewayDevice:1
USN: uuid:C42C1F3F-6E63-7FFC-F982-035B355D6E76::urn:schemas-upnp-org:device:InternetGatewayDevice:1
Receive ssdp.
Time out.
C'è qualche idea del perché il primo e il secondo modo è riuscito a chiedere al router tramite protocollo UPnP? E perché il secondo sembra non inviare nulla?
Grazie mille!
+ 1 per la bella presentazione della domanda. – deadlock