Weupnp

A tiny UPnP (Universal Plug and Play) client library written in Java

View project onGitHub

Overview

Weupnp is a lightweight Java library designed to implement the UPnP protocol to handle port mappings on Gateway Devices.

weupnp in the wild

  • Weupnp is used by the BitLet applet to open ports for incoming connections and to build an interactive console for the administration of port mappings on UPnP devices.
  • Since version 1.6, the UPnP PortMapper can use weupnp to communicate with Gateway Devices.
  • Jitsi (formerly SIP communicator) uses weupnp to gather UPnP candidates for ICE operations

Getting weupnp

Source code

The link at the top of this page will allow you to download archives with source code, otherwise you can clone the git repository.

Maven dependency

If you use Maven with your project, you just have to include the following dependency in your pom.xml:

<dependency>
    <groupId>org.bitlet</groupId>
    <artifactId>weupnp</artifactId>
    <version>0.1.2</version>
</dependency>

Binary archives

In case you do not use Maven, the binary archives for weupnp are available for direct download.

Licensing

weupnp is released under the LGPL license.

Using weupnp

Using weupnp is fairly simple, here is an annotated example of the what you would need to do to manipulate a simple mapping on your gateway.

Annotated example

Set up a logger (you can use whichever library you prefer, the example uses java.util.logging for simplicity) and start the gateway discovery: this will send a probe message to find suitable UPnP devices on the same network the client is on.

Logger logger = LogUtils.getLogger();
logger.info("Starting weupnp");

GatewayDiscover discover = new GatewayDiscover();
logger.info("Looking for Gateway Devices");
discover.discover();

Select a valid gateway that can be used to do port mappings.

GatewayDevice d = discover.getValidGateway();

The previous method will return null if no valid gateway has not been found.

if (null != d) {
    logger.info("Found gateway device.\n{0} ({1})",
        new Object[]{d.getModelName(), d.getModelDescription()});
} else {
    logger.info("No valid gateway device found.");
    return;
}

The retrieved GatewayDevice will contain some useful information, including the internal/external addresses of the device.

InetAddress localAddress = d.getLocalAddress();
logger.info("Using local address: {0}", localAddress);
String externalIPAddress = d.getExternalIPAddress();
logger.info("External address: {0}", externalIPAddress);

Create a new Port Mapping entry:

logger.info("Attempting to map port {0}", SAMPLE_PORT);
PortMappingEntry portMapping = new PortMappingEntry();

The getSpecificPortMappingEntry method can be used to search for existing mappings. If it returns true, it means that a mapping for the given port is already registered on the gateway.

logger.info("Querying device to see if mapping for port {0} already exists",
        SAMPLE_PORT);
if (!d.getSpecificPortMappingEntry(SAMPLE_PORT,"TCP",portMapping)) {
    logger.info("Port was already mapped. Aborting test.");    
} else {

In case it return false, we can move on to create the mapping by using addPortMapping. We will configure the gateway to forward any TCP connection it receives on SAMPLE_PORT to SAMPLE_PORT on the local address (the address of the device weupnp is running on). If the operation succeeds, the method will return true and the mapping will be called test.

    logger.info("Sending port mapping request");
    if (!d.addPortMapping(SAMPLE_PORT, SAMPLE_PORT,
            localAddress.getHostAddress(),"TCP","test")) {
        logger.info("Port mapping attempt failed");
        logger.info("Test FAILED");
    } else {

Wait a few seconds and then remove the mapping. If your gateway has an admin interface for UPnP, you can use that time to verify that a mapping called test is present.

        logger.info("Mapping successful: waiting {0} seconds before removing.",
            WAIT_TIME);
        Thread.sleep(1000*WAIT_TIME);
        d.deletePortMapping(SAMPLE_PORT,"TCP");

        logger.info("Port mapping removed");
        logger.info("Test SUCCESSFUL");
    }
}

logger.info("Stopping weupnp");

You can find a runnable version of the code above in the Main class of the package org.bitlet.weupnp.

Acknowledgements

The implementation of weupnp was inspired by miniupnp, a C UPnP library by Thomas Bernard.

Participating

If you wish to contribute, feel free to drop a line to @abahgat and @DCastagna.