001: // serverPortForwardingUpnp.java
002: // -------------------------------------
003: // part of YACY
004: // (C) by Michael Peter Christen; mc@anomic.de
005: // first published on http://www.anomic.de
006: // Frankfurt, Germany, 2004
007: //
008: // This file ist contributed by Martin Thelian
009: //
010: // $LastChangedDate: 2006-02-20 23:57:42 +0100 (Mo, 20 Feb 2006) $
011: // $LastChangedRevision: 1715 $
012: // $LastChangedBy: theli $
013: //
014: // This program is free software; you can redistribute it and/or modify
015: // it under the terms of the GNU General Public License as published by
016: // the Free Software Foundation; either version 2 of the License, or
017: // (at your option) any later version.
018: //
019: // This program is distributed in the hope that it will be useful,
020: // but WITHOUT ANY WARRANTY; without even the implied warranty of
021: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
022: // GNU General Public License for more details.
023: //
024: // You should have received a copy of the GNU General Public License
025: // along with this program; if not, write to the Free Software
026: // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
027: //
028: // Using this software in any meaning (reading, learning, copying, compiling,
029: // running) means that you agree that the Author(s) is (are) not responsible
030: // for cost, loss of data or any harm that may be caused directly or indirectly
031: // by usage of this softare or this documentation. The usage of this software
032: // is on your own risk. The installation and usage (starting/running) of this
033: // software may allow other people or application to access your computer and
034: // any attached devices and is highly dependent on the configuration of the
035: // software which must be done by the user of the software; the author(s) is
036: // (are) also not responsible for proper configuration and usage of the
037: // software, even if provoked by documentation provided together with
038: // the software.
039: //
040: // Any changes to this file according to the GPL as documented in the file
041: // gpl.txt aside this file in the shipment you received can be done to the
042: // lines that follows this copyright notice here, but changes must not be
043: // done inside the copyright notive above. A re-distribution must contain
044: // the intact and unchanged copyright notice.
045: // Contributions and changes to the program code must be marked as such.
046:
047: package de.anomic.server.portForwarding.upnp;
048:
049: import java.io.IOException;
050: import java.net.InetAddress;
051:
052: import net.sbbi.upnp.impls.InternetGatewayDevice;
053: import net.sbbi.upnp.messages.ActionResponse;
054: import net.sbbi.upnp.messages.UPNPResponseException;
055: import de.anomic.server.serverSwitch;
056: import de.anomic.server.logging.serverLog;
057: import de.anomic.server.portForwarding.serverPortForwarding;
058:
059: public class serverPortForwardingUpnp implements serverPortForwarding {
060:
061: private InternetGatewayDevice gateway;
062: private String localHost;
063: private int localHostPort;
064: private String externalAddress = null;
065: private serverLog log;
066:
067: public serverPortForwardingUpnp() {
068: super ();
069: this .log = new serverLog("PORT_FORWARDING_UPNP");
070: }
071:
072: public void connect() throws IOException {
073: try {
074: if (this .gateway != null)
075: throw new IOException("Session already connected");
076:
077: int timeout = 8000;
078: try {
079: // trying to get all internet gateways on the local network
080: this .log
081: .logInfo("Trying to find all available internet gateways.");
082: InternetGatewayDevice[] IGDs = InternetGatewayDevice
083: .getDevices(timeout);
084: boolean mapped = false;
085: if (IGDs != null) {
086: for (int i = 0; i < IGDs.length; i++) {
087:
088: this .gateway = IGDs[i];
089: this .log.logInfo("Found device "
090: + this .gateway.getIGDRootDevice()
091: .getModelName());
092: this .log.logInfo("NAT table size is "
093: + this .gateway.getNatTableSize());
094:
095: // now let's open the port
096: this .log.logInfo("Adding port mapping ...");
097: mapped = this .gateway.addPortMapping(
098: "YaCy port forwarding", null,
099: this .localHostPort, this .localHostPort,
100: this .localHost, 0, "TCP");
101:
102: if (mapped) {
103: this .log.logInfo("Gateway port "
104: + this .localHostPort
105: + " mapped to " + this .localHost);
106: this .log
107: .logInfo("Current mappings count is "
108: + this .gateway
109: .getNatMappingsCount());
110: mapped = isConnected();
111: }
112: if (mapped)
113: break;
114: }
115: if (!mapped) {
116: throw new IOException(
117: "Unable to configure the port mapping.");
118: }
119: } else {
120: throw new IOException(
121: "No internet gateway device found.");
122: }
123:
124: } catch (IOException ex) {
125: throw new Exception(
126: "IOException occured during discovery or ports mapping. "
127: + ex.getMessage());
128: } catch (UPNPResponseException respEx) {
129: throw new Exception("UPNP device unhappy "
130: + respEx.getDetailErrorCode() + " "
131: + respEx.getDetailErrorDescription());
132: }
133: } catch (Exception e) {
134: this .gateway = null;
135: this .log
136: .logSevere(
137: "Unable to connect to remote port forwarding host. ",
138: e);
139: throw new IOException(e.getMessage());
140: }
141: }
142:
143: public boolean routerAvailable(int timeout) {
144: try {
145: InternetGatewayDevice[] IGDs = InternetGatewayDevice
146: .getDevices(timeout);
147: return (IGDs != null) && (IGDs.length > 0);
148: } catch (Exception e) {
149: this .log
150: .logSevere("Unable to determine available routers: "
151: + e.getMessage());
152: return false;
153: }
154: }
155:
156: public void disconnect() throws IOException {
157: if (this .gateway == null)
158: throw new IOException("No connection established.");
159:
160: boolean unmapped;
161: try {
162: this .log.logInfo("Trying to disable port mapping ...");
163: unmapped = this .gateway.deletePortMapping(null,
164: this .localHostPort, "TCP");
165: if (unmapped) {
166: this .log.logInfo("Port mapping disabled");
167: }
168: } catch (UPNPResponseException e) {
169: new IOException("Unable to disable port forwarding. "
170: + e.getMessage());
171: }
172: }
173:
174: public String getHost() {
175: if (this .gateway == null)
176: return "";
177: if (this .externalAddress == null) {
178: try {
179: this .externalAddress = this .gateway
180: .getExternalIPAddress();
181: } catch (Exception e) {
182: this .log
183: .logWarning("Unable to get the external address of the gateway");
184: }
185: }
186: return this .externalAddress;
187: }
188:
189: public int getPort() {
190: return this .localHostPort;
191: }
192:
193: public void init(serverSwitch switchboard, String localHost,
194: int localPort) throws Exception {
195: try {
196: this .log
197: .logFine("Initializing port forwarding via UPnP ...");
198:
199: if (localHost.equals("0.0.0.0")) {
200: this .localHost = InetAddress.getLocalHost()
201: .getHostAddress();
202: } else {
203: this .localHost = localHost;
204: }
205: this .localHostPort = localPort;
206:
207: // checking if all needed libs are availalbe
208: String javaClassPath = System
209: .getProperty("java.class.path");
210: if (javaClassPath.indexOf("sbbi-upnplib") == -1) {
211: throw new IllegalStateException("Missing library.");
212: }
213:
214: // setting the proper xml parser
215: // if (System.getProperty("javax.xml.parsers.DocumentBuilderFactory", "").equals("")) {
216: // System.setProperty("javax.xml.parsers.DocumentBuilderFactory", "");
217: // }
218:
219: } catch (Exception e) {
220: this .log.logSevere("Unable to initialize port forwarding.",
221: e);
222: throw e;
223: }
224: }
225:
226: public boolean isConnected() {
227: if (this .gateway == null)
228: return false;
229: try {
230: ActionResponse resp = this .gateway
231: .getSpecificPortMappingEntry(null,
232: this .localHostPort, "TCP");
233: return (resp != null);
234: } catch (Exception e) {
235: this .log
236: .logSevere("Unable to determine the connection status");
237: return false;
238: }
239: }
240:
241: public boolean reconnect() throws IOException {
242: if (!this .isConnected()) {
243: this .log
244: .logFine("Trying to reconnect to port forwarding host.");
245: this .disconnect();
246: this .connect();
247: return this .isConnected();
248: }
249: return false;
250: }
251:
252: }
|