diff options
Diffstat (limited to 'node')
-rw-r--r-- | node/Address.hpp | 9 | ||||
-rw-r--r-- | node/EthernetTapFactory.hpp | 4 | ||||
-rw-r--r-- | node/IpcConnection.cpp | 224 | ||||
-rw-r--r-- | node/IpcConnection.hpp | 105 | ||||
-rw-r--r-- | node/IpcListener.cpp | 164 | ||||
-rw-r--r-- | node/IpcListener.hpp | 96 | ||||
-rw-r--r-- | node/MAC.hpp | 19 | ||||
-rw-r--r-- | node/Network.hpp | 14 | ||||
-rw-r--r-- | node/Node.cpp | 424 | ||||
-rw-r--r-- | node/Node.hpp | 155 | ||||
-rw-r--r-- | node/NodeConfig.cpp | 10 | ||||
-rw-r--r-- | node/NodeConfig.hpp | 38 | ||||
-rw-r--r-- | node/Peer.hpp | 16 | ||||
-rw-r--r-- | node/Topology.hpp | 9 |
14 files changed, 425 insertions, 862 deletions
diff --git a/node/Address.hpp b/node/Address.hpp index c63d41d9..728862da 100644 --- a/node/Address.hpp +++ b/node/Address.hpp @@ -194,6 +194,15 @@ public: }; /** + * @param buf Buffer to fill + * @param len Length of buffer + */ + inline void toString(char *buf,unsigned int len) const + { + Utils::snprintf(buf,len,"%.10llx",(unsigned long long)_a); + } + + /** * @return True if this address is not zero */ inline operator bool() const throw() { return (_a != 0); } diff --git a/node/EthernetTapFactory.hpp b/node/EthernetTapFactory.hpp index d0f5e9b3..c037f451 100644 --- a/node/EthernetTapFactory.hpp +++ b/node/EthernetTapFactory.hpp @@ -30,10 +30,6 @@ #include <stdint.h> -#include <stdexcept> -#include <vector> -#include <string> - #include "MAC.hpp" #include "NonCopyable.hpp" #include "Buffer.hpp" diff --git a/node/IpcConnection.cpp b/node/IpcConnection.cpp deleted file mode 100644 index 5924f545..00000000 --- a/node/IpcConnection.cpp +++ /dev/null @@ -1,224 +0,0 @@ -/* - * ZeroTier One - Global Peer to Peer Ethernet - * Copyright (C) 2011-2014 ZeroTier Networks LLC - * - * 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/ - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <stdarg.h> - -#include <stdexcept> - -#include "IpcConnection.hpp" - -#ifndef __WINDOWS__ -#include <sys/socket.h> -#include <sys/un.h> -#include <unistd.h> -#endif - -namespace ZeroTier { - -IpcConnection::IpcConnection(const char *endpoint,void (*commandHandler)(void *,IpcConnection *,IpcConnection::EventType,const char *),void *arg) : - _handler(commandHandler), - _arg(arg), -#ifdef __WINDOWS__ - _sock(INVALID_HANDLE_VALUE), - _incoming(false), -#else - _sock(-1), -#endif - _run(true), - _running(true) -{ -#ifdef __WINDOWS__ - _sock = CreateFileA(endpoint,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,NULL,OPEN_EXISTING,0,NULL); - if (_sock == INVALID_HANDLE_VALUE) - throw std::runtime_error("IPC endpoint unreachable"); - DWORD pipeMode = PIPE_READMODE_BYTE; - SetNamedPipeHandleState(_sock,&pipeMode,NULL,NULL); -#else - struct sockaddr_un unaddr; - unaddr.sun_family = AF_UNIX; - strncpy(unaddr.sun_path,endpoint,sizeof(unaddr.sun_path)); - unaddr.sun_path[sizeof(unaddr.sun_path) - 1] = (char)0; - - _sock = socket(AF_UNIX,SOCK_STREAM,0); - if (_sock <= 0) - throw std::runtime_error("unable to create socket of type AF_UNIX"); - - if (connect(_sock,(struct sockaddr *)&unaddr,sizeof(unaddr))) { - ::close(_sock); - throw std::runtime_error("IPC endpoint unreachable"); - } -#endif - - _thread = Thread::start(this); -} - -#ifdef __WINDOWS__ -IpcConnection::IpcConnection(HANDLE s,void (*commandHandler)(void *,IpcConnection *,IpcConnection::EventType,const char *),void *arg) : -#else -IpcConnection::IpcConnection(int s,void (*commandHandler)(void *,IpcConnection *,IpcConnection::EventType,const char *),void *arg) : -#endif - _handler(commandHandler), - _arg(arg), - _sock(s), -#ifdef __WINDOWS__ - _incoming(true), -#endif - _run(true), - _running(true) -{ - _thread = Thread::start(this); -} - -IpcConnection::~IpcConnection() -{ - _writeLock.lock(); - _run = false; - _writeLock.unlock(); - -#ifdef __WINDOWS__ - while (_running) { - Thread::cancelIO(_thread); - Sleep(100); - } -#else - int s = _sock; - _sock = 0; - if (s > 0) { - ::shutdown(s,SHUT_RDWR); - ::close(s); - } -#endif -} - -void IpcConnection::printf(const char *format,...) -{ - va_list ap; - int n; - char tmp[65536]; - - va_start(ap,format); - n = (int)::vsnprintf(tmp,sizeof(tmp),format,ap); - va_end(ap); - if (n <= 0) - return; - - Mutex::Lock _l(_writeLock); - -#ifdef __WINDOWS__ - _writeBuf.append(tmp,n); - Thread::cancelIO(_thread); -#else - if (_sock > 0) - ::write(_sock,tmp,n); -#endif -} - -void IpcConnection::threadMain() - throw() -{ - char tmp[65536]; - char linebuf[65536]; - unsigned int lineptr = 0; - char c; - -#ifdef __WINDOWS__ - DWORD n,i; - std::string wbuf; -#else - int s,n,i; -#endif - - while (_run) { -#ifdef __WINDOWS__ - { - Mutex::Lock _l(_writeLock); - if (!_run) - break; - if (_writeBuf.length() > 0) { - wbuf.append(_writeBuf); - _writeBuf.clear(); - } - } - if (wbuf.length() > 0) { - n = 0; - if ((WriteFile(_sock,wbuf.data(),(DWORD)(wbuf.length()),&n,NULL))&&(n > 0)) { - if (n < (DWORD)wbuf.length()) - wbuf.erase(0,n); - else wbuf.clear(); - } else if (GetLastError() != ERROR_OPERATION_ABORTED) - break; - FlushFileBuffers(_sock); - } - if (!_run) - break; - n = 0; - if ((!ReadFile(_sock,tmp,sizeof(tmp),&n,NULL))||(n <= 0)) { - if (GetLastError() == ERROR_OPERATION_ABORTED) - n = 0; - else break; - } - if (!_run) - break; -#else - if ((s = _sock) <= 0) - break; - n = (int)::read(s,tmp,sizeof(tmp)); - if ((n <= 0)||(_sock <= 0)) - break; -#endif - for(i=0;i<n;++i) { - c = (linebuf[lineptr] = tmp[i]); - if ((c == '\r')||(c == '\n')||(lineptr == (sizeof(linebuf) - 1))) { - if (lineptr) { - linebuf[lineptr] = (char)0; - _handler(_arg,this,IPC_EVENT_COMMAND,linebuf); - lineptr = 0; - } - } else ++lineptr; - } - } - - _writeLock.lock(); - bool r = _run; - _writeLock.unlock(); - -#ifdef __WINDOWS__ - if (_incoming) - DisconnectNamedPipe(_sock); - CloseHandle(_sock); - _running = false; -#endif - - if (r) - _handler(_arg,this,IPC_EVENT_CONNECTION_CLOSED,(const char *)0); -} - -} // namespace ZeroTier diff --git a/node/IpcConnection.hpp b/node/IpcConnection.hpp deleted file mode 100644 index f08d27cb..00000000 --- a/node/IpcConnection.hpp +++ /dev/null @@ -1,105 +0,0 @@ -/* - * ZeroTier One - Global Peer to Peer Ethernet - * Copyright (C) 2011-2014 ZeroTier Networks LLC - * - * 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/ - */ - -#ifndef ZT_IPCCONNECTION_HPP -#define ZT_IPCCONNECTION_HPP - -#include "Constants.hpp" -#include "Thread.hpp" -#include "NonCopyable.hpp" -#include "Mutex.hpp" - -#ifdef __WINDOWS__ -#include <WinSock2.h> -#include <Windows.h> -#endif - -namespace ZeroTier { - -class IpcListener; - -/** - * Interprocess communication connection - */ -class IpcConnection : NonCopyable -{ - friend class IpcListener; - -public: - enum EventType - { - IPC_EVENT_COMMAND, - IPC_EVENT_NEW_CONNECTION, - IPC_EVENT_CONNECTION_CLOSED - }; - - /** - * Connect to an IPC endpoint - * - * @param endpoint Endpoint path - * @param commandHandler Command handler function - * @param arg First argument to command handler - * @throws std::runtime_error Unable to connect - */ - IpcConnection(const char *endpoint,void (*commandHandler)(void *,IpcConnection *,IpcConnection::EventType,const char *),void *arg); - ~IpcConnection(); - - /** - * @param format Printf format string - * @param ... Printf arguments - */ - void printf(const char *format,...); - - void threadMain() - throw(); - -private: - // Used by IpcListener to construct incoming connections -#ifdef __WINDOWS__ - IpcConnection(HANDLE s,void (*commandHandler)(void *,IpcConnection *,IpcConnection::EventType,const char *),void *arg); -#else - IpcConnection(int s,void (*commandHandler)(void *,IpcConnection *,IpcConnection::EventType,const char *),void *arg); -#endif - - void (*_handler)(void *,IpcConnection *,IpcConnection::EventType,const char *); - void *_arg; -#ifdef __WINDOWS__ - HANDLE _sock; - std::string _writeBuf; - bool _incoming; -#else - volatile int _sock; -#endif - Mutex _writeLock; - Thread _thread; - volatile bool _run; - volatile bool _running; -}; - -} // namespace ZeroTier - -#endif diff --git a/node/IpcListener.cpp b/node/IpcListener.cpp deleted file mode 100644 index 681328f8..00000000 --- a/node/IpcListener.cpp +++ /dev/null @@ -1,164 +0,0 @@ -/* - * ZeroTier One - Global Peer to Peer Ethernet - * Copyright (C) 2011-2014 ZeroTier Networks LLC - * - * 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/ - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> - -#include "IpcListener.hpp" - -#ifndef __WINDOWS__ -#include <sys/socket.h> -#include <sys/un.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> -#endif - -namespace ZeroTier { - -IpcListener::IpcListener(const char *ep,void (*commandHandler)(void *,IpcConnection *,IpcConnection::EventType,const char *),void *arg) : - _endpoint(ep), - _handler(commandHandler), - _arg(arg), -#ifdef __WINDOWS__ - _run(true), - _running(true) -#else - _sock(0) -#endif -{ -#ifndef __WINDOWS__ - struct sockaddr_un unaddr; - unaddr.sun_family = AF_UNIX; - strncpy(unaddr.sun_path,_endpoint.c_str(),sizeof(unaddr.sun_path)); - unaddr.sun_path[sizeof(unaddr.sun_path) - 1] = (char)0; - - struct stat stattmp; - if (stat(_endpoint.c_str(),&stattmp)) { - int testSock = socket(AF_UNIX,SOCK_STREAM,0); - if (testSock <= 0) - throw std::runtime_error("unable to create socket of type AF_UNIX"); - if (connect(testSock,(struct sockaddr *)&unaddr,sizeof(unaddr))) { - // error means nothing is listening, orphaned name - ::close(testSock); - } else { - // success means endpoint is being actively listened to by a process - ::close(testSock); - throw std::runtime_error("IPC endpoint address in use"); - } - } - ::unlink(_endpoint.c_str()); - - _sock = socket(AF_UNIX,SOCK_STREAM,0); - if (_sock <= 0) - throw std::runtime_error("unable to create socket of type AF_UNIX"); - if (bind(_sock,(struct sockaddr *)&unaddr,sizeof(unaddr))) { - ::close(_sock); - throw std::runtime_error("IPC endpoint could not be bound"); - } - if (listen(_sock,8)) { - ::close(_sock); - throw std::runtime_error("listen() failed for bound AF_UNIX socket"); - } - ::chmod(_endpoint.c_str(),0777); -#endif - - _thread = Thread::start(this); -} - -IpcListener::~IpcListener() -{ -#ifdef __WINDOWS__ - _run = false; - while (_running) { - Thread::cancelIO(_thread); - HANDLE tmp = CreateFileA(_endpoint.c_str(),GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,NULL,OPEN_EXISTING,0,NULL); - if (tmp != INVALID_HANDLE_VALUE) - CloseHandle(tmp); - Sleep(250); - } -#else - int s = _sock; - _sock = 0; - if (s > 0) { - ::shutdown(s,SHUT_RDWR); - ::close(s); - } - Thread::join(_thread); - ::unlink(_endpoint.c_str()); -#endif -} - -void IpcListener::threadMain() - throw() -{ -#ifdef __WINDOWS__ - HANDLE s; - while (_run) { - s = CreateNamedPipeA(_endpoint.c_str(),PIPE_ACCESS_DUPLEX,PIPE_READMODE_BYTE|PIPE_TYPE_BYTE|PIPE_WAIT,PIPE_UNLIMITED_INSTANCES,1024,1024,0,NULL); - if (s != INVALID_HANDLE_VALUE) { - if ((ConnectNamedPipe(s,NULL))||(GetLastError() == ERROR_PIPE_CONNECTED)) { - if (!_run) { - DisconnectNamedPipe(s); - CloseHandle(s); - break; - } - try { - _handler(_arg,new IpcConnection(s,_handler,_arg),IpcConnection::IPC_EVENT_NEW_CONNECTION,(const char *)0); - } catch ( ... ) {} // handlers should not throw - } else { - CloseHandle(s); - } - } - } - _running = false; -#else - struct sockaddr_un unaddr; - socklen_t socklen; - int s; - while (_sock > 0) { - unaddr.sun_family = AF_UNIX; - strncpy(unaddr.sun_path,_endpoint.c_str(),sizeof(unaddr.sun_path)); - unaddr.sun_path[sizeof(unaddr.sun_path) - 1] = (char)0; - socklen = sizeof(unaddr); - s = accept(_sock,(struct sockaddr *)&unaddr,&socklen); - if (s <= 0) - break; - if (!_sock) { - ::close(s); - break; - } - try { - _handler(_arg,new IpcConnection(s,_handler,_arg),IpcConnection::IPC_EVENT_NEW_CONNECTION,(const char *)0); - } catch ( ... ) {} // handlers should not throw - } -#endif -} - -} // namespace ZeroTier diff --git a/node/IpcListener.hpp b/node/IpcListener.hpp deleted file mode 100644 index 8dd6e6fb..00000000 --- a/node/IpcListener.hpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - * ZeroTier One - Global Peer to Peer Ethernet - * Copyright (C) 2011-2014 ZeroTier Networks LLC - * - * 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/ - */ - -#ifndef ZT_IPCLISTENER_HPP -#define ZT_IPCLISTENER_HPP - -#include "Constants.hpp" -#include "Thread.hpp" -#include "NonCopyable.hpp" -#include "IpcConnection.hpp" - -#include <string> -#include <stdexcept> - -#ifdef __WINDOWS__ -#include <WinSock2.h> -#include <Windows.h> -#define ZT_IPC_ENDPOINT_BASE "\\\\.\\pipe\\ZeroTierOne-" -#else -#define ZT_IPC_ENDPOINT_BASE "/tmp/.ZeroTierOne-" -#endif - -namespace ZeroTier { - -/** - * IPC incoming connection listener (Unix domain sockets or named pipes on Windows) - */ -class IpcListener : NonCopyable -{ -public: - /** - * Listen for IPC connections - * - * The supplied handler is passed on to incoming instances of IpcConnection. When - * a connection is first opened, it is called with IPC_EVENT_NEW_CONNECTION. The - * receiver must take ownership of the connection object. When a connection is - * closed, IPC_EVENT_CONNECTION_CLOSING is generated. At this point (or after) the - * receiver must delete the object. IPC_EVENT_COMMAND is generated when lines of - * text are read, and in this cases the last argument is not NULL. No closed event - * is generated in the event of manual delete if the connection is still open. - * - * Yeah, this whole callback model sort of sucks. Might rethink and replace with - * some kind of actor model or something if it gets too unweildy. But for now the - * use cases are simple enough that it's not too bad. - * - * @param commandHandler Function to call for each command - * @param arg First argument to pass to handler - * @throws std::runtime_error Unable to bind to endpoint - */ - IpcListener(const char *ep,void (*commandHandler)(void *,IpcConnection *,IpcConnection::EventType,const char *),void *arg); - - ~IpcListener(); - - void threadMain() - throw(); - -private: - std::string _endpoint; - void (*_handler)(void *,IpcConnection *,IpcConnection::EventType,const char *); - void *_arg; -#ifdef __WINDOWS__ - volatile bool _run; - volatile bool _running; -#else - volatile int _sock; -#endif - Thread _thread; -}; - -} // namespace ZeroTier - -#endif diff --git a/node/MAC.hpp b/node/MAC.hpp index e4f69aa6..5be78f02 100644 --- a/node/MAC.hpp +++ b/node/MAC.hpp @@ -170,14 +170,17 @@ public: inline std::string toString() const { char tmp[24]; - std::string s; - Utils::snprintf(tmp,sizeof(tmp),"%.12llx",_m); - for(int i=0;i<12;++i) { - if ((i > 0)&&((i % 2) == 0)) - s.push_back(':'); - s.push_back(tmp[i]); - } - return s; + toString(tmp,sizeof(tmp)); + return std::string(tmp); + } + + /** + * @param buf Buffer to contain human-readable MAC + * @param len Length of buffer + */ + inline void toString(char *buf,unsigned int len) const + { + Utils::snprintf(buf,len,"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(int)(*this)[0],(int)(*this)[1],(int)(*this)[2],(int)(*this)[3],(int)(*this)[4],(int)(*this)[5]); } /** diff --git a/node/Network.hpp b/node/Network.hpp index cab41411..a24f161c 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -110,13 +110,13 @@ public: */ enum Status { - NETWORK_INITIALIZING, // Creating tap device and setting up state - NETWORK_WAITING_FOR_FIRST_AUTOCONF, // Waiting for initial setup with netconf master - NETWORK_OK, // Network is up, seems to be working - NETWORK_ACCESS_DENIED, // Netconf node reported permission denied - NETWORK_NOT_FOUND, // Netconf node reported network not found - NETWORK_INITIALIZATION_FAILED, // Cannot initialize device (OS/installation problem?) - NETWORK_NO_MORE_DEVICES // OS cannot create any more tap devices (some OSes have a limit) + NETWORK_INITIALIZING = 0, // Creating tap device and setting up state + NETWORK_WAITING_FOR_FIRST_AUTOCONF = 1, // Waiting for initial setup with netconf master + NETWORK_OK = 2, // Network is up, seems to be working + NETWORK_ACCESS_DENIED = 3, // Netconf node reported permission denied + NETWORK_NOT_FOUND = 4, // Netconf node reported network not found + NETWORK_INITIALIZATION_FAILED = 5, // Cannot initialize device (OS/installation problem?) + NETWORK_NO_MORE_DEVICES = 6 // OS cannot create any more tap devices (some OSes have a limit) }; /** diff --git a/node/Node.cpp b/node/Node.cpp index 62a4d9ae..9fe7a3cb 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -74,148 +74,12 @@ #include "Service.hpp" #include "SoftwareUpdater.hpp" #include "Buffer.hpp" -#include "IpcConnection.hpp" #include "AntiRecursion.hpp" #include "RoutingTable.hpp" #include "HttpClient.hpp" namespace ZeroTier { -// --------------------------------------------------------------------------- - -struct _NodeControlClientImpl -{ - void (*resultHandler)(void *,const char *); - void *arg; - IpcConnection *ipcc; - std::string err; -}; - -static void _CBipcResultHandler(void *arg,IpcConnection *ipcc,IpcConnection::EventType event,const char *result) -{ - if ((event == IpcConnection::IPC_EVENT_COMMAND)&&(result)) { - if (strcmp(result,"200 auth OK")) - ((_NodeControlClientImpl *)arg)->resultHandler(((_NodeControlClientImpl *)arg)->arg,result); - } -} - -Node::NodeControlClient::NodeControlClient(const char *hp,void (*resultHandler)(void *,const char *),void *arg,const char *authToken) - throw() : - _impl((void *)new _NodeControlClientImpl) -{ - _NodeControlClientImpl *impl = (_NodeControlClientImpl *)_impl; - impl->ipcc = (IpcConnection *)0; - - if (!hp) - hp = ZT_DEFAULTS.defaultHomePath.c_str(); - - std::string at; - if (authToken) - at = authToken; - else if (!Utils::readFile(authTokenDefaultSystemPath(),at)) { - if (!Utils::readFile(authTokenDefaultUserPath(),at)) { - impl->err = "no authentication token specified and authtoken.secret not readable"; - return; - } - } - - std::string myid; - if (Utils::readFile((std::string(hp) + ZT_PATH_SEPARATOR_S + "identity.public").c_str(),myid)) { - std::string myaddr(myid.substr(0,myid.find(':'))); - if (myaddr.length() != 10) - impl->err = "invalid address extracted from identity.public"; - else { - try { - impl->resultHandler = resultHandler; - impl->arg = arg; - impl->ipcc = new IpcConnection((std::string(ZT_IPC_ENDPOINT_BASE) + myaddr).c_str(),&_CBipcResultHandler,_impl); - impl->ipcc->printf("auth %s"ZT_EOL_S,at.c_str()); - } catch ( ... ) { - impl->ipcc = (IpcConnection *)0; - impl->err = "failure connecting to running ZeroTier One service"; - } - } - } else impl->err = "unable to read identity.public"; -} - -Node::NodeControlClient::~NodeControlClient() -{ - if (_impl) { - delete ((_NodeControlClientImpl *)_impl)->ipcc; - delete (_NodeControlClientImpl *)_impl; - } -} - -const char *Node::NodeControlClient::error() const - throw() -{ - if (((_NodeControlClientImpl *)_impl)->err.length()) - return ((_NodeControlClientImpl *)_impl)->err.c_str(); - return (const char *)0; -} - -void Node::NodeControlClient::send(const char *command) - throw() -{ - try { - if (((_NodeControlClientImpl *)_impl)->ipcc) - ((_NodeControlClientImpl *)_impl)->ipcc->printf("%s"ZT_EOL_S,command); - } catch ( ... ) {} -} - -std::vector<std::string> Node::NodeControlClient::splitLine(const char *line) -{ - return Utils::split(line," ","\\","\""); -} - -const char *Node::NodeControlClient::authTokenDefaultUserPath() -{ - static std::string dlp; - static Mutex dlp_m; - - Mutex::Lock _l(dlp_m); - -#ifdef __WINDOWS__ - - if (!dlp.length()) { - char buf[16384]; - if (SUCCEEDED(SHGetFolderPathA(NULL,CSIDL_APPDATA,NULL,0,buf))) - dlp = (std::string(buf) + "\\ZeroTier\\One\\authtoken.secret"); - } - -#else // not __WINDOWS__ - - if (!dlp.length()) { - const char *home = getenv("HOME"); - if (home) { -#ifdef __APPLE__ - dlp = (std::string(home) + "/Library/Application Support/ZeroTier/One/authtoken.secret"); -#else - dlp = (std::string(home) + "/.zeroTierOneAuthToken"); -#endif - } - } - -#endif // __WINDOWS__ or not __WINDOWS__ - - return dlp.c_str(); -} - -const char *Node::NodeControlClient::authTokenDefaultSystemPath() -{ - static std::string dsp; - static Mutex dsp_m; - - Mutex::Lock _l(dsp_m); - - if (!dsp.length()) - dsp = (ZT_DEFAULTS.defaultHomePath + ZT_PATH_SEPARATOR_S"authtoken.secret"); - - return dsp.c_str(); -} - -// --------------------------------------------------------------------------- - struct _NodeImpl { RuntimeEnvironment renv; @@ -541,6 +405,7 @@ Node::ReasonForTermination Node::run() return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"unable to initialize IPC socket: is ZeroTier One already running?"); } _r->node = this; + #ifdef ZT_AUTO_UPDATE if (ZT_DEFAULTS.updateLatestNfoURL.length()) { _r->updater = new SoftwareUpdater(_r); @@ -799,7 +664,7 @@ Node::ReasonForTermination Node::run() return impl->terminate(); } -const char *Node::reasonForTermination() const +const char *Node::terminationMessage() const throw() { if ((!((_NodeImpl *)_impl)->started)||(((_NodeImpl *)_impl)->running)) @@ -822,6 +687,291 @@ void Node::resync() ((_NodeImpl *)_impl)->renv.sm->whack(); } +bool Node::online() + throw() +{ + _NodeImpl *impl = (_NodeImpl *)_impl; + if (!impl->running) + return false; + RuntimeEnvironment *_r = (RuntimeEnvironment *)&(impl->renv); + uint64_t now = Utils::now(); + uint64_t since = _r->timeOfLastResynchronize; + std::vector< SharedPtr<Peer> > snp(_r->topology->supernodePeers()); + for(std::vector< SharedPtr<Peer> >::const_iterator sn(snp.begin());sn!=snp.end();++sn) { + uint64_t lastRec = (*sn)->lastDirectReceive(); + if ((lastRec)&&(lastRec > since)&&((now - lastRec) < ZT_PEER_PATH_ACTIVITY_TIMEOUT)) + return true; + } + return false; +} + +void Node::join(uint64_t nwid) + throw() +{ + _NodeImpl *impl = (_NodeImpl *)_impl; + RuntimeEnvironment *_r = (RuntimeEnvironment *)&(impl->renv); + _r->nc->join(nwid); +} + +void Node::leave(uint64_t nwid) + throw() +{ + _NodeImpl *impl = (_NodeImpl *)_impl; + RuntimeEnvironment *_r = (RuntimeEnvironment *)&(impl->renv); + _r->nc->leave(nwid); +} + +struct GatherPeerStatistics +{ + uint64_t now; + ZT1_Node_Status *status; + inline void operator()(Topology &t,const SharedPtr<Peer> &p) + { + ++status->knownPeers; + if (p->hasActiveDirectPath(now)) + ++status->directlyConnectedPeers; + if (p->alive(now)) + ++status->alivePeers; + } +}; +void Node::status(ZT1_Node_Status *status) + throw() +{ + _NodeImpl *impl = (_NodeImpl *)_impl; + RuntimeEnvironment *_r = (RuntimeEnvironment *)&(impl->renv); + + memset(status,0,sizeof(ZT1_Node_Status)); + + Utils::scopy(status->publicIdentity,sizeof(status->publicIdentity),_r->identity.toString(false).c_str()); + _r->identity.address().toString(status->address,sizeof(status->address)); + status->rawAddress = _r->identity.address().toInt(); + + status->knownPeers = 0; + status->supernodes = _r->topology->numSupernodes(); + status->directlyConnectedPeers = 0; + status->alivePeers = 0; + GatherPeerStatistics gps; + gps.now = Utils::now(); + gps.status = status; + _r->topology->eachPeer(gps); + + if (status->alivePeers > 0) { + double dlsr = (double)status->directlyConnectedPeers / (double)status->alivePeers; + if (dlsr > 1.0) dlsr = 1.0; + if (dlsr < 0.0) dlsr = 0.0; + status->directLinkSuccessRate = (float)dlsr; + } else status->directLinkSuccessRate = 1.0f; // no connections to no active peers == 100% success at nothing + + status->online = online(); + status->running = impl->running; +} + +struct CollectPeersAndPaths +{ + std::vector< std::pair< SharedPtr<Peer>,std::vector<Path> > > data; + inline void operator()(Topology &t,const SharedPtr<Peer> &p) { data.push_back(std::pair< SharedPtr<Peer>,std::vector<Path> >(p,p->paths())); } +}; +struct SortPeersAndPathsInAscendingAddressOrder +{ + inline bool operator()(const std::pair< SharedPtr<Peer>,std::vector<Path> > &a,const std::pair< SharedPtr<Peer>,std::vector<Path> > &b) const { return (a.first->address() < b.first->address()); } +}; +ZT1_Node_PeerList *Node::listPeers() + throw() +{ + _NodeImpl *impl = (_NodeImpl *)_impl; + RuntimeEnvironment *_r = (RuntimeEnvironment *)&(impl->renv); + + CollectPeersAndPaths pp; + _r->topology->eachPeer(pp); + std::sort(pp.data.begin(),pp.data.end(),SortPeersAndPathsInAscendingAddressOrder()); + + unsigned int returnBufSize = sizeof(ZT1_Node_PeerList); + for(std::vector< std::pair< SharedPtr<Peer>,std::vector<Path> > >::iterator p(pp.data.begin());p!=pp.data.end();++p) + returnBufSize += sizeof(ZT1_Node_Peer) + (sizeof(ZT1_Node_PhysicalPath) * p->second.size()); + + char *buf = (char *)::malloc(returnBufSize); + if (!buf) + return (ZT1_Node_PeerList *)0; + memset(buf,0,returnBufSize); + + ZT1_Node_PeerList *pl = (ZT1_Node_PeerList *)buf; + buf += sizeof(ZT1_Node_PeerList); + + pl->peers = (ZT1_Node_Peer *)buf; + buf += (sizeof(ZT1_Node_Peer) * pp.data.size()); + pl->numPeers = 0; + + uint64_t now = Utils::now(); + for(std::vector< std::pair< SharedPtr<Peer>,std::vector<Path> > >::iterator p(pp.data.begin());p!=pp.data.end();++p) { + ZT1_Node_Peer *prec = &(pl->peers[pl->numPeers++]); + if (p->first->remoteVersionKnown()) + Utils::snprintf(prec->remoteVersion,sizeof(prec->remoteVersion),"%u.%u.%u",p->first->remoteVersionMajor(),p->first->remoteVersionMinor(),p->first->remoteVersionRevision()); + p->first->address().toString(prec->address,sizeof(prec->address)); + prec->rawAddress = p->first->address().toInt(); + prec->latency = p->first->latency(); + + prec->paths = (ZT1_Node_PhysicalPath *)buf; + buf += sizeof(ZT1_Node_PhysicalPath) * p->second.size(); + + prec->numPaths = 0; + for(std::vector<Path>::iterator pi(p->second.begin());pi!=p->second.end();++pi) { + ZT1_Node_PhysicalPath *path = &(prec->paths[prec->numPaths++]); + path->type = static_cast<typeof(path->type)>(pi->type()); + if (pi->address().isV6()) { + path->address.type = ZT1_Node_PhysicalAddress::ZT1_Node_PhysicalAddress_TYPE_IPV6; + memcpy(path->address.bits,pi->address().rawIpData(),16); + // TODO: zoneIndex not supported yet, but should be once echo-location works w/V6 + } else { + path->address.type = ZT1_Node_PhysicalAddress::ZT1_Node_PhysicalAddress_TYPE_IPV4; + memcpy(path->address.bits,pi->address().rawIpData(),4); + } + path->address.port = pi->address().port(); + Utils::scopy(path->address.ascii,sizeof(path->address.ascii),pi->address().toIpString().c_str()); + path->lastSend = (pi->lastSend() > 0) ? ((long)(now - pi->lastSend())) : (long)-1; + path->lastReceive = (pi->lastReceived() > 0) ? ((long)(now - pi->lastReceived())) : (long)-1; + path->lastPing = (pi->lastPing() > 0) ? ((long)(now - pi->lastPing())) : (long)-1; + path->active = pi->active(now); + path->fixed = pi->fixed(); + } + } + + return pl; +} + +// Fills out everything but ips[] and numIps, which must be done more manually +static void _fillNetworkQueryResultBuffer(const SharedPtr<Network> &network,const SharedPtr<NetworkConfig> &nconf,ZT1_Node_Network *nbuf) +{ + nbuf->nwid = network->id(); + Utils::snprintf(nbuf->nwidHex,sizeof(nbuf->nwidHex),"%.16llx",(unsigned long long)network->id()); + if (nconf) { + Utils::scopy(nbuf->name,sizeof(nbuf->name),nconf->name().c_str()); + Utils::scopy(nbuf->description,sizeof(nbuf->description),nconf->description().c_str()); + } + Utils::scopy(nbuf->device,sizeof(nbuf->device),network->tapDeviceName().c_str()); + Utils::scopy(nbuf->statusStr,sizeof(nbuf->statusStr),Network::statusString(network->status())); + network->mac().toString(nbuf->macStr,sizeof(nbuf->macStr)); + network->mac().copyTo(nbuf->mac,sizeof(nbuf->mac)); + uint64_t lcu = network->lastConfigUpdate(); + if (lcu > 0) + nbuf->configAge = (long)(Utils::now() - lcu); + else nbuf->configAge = -1; + nbuf->status = static_cast<typeof(nbuf->status)>(network->status()); + nbuf->enabled = network->enabled(); + nbuf->isPrivate = (nconf) ? nconf->isPrivate() : true; +} + +ZT1_Node_Network *Node::getNetworkStatus(uint64_t nwid) + throw() +{ + _NodeImpl *impl = (_NodeImpl *)_impl; + RuntimeEnvironment *_r = (RuntimeEnvironment *)&(impl->renv); + + SharedPtr<Network> network(_r->nc->network(nwid)); + if (!network) + return (ZT1_Node_Network *)0; + SharedPtr<NetworkConfig> nconf(network->config2()); + std::set<InetAddress> ips(network->ips()); + + char *buf = (char *)::malloc(sizeof(ZT1_Node_Network) + (sizeof(ZT1_Node_PhysicalAddress) * ips.size())); + if (!buf) + return (ZT1_Node_Network *)0; + memset(buf,0,sizeof(ZT1_Node_Network) + (sizeof(ZT1_Node_PhysicalAddress) * ips.size())); + + ZT1_Node_Network *nbuf = (ZT1_Node_Network *)buf; + buf += sizeof(ZT1_Node_Network); + + _fillNetworkQueryResultBuffer(network,nconf,nbuf); + + nbuf->ips = (ZT1_Node_PhysicalAddress *)buf; + nbuf->numIps = 0; + for(std::set<InetAddress>::iterator ip(ips.begin());ip!=ips.end();++ip) { + ZT1_Node_PhysicalAddress *ipb = &(nbuf->ips[nbuf->numIps++]); + if (ip->isV6()) { + ipb->type = ZT1_Node_PhysicalAddress::ZT1_Node_PhysicalAddress_TYPE_IPV6; + memcpy(ipb->bits,ip->rawIpData(),16); + } else { + ipb->type = ZT1_Node_PhysicalAddress::ZT1_Node_PhysicalAddress_TYPE_IPV4; + memcpy(ipb->bits,ip->rawIpData(),4); + } + ipb->port = ip->port(); + Utils::scopy(ipb->ascii,sizeof(ipb->ascii),ip->toIpString().c_str()); + } + + return nbuf; +} + +ZT1_Node_NetworkList *Node::listNetworks() + throw() +{ + _NodeImpl *impl = (_NodeImpl *)_impl; + RuntimeEnvironment *_r = (RuntimeEnvironment *)&(impl->renv); + + std::vector< SharedPtr<Network> > networks(_r->nc->networks()); + std::vector< SharedPtr<NetworkConfig> > nconfs(networks.size()); + std::vector< std::set<InetAddress> > ipsv(networks.size()); + + unsigned long returnBufSize = sizeof(ZT1_Node_NetworkList); + for(unsigned long i=0;i<networks.size();++i) { + nconfs[i] = networks[i]->config2(); + ipsv[i] = networks[i]->ips(); + returnBufSize += sizeof(ZT1_Node_Network) + (sizeof(ZT1_Node_PhysicalAddress) * ipsv[i].size()); + } + + char *buf = (char *)::malloc(returnBufSize); + if (!buf) + return (ZT1_Node_NetworkList *)0; + memset(buf,0,returnBufSize); + + ZT1_Node_NetworkList *nl = (ZT1_Node_NetworkList *)buf; + buf += sizeof(ZT1_Node_NetworkList); + + nl->networks = (ZT1_Node_Network *)buf; + buf += sizeof(ZT1_Node_Network) * networks.size(); + + for(unsigned long i=0;i<networks.size();++i) { + ZT1_Node_Network *nbuf = &(nl->networks[nl->numNetworks++]); + + _fillNetworkQueryResultBuffer(networks[i],nconfs[i],nbuf); + + nbuf->ips = (ZT1_Node_PhysicalAddress *)buf; + buf += sizeof(ZT1_Node_PhysicalAddress); + + nbuf->numIps = 0; + for(std::set<InetAddress>::iterator ip(ipsv[i].begin());ip!=ipsv[i].end();++ip) { + ZT1_Node_PhysicalAddress *ipb = &(nbuf->ips[nbuf->numIps++]); + if (ip->isV6()) { + ipb->type = ZT1_Node_PhysicalAddress::ZT1_Node_PhysicalAddress_TYPE_IPV6; + memcpy(ipb->bits,ip->rawIpData(),16); + } else { + ipb->type = ZT1_Node_PhysicalAddress::ZT1_Node_PhysicalAddress_TYPE_IPV4; + memcpy(ipb->bits,ip->rawIpData(),4); + } + ipb->port = ip->port(); + Utils::scopy(ipb->ascii,sizeof(ipb->ascii),ip->toIpString().c_str()); + } + } + + return nl; +} + +void Node::freeQueryResult(void *qr) + throw() +{ + ::free(qr); +} + +bool Node::updateCheck() + throw() +{ + _NodeImpl *impl = (_NodeImpl *)_impl; + RuntimeEnvironment *_r = (RuntimeEnvironment *)&(impl->renv); + if (_r->updater) { + _r->updater->checkNow(); + return true; + } + return false; +} + class _VersionStringMaker { public: diff --git a/node/Node.hpp b/node/Node.hpp index 179afbea..4e4a8d91 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -28,8 +28,9 @@ #ifndef ZT_NODE_HPP #define ZT_NODE_HPP -#include <string> -#include <vector> +#include <stdint.h> + +#include "../include/ZeroTierOne.h" namespace ZeroTier { @@ -38,88 +39,11 @@ class RoutingTable; /** * A ZeroTier One node - * - * This class hides all its implementation details and all other classes in - * preparation for ZeroTier One being made available in library form for - * embedding in mobile apps. */ class Node { public: /** - * Client for controlling a local ZeroTier One node - * - * Windows note: be sure you call WSAStartup() before using this, - * otherwise it will be unable to open a local UDP socket to - * communicate with the service. - */ - class NodeControlClient - { - public: - /** - * Create a new node config client - * - * Initialization may fail. Call error() to check. - * - * @param hp Home path of ZeroTier One instance or NULL for default system home path - * @param resultHandler Function to call when commands provide results - * @param arg First argument to result handler - * @param authToken Authentication token or NULL (default) to read from authtoken.secret in home path - */ - NodeControlClient(const char *hp,void (*resultHandler)(void *,const char *),void *arg,const char *authToken = (const char *)0) - throw(); - - ~NodeControlClient(); - - /** - * @return Initialization error or NULL if none - */ - const char *error() const - throw(); - - /** - * Send a command to the local node - * - * Note that the returned conversation ID will never be 0. A return value - * of 0 indicates a fatal error such as failure to bind to any local UDP - * port. - * - * @param command - * @return Conversation ID that will be provided to result handler when/if results are sent back - */ - void send(const char *command) - throw(); - inline void send(const std::string &command) - throw() { return send(command.c_str()); } - - /** - * Split a line of results - * - * @param line Line to split - * @return Vector of fields - */ - static std::vector<std::string> splitLine(const char *line); - static inline std::vector<std::string> splitLine(const std::string &line) { return splitLine(line.c_str()); } - - /** - * @return Default path for current user's authtoken.secret - */ - static const char *authTokenDefaultUserPath(); - - /** - * @return Default path to system authtoken.secret - */ - static const char *authTokenDefaultSystemPath(); - - private: - // NodeControlClient is not copyable - NodeControlClient(const NodeControlClient&); - const NodeControlClient& operator=(const NodeControlClient&); - - void *_impl; - }; - - /** * Returned by node main if/when it terminates */ enum ReasonForTermination @@ -155,7 +79,7 @@ public: * * The node is not executed until run() is called. The supplied tap factory * and routing table must not be freed until the node is no longer - * executing. Node does not delete these objects, so the caller still owns + * executing. Node does not delete these objects; the caller still owns * them. * * @param hp Home directory path or NULL for system-wide default for this platform @@ -171,18 +95,12 @@ public: RoutingTable *rt, unsigned int udpPort, unsigned int tcpPort, - bool resetIdentity) - throw(); + bool resetIdentity) throw(); ~Node(); /** - * Execute node in current thread - * - * This does not return until the node shuts down. Shutdown may be caused - * by an internally detected condition such as a new upgrade being - * available or a fatal error, or it may be signaled externally using - * the terminate() method. + * Execute node in current thread, return on shutdown * * @return Reason for termination */ @@ -194,56 +112,93 @@ public: * * @return Reason for node termination or NULL if run() has not returned */ - const char *reasonForTermination() const + const char *terminationMessage() const throw(); /** * Terminate this node, causing run() to return * * @param reason Reason for termination - * @param reasonText Text to be returned by reasonForTermination() + * @param reasonText Text to be returned by terminationMessage() */ void terminate(ReasonForTermination reason,const char *reasonText) throw(); /** * Forget p2p links now and resynchronize with peers + * + * This can be used if the containing application knows its network environment has + * changed. ZeroTier itself tries to detect such changes, but is not always successful. */ void resync() throw(); /** + * @return True if we appear to be online in some viable capacity + */ + bool online() + throw(); + + /** * Join a network * - * @param nwid 16-digit hex network ID + * Use getNetworkStatus() to check the network's status after joining. If you + * are already a member of the network, this does nothing. + * + * @param nwid 64-bit network ID */ - bool join(const char *nwid) + void join(uint64_t nwid) throw(); /** * Leave a network * - * @param nwid 16-digit hex network ID + * @param nwid 64-bit network ID + */ + void leave(uint64_t nwid) + throw(); + + /** + * Get the status of this node + * + * @param status Buffer to fill with status information */ - bool leave(const char *nwid) + void status(ZT1_Node_Status *status) throw(); - void listPeers() + /** + * @return List of known peers or NULL on failure + */ + ZT1_Node_PeerList *listPeers() throw(); - void listNetworks() + /** + * @param nwid 64-bit network ID + * @return Network status or NULL if we are not a member of this network + */ + ZT1_Node_Network *getNetworkStatus(uint64_t nwid) throw(); /** - * Check for software updates (if enabled) + * @return List of networks we've joined or NULL on failure */ - bool updateCheck() + ZT1_Node_NetworkList *listNetworks() throw(); /** - * @return Description of last non-fatal error or empty string if none + * Free a query result buffer + * + * Use this to free the return values of listNetworks(), listPeers(), etc. + * + * @param qr Query result buffer + */ + void freeQueryResult(void *qr) + throw(); + + /** + * Check for software updates (if enabled) (updates will eventually get factored out of node/) */ - const char *getLastError() + bool updateCheck() throw(); static const char *versionString() throw(); diff --git a/node/NodeConfig.cpp b/node/NodeConfig.cpp index 732d41a3..996163d0 100644 --- a/node/NodeConfig.cpp +++ b/node/NodeConfig.cpp @@ -52,9 +52,9 @@ namespace ZeroTier { NodeConfig::NodeConfig(const RuntimeEnvironment *renv,const char *authToken) : - _r(renv), - _ipcListener((std::string(ZT_IPC_ENDPOINT_BASE) + renv->identity.address().toString()).c_str(),&_CBcommandHandler,this), - _authToken(authToken) + _r(renv) +// _ipcListener((std::string(ZT_IPC_ENDPOINT_BASE) + renv->identity.address().toString()).c_str(),&_CBcommandHandler,this), +// _authToken(authToken) { { Mutex::Lock _l(_localConfig_m); @@ -91,10 +91,12 @@ NodeConfig::~NodeConfig() _writeLocalConfig(); // Close any open IPC connections + /* Mutex::Lock _l(_connections_m); for(std::map< IpcConnection *,bool >::iterator c(_connections.begin());c!=_connections.end();++c) delete c->first; _connections.clear(); + */ } void NodeConfig::putLocalConfig(const std::string &key,const char *value) @@ -127,6 +129,7 @@ void NodeConfig::clean() n->second->clean(); } +/* void NodeConfig::_CBcommandHandler(void *arg,IpcConnection *ipcc,IpcConnection::EventType event,const char *commandLine) { switch(event) { @@ -310,6 +313,7 @@ void NodeConfig::_doCommand(IpcConnection *ipcc,const char *commandLine) ipcc->printf("."ZT_EOL_S); // blank line ends response } +*/ void NodeConfig::_readLocalConfig() { diff --git a/node/NodeConfig.hpp b/node/NodeConfig.hpp index b9bc8f5f..d374eee6 100644 --- a/node/NodeConfig.hpp +++ b/node/NodeConfig.hpp @@ -36,8 +36,6 @@ #include <vector> #include <stdexcept> -#include "IpcListener.hpp" -#include "IpcConnection.hpp" #include "SharedPtr.hpp" #include "Network.hpp" #include "Utils.hpp" @@ -105,6 +103,38 @@ public: } /** + * Join a network or return existing network if already joined + * + * @param nwid Network ID to join + * @return New network instance + */ + inline SharedPtr<Network> join(uint64_t nwid) + { + Mutex::Lock _l(_networks_m); + SharedPtr<Network> &nw = _networks[nwid]; + if (nw) + return nw; + else return (nw = Network::newInstance(_r,this,nwid)); + } + + /** + * Leave a network + * + * @param nwid Network ID + * @return True if network was left, false if we were not a member of this network + */ + inline bool leave(uint64_t nwid) + { + Mutex::Lock _l(_networks_m); + std::map< uint64_t,SharedPtr<Network> >::iterator n(_networks.find(nwid)); + if (n != _networks.end()) { + n->second->destroy(); + _networks.erase(n); + return true; + } else return false; + } + + /** * Perform cleanup and possibly persist saved state */ void clean(); @@ -135,18 +165,22 @@ public: } private: + /* static void _CBcommandHandler(void *arg,IpcConnection *ipcc,IpcConnection::EventType event,const char *commandLine); void _doCommand(IpcConnection *ipcc,const char *commandLine); + */ void _readLocalConfig(); void _writeLocalConfig(); const RuntimeEnvironment *_r; + /* IpcListener _ipcListener; std::string _authToken; std::map< IpcConnection *,bool > _connections; Mutex _connections_m; + */ Dictionary _localConfig; // persisted as local.conf Mutex _localConfig_m; diff --git a/node/Peer.hpp b/node/Peer.hpp index 05005a30..5204cb84 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -363,18 +363,10 @@ public: _vRevision = vrev; } - /** - * @return Remote version in string form or '?' if unknown - */ - inline std::string remoteVersion() const - { - if ((_vMajor > 0)||(_vMinor > 0)||(_vRevision > 0)) { - char tmp[32]; - Utils::snprintf(tmp,sizeof(tmp),"%u.%u.%u",_vMajor,_vMinor,_vRevision); - return std::string(tmp); - } - return std::string("?.?.?"); - } + inline unsigned int remoteVersionMajor() const throw() { return _vMajor; } + inline unsigned int remoteVersionMinor() const throw() { return _vMinor; } + inline unsigned int remoteVersionRevision() const throw() { return _vRevision; } + inline bool remoteVersionKnown() const throw() { return ((_vMajor > 0)||(_vMinor > 0)||(_vRevision > 0)); } /** * Get most recently active UDP path addresses for IPv4 and/or IPv6 diff --git a/node/Topology.hpp b/node/Topology.hpp index 6349fe87..6bbbc297 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -126,6 +126,15 @@ public: } /** + * @return Number of supernodes + */ + inline unsigned int numSupernodes() const + { + Mutex::Lock _l(_supernodes_m); + return _supernodePeers.size(); + } + + /** * Get the current favorite supernode * * @return Supernode with lowest latency or NULL if none |