/* * weupnp - Trivial upnp java library * * Copyright (C) 2008 Alessandro Bahgat Shehata, Daniele Castagna * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * Alessandro Bahgat Shehata - ale dot bahgat at gmail dot com * Daniele Castagna - daniele dot castagna at gmail dot com * */ package org.wetorrent.upnp; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.net.BindException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.net.SocketTimeoutException; import java.net.UnknownHostException; import java.util.HashMap; import java.util.Map; public class GatewayDiscover { private static final int PORT = 1900; private final String IP = "239.255.255.250"; private final Map<InetAddress, GatewayDevice> devices = new HashMap<InetAddress, GatewayDevice>(); public GatewayDiscover() { } public Map<InetAddress, GatewayDevice> discover() throws WeUPnPException { DatagramSocket ssdp = null; try { // try binding using the default port ssdp = new DatagramSocket(PORT); } catch (BindException be) { // could not bind to the default port } catch (SocketException e) { throw new WeUPnPException("Error discovering gateway devices", e); } try { if (null == ssdp) { // let the JVM choose an available port ssdp = new DatagramSocket(); } } catch (SocketException e) { throw new WeUPnPException("Error discovering gateway devices", e); } int port = ssdp.getLocalPort(); final String searchMessage = "M-SEARCH * HTTP/1.1\r\n" + "HOST: " + IP + ":" + port + "\r\n" + "ST: " + "urn:schemas-upnp-org:device:InternetGatewayDevice:1" + "\r\n" + "MAN: \"ssdp:discover\"\r\n" + "MX: 2\r\n" + "\r\n"; try { byte[] searchMessageBytes = searchMessage.getBytes(); DatagramPacket ssdpDiscoverPacket = new DatagramPacket( searchMessageBytes, searchMessageBytes.length); try { ssdpDiscoverPacket.setAddress(InetAddress.getByName(IP)); } catch (UnknownHostException e1) { throw new WeUPnPException("Error resolving host with name " + IP, e1); } ssdpDiscoverPacket.setPort(PORT); ssdp.send(ssdpDiscoverPacket); ssdp.setSoTimeout(3000); boolean waitingPacket = true; while (waitingPacket) { DatagramPacket receivePacket = new DatagramPacket( new byte[1536], 1536); try { ssdp.receive(receivePacket); byte[] receivedData = new byte[receivePacket.getLength()]; System.arraycopy(receivePacket.getData(), 0, receivedData, 0, receivePacket.getLength()); // TODO: devices should be a map, and receivePacket.address // should be the key ;) GatewayDevice d = parseMSearchReplay(receivedData); /* Get local address as it appears to the Gateway */ DatagramSocket sock = new DatagramSocket(); sock.connect(receivePacket.getSocketAddress()); InetAddress localAddress = sock.getLocalAddress(); sock.disconnect(); sock = null; d.setLocalAddress(localAddress); devices.put(localAddress, d); } catch (SocketTimeoutException ste) { waitingPacket = false; } } for (GatewayDevice device : devices.values()) { try { device.loadDescription(); } catch (Exception e) { } } } catch (IOException e) { throw new WeUPnPException("Error discovering gateway devices", e); } finally { ssdp.close(); } return devices; } private GatewayDevice parseMSearchReplay(byte[] reply) throws WeUPnPException { GatewayDevice device = new GatewayDevice(); BufferedReader br = new BufferedReader(new InputStreamReader( new ByteArrayInputStream(reply))); String line = null; try { line = br.readLine().trim(); } catch (IOException e) { throw new WeUPnPException("Error reading search replay", e); } while (line != null && line.trim().length() > 0) { if (line.startsWith("HTTP/1.")) { } else { String key = line.substring(0, line.indexOf(':')); String value = line.length() > key.length() + 1 ? line .substring(key.length() + 1) : null; key = key.trim(); if (value != null) value = value.trim(); if (key.compareToIgnoreCase("location") == 0) device.setLocation(value); else if (key.compareToIgnoreCase("st") == 0) device.setSt(value); } try { line = br.readLine().trim(); } catch (IOException ex) { } } return device; } public GatewayDevice getValidGateway() throws WeUPnPException { if (devices.isEmpty()) { throw new WeUPnPException("Did not find any gateways"); } for (GatewayDevice device : devices.values()) { if (device.isConnected()) return device; } return null; } }