Merge dev

This commit is contained in:
Adam Ierymenko 2015-11-30 15:17:31 -08:00
commit 7e28161638
39 changed files with 3797 additions and 320 deletions

View File

@ -0,0 +1,98 @@
$Id: Changelog.txt,v 1.33 2013/11/26 08:47:36 nanard Exp $
2013/11/26:
enforce strict aliasing rules.
2013/09/10:
small patch for MSVC >= 16
rename win32 implementation of gettimeofday() to natpmp_gettimeofday()
2012/08/21:
Little change in Makefile
removed warnings in testgetgateway.c
Fixed bugs in command line argumentparsing in natpmpc.c
2011/08/07:
Patch to build on debian/kFreeBSD.
2011/07/15:
Put 3 clauses BSD licence at the top of source files.
2011/06/18:
--no-undefined => -Wl,--no-undefined
adding a natpmpc.1 man page
2011/05/19:
Small fix in libnatpmpmodule.c thanks to Manuel Mausz
2011/01/03:
Added an argument to initnatpmp() in order to force the gateway to be used
2011/01/01:
fix in make install
2010/05/21:
make install now working under MacOSX (and BSD)
2010/04/12:
cplusplus stuff in natpmp.h
2010/02/02:
Fixed compilation under Mac OS X
2009/12/19:
improve and fix building under Windows.
Project files for MS Visual Studio 2008
More simple (and working) code for Win32.
More checks in the /proc/net/route parsing. Add some comments.
2009/08/04:
improving getgateway.c for windows
2009/07/13:
Adding Haiku code in getgateway.c
2009/06/04:
Adding Python module thanks to David Wu
2009/03/10:
Trying to have windows get gateway working if not using DHCP
2009/02/27:
dont include declspec.h if not under WIN32.
2009/01/23:
Prefixed the libraries name with lib
2008/10/06:
Fixed a memory leak in getdefaultgateway() (USE_SYSCTL_NET_ROUTE)
2008/07/03:
Adding WIN32 code from Robbie Hanson
2008/06/30:
added a Solaris implementation for getgateway().
added a LICENCE file to the distribution
2008/05/29:
Anonymous unions are forbidden in ANSI C. That was causing problems with
non-GCC compilers.
2008/04/28:
introduced strnatpmperr()
improved natpmpc.c sample
make install now install the binary
2007/12/13:
Fixed getgateway.c for working under OS X ;)
Fixed values for NATPMP_PROTOCOL_TCP and NATPMP_PROTOCOL_UDP
2007/12/11:
Fixed getgateway.c for compilation under Mac OS X
2007/12/01:
added some comments in .h
2007/11/30:
implemented almost everything

View File

@ -0,0 +1,42 @@
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import fr.free.miniupnp.libnatpmp.NatPmp;
import fr.free.miniupnp.libnatpmp.NatPmpResponse;
class JavaTest {
public static void main(String[] args) {
NatPmp natpmp = new NatPmp();
natpmp.sendPublicAddressRequest();
NatPmpResponse response = new NatPmpResponse();
int result = -1;
do{
result = natpmp.readNatPmpResponseOrRetry(response);
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
//fallthrough
}
} while (result != 0);
byte[] bytes = intToByteArray(response.addr);
try {
InetAddress inetAddress = InetAddress.getByAddress(bytes);
System.out.println("Public address is " + inetAddress);
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
}
public static final byte[] intToByteArray(int value) {
return new byte[] {
(byte)value,
(byte)(value >>> 8),
(byte)(value >>> 16),
(byte)(value >>> 24)};
}
}

26
ext/libnatpmp/LICENSE Normal file
View File

@ -0,0 +1,26 @@
Copyright (c) 2007-2011, Thomas BERNARD
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

177
ext/libnatpmp/Makefile Normal file
View File

@ -0,0 +1,177 @@
# $Id: Makefile,v 1.23 2013/11/26 16:38:15 nanard Exp $
# This Makefile is designed for use with GNU make
# libnatpmp
# (c) 2007-2013 Thomas Bernard
# http://miniupnp.free.fr/libnatpmp.html
OS = $(shell uname -s)
CC = gcc
INSTALL = install -p
ARCH = $(shell uname -m | sed -e s/i.86/i686/)
VERSION = $(shell cat VERSION)
ifeq ($(OS), Darwin)
JARSUFFIX=mac
endif
ifeq ($(OS), Linux)
JARSUFFIX=linux
endif
ifneq (,$(findstring WIN,$(OS)))
JARSUFFIX=win32
endif
# APIVERSION is used in soname
APIVERSION = 1
#LDFLAGS = -Wl,--no-undefined
CFLAGS ?= -Os
#CFLAGS = -g -O0
CFLAGS += -fPIC
CFLAGS += -Wall
#CFLAGS += -Wextra
CFLAGS += -DENABLE_STRNATPMPERR
#CFLAGS += -Wstrict-aliasing
LIBOBJS = natpmp.o getgateway.o
OBJS = $(LIBOBJS) testgetgateway.o natpmpc.o natpmp-jni.o
STATICLIB = libnatpmp.a
ifeq ($(OS), Darwin)
SHAREDLIB = libnatpmp.dylib
JNISHAREDLIB = libjninatpmp.dylib
SONAME = $(basename $(SHAREDLIB)).$(APIVERSION).dylib
CFLAGS := -DMACOSX -D_DARWIN_C_SOURCE $(CFLAGS)
SONAMEFLAGS=-Wl,-install_name,$(JNISHAREDLIB) -dynamiclib -framework JavaVM
else
ifneq (,$(findstring WIN,$(OS)))
SHAREDLIB = natpmp.dll
JNISHAREDLIB = jninatpmp.dll
CC = i686-w64-mingw32-gcc
EXTRA_LD = -lws2_32 -lIphlpapi -Wl,--no-undefined -Wl,--enable-runtime-pseudo-reloc --Wl,kill-at
else
SHAREDLIB = libnatpmp.so
JNISHAREDLIB = libjninatpmp.so
SONAME = $(SHAREDLIB).$(APIVERSION)
SONAMEFLAGS=-Wl,-soname,$(JNISHAREDLIB)
endif
endif
HEADERS = natpmp.h
EXECUTABLES = testgetgateway natpmpc-shared natpmpc-static
INSTALLPREFIX ?= $(PREFIX)/usr
INSTALLDIRINC = $(INSTALLPREFIX)/include
INSTALLDIRLIB = $(INSTALLPREFIX)/lib
INSTALLDIRBIN = $(INSTALLPREFIX)/bin
JAVA ?= java
JAVAC ?= javac
JAVAH ?= javah
JAVAPACKAGE = fr/free/miniupnp/libnatpmp
JAVACLASSES = $(JAVAPACKAGE)/NatPmp.class $(JAVAPACKAGE)/NatPmpResponse.class $(JAVAPACKAGE)/LibraryExtractor.class $(JAVAPACKAGE)/URLUtils.class
JNIHEADERS = fr_free_miniupnp_libnatpmp_NatPmp.h
.PHONY: all clean depend install cleaninstall installpythonmodule
all: $(STATICLIB) $(SHAREDLIB) $(EXECUTABLES)
pythonmodule: $(STATICLIB) libnatpmpmodule.c setup.py
python setup.py build
touch $@
installpythonmodule: pythonmodule
python setup.py install
clean:
$(RM) $(OBJS) $(EXECUTABLES) $(STATICLIB) $(SHAREDLIB) $(JAVACLASSES) $(JNISHAREDLIB)
$(RM) pythonmodule
$(RM) -r build/ dist/ libraries/
depend:
makedepend -f$(MAKEFILE_LIST) -Y $(OBJS:.o=.c) 2>/dev/null
install: $(HEADERS) $(STATICLIB) $(SHAREDLIB) natpmpc-shared
$(INSTALL) -d $(INSTALLDIRINC)
$(INSTALL) -m 644 $(HEADERS) $(INSTALLDIRINC)
$(INSTALL) -d $(INSTALLDIRLIB)
$(INSTALL) -m 644 $(STATICLIB) $(INSTALLDIRLIB)
$(INSTALL) -m 644 $(SHAREDLIB) $(INSTALLDIRLIB)/$(SONAME)
$(INSTALL) -d $(INSTALLDIRBIN)
$(INSTALL) -m 755 natpmpc-shared $(INSTALLDIRBIN)/natpmpc
ln -s -f $(SONAME) $(INSTALLDIRLIB)/$(SHAREDLIB)
$(JNIHEADERS): fr/free/miniupnp/libnatpmp/NatPmp.class
$(JAVAH) -jni fr.free.miniupnp.libnatpmp.NatPmp
%.class: %.java
$(JAVAC) -cp . $<
$(JNISHAREDLIB): $(SHAREDLIB) $(JNIHEADERS) $(JAVACLASSES)
ifeq (,$(JAVA_HOME))
@echo "Check your JAVA_HOME environement variable" && false
endif
ifneq (,$(findstring WIN,$(OS)))
$(CC) -m32 -D_JNI_Implementation_ -Wl,--kill-at \
-I"$(JAVA_HOME)/include" -I"$(JAVA_HOME)/include/win32" \
natpmp-jni.c -shared \
-o $(JNISHAREDLIB) -L. -lnatpmp -lws2_32 -lIphlpapi
else
$(CC) $(CFLAGS) -c -I"$(JAVA_HOME)/include" -I"$(JAVA_HOME)/include/win32" natpmp-jni.c
$(CC) $(CFLAGS) -o $(JNISHAREDLIB) -shared $(SONAMEFLAGS) natpmp-jni.o -lc -L. -lnatpmp
endif
jar: $(JNISHAREDLIB)
find fr -name '*.class' -print > classes.list
$(eval JNISHAREDLIBPATH := $(shell java fr.free.miniupnp.libnatpmp.LibraryExtractor))
mkdir -p libraries/$(JNISHAREDLIBPATH)
mv $(JNISHAREDLIB) libraries/$(JNISHAREDLIBPATH)/$(JNISHAREDLIB)
jar cf natpmp_$(JARSUFFIX).jar @classes.list libraries/$(JNISHAREDLIBPATH)/$(JNISHAREDLIB)
$(RM) classes.list
jnitest: $(JNISHAREDLIB) JavaTest.class
$(RM) libjninatpmp.so
$(JAVA) -Djna.nosys=true -cp . JavaTest
mvn_install:
mvn install:install-file -Dfile=java/natpmp_$(JARSUFFIX).jar \
-DgroupId=com.github \
-DartifactId=natpmp \
-Dversion=$(VERSION) \
-Dpackaging=jar \
-Dclassifier=$(JARSUFFIX) \
-DgeneratePom=true \
-DcreateChecksum=true
cleaninstall:
$(RM) $(addprefix $(INSTALLDIRINC), $(HEADERS))
$(RM) $(INSTALLDIRLIB)/$(SONAME)
$(RM) $(INSTALLDIRLIB)/$(SHAREDLIB)
$(RM) $(INSTALLDIRLIB)/$(STATICLIB)
testgetgateway: testgetgateway.o getgateway.o
$(CC) $(LDFLAGS) -o $@ $^ $(EXTRA_LD)
natpmpc-static: natpmpc.o $(STATICLIB)
$(CC) $(LDFLAGS) -o $@ $^ $(EXTRA_LD)
natpmpc-shared: natpmpc.o $(SHAREDLIB)
$(CC) $(LDFLAGS) -o $@ $^ $(EXTRA_LD)
$(STATICLIB): $(LIBOBJS)
$(AR) crs $@ $?
$(SHAREDLIB): $(LIBOBJS)
ifeq ($(OS), Darwin)
$(CC) -dynamiclib -Wl,-install_name,$(SONAME) -o $@ $^
else
$(CC) -shared -Wl,-soname,$(SONAME) -o $@ $^ $(EXTRA_LD)
endif
# DO NOT DELETE
natpmp.o: natpmp.h getgateway.h declspec.h
getgateway.o: getgateway.h declspec.h
testgetgateway.o: getgateway.h declspec.h
natpmpc.o: natpmp.h

7
ext/libnatpmp/README Normal file
View File

@ -0,0 +1,7 @@
libnatpmp (c) 2007-2009 Thomas Bernard
contact : miniupnp@free.fr
see http://miniupnp.free.fr/libnatpmp.html
or http://miniupnp.tuxfamily.org/libnatpmp.html
for some documentation and code samples.

30
ext/libnatpmp/build.bat Normal file
View File

@ -0,0 +1,30 @@
@echo Compiling with MinGW
@SET LIBS=-lws2_32 -liphlpapi
@echo Compile getgateway
gcc -c -Wall -Os -DWIN32 -DSTATICLIB -DENABLE_STRNATPMPERR getgateway.c
gcc -c -Wall -Os -DWIN32 -DSTATICLIB -DENABLE_STRNATPMPERR testgetgateway.c
gcc -o testgetgateway getgateway.o testgetgateway.o %LIBS%
del testgetgateway.o
@echo Compile natpmp-static:
gcc -c -Wall -Os -DWIN32 -DSTATICLIB -DENABLE_STRNATPMPERR getgateway.c
gcc -c -Wall -Os -DWIN32 -DSTATICLIB -DENABLE_STRNATPMPERR natpmp.c
gcc -c -Wall -Os -DWIN32 wingettimeofday.c
ar cr natpmp.a getgateway.o natpmp.o wingettimeofday.o
del getgateway.o natpmp.o
gcc -c -Wall -Os -DWIN32 -DSTATICLIB -DENABLE_STRNATPMPERR natpmpc.c
gcc -o natpmpc-static natpmpc.o natpmp.a %LIBS%
upx --best natpmpc-static.exe
del natpmpc.o
@echo Create natpmp.dll:
gcc -c -Wall -Os -DWIN32 -DENABLE_STRNATPMPERR -DNATPMP_EXPORTS getgateway.c
gcc -c -Wall -Os -DWIN32 -DENABLE_STRNATPMPERR -DNATPMP_EXPORTS natpmp.c
dllwrap -k --driver-name gcc --def natpmp.def --output-def natpmp.dll.def --implib natpmp.lib -o natpmp.dll getgateway.o natpmp.o wingettimeofday.o %LIBS%
@echo Compile natpmp-shared:
gcc -c -Wall -Os -DWIN32 -DENABLE_STRNATPMPERR -DNATPMP_EXPORTS natpmpc.c
gcc -o natpmpc-shared natpmpc.o natpmp.lib -lws2_32
upx --best natpmpc-shared.exe
del *.o

21
ext/libnatpmp/declspec.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef DECLSPEC_H_INCLUDED
#define DECLSPEC_H_INCLUDED
#if defined(WIN32) && !defined(STATICLIB)
/* for windows dll */
#ifdef NATPMP_EXPORTS
#define LIBSPEC __declspec(dllexport)
#else
#define LIBSPEC __declspec(dllimport)
#endif
#else
#if defined(__GNUC__) && __GNUC__ >= 4
/* fix dynlib for OS X 10.9.2 and Apple LLVM version 5.0 */
#define LIBSPEC __attribute__ ((visibility ("default")))
#else
#define LIBSPEC
#endif
#endif
#endif

View File

@ -0,0 +1,238 @@
package fr.free.miniupnp.libnatpmp;
/** I (Leah X Schmidt) copied this code from jnaerator, because
JNAerator's extractor requires you to buy into the whole JNA
concept.
JNAErator is
Copyright (c) 2009 Olivier Chafik, All Rights Reserved
JNAerator is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JNAerator 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JNAerator. If not, see <http://www.gnu.org/licenses/>.
*/
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class LibraryExtractor {
private static boolean libPathSet = false;
public static String getLibraryPath(String libraryName, boolean extractAllLibraries, Class<?> cl) {
try {
String customPath = System.getProperty("library." + libraryName);
if (customPath == null)
customPath = System.getenv(libraryName.toUpperCase() + "_LIBRARY");
if (customPath != null) {
File f = new File(customPath);
if (!f.exists())
System.err.println("Library file '" + customPath + "' does not exist !");
else
return f.getAbsolutePath();
}
//ClassLoader cl = LibraryExtractor.class.getClassLoader();
String prefix = "(?i)" + (isWindows() ? "" : "lib") + libraryName + "[^A-Za-z_].*";
String libsuffix = "(?i).*\\.(so|dll|dylib|jnilib)";
//String othersuffix = "(?i).*\\.(pdb)";
URL sourceURL = null;
List<URL> otherURLs = new ArrayList<URL>();
String arch = getCurrentOSAndArchString();
//System.out.println("libURL = " + libURL);
List<URL> list = URLUtils.listFiles(URLUtils.getResource(cl, "libraries/" + arch)),
noArchList = URLUtils.listFiles(URLUtils.getResource(cl, "libraries/noarch"));
Set<String> names = new HashSet<String>();
for (URL url : list) {
String name = getFileName(url);
names.add(name);
}
for (URL url : noArchList) {
String name = getFileName(url);
if (names.add(name))
list.add(url);
}
for (File f : new File(".").listFiles())
if (f.isFile())
list.add(f.toURI().toURL());
for (URL url : list) {
String name = getFileName(url);
boolean pref = name.matches(prefix), suff = name.matches(libsuffix);
if (pref && suff)
sourceURL = url;
else //if (suff || fileName.matches(othersuffix))
otherURLs.add(url);
}
List<File> files = new ArrayList<File>();
if (extractAllLibraries) {
for (URL url : otherURLs)
files.add(extract(url));
}
if (System.getProperty("javawebstart.version") != null) {
if (isWindows()) {
//File f = new File("c:\\Windows\\" + (Platform.is64Bit() ? "SysWOW64\\" : "System32\\") + libraryName + ".dll");
File f = new File("c:\\Windows\\" + "System32\\" + libraryName + ".dll");
if (f.exists())
return f.toString();
} else if (isMac()) {
File f = new File("/System/Library/Frameworks/" + libraryName + ".framework/" + libraryName);
if (f.exists())
return f.toString();
}
}
if (sourceURL == null)
return libraryName;
else {
File file = extract(sourceURL);
files.add(file);
int lastSize;
do {
lastSize = files.size();
for (Iterator<File> it = files.iterator(); it.hasNext();) {
File f = it.next();
if (!f.getName().matches(libsuffix))
continue;
try {
System.load(f.toString());
it.remove();
} catch (Throwable ex) {
System.err.println("Loading " + f.getName() + " failed (" + ex + ")");
}
}
} while (files.size() < lastSize);
return file.getCanonicalPath();
}
} catch (Throwable ex) {
System.err.println("ERROR: Failed to extract library " + libraryName);
ex.printStackTrace();
return libraryName;
}
}
public static final boolean isWindows() {
String osName = System.getProperty("os.name");
return osName.startsWith("Windows");
}
public static final boolean isMac() {
String osName = System.getProperty("os.name");
return osName.startsWith("Mac") || osName.startsWith("Darwin");
}
//this code is from JNA, but JNA has a fallback to some native
//stuff in case this doesn't work. Since sun.arch.data.model is
//defined for Sun and IBM, this should work nearly everywhere.
public static final boolean is64Bit() {
String model = System.getProperty("sun.arch.data.model",
System.getProperty("com.ibm.vm.bitmode"));
if (model != null) {
return "64".equals(model);
}
String arch = System.getProperty("os.arch").toLowerCase();
if ("x86_64".equals(arch)
|| "ia64".equals(arch)
|| "ppc64".equals(arch)
|| "sparcv9".equals(arch)
|| "amd64".equals(arch)) {
return true;
}
return false;
}
public static String getCurrentOSAndArchString() {
String os = System.getProperty("os.name"), arch = System.getProperty("os.arch");
if (os.equals("Mac OS X")) {
os = "darwin";
arch = "fat";
} else if (os.startsWith("Windows")) {
return "win" + (is64Bit() ? "64" : "32");
} else if (os.matches("SunOS|Solaris"))
os = "solaris";
return os + "-" + arch;
}
private static File extract(URL url) throws IOException {
File localFile;
if ("file".equals(url.getProtocol()))
localFile = new File(URLDecoder.decode(url.getFile(), "UTF-8"));
else {
File f = new File(System.getProperty("user.home"));
f = new File(f, ".jnaerator");
f = new File(f, "extractedLibraries");
if (!f.exists())
f.mkdirs();
if (!libPathSet) {
String path = System.getProperty("java.library.path");
if (path == null) {
System.setProperty("java.library.path", f.toString());
} else {
System.setProperty("java.library.path", path + ":" + f);
}
libPathSet = true;
}
localFile = new File(f, new File(url.getFile()).getName());
URLConnection c = url.openConnection();
if (localFile.exists() && localFile.lastModified() > c.getLastModified()) {
c.getInputStream().close();
} else {
System.out.println("Extracting " + url);
InputStream in = c.getInputStream();
OutputStream out = new FileOutputStream(localFile);
int len;
byte[] b = new byte[1024];
while ((len = in.read(b)) > 0)
out.write(b, 0, len);
out.close();
in.close();
}
}
return localFile;
}
private static String getFileName(URL url) {
return new File(url.getFile()).getName();
}
public static void main(String[] args) {
System.out.println(getCurrentOSAndArchString());
}
}

View File

@ -0,0 +1,50 @@
package fr.free.miniupnp.libnatpmp;
import java.nio.ByteBuffer;
public class NatPmp {
private static final String JNA_LIBRARY_NAME = LibraryExtractor.getLibraryPath("jninatpmp", true, NatPmp.class);
static {
String s = JNA_LIBRARY_NAME;
startup();
}
public ByteBuffer natpmp;
public NatPmp() {
init(0, 0);
}
public NatPmp(int forcedgw) {
init(1, forcedgw);
}
/** Cleans up the native resources used by this object.
Attempting to use the object after this has been called
will lead to crashes.*/
public void dispose() {
free();
}
protected void finalize() {
if (natpmp != null)
free();
}
private native void init(int forcegw, int forcedgw);
private native void free();
private static native void startup();
public native int sendPublicAddressRequest();
public native int sendNewPortMappingRequest(int protocol, int privateport, int publicport, int lifetime);
//returns a number of milliseconds, in accordance with Java convention
public native long getNatPmpRequestTimeout();
public native int readNatPmpResponseOrRetry(NatPmpResponse response);
}

View File

@ -0,0 +1,28 @@
package fr.free.miniupnp.libnatpmp;
public class NatPmpResponse {
public static final int TYPE_PUBLICADDRESS=0;
public static final int TYPE_UDPPORTMAPPING=1;
public static final int TYPE_TCPPORTMAPPING=2;
/** see TYPE_* constants */
public short type;
/** NAT-PMP response code */
public short resultcode;
/** milliseconds since start of epoch */
public long epoch;
/** only defined if type == 0*/
public int addr;
/** only defined if type != 0 */
public int privateport;
/** only defined if type != 0 */
public int mappedpublicport;
/** only defined if type != 0 */
public long lifetime; //milliseconds
}

View File

@ -0,0 +1,81 @@
package fr.free.miniupnp.libnatpmp;
/** I (Leah X Schmidt) copied this code from jnaerator, because
JNAerator's extractor requires you to buy into the whole JNA
concept.
JNAErator is
Copyright (c) 2009 Olivier Chafik, All Rights Reserved
JNAerator is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JNAerator 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JNAerator. If not, see <http://www.gnu.org/licenses/>.
*/
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
public class URLUtils {
public static URL getResource(Class<?> cl, String path) throws IOException {
String clp = cl.getName().replace('.', '/') + ".class";
URL clu = cl.getClassLoader().getResource(clp);
String s = clu.toString();
if (s.endsWith(clp))
return new URL(s.substring(0, s.length() - clp.length()) + path);
if (s.startsWith("jar:")) {
String[] ss = s.split("!");
return new URL(ss[1] + "!/" + path);
}
return null;
}
public static List<URL> listFiles(URL directory) throws IOException {
List<URL> ret = new ArrayList<URL>();
String s = directory.toString();
if (s.startsWith("jar:")) {
String[] ss = s.substring("jar:".length()).split("!");
String path = ss[1];
URL target = new URL(ss[0]);
InputStream tin = target.openStream();
try {
JarInputStream jin = new JarInputStream(tin);
JarEntry je;
while ((je = jin.getNextJarEntry()) != null) {
String p = "/" + je.getName();
if (p.startsWith(path) && p.indexOf('/', path.length() + 1) < 0)
ret.add(new URL("jar:" + target + "!" + p));
}
} finally {
tin.close();
}
} else if (s.startsWith("file:")) {
File f = new File(directory.getFile());
File[] ffs = f.listFiles();
if (ffs != null)
for (File ff : ffs)
ret.add(ff.toURI().toURL());
} else
throw new IOException("Cannot list contents of " + directory);
return ret;
}
}

573
ext/libnatpmp/getgateway.c Normal file
View File

@ -0,0 +1,573 @@
/* $Id: getgateway.c,v 1.25 2014/04/22 10:28:57 nanard Exp $ */
/* libnatpmp
Copyright (c) 2007-2014, Thomas BERNARD
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <ctype.h>
#ifndef WIN32
#include <netinet/in.h>
#endif
#if !defined(_MSC_VER)
#include <sys/param.h>
#endif
/* There is no portable method to get the default route gateway.
* So below are four (or five ?) differents functions implementing this.
* Parsing /proc/net/route is for linux.
* sysctl is the way to access such informations on BSD systems.
* Many systems should provide route information through raw PF_ROUTE
* sockets.
* In MS Windows, default gateway is found by looking into the registry
* or by using GetBestRoute(). */
#ifdef __linux__
#define USE_PROC_NET_ROUTE
#undef USE_SOCKET_ROUTE
#undef USE_SYSCTL_NET_ROUTE
#endif
#if defined(BSD) || defined(__FreeBSD_kernel__)
#undef USE_PROC_NET_ROUTE
#define USE_SOCKET_ROUTE
#undef USE_SYSCTL_NET_ROUTE
#endif
#ifdef __APPLE__
#undef USE_PROC_NET_ROUTE
#undef USE_SOCKET_ROUTE
#define USE_SYSCTL_NET_ROUTE
#endif
#if (defined(sun) && defined(__SVR4))
#undef USE_PROC_NET_ROUTE
#define USE_SOCKET_ROUTE
#undef USE_SYSCTL_NET_ROUTE
#endif
#ifdef WIN32
#undef USE_PROC_NET_ROUTE
#undef USE_SOCKET_ROUTE
#undef USE_SYSCTL_NET_ROUTE
//#define USE_WIN32_CODE
#define USE_WIN32_CODE_2
#endif
#ifdef __CYGWIN__
#undef USE_PROC_NET_ROUTE
#undef USE_SOCKET_ROUTE
#undef USE_SYSCTL_NET_ROUTE
#define USE_WIN32_CODE
#include <stdarg.h>
#include <w32api/windef.h>
#include <w32api/winbase.h>
#include <w32api/winreg.h>
#endif
#ifdef __HAIKU__
#include <stdlib.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/sockio.h>
#define USE_HAIKU_CODE
#endif
#ifdef USE_SYSCTL_NET_ROUTE
#include <stdlib.h>
#include <sys/sysctl.h>
#include <sys/socket.h>
#include <net/route.h>
#endif
#ifdef USE_SOCKET_ROUTE
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/route.h>
#endif
#ifdef USE_WIN32_CODE
#include <unknwn.h>
#include <winreg.h>
#define MAX_KEY_LENGTH 255
#define MAX_VALUE_LENGTH 16383
#endif
#ifdef USE_WIN32_CODE_2
#include <windows.h>
#include <iphlpapi.h>
#endif
#include "getgateway.h"
#ifndef WIN32
#define SUCCESS (0)
#define FAILED (-1)
#endif
#ifdef USE_PROC_NET_ROUTE
/*
parse /proc/net/route which is as follow :
Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
wlan0 0001A8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0
eth0 0000FEA9 00000000 0001 0 0 0 0000FFFF 0 0 0
wlan0 00000000 0101A8C0 0003 0 0 0 00000000 0 0 0
eth0 00000000 00000000 0001 0 0 1000 00000000 0 0 0
One header line, and then one line by route by route table entry.
*/
int getdefaultgateway(in_addr_t * addr)
{
unsigned long d, g;
char buf[256];
int line = 0;
FILE * f;
char * p;
f = fopen("/proc/net/route", "r");
if(!f)
return FAILED;
while(fgets(buf, sizeof(buf), f)) {
if(line > 0) { /* skip the first line */
p = buf;
/* skip the interface name */
while(*p && !isspace(*p))
p++;
while(*p && isspace(*p))
p++;
if(sscanf(p, "%lx%lx", &d, &g)==2) {
if(d == 0 && g != 0) { /* default */
*addr = g;
fclose(f);
return SUCCESS;
}
}
}
line++;
}
/* default route not found ! */
if(f)
fclose(f);
return FAILED;
}
#endif /* #ifdef USE_PROC_NET_ROUTE */
#ifdef USE_SYSCTL_NET_ROUTE
#define ROUNDUP(a) \
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
int getdefaultgateway(in_addr_t * addr)
{
#if 0
/* net.route.0.inet.dump.0.0 ? */
int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET,
NET_RT_DUMP, 0, 0/*tableid*/};
#endif
/* net.route.0.inet.flags.gateway */
int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET,
NET_RT_FLAGS, RTF_GATEWAY};
size_t l;
char * buf, * p;
struct rt_msghdr * rt;
struct sockaddr * sa;
struct sockaddr * sa_tab[RTAX_MAX];
int i;
int r = FAILED;
if(sysctl(mib, sizeof(mib)/sizeof(int), 0, &l, 0, 0) < 0) {
return FAILED;
}
if(l>0) {
buf = malloc(l);
if(sysctl(mib, sizeof(mib)/sizeof(int), buf, &l, 0, 0) < 0) {
free(buf);
return FAILED;
}
for(p=buf; p<buf+l; p+=rt->rtm_msglen) {
rt = (struct rt_msghdr *)p;
sa = (struct sockaddr *)(rt + 1);
for(i=0; i<RTAX_MAX; i++) {
if(rt->rtm_addrs & (1 << i)) {
sa_tab[i] = sa;
sa = (struct sockaddr *)((char *)sa + ROUNDUP(sa->sa_len));
} else {
sa_tab[i] = NULL;
}
}
if( ((rt->rtm_addrs & (RTA_DST|RTA_GATEWAY)) == (RTA_DST|RTA_GATEWAY))
&& sa_tab[RTAX_DST]->sa_family == AF_INET
&& sa_tab[RTAX_GATEWAY]->sa_family == AF_INET) {
if(((struct sockaddr_in *)sa_tab[RTAX_DST])->sin_addr.s_addr == 0) {
*addr = ((struct sockaddr_in *)(sa_tab[RTAX_GATEWAY]))->sin_addr.s_addr;
r = SUCCESS;
}
}
}
free(buf);
}
return r;
}
#endif /* #ifdef USE_SYSCTL_NET_ROUTE */
#ifdef USE_SOCKET_ROUTE
/* Thanks to Darren Kenny for this code */
#define NEXTADDR(w, u) \
if (rtm_addrs & (w)) {\
l = sizeof(struct sockaddr); memmove(cp, &(u), l); cp += l;\
}
#define rtm m_rtmsg.m_rtm
struct {
struct rt_msghdr m_rtm;
char m_space[512];
} m_rtmsg;
int getdefaultgateway(in_addr_t *addr)
{
int s, seq, l, rtm_addrs, i;
pid_t pid;
struct sockaddr so_dst, so_mask;
char *cp = m_rtmsg.m_space;
struct sockaddr *gate = NULL, *sa;
struct rt_msghdr *msg_hdr;
pid = getpid();
seq = 0;
rtm_addrs = RTA_DST | RTA_NETMASK;
memset(&so_dst, 0, sizeof(so_dst));
memset(&so_mask, 0, sizeof(so_mask));
memset(&rtm, 0, sizeof(struct rt_msghdr));
rtm.rtm_type = RTM_GET;
rtm.rtm_flags = RTF_UP | RTF_GATEWAY;
rtm.rtm_version = RTM_VERSION;
rtm.rtm_seq = ++seq;
rtm.rtm_addrs = rtm_addrs;
so_dst.sa_family = AF_INET;
so_mask.sa_family = AF_INET;
NEXTADDR(RTA_DST, so_dst);
NEXTADDR(RTA_NETMASK, so_mask);
rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
s = socket(PF_ROUTE, SOCK_RAW, 0);
if (write(s, (char *)&m_rtmsg, l) < 0) {
close(s);
return FAILED;
}
do {
l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
} while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
close(s);
msg_hdr = &rtm;
cp = ((char *)(msg_hdr + 1));
if (msg_hdr->rtm_addrs) {
for (i = 1; i; i <<= 1)
if (i & msg_hdr->rtm_addrs) {
sa = (struct sockaddr *)cp;
if (i == RTA_GATEWAY )
gate = sa;
cp += sizeof(struct sockaddr);
}
} else {
return FAILED;
}
if (gate != NULL ) {
*addr = ((struct sockaddr_in *)gate)->sin_addr.s_addr;
return SUCCESS;
} else {
return FAILED;
}
}
#endif /* #ifdef USE_SOCKET_ROUTE */
#ifdef USE_WIN32_CODE
LIBSPEC int getdefaultgateway(in_addr_t * addr)
{
HKEY networkCardsKey;
HKEY networkCardKey;
HKEY interfacesKey;
HKEY interfaceKey;
DWORD i = 0;
DWORD numSubKeys = 0;
TCHAR keyName[MAX_KEY_LENGTH];
DWORD keyNameLength = MAX_KEY_LENGTH;
TCHAR keyValue[MAX_VALUE_LENGTH];
DWORD keyValueLength = MAX_VALUE_LENGTH;
DWORD keyValueType = REG_SZ;
TCHAR gatewayValue[MAX_VALUE_LENGTH];
DWORD gatewayValueLength = MAX_VALUE_LENGTH;
DWORD gatewayValueType = REG_MULTI_SZ;
int done = 0;
//const char * networkCardsPath = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards";
//const char * interfacesPath = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces";
#ifdef UNICODE
LPCTSTR networkCardsPath = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards";
LPCTSTR interfacesPath = L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces";
#define STR_SERVICENAME L"ServiceName"
#define STR_DHCPDEFAULTGATEWAY L"DhcpDefaultGateway"
#define STR_DEFAULTGATEWAY L"DefaultGateway"
#else
LPCTSTR networkCardsPath = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards";
LPCTSTR interfacesPath = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces";
#define STR_SERVICENAME "ServiceName"
#define STR_DHCPDEFAULTGATEWAY "DhcpDefaultGateway"
#define STR_DEFAULTGATEWAY "DefaultGateway"
#endif
// The windows registry lists its primary network devices in the following location:
// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkCards
//
// Each network device has its own subfolder, named with an index, with various properties:
// -NetworkCards
// -5
// -Description = Broadcom 802.11n Network Adapter
// -ServiceName = {E35A72F8-5065-4097-8DFE-C7790774EE4D}
// -8
// -Description = Marvell Yukon 88E8058 PCI-E Gigabit Ethernet Controller
// -ServiceName = {86226414-5545-4335-A9D1-5BD7120119AD}
//
// The above service name is the name of a subfolder within:
// HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces
//
// There may be more subfolders in this interfaces path than listed in the network cards path above:
// -Interfaces
// -{3a539854-6a70-11db-887c-806e6f6e6963}
// -DhcpIPAddress = 0.0.0.0
// -[more]
// -{E35A72F8-5065-4097-8DFE-C7790774EE4D}
// -DhcpIPAddress = 10.0.1.4
// -DhcpDefaultGateway = 10.0.1.1
// -[more]
// -{86226414-5545-4335-A9D1-5BD7120119AD}
// -DhcpIpAddress = 10.0.1.5
// -DhcpDefaultGateay = 10.0.1.1
// -[more]
//
// In order to extract this information, we enumerate each network card, and extract the ServiceName value.
// This is then used to open the interface subfolder, and attempt to extract a DhcpDefaultGateway value.
// Once one is found, we're done.
//
// It may be possible to simply enumerate the interface folders until we find one with a DhcpDefaultGateway value.
// However, the technique used is the technique most cited on the web, and we assume it to be more correct.
if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, // Open registry key or predifined key
networkCardsPath, // Name of registry subkey to open
0, // Reserved - must be zero
KEY_READ, // Mask - desired access rights
&networkCardsKey)) // Pointer to output key
{
// Unable to open network cards keys
return -1;
}
if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, // Open registry key or predefined key
interfacesPath, // Name of registry subkey to open
0, // Reserved - must be zero
KEY_READ, // Mask - desired access rights
&interfacesKey)) // Pointer to output key
{
// Unable to open interfaces key
RegCloseKey(networkCardsKey);
return -1;
}
// Figure out how many subfolders are within the NetworkCards folder
RegQueryInfoKey(networkCardsKey, NULL, NULL, NULL, &numSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
//printf( "Number of subkeys: %u\n", (unsigned int)numSubKeys);
// Enumrate through each subfolder within the NetworkCards folder
for(i = 0; i < numSubKeys && !done; i++)
{
keyNameLength = MAX_KEY_LENGTH;
if(ERROR_SUCCESS == RegEnumKeyEx(networkCardsKey, // Open registry key
i, // Index of subkey to retrieve
keyName, // Buffer that receives the name of the subkey
&keyNameLength, // Variable that receives the size of the above buffer
NULL, // Reserved - must be NULL
NULL, // Buffer that receives the class string
NULL, // Variable that receives the size of the above buffer
NULL)) // Variable that receives the last write time of subkey
{
if(RegOpenKeyEx(networkCardsKey, keyName, 0, KEY_READ, &networkCardKey) == ERROR_SUCCESS)
{
keyValueLength = MAX_VALUE_LENGTH;
if(ERROR_SUCCESS == RegQueryValueEx(networkCardKey, // Open registry key
STR_SERVICENAME, // Name of key to query
NULL, // Reserved - must be NULL
&keyValueType, // Receives value type
(LPBYTE)keyValue, // Receives value
&keyValueLength)) // Receives value length in bytes
{
// printf("keyValue: %s\n", keyValue);
if(RegOpenKeyEx(interfacesKey, keyValue, 0, KEY_READ, &interfaceKey) == ERROR_SUCCESS)
{
gatewayValueLength = MAX_VALUE_LENGTH;
if(ERROR_SUCCESS == RegQueryValueEx(interfaceKey, // Open registry key
STR_DHCPDEFAULTGATEWAY, // Name of key to query
NULL, // Reserved - must be NULL
&gatewayValueType, // Receives value type
(LPBYTE)gatewayValue, // Receives value
&gatewayValueLength)) // Receives value length in bytes
{
// Check to make sure it's a string
if((gatewayValueType == REG_MULTI_SZ || gatewayValueType == REG_SZ) && (gatewayValueLength > 1))
{
//printf("gatewayValue: %s\n", gatewayValue);
done = 1;
}
}
else if(ERROR_SUCCESS == RegQueryValueEx(interfaceKey, // Open registry key
STR_DEFAULTGATEWAY, // Name of key to query
NULL, // Reserved - must be NULL
&gatewayValueType, // Receives value type
(LPBYTE)gatewayValue,// Receives value
&gatewayValueLength)) // Receives value length in bytes
{
// Check to make sure it's a string
if((gatewayValueType == REG_MULTI_SZ || gatewayValueType == REG_SZ) && (gatewayValueLength > 1))
{
//printf("gatewayValue: %s\n", gatewayValue);
done = 1;
}
}
RegCloseKey(interfaceKey);
}
}
RegCloseKey(networkCardKey);
}
}
}
RegCloseKey(interfacesKey);
RegCloseKey(networkCardsKey);
if(done)
{
#if UNICODE
char tmp[32];
for(i = 0; i < 32; i++) {
tmp[i] = (char)gatewayValue[i];
if(!tmp[i])
break;
}
tmp[31] = '\0';
*addr = inet_addr(tmp);
#else
*addr = inet_addr(gatewayValue);
#endif
return 0;
}
return -1;
}
#endif /* #ifdef USE_WIN32_CODE */
#ifdef USE_WIN32_CODE_2
int getdefaultgateway(in_addr_t *addr)
{
MIB_IPFORWARDROW ip_forward;
memset(&ip_forward, 0, sizeof(ip_forward));
if(GetBestRoute(inet_addr("0.0.0.0"), 0, &ip_forward) != NO_ERROR)
return -1;
*addr = ip_forward.dwForwardNextHop;
return 0;
}
#endif /* #ifdef USE_WIN32_CODE_2 */
#ifdef USE_HAIKU_CODE
int getdefaultgateway(in_addr_t *addr)
{
int fd, ret = -1;
struct ifconf config;
void *buffer = NULL;
struct ifreq *interface;
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
return -1;
}
if (ioctl(fd, SIOCGRTSIZE, &config, sizeof(config)) != 0) {
goto fail;
}
if (config.ifc_value < 1) {
goto fail; /* No routes */
}
if ((buffer = malloc(config.ifc_value)) == NULL) {
goto fail;
}
config.ifc_len = config.ifc_value;
config.ifc_buf = buffer;
if (ioctl(fd, SIOCGRTTABLE, &config, sizeof(config)) != 0) {
goto fail;
}
for (interface = buffer;
(uint8_t *)interface < (uint8_t *)buffer + config.ifc_len; ) {
struct route_entry route = interface->ifr_route;
int intfSize;
if (route.flags & (RTF_GATEWAY | RTF_DEFAULT)) {
*addr = ((struct sockaddr_in *)route.gateway)->sin_addr.s_addr;
ret = 0;
break;
}
intfSize = sizeof(route) + IF_NAMESIZE;
if (route.destination != NULL) {
intfSize += route.destination->sa_len;
}
if (route.mask != NULL) {
intfSize += route.mask->sa_len;
}
if (route.gateway != NULL) {
intfSize += route.gateway->sa_len;
}
interface = (struct ifreq *)((uint8_t *)interface + intfSize);
}
fail:
free(buffer);
close(fd);
return ret;
}
#endif /* #ifdef USE_HAIKU_CODE */
#if !defined(USE_PROC_NET_ROUTE) && !defined(USE_SOCKET_ROUTE) && !defined(USE_SYSCTL_NET_ROUTE) && !defined(USE_WIN32_CODE) && !defined(USE_WIN32_CODE_2) && !defined(USE_HAIKU_CODE)
int getdefaultgateway(in_addr_t * addr)
{
return -1;
}
#endif

View File

@ -0,0 +1,49 @@
/* $Id: getgateway.h,v 1.8 2014/04/22 09:15:40 nanard Exp $ */
/* libnatpmp
Copyright (c) 2007-2014, Thomas BERNARD
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __GETGATEWAY_H__
#define __GETGATEWAY_H__
#ifdef WIN32
#if !defined(_MSC_VER) || _MSC_VER >= 1600
#include <stdint.h>
#else
typedef unsigned long uint32_t;
typedef unsigned short uint16_t;
#endif
#define in_addr_t uint32_t
#endif
/* #include "declspec.h" */
/* getdefaultgateway() :
* return value :
* 0 : success
* -1 : failure */
/* LIBSPEC */int getdefaultgateway(in_addr_t * addr);
#endif

View File

@ -0,0 +1,281 @@
/* $Id: libnatpmpmodule.c,v 1.7 2012/03/05 19:38:37 nanard Exp $ */
/* libnatpmp
* http://miniupnp.free.fr/libnatpmp.html
Copyright (c) 2007-2011, Thomas BERNARD
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include <Python.h>
#ifdef WIN32
#include <winsock2.h>
#else
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
#define STATICLIB
#include "structmember.h"
#include "natpmp.h"
/* for compatibility with Python < 2.4 */
#ifndef Py_RETURN_NONE
#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
#endif
#ifndef Py_RETURN_TRUE
#define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True
#endif
#ifndef Py_RETURN_FALSE
#define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False
#endif
typedef struct {
PyObject_HEAD
/* Type-specific fields go here. */
unsigned int discoverdelay;
natpmp_t natpmp;
} NATPMPObject;
static PyMemberDef NATPMP_members[] = {
{"discoverdelay", T_UINT, offsetof(NATPMPObject, discoverdelay),
0/*READWRITE*/, "value in ms used to wait for NATPMP responses"
},
{NULL}
};
static PyObject *
NATPMPObject_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
NATPMPObject *self;
self = (NATPMPObject *)type->tp_alloc(type, 0);
if (self) {
initnatpmp(&self->natpmp, 0, 0);
}
return (PyObject *)self;
}
static void
NATPMPObject_dealloc(NATPMPObject *self)
{
closenatpmp(&self->natpmp);
self->ob_type->tp_free((PyObject*)self);
}
static PyObject *
NATPMP_externalipaddress(NATPMPObject *self)
{
int r;
struct timeval timeout;
fd_set fds;
natpmpresp_t response;
r = sendpublicaddressrequest(&self->natpmp);
if (r < 0) {
#ifdef ENABLE_STRNATPMPERR
PyErr_SetString(PyExc_Exception, strnatpmperr(r));
#endif
return NULL;
}
do {
FD_ZERO(&fds);
FD_SET(self->natpmp.s, &fds);
getnatpmprequesttimeout(&self->natpmp, &timeout);
select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
r = readnatpmpresponseorretry(&self->natpmp, &response);
if (r < 0 && r != NATPMP_TRYAGAIN) {
#ifdef ENABLE_STRNATPMPERR
PyErr_SetString(PyExc_Exception, strnatpmperr(r));
#endif
return NULL;
}
} while (r == NATPMP_TRYAGAIN);
return Py_BuildValue("s", inet_ntoa(response.pnu.publicaddress.addr));
}
static PyObject *
NATPMP_domapping(natpmp_t *n, unsigned short eport, unsigned short iport,
const char *protocol, unsigned int lifetime)
{
int proto;
struct timeval timeout;
fd_set fds;
natpmpresp_t response;
int r;
if (!strncasecmp("tcp", protocol, 3)) {
proto = NATPMP_PROTOCOL_TCP;
} else if (!strncasecmp("udp", protocol, 3)) {
proto = NATPMP_PROTOCOL_UDP;
} else {
PyErr_SetString(PyExc_Exception, "Unknown protocol");
return NULL;
}
r = sendnewportmappingrequest(n, proto, iport, eport,
lifetime);
if (r < 0) {
#ifdef ENABLE_STRNATPMPERR
PyErr_SetString(PyExc_Exception, strnatpmperr(r));
#endif
return NULL;
}
do {
FD_ZERO(&fds);
FD_SET(n->s, &fds);
getnatpmprequesttimeout(n, &timeout);
select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
r = readnatpmpresponseorretry(n, &response);
if (r < 0 && r != NATPMP_TRYAGAIN) {
#ifdef ENABLE_STRNATPMPERR
PyErr_SetString(PyExc_Exception, strnatpmperr(r));
#endif
return NULL;
}
} while (r == NATPMP_TRYAGAIN);
return Py_BuildValue("H", response.pnu.newportmapping.mappedpublicport);
}
/* AddPortMapping(externalPort, protocol, internalPort, lifetime)
* protocol is 'UDP' or 'TCP' */
static PyObject *
NATPMP_addportmapping(NATPMPObject *self, PyObject *args)
{
unsigned short eport;
unsigned short iport;
unsigned int lifetime;
const char *protocol;
if (!PyArg_ParseTuple(args, "HsHI", &eport, &protocol, &iport, &lifetime))
return NULL;
return NATPMP_domapping(&self->natpmp, eport, iport, protocol, lifetime);
}
/* DeletePortMapping(externalPort, protocol, internalPort)
* protocol is 'UDP' or 'TCP' */
static PyObject *
NATPMP_deleteportmapping(NATPMPObject *self, PyObject *args)
{
unsigned short eport;
unsigned short iport;
const char *protocol;
if (!PyArg_ParseTuple(args, "HsH", &eport, &protocol, &iport))
return NULL;
return NATPMP_domapping(&self->natpmp, eport, iport, protocol, 0);
}
/* natpmp.NATPMP object Method Table */
static PyMethodDef NATPMP_methods[] = {
{"externalipaddress", (PyCFunction)NATPMP_externalipaddress, METH_NOARGS,
"return external IP address"
},
{"addportmapping", (PyCFunction)NATPMP_addportmapping, METH_VARARGS,
"add a port mapping"
},
{"deleteportmapping", (PyCFunction)NATPMP_deleteportmapping, METH_VARARGS,
"delete a port mapping"
},
{NULL} /* Sentinel */
};
static PyTypeObject NATPMPType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"libnatpmp.NATPMP", /*tp_name*/
sizeof(NATPMPObject), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor)NATPMPObject_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /*tp_flags*/
"NATPMP objects", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
NATPMP_methods, /* tp_methods */
NATPMP_members, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
NATPMPObject_new, /* tp_new */
};
/* module methods */
static PyMethodDef libnatpmp_methods[] = {
{NULL} /* Sentinel */
};
#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
#define PyMODINIT_FUNC void
#endif
PyMODINIT_FUNC
initlibnatpmp(void)
{
PyObject* m;
if (PyType_Ready(&NATPMPType) < 0)
return;
m = Py_InitModule3("libnatpmp", libnatpmp_methods,
"libnatpmp module.");
Py_INCREF(&NATPMPType);
PyModule_AddObject(m, "NATPMP", (PyObject *)&NATPMPType);
}

View File

@ -0,0 +1,29 @@

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual C++ Express 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libnatpmp", "libnatpmp.vcproj", "{D59B6527-F3DE-4D26-A08D-52F1EE989301}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "natpmpc-static", "natpmpc-static.vcproj", "{A0B49FA9-98AB-4A74-8B4C-8AB7FA36089B}"
ProjectSection(ProjectDependencies) = postProject
{D59B6527-F3DE-4D26-A08D-52F1EE989301} = {D59B6527-F3DE-4D26-A08D-52F1EE989301}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D59B6527-F3DE-4D26-A08D-52F1EE989301}.Debug|Win32.ActiveCfg = Debug|Win32
{D59B6527-F3DE-4D26-A08D-52F1EE989301}.Debug|Win32.Build.0 = Debug|Win32
{D59B6527-F3DE-4D26-A08D-52F1EE989301}.Release|Win32.ActiveCfg = Release|Win32
{D59B6527-F3DE-4D26-A08D-52F1EE989301}.Release|Win32.Build.0 = Release|Win32
{A0B49FA9-98AB-4A74-8B4C-8AB7FA36089B}.Debug|Win32.ActiveCfg = Debug|Win32
{A0B49FA9-98AB-4A74-8B4C-8AB7FA36089B}.Debug|Win32.Build.0 = Debug|Win32
{A0B49FA9-98AB-4A74-8B4C-8AB7FA36089B}.Release|Win32.ActiveCfg = Release|Win32
{A0B49FA9-98AB-4A74-8B4C-8AB7FA36089B}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,195 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9,00"
Name="libnatpmp"
ProjectGUID="{D59B6527-F3DE-4D26-A08D-52F1EE989301}"
RootNamespace="libnatpmp"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;STATICLIB"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;STATICLIB"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Fichiers sources"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="..\getgateway.c"
>
</File>
<File
RelativePath="..\natpmp.c"
>
</File>
<File
RelativePath="..\wingettimeofday.c"
>
</File>
</Filter>
<Filter
Name="Fichiers d&apos;en-tête"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath="..\declspec.h"
>
</File>
<File
RelativePath="..\getgateway.h"
>
</File>
<File
RelativePath="..\natpmp.h"
>
</File>
<File
RelativePath="..\wingettimeofday.h"
>
</File>
</Filter>
<Filter
Name="Fichiers de ressources"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -0,0 +1,195 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9,00"
Name="natpmpc-static"
ProjectGUID="{A0B49FA9-98AB-4A74-8B4C-8AB7FA36089B}"
RootNamespace="natpmpcstatic"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;STATICLIB;_CRT_SECURE_NO_WARNINGS"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="ws2_32.lib Iphlpapi.lib"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;STATICLIB;_CRT_SECURE_NO_WARNINGS"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="ws2_32.lib iphlpapi.lib"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Fichiers sources"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="..\natpmpc.c"
>
</File>
</Filter>
<Filter
Name="Fichiers d&apos;en-tête"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
</Filter>
<Filter
Name="Fichiers de ressources"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

157
ext/libnatpmp/natpmp-jni.c Normal file
View File

@ -0,0 +1,157 @@
#ifdef __CYGWIN__
#include <stdint.h>
#define __int64 uint64_t
#endif
#ifdef WIN32
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
#include <stdlib.h>
#include "natpmp.h"
#include "fr_free_miniupnp_libnatpmp_NatPmp.h"
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT void JNICALL Java_fr_free_miniupnp_libnatpmp_NatPmp_init (JNIEnv *env, jobject obj, jint forcegw, jint forcedgw) {
natpmp_t *p = malloc (sizeof(natpmp_t));
if (p == NULL) return;
initnatpmp(p, forcegw, (in_addr_t) forcedgw);
jobject wrapped = (*env)->NewDirectByteBuffer(env, p, sizeof(natpmp_t));
if (wrapped == NULL) return;
jclass thisClass = (*env)->GetObjectClass(env,obj);
if (thisClass == NULL) return;
jfieldID fid = (*env)->GetFieldID(env, thisClass, "natpmp", "Ljava/nio/ByteBuffer;");
if (fid == NULL) return;
(*env)->SetObjectField(env, obj, fid, wrapped);
}
JNIEXPORT void JNICALL Java_fr_free_miniupnp_libnatpmp_NatPmp_free (JNIEnv *env, jobject obj) {
jclass thisClass = (*env)->GetObjectClass(env,obj);
if (thisClass == NULL) return;
jfieldID fid = (*env)->GetFieldID(env, thisClass, "natpmp", "Ljava/nio/ByteBuffer;");
if (fid == NULL) return;
jobject wrapped = (*env)->GetObjectField(env, obj, fid);
if (wrapped == NULL) return;
natpmp_t* natpmp = (natpmp_t*) (*env)->GetDirectBufferAddress(env, wrapped);
closenatpmp(natpmp);
if (natpmp == NULL) return;
free(natpmp);
(*env)->SetObjectField(env, obj, fid, NULL);
}
static natpmp_t* getNatPmp(JNIEnv* env, jobject obj) {
jclass thisClass = (*env)->GetObjectClass(env,obj);
if (thisClass == NULL) return NULL;
jfieldID fid = (*env)->GetFieldID(env, thisClass, "natpmp", "Ljava/nio/ByteBuffer;");
if (fid == NULL) return NULL;
jobject wrapped = (*env)->GetObjectField(env, obj, fid);
if (wrapped == NULL) return NULL;
natpmp_t* natpmp = (natpmp_t*) (*env)->GetDirectBufferAddress(env, wrapped);
return natpmp;
}
JNIEXPORT jint JNICALL Java_fr_free_miniupnp_libnatpmp_NatPmp_sendPublicAddressRequest(JNIEnv* env, jobject obj) {
natpmp_t* natpmp = getNatPmp(env, obj);
if (natpmp == NULL) return -1;
return sendpublicaddressrequest(natpmp);
}
JNIEXPORT void JNICALL Java_fr_free_miniupnp_libnatpmp_NatPmp_startup(JNIEnv* env, jclass cls) {
(void)env;
(void)cls;
#ifdef WIN32
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(2, 2);
WSAStartup(wVersionRequested, &wsaData);
#endif
}
JNIEXPORT jint JNICALL Java_fr_free_miniupnp_libnatpmp_NatPmp_sendNewPortMappingRequest(JNIEnv* env, jobject obj, jint protocol, jint privateport, jint publicport, jint lifetime) {
natpmp_t* natpmp = getNatPmp(env, obj);
if (natpmp == NULL) return -1;
return sendnewportmappingrequest(natpmp, protocol, privateport, publicport, lifetime);
}
JNIEXPORT jlong JNICALL Java_fr_free_miniupnp_libnatpmp_NatPmp_getNatPmpRequestTimeout(JNIEnv* env, jobject obj) {
natpmp_t* natpmp = getNatPmp(env, obj);
struct timeval timeout;
getnatpmprequesttimeout(natpmp, &timeout);
return ((jlong) timeout.tv_sec) * 1000 + (timeout.tv_usec / 1000);
}
#define SET_FIELD(prefix, name, type, longtype) { \
jfieldID fid = (*env)->GetFieldID(env, thisClass, #name, type); \
if (fid == NULL) return -1; \
(*env)->Set ## longtype ## Field(env, response, fid, resp. prefix name); \
}
JNIEXPORT jint JNICALL Java_fr_free_miniupnp_libnatpmp_NatPmp_readNatPmpResponseOrRetry(JNIEnv* env, jobject obj, jobject response) {
natpmp_t* natpmp = getNatPmp(env, obj);
natpmpresp_t resp;
int result = readnatpmpresponseorretry(natpmp, &resp);
if (result != 0) {
return result;
}
jclass thisClass = (*env)->GetObjectClass(env, response);
if (thisClass == NULL) return -1;
SET_FIELD(,type, "S", Short);
SET_FIELD(,resultcode, "S", Short);
jfieldID fid = (*env)->GetFieldID(env, thisClass, "epoch", "J");
if (fid == NULL) return -1;
(*env)->SetLongField(env, response, fid, ((jlong)resp.epoch) * 1000);
if (resp.type == 0) {
jfieldID fid = (*env)->GetFieldID(env, thisClass, "addr", "I");
if (fid == NULL) return -1;
(*env)->SetIntField(env, response, fid, resp.pnu.publicaddress.addr.s_addr);
} else {
SET_FIELD(pnu.newportmapping., privateport, "I", Int);
SET_FIELD(pnu.newportmapping., mappedpublicport, "I", Int);
jfieldID fid = (*env)->GetFieldID(env, thisClass, "lifetime", "J");
if (fid == NULL) return -1;
(*env)->SetLongField(env, response, fid, ((jlong) resp.pnu.newportmapping.lifetime) * 1000 * 1000);
}
return result;
}
#ifdef __cplusplus
}
#endif

379
ext/libnatpmp/natpmp.c Normal file
View File

@ -0,0 +1,379 @@
/* $Id: natpmp.c,v 1.20 2015/05/27 12:43:15 nanard Exp $ */
/* libnatpmp
Copyright (c) 2007-2015, Thomas BERNARD
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef __linux__
#define _BSD_SOURCE 1
#endif
#include <string.h>
#include <time.h>
#if !defined(_MSC_VER)
#include <sys/time.h>
#endif
#ifdef WIN32
#include <errno.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <io.h>
#define EWOULDBLOCK WSAEWOULDBLOCK
#define ECONNREFUSED WSAECONNREFUSED
#include "wingettimeofday.h"
#define gettimeofday natpmp_gettimeofday
#else
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#define closesocket close
#endif
#include "natpmp.h"
#include "getgateway.h"
#include <stdio.h>
LIBSPEC int initnatpmp(natpmp_t * p, int forcegw, in_addr_t forcedgw)
{
#ifdef WIN32
u_long ioctlArg = 1;
#else
int flags;
#endif
struct sockaddr_in addr;
if(!p)
return NATPMP_ERR_INVALIDARGS;
memset(p, 0, sizeof(natpmp_t));
p->s = socket(PF_INET, SOCK_DGRAM, 0);
if(p->s < 0)
return NATPMP_ERR_SOCKETERROR;
#ifdef WIN32
if(ioctlsocket(p->s, FIONBIO, &ioctlArg) == SOCKET_ERROR)
return NATPMP_ERR_FCNTLERROR;
#else
if((flags = fcntl(p->s, F_GETFL, 0)) < 0)
return NATPMP_ERR_FCNTLERROR;
if(fcntl(p->s, F_SETFL, flags | O_NONBLOCK) < 0)
return NATPMP_ERR_FCNTLERROR;
#endif
if(forcegw) {
p->gateway = forcedgw;
} else {
if(getdefaultgateway(&(p->gateway)) < 0)
return NATPMP_ERR_CANNOTGETGATEWAY;
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(NATPMP_PORT);
addr.sin_addr.s_addr = p->gateway;
if(connect(p->s, (struct sockaddr *)&addr, sizeof(addr)) < 0)
return NATPMP_ERR_CONNECTERR;
return 0;
}
LIBSPEC int closenatpmp(natpmp_t * p)
{
if(!p)
return NATPMP_ERR_INVALIDARGS;
if(closesocket(p->s) < 0)
return NATPMP_ERR_CLOSEERR;
return 0;
}
int sendpendingrequest(natpmp_t * p)
{
int r;
/* struct sockaddr_in addr;*/
if(!p)
return NATPMP_ERR_INVALIDARGS;
/* memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(NATPMP_PORT);
addr.sin_addr.s_addr = p->gateway;
r = (int)sendto(p->s, p->pending_request, p->pending_request_len, 0,
(struct sockaddr *)&addr, sizeof(addr));*/
r = (int)send(p->s, (const char *)p->pending_request, p->pending_request_len, 0);
return (r<0) ? NATPMP_ERR_SENDERR : r;
}
int sendnatpmprequest(natpmp_t * p)
{
int n;
if(!p)
return NATPMP_ERR_INVALIDARGS;
/* TODO : check if no request is already pending */
p->has_pending_request = 1;
p->try_number = 1;
n = sendpendingrequest(p);
gettimeofday(&p->retry_time, NULL); // check errors !
p->retry_time.tv_usec += 250000; /* add 250ms */
if(p->retry_time.tv_usec >= 1000000) {
p->retry_time.tv_usec -= 1000000;
p->retry_time.tv_sec++;
}
return n;
}
LIBSPEC int getnatpmprequesttimeout(natpmp_t * p, struct timeval * timeout)
{
struct timeval now;
if(!p || !timeout)
return NATPMP_ERR_INVALIDARGS;
if(!p->has_pending_request)
return NATPMP_ERR_NOPENDINGREQ;
if(gettimeofday(&now, NULL) < 0)
return NATPMP_ERR_GETTIMEOFDAYERR;
timeout->tv_sec = p->retry_time.tv_sec - now.tv_sec;
timeout->tv_usec = p->retry_time.tv_usec - now.tv_usec;
if(timeout->tv_usec < 0) {
timeout->tv_usec += 1000000;
timeout->tv_sec--;
}
return 0;
}
LIBSPEC int sendpublicaddressrequest(natpmp_t * p)
{
if(!p)
return NATPMP_ERR_INVALIDARGS;
//static const unsigned char request[] = { 0, 0 };
p->pending_request[0] = 0;
p->pending_request[1] = 0;
p->pending_request_len = 2;
// TODO: return 0 instead of sizeof(request) ??
return sendnatpmprequest(p);
}
LIBSPEC int sendnewportmappingrequest(natpmp_t * p, int protocol,
uint16_t privateport, uint16_t publicport,
uint32_t lifetime)
{
if(!p || (protocol!=NATPMP_PROTOCOL_TCP && protocol!=NATPMP_PROTOCOL_UDP))
return NATPMP_ERR_INVALIDARGS;
p->pending_request[0] = 0;
p->pending_request[1] = protocol;
p->pending_request[2] = 0;
p->pending_request[3] = 0;
/* break strict-aliasing rules :
*((uint16_t *)(p->pending_request + 4)) = htons(privateport); */
p->pending_request[4] = (privateport >> 8) & 0xff;
p->pending_request[5] = privateport & 0xff;
/* break stric-aliasing rules :
*((uint16_t *)(p->pending_request + 6)) = htons(publicport); */
p->pending_request[6] = (publicport >> 8) & 0xff;
p->pending_request[7] = publicport & 0xff;
/* break stric-aliasing rules :
*((uint32_t *)(p->pending_request + 8)) = htonl(lifetime); */
p->pending_request[8] = (lifetime >> 24) & 0xff;
p->pending_request[9] = (lifetime >> 16) & 0xff;
p->pending_request[10] = (lifetime >> 8) & 0xff;
p->pending_request[11] = lifetime & 0xff;
p->pending_request_len = 12;
return sendnatpmprequest(p);
}
LIBSPEC int readnatpmpresponse(natpmp_t * p, natpmpresp_t * response)
{
unsigned char buf[16];
struct sockaddr_in addr;
socklen_t addrlen = sizeof(addr);
int n;
if(!p)
return NATPMP_ERR_INVALIDARGS;
n = recvfrom(p->s, (char *)buf, sizeof(buf), 0,
(struct sockaddr *)&addr, &addrlen);
if(n<0)
#ifdef WIN32
switch(WSAGetLastError()) {
#else
switch(errno) {
#endif
/*case EAGAIN:*/
case EWOULDBLOCK:
n = NATPMP_TRYAGAIN;
break;
case ECONNREFUSED:
n = NATPMP_ERR_NOGATEWAYSUPPORT;
break;
default:
n = NATPMP_ERR_RECVFROM;
}
/* check that addr is correct (= gateway) */
else if(addr.sin_addr.s_addr != p->gateway)
n = NATPMP_ERR_WRONGPACKETSOURCE;
else {
response->resultcode = ntohs(*((uint16_t *)(buf + 2)));
response->epoch = ntohl(*((uint32_t *)(buf + 4)));
if(buf[0] != 0)
n = NATPMP_ERR_UNSUPPORTEDVERSION;
else if(buf[1] < 128 || buf[1] > 130)
n = NATPMP_ERR_UNSUPPORTEDOPCODE;
else if(response->resultcode != 0) {
switch(response->resultcode) {
case 1:
n = NATPMP_ERR_UNSUPPORTEDVERSION;
break;
case 2:
n = NATPMP_ERR_NOTAUTHORIZED;
break;
case 3:
n = NATPMP_ERR_NETWORKFAILURE;
break;
case 4:
n = NATPMP_ERR_OUTOFRESOURCES;
break;
case 5:
n = NATPMP_ERR_UNSUPPORTEDOPCODE;
break;
default:
n = NATPMP_ERR_UNDEFINEDERROR;
}
} else {
response->type = buf[1] & 0x7f;
if(buf[1] == 128)
//response->publicaddress.addr = *((uint32_t *)(buf + 8));
response->pnu.publicaddress.addr.s_addr = *((uint32_t *)(buf + 8));
else {
response->pnu.newportmapping.privateport = ntohs(*((uint16_t *)(buf + 8)));
response->pnu.newportmapping.mappedpublicport = ntohs(*((uint16_t *)(buf + 10)));
response->pnu.newportmapping.lifetime = ntohl(*((uint32_t *)(buf + 12)));
}
n = 0;
}
}
return n;
}
int readnatpmpresponseorretry(natpmp_t * p, natpmpresp_t * response)
{
int n;
if(!p || !response)
return NATPMP_ERR_INVALIDARGS;
if(!p->has_pending_request)
return NATPMP_ERR_NOPENDINGREQ;
n = readnatpmpresponse(p, response);
if(n<0) {
if(n==NATPMP_TRYAGAIN) {
struct timeval now;
gettimeofday(&now, NULL); // check errors !
if(timercmp(&now, &p->retry_time, >=)) {
int delay, r;
if(p->try_number >= 9) {
return NATPMP_ERR_NOGATEWAYSUPPORT;
}
/*printf("retry! %d\n", p->try_number);*/
delay = 250 * (1<<p->try_number); // ms
/*for(i=0; i<p->try_number; i++)
delay += delay;*/
p->retry_time.tv_sec += (delay / 1000);
p->retry_time.tv_usec += (delay % 1000) * 1000;
if(p->retry_time.tv_usec >= 1000000) {
p->retry_time.tv_usec -= 1000000;
p->retry_time.tv_sec++;
}
p->try_number++;
r = sendpendingrequest(p);
if(r<0)
return r;
}
}
} else {
p->has_pending_request = 0;
}
return n;
}
#ifdef ENABLE_STRNATPMPERR
LIBSPEC const char * strnatpmperr(int r)
{
const char * s;
switch(r) {
case NATPMP_ERR_INVALIDARGS:
s = "invalid arguments";
break;
case NATPMP_ERR_SOCKETERROR:
s = "socket() failed";
break;
case NATPMP_ERR_CANNOTGETGATEWAY:
s = "cannot get default gateway ip address";
break;
case NATPMP_ERR_CLOSEERR:
#ifdef WIN32
s = "closesocket() failed";
#else
s = "close() failed";
#endif
break;
case NATPMP_ERR_RECVFROM:
s = "recvfrom() failed";
break;
case NATPMP_ERR_NOPENDINGREQ:
s = "no pending request";
break;
case NATPMP_ERR_NOGATEWAYSUPPORT:
s = "the gateway does not support nat-pmp";
break;
case NATPMP_ERR_CONNECTERR:
s = "connect() failed";
break;
case NATPMP_ERR_WRONGPACKETSOURCE:
s = "packet not received from the default gateway";
break;
case NATPMP_ERR_SENDERR:
s = "send() failed";
break;
case NATPMP_ERR_FCNTLERROR:
s = "fcntl() failed";
break;
case NATPMP_ERR_GETTIMEOFDAYERR:
s = "gettimeofday() failed";
break;
case NATPMP_ERR_UNSUPPORTEDVERSION:
s = "unsupported nat-pmp version error from server";
break;
case NATPMP_ERR_UNSUPPORTEDOPCODE:
s = "unsupported nat-pmp opcode error from server";
break;
case NATPMP_ERR_UNDEFINEDERROR:
s = "undefined nat-pmp server error";
break;
case NATPMP_ERR_NOTAUTHORIZED:
s = "not authorized";
break;
case NATPMP_ERR_NETWORKFAILURE:
s = "network failure";
break;
case NATPMP_ERR_OUTOFRESOURCES:
s = "nat-pmp server out of resources";
break;
default:
s = "Unknown libnatpmp error";
}
return s;
}
#endif

11
ext/libnatpmp/natpmp.def Normal file
View File

@ -0,0 +1,11 @@
LIBRARY
; libnatpmp library
EXPORTS
initnatpmp
closenatpmp
sendpublicaddressrequest
sendnewportmappingrequest
getnatpmprequesttimeout
readnatpmpresponseorretry
strnatpmperr

219
ext/libnatpmp/natpmp.h Normal file
View File

@ -0,0 +1,219 @@
/* $Id: natpmp.h,v 1.20 2014/04/22 09:15:40 nanard Exp $ */
/* libnatpmp
Copyright (c) 2007-2014, Thomas BERNARD
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __NATPMP_H__
#define __NATPMP_H__
/* NAT-PMP Port as defined by the NAT-PMP draft */
#define NATPMP_PORT (5351)
#include <time.h>
#if !defined(_MSC_VER)
#include <sys/time.h>
#endif /* !defined(_MSC_VER) */
#ifdef WIN32
#include <winsock2.h>
#if !defined(_MSC_VER) || _MSC_VER >= 1600
#include <stdint.h>
#else /* !defined(_MSC_VER) || _MSC_VER >= 1600 */
typedef unsigned long uint32_t;
typedef unsigned short uint16_t;
#endif /* !defined(_MSC_VER) || _MSC_VER >= 1600 */
#define in_addr_t uint32_t
#include "declspec.h"
#else /* WIN32 */
#define LIBSPEC
#include <netinet/in.h>
#endif /* WIN32 */
/* causes problem when installing. Maybe should it be inlined ? */
/* #include "declspec.h" */
typedef struct {
int s; /* socket */
in_addr_t gateway; /* default gateway (IPv4) */
int has_pending_request;
unsigned char pending_request[12];
int pending_request_len;
int try_number;
struct timeval retry_time;
} natpmp_t;
typedef struct {
uint16_t type; /* NATPMP_RESPTYPE_* */
uint16_t resultcode; /* NAT-PMP response code */
uint32_t epoch; /* Seconds since start of epoch */
union {
struct {
//in_addr_t addr;
struct in_addr addr;
} publicaddress;
struct {
uint16_t privateport;
uint16_t mappedpublicport;
uint32_t lifetime;
} newportmapping;
} pnu;
} natpmpresp_t;
/* possible values for type field of natpmpresp_t */
#define NATPMP_RESPTYPE_PUBLICADDRESS (0)
#define NATPMP_RESPTYPE_UDPPORTMAPPING (1)
#define NATPMP_RESPTYPE_TCPPORTMAPPING (2)
/* Values to pass to sendnewportmappingrequest() */
#define NATPMP_PROTOCOL_UDP (1)
#define NATPMP_PROTOCOL_TCP (2)
/* return values */
/* NATPMP_ERR_INVALIDARGS : invalid arguments passed to the function */
#define NATPMP_ERR_INVALIDARGS (-1)
/* NATPMP_ERR_SOCKETERROR : socket() failed. check errno for details */
#define NATPMP_ERR_SOCKETERROR (-2)
/* NATPMP_ERR_CANNOTGETGATEWAY : can't get default gateway IP */
#define NATPMP_ERR_CANNOTGETGATEWAY (-3)
/* NATPMP_ERR_CLOSEERR : close() failed. check errno for details */
#define NATPMP_ERR_CLOSEERR (-4)
/* NATPMP_ERR_RECVFROM : recvfrom() failed. check errno for details */
#define NATPMP_ERR_RECVFROM (-5)
/* NATPMP_ERR_NOPENDINGREQ : readnatpmpresponseorretry() called while
* no NAT-PMP request was pending */
#define NATPMP_ERR_NOPENDINGREQ (-6)
/* NATPMP_ERR_NOGATEWAYSUPPORT : the gateway does not support NAT-PMP */
#define NATPMP_ERR_NOGATEWAYSUPPORT (-7)
/* NATPMP_ERR_CONNECTERR : connect() failed. check errno for details */
#define NATPMP_ERR_CONNECTERR (-8)
/* NATPMP_ERR_WRONGPACKETSOURCE : packet not received from the network gateway */
#define NATPMP_ERR_WRONGPACKETSOURCE (-9)
/* NATPMP_ERR_SENDERR : send() failed. check errno for details */
#define NATPMP_ERR_SENDERR (-10)
/* NATPMP_ERR_FCNTLERROR : fcntl() failed. check errno for details */
#define NATPMP_ERR_FCNTLERROR (-11)
/* NATPMP_ERR_GETTIMEOFDAYERR : gettimeofday() failed. check errno for details */
#define NATPMP_ERR_GETTIMEOFDAYERR (-12)
/* */
#define NATPMP_ERR_UNSUPPORTEDVERSION (-14)
#define NATPMP_ERR_UNSUPPORTEDOPCODE (-15)
/* Errors from the server : */
#define NATPMP_ERR_UNDEFINEDERROR (-49)
#define NATPMP_ERR_NOTAUTHORIZED (-51)
#define NATPMP_ERR_NETWORKFAILURE (-52)
#define NATPMP_ERR_OUTOFRESOURCES (-53)
/* NATPMP_TRYAGAIN : no data available for the moment. try again later */
#define NATPMP_TRYAGAIN (-100)
#ifdef __cplusplus
extern "C" {
#endif
/* initnatpmp()
* initialize a natpmp_t object
* With forcegw=1 the gateway is not detected automaticaly.
* Return values :
* 0 = OK
* NATPMP_ERR_INVALIDARGS
* NATPMP_ERR_SOCKETERROR
* NATPMP_ERR_FCNTLERROR
* NATPMP_ERR_CANNOTGETGATEWAY
* NATPMP_ERR_CONNECTERR */
LIBSPEC int initnatpmp(natpmp_t * p, int forcegw, in_addr_t forcedgw);
/* closenatpmp()
* close resources associated with a natpmp_t object
* Return values :
* 0 = OK
* NATPMP_ERR_INVALIDARGS
* NATPMP_ERR_CLOSEERR */
LIBSPEC int closenatpmp(natpmp_t * p);
/* sendpublicaddressrequest()
* send a public address NAT-PMP request to the network gateway
* Return values :
* 2 = OK (size of the request)
* NATPMP_ERR_INVALIDARGS
* NATPMP_ERR_SENDERR */
LIBSPEC int sendpublicaddressrequest(natpmp_t * p);
/* sendnewportmappingrequest()
* send a new port mapping NAT-PMP request to the network gateway
* Arguments :
* protocol is either NATPMP_PROTOCOL_TCP or NATPMP_PROTOCOL_UDP,
* lifetime is in seconds.
* To remove a port mapping, set lifetime to zero.
* To remove all port mappings to the host, set lifetime and both ports
* to zero.
* Return values :
* 12 = OK (size of the request)
* NATPMP_ERR_INVALIDARGS
* NATPMP_ERR_SENDERR */
LIBSPEC int sendnewportmappingrequest(natpmp_t * p, int protocol,
uint16_t privateport, uint16_t publicport,
uint32_t lifetime);
/* getnatpmprequesttimeout()
* fills the timeval structure with the timeout duration of the
* currently pending NAT-PMP request.
* Return values :
* 0 = OK
* NATPMP_ERR_INVALIDARGS
* NATPMP_ERR_GETTIMEOFDAYERR
* NATPMP_ERR_NOPENDINGREQ */
LIBSPEC int getnatpmprequesttimeout(natpmp_t * p, struct timeval * timeout);
/* readnatpmpresponseorretry()
* fills the natpmpresp_t structure if possible
* Return values :
* 0 = OK
* NATPMP_TRYAGAIN
* NATPMP_ERR_INVALIDARGS
* NATPMP_ERR_NOPENDINGREQ
* NATPMP_ERR_NOGATEWAYSUPPORT
* NATPMP_ERR_RECVFROM
* NATPMP_ERR_WRONGPACKETSOURCE
* NATPMP_ERR_UNSUPPORTEDVERSION
* NATPMP_ERR_UNSUPPORTEDOPCODE
* NATPMP_ERR_NOTAUTHORIZED
* NATPMP_ERR_NETWORKFAILURE
* NATPMP_ERR_OUTOFRESOURCES
* NATPMP_ERR_UNSUPPORTEDOPCODE
* NATPMP_ERR_UNDEFINEDERROR */
LIBSPEC int readnatpmpresponseorretry(natpmp_t * p, natpmpresp_t * response);
#ifdef ENABLE_STRNATPMPERR
LIBSPEC const char * strnatpmperr(int t);
#endif
#ifdef __cplusplus
}
#endif
#endif

19
ext/libnatpmp/natpmpc.1 Normal file
View File

@ -0,0 +1,19 @@
.TH natpmpc 1
.SH NAME
natpmpc \- NAT\-PMP library test client and mapping setter.
.SH "SYNOPSIS"
Display the public IP address:
.br
\fBnatpmpc\fP
Add a port mapping:
.br
\fBnatpmpc\fP \-a <public port> <private port> <protocol> [lifetime]
.SH DESCRIPTION
In order to remove a mapping, set it with a lifetime of 0 seconds.
To remove all mappings for your machine, use 0 as private port and
lifetime.

244
ext/libnatpmp/natpmpc.c Normal file
View File

@ -0,0 +1,244 @@
/* $Id: natpmpc.c,v 1.13 2012/08/21 17:23:38 nanard Exp $ */
/* libnatpmp
Copyright (c) 2007-2011, Thomas BERNARD
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <errno.h>
#include <string.h>
#if defined(_MSC_VER)
#if _MSC_VER >= 1400
#define strcasecmp _stricmp
#else
#define strcasecmp stricmp
#endif
#else
#include <unistd.h>
#endif
#ifdef WIN32
#include <winsock2.h>
#else
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
#include "natpmp.h"
void usage(FILE * out, const char * argv0)
{
fprintf(out, "Usage :\n");
fprintf(out, " %s [options]\n", argv0);
fprintf(out, "\tdisplay the public IP address.\n");
fprintf(out, " %s -h\n", argv0);
fprintf(out, "\tdisplay this help screen.\n");
fprintf(out, " %s [options] -a <public port> <private port> <protocol> [lifetime]\n", argv0);
fprintf(out, "\tadd a port mapping.\n");
fprintf(out, "\nOption available :\n");
fprintf(out, " -g ipv4address\n");
fprintf(out, "\tforce the gateway to be used as destination for NAT-PMP commands.\n");
fprintf(out, "\n In order to remove a mapping, set it with a lifetime of 0 seconds.\n");
fprintf(out, " To remove all mappings for your machine, use 0 as private port and lifetime.\n");
}
/* sample code for using libnatpmp */
int main(int argc, char * * argv)
{
natpmp_t natpmp;
natpmpresp_t response;
int r;
int sav_errno;
struct timeval timeout;
fd_set fds;
int i;
int protocol = 0;
uint16_t privateport = 0;
uint16_t publicport = 0;
uint32_t lifetime = 3600;
int command = 0;
int forcegw = 0;
in_addr_t gateway = 0;
struct in_addr gateway_in_use;
#ifdef WIN32
WSADATA wsaData;
int nResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if(nResult != NO_ERROR)
{
fprintf(stderr, "WSAStartup() failed.\n");
return -1;
}
#endif
/* argument parsing */
for(i=1; i<argc; i++) {
if(argv[i][0] == '-') {
switch(argv[i][1]) {
case 'h':
usage(stdout, argv[0]);
return 0;
case 'g':
forcegw = 1;
if(argc < i + 1) {
fprintf(stderr, "Not enough arguments for option -%c\n", argv[i][1]);
return 1;
}
gateway = inet_addr(argv[++i]);
break;
case 'a':
command = 'a';
if(argc < i + 4) {
fprintf(stderr, "Not enough arguments for option -%c\n", argv[i][1]);
return 1;
}
i++;
if(1 != sscanf(argv[i], "%hu", &publicport)) {
fprintf(stderr, "%s is not a correct 16bits unsigned integer\n", argv[i]);
return 1;
}
i++;
if(1 != sscanf(argv[i], "%hu", &privateport)) {
fprintf(stderr, "%s is not a correct 16bits unsigned integer\n", argv[i]);
return 1;
}
i++;
if(0 == strcasecmp(argv[i], "tcp"))
protocol = NATPMP_PROTOCOL_TCP;
else if(0 == strcasecmp(argv[i], "udp"))
protocol = NATPMP_PROTOCOL_UDP;
else {
fprintf(stderr, "%s is not a valid protocol\n", argv[i]);
return 1;
}
if(argc > i + 1) {
if(1 != sscanf(argv[i+1], "%u", &lifetime)) {
fprintf(stderr, "%s is not a correct 32bits unsigned integer\n", argv[i]);
} else {
i++;
}
}
break;
default:
fprintf(stderr, "Unknown option %s\n", argv[i]);
usage(stderr, argv[0]);
return 1;
}
} else {
fprintf(stderr, "Unknown option %s\n", argv[i]);
usage(stderr, argv[0]);
return 1;
}
}
/* initnatpmp() */
r = initnatpmp(&natpmp, forcegw, gateway);
printf("initnatpmp() returned %d (%s)\n", r, r?"FAILED":"SUCCESS");
if(r<0)
return 1;
gateway_in_use.s_addr = natpmp.gateway;
printf("using gateway : %s\n", inet_ntoa(gateway_in_use));
/* sendpublicaddressrequest() */
r = sendpublicaddressrequest(&natpmp);
printf("sendpublicaddressrequest returned %d (%s)\n",
r, r==2?"SUCCESS":"FAILED");
if(r<0)
return 1;
do {
FD_ZERO(&fds);
FD_SET(natpmp.s, &fds);
getnatpmprequesttimeout(&natpmp, &timeout);
r = select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
if(r<0) {
fprintf(stderr, "select()");
return 1;
}
r = readnatpmpresponseorretry(&natpmp, &response);
sav_errno = errno;
printf("readnatpmpresponseorretry returned %d (%s)\n",
r, r==0?"OK":(r==NATPMP_TRYAGAIN?"TRY AGAIN":"FAILED"));
if(r<0 && r!=NATPMP_TRYAGAIN) {
#ifdef ENABLE_STRNATPMPERR
fprintf(stderr, "readnatpmpresponseorretry() failed : %s\n",
strnatpmperr(r));
#endif
fprintf(stderr, " errno=%d '%s'\n",
sav_errno, strerror(sav_errno));
}
} while(r==NATPMP_TRYAGAIN);
if(r<0)
return 1;
/* TODO : check that response.type == 0 */
printf("Public IP address : %s\n", inet_ntoa(response.pnu.publicaddress.addr));
printf("epoch = %u\n", response.epoch);
if(command == 'a') {
/* sendnewportmappingrequest() */
r = sendnewportmappingrequest(&natpmp, protocol,
privateport, publicport,
lifetime);
printf("sendnewportmappingrequest returned %d (%s)\n",
r, r==12?"SUCCESS":"FAILED");
if(r < 0)
return 1;
do {
FD_ZERO(&fds);
FD_SET(natpmp.s, &fds);
getnatpmprequesttimeout(&natpmp, &timeout);
select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
r = readnatpmpresponseorretry(&natpmp, &response);
printf("readnatpmpresponseorretry returned %d (%s)\n",
r, r==0?"OK":(r==NATPMP_TRYAGAIN?"TRY AGAIN":"FAILED"));
} while(r==NATPMP_TRYAGAIN);
if(r<0) {
#ifdef ENABLE_STRNATPMPERR
fprintf(stderr, "readnatpmpresponseorretry() failed : %s\n",
strnatpmperr(r));
#endif
return 1;
}
printf("Mapped public port %hu protocol %s to local port %hu "
"liftime %u\n",
response.pnu.newportmapping.mappedpublicport,
response.type == NATPMP_RESPTYPE_UDPPORTMAPPING ? "UDP" :
(response.type == NATPMP_RESPTYPE_TCPPORTMAPPING ? "TCP" :
"UNKNOWN"),
response.pnu.newportmapping.privateport,
response.pnu.newportmapping.lifetime);
printf("epoch = %u\n", response.epoch);
}
r = closenatpmp(&natpmp);
printf("closenatpmp() returned %d (%s)\n", r, r==0?"SUCCESS":"FAILED");
if(r<0)
return 1;
return 0;
}

18
ext/libnatpmp/setup.py Normal file
View File

@ -0,0 +1,18 @@
#! /usr/bin/python
# $Id: setup.py,v 1.3 2012/03/05 04:54:01 nanard Exp $
#
# python script to build the libnatpmp module under unix
#
# replace libnatpmp.a by libnatpmp.so for shared library usage
from distutils.core import setup, Extension
from distutils import sysconfig
sysconfig.get_config_vars()["OPT"] = ''
sysconfig.get_config_vars()["CFLAGS"] = ''
setup(name="libnatpmp", version="1.0",
ext_modules=[
Extension(name="libnatpmp", sources=["libnatpmpmodule.c"],
extra_objects=["libnatpmp.a"],
define_macros=[('ENABLE_STRNATPMPERR', None)]
)]
)

View File

@ -0,0 +1,17 @@
#! /usr/bin/python
# $Id: setupmingw32.py,v 1.3 2012/03/05 04:54:01 nanard Exp $
# python script to build the miniupnpc module under windows
#
from distutils.core import setup, Extension
from distutils import sysconfig
sysconfig.get_config_vars()["OPT"] = ''
sysconfig.get_config_vars()["CFLAGS"] = ''
setup(name="libnatpmp", version="1.0",
ext_modules=[
Extension(name="libnatpmp", sources=["libnatpmpmodule.c"],
libraries=["ws2_32"],
extra_objects=["libnatpmp.a"],
define_macros=[('ENABLE_STRNATPMPERR', None)]
)]
)

View File

@ -0,0 +1,57 @@
/* $Id: testgetgateway.c,v 1.7 2012/08/21 17:13:31 nanard Exp $ */
/* libnatpmp
Copyright (c) 2007-2011, Thomas BERNARD
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#ifdef WIN32
#include <winsock2.h>
#else
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
#include "getgateway.h"
int main(int argc, char * * argv)
{
(void)argc;
(void)argv;
struct in_addr gatewayaddr;
int r;
#ifdef WIN32
uint32_t temp = 0;
r = getdefaultgateway(&temp);
gatewayaddr.S_un.S_addr = temp;
#else
r = getdefaultgateway(&(gatewayaddr.s_addr));
#endif
if(r>=0)
printf("default gateway : %s\n", inet_ntoa(gatewayaddr));
else
fprintf(stderr, "getdefaultgateway() failed\n");
return 0;
}

View File

@ -0,0 +1,60 @@
/* $Id: wingettimeofday.c,v 1.6 2013/09/10 20:13:26 nanard Exp $ */
/* libnatpmp
Copyright (c) 2007-2013, Thomas BERNARD
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef WIN32
#if defined(_MSC_VER)
struct timeval {
long tv_sec;
long tv_usec;
};
#else
#include <sys/time.h>
#endif
typedef struct _FILETIME {
unsigned long dwLowDateTime;
unsigned long dwHighDateTime;
} FILETIME;
void __stdcall GetSystemTimeAsFileTime(FILETIME*);
int natpmp_gettimeofday(struct timeval* p, void* tz /* IGNORED */) {
union {
long long ns100; /*time since 1 Jan 1601 in 100ns units */
FILETIME ft;
} _now;
if(!p)
return -1;
GetSystemTimeAsFileTime( &(_now.ft) );
p->tv_usec =(long)((_now.ns100 / 10LL) % 1000000LL );
p->tv_sec = (long)((_now.ns100-(116444736000000000LL))/10000000LL);
return 0;
}
#endif

View File

@ -0,0 +1,39 @@
/* $Id: wingettimeofday.h,v 1.5 2013/09/11 07:22:25 nanard Exp $ */
/* libnatpmp
Copyright (c) 2007-2013, Thomas BERNARD
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __WINGETTIMEOFDAY_H__
#define __WINGETTIMEOFDAY_H__
#ifdef WIN32
#if defined(_MSC_VER)
#include <time.h>
#else
#include <sys/time.h>
#endif
int natpmp_gettimeofday(struct timeval* p, void* tz /* IGNORED */);
#endif
#endif

View File

@ -24,8 +24,6 @@
#define OS_STRING "Win32"
#define MINIUPNPC_VERSION_STRING "1.9"
#define UPNP_VERSION_STRING "UPnP/1.1"
#else
#include "miniupnpcstrings.h"
#endif
/* only for malloc */
@ -126,5 +124,3 @@ int soapPostSubmit(int fd,
#endif
return httpWrite(fd, body, bodysize, headerbuf, headerssize);
}

View File

@ -54,8 +54,6 @@
#define OS_STRING "Win32"
#define MINIUPNPC_VERSION_STRING "1.9"
#define UPNP_VERSION_STRING "UPnP/1.1"
#else
#include "miniupnpcstrings.h"
#endif
#include "miniwget.h"
#include "connecthostport.h"
@ -630,4 +628,3 @@ miniwget_getaddr(const char * url, int * size,
#endif
return miniwget2(hostname, port, path, size, addr, addrlen, scope_id);
}

View File

@ -43,9 +43,8 @@ ifeq ($(ZT_OFFICIAL_RELEASE),1)
endif
ifeq ($(ZT_USE_MINIUPNPC),1)
DEFS+=-DZT_USE_MINIUPNPC
LDLIBS+=ext/miniupnpc/libminiupnpc.a
OBJS+=osdep/UPNPClient.o
DEFS+=-DZT_USE_MINIUPNPC -DMINIUPNP_STATICLIB -DMINIUPNPC_SET_SOCKET_TIMEOUT -DMINIUPNPC_GET_SRC_ADDR -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -DOS_STRING=\"Linux\" -DMINIUPNPC_VERSION_STRING=\"1.9\" -DUPNP_VERSION_STRING=\"UPnP/1.1\" -DENABLE_STRNATPMPERR
OBJS+=ext/libnatpmp/natpmp.o ext/libnatpmp/getgateway.o ext/miniupnpc/connecthostport.o ext/miniupnpc/igd_desc_parse.o ext/miniupnpc/minisoap.o ext/miniupnpc/minissdpc.o ext/miniupnpc/miniupnpc.o ext/miniupnpc/miniwget.o ext/miniupnpc/minixml.o ext/miniupnpc/portlistingparse.o ext/miniupnpc/receivedata.o ext/miniupnpc/upnpcommands.o ext/miniupnpc/upnpdev.o ext/miniupnpc/upnperrors.o ext/miniupnpc/upnpreplyparse.o osdep/PortMapper.o
endif
# Build with ZT_ENABLE_NETWORK_CONTROLLER=1 to build with the Sqlite network controller
@ -65,8 +64,13 @@ ifeq ($(ZT_DEBUG),1)
DEFS+=-DZT_TRACE
CFLAGS+=-Wall -g -pthread $(INCLUDES) $(DEFS)
CXXFLAGS+=-Wall -g -pthread $(INCLUDES) $(DEFS)
<<<<<<< HEAD
LDFLAGS=-ldl
STRIP=echo
=======
LDFLAGS=
STRIP?=echo
>>>>>>> origin/dev
# The following line enables optimization for the crypto code, since
# C25519 in particular is almost UNUSABLE in -O0 even on a 3ghz box!
ext/lz4/lz4.o node/Salsa20.o node/SHA512.o node/C25519.o node/Poly1305.o: CFLAGS = -Wall -O2 -g -pthread $(INCLUDES) $(DEFS)
@ -74,9 +78,16 @@ else
CFLAGS?=-O3 -fstack-protector
CFLAGS+=-Wall -fPIE -fvisibility=hidden -pthread $(INCLUDES) -DNDEBUG $(DEFS)
CXXFLAGS?=-O3 -fstack-protector
<<<<<<< HEAD
CXXFLAGS+=-Wall -Wreorder -fPIE -fvisibility=hidden -fno-rtti -pthread $(INCLUDES) -DNDEBUG $(DEFS)
LDFLAGS=-ldl -pie -Wl,-z,relro,-z,now
STRIP=strip --strip-all
=======
CXXFLAGS+=-Wall -fPIE -fvisibility=hidden -fno-rtti -pthread $(INCLUDES) -DNDEBUG $(DEFS)
LDFLAGS=-pie -Wl,-z,relro,-z,now
STRIP?=strip
STRIP+=--strip-all
>>>>>>> origin/dev
endif
ifeq ($(ZT_TRACE),1)
@ -92,9 +103,6 @@ endif
all: one
one: $(OBJS) one.o
ifeq ($(ZT_USE_MINIUPNPC),1)
cd ext/miniupnpc ; make clean ; make 'CFLAGS=-O2 -fstack-protector -fPIE -fno-common -DMINIUPNPC_SET_SOCKET_TIMEOUT -DMINIUPNPC_GET_SRC_ADDR -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600' -j 2 libminiupnpc.a
endif
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-one $(OBJS) one.o $(LDLIBS)
$(STRIP) zerotier-one
ln -sf zerotier-one zerotier-idtool
@ -108,6 +116,7 @@ installer: one FORCE
./ext/installfiles/linux/buildinstaller.sh
clean:
<<<<<<< HEAD
find ./ -type f -name '*.o' -delete
find netcon/ -type f -name '*.so' -delete
find netcon/ -type f -name '*.1.0' -delete
@ -116,6 +125,9 @@ clean:
find netcon/docker-test -name "zerotier-intercept" -type f -delete
rm -rf zerotier-one zerotier-idtool zerotier-cli zerotier-selftest zerotier-netcon build-* ZeroTierOneInstaller-* *.deb *.rpm *.pkg *.tgz
cd ext/miniupnpc ; make clean
=======
rm -rf *.o node/*.o controller/*.o osdep/*.o service/*.o ext/http-parser/*.o ext/lz4/*.o ext/json-parser/*.o $(OBJS) zerotier-one zerotier-idtool zerotier-cli zerotier-selftest build-* ZeroTierOneInstaller-* *.deb *.rpm
>>>>>>> origin/dev
debug: FORCE
make ZT_DEBUG=1 one

View File

@ -42,9 +42,8 @@ ifeq ($(ZT_AUTO_UPDATE),1)
endif
ifeq ($(ZT_USE_MINIUPNPC),1)
DEFS+=-DZT_USE_MINIUPNPC
LIBS+=ext/miniupnpc/libminiupnpc.a
OBJS+=osdep/UPNPClient.o
DEFS+=-DMACOSX -DZT_USE_MINIUPNPC -DMINIUPNP_STATICLIB -D_DARWIN_C_SOURCE -DMINIUPNPC_SET_SOCKET_TIMEOUT -DMINIUPNPC_GET_SRC_ADDR -D_BSD_SOURCE -D_DEFAULT_SOURCE -DOS_STRING=\"Darwin/15.0.0\" -DMINIUPNPC_VERSION_STRING=\"1.9\" -DUPNP_VERSION_STRING=\"UPnP/1.1\" -DENABLE_STRNATPMPERR
OBJS+=ext/libnatpmp/natpmp.o ext/libnatpmp/getgateway.o ext/miniupnpc/connecthostport.o ext/miniupnpc/igd_desc_parse.o ext/miniupnpc/minisoap.o ext/miniupnpc/minissdpc.o ext/miniupnpc/miniupnpc.o ext/miniupnpc/miniwget.o ext/miniupnpc/minixml.o ext/miniupnpc/portlistingparse.o ext/miniupnpc/receivedata.o ext/miniupnpc/upnpcommands.o ext/miniupnpc/upnpdev.o ext/miniupnpc/upnperrors.o ext/miniupnpc/upnpreplyparse.o osdep/PortMapper.o
endif
# Build with ZT_ENABLE_NETWORK_CONTROLLER=1 to build with the Sqlite network controller
@ -73,9 +72,6 @@ CXXFLAGS=$(CFLAGS) -fno-rtti
all: one
one: $(OBJS) one.o
ifeq ($(ZT_USE_MINIUPNPC),1)
cd ext/miniupnpc ; make clean ; make 'CFLAGS=-D_DARWIN_C_SOURCE -O2 -fstack-protector -fPIE -flto -pthread -mmacosx-version-min=10.7 -fno-common -DMINIUPNPC_SET_SOCKET_TIMEOUT -DMINIUPNPC_GET_SRC_ADDR -D_BSD_SOURCE -D_DEFAULT_SOURCE' -j 2 libminiupnpc.a
endif
$(CXX) $(CXXFLAGS) -o zerotier-one $(OBJS) one.o $(LIBS)
$(STRIP) zerotier-one
ln -sf zerotier-one zerotier-idtool
@ -101,8 +97,7 @@ official: FORCE
make ZT_OFFICIAL_RELEASE=1 mac-dist-pkg
clean:
rm -rf *.dSYM build-* *.pkg *.dmg *.o node/*.o controller/*.o service/*.o osdep/*.o ext/http-parser/*.o ext/lz4/*.o ext/json-parser/*.o zerotier-one zerotier-idtool zerotier-selftest zerotier-cli ZeroTierOneInstaller-* mkworld
cd ext/miniupnpc ; make clean
rm -rf *.dSYM build-* *.pkg *.dmg *.o node/*.o controller/*.o service/*.o osdep/*.o ext/http-parser/*.o ext/lz4/*.o ext/json-parser/*.o $(OBJS) zerotier-one zerotier-idtool zerotier-selftest zerotier-cli ZeroTierOneInstaller-* mkworld
# For those building from source -- installs signed binary tap driver in system ZT home
install-mac-tap: FORCE

View File

@ -343,7 +343,7 @@
/**
* Maximum number of paths per IP scope (e.g. global, link-local) and family (e.g. v4/v6)
*/
#define ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY 1
#define ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY 4
/**
* A test pseudo-network-ID that can be joined

View File

@ -210,8 +210,8 @@ static bool ___removeIp(const std::string &_dev,const InetAddress &ip)
long cpid = (long)vfork();
if (cpid == 0) {
OSUtils::redirectUnixOutputs("/dev/null",(const char *)0);
::execl("/sbin/ip","/sbin/ip","addr","del",ip.toString().c_str(),"dev",_dev.c_str(),(const char *)0);
::execl("/usr/sbin/ip","/usr/sbin/ip","addr","del",ip.toString().c_str(),"dev",_dev.c_str(),(const char *)0);
setenv("PATH", "/sbin:/bin:/usr/sbin:/usr/bin", 1);
::execlp("ip","ip","addr","del",ip.toString().c_str(),"dev",_dev.c_str(),(const char *)0);
::_exit(-1);
} else {
int exitcode = -1;
@ -238,12 +238,11 @@ bool LinuxEthernetTap::addIp(const InetAddress &ip)
long cpid = (long)vfork();
if (cpid == 0) {
OSUtils::redirectUnixOutputs("/dev/null",(const char *)0);
setenv("PATH", "/sbin:/bin:/usr/sbin:/usr/bin", 1);
if (ip.isV4()) {
::execl("/sbin/ip","/sbin/ip","addr","add",ip.toString().c_str(),"broadcast",ip.broadcast().toIpString().c_str(),"dev",_dev.c_str(),(const char *)0);
::execl("/usr/sbin/ip","/usr/sbin/ip","addr","add",ip.toString().c_str(),"broadcast",ip.broadcast().toIpString().c_str(),"dev",_dev.c_str(),(const char *)0);
::execlp("ip","ip","addr","add",ip.toString().c_str(),"broadcast",ip.broadcast().toIpString().c_str(),"dev",_dev.c_str(),(const char *)0);
} else {
::execl("/sbin/ip","/sbin/ip","addr","add",ip.toString().c_str(),"dev",_dev.c_str(),(const char *)0);
::execl("/usr/sbin/ip","/usr/sbin/ip","addr","add",ip.toString().c_str(),"dev",_dev.c_str(),(const char *)0);
::execlp("ip","ip","addr","add",ip.toString().c_str(),"dev",_dev.c_str(),(const char *)0);
}
::_exit(-1);
} else if (cpid > 0) {

320
osdep/PortMapper.cpp Normal file
View File

@ -0,0 +1,320 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2015 ZeroTier, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
* ZeroTier may be used and distributed under the terms of the GPLv3, which
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
*
* If you would like to embed ZeroTier into a commercial application or
* redistribute it in a modified binary form, please contact ZeroTier Networks
* LLC. Start here: http://www.zerotier.com/
*/
#ifdef ZT_USE_MINIUPNPC
// Uncomment to dump debug messages
#define ZT_PORTMAPPER_TRACE 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include "../node/Utils.hpp"
#include "OSUtils.hpp"
#include "PortMapper.hpp"
#ifdef __WINDOWS__
#ifndef MINIUPNP_STATICLIB
#define MINIUPNP_STATICLIB
#endif
#endif
#include "../ext/miniupnpc/miniupnpc.h"
#include "../ext/miniupnpc/upnpcommands.h"
#include "../ext/libnatpmp/natpmp.h"
namespace ZeroTier {
class PortMapperImpl
{
public:
PortMapperImpl(int localUdpPortToMap,const char *un) :
run(true),
localPort(localUdpPortToMap),
uniqueName(un)
{
}
~PortMapperImpl() {}
void threadMain()
throw()
{
int mode = 0; // 0 == NAT-PMP, 1 == UPnP
#ifdef ZT_PORTMAPPER_TRACE
fprintf(stderr,"PortMapper: started for UDP port %d"ZT_EOL_S,localPort);
#endif
while (run) {
// ---------------------------------------------------------------------
// NAT-PMP mode (preferred)
// ---------------------------------------------------------------------
if (mode == 0) {
natpmp_t natpmp;
natpmpresp_t response;
int r = 0;
bool natPmpSuccess = false;
for(int tries=0;tries<60;++tries) {
int tryPort = (int)localPort + tries;
if (tryPort >= 65535)
tryPort = (tryPort - 65535) + 1025;
memset(&natpmp,0,sizeof(natpmp));
memset(&response,0,sizeof(response));
if (initnatpmp(&natpmp,0,0) != 0) {
mode = 1;
#ifdef ZT_PORTMAPPER_TRACE
fprintf(stderr,"PortMapper: NAT-PMP: init failed, switching to UPnP mode"ZT_EOL_S);
#endif
break;
}
InetAddress publicAddress;
sendpublicaddressrequest(&natpmp);
uint64_t myTimeout = OSUtils::now() + 5000;
do {
fd_set fds;
struct timeval timeout;
FD_ZERO(&fds);
FD_SET(natpmp.s, &fds);
getnatpmprequesttimeout(&natpmp, &timeout);
select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
r = readnatpmpresponseorretry(&natpmp, &response);
if (OSUtils::now() >= myTimeout)
break;
} while (r == NATPMP_TRYAGAIN);
if (r == 0) {
publicAddress = InetAddress((uint32_t)response.pnu.publicaddress.addr.s_addr,0);
} else {
#ifdef ZT_PORTMAPPER_TRACE
fprintf(stderr,"PortMapper: NAT-PMP: request for external address failed, aborting..."ZT_EOL_S);
#endif
closenatpmp(&natpmp);
break;
}
sendnewportmappingrequest(&natpmp,NATPMP_PROTOCOL_UDP,localPort,tryPort,(ZT_PORTMAPPER_REFRESH_DELAY * 2) / 1000);
myTimeout = OSUtils::now() + 10000;
do {
fd_set fds;
struct timeval timeout;
FD_ZERO(&fds);
FD_SET(natpmp.s, &fds);
getnatpmprequesttimeout(&natpmp, &timeout);
select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
r = readnatpmpresponseorretry(&natpmp, &response);
if (OSUtils::now() >= myTimeout)
break;
} while (r == NATPMP_TRYAGAIN);
if (r == 0) {
publicAddress.setPort(response.pnu.newportmapping.mappedpublicport);
#ifdef ZT_PORTMAPPER_TRACE
fprintf(stderr,"PortMapper: NAT-PMP: mapped %u to %s"ZT_EOL_S,(unsigned int)localPort,publicAddress.toString().c_str());
#endif
Mutex::Lock sl(surface_l);
surface.clear();
surface.push_back(publicAddress);
natPmpSuccess = true;
closenatpmp(&natpmp);
break;
} else {
closenatpmp(&natpmp);
// continue
}
}
if (!natPmpSuccess) {
mode = 1;
#ifdef ZT_PORTMAPPER_TRACE
fprintf(stderr,"PortMapper: NAT-PMP: request failed, switching to UPnP mode"ZT_EOL_S);
#endif
}
}
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// UPnP mode
// ---------------------------------------------------------------------
if (mode == 1) {
char lanaddr[4096];
char externalip[4096]; // no range checking? so make these buffers larger than any UDP packet a uPnP server could send us as a precaution :P
char inport[16];
char outport[16];
struct UPNPUrls urls;
struct IGDdatas data;
int upnpError = 0;
UPNPDev *devlist = upnpDiscoverAll(5000,(const char *)0,(const char *)0,0,0,2,&upnpError);
if (devlist) {
#ifdef ZT_PORTMAPPER_TRACE
{
UPNPDev *dev = devlist;
while (dev) {
fprintf(stderr,"PortMapper: found UPnP device at URL '%s': %s"ZT_EOL_S,dev->descURL,dev->st);
dev = dev->pNext;
}
}
#endif
memset(lanaddr,0,sizeof(lanaddr));
memset(externalip,0,sizeof(externalip));
memset(&urls,0,sizeof(urls));
memset(&data,0,sizeof(data));
Utils::snprintf(inport,sizeof(inport),"%d",localPort);
if ((UPNP_GetValidIGD(devlist,&urls,&data,lanaddr,sizeof(lanaddr)))&&(lanaddr[0])) {
#ifdef ZT_PORTMAPPER_TRACE
fprintf(stderr,"PortMapper: UPnP: my LAN IP address: %s"ZT_EOL_S,lanaddr);
#endif
if ((UPNP_GetExternalIPAddress(urls.controlURL,data.first.servicetype,externalip) == UPNPCOMMAND_SUCCESS)&&(externalip[0])) {
#ifdef ZT_PORTMAPPER_TRACE
fprintf(stderr,"PortMapper: UPnP: my external IP address: %s"ZT_EOL_S,externalip);
#endif
for(int tries=0;tries<60;++tries) {
int tryPort = (int)localPort + tries;
if (tryPort >= 65535)
tryPort = (tryPort - 65535) + 1025;
Utils::snprintf(outport,sizeof(outport),"%u",tryPort);
// First check and see if this port is already mapped to the
// same unique name. If so, keep this mapping and don't try
// to map again since this can break buggy routers. But don't
// fail if this command fails since not all routers support it.
{
char haveIntClient[128]; // 128 == big enough for all these as per miniupnpc "documentation"
char haveIntPort[128];
char haveDesc[128];
char haveEnabled[128];
char haveLeaseDuration[128];
memset(haveIntClient,0,sizeof(haveIntClient));
memset(haveIntPort,0,sizeof(haveIntPort));
memset(haveDesc,0,sizeof(haveDesc));
memset(haveEnabled,0,sizeof(haveEnabled));
memset(haveLeaseDuration,0,sizeof(haveLeaseDuration));
if ((UPNP_GetSpecificPortMappingEntry(urls.controlURL,data.first.servicetype,outport,"UDP",(const char *)0,haveIntClient,haveIntPort,haveDesc,haveEnabled,haveLeaseDuration) == UPNPCOMMAND_SUCCESS)&&(uniqueName == haveDesc)) {
#ifdef ZT_PORTMAPPER_TRACE
fprintf(stderr,"PortMapper: UPnP: reusing previously reserved external port: %s"ZT_EOL_S,outport);
#endif
Mutex::Lock sl(surface_l);
surface.clear();
InetAddress tmp(externalip);
tmp.setPort(tryPort);
surface.push_back(tmp);
break;
}
}
// Try to map this port
int mapResult = 0;
if ((mapResult = UPNP_AddPortMapping(urls.controlURL,data.first.servicetype,outport,inport,lanaddr,uniqueName.c_str(),"UDP",(const char *)0,"0")) == UPNPCOMMAND_SUCCESS) {
#ifdef ZT_PORTMAPPER_TRACE
fprintf(stderr,"PortMapper: UPnP: reserved external port: %s"ZT_EOL_S,outport);
#endif
Mutex::Lock sl(surface_l);
surface.clear();
InetAddress tmp(externalip);
tmp.setPort(tryPort);
surface.push_back(tmp);
break;
} else {
#ifdef ZT_PORTMAPPER_TRACE
fprintf(stderr,"PortMapper: UPnP: UPNP_AddPortMapping(%s) failed: %d"ZT_EOL_S,outport,mapResult);
#endif
Thread::sleep(1000);
}
}
} else {
mode = 0;
#ifdef ZT_PORTMAPPER_TRACE
fprintf(stderr,"PortMapper: UPnP: UPNP_GetExternalIPAddress failed, returning to NAT-PMP mode"ZT_EOL_S);
#endif
}
} else {
mode = 0;
#ifdef ZT_PORTMAPPER_TRACE
fprintf(stderr,"PortMapper: UPnP: UPNP_GetValidIGD failed, returning to NAT-PMP mode"ZT_EOL_S);
#endif
}
freeUPNPDevlist(devlist);
} else {
mode = 0;
#ifdef ZT_PORTMAPPER_TRACE
fprintf(stderr,"PortMapper: upnpDiscover failed, returning to NAT-PMP mode: %d"ZT_EOL_S,upnpError);
#endif
}
}
// ---------------------------------------------------------------------
#ifdef ZT_PORTMAPPER_TRACE
fprintf(stderr,"UPNPClient: rescanning in %d ms"ZT_EOL_S,ZT_PORTMAPPER_REFRESH_DELAY);
#endif
Thread::sleep(ZT_PORTMAPPER_REFRESH_DELAY);
}
delete this;
}
volatile bool run;
int localPort;
std::string uniqueName;
Mutex surface_l;
std::vector<InetAddress> surface;
};
PortMapper::PortMapper(int localUdpPortToMap,const char *uniqueName)
{
_impl = new PortMapperImpl(localUdpPortToMap,uniqueName);
Thread::start(_impl);
}
PortMapper::~PortMapper()
{
_impl->run = false;
}
std::vector<InetAddress> PortMapper::get() const
{
Mutex::Lock _l(_impl->surface_l);
return _impl->surface;
}
} // namespace ZeroTier
#endif // ZT_USE_MINIUPNPC

View File

@ -25,11 +25,11 @@
* LLC. Start here: http://www.zerotier.com/
*/
#ifndef ZT_UPNPCLIENT_HPP
#define ZT_UPNPCLIENT_HPP
#ifdef ZT_USE_MINIUPNPC
#ifndef ZT_PORTMAPPER_HPP
#define ZT_PORTMAPPER_HPP
#include <vector>
#include "../node/Constants.hpp"
@ -40,28 +40,29 @@
/**
* How frequently should we refresh our UPNP/NAT-PnP/whatever state?
*/
#define ZT_UPNP_CLIENT_REFRESH_DELAY 600000
#define ZT_PORTMAPPER_REFRESH_DELAY 300000
namespace ZeroTier {
class UPNPClientImpl;
class PortMapperImpl;
/**
* UPnP/NAT-PnP daemon thread
* UPnP/NAT-PnP port mapping "daemon"
*/
class UPNPClient
class PortMapper
{
friend class UPNPClientImpl;
friend class PortMapperImpl;
public:
/**
* Create and start UPNP client service
* Create and start port mapper service
*
* @param localUdpPortToMap Port we want visible to the outside world
* @param name Unique name of this endpoint (based on ZeroTier address)
*/
UPNPClient(int localUdpPortToMap);
PortMapper(int localUdpPortToMap,const char *uniqueName);
~UPNPClient();
~PortMapper();
/**
* @return All current external mappings for our port
@ -69,11 +70,11 @@ public:
std::vector<InetAddress> get() const;
private:
UPNPClientImpl *_impl;
PortMapperImpl *_impl;
};
} // namespace ZeroTier
#endif // ZT_USE_MINIUPNPC
#endif
#endif // ZT_USE_MINIUPNPC

View File

@ -1,198 +0,0 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2015 ZeroTier, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
* ZeroTier may be used and distributed under the terms of the GPLv3, which
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
*
* If you would like to embed ZeroTier into a commercial application or
* redistribute it in a modified binary form, please contact ZeroTier Networks
* LLC. Start here: http://www.zerotier.com/
*/
#ifdef ZT_USE_MINIUPNPC
// Uncomment to dump debug messages
//#define ZT_UPNP_TRACE 1
// Uncomment to build a main() for ad-hoc testing
//#define ZT_UPNP_TEST 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../node/Utils.hpp"
#include "UPNPClient.hpp"
#ifdef __WINDOWS__
#ifndef MINIUPNP_STATICLIB
#define MINIUPNP_STATICLIB
#endif
#endif
#include "../ext/miniupnpc/miniupnpc.h"
#include "../ext/miniupnpc/upnpcommands.h"
namespace ZeroTier {
class UPNPClientImpl
{
public:
UPNPClientImpl(int localUdpPortToMap) :
run(true),
localPort(localUdpPortToMap)
{
}
void threadMain()
throw()
{
char lanaddr[4096];
char externalip[4096]; // no range checking? so make these buffers larger than any UDP packet a uPnP server could send us as a precaution :P
char inport[16];
char outport[16];
struct UPNPUrls urls;
struct IGDdatas data;
#ifdef ZT_UPNP_TRACE
fprintf(stderr,"UPNPClient: started for UDP port %d"ZT_EOL_S,localPort);
#endif
unsigned int tryPortStart = 0;
Utils::getSecureRandom(&tryPortStart,sizeof(tryPortStart));
tryPortStart = (tryPortStart % (65535 - 1025)) + 1025;
while (run) {
{
int upnpError = 0;
UPNPDev *devlist = upnpDiscover(2000,(const char *)0,(const char *)0,0,0,0,&upnpError);
if (devlist) {
#ifdef ZT_UPNP_TRACE
{
UPNPDev *dev = devlist;
while (dev) {
fprintf(stderr,"UPNPClient: found device at URL '%s': %s"ZT_EOL_S,dev->descURL,dev->st);
dev = dev->pNext;
}
}
#endif
memset(lanaddr,0,sizeof(lanaddr));
memset(externalip,0,sizeof(externalip));
memset(&urls,0,sizeof(urls));
memset(&data,0,sizeof(data));
Utils::snprintf(inport,sizeof(inport),"%d",localPort);
if ((UPNP_GetValidIGD(devlist,&urls,&data,lanaddr,sizeof(lanaddr)))&&(lanaddr[0])) {
#ifdef ZT_UPNP_TRACE
fprintf(stderr,"UPNPClient: my LAN IP address: %s"ZT_EOL_S,lanaddr);
#endif
if ((UPNP_GetExternalIPAddress(urls.controlURL,data.first.servicetype,externalip) == UPNPCOMMAND_SUCCESS)&&(externalip[0])) {
#ifdef ZT_UPNP_TRACE
fprintf(stderr,"UPNPClient: my external IP address: %s"ZT_EOL_S,externalip);
#endif
for(int tries=0;tries<64;++tries) {
int tryPort = (int)tryPortStart + tries;
if (tryPort >= 65535)
tryPort = (tryPort - 65535) + 1025;
Utils::snprintf(outport,sizeof(outport),"%u",tryPort);
int mapResult = 0;
if ((mapResult = UPNP_AddPortMapping(urls.controlURL,data.first.servicetype,outport,inport,lanaddr,"ZeroTier","UDP",(const char *)0,"0")) == UPNPCOMMAND_SUCCESS) {
#ifdef ZT_UPNP_TRACE
fprintf(stderr,"UPNPClient: reserved external port: %s"ZT_EOL_S,outport);
#endif
{
Mutex::Lock sl(surface_l);
surface.clear();
InetAddress tmp(externalip);
tmp.setPort(tryPort);
surface.push_back(tmp);
}
break;
} else {
#ifdef ZT_UPNP_TRACE
fprintf(stderr,"UPNPClient: UPNP_AddAnyPortMapping(%s) failed: %d"ZT_EOL_S,outport,mapResult);
#endif
Thread::sleep(1000);
}
}
} else {
#ifdef ZT_UPNP_TRACE
fprintf(stderr,"UPNPClient: UPNP_GetExternalIPAddress failed"ZT_EOL_S);
#endif
}
} else {
#ifdef ZT_UPNP_TRACE
fprintf(stderr,"UPNPClient: UPNP_GetValidIGD failed"ZT_EOL_S);
#endif
}
freeUPNPDevlist(devlist);
} else {
#ifdef ZT_UPNP_TRACE
fprintf(stderr,"UPNPClient: upnpDiscover error code: %d"ZT_EOL_S,upnpError);
#endif
}
}
#ifdef ZT_UPNP_TRACE
fprintf(stderr,"UPNPClient: rescanning in %d ms"ZT_EOL_S,ZT_UPNP_CLIENT_REFRESH_DELAY);
#endif
Thread::sleep(ZT_UPNP_CLIENT_REFRESH_DELAY);
}
delete this;
}
volatile bool run;
int localPort;
Mutex surface_l;
std::vector<InetAddress> surface;
};
UPNPClient::UPNPClient(int localUdpPortToMap)
{
_impl = new UPNPClientImpl(localUdpPortToMap);
Thread::start(_impl);
}
UPNPClient::~UPNPClient()
{
_impl->run = false;
}
std::vector<InetAddress> UPNPClient::get() const
{
Mutex::Lock _l(_impl->surface_l);
return _impl->surface;
}
} // namespace ZeroTier
#ifdef ZT_UPNP_TEST
int main(int argc,char **argv)
{
ZeroTier::UPNPClient *client = new ZeroTier::UPNPClient(12345);
ZeroTier::Thread::sleep(0xffffffff); // wait forever
return 0;
}
#endif
#endif // ZT_USE_MINIUPNPC

View File

@ -58,6 +58,8 @@
#include "osdep/Phy.hpp"
#include "osdep/Http.hpp"
#include "osdep/BackgroundResolver.hpp"
#include "osdep/PortMapper.hpp"
#include "osdep/Thread.hpp"
#ifdef ZT_ENABLE_NETWORK_CONTROLLER
#include "controller/SqliteNetworkController.hpp"
@ -1094,6 +1096,7 @@ int main(int argc,char **argv)
srand((unsigned int)time(0));
/*
r |= testSqliteNetworkController();
r |= testOther();
r |= testCrypto();
@ -1103,9 +1106,17 @@ int main(int argc,char **argv)
r |= testPhy();
r |= testResolver();
//r |= testHttp();
*/
if (r)
std::cout << std::endl << "SOMETHING FAILED!" << std::endl;
#ifdef ZT_USE_MINIUPNPC
std::cout << std::endl;
std::cout << "[portmapper] Starting port mapper and waiting forever... use CTRL+C to exit. (enable ZT_PORTMAPPER_TRACE in PortMapper.cpp for output)" << std::endl;
PortMapper mapper(12345,"ZeroTier/__selftest");
Thread::sleep(0xffffffff);
#endif
return r;
}

View File

@ -54,7 +54,7 @@
#include "../osdep/OSUtils.hpp"
#include "../osdep/Http.hpp"
#include "../osdep/BackgroundResolver.hpp"
#include "../osdep/UPNPClient.hpp"
#include "../osdep/PortMapper.hpp"
#include "OneService.hpp"
#include "ControlPlane.hpp"
@ -467,7 +467,7 @@ public:
,_port(0)
#ifdef ZT_USE_MINIUPNPC
,_v4UpnpUdpSocket((PhySocket *)0)
,_upnpClient((UPNPClient *)0)
,_portMapper((PortMapper *)0)
#endif
#ifdef ZT_ENABLE_CLUSTER
,_clusterMessageSocket((PhySocket *)0)
@ -523,22 +523,6 @@ public:
char portstr[64];
Utils::snprintf(portstr,sizeof(portstr),"%u",_port);
OSUtils::writeFile((_homePath + ZT_PATH_SEPARATOR_S + "zerotier-one.port").c_str(),std::string(portstr));
#ifdef ZT_USE_MINIUPNPC
// Bind a secondary port for use with uPnP, since some NAT routers
// (cough Ubiquity Edge cough) barf up a lung if you do both conventional
// NAT-t and uPnP from behind the same port. I think this is a bug, but
// everyone else's router bugs are our problem. :P
for(int k=0;k<512;++k) {
const unsigned int upnport = 40000 + (((port + 1) * (k + 1)) % 25500);
_v4UpnpLocalAddress = InetAddress(0,upnport);
_v4UpnpUdpSocket = _phy.udpBind((const struct sockaddr *)&_v4UpnpLocalAddress,reinterpret_cast<void *>(&_v4UpnpLocalAddress),ZT_UDP_DESIRED_BUF_SIZE);
if (_v4UpnpUdpSocket) {
_upnpClient = new UPNPClient(upnport);
break;
}
}
#endif
}
virtual ~OneServiceImpl()
@ -552,7 +536,7 @@ public:
#endif
#ifdef ZT_USE_MINIUPNPC
_phy.close(_v4UpnpUdpSocket);
delete _upnpClient;
delete _portMapper;
#endif
#ifdef ZT_ENABLE_NETWORK_CONTROLLER
delete _controller;
@ -595,73 +579,91 @@ public:
SnodeVirtualNetworkConfigFunction,
SnodeEventCallback);
#ifdef ZT_USE_MINIUPNPC
// Bind a secondary port for use with uPnP, since some NAT routers
// (cough Ubiquity Edge cough) barf up a lung if you do both conventional
// NAT-t and uPnP from behind the same port. I think this is a bug, but
// everyone else's router bugs are our problem. :P
for(int k=0;k<512;++k) {
unsigned int mapperPort = 40000 + (((_port + 1) * (k + 1)) % 25500);
char uniqueName[64];
_v4UpnpLocalAddress = InetAddress(0,mapperPort);
_v4UpnpUdpSocket = _phy.udpBind((const struct sockaddr *)&_v4UpnpLocalAddress,reinterpret_cast<void *>(&_v4UpnpLocalAddress),ZT_UDP_DESIRED_BUF_SIZE);
if (_v4UpnpUdpSocket) {
Utils::snprintf(uniqueName,sizeof(uniqueName),"ZeroTier/%.16llx",_node->address());
_portMapper = new PortMapper(mapperPort,uniqueName);
break;
}
}
#endif
#ifdef ZT_ENABLE_NETWORK_CONTROLLER
_controller = new SqliteNetworkController(_node,(_homePath + ZT_PATH_SEPARATOR_S + ZT_CONTROLLER_DB_PATH).c_str(),(_homePath + ZT_PATH_SEPARATOR_S + "circuitTestResults.d").c_str());
_node->setNetconfMaster((void *)_controller);
#endif
#ifdef ZT_ENABLE_CLUSTER
if (OSUtils::fileExists((_homePath + ZT_PATH_SEPARATOR_S + "cluster").c_str())) {
_clusterDefinition = new ClusterDefinition(_node->address(),(_homePath + ZT_PATH_SEPARATOR_S + "cluster").c_str());
if (_clusterDefinition->size() > 0) {
std::vector<ClusterDefinition::MemberDefinition> members(_clusterDefinition->members());
for(std::vector<ClusterDefinition::MemberDefinition>::iterator m(members.begin());m!=members.end();++m) {
PhySocket *cs = _phy.udpBind(reinterpret_cast<const struct sockaddr *>(&(m->clusterEndpoint)));
if (cs) {
if (_clusterMessageSocket) {
_phy.close(_clusterMessageSocket,false);
_phy.close(cs,false);
Mutex::Lock _l(_termReason_m);
_termReason = ONE_UNRECOVERABLE_ERROR;
_fatalErrorMessage = "Cluster: can't determine my cluster member ID: able to bind more than one cluster message socket IP/port!";
return _termReason;
}
_clusterMessageSocket = cs;
_clusterMemberId = m->id;
}
}
if (!_clusterMessageSocket) {
Mutex::Lock _l(_termReason_m);
_termReason = ONE_UNRECOVERABLE_ERROR;
_fatalErrorMessage = "Cluster: can't determine my cluster member ID: unable to bind to any cluster message socket IP/port.";
return _termReason;
}
if (OSUtils::fileExists((_homePath + ZT_PATH_SEPARATOR_S + "cluster-geo.exe").c_str()))
_clusterGeoIpService = new ClusterGeoIpService((_homePath + ZT_PATH_SEPARATOR_S + "cluster-geo.exe").c_str());
const ClusterDefinition::MemberDefinition &me = (*_clusterDefinition)[_clusterMemberId];
InetAddress endpoints[255];
unsigned int numEndpoints = 0;
for(std::vector<InetAddress>::const_iterator i(me.zeroTierEndpoints.begin());i!=me.zeroTierEndpoints.end();++i)
endpoints[numEndpoints++] = *i;
if (_node->clusterInit(
_clusterMemberId,
reinterpret_cast<const struct sockaddr_storage *>(endpoints),
numEndpoints,
me.x,
me.y,
me.z,
&SclusterSendFunction,
this,
(_clusterGeoIpService) ? &SclusterGeoIpFunction : 0,
this) == ZT_RESULT_OK) {
if (OSUtils::fileExists((_homePath + ZT_PATH_SEPARATOR_S + "cluster").c_str())) {
_clusterDefinition = new ClusterDefinition(_node->address(),(_homePath + ZT_PATH_SEPARATOR_S + "cluster").c_str());
if (_clusterDefinition->size() > 0) {
std::vector<ClusterDefinition::MemberDefinition> members(_clusterDefinition->members());
for(std::vector<ClusterDefinition::MemberDefinition>::iterator m(members.begin());m!=members.end();++m) {
if (m->id != _clusterMemberId)
_node->clusterAddMember(m->id);
PhySocket *cs = _phy.udpBind(reinterpret_cast<const struct sockaddr *>(&(m->clusterEndpoint)));
if (cs) {
if (_clusterMessageSocket) {
_phy.close(_clusterMessageSocket,false);
_phy.close(cs,false);
Mutex::Lock _l(_termReason_m);
_termReason = ONE_UNRECOVERABLE_ERROR;
_fatalErrorMessage = "Cluster: can't determine my cluster member ID: able to bind more than one cluster message socket IP/port!";
return _termReason;
}
_clusterMessageSocket = cs;
_clusterMemberId = m->id;
}
}
if (!_clusterMessageSocket) {
Mutex::Lock _l(_termReason_m);
_termReason = ONE_UNRECOVERABLE_ERROR;
_fatalErrorMessage = "Cluster: can't determine my cluster member ID: unable to bind to any cluster message socket IP/port.";
return _termReason;
}
if (OSUtils::fileExists((_homePath + ZT_PATH_SEPARATOR_S + "cluster-geo.exe").c_str()))
_clusterGeoIpService = new ClusterGeoIpService((_homePath + ZT_PATH_SEPARATOR_S + "cluster-geo.exe").c_str());
const ClusterDefinition::MemberDefinition &me = (*_clusterDefinition)[_clusterMemberId];
InetAddress endpoints[255];
unsigned int numEndpoints = 0;
for(std::vector<InetAddress>::const_iterator i(me.zeroTierEndpoints.begin());i!=me.zeroTierEndpoints.end();++i)
endpoints[numEndpoints++] = *i;
if (_node->clusterInit(
_clusterMemberId,
reinterpret_cast<const struct sockaddr_storage *>(endpoints),
numEndpoints,
me.x,
me.y,
me.z,
&SclusterSendFunction,
this,
(_clusterGeoIpService) ? &SclusterGeoIpFunction : 0,
this) == ZT_RESULT_OK) {
std::vector<ClusterDefinition::MemberDefinition> members(_clusterDefinition->members());
for(std::vector<ClusterDefinition::MemberDefinition>::iterator m(members.begin());m!=members.end();++m) {
if (m->id != _clusterMemberId)
_node->clusterAddMember(m->id);
}
}
} else {
delete _clusterDefinition;
_clusterDefinition = (ClusterDefinition *)0;
}
} else {
delete _clusterDefinition;
_clusterDefinition = (ClusterDefinition *)0;
}
}
#endif
_controlPlane = new ControlPlane(this,_node,(_homePath + ZT_PATH_SEPARATOR_S + "ui").c_str());
@ -689,7 +691,7 @@ public:
_lastRestart = clockShouldBe;
uint64_t lastTapMulticastGroupCheck = 0;
uint64_t lastTcpFallbackResolve = 0;
uint64_t lastLocalInterfaceAddressCheck = (OSUtils::now() - ZT_LOCAL_INTERFACE_CHECK_INTERVAL) + 15000; // do this in 15s to give UPnP time to configure and other things time to settle
uint64_t lastLocalInterfaceAddressCheck = (OSUtils::now() - ZT_LOCAL_INTERFACE_CHECK_INTERVAL) + 15000; // do this in 15s to give portmapper time to configure and other things time to settle
#ifdef ZT_AUTO_UPDATE
uint64_t lastSoftwareUpdateCheck = 0;
#endif // ZT_AUTO_UPDATE
@ -757,8 +759,8 @@ public:
_node->clearLocalInterfaceAddresses();
#ifdef ZT_USE_MINIUPNPC
std::vector<InetAddress> upnpAddresses(_upnpClient->get());
for(std::vector<InetAddress>::const_iterator ext(upnpAddresses.begin());ext!=upnpAddresses.end();++ext)
std::vector<InetAddress> mappedAddresses(_portMapper->get());
for(std::vector<InetAddress>::const_iterator ext(mappedAddresses.begin());ext!=mappedAddresses.end();++ext)
_node->addLocalInterfaceAddress(reinterpret_cast<const struct sockaddr_storage *>(&(*ext)));
#endif
@ -1162,11 +1164,13 @@ public:
newAssignedIps.erase(std::unique(newAssignedIps.begin(),newAssignedIps.end()),newAssignedIps.end());
for(std::vector<InetAddress>::iterator ip(newAssignedIps.begin());ip!=newAssignedIps.end();++ip) {
if (!std::binary_search(assignedIps.begin(),assignedIps.end(),*ip))
t->second->addIp(*ip);
if (!t->second->addIp(*ip))
fprintf(stderr,"ERROR: unable to add ip address %s"ZT_EOL_S, ip->toString().c_str());
}
for(std::vector<InetAddress>::iterator ip(assignedIps.begin());ip!=assignedIps.end();++ip) {
if (!std::binary_search(newAssignedIps.begin(),newAssignedIps.end(),*ip))
t->second->removeIp(*ip);
if (!t->second->removeIp(*ip))
fprintf(stderr,"ERROR: unable to remove ip address %s"ZT_EOL_S, ip->toString().c_str());
}
assignedIps.swap(newAssignedIps);
} else {
@ -1485,7 +1489,7 @@ public:
#ifdef ZT_USE_MINIUPNPC
InetAddress _v4UpnpLocalAddress;
PhySocket *_v4UpnpUdpSocket;
UPNPClient *_upnpClient;
PortMapper *_portMapper;
#endif
#ifdef ZT_ENABLE_CLUSTER