diff --git a/make-freebsd.mk b/make-freebsd.mk
index c381a0a8a..5ee2a0a36 100644
--- a/make-freebsd.mk
+++ b/make-freebsd.mk
@@ -71,7 +71,7 @@ selftest: $(OBJS) selftest.o
# ./buildinstaller.sh
clean:
- rm -rf *.o node/*.o controller/*.o osdep/*.o service/*.o ext/http-parser/*.o ext/lz4/*.o build-* zerotier-one zerotier-idtool zerotier-selftest ZeroTierOneInstaller-*
+ rm -rf *.o node/*.o controller/*.o osdep/*.o service/*.o ext/http-parser/*.o ext/lz4/*.o ext/json-parser/*.o build-* zerotier-one zerotier-idtool zerotier-selftest ZeroTierOneInstaller-*
debug: FORCE
make -j 4 ZT_DEBUG=1
diff --git a/make-linux.mk b/make-linux.mk
index 082ba07db..63111fdf5 100644
--- a/make-linux.mk
+++ b/make-linux.mk
@@ -76,7 +76,7 @@ installer: one FORCE
./buildinstaller.sh
clean:
- rm -rf *.o node/*.o controller/*.o osdep/*.o service/*.o ext/http-parser/*.o ext/lz4/*.o zerotier-one zerotier-idtool zerotier-selftest build-* ZeroTierOneInstaller-* *.deb *.rpm
+ rm -rf *.o node/*.o controller/*.o osdep/*.o service/*.o ext/http-parser/*.o ext/lz4/*.o ext/json-parser/*.o zerotier-one zerotier-idtool zerotier-selftest build-* ZeroTierOneInstaller-* *.deb *.rpm
debug: FORCE
make -j 4 ZT_DEBUG=1
diff --git a/make-mac.mk b/make-mac.mk
index 2a38714ad..425d9ded2 100644
--- a/make-mac.mk
+++ b/make-mac.mk
@@ -75,7 +75,7 @@ selftest: $(OBJS) selftest.o
# $(CODESIGN) -vvv "build-ZeroTierUI-release/ZeroTier One.app"
clean:
- rm -rf *.dSYM build-* *.pkg *.dmg *.o node/*.o controller/*.o service/*.o osdep/*.o ext/http-parser/*.o ext/lz4/*.o zerotier-one zerotier-idtool zerotier-selftest ZeroTierOneInstaller-*
+ 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 ZeroTierOneInstaller-*
# For our use -- builds official signed binary, packages in installer and download DMG
official: FORCE
diff --git a/objects.mk b/objects.mk
index cf7b256a5..da7086f40 100644
--- a/objects.mk
+++ b/objects.mk
@@ -23,6 +23,7 @@ OBJS=\
node/Switch.o \
node/Topology.o \
node/Utils.o \
+ osdep/Http.o \
osdep/OSUtils.o \
service/ControlPlane.o \
service/OneService.o
diff --git a/one.cpp b/one.cpp
index bcf27bd46..e5afbcb04 100644
--- a/one.cpp
+++ b/one.cpp
@@ -75,6 +75,18 @@ using namespace ZeroTier;
static OneService *volatile zt1Service = (OneService *)0;
+/****************************************************************************/
+/* zerotier-cli personality */
+/****************************************************************************/
+
+#ifdef __WINDOWS__
+static int cli(int argc, _TCHAR* argv[])
+#else
+static int cli(int argc,char **argv)
+#endif
+{
+}
+
/****************************************************************************/
/* zerotier-idtool personality */
/****************************************************************************/
@@ -107,9 +119,9 @@ static Identity getIdFromArg(char *arg)
}
#ifdef __WINDOWS__
-int idtool(int argc, _TCHAR* argv[])
+static int idtool(int argc, _TCHAR* argv[])
#else
-int idtool(int argc,char **argv)
+static int idtool(int argc,char **argv)
#endif
{
if (argc < 2) {
diff --git a/osdep/Http.cpp b/osdep/Http.cpp
new file mode 100644
index 000000000..57efc5569
--- /dev/null
+++ b/osdep/Http.cpp
@@ -0,0 +1,264 @@
+/*
+ * 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 .
+ *
+ * --
+ *
+ * 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/
+ */
+
+#include
+#include
+#include
+
+#include "Http.hpp"
+#include "Phy.hpp"
+#include "OSUtils.hpp"
+#include "../node/Constants.hpp"
+#include "../node/Utils.hpp"
+#include "../ext/http-parser/http_parser.h"
+
+namespace ZeroTier {
+
+namespace {
+
+static int ShttpOnMessageBegin(http_parser *parser);
+static int ShttpOnUrl(http_parser *parser,const char *ptr,size_t length);
+static int ShttpOnStatus(http_parser *parser,const char *ptr,size_t length);
+static int ShttpOnHeaderField(http_parser *parser,const char *ptr,size_t length);
+static int ShttpOnValue(http_parser *parser,const char *ptr,size_t length);
+static int ShttpOnHeadersComplete(http_parser *parser);
+static int ShttpOnBody(http_parser *parser,const char *ptr,size_t length);
+static int ShttpOnMessageComplete(http_parser *parser);
+static const struct http_parser_settings HTTP_PARSER_SETTINGS = {
+ ShttpOnMessageBegin,
+ ShttpOnUrl,
+ ShttpOnStatus,
+ ShttpOnHeaderField,
+ ShttpOnValue,
+ ShttpOnHeadersComplete,
+ ShttpOnBody,
+ ShttpOnMessageComplete
+};
+
+struct HttpPhyHandler
+{
+ // not used
+ inline void phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *from,void *data,unsigned long len) {}
+ inline void phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from) {}
+
+ inline void phyOnTcpConnect(PhySocket *sock,void **uptr,bool success)
+ {
+ if (success) {
+ phy->tcpSetNotifyWritable(sock,true);
+ } else {
+ *responseBody = "connection failed";
+ error = true;
+ done = true;
+ }
+ }
+
+ inline void phyOnTcpClose(PhySocket *sock,void **uptr)
+ {
+ done = true;
+ }
+
+ inline void phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len)
+ {
+ lastActivity = OSUtils::now();
+ http_parser_execute(&parser,&HTTP_PARSER_SETTINGS,(const char *)data,len);
+ if ((parser.upgrade)||(parser.http_errno != HPE_OK))
+ phy->close(sock);
+ }
+
+ inline void phyOnTcpWritable(PhySocket *sock,void **uptr)
+ {
+ if (writePtr < writeSize) {
+ long n = phy->tcpSend(sock,writeBuf + writePtr,writeSize - writePtr,true);
+ if (n > 0)
+ writePtr += n;
+ }
+ if (writePtr >= writeSize)
+ phy->tcpSetNotifyWritable(sock,false);
+ }
+
+ http_parser parser;
+ std::string currentHeaderField;
+ std::string currentHeaderValue;
+ unsigned long messageSize;
+ unsigned long writePtr;
+ uint64_t lastActivity;
+ unsigned long writeSize;
+ char writeBuf[32768];
+
+ unsigned long maxResponseSize;
+ std::map *responseHeaders;
+ std::string *responseBody;
+ bool error;
+ bool done;
+
+ Phy *phy;
+ PhySocket *sock;
+};
+
+static int ShttpOnMessageBegin(http_parser *parser)
+{
+ return 0;
+}
+static int ShttpOnUrl(http_parser *parser,const char *ptr,size_t length)
+{
+ return 0;
+}
+static int ShttpOnStatus(http_parser *parser,const char *ptr,size_t length)
+{
+ HttpPhyHandler *hh = reinterpret_cast(parser->data);
+ hh->messageSize += length;
+ if (hh->messageSize > hh->maxResponseSize)
+ return -1;
+ return 0;
+}
+static int ShttpOnHeaderField(http_parser *parser,const char *ptr,size_t length)
+{
+ HttpPhyHandler *hh = reinterpret_cast(parser->data);
+ hh->messageSize += length;
+ if (hh->messageSize > hh->maxResponseSize)
+ return -1;
+ if ((hh->currentHeaderField.length())&&(hh->currentHeaderValue.length())) {
+ (*hh->responseHeaders)[hh->currentHeaderField] = hh->currentHeaderValue;
+ hh->currentHeaderField.assign("",0);
+ hh->currentHeaderValue.assign("",0);
+ }
+ for(size_t i=0;icurrentHeaderField.push_back(OSUtils::toLower(ptr[i]));
+ return 0;
+}
+static int ShttpOnValue(http_parser *parser,const char *ptr,size_t length)
+{
+ HttpPhyHandler *hh = reinterpret_cast(parser->data);
+ hh->messageSize += length;
+ if (hh->messageSize > hh->maxResponseSize)
+ return -1;
+ hh->currentHeaderValue.append(ptr,length);
+ return 0;
+}
+static int ShttpOnHeadersComplete(http_parser *parser)
+{
+ HttpPhyHandler *hh = reinterpret_cast(parser->data);
+ if ((hh->currentHeaderField.length())&&(hh->currentHeaderValue.length()))
+ (*hh->responseHeaders)[hh->currentHeaderField] = hh->currentHeaderValue;
+ return 0;
+}
+static int ShttpOnBody(http_parser *parser,const char *ptr,size_t length)
+{
+ HttpPhyHandler *hh = reinterpret_cast(parser->data);
+ hh->messageSize += length;
+ if (hh->messageSize > hh->maxResponseSize)
+ return -1;
+ hh->responseBody->append(ptr,length);
+ return 0;
+}
+static int ShttpOnMessageComplete(http_parser *parser)
+{
+ HttpPhyHandler *hh = reinterpret_cast(parser->data);
+ hh->phy->close(hh->sock);
+ return 0;
+}
+
+} // anonymous namespace
+
+unsigned int Http::_do(
+ const char *method,
+ unsigned long maxResponseSize,
+ unsigned long timeout,
+ const struct sockaddr *remoteAddress,
+ const char *path,
+ const std::map &requestHeaders,
+ const void *requestBody,
+ unsigned long requestBodyLength,
+ std::map &responseHeaders,
+ std::string &responseBody)
+{
+ try {
+ responseHeaders.clear();
+ responseBody.assign("",0);
+
+ HttpPhyHandler handler;
+
+ http_parser_init(&(handler.parser),HTTP_RESPONSE);
+ handler.parser.data = (void *)&handler;
+ handler.messageSize = 0;
+ handler.writePtr = 0;
+ handler.lastActivity = OSUtils::now();
+
+ try {
+ handler.writeSize = Utils::snprintf(handler.writeBuf,sizeof(handler.writeBuf),"GET %s HTTP/1.1\r\n",path);
+ for(std::map::const_iterator h(requestHeaders.begin());h!=requestHeaders.end();++h)
+ handler.writeSize += Utils::snprintf(handler.writeBuf + handler.writeSize,sizeof(handler.writeBuf) - handler.writeSize,"%s: %s\r\n",h->first.c_str(),h->second.c_str());
+ handler.writeSize += Utils::snprintf(handler.writeBuf + handler.writeSize,sizeof(handler.writeBuf) - handler.writeSize,"\r\n");
+ if ((requestBody)&&(requestBodyLength)) {
+ if ((handler.writeSize + requestBodyLength) > sizeof(handler.writeBuf)) {
+ responseBody = "request too large";
+ return 0;
+ }
+ memcpy(handler.writeBuf + handler.writeSize,requestBody,requestBodyLength);
+ handler.writeSize += requestBodyLength;
+ }
+ } catch ( ... ) {
+ responseBody = "request too large";
+ return 0;
+ }
+
+ handler.maxResponseSize = maxResponseSize;
+ handler.responseHeaders = &responseHeaders;
+ handler.responseBody = &responseBody;
+ handler.error = false;
+ handler.done = false;
+
+ Phy phy(&handler,true);
+
+ bool instantConnect = false;
+ handler.phy = &phy;
+ handler.sock = phy.tcpConnect((const struct sockaddr *)remoteAddress,instantConnect,(void *)0,true);
+ if (!handler.sock) {
+ responseBody = "connection failed (2)";
+ return 0;
+ }
+
+ while (!handler.done) {
+ phy.poll(timeout / 2);
+ if ((timeout)&&((unsigned long)(OSUtils::now() - handler.lastActivity) > timeout)) {
+ phy.close(handler.sock);
+ responseBody = "timed out";
+ return 0;
+ }
+ }
+
+ return ((handler.error) ? 0 : ((handler.parser.http_errno != HPE_OK) ? 0 : handler.parser.status_code));
+ } catch (std::exception &exc) {
+ responseBody = exc.what();
+ return 0;
+ } catch ( ... ) {
+ responseBody = "unknown exception";
+ return 0;
+ }
+}
+
+} // namespace ZeroTier
diff --git a/osdep/Http.hpp b/osdep/Http.hpp
new file mode 100644
index 000000000..c73cc112c
--- /dev/null
+++ b/osdep/Http.hpp
@@ -0,0 +1,134 @@
+/*
+ * 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 .
+ *
+ * --
+ *
+ * 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/
+ */
+
+#ifndef ZT_HTTP_HPP
+#define ZT_HTTP_HPP
+
+#include
+#include