/* * This file is part of jNAT-PMPlib. * * jNAT-PMPlib 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 3 of the License, or * (at your option) any later version. * * jNAT-PMPlib 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 jNAT-PMPlib. If not, see <http://www.gnu.org/licenses/>. */ package net.tomp2p.natpmp; import java.net.InetAddress; /** * This class manages a NAT-PMP device. This class is thread-safe. This manages * communication with a NAT-PMP device on the network. There are two types of * messages that can be sent to the device. * {@link ExternalAddressRequestMessage} can be sent to get the external IP of * the gateway. {@link MapRequestMessage} can be sent to map a port for a * certain amount of time. These two messages can be put into the message queue * through the {@link #enqueueMessage(Message)} method. As this class manages a * message queue to the NAT-PMP device, it is important to shut it down * correctly. Any mapped ports that are no longer desired should be unmapped * before shutdown occurs. Refer to {@link #NatPmpDevice(boolean)} for details * about the shutdown mechanism. * * @author flszen */ public class NatPmpDevice { // Shutdown control instance fields. private boolean isShutdown = false; private final Object shutdownLock = new Object(); private MessageQueue messageQueue; /** * Constructs a new NatPmpDevice. * * @param shutdownHookEnabled * Shutting down existing port mappings is a desired behavior; * therefore, this value is required! Refer to * {@link #setShutdownHookEnabled(boolean)} for details about * what value should be provided here and how it alters the * object's behavior. * @throws NatPmpException * A NatPmpException may be thrown if the local network is not * using addresses defined in RFC1918. A NatPmpException may * also be thrown if the the network gateway cannot be * determined, which may rarely be due to the network not using * IPv4. NAT-PMP should only be used on RFC1918 networks using * IPv4. * @see #setShutdownHookEnabled(boolean) * @see #shutdown() */ public NatPmpDevice(InetAddress gateway) throws NatPmpException { // Reject if the gateway is null. // This indicates either no gateway or the network is not IPv4. // It could also be that the netstat response is not supported. if (gateway == null) { throw new NatPmpException("The network gateway cannot be located."); } // Reject if it is not RFC1918. if (!gateway.isSiteLocalAddress()) { throw new NatPmpException("The network gateway address is not RFC1918 compliant."); } // Set up messaging queue. messageQueue = MessageQueue.createMessageQueue(gateway); } /** * Enqueues a message for sending. * * @param message * The {@link Message} to send. * @see #clearQueue() */ public void enqueueMessage(Message message) { messageQueue.enqueueMessage(message); } /** * Clears the queue of messages to send. If a message is currently sending, * it is not interrupted. * * @see #enqueueMessage(Message) */ public void clearQueue() { messageQueue.clearQueue(); } /** * Synchronously waits until the queue is empty before returning. */ public void waitUntilQueueEmpty() { messageQueue.waitUntilQueueEmpty(); } /** * Shuts down this NatPmpDevice. If the shutdown hook is disabled, this * method should be called manually at the time port mappings through the * NAT-PMP gateway are no longer needed. If the shutdown hook is enabled, * this method is called automatically during Java VM shutdown. When this * method is called, if the shutdown hook is enabled, it is automatically * disabled. It should be noted that when this method is called manually, it * blocks until it completes. If it is desired to shutdown asynchronously, * the {@link #shutdownAsync(boolean)} method should be called. * * @see #isShutdown() * @see #setShutdownHookEnabled(boolean) * @see #shutdownAsync(boolean) */ public void shutdown() { synchronized (shutdownLock) { // Do the shutdown stuff. messageQueue.shutdown(); // Set the isShutdown flag. isShutdown = true; } } /** * Flag indicates if this NatPmpDevice is shutdown. This method will block * if a shutdown is in progress. If you desire to wait for an asynchronous * shutdown to complete, please monitor the returned {@link Thread} instead. * * @return True if this NatPmpDeviceTest is shutdown, false if it is not. * @see #shutdown() */ public boolean isShutdown() { synchronized (shutdownLock) { return isShutdown; } } }