diff --git a/AUTHORS.md b/AUTHORS.md
index 4900aab5..b286e7ca 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -39,3 +39,6 @@
digital signature algorithm, and Poly1305 MAC algorithm, all by
Daniel J. Bernstein (public domain)
http://cr.yp.to/
+
+ * MiniUPNPC by Thomas Bernard [BSD]
+ http://miniupnp.free.fr
diff --git a/controller/SqliteNetworkController.cpp b/controller/SqliteNetworkController.cpp
index 700b3561..50be5b34 100644
--- a/controller/SqliteNetworkController.cpp
+++ b/controller/SqliteNetworkController.cpp
@@ -64,6 +64,10 @@
// API version reported via JSON control plane
#define ZT_NETCONF_CONTROLLER_API_VERSION 1
+// Drop requests for a given peer and network ID that occur more frequently
+// than this (ms).
+#define ZT_NETCONF_MIN_REQUEST_PERIOD 1000
+
namespace ZeroTier {
namespace {
@@ -142,6 +146,7 @@ SqliteNetworkController::SqliteNetworkController(const char *dbPath) :
// Prepare statement will fail if Config table doesn't exist, which means our DB
// needs to be initialized.
if (sqlite3_exec(_db,ZT_NETCONF_SCHEMA_SQL"INSERT INTO Config (k,v) VALUES ('schemaVersion',"ZT_NETCONF_SQLITE_SCHEMA_VERSION_STR");",0,0,0) != SQLITE_OK) {
+ //printf("%s\n",sqlite3_errmsg(_db));
sqlite3_close(_db);
throw std::runtime_error("SqliteNetworkController cannot initialize database and/or insert schemaVersion into Config table");
}
@@ -199,16 +204,21 @@ SqliteNetworkController::SqliteNetworkController(const char *dbPath) :
||(sqlite3_prepare_v2(_db,"DELETE FROM Member WHERE networkId = ? AND nodeId = ?",-1,&_sDeleteMember,(const char **)0) != SQLITE_OK)
/* Gateway */
- ||(sqlite3_prepare_v2(_db,"SELECT ip,ipVersion,metric FROM Gateway WHERE networkId = ? ORDER BY metric ASC",-1,&_sGetGateways,(const char **)0) != SQLITE_OK)
+ ||(sqlite3_prepare_v2(_db,"SELECT \"ip\",ipVersion,metric FROM Gateway WHERE networkId = ? ORDER BY metric ASC",-1,&_sGetGateways,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"DELETE FROM Gateway WHERE networkId = ?",-1,&_sDeleteGateways,(const char **)0) != SQLITE_OK)
- ||(sqlite3_prepare_v2(_db,"INSERT INTO Gateway (networkId,ip,ipVersion,metric) VALUES (?,?,?,?)",-1,&_sCreateGateway,(const char **)0) != SQLITE_OK)
+ ||(sqlite3_prepare_v2(_db,"INSERT INTO Gateway (networkId,\"ip\",ipVersion,metric) VALUES (?,?,?,?)",-1,&_sCreateGateway,(const char **)0) != SQLITE_OK)
+
+ /* Log */
+ ||(sqlite3_prepare_v2(_db,"INSERT INTO \"Log\" (networkId,nodeId,\"ts\",\"authorized\",\"version\",fromAddr) VALUES (?,?,?,?,?,?)",-1,&_sPutLog,(const char **)0) != SQLITE_OK)
+ ||(sqlite3_prepare_v2(_db,"SELECT \"ts\",\"authorized\",\"version\",fromAddr FROM \"Log\" WHERE networkId = ? AND nodeId = ? AND \"ts\" >= ? ORDER BY \"ts\" ASC",-1,&_sGetMemberLog,(const char **)0) != SQLITE_OK)
+ ||(sqlite3_prepare_v2(_db,"SELECT \"ts\",\"authorized\",\"version\",fromAddr FROM \"Log\" WHERE networkId = ? AND nodeId = ? ORDER BY \"ts\" DESC LIMIT 10",-1,&_sGetRecentMemberLog,(const char **)0) != SQLITE_OK)
/* Config */
||(sqlite3_prepare_v2(_db,"SELECT \"v\" FROM \"Config\" WHERE \"k\" = ?",-1,&_sGetConfig,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"INSERT OR REPLACE INTO \"Config\" (\"k\",\"v\") VALUES (?,?)",-1,&_sSetConfig,(const char **)0) != SQLITE_OK)
) {
- //printf("!!! %s\n",sqlite3_errmsg(_db));
+ //printf("%s\n",sqlite3_errmsg(_db));
sqlite3_close(_db);
throw std::runtime_error("SqliteNetworkController unable to initialize one or more prepared statements");
}
@@ -283,12 +293,21 @@ SqliteNetworkController::~SqliteNetworkController()
sqlite3_finalize(_sIncrementMemberRevisionCounter);
sqlite3_finalize(_sGetConfig);
sqlite3_finalize(_sSetConfig);
+ sqlite3_finalize(_sPutLog);
+ sqlite3_finalize(_sGetMemberLog);
+ sqlite3_finalize(_sGetRecentMemberLog);
sqlite3_close(_db);
}
}
NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(const InetAddress &fromAddr,const Identity &signingId,const Identity &identity,uint64_t nwid,const Dictionary &metaData,uint64_t haveRevision,Dictionary &netconf)
{
+ // Decode some stuff from metaData
+ const unsigned int clientMajorVersion = (unsigned int)metaData.getHexUInt(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION,0);
+ const unsigned int clientMinorVersion = (unsigned int)metaData.getHexUInt(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION,0);
+ const unsigned int clientRevision = (unsigned int)metaData.getHexUInt(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION,0);
+ const bool clientIs104 = (Utils::compareVersion(clientMajorVersion,clientMinorVersion,clientRevision,1,0,4) >= 0);
+
Mutex::Lock _l(_lock);
// Note: we can't reuse prepared statements that return const char * pointers without
@@ -303,6 +322,15 @@ NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(co
return NetworkController::NETCONF_QUERY_INTERNAL_SERVER_ERROR;
}
+ // Check rate limit
+
+ {
+ uint64_t &lrt = _lastRequestTime[std::pair
(identity.address(),nwid)];
+ uint64_t lrt2 = lrt;
+ if (((lrt = OSUtils::now()) - lrt2) <= ZT_NETCONF_MIN_REQUEST_PERIOD)
+ return NetworkController::NETCONF_QUERY_IGNORE;
+ }
+
NetworkRecord network;
memset(&network,0,sizeof(network));
Utils::snprintf(network.id,sizeof(network.id),"%.16llx",(unsigned long long)nwid);
@@ -387,18 +415,35 @@ NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(co
sqlite3_step(_sIncrementMemberRevisionCounter);
}
+ // Add log entry
+ {
+ char ver[16];
+ std::string fa;
+ if (fromAddr) {
+ fa = fromAddr.toString();
+ if (fa.length() > 64)
+ fa = fa.substr(0,64);
+ }
+ sqlite3_reset(_sPutLog);
+ sqlite3_bind_text(_sPutLog,1,network.id,16,SQLITE_STATIC);
+ sqlite3_bind_text(_sPutLog,2,member.nodeId,10,SQLITE_STATIC);
+ sqlite3_bind_int64(_sPutLog,3,(long long)OSUtils::now());
+ sqlite3_bind_int(_sPutLog,4,member.authorized ? 1 : 0);
+ if ((clientMajorVersion > 0)||(clientMinorVersion > 0)||(clientRevision > 0)) {
+ Utils::snprintf(ver,sizeof(ver),"%u.%u.%u",clientMajorVersion,clientMinorVersion,clientRevision);
+ sqlite3_bind_text(_sPutLog,5,ver,-1,SQLITE_STATIC);
+ } else sqlite3_bind_null(_sPutLog,5);
+ if (fa.length() > 0)
+ sqlite3_bind_text(_sPutLog,6,fa.c_str(),-1,SQLITE_STATIC);
+ else sqlite3_bind_null(_sPutLog,6);
+ sqlite3_step(_sPutLog);
+ }
+
// Check member authorization
if (!member.authorized)
return NetworkController::NETCONF_QUERY_ACCESS_DENIED;
- // If netconf is unchanged from client reported revision, just tell client they're up to date
-
- // Temporarily disabled -- old version didn't do this, and we'll go ahead and
- // test more thoroughly before enabling this optimization.
- //if ((haveRevision > 0)&&(haveRevision == network.revision))
- // return NetworkController::NETCONF_QUERY_OK_BUT_NOT_NEWER;
-
// Create and sign netconf
netconf.clear();
@@ -555,7 +600,8 @@ NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(co
if ((ipNetmaskBits <= 0)||(ipNetmaskBits > 32))
continue;
- switch((IpAssignmentType)sqlite3_column_int(_sGetIpAssignmentsForNode,0)) {
+ const IpAssignmentType ipt = (IpAssignmentType)sqlite3_column_int(_sGetIpAssignmentsForNode,0);
+ switch(ipt) {
case ZT_IP_ASSIGNMENT_TYPE_ADDRESS:
haveStaticIpAssignment = true;
break;
@@ -566,13 +612,15 @@ NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(co
continue;
}
- // We send both routes and IP assignments -- client knows which is
- // which by whether address ends in all zeroes after netmask.
- char tmp[32];
- Utils::snprintf(tmp,sizeof(tmp),"%d.%d.%d.%d/%d",(int)ip[12],(int)ip[13],(int)ip[14],(int)ip[15],ipNetmaskBits);
- if (v4s.length())
- v4s.push_back(',');
- v4s.append(tmp);
+ // 1.0.4 or newer clients support network routes in addition to IPs.
+ // Older clients only support IP address / netmask entries.
+ if ((clientIs104)||(ipt == ZT_IP_ASSIGNMENT_TYPE_ADDRESS)) {
+ char tmp[32];
+ Utils::snprintf(tmp,sizeof(tmp),"%d.%d.%d.%d/%d",(int)ip[12],(int)ip[13],(int)ip[14],(int)ip[15],ipNetmaskBits);
+ if (v4s.length())
+ v4s.push_back(',');
+ v4s.append(tmp);
+ }
}
if (!haveStaticIpAssignment) {
@@ -648,7 +696,7 @@ NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(co
// TODO: IPv6 auto-assign once it's supported in UI
if (network.isPrivate) {
- CertificateOfMembership com(network.revision,ZT1_CERTIFICATE_OF_MEMBERSHIP_REVISION_MAX_DELTA,nwid,identity.address());
+ CertificateOfMembership com(OSUtils::now(),ZT_NETWORK_AUTOCONF_DELAY + (ZT_NETWORK_AUTOCONF_DELAY / 2),nwid,identity.address());
if (com.sign(signingId)) // basically can't fail unless our identity is invalid
netconf[ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATE_OF_MEMBERSHIP] = com.toString();
else {
@@ -716,6 +764,8 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST(
char addrs[24];
Utils::snprintf(addrs,sizeof(addrs),"%.10llx",address);
+ int64_t addToNetworkRevision = 0;
+
int64_t memberRowId = 0;
sqlite3_reset(_sGetMember);
sqlite3_bind_text(_sGetMember,1,nwids,16,SQLITE_STATIC);
@@ -739,6 +789,7 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST(
sqlite3_reset(_sIncrementMemberRevisionCounter);
sqlite3_bind_text(_sIncrementMemberRevisionCounter,1,nwids,16,SQLITE_STATIC);
sqlite3_step(_sIncrementMemberRevisionCounter);
+ addToNetworkRevision = 1;
}
json_value *j = json_parse(body.c_str(),body.length());
@@ -758,6 +809,7 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST(
sqlite3_reset(_sIncrementMemberRevisionCounter);
sqlite3_bind_text(_sIncrementMemberRevisionCounter,1,nwids,16,SQLITE_STATIC);
sqlite3_step(_sIncrementMemberRevisionCounter);
+ addToNetworkRevision = 1;
}
} else if (!strcmp(j->u.object.values[k].name,"activeBridge")) {
if (j->u.object.values[k].value->type == json_boolean) {
@@ -771,6 +823,7 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST(
sqlite3_reset(_sIncrementMemberRevisionCounter);
sqlite3_bind_text(_sIncrementMemberRevisionCounter,1,nwids,16,SQLITE_STATIC);
sqlite3_step(_sIncrementMemberRevisionCounter);
+ addToNetworkRevision = 1;
}
} else if (!strcmp(j->u.object.values[k].name,"ipAssignments")) {
if (j->u.object.values[k].value->type == json_array) {
@@ -814,6 +867,7 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST(
}
}
}
+ addToNetworkRevision = 1;
}
}
@@ -822,6 +876,13 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST(
json_value_free(j);
}
+ if ((addToNetworkRevision > 0)&&(revision > 0)) {
+ sqlite3_reset(_sSetNetworkRevision);
+ sqlite3_bind_int64(_sSetNetworkRevision,1,revision + addToNetworkRevision);
+ sqlite3_bind_text(_sSetNetworkRevision,2,nwids,16,SQLITE_STATIC);
+ sqlite3_step(_sSetNetworkRevision);
+ }
+
return _doCPGet(path,urlArgs,headers,body,responseBody,responseContentType);
} // else 404
@@ -1332,58 +1393,33 @@ unsigned int SqliteNetworkController::_doCPGet(
responseBody.push_back('"');
}
- responseBody.append("]");
+ responseBody.append("],\n\t\"recentLog\": [");
- /* It's possible to get the actual netconf dictionary by including these
- * three URL arguments. The member identity must be the string
- * serialized identity of this member, and the signing identity must be
- * the full secret identity of this network controller. The have revision
- * is optional but would designate the revision our hypothetical client
- * already has.
- *
- * This is primarily for testing and is not used in production. It makes
- * it easy to test the entire network controller via its JSON API.
- *
- * If these arguments are included, three more object fields are returned:
- * 'netconf', 'netconfResult', and 'netconfResultMessage'. These are all
- * string fields and contain the actual netconf dictionary, the query
- * result code, and any verbose message e.g. an error description. */
- std::map::const_iterator memids(urlArgs.find("memberIdentity"));
- std::map::const_iterator sigids(urlArgs.find("signingIdentity"));
- std::map::const_iterator hrs(urlArgs.find("haveRevision"));
- if ((memids != urlArgs.end())&&(sigids != urlArgs.end())) {
- Dictionary netconf;
- Identity memid,sigid;
- try {
- if (memid.fromString(memids->second)&&sigid.fromString(sigids->second)&&sigid.hasPrivate()) {
- uint64_t hr = 0;
- if (hrs != urlArgs.end())
- hr = Utils::strToU64(hrs->second.c_str());
- const char *result = "";
- switch(this->doNetworkConfigRequest(InetAddress(),sigid,memid,nwid,Dictionary(),hr,netconf)) {
- case NetworkController::NETCONF_QUERY_OK: result = "OK"; break;
- case NetworkController::NETCONF_QUERY_OK_BUT_NOT_NEWER: result = "OK_BUT_NOT_NEWER"; break;
- case NetworkController::NETCONF_QUERY_OBJECT_NOT_FOUND: result = "OBJECT_NOT_FOUND"; break;
- case NetworkController::NETCONF_QUERY_ACCESS_DENIED: result = "ACCESS_DENIED"; break;
- case NetworkController::NETCONF_QUERY_INTERNAL_SERVER_ERROR: result = "INTERNAL_SERVER_ERROR"; break;
- default: result = "(unrecognized result code)"; break;
- }
- responseBody.append(",\n\t\"netconf\": \"");
- responseBody.append(_jsonEscape(netconf.toString().c_str()));
- responseBody.append("\",\n\t\"netconfResult\": \"");
- responseBody.append(result);
- responseBody.append("\",\n\t\"netconfResultMessage\": \"");
- responseBody.append(_jsonEscape(netconf["error"].c_str()));
- responseBody.append("\"");
- } else {
- responseBody.append(",\n\t\"netconf\": \"\",\n\t\"netconfResult\": \"INTERNAL_SERVER_ERROR\",\n\t\"netconfResultMessage\": \"invalid member or signing identity\"");
- }
- } catch ( ... ) {
- responseBody.append(",\n\t\"netconf\": \"\",\n\t\"netconfResult\": \"INTERNAL_SERVER_ERROR\",\n\t\"netconfResultMessage\": \"unexpected exception\"");
- }
+ sqlite3_reset(_sGetRecentMemberLog);
+ sqlite3_bind_text(_sGetRecentMemberLog,1,nwids,16,SQLITE_STATIC);
+ sqlite3_bind_text(_sGetRecentMemberLog,2,addrs,10,SQLITE_STATIC);
+ bool firstLog = true;
+ while (sqlite3_step(_sGetRecentMemberLog) == SQLITE_ROW) {
+ responseBody.append(firstLog ? "{" : ",{");
+ firstLog = false;
+ responseBody.append("\"ts\":");
+ responseBody.append(reinterpret_cast(sqlite3_column_text(_sGetRecentMemberLog,0)));
+ responseBody.append((sqlite3_column_int(_sGetRecentMemberLog,1) == 0) ? ",\"authorized\":false,\"version\":" : ",\"authorized\":true,\"version\":");
+ const char *ver = reinterpret_cast(sqlite3_column_text(_sGetRecentMemberLog,2));
+ if ((ver)&&(ver[0])) {
+ responseBody.push_back('"');
+ responseBody.append(_jsonEscape(ver));
+ responseBody.append("\",\"fromAddr\":");
+ } else responseBody.append("null,\"fromAddr\":");
+ const char *fa = reinterpret_cast(sqlite3_column_text(_sGetRecentMemberLog,3));
+ if ((fa)&&(fa[0])) {
+ responseBody.push_back('"');
+ responseBody.append(_jsonEscape(fa));
+ responseBody.append("\"}");
+ } else responseBody.append("null}");
}
- responseBody.append("\n}\n");
+ responseBody.append("]\n}\n");
responseContentType = "application/json";
return 200;
@@ -1394,8 +1430,11 @@ unsigned int SqliteNetworkController::_doCPGet(
sqlite3_reset(_sListNetworkMembers);
sqlite3_bind_text(_sListNetworkMembers,1,nwids,16,SQLITE_STATIC);
+ responseBody.append("{");
+ bool firstMember = true;
while (sqlite3_step(_sListNetworkMembers) == SQLITE_ROW) {
- responseBody.append((responseBody.length() > 0) ? ",\"" : "{\"");
+ responseBody.append(firstMember ? "\"" : ",\"");
+ firstMember = false;
responseBody.append((const char *)sqlite3_column_text(_sListNetworkMembers,0));
responseBody.append("\":");
responseBody.append((const char *)sqlite3_column_text(_sListNetworkMembers,1));
diff --git a/controller/SqliteNetworkController.hpp b/controller/SqliteNetworkController.hpp
index 8b39f7d9..adfe0991 100644
--- a/controller/SqliteNetworkController.hpp
+++ b/controller/SqliteNetworkController.hpp
@@ -97,6 +97,9 @@ private:
std::string _dbPath;
std::string _instanceId;
+
+ std::map< std::pair,uint64_t > _lastRequestTime;
+
sqlite3 *_db;
sqlite3_stmt *_sGetNetworkById;
@@ -141,6 +144,9 @@ private:
sqlite3_stmt *_sIncrementMemberRevisionCounter;
sqlite3_stmt *_sGetConfig;
sqlite3_stmt *_sSetConfig;
+ sqlite3_stmt *_sPutLog;
+ sqlite3_stmt *_sGetMemberLog;
+ sqlite3_stmt *_sGetRecentMemberLog;
Mutex _lock;
};
diff --git a/controller/schema.sql b/controller/schema.sql
index e85785b7..398d63ac 100644
--- a/controller/schema.sql
+++ b/controller/schema.sql
@@ -65,6 +65,18 @@ CREATE TABLE Member (
CREATE INDEX Member_networkId_activeBridge ON Member(networkId, activeBridge);
CREATE INDEX Member_networkId_memberRevision ON Member(networkId, memberRevision);
+CREATE TABLE Log (
+ networkId char(16) NOT NULL,
+ nodeId char(10) NOT NULL,
+ ts integer NOT NULL,
+ authorized integer NOT NULL,
+ version varchar(16),
+ fromAddr varchar(64)
+);
+
+CREATE INDEX Log_networkId_nodeId ON Log(networkId, nodeId);
+CREATE INDEX Log_ts ON Log(ts);
+
CREATE TABLE Relay (
networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,
address char(10) NOT NULL,
diff --git a/controller/schema.sql.c b/controller/schema.sql.c
index efeb280c..fa83f880 100644
--- a/controller/schema.sql.c
+++ b/controller/schema.sql.c
@@ -66,6 +66,18 @@
"CREATE INDEX Member_networkId_activeBridge ON Member(networkId, activeBridge);\n"\
"CREATE INDEX Member_networkId_memberRevision ON Member(networkId, memberRevision);\n"\
"\n"\
+"CREATE TABLE Log (\n"\
+" networkId char(16) NOT NULL,\n"\
+" nodeId char(10) NOT NULL,\n"\
+" ts integer NOT NULL,\n"\
+" authorized integer NOT NULL,\n"\
+" version varchar(16),\n"\
+" fromAddr varchar(64)\n"\
+");\n"\
+"\n"\
+"CREATE INDEX Log_networkId_nodeId ON Log(networkId, nodeId);\n"\
+"CREATE INDEX Log_ts ON Log(ts);\n"\
+"\n"\
"CREATE TABLE Relay (\n"\
" networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,\n"\
" address char(10) NOT NULL,\n"\
diff --git a/ext/bin/miniupnpc/Changelog.txt b/ext/bin/miniupnpc/Changelog.txt
new file mode 100644
index 00000000..bb2abb7e
--- /dev/null
+++ b/ext/bin/miniupnpc/Changelog.txt
@@ -0,0 +1,633 @@
+$Id: Changelog.txt,v 1.208 2015/07/15 12:18:59 nanard Exp $
+miniUPnP client Changelog.
+
+2015/07/15:
+ Check malloc/calloc
+
+2015/06/16:
+ update getDevicesFromMiniSSDPD() to process longer minissdpd
+ responses
+
+2015/05/22:
+ add searchalltypes param to upnpDiscoverDevices()
+ increments API_VERSION to 13
+
+2015/04/30:
+ upnpc: output version on the terminal
+
+2015/04/27:
+ _BSD_SOURCE is deprecated in favor of _DEFAULT_SOURCE
+ fix CMakeLists.txt COMPILE_DEFINITIONS
+ fix getDevicesFromMiniSSDPD() not setting scope_id
+ improve -r command of upnpc command line tool
+
+2014/11/17:
+ search all :
+ upnpDiscoverDevices() / upnpDiscoverAll() functions
+ listdevices executable
+ increment API_VERSION to 12
+ validate igd_desc_parse
+
+2014/11/13:
+ increment API_VERSION to 11
+
+2014/11/05:
+ simplified function GetUPNPUrls()
+
+2014/09/11:
+ use remoteHost arg of DeletePortMapping
+
+2014/09/06:
+ Fix python3 build
+
+2014/07/01:
+ Fix parsing of IGD2 root descriptions
+
+2014/06/10:
+ rename LIBSPEC to MINIUPNP_LIBSPEC
+
+2014/05/15:
+ Add support for IGD2 AddAnyPortMapping and DeletePortMappingRange
+
+2014/02/05:
+ handle EINPROGRESS after connect()
+
+2014/02/03:
+ minixml now handle XML comments
+
+VERSION 1.9 : released 2014/01/31
+
+2014/01/31:
+ added argument remoteHost to UPNP_GetSpecificPortMappingEntry()
+ increment API_VERSION to 10
+
+2013/12/09:
+ --help and -h arguments in upnpc.c
+
+2013/10/07:
+ fixed potential buffer overrun in miniwget.c
+ Modified UPNP_GetValidIGD() to check for ExternalIpAddress
+
+2013/08/01:
+ define MAXHOSTNAMELEN if not already done
+
+2013/06/06:
+ update upnpreplyparse to allow larger values (128 chars instead of 64)
+
+2013/05/14:
+ Update upnpreplyparse to take into account "empty" elements
+ validate upnpreplyparse.c code with "make check"
+
+2013/05/03:
+ Fix Solaris build thanks to Maciej Małecki
+
+2013/04/27:
+ Fix testminiwget.sh for BSD
+
+2013/03/23:
+ Fixed Makefile for *BSD
+
+2013/03/11:
+ Update Makefile to use JNAerator version 0.11
+
+2013/02/11:
+ Fix testminiwget.sh for use with dash
+ Use $(DESTDIR) in Makefile
+
+VERSION 1.8 : released 2013/02/06
+
+2012/10/16:
+ fix testminiwget with no IPv6 support
+
+2012/09/27:
+ Rename all include guards to not clash with C99
+ (7.1.3 Reserved identifiers).
+
+2012/08/30:
+ Added -e option to upnpc program (set description for port mappings)
+
+2012/08/29:
+ Python 3 support (thanks to Christopher Foo)
+
+2012/08/11:
+ Fix a memory link in UPNP_GetValidIGD()
+ Try to handle scope id in link local IPv6 URL under MS Windows
+
+2012/07/20:
+ Disable HAS_IP_MREQN on DragonFly BSD
+
+2012/06/28:
+ GetUPNPUrls() now inserts scope into link-local IPv6 addresses
+
+2012/06/23:
+ More error return checks in upnpc.c
+ #define MINIUPNPC_GET_SRC_ADDR enables receivedata() to get scope_id
+ parseURL() now parses IPv6 addresses scope
+ new parameter for miniwget() : IPv6 address scope
+ increment API_VERSION to 9
+
+2012/06/20:
+ fixed CMakeLists.txt
+
+2012/05/29
+ Improvements in testminiwget.sh
+
+VERSION 1.7 : released 2012/05/24
+
+2012/05/01:
+ Cleanup settings of CFLAGS in Makefile
+ Fix signed/unsigned integer comparaisons
+
+2012/04/20:
+ Allow to specify protocol with TCP or UDP for -A option
+
+2012/04/09:
+ Only try to fetch XML description once in UPNP_GetValidIGD()
+ Added -ansi flag to compilation, and fixed C++ comments to ANSI C comments.
+
+2012/04/05:
+ minor improvements to minihttptestserver.c
+
+2012/03/15:
+ upnperrors.c returns valid error string for unrecognized error codes
+
+2012/03/08:
+ make minihttptestserver listen on loopback interface instead of 0.0.0.0
+
+2012/01/25:
+ Maven installation thanks to Alexey Kuznetsov
+
+2012/01/21:
+ Replace WIN32 macro by _WIN32
+
+2012/01/19:
+ Fixes in java wrappers thanks to Alexey Kuznetsov :
+ https://github.com/axet/miniupnp/tree/fix-javatest/miniupnpc
+ Make and install .deb packages (python) thanks to Alexey Kuznetsov :
+ https://github.com/axet/miniupnp/tree/feature-debbuild/miniupnpc
+
+2012/01/07:
+ The multicast interface can now be specified by name with IPv4.
+
+2012/01/02:
+ Install man page
+
+2011/11/25:
+ added header to Port Mappings list in upnpc.c
+
+2011/10/09:
+ Makefile : make clean now removes jnaerator generated files.
+ MINIUPNPC_VERSION in miniupnpc.h (updated by make)
+
+2011/09/12:
+ added rootdescURL to UPNPUrls structure.
+
+VERSION 1.6 : released 2011/07/25
+
+2011/07/25:
+ Update doc for version 1.6 release
+
+2011/06/18:
+ Fix for windows in miniwget.c
+
+2011/06/04:
+ display remote host in port mapping listing
+
+2011/06/03:
+ Fix in make install : there were missing headers
+
+2011/05/26:
+ Fix the socket leak in miniwget thanks to Richard Marsh.
+ Permit to add leaseduration in -a command. Display lease duration.
+
+2011/05/15:
+ Try both LinkLocal and SiteLocal multicast address for SSDP in IPv6
+
+2011/05/09:
+ add a test in testminiwget.sh.
+ more error checking in miniwget.c
+
+2011/05/06:
+ Adding some tool to test and validate miniwget.c
+ simplified and debugged miniwget.c
+
+2011/04/11:
+ moving ReceiveData() to a receivedata.c file.
+ parsing presentation url
+ adding IGD v2 WANIPv6FirewallControl commands
+
+2011/04/10:
+ update of miniupnpcmodule.c
+ comments in miniwget.c, update in testminiwget
+ Adding errors codes from IGD v2
+ new functions in upnpc.c for IGD v2
+
+2011/04/09:
+ Support for litteral ip v6 address in miniwget
+
+2011/04/08:
+ Adding support for urn:schemas-upnp-org:service:WANIPv6FirewallControl:1
+ Updating APIVERSION
+ Supporting IPV6 in upnpDiscover()
+ Adding a -6 option to upnpc command line tool
+
+2011/03/18:
+ miniwget/parseURL() : return an error when url param is null.
+ fixing GetListOfPortMappings()
+
+2011/03/14:
+ upnpDiscover() now reporting an error code.
+ improvements in comments.
+
+2011/03/11:
+ adding miniupnpcstrings.h.cmake and CMakeLists.txt files.
+
+2011/02/15:
+ Implementation of GetListOfPortMappings()
+
+2011/02/07:
+ updates to minixml to support character data starting with spaces
+ minixml now support CDATA
+ upnpreplyparse treats specificaly
+ change in simpleUPnPcommand to return the buffer (simplification)
+
+2011/02/06:
+ Added leaseDuration argument to AddPortMapping()
+ Starting to implement GetListOfPortMappings()
+
+2011/01/11:
+ updating wingenminiupnpcstrings.c
+
+2011/01/04:
+ improving updateminiupnpcstrings.sh
+
+VERSION 1.5 : released 2011/01/01
+
+2010/12/21:
+ use NO_GETADDRINFO macro to disable the use of getaddrinfo/freeaddrinfo
+
+2010/12/11:
+ Improvements on getHTTPResponse() code.
+
+2010/12/09:
+ new code for miniwget that handle Chunked transfer encoding
+ using getHTTPResponse() in SOAP call code
+ Adding MANIFEST.in for 'python setup.py bdist_rpm'
+
+2010/11/25:
+ changes to minissdpc.c to compile under Win32.
+ see http://miniupnp.tuxfamily.org/forum/viewtopic.php?t=729
+
+2010/09/17:
+ Various improvement to Makefile from Michał Górny
+
+2010/08/05:
+ Adding the script "external-ip.sh" from Reuben Hawkins
+
+2010/06/09:
+ update to python module to match modification made on 2010/04/05
+ update to Java test code to match modification made on 2010/04/05
+ all UPNP_* function now return an error if the SOAP request failed
+ at HTTP level.
+
+2010/04/17:
+ Using GetBestRoute() under win32 in order to find the
+ right interface to use.
+
+2010/04/12:
+ Retrying with HTTP/1.1 if HTTP/1.0 failed. see
+ http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=1703
+
+2010/04/07:
+ avoid returning duplicates in upnpDiscover()
+
+2010/04/05:
+ Create a connecthostport.h/.c with connecthostport() function
+ and use it in miniwget and miniupnpc.
+ Use getnameinfo() instead of inet_ntop or inet_ntoa
+ Work to make miniupnpc IPV6 compatible...
+ Add java test code.
+ Big changes in order to support device having both WANIPConnection
+ and WANPPPConnection.
+
+2010/04/04:
+ Use getaddrinfo() instead of gethostbyname() in miniwget.
+
+2010/01/06:
+ #define _DARWIN_C_SOURCE for Mac OS X
+
+2009/12/19:
+ Improve MinGW32 build
+
+2009/12/11:
+ adding a MSVC9 project to build the static library and executable
+
+2009/12/10:
+ Fixing some compilation stuff for Windows/MinGW
+
+2009/12/07:
+ adaptations in Makefile and updateminiupnpcstring.sh for AmigaOS
+ some fixes for Windows when using virtual ethernet adapters (it is the
+ case with VMWare installed).
+
+2009/12/04:
+ some fixes for AmigaOS compilation
+ Changed HTTP version to HTTP/1.0 for Soap too (to prevent chunked
+ transfer encoding)
+
+2009/12/03:
+ updating printIDG and testigddescparse.c for debug.
+ modifications to compile under AmigaOS
+ adding a testminiwget program
+ Changed miniwget to advertise itself as HTTP/1.0 to prevent chunked
+ transfer encoding
+
+2009/11/26:
+ fixing updateminiupnpcstrings.sh to take into account
+ which command that does not return an error code.
+
+VERSION 1.4 : released 2009/10/30
+
+2009/10/16:
+ using Py_BEGIN_ALLOW_THREADS and Py_END_ALLOW_THREADS in python module.
+
+2009/10/10:
+ Some fixes for compilation under Solaris
+ compilation fixes : http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=1464
+
+2009/09/21:
+ fixing the code to ignore EINTR during connect() calls.
+
+2009/08/07:
+ Set socket timeout for connect()
+ Some cleanup in miniwget.c
+
+2009/08/04:
+ remove multiple redirections with -d in upnpc.c
+ Print textual error code in upnpc.c
+ Ignore EINTR during the connect() and poll() calls.
+
+2009/07/29:
+ fix in updateminiupnpcstrings.sh if OS name contains "/"
+ Sending a correct value for MX: field in SSDP request
+
+2009/07/20:
+ Change the Makefile to compile under Mac OS X
+ Fixed a stackoverflow in getDevicesFromMiniSSDPD()
+
+2009/07/09:
+ Compile under Haiku
+ generate miniupnpcstrings.h.in from miniupnpcstrings.h
+
+2009/06/04:
+ patching to compile under CygWin and cross compile for minGW
+
+VERSION 1.3 :
+
+2009/04/17:
+ updating python module
+ Use strtoull() when using C99
+
+2009/02/28:
+ Fixed miniwget.c for compiling under sun
+
+2008/12/18:
+ cleanup in Makefile (thanks to Paul de Weerd)
+ minissdpc.c : win32 compatibility
+ miniupnpc.c : changed xmlns prefix from 'm' to 'u'
+ Removed NDEBUG (using DEBUG)
+
+2008/10/14:
+ Added the ExternalHost argument to DeletePortMapping()
+
+2008/10/11:
+ Added the ExternalHost argument to AddPortMapping()
+ Put a correct User-Agent: header in HTTP requests.
+
+VERSION 1.2 :
+
+2008/10/07:
+ Update docs
+
+2008/09/25:
+ Integrated sameport patch from Dario Meloni : Added a "sameport"
+ argument to upnpDiscover().
+
+2008/07/18:
+ small modif to make Clang happy :)
+
+2008/07/17:
+ #define SOAPPREFIX "s" in miniupnpc.c in order to remove SOAP-ENV...
+
+2008/07/14:
+ include declspec.h in installation (to /usr/include/miniupnpc)
+
+VERSION 1.1 :
+
+2008/07/04:
+ standard options for install/ln instead of gnu-specific stuff.
+
+2008/07/03:
+ now builds a .dll and .lib with win32. (mingw32)
+
+2008/04/28:
+ make install now install the binary of the upnpc tool
+
+2008/04/27:
+ added testupnpigd.py
+ added error strings for miniupnpc "internal" errors
+ improved python module error/exception reporting.
+
+2008/04/23:
+ Completely rewrite igd_desc_parse.c in order to be compatible with
+ Linksys WAG200G
+ Added testigddescparse
+ updated python module
+
+VERSION 1.0 :
+
+2008/02/21:
+ put some #ifdef DEBUG around DisplayNameValueList()
+
+2008/02/18:
+ Improved error reporting in upnpcommands.c
+ UPNP_GetStatusInfo() returns LastConnectionError
+
+2008/02/16:
+ better error handling in minisoap.c
+ improving display of "valid IGD found" in upnpc.c
+
+2008/02/03:
+ Fixing UPNP_GetValidIGD()
+ improved make install :)
+
+2007/12/22:
+ Adding upnperrors.c/h to provide a strupnperror() function
+ used to translate UPnP error codes to string.
+
+2007/12/19:
+ Fixing getDevicesFromMiniSSDPD()
+ improved error reporting of UPnP functions
+
+2007/12/18:
+ It is now possible to specify a different location for MiniSSDPd socket.
+ working with MiniSSDPd is now more efficient.
+ python module improved.
+
+2007/12/16:
+ improving error reporting
+
+2007/12/13:
+ Try to improve compatibility by using HTTP/1.0 instead of 1.1 and
+ XML a bit different for SOAP.
+
+2007/11/25:
+ fixed select() call for linux
+
+2007/11/15:
+ Added -fPIC to CFLAG for better shared library code.
+
+2007/11/02:
+ Fixed a potential socket leak in miniwget2()
+
+2007/10/16:
+ added a parameter to upnpDiscover() in order to allow the use of another
+ interface than the default multicast interface.
+
+2007/10/12:
+ Fixed the creation of symbolic link in Makefile
+
+2007/10/08:
+ Added man page
+
+2007/10/02:
+ fixed memory bug in GetUPNPUrls()
+
+2007/10/01:
+ fixes in the Makefile
+ Added UPNP_GetIGDFromUrl() and adapted the sample program accordingly.
+ Added SONAME in the shared library to please debian :)
+ fixed MS Windows compilation (minissdpd is not available under MS Windows).
+
+2007/09/25:
+ small change to Makefile to be able to install in a different location
+ (default is /usr)
+
+2007/09/24:
+ now compiling both shared and static library
+
+2007/09/19:
+ Cosmetic changes on upnpc.c
+
+2007/09/02:
+ adapting to new miniSSDPd (release version ?)
+
+2007/08/31:
+ Usage of miniSSDPd to skip discovery process.
+
+2007/08/27:
+ fixed python module to allow compilation with Python older than Python 2.4
+
+2007/06/12:
+ Added a python module.
+
+2007/05/19:
+ Fixed compilation under MinGW
+
+2007/05/15:
+ fixed a memory leak in AddPortMapping()
+ Added testupnpreplyparse executable to check the parsing of
+ upnp soap messages
+ minixml now ignore namespace prefixes.
+
+2007/04/26:
+ upnpc now displays external ip address with -s or -l
+
+2007/04/11:
+ changed MINIUPNPC_URL_MAXSIZE to 128 to accomodate the "BT Voyager 210"
+
+2007/03/19:
+ cleanup in miniwget.c
+
+2007/03/01:
+ Small typo fix...
+
+2007/01/30:
+ Now parsing the HTTP header from SOAP responses in order to
+ get content-length value.
+
+2007/01/29:
+ Fixed the Soap Query to speedup the HTTP request.
+ added some Win32 DLL stuff...
+
+2007/01/27:
+ Fixed some WIN32 compatibility issues
+
+2006/12/14:
+ Added UPNPIGD_IsConnected() function in miniupnp.c/.h
+ Added UPNP_GetValidIGD() in miniupnp.c/.h
+ cleaned upnpc.c main(). now using UPNP_GetValidIGD()
+
+2006/12/07:
+ Version 1.0-RC1 released
+
+2006/12/03:
+ Minor changes to compile under SunOS/Solaris
+
+2006/11/30:
+ made a minixml parser validator program
+ updated minixml to handle attributes correctly
+
+2006/11/22:
+ Added a -r option to the upnpc sample thanks to Alexander Hubmann.
+
+2006/11/19:
+ Cleanup code to make it more ANSI C compliant
+
+2006/11/10:
+ detect and display local lan address.
+
+2006/11/04:
+ Packets and Bytes Sent/Received are now unsigned int.
+
+2006/11/01:
+ Bug fix thanks to Giuseppe D'Angelo
+
+2006/10/31:
+ C++ compatibility for .h files.
+ Added a way to get ip Address on the LAN used to reach the IGD.
+
+2006/10/25:
+ Added M-SEARCH to the services in the discovery process.
+
+2006/10/22:
+ updated the Makefile to use makedepend, added a "make install"
+ update Makefile
+
+2006/10/20:
+ fixing the description url parsing thanks to patch sent by
+ Wayne Dawe.
+ Fixed/translated some comments.
+ Implemented a better discover process, first looking
+ for IGD then for root devices (as some devices only reply to
+ M-SEARCH for root devices).
+
+2006/09/02:
+ added freeUPNPDevlist() function.
+
+2006/08/04:
+ More command line arguments checking
+
+2006/08/01:
+ Added the .bat file to compile under Win32 with minGW32
+
+2006/07/31:
+ Fixed the rootdesc parser (igd_desc_parse.c)
+
+2006/07/20:
+ parseMSEARCHReply() is now returning the ST: line as well
+ starting changes to detect several UPnP devices on the network
+
+2006/07/19:
+ using GetCommonLinkProperties to get down/upload bitrate
+
diff --git a/ext/bin/miniupnpc/LICENSE b/ext/bin/miniupnpc/LICENSE
new file mode 100644
index 00000000..cb5a0604
--- /dev/null
+++ b/ext/bin/miniupnpc/LICENSE
@@ -0,0 +1,27 @@
+MiniUPnPc
+Copyright (c) 2005-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.
+
diff --git a/ext/bin/miniupnpc/README.md b/ext/bin/miniupnpc/README.md
new file mode 100644
index 00000000..c3d538ba
--- /dev/null
+++ b/ext/bin/miniupnpc/README.md
@@ -0,0 +1,4 @@
+libminiupnpc binaries
+======
+
+This is a binary build of [libminiupnpc](http://miniupnp.free.fr) for certain architectures to faciliate easy building. Where possible the build flags were set for improved security by enabling options like stack protector (a.k.a. stack canary), ASLR support, etc.
diff --git a/ext/bin/miniupnpc/VERSION b/ext/bin/miniupnpc/VERSION
new file mode 100644
index 00000000..2e0e38c6
--- /dev/null
+++ b/ext/bin/miniupnpc/VERSION
@@ -0,0 +1 @@
+1.9
diff --git a/ext/bin/miniupnpc/include/miniupnpc/codelength.h b/ext/bin/miniupnpc/include/miniupnpc/codelength.h
new file mode 100644
index 00000000..f5f8e30f
--- /dev/null
+++ b/ext/bin/miniupnpc/include/miniupnpc/codelength.h
@@ -0,0 +1,54 @@
+/* $Id: codelength.h,v 1.5 2015/07/09 12:40:18 nanard Exp $ */
+/* Project : miniupnp
+ * Author : Thomas BERNARD
+ * copyright (c) 2005-2015 Thomas Bernard
+ * This software is subjet to the conditions detailed in the
+ * provided LICENCE file. */
+#ifndef CODELENGTH_H_INCLUDED
+#define CODELENGTH_H_INCLUDED
+
+/* Encode length by using 7bit per Byte :
+ * Most significant bit of each byte specifies that the
+ * following byte is part of the code */
+
+/* n : unsigned
+ * p : unsigned char *
+ */
+#define DECODELENGTH(n, p) n = 0; \
+ do { n = (n << 7) | (*p & 0x7f); } \
+ while((*(p++)&0x80) && (n<(1<<25)));
+
+/* n : unsigned
+ * READ : function/macro to read one byte (unsigned char)
+ */
+#define DECODELENGTH_READ(n, READ) \
+ n = 0; \
+ do { \
+ unsigned char c; \
+ READ(c); \
+ n = (n << 7) | (c & 0x07f); \
+ if(!(c&0x80)) break; \
+ } while(n<(1<<25));
+
+/* n : unsigned
+ * p : unsigned char *
+ * p_limit : unsigned char *
+ */
+#define DECODELENGTH_CHECKLIMIT(n, p, p_limit) \
+ n = 0; \
+ do { \
+ if((p) >= (p_limit)) break; \
+ n = (n << 7) | (*(p) & 0x7f); \
+ } while((*((p)++)&0x80) && (n<(1<<25)));
+
+
+/* n : unsigned
+ * p : unsigned char *
+ */
+#define CODELENGTH(n, p) if(n>=268435456) *(p++) = (n >> 28) | 0x80; \
+ if(n>=2097152) *(p++) = (n >> 21) | 0x80; \
+ if(n>=16384) *(p++) = (n >> 14) | 0x80; \
+ if(n>=128) *(p++) = (n >> 7) | 0x80; \
+ *(p++) = n & 0x7f;
+
+#endif /* CODELENGTH_H_INCLUDED */
diff --git a/ext/bin/miniupnpc/include/miniupnpc/connecthostport.h b/ext/bin/miniupnpc/include/miniupnpc/connecthostport.h
new file mode 100644
index 00000000..56941d6f
--- /dev/null
+++ b/ext/bin/miniupnpc/include/miniupnpc/connecthostport.h
@@ -0,0 +1,18 @@
+/* $Id: connecthostport.h,v 1.3 2012/09/27 15:42:10 nanard Exp $ */
+/* Project: miniupnp
+ * http://miniupnp.free.fr/
+ * Author: Thomas Bernard
+ * Copyright (c) 2010-2012 Thomas Bernard
+ * This software is subjects to the conditions detailed
+ * in the LICENCE file provided within this distribution */
+#ifndef CONNECTHOSTPORT_H_INCLUDED
+#define CONNECTHOSTPORT_H_INCLUDED
+
+/* connecthostport()
+ * return a socket connected (TCP) to the host and port
+ * or -1 in case of error */
+int connecthostport(const char * host, unsigned short port,
+ unsigned int scope_id);
+
+#endif
+
diff --git a/ext/bin/miniupnpc/include/miniupnpc/igd_desc_parse.h b/ext/bin/miniupnpc/include/miniupnpc/igd_desc_parse.h
new file mode 100644
index 00000000..0de546b6
--- /dev/null
+++ b/ext/bin/miniupnpc/include/miniupnpc/igd_desc_parse.h
@@ -0,0 +1,49 @@
+/* $Id: igd_desc_parse.h,v 1.12 2014/11/17 17:19:13 nanard Exp $ */
+/* Project : miniupnp
+ * http://miniupnp.free.fr/
+ * Author : Thomas Bernard
+ * Copyright (c) 2005-2014 Thomas Bernard
+ * This software is subject to the conditions detailed in the
+ * LICENCE file provided in this distribution.
+ * */
+#ifndef IGD_DESC_PARSE_H_INCLUDED
+#define IGD_DESC_PARSE_H_INCLUDED
+
+/* Structure to store the result of the parsing of UPnP
+ * descriptions of Internet Gateway Devices */
+#define MINIUPNPC_URL_MAXSIZE (128)
+struct IGDdatas_service {
+ char controlurl[MINIUPNPC_URL_MAXSIZE];
+ char eventsuburl[MINIUPNPC_URL_MAXSIZE];
+ char scpdurl[MINIUPNPC_URL_MAXSIZE];
+ char servicetype[MINIUPNPC_URL_MAXSIZE];
+ /*char devicetype[MINIUPNPC_URL_MAXSIZE];*/
+};
+
+struct IGDdatas {
+ char cureltname[MINIUPNPC_URL_MAXSIZE];
+ char urlbase[MINIUPNPC_URL_MAXSIZE];
+ char presentationurl[MINIUPNPC_URL_MAXSIZE];
+ int level;
+ /*int state;*/
+ /* "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */
+ struct IGDdatas_service CIF;
+ /* "urn:schemas-upnp-org:service:WANIPConnection:1"
+ * "urn:schemas-upnp-org:service:WANPPPConnection:1" */
+ struct IGDdatas_service first;
+ /* if both WANIPConnection and WANPPPConnection are present */
+ struct IGDdatas_service second;
+ /* "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1" */
+ struct IGDdatas_service IPv6FC;
+ /* tmp */
+ struct IGDdatas_service tmp;
+};
+
+void IGDstartelt(void *, const char *, int);
+void IGDendelt(void *, const char *, int);
+void IGDdata(void *, const char *, int);
+#ifdef DEBUG
+void printIGD(struct IGDdatas *);
+#endif /* DEBUG */
+
+#endif /* IGD_DESC_PARSE_H_INCLUDED */
diff --git a/ext/bin/miniupnpc/include/miniupnpc/minisoap.h b/ext/bin/miniupnpc/include/miniupnpc/minisoap.h
new file mode 100644
index 00000000..14c859d1
--- /dev/null
+++ b/ext/bin/miniupnpc/include/miniupnpc/minisoap.h
@@ -0,0 +1,15 @@
+/* $Id: minisoap.h,v 1.5 2012/09/27 15:42:10 nanard Exp $ */
+/* Project : miniupnp
+ * Author : Thomas Bernard
+ * Copyright (c) 2005 Thomas Bernard
+ * This software is subject to the conditions detailed in the
+ * LICENCE file provided in this distribution. */
+#ifndef MINISOAP_H_INCLUDED
+#define MINISOAP_H_INCLUDED
+
+/*int httpWrite(int, const char *, int, const char *);*/
+int soapPostSubmit(int, const char *, const char *, unsigned short,
+ const char *, const char *, const char *);
+
+#endif
+
diff --git a/ext/bin/miniupnpc/include/miniupnpc/minissdpc.h b/ext/bin/miniupnpc/include/miniupnpc/minissdpc.h
new file mode 100644
index 00000000..915b0026
--- /dev/null
+++ b/ext/bin/miniupnpc/include/miniupnpc/minissdpc.h
@@ -0,0 +1,15 @@
+/* $Id: minissdpc.h,v 1.2 2012/09/27 15:42:10 nanard Exp $ */
+/* Project: miniupnp
+ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
+ * Author: Thomas Bernard
+ * Copyright (c) 2005-2007 Thomas Bernard
+ * This software is subjects to the conditions detailed
+ * in the LICENCE file provided within this distribution */
+#ifndef MINISSDPC_H_INCLUDED
+#define MINISSDPC_H_INCLUDED
+
+struct UPNPDev *
+getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath);
+
+#endif
+
diff --git a/ext/bin/miniupnpc/include/miniupnpc/miniupnpc.h b/ext/bin/miniupnpc/include/miniupnpc/miniupnpc.h
new file mode 100644
index 00000000..0eeabc23
--- /dev/null
+++ b/ext/bin/miniupnpc/include/miniupnpc/miniupnpc.h
@@ -0,0 +1,154 @@
+/* $Id: miniupnpc.h,v 1.42 2015/07/21 13:16:55 nanard Exp $ */
+/* Project: miniupnp
+ * http://miniupnp.free.fr/
+ * Author: Thomas Bernard
+ * Copyright (c) 2005-2015 Thomas Bernard
+ * This software is subjects to the conditions detailed
+ * in the LICENCE file provided within this distribution */
+#ifndef MINIUPNPC_H_INCLUDED
+#define MINIUPNPC_H_INCLUDED
+
+#include "miniupnpc_declspec.h"
+#include "igd_desc_parse.h"
+
+/* error codes : */
+#define UPNPDISCOVER_SUCCESS (0)
+#define UPNPDISCOVER_UNKNOWN_ERROR (-1)
+#define UPNPDISCOVER_SOCKET_ERROR (-101)
+#define UPNPDISCOVER_MEMORY_ERROR (-102)
+
+/* versions : */
+#define MINIUPNPC_VERSION "1.9.20150721"
+#define MINIUPNPC_API_VERSION 13
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Structures definitions : */
+struct UPNParg { const char * elt; const char * val; };
+
+char *
+simpleUPnPcommand(int, const char *, const char *,
+ const char *, struct UPNParg *,
+ int *);
+
+struct UPNPDev {
+ struct UPNPDev * pNext;
+ char * descURL;
+ char * st;
+ unsigned int scope_id;
+ char buffer[2];
+};
+
+/* upnpDiscover()
+ * discover UPnP devices on the network.
+ * The discovered devices are returned as a chained list.
+ * It is up to the caller to free the list with freeUPNPDevlist().
+ * delay (in millisecond) is the maximum time for waiting any device
+ * response.
+ * If available, device list will be obtained from MiniSSDPd.
+ * Default path for minissdpd socket will be used if minissdpdsock argument
+ * is NULL.
+ * If multicastif is not NULL, it will be used instead of the default
+ * multicast interface for sending SSDP discover packets.
+ * If sameport is not null, SSDP packets will be sent from the source port
+ * 1900 (same as destination port) otherwise system assign a source port.
+ * "searchalltypes" parameter is useful when searching several types,
+ * if 0, the discovery will stop with the first type returning results. */
+MINIUPNP_LIBSPEC struct UPNPDev *
+upnpDiscover(int delay, const char * multicastif,
+ const char * minissdpdsock, int sameport,
+ int ipv6,
+ int * error);
+
+MINIUPNP_LIBSPEC struct UPNPDev *
+upnpDiscoverAll(int delay, const char * multicastif,
+ const char * minissdpdsock, int sameport,
+ int ipv6,
+ int * error);
+
+MINIUPNP_LIBSPEC struct UPNPDev *
+upnpDiscoverDevice(const char * device, int delay, const char * multicastif,
+ const char * minissdpdsock, int sameport,
+ int ipv6,
+ int * error);
+
+MINIUPNP_LIBSPEC struct UPNPDev *
+upnpDiscoverDevices(const char * const deviceTypes[],
+ int delay, const char * multicastif,
+ const char * minissdpdsock, int sameport,
+ int ipv6,
+ int * error,
+ int searchalltypes);
+
+/* freeUPNPDevlist()
+ * free list returned by upnpDiscover() */
+MINIUPNP_LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist);
+
+/* parserootdesc() :
+ * parse root XML description of a UPnP device and fill the IGDdatas
+ * structure. */
+MINIUPNP_LIBSPEC void parserootdesc(const char *, int, struct IGDdatas *);
+
+/* structure used to get fast access to urls
+ * controlURL: controlURL of the WANIPConnection
+ * ipcondescURL: url of the description of the WANIPConnection
+ * controlURL_CIF: controlURL of the WANCommonInterfaceConfig
+ * controlURL_6FC: controlURL of the WANIPv6FirewallControl
+ */
+struct UPNPUrls {
+ char * controlURL;
+ char * ipcondescURL;
+ char * controlURL_CIF;
+ char * controlURL_6FC;
+ char * rootdescURL;
+};
+
+/* UPNP_GetValidIGD() :
+ * return values :
+ * 0 = NO IGD found
+ * 1 = A valid connected IGD has been found
+ * 2 = A valid IGD has been found but it reported as
+ * not connected
+ * 3 = an UPnP device has been found but was not recognized as an IGD
+ *
+ * In any non zero return case, the urls and data structures
+ * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to
+ * free allocated memory.
+ */
+MINIUPNP_LIBSPEC int
+UPNP_GetValidIGD(struct UPNPDev * devlist,
+ struct UPNPUrls * urls,
+ struct IGDdatas * data,
+ char * lanaddr, int lanaddrlen);
+
+/* UPNP_GetIGDFromUrl()
+ * Used when skipping the discovery process.
+ * When succeding, urls, data, and lanaddr arguments are set.
+ * return value :
+ * 0 - Not ok
+ * 1 - OK */
+MINIUPNP_LIBSPEC int
+UPNP_GetIGDFromUrl(const char * rootdescurl,
+ struct UPNPUrls * urls,
+ struct IGDdatas * data,
+ char * lanaddr, int lanaddrlen);
+
+MINIUPNP_LIBSPEC void
+GetUPNPUrls(struct UPNPUrls *, struct IGDdatas *,
+ const char *, unsigned int);
+
+MINIUPNP_LIBSPEC void
+FreeUPNPUrls(struct UPNPUrls *);
+
+/* return 0 or 1 */
+MINIUPNP_LIBSPEC int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/ext/bin/miniupnpc/include/miniupnpc/miniupnpc_declspec.h b/ext/bin/miniupnpc/include/miniupnpc/miniupnpc_declspec.h
new file mode 100644
index 00000000..40adb922
--- /dev/null
+++ b/ext/bin/miniupnpc/include/miniupnpc/miniupnpc_declspec.h
@@ -0,0 +1,21 @@
+#ifndef MINIUPNPC_DECLSPEC_H_INCLUDED
+#define MINIUPNPC_DECLSPEC_H_INCLUDED
+
+#if defined(_WIN32) && !defined(MINIUPNP_STATICLIB)
+ /* for windows dll */
+ #ifdef MINIUPNP_EXPORTS
+ #define MINIUPNP_LIBSPEC __declspec(dllexport)
+ #else
+ #define MINIUPNP_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 MINIUPNP_LIBSPEC __attribute__ ((visibility ("default")))
+ #else
+ #define MINIUPNP_LIBSPEC
+ #endif
+#endif
+
+#endif /* MINIUPNPC_DECLSPEC_H_INCLUDED */
+
diff --git a/ext/bin/miniupnpc/include/miniupnpc/miniupnpcstrings.h b/ext/bin/miniupnpc/include/miniupnpc/miniupnpcstrings.h
new file mode 100644
index 00000000..80a1d757
--- /dev/null
+++ b/ext/bin/miniupnpc/include/miniupnpc/miniupnpcstrings.h
@@ -0,0 +1,23 @@
+/* $Id: miniupnpcstrings.h.in,v 1.6 2014/11/04 22:31:55 nanard Exp $ */
+/* Project: miniupnp
+ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
+ * Author: Thomas Bernard
+ * Copyright (c) 2005-2014 Thomas Bernard
+ * This software is subjects to the conditions detailed
+ * in the LICENCE file provided within this distribution */
+#ifndef MINIUPNPCSTRINGS_H_INCLUDED
+#define MINIUPNPCSTRINGS_H_INCLUDED
+
+#define OS_STRING "Darwin/14.4.0"
+#define MINIUPNPC_VERSION_STRING "1.9"
+
+#if 0
+/* according to "UPnP Device Architecture 1.0" */
+#define UPNP_VERSION_STRING "UPnP/1.0"
+#else
+/* according to "UPnP Device Architecture 1.1" */
+#define UPNP_VERSION_STRING "UPnP/1.1"
+#endif
+
+#endif
+
diff --git a/ext/bin/miniupnpc/include/miniupnpc/miniupnpctypes.h b/ext/bin/miniupnpc/include/miniupnpc/miniupnpctypes.h
new file mode 100644
index 00000000..591c32fb
--- /dev/null
+++ b/ext/bin/miniupnpc/include/miniupnpc/miniupnpctypes.h
@@ -0,0 +1,19 @@
+/* $Id: miniupnpctypes.h,v 1.2 2012/09/27 15:42:10 nanard Exp $ */
+/* Miniupnp project : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org
+ * Author : Thomas Bernard
+ * Copyright (c) 2011 Thomas Bernard
+ * This software is subject to the conditions detailed in the
+ * LICENCE file provided within this distribution */
+#ifndef MINIUPNPCTYPES_H_INCLUDED
+#define MINIUPNPCTYPES_H_INCLUDED
+
+#if (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
+#define UNSIGNED_INTEGER unsigned long long
+#define STRTOUI strtoull
+#else
+#define UNSIGNED_INTEGER unsigned int
+#define STRTOUI strtoul
+#endif
+
+#endif
+
diff --git a/ext/bin/miniupnpc/include/miniupnpc/miniwget.h b/ext/bin/miniupnpc/include/miniupnpc/miniwget.h
new file mode 100644
index 00000000..d6db71a8
--- /dev/null
+++ b/ext/bin/miniupnpc/include/miniupnpc/miniwget.h
@@ -0,0 +1,30 @@
+/* $Id: miniwget.h,v 1.10 2015/07/21 13:16:55 nanard Exp $ */
+/* Project : miniupnp
+ * Author : Thomas Bernard
+ * Copyright (c) 2005-2015 Thomas Bernard
+ * This software is subject to the conditions detailed in the
+ * LICENCE file provided in this distribution.
+ * */
+#ifndef MINIWGET_H_INCLUDED
+#define MINIWGET_H_INCLUDED
+
+#include "miniupnpc_declspec.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+MINIUPNP_LIBSPEC void * getHTTPResponse(int s, int * size);
+
+MINIUPNP_LIBSPEC void * miniwget(const char *, int *, unsigned int);
+
+MINIUPNP_LIBSPEC void * miniwget_getaddr(const char *, int *, char *, int, unsigned int);
+
+int parseURL(const char *, char *, unsigned short *, char * *, unsigned int *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/ext/bin/miniupnpc/include/miniupnpc/minixml.h b/ext/bin/miniupnpc/include/miniupnpc/minixml.h
new file mode 100644
index 00000000..9f43aa48
--- /dev/null
+++ b/ext/bin/miniupnpc/include/miniupnpc/minixml.h
@@ -0,0 +1,37 @@
+/* $Id: minixml.h,v 1.7 2012/09/27 15:42:10 nanard Exp $ */
+/* minimal xml parser
+ *
+ * Project : miniupnp
+ * Website : http://miniupnp.free.fr/
+ * Author : Thomas Bernard
+ * Copyright (c) 2005 Thomas Bernard
+ * This software is subject to the conditions detailed in the
+ * LICENCE file provided in this distribution.
+ * */
+#ifndef MINIXML_H_INCLUDED
+#define MINIXML_H_INCLUDED
+#define IS_WHITE_SPACE(c) ((c==' ') || (c=='\t') || (c=='\r') || (c=='\n'))
+
+/* if a callback function pointer is set to NULL,
+ * the function is not called */
+struct xmlparser {
+ const char *xmlstart;
+ const char *xmlend;
+ const char *xml; /* pointer to current character */
+ int xmlsize;
+ void * data;
+ void (*starteltfunc) (void *, const char *, int);
+ void (*endeltfunc) (void *, const char *, int);
+ void (*datafunc) (void *, const char *, int);
+ void (*attfunc) (void *, const char *, int, const char *, int);
+};
+
+/* parsexml()
+ * the xmlparser structure must be initialized before the call
+ * the following structure members have to be initialized :
+ * xmlstart, xmlsize, data, *func
+ * xml is for internal usage, xmlend is computed automatically */
+void parsexml(struct xmlparser *);
+
+#endif
+
diff --git a/ext/bin/miniupnpc/include/miniupnpc/portlistingparse.h b/ext/bin/miniupnpc/include/miniupnpc/portlistingparse.h
new file mode 100644
index 00000000..661ad1fa
--- /dev/null
+++ b/ext/bin/miniupnpc/include/miniupnpc/portlistingparse.h
@@ -0,0 +1,65 @@
+/* $Id: portlistingparse.h,v 1.11 2015/07/21 13:16:55 nanard Exp $ */
+/* MiniUPnP project
+ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
+ * (c) 2011-2015 Thomas Bernard
+ * This software is subject to the conditions detailed
+ * in the LICENCE file provided within the distribution */
+#ifndef PORTLISTINGPARSE_H_INCLUDED
+#define PORTLISTINGPARSE_H_INCLUDED
+
+#include "miniupnpc_declspec.h"
+/* for the definition of UNSIGNED_INTEGER */
+#include "miniupnpctypes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* sample of PortMappingEntry :
+
+ 202.233.2.1
+ 2345
+ TCP
+ 2345
+ 192.168.1.137
+ 1
+ dooom
+ 345
+
+ */
+typedef enum { PortMappingEltNone,
+ PortMappingEntry, NewRemoteHost,
+ NewExternalPort, NewProtocol,
+ NewInternalPort, NewInternalClient,
+ NewEnabled, NewDescription,
+ NewLeaseTime } portMappingElt;
+
+struct PortMapping {
+ struct PortMapping * l_next; /* list next element */
+ UNSIGNED_INTEGER leaseTime;
+ unsigned short externalPort;
+ unsigned short internalPort;
+ char remoteHost[64];
+ char internalClient[64];
+ char description[64];
+ char protocol[4];
+ unsigned char enabled;
+};
+
+struct PortMappingParserData {
+ struct PortMapping * l_head; /* list head */
+ portMappingElt curelt;
+};
+
+MINIUPNP_LIBSPEC void
+ParsePortListing(const char * buffer, int bufsize,
+ struct PortMappingParserData * pdata);
+
+MINIUPNP_LIBSPEC void
+FreePortListing(struct PortMappingParserData * pdata);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/ext/bin/miniupnpc/include/miniupnpc/receivedata.h b/ext/bin/miniupnpc/include/miniupnpc/receivedata.h
new file mode 100644
index 00000000..0520a11d
--- /dev/null
+++ b/ext/bin/miniupnpc/include/miniupnpc/receivedata.h
@@ -0,0 +1,19 @@
+/* $Id: receivedata.h,v 1.4 2012/09/27 15:42:10 nanard Exp $ */
+/* Project: miniupnp
+ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
+ * Author: Thomas Bernard
+ * Copyright (c) 2011-2012 Thomas Bernard
+ * This software is subjects to the conditions detailed
+ * in the LICENCE file provided within this distribution */
+#ifndef RECEIVEDATA_H_INCLUDED
+#define RECEIVEDATA_H_INCLUDED
+
+/* Reads data from the specified socket.
+ * Returns the number of bytes read if successful, zero if no bytes were
+ * read or if we timed out. Returns negative if there was an error. */
+int receivedata(int socket,
+ char * data, int length,
+ int timeout, unsigned int * scope_id);
+
+#endif
+
diff --git a/ext/bin/miniupnpc/include/miniupnpc/upnpcommands.h b/ext/bin/miniupnpc/include/miniupnpc/upnpcommands.h
new file mode 100644
index 00000000..22eda5e3
--- /dev/null
+++ b/ext/bin/miniupnpc/include/miniupnpc/upnpcommands.h
@@ -0,0 +1,348 @@
+/* $Id: upnpcommands.h,v 1.31 2015/07/21 13:16:55 nanard Exp $ */
+/* Miniupnp project : http://miniupnp.free.fr/
+ * Author : Thomas Bernard
+ * Copyright (c) 2005-2015 Thomas Bernard
+ * This software is subject to the conditions detailed in the
+ * LICENCE file provided within this distribution */
+#ifndef UPNPCOMMANDS_H_INCLUDED
+#define UPNPCOMMANDS_H_INCLUDED
+
+#include "upnpreplyparse.h"
+#include "portlistingparse.h"
+#include "miniupnpc_declspec.h"
+#include "miniupnpctypes.h"
+
+/* MiniUPnPc return codes : */
+#define UPNPCOMMAND_SUCCESS (0)
+#define UPNPCOMMAND_UNKNOWN_ERROR (-1)
+#define UPNPCOMMAND_INVALID_ARGS (-2)
+#define UPNPCOMMAND_HTTP_ERROR (-3)
+#define UPNPCOMMAND_INVALID_RESPONSE (-4)
+#define UPNPCOMMAND_MEM_ALLOC_ERROR (-5)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+MINIUPNP_LIBSPEC UNSIGNED_INTEGER
+UPNP_GetTotalBytesSent(const char * controlURL,
+ const char * servicetype);
+
+MINIUPNP_LIBSPEC UNSIGNED_INTEGER
+UPNP_GetTotalBytesReceived(const char * controlURL,
+ const char * servicetype);
+
+MINIUPNP_LIBSPEC UNSIGNED_INTEGER
+UPNP_GetTotalPacketsSent(const char * controlURL,
+ const char * servicetype);
+
+MINIUPNP_LIBSPEC UNSIGNED_INTEGER
+UPNP_GetTotalPacketsReceived(const char * controlURL,
+ const char * servicetype);
+
+/* UPNP_GetStatusInfo()
+ * status and lastconnerror are 64 byte buffers
+ * Return values :
+ * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
+ * or a UPnP Error code */
+MINIUPNP_LIBSPEC int
+UPNP_GetStatusInfo(const char * controlURL,
+ const char * servicetype,
+ char * status,
+ unsigned int * uptime,
+ char * lastconnerror);
+
+/* UPNP_GetConnectionTypeInfo()
+ * argument connectionType is a 64 character buffer
+ * Return Values :
+ * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
+ * or a UPnP Error code */
+MINIUPNP_LIBSPEC int
+UPNP_GetConnectionTypeInfo(const char * controlURL,
+ const char * servicetype,
+ char * connectionType);
+
+/* UPNP_GetExternalIPAddress() call the corresponding UPNP method.
+ * if the third arg is not null the value is copied to it.
+ * at least 16 bytes must be available
+ *
+ * Return values :
+ * 0 : SUCCESS
+ * NON ZERO : ERROR Either an UPnP error code or an unknown error.
+ *
+ * possible UPnP Errors :
+ * 402 Invalid Args - See UPnP Device Architecture section on Control.
+ * 501 Action Failed - See UPnP Device Architecture section on Control. */
+MINIUPNP_LIBSPEC int
+UPNP_GetExternalIPAddress(const char * controlURL,
+ const char * servicetype,
+ char * extIpAdd);
+
+/* UPNP_GetLinkLayerMaxBitRates()
+ * call WANCommonInterfaceConfig:1#GetCommonLinkProperties
+ *
+ * return values :
+ * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
+ * or a UPnP Error Code. */
+MINIUPNP_LIBSPEC int
+UPNP_GetLinkLayerMaxBitRates(const char* controlURL,
+ const char* servicetype,
+ unsigned int * bitrateDown,
+ unsigned int * bitrateUp);
+
+/* UPNP_AddPortMapping()
+ * if desc is NULL, it will be defaulted to "libminiupnpc"
+ * remoteHost is usually NULL because IGD don't support it.
+ *
+ * Return values :
+ * 0 : SUCCESS
+ * NON ZERO : ERROR. Either an UPnP error code or an unknown error.
+ *
+ * List of possible UPnP errors for AddPortMapping :
+ * errorCode errorDescription (short) - Description (long)
+ * 402 Invalid Args - See UPnP Device Architecture section on Control.
+ * 501 Action Failed - See UPnP Device Architecture section on Control.
+ * 606 Action not authorized - The action requested REQUIRES authorization and
+ * the sender was not authorized.
+ * 715 WildCardNotPermittedInSrcIP - The source IP address cannot be
+ * wild-carded
+ * 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded
+ * 718 ConflictInMappingEntry - The port mapping entry specified conflicts
+ * with a mapping assigned previously to another client
+ * 724 SamePortValuesRequired - Internal and External port values
+ * must be the same
+ * 725 OnlyPermanentLeasesSupported - The NAT implementation only supports
+ * permanent lease times on port mappings
+ * 726 RemoteHostOnlySupportsWildcard - RemoteHost must be a wildcard
+ * and cannot be a specific IP address or DNS name
+ * 727 ExternalPortOnlySupportsWildcard - ExternalPort must be a wildcard and
+ * cannot be a specific port value
+ * 728 NoPortMapsAvailable - There are not enough free ports available to
+ * complete port mapping.
+ * 729 ConflictWithOtherMechanisms - Attempted port mapping is not allowed
+ * due to conflict with other mechanisms.
+ * 732 WildCardNotPermittedInIntPort - The internal port cannot be wild-carded
+ */
+MINIUPNP_LIBSPEC int
+UPNP_AddPortMapping(const char * controlURL, const char * servicetype,
+ const char * extPort,
+ const char * inPort,
+ const char * inClient,
+ const char * desc,
+ const char * proto,
+ const char * remoteHost,
+ const char * leaseDuration);
+
+/* UPNP_AddAnyPortMapping()
+ * if desc is NULL, it will be defaulted to "libminiupnpc"
+ * remoteHost is usually NULL because IGD don't support it.
+ *
+ * Return values :
+ * 0 : SUCCESS
+ * NON ZERO : ERROR. Either an UPnP error code or an unknown error.
+ *
+ * List of possible UPnP errors for AddPortMapping :
+ * errorCode errorDescription (short) - Description (long)
+ * 402 Invalid Args - See UPnP Device Architecture section on Control.
+ * 501 Action Failed - See UPnP Device Architecture section on Control.
+ * 606 Action not authorized - The action requested REQUIRES authorization and
+ * the sender was not authorized.
+ * 715 WildCardNotPermittedInSrcIP - The source IP address cannot be
+ * wild-carded
+ * 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded
+ * 728 NoPortMapsAvailable - There are not enough free ports available to
+ * complete port mapping.
+ * 729 ConflictWithOtherMechanisms - Attempted port mapping is not allowed
+ * due to conflict with other mechanisms.
+ * 732 WildCardNotPermittedInIntPort - The internal port cannot be wild-carded
+ */
+MINIUPNP_LIBSPEC int
+UPNP_AddAnyPortMapping(const char * controlURL, const char * servicetype,
+ const char * extPort,
+ const char * inPort,
+ const char * inClient,
+ const char * desc,
+ const char * proto,
+ const char * remoteHost,
+ const char * leaseDuration,
+ char * reservedPort);
+
+/* UPNP_DeletePortMapping()
+ * Use same argument values as what was used for AddPortMapping().
+ * remoteHost is usually NULL because IGD don't support it.
+ * Return Values :
+ * 0 : SUCCESS
+ * NON ZERO : error. Either an UPnP error code or an undefined error.
+ *
+ * List of possible UPnP errors for DeletePortMapping :
+ * 402 Invalid Args - See UPnP Device Architecture section on Control.
+ * 606 Action not authorized - The action requested REQUIRES authorization
+ * and the sender was not authorized.
+ * 714 NoSuchEntryInArray - The specified value does not exist in the array */
+MINIUPNP_LIBSPEC int
+UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
+ const char * extPort, const char * proto,
+ const char * remoteHost);
+
+/* UPNP_DeletePortRangeMapping()
+ * Use same argument values as what was used for AddPortMapping().
+ * remoteHost is usually NULL because IGD don't support it.
+ * Return Values :
+ * 0 : SUCCESS
+ * NON ZERO : error. Either an UPnP error code or an undefined error.
+ *
+ * List of possible UPnP errors for DeletePortMapping :
+ * 606 Action not authorized - The action requested REQUIRES authorization
+ * and the sender was not authorized.
+ * 730 PortMappingNotFound - This error message is returned if no port
+ * mapping is found in the specified range.
+ * 733 InconsistentParameters - NewStartPort and NewEndPort values are not consistent. */
+MINIUPNP_LIBSPEC int
+UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype,
+ const char * extPortStart, const char * extPortEnd,
+ const char * proto,
+ const char * manage);
+
+/* UPNP_GetPortMappingNumberOfEntries()
+ * not supported by all routers */
+MINIUPNP_LIBSPEC int
+UPNP_GetPortMappingNumberOfEntries(const char* controlURL,
+ const char* servicetype,
+ unsigned int * num);
+
+/* UPNP_GetSpecificPortMappingEntry()
+ * retrieves an existing port mapping
+ * params :
+ * in extPort
+ * in proto
+ * in remoteHost
+ * out intClient (16 bytes)
+ * out intPort (6 bytes)
+ * out desc (80 bytes)
+ * out enabled (4 bytes)
+ * out leaseDuration (16 bytes)
+ *
+ * return value :
+ * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
+ * or a UPnP Error Code.
+ *
+ * List of possible UPnP errors for _GetSpecificPortMappingEntry :
+ * 402 Invalid Args - See UPnP Device Architecture section on Control.
+ * 501 Action Failed - See UPnP Device Architecture section on Control.
+ * 606 Action not authorized - The action requested REQUIRES authorization
+ * and the sender was not authorized.
+ * 714 NoSuchEntryInArray - The specified value does not exist in the array.
+ */
+MINIUPNP_LIBSPEC int
+UPNP_GetSpecificPortMappingEntry(const char * controlURL,
+ const char * servicetype,
+ const char * extPort,
+ const char * proto,
+ const char * remoteHost,
+ char * intClient,
+ char * intPort,
+ char * desc,
+ char * enabled,
+ char * leaseDuration);
+
+/* UPNP_GetGenericPortMappingEntry()
+ * params :
+ * in index
+ * out extPort (6 bytes)
+ * out intClient (16 bytes)
+ * out intPort (6 bytes)
+ * out protocol (4 bytes)
+ * out desc (80 bytes)
+ * out enabled (4 bytes)
+ * out rHost (64 bytes)
+ * out duration (16 bytes)
+ *
+ * return value :
+ * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
+ * or a UPnP Error Code.
+ *
+ * Possible UPNP Error codes :
+ * 402 Invalid Args - See UPnP Device Architecture section on Control.
+ * 606 Action not authorized - The action requested REQUIRES authorization
+ * and the sender was not authorized.
+ * 713 SpecifiedArrayIndexInvalid - The specified array index is out of bounds
+ */
+MINIUPNP_LIBSPEC int
+UPNP_GetGenericPortMappingEntry(const char * controlURL,
+ const char * servicetype,
+ const char * index,
+ char * extPort,
+ char * intClient,
+ char * intPort,
+ char * protocol,
+ char * desc,
+ char * enabled,
+ char * rHost,
+ char * duration);
+
+/* UPNP_GetListOfPortMappings() Available in IGD v2
+ *
+ *
+ * Possible UPNP Error codes :
+ * 606 Action not Authorized
+ * 730 PortMappingNotFound - no port mapping is found in the specified range.
+ * 733 InconsistantParameters - NewStartPort and NewEndPort values are not
+ * consistent.
+ */
+MINIUPNP_LIBSPEC int
+UPNP_GetListOfPortMappings(const char * controlURL,
+ const char * servicetype,
+ const char * startPort,
+ const char * endPort,
+ const char * protocol,
+ const char * numberOfPorts,
+ struct PortMappingParserData * data);
+
+/* IGD:2, functions for service WANIPv6FirewallControl:1 */
+MINIUPNP_LIBSPEC int
+UPNP_GetFirewallStatus(const char * controlURL,
+ const char * servicetype,
+ int * firewallEnabled,
+ int * inboundPinholeAllowed);
+
+MINIUPNP_LIBSPEC int
+UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype,
+ const char * remoteHost,
+ const char * remotePort,
+ const char * intClient,
+ const char * intPort,
+ const char * proto,
+ int * opTimeout);
+
+MINIUPNP_LIBSPEC int
+UPNP_AddPinhole(const char * controlURL, const char * servicetype,
+ const char * remoteHost,
+ const char * remotePort,
+ const char * intClient,
+ const char * intPort,
+ const char * proto,
+ const char * leaseTime,
+ char * uniqueID);
+
+MINIUPNP_LIBSPEC int
+UPNP_UpdatePinhole(const char * controlURL, const char * servicetype,
+ const char * uniqueID,
+ const char * leaseTime);
+
+MINIUPNP_LIBSPEC int
+UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID);
+
+MINIUPNP_LIBSPEC int
+UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype,
+ const char * uniqueID, int * isWorking);
+
+MINIUPNP_LIBSPEC int
+UPNP_GetPinholePackets(const char * controlURL, const char * servicetype,
+ const char * uniqueID, int * packets);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/ext/bin/miniupnpc/include/miniupnpc/upnperrors.h b/ext/bin/miniupnpc/include/miniupnpc/upnperrors.h
new file mode 100644
index 00000000..3115aee5
--- /dev/null
+++ b/ext/bin/miniupnpc/include/miniupnpc/upnperrors.h
@@ -0,0 +1,26 @@
+/* $Id: upnperrors.h,v 1.6 2015/07/21 13:16:55 nanard Exp $ */
+/* (c) 2007-2015 Thomas Bernard
+ * All rights reserved.
+ * MiniUPnP Project.
+ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
+ * This software is subjet to the conditions detailed in the
+ * provided LICENCE file. */
+#ifndef UPNPERRORS_H_INCLUDED
+#define UPNPERRORS_H_INCLUDED
+
+#include "miniupnpc_declspec.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* strupnperror()
+ * Return a string description of the UPnP error code
+ * or NULL for undefinded errors */
+MINIUPNP_LIBSPEC const char * strupnperror(int err);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/ext/bin/miniupnpc/include/miniupnpc/upnpreplyparse.h b/ext/bin/miniupnpc/include/miniupnpc/upnpreplyparse.h
new file mode 100644
index 00000000..6badd15b
--- /dev/null
+++ b/ext/bin/miniupnpc/include/miniupnpc/upnpreplyparse.h
@@ -0,0 +1,63 @@
+/* $Id: upnpreplyparse.h,v 1.19 2014/10/27 16:33:19 nanard Exp $ */
+/* MiniUPnP project
+ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
+ * (c) 2006-2013 Thomas Bernard
+ * This software is subject to the conditions detailed
+ * in the LICENCE file provided within the distribution */
+
+#ifndef UPNPREPLYPARSE_H_INCLUDED
+#define UPNPREPLYPARSE_H_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct NameValue {
+ struct NameValue * l_next;
+ char name[64];
+ char value[128];
+};
+
+struct NameValueParserData {
+ struct NameValue * l_head;
+ char curelt[64];
+ char * portListing;
+ int portListingLength;
+ int topelt;
+ const char * cdata;
+ int cdatalen;
+};
+
+/* ParseNameValue() */
+void
+ParseNameValue(const char * buffer, int bufsize,
+ struct NameValueParserData * data);
+
+/* ClearNameValueList() */
+void
+ClearNameValueList(struct NameValueParserData * pdata);
+
+/* GetValueFromNameValueList() */
+char *
+GetValueFromNameValueList(struct NameValueParserData * pdata,
+ const char * Name);
+
+#if 0
+/* GetValueFromNameValueListIgnoreNS() */
+char *
+GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata,
+ const char * Name);
+#endif
+
+/* DisplayNameValueList() */
+#ifdef DEBUG
+void
+DisplayNameValueList(char * buffer, int bufsize);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/ext/bin/miniupnpc/linux-arm32/libminiupnpc.a b/ext/bin/miniupnpc/linux-arm32/libminiupnpc.a
new file mode 100644
index 00000000..4983f628
Binary files /dev/null and b/ext/bin/miniupnpc/linux-arm32/libminiupnpc.a differ
diff --git a/ext/bin/miniupnpc/linux-x64/libminiupnpc.a b/ext/bin/miniupnpc/linux-x64/libminiupnpc.a
new file mode 100644
index 00000000..270366e0
Binary files /dev/null and b/ext/bin/miniupnpc/linux-x64/libminiupnpc.a differ
diff --git a/ext/bin/miniupnpc/linux-x86/libminiupnpc.a b/ext/bin/miniupnpc/linux-x86/libminiupnpc.a
new file mode 100644
index 00000000..99cbef21
Binary files /dev/null and b/ext/bin/miniupnpc/linux-x86/libminiupnpc.a differ
diff --git a/ext/bin/miniupnpc/mac-x64/libminiupnpc.a b/ext/bin/miniupnpc/mac-x64/libminiupnpc.a
new file mode 100644
index 00000000..3c2e528d
Binary files /dev/null and b/ext/bin/miniupnpc/mac-x64/libminiupnpc.a differ
diff --git a/ext/bin/miniupnpc/windows-x64/miniupnpc.lib b/ext/bin/miniupnpc/windows-x64/miniupnpc.lib
new file mode 100644
index 00000000..e05fefc8
Binary files /dev/null and b/ext/bin/miniupnpc/windows-x64/miniupnpc.lib differ
diff --git a/ext/bin/miniupnpc/windows-x86/miniupnpc.lib b/ext/bin/miniupnpc/windows-x86/miniupnpc.lib
new file mode 100644
index 00000000..a7fe4191
Binary files /dev/null and b/ext/bin/miniupnpc/windows-x86/miniupnpc.lib differ
diff --git a/ext/installfiles/windows/ZeroTier One.aip b/ext/installfiles/windows/ZeroTier One.aip
index ff7ee219..61755698 100644
--- a/ext/installfiles/windows/ZeroTier One.aip
+++ b/ext/installfiles/windows/ZeroTier One.aip
@@ -23,7 +23,7 @@
-
+
@@ -87,8 +87,8 @@
-
-
+
+
diff --git a/ext/mac-ui-macgap1-wrapper/src/MacGap/en.lproj/MainMenu.xib b/ext/mac-ui-macgap1-wrapper/src/MacGap/en.lproj/MainMenu.xib
index 61dafbcc..dd67a86a 100644
--- a/ext/mac-ui-macgap1-wrapper/src/MacGap/en.lproj/MainMenu.xib
+++ b/ext/mac-ui-macgap1-wrapper/src/MacGap/en.lproj/MainMenu.xib
@@ -125,7 +125,7 @@