2013-03-06 22 views
7

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!

+0

+ 1 per la bella presentazione della domanda. – deadlock

risposta

1

Suppongo che potrebbe trattarsi di un problema relativo al firmware del router OS +. Assicurati che il tuo firewall sia spento.

Prima Methot: Questo metodo non funziona per niente sul mio computer (OS X):

Send multicast request. 
Exception in thread "main" java.io.IOException: Can't assign requested address 
Multicast ends. Close connection. 
    at java.net.PlainDatagramSocketImpl.send(Native Method) 
    at java.net.DatagramSocket.send(DatagramSocket.java:676) 
    at Test.discovery(Test.java:55) 
    at Test.main(Test.java:93) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:601) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120) 

Tuttavia, dopo che ho cambiato:

InetSocketAddress srcAddress = new InetSocketAddress(localhost, SSDP_SEARCH_PORT); 

a

InetSocketAddress srcAddress = new InetSocketAddress(SSDP_SEARCH_PORT); 

Funziona perfettamente:

Send multicast request. 
Multicast ends. Close connection. 
Receive ssdp. 
Recieved messages: 
HTTP/1.1 200 OK 
Cache-Control: max-age=60 
Date: Sun, 04 Jan 1970 21:55:18 GMT 
Ext: 
Location: http://192.168.0.2:1780/InternetGatewayDevice.xml 
Server: POSIX UPnP/1.0 linux/5.20.61.0 
ST: urn:schemas-upnp-org:device:InternetGatewayDevice:1 
USN: uuid:C04E066F-F351-72B6-CCCF-E98237DCB05C::urn:schemas-upnp-org:device:InternetGatewayDevice:1 


Receive ssdp. 
Time out. 

Secondo metodo: Works.

Terzo metodo: Opere.

(troppo lungo per il commento)

[modifica]

Nel caso in cui il vostro obiettivo è quello di produrre software stabile, Consiglierei di attenersi a modo convenzionale: https://stackoverflow.com/a/4405143