diff --git a/modP2pImpl/build.xml b/modP2pImpl/build.xml index ddeb7430f6..a1a3d2242f 100644 --- a/modP2pImpl/build.xml +++ b/modP2pImpl/build.xml @@ -16,6 +16,7 @@ + diff --git a/modP2pImpl/module-info.java b/modP2pImpl/module-info.java index 83be492ae3..b35397be18 100644 --- a/modP2pImpl/module-info.java +++ b/modP2pImpl/module-info.java @@ -1,4 +1,5 @@ module aion.p2p.impl { requires aion.p2p; + requires miniupnpc.linux; exports org.aion.p2p.impl; } \ No newline at end of file diff --git a/modP2pImpl/src/org/aion/p2p/impl/P2pMgr.java b/modP2pImpl/src/org/aion/p2p/impl/P2pMgr.java index d62c9cc9ee..3e577dd859 100644 --- a/modP2pImpl/src/org/aion/p2p/impl/P2pMgr.java +++ b/modP2pImpl/src/org/aion/p2p/impl/P2pMgr.java @@ -61,6 +61,7 @@ public final class P2pMgr implements IP2pMgr { private final static int TIMEOUT_OUTBOUND_CONNECT = 10000; private final static int TIMEOUT_OUTBOUND_NODES = 10000; + private final static int PERIOD_UPNP_PORT_MAPPING = 3600000; private final static int TIMEOUT_MSG_READ = 10000; @@ -678,10 +679,6 @@ private void handleKernelMsg(int _nodeIdHash, int _route, final byte[] _msgBytes } } - private void runUpnp() { - // TODO: implement - } - @Override public void run() { try { @@ -697,13 +694,13 @@ public void run() { tcpServer.socket().bind(new InetSocketAddress(Node.ipBytesToStr(selfIp), selfPort)); tcpServer.register(selector, SelectionKey.OP_ACCEPT); - if (this.upnpEnable) - runUpnp(); - Thread boss = new Thread(new TaskInbound(), "p2p-pi"); boss.setPriority(Thread.MAX_PRIORITY); boss.start(); + if (upnpEnable) + scheduledWorkers.scheduleWithFixedDelay(new TaskUPnPManager(selfPort), 1, PERIOD_UPNP_PORT_MAPPING, TimeUnit.MILLISECONDS); + if (showStatus) scheduledWorkers.scheduleWithFixedDelay(new TaskStatus(), 2, PERIOD_SHOW_STATUS, TimeUnit.MILLISECONDS); scheduledWorkers.scheduleWithFixedDelay(new TaskRequestActiveNodes(this), 5, PERIOD_REQUEST_ACTIVE_NODES, diff --git a/modP2pImpl/src/org/aion/p2p/impl/TaskUPnPManager.java b/modP2pImpl/src/org/aion/p2p/impl/TaskUPnPManager.java new file mode 100644 index 0000000000..284411037f --- /dev/null +++ b/modP2pImpl/src/org/aion/p2p/impl/TaskUPnPManager.java @@ -0,0 +1,103 @@ +package org.aion.p2p.impl; + +import fr.free.miniupnp.IGDdatas; +import fr.free.miniupnp.MiniupnpcLibrary; +import fr.free.miniupnp.UPNPDev; +import fr.free.miniupnp.UPNPUrls; +import java.nio.ByteBuffer; +import java.nio.IntBuffer; + +public class TaskUPnPManager implements Runnable { + + private final static String UPNP_PROTOCOL_TCP = "TCP"; + private final static String UPNP_PORT_MAPPING_DESCRIPTION = "aion-UPnP"; + private final static int DEFAULT_UPNP_PORT_MAPPING_LIFETIME_IN_SECONDS = 3600; + private final static int UPNP_DELAY = 2000; + + private int port; + MiniupnpcLibrary miniupnpc; + + TaskUPnPManager(int port){ + this.port = port; + miniupnpc = MiniupnpcLibrary.INSTANCE; + } + + @Override + public void run() { + Thread.currentThread().setName("p2p-UPnP"); + + UPNPUrls urls = new UPNPUrls(); + IGDdatas data = new IGDdatas(); + + ByteBuffer lanaddr = ByteBuffer.allocate(16); + + UPNPDev devlist = miniupnpc.upnpDiscover(UPNP_DELAY, null, null, 0, 0, (byte) 2, IntBuffer.allocate(1)); + if (devlist != null) { + if (miniupnpc.UPNP_GetValidIGD(devlist, urls, data, lanaddr, 16) != 0) { + System.out.println(""); + System.out.println(""); + + getExternalIpAddress(urls, data); + addPortMapping(urls, data, lanaddr); + getMappedPortInfo(urls, data); + + miniupnpc.FreeUPNPUrls(urls); + } else { + System.out.println(""); + } + } else { + System.out.println(""); + } + } + + private void addPortMapping(UPNPUrls urls, IGDdatas data, ByteBuffer lanaddr) { + int ret = miniupnpc.UPNP_AddPortMapping( + urls.controlURL.getString(0), + new String(data.first.servicetype), + String.valueOf(port), + String.valueOf(port), + new String(lanaddr.array()), + UPNP_PORT_MAPPING_DESCRIPTION, + UPNP_PROTOCOL_TCP, + null, + String.valueOf(DEFAULT_UPNP_PORT_MAPPING_LIFETIME_IN_SECONDS)); + + if (ret != MiniupnpcLibrary.UPNPCOMMAND_SUCCESS) + System.out.println(""); + } + + private void getMappedPortInfo(UPNPUrls urls, IGDdatas data) { + ByteBuffer intClient = ByteBuffer.allocate(16); + ByteBuffer intPort = ByteBuffer.allocate(6); + ByteBuffer desc = ByteBuffer.allocate(80); + ByteBuffer enabled = ByteBuffer.allocate(4); + ByteBuffer leaseDuration = ByteBuffer.allocate(16); + + int ret = miniupnpc.UPNP_GetSpecificPortMappingEntry( + urls.controlURL.getString(0), new String(data.first.servicetype), + String.valueOf(port), UPNP_PROTOCOL_TCP, null, intClient, intPort, + desc, enabled, leaseDuration); + + if (ret != MiniupnpcLibrary.UPNPCOMMAND_SUCCESS) { + System.out.println(""); + return; + } + + System.out.println(""); + } + + private void getExternalIpAddress(UPNPUrls urls, IGDdatas data) { + ByteBuffer externalAddress = ByteBuffer.allocate(16); + int ret = miniupnpc.UPNP_GetExternalIPAddress(urls.controlURL.getString(0), + new String(data.first.servicetype), externalAddress); + + if(ret != MiniupnpcLibrary.UPNPCOMMAND_SUCCESS) { + System.out.println(""); + return; + } + + System.out.println(""); + } +} \ No newline at end of file