/* * 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.IOException; import java.net.HttpURLConnection; import java.net.InetAddress; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.util.HashMap; import java.util.Map; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.XMLReaderFactory; /** * * @author casta */ public class GatewayDevice { private String st; private String location; private String serviceType; private String serviceTypeCIF; private String uRLBase; private String controlURL; private String controlURLCIF; private String eventSubURL; private String eventSubURLCIF; private String sCPDURL; private String sCPDURLCIF; private String deviceType; private String deviceTypeCIF; // description data private String friendlyName; private String manufacturer; private String modelDescription; private String presentationURL; /** * The address used to reach this machine from the GatewayDevice */ private InetAddress localAddress; public InetAddress getLocalAddress() { return localAddress; } public void setLocalAddress(InetAddress localAddress) { this.localAddress = localAddress; } /** * Creates a new instance of GatewayDevice */ public GatewayDevice() { } public String getSt() { return st; } public void setSt(String st) { this.st = st; } public String getLocation() { return location; } public void setLocation(String location) { this.location = location; } private String copyOrCatUrl(String dst, String src) { if (src == null) { return dst; } if (src.startsWith("http://")) { return src; } else { if (!src.startsWith("/")) { dst += "/"; } dst += src; } return dst; } public void loadDescription() throws WeUPnPException { URLConnection urlConn; try { urlConn = new URL(getLocation()).openConnection(); XMLReader parser; parser = XMLReaderFactory.createXMLReader(); parser.setContentHandler(new GatewayDeviceHandler(this)); parser.parse(new InputSource(urlConn.getInputStream())); /* fix urls */ String ipConDescURL; if (uRLBase != null && uRLBase.trim().length() > 0) ipConDescURL = uRLBase; else ipConDescURL = location; int lastSlashIndex = ipConDescURL.indexOf('/', 7); if (lastSlashIndex > 0) ipConDescURL = ipConDescURL.substring(0, lastSlashIndex); sCPDURL = copyOrCatUrl(ipConDescURL, sCPDURL); controlURL = copyOrCatUrl(ipConDescURL, controlURL); controlURLCIF = copyOrCatUrl(ipConDescURL, controlURLCIF); } catch (MalformedURLException e) { throw new WeUPnPException("Could not load description", e); } catch (IOException e) { throw new WeUPnPException("Could not load description", e); } catch (SAXException e) { throw new WeUPnPException("Could not load description", e); } } public boolean isConnected() throws WeUPnPException { Map<String, String> nameValue = simpleUPnPcommand(controlURL, serviceType, "GetStatusInfo", null); String connectionStatus = nameValue.get("NewConnectionStatus"); return connectionStatus != null && connectionStatus.equalsIgnoreCase("Connected"); } public Map<String, String> simpleUPnPcommand(String url, String service, String action, Map<String, String> args) throws WeUPnPException { StringBuffer soapBody = new StringBuffer(); soapBody .append("<?xml version=\"1.0\"?>\r\n" + "<SOAP-ENV:Envelope " + "xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" " + "SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" + "<SOAP-ENV:Body>" + "<m:" + action + " xmlns:m=\"" + service + "\">"); if (args != null && args.size() > 0) { for (String key : args.keySet()) { soapBody.append("<" + key + ">" + args.get(key) + "</" + key + ">"); } } soapBody.append("</m:" + action + ">"); soapBody.append("</SOAP-ENV:Body></SOAP-ENV:Envelope>"); HttpURLConnection conn = null; try { URL postUrl = new URL(url); conn = (HttpURLConnection) postUrl.openConnection(); conn.setRequestMethod("POST"); conn.setDoOutput(true); conn.setRequestProperty("Content-Type", "text/xml"); String soapAction = service + "#" + action; conn.setRequestProperty("SOAPAction", soapAction); conn.setRequestProperty("Connection", "Close"); byte[] soapBodyBytes = soapBody.toString().getBytes(); conn.setRequestProperty("Content-Length", Integer .toString(soapBodyBytes.length)); conn.getOutputStream().write(soapBodyBytes); XMLReader parser = XMLReaderFactory.createXMLReader(); NameValueHandler nameValueHandler = new NameValueHandler(); parser.setContentHandler(nameValueHandler); if (conn.getResponseCode() == HttpURLConnection.HTTP_INTERNAL_ERROR) { parser.parse(new InputSource(conn.getErrorStream())); } else { parser.parse(new InputSource(conn.getInputStream())); } return nameValueHandler.getNameValue(); } catch (MalformedURLException e) { throw new WeUPnPException("Could not send simple upnp command", e); } catch (SAXException e) { throw new WeUPnPException("Could not send simple upnp command", e); } catch (IOException e) { throw new WeUPnPException("Could not send simple upnp command", e); } finally { if (conn != null) { conn.disconnect(); } } } public String getExternalIPAddress() throws WeUPnPException { Map<String, String> nameValue = simpleUPnPcommand(controlURL, serviceType, "GetExternalIPAddress", null); return nameValue.get("NewExternalIPAddress"); } public boolean addPortMapping(int externalPort, int internalPort, String internalClient, String protocol, String description) throws WeUPnPException { Map<String, String> args = new HashMap<String, String>(); args.put("NewRemoteHost", ""); args.put("NewExternalPort", Integer.toString(externalPort)); args.put("NewProtocol", protocol); args.put("NewInternalPort", Integer.toString(internalPort)); args.put("NewInternalClient", internalClient); args.put("NewEnabled", Integer.toString(1)); args.put("NewPortMappingDescription", description); args.put("NewLeaseDuration", Integer.toString(0)); Map<String, String> nameValue = simpleUPnPcommand(controlURL, serviceType, "AddPortMapping", args); return nameValue.get("errorCode") == null; } public PortMappingEntry getSpecificPortMappingEntry(int externalPort, String protocol, final PortMappingEntry portMappingEntry) throws WeUPnPException { portMappingEntry.setExternalPort(externalPort); portMappingEntry.setProtocol(protocol); Map<String, String> args = new HashMap<String, String>(); args.put("NewRemoteHost", ""); args.put("NewExternalPort", Integer.toString(externalPort)); args.put("NewProtocol", protocol); Map<String, String> nameValue = simpleUPnPcommand(controlURL, serviceType, "GetSpecificPortMappingEntry", args); String internalClient = nameValue.get("NewInternalClient"); String internalPort = nameValue.get("NewInternalPort"); if (internalClient == null) { throw new WeUPnPException("Did not get internal client"); } portMappingEntry.setInternalClient(internalClient); if (internalPort != null) { try { portMappingEntry .setInternalPort(Integer.parseInt(internalPort)); } catch (NumberFormatException e) { throw new WeUPnPException("Got invalid internal port number " + internalPort, e); } } return portMappingEntry; } public PortMappingEntry getGenericPortMappingEntry(int index) throws WeUPnPException { Map<String, String> args = new HashMap<String, String>(); args.put("NewPortMappingIndex", Integer.toString(index)); Map<String, String> nameValue = simpleUPnPcommand(controlURL, serviceType, "GetGenericPortMappingEntry", args); PortMappingEntry portMappingEntry = new PortMappingEntry(); if (nameValue.get("NewExternalPort") != null) { portMappingEntry.setExternalPort(parseInt(nameValue .get("NewExternalPort"))); } else { portMappingEntry.setExternalPort(-1); } portMappingEntry.setRemoteHost(nameValue.get("NewRemoteHost")); portMappingEntry.setInternalClient(nameValue.get("NewInternalClient")); portMappingEntry.setProtocol(nameValue.get("NewProtocol")); if (nameValue.get("NewInternalPort") != null) { portMappingEntry.setInternalPort(parseInt(nameValue .get("NewInternalPort"))); } else { portMappingEntry.setInternalPort(-1); } portMappingEntry.setEnabled(nameValue.get("NewEnabled")); portMappingEntry.setPortMappingDescription(nameValue .get("NewPortMappingDescription")); // portMappingEntry.set(nameValue.get("NewLeaseDuration")); if (nameValue.get("errorCode") != null) { throw new WeUPnPException("Got error code '" + nameValue.get("errorCode") + "' when getting port mapping " + index); } return portMappingEntry; } private Integer parseInt(String value) { try { return Integer.parseInt(value); } catch (NumberFormatException e) { // TODO: log warning return null; } } public int getPortMappingNumberOfEntries() throws WeUPnPException { Map<String, String> nameValue = simpleUPnPcommand(controlURL, serviceType, "GetPortMappingNumberOfEntries", null); String portMappingNumberString = nameValue .get("NewPortMappingNumberOfEntries"); try { return Integer.parseInt(portMappingNumberString); } catch (NumberFormatException e) { throw new WeUPnPException("Got invalid port number '" + portMappingNumberString + "'", e); } } public boolean deletePortMapping(int externalPort, String protocol) throws WeUPnPException { Map<String, String> args = new HashMap<String, String>(); args.put("NewRemoteHost", ""); args.put("NewExternalPort", Integer.toString(externalPort)); args.put("NewProtocol", protocol); Map<String, String> nameValue = simpleUPnPcommand(controlURL, serviceType, "DeletePortMapping", args); // TODO: check, if port mapping was deleted // return nameValue.get("errorCode") == null; return true; } public String getServiceType() { return serviceType; } public void setServiceType(String serviceType) { this.serviceType = serviceType; } public String getServiceTypeCIF() { return serviceTypeCIF; } public void setServiceTypeCIF(String serviceTypeCIF) { this.serviceTypeCIF = serviceTypeCIF; } public String getControlURL() { return controlURL; } public void setControlURL(String controlURL) { this.controlURL = controlURL; } public String getControlURLCIF() { return controlURLCIF; } public void setControlURLCIF(String controlURLCIF) { this.controlURLCIF = controlURLCIF; } public String getEventSubURL() { return eventSubURL; } public void setEventSubURL(String eventSubURL) { this.eventSubURL = eventSubURL; } public String getEventSubURLCIF() { return eventSubURLCIF; } public void setEventSubURLCIF(String eventSubURLCIF) { this.eventSubURLCIF = eventSubURLCIF; } public String getSCPDURL() { return sCPDURL; } public void setSCPDURL(String sCPDURL) { this.sCPDURL = sCPDURL; } public String getSCPDURLCIF() { return sCPDURLCIF; } public void setSCPDURLCIF(String sCPDURLCIF) { this.sCPDURLCIF = sCPDURLCIF; } public String getDeviceType() { return deviceType; } public void setDeviceType(String deviceType) { this.deviceType = deviceType; } public String getDeviceTypeCIF() { return deviceTypeCIF; } public void setDeviceTypeCIF(String deviceTypeCIF) { this.deviceTypeCIF = deviceTypeCIF; } public String getURLBase() { return uRLBase; } public void setURLBase(String uRLBase) { this.uRLBase = uRLBase; } public String getFriendlyName() { return friendlyName; } public void setFriendlyName(String friendlyName) { this.friendlyName = friendlyName; } public String getManufacturer() { return manufacturer; } public void setManufacturer(String manufacturer) { this.manufacturer = manufacturer; } public String getModelDescription() { return modelDescription; } public void setModelDescription(String modelDescription) { this.modelDescription = modelDescription; } public String getPresentationURL() { return presentationURL; } public void setPresentationURL(String presentationURL) { this.presentationURL = presentationURL; } }