diff options
-rw-r--r-- | node/IpcConnection.cpp | 138 | ||||
-rw-r--r-- | node/IpcConnection.hpp | 23 | ||||
-rw-r--r-- | node/IpcListener.cpp | 27 | ||||
-rw-r--r-- | node/IpcListener.hpp | 2 | ||||
-rw-r--r-- | objects.mk | 2 |
5 files changed, 178 insertions, 14 deletions
diff --git a/node/IpcConnection.cpp b/node/IpcConnection.cpp new file mode 100644 index 00000000..784c651d --- /dev/null +++ b/node/IpcConnection.cpp @@ -0,0 +1,138 @@ +/* + * 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" + +#ifdef __WINDOWS__ +#include <WinSock2.h> +#include <Windows.h> +#else +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#endif + +namespace ZeroTier { + +IpcConnection::IpcConnection(const char *endpoint,void (*commandHandler)(void *,const SharedPtr<IpcConnection> &,const char *),void *arg) : + _handler(commandHandler), + _arg(arg), + _sock(0) +{ + 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"); + } + + Thread::start(this); +} + +IpcConnection::IpcConnection(int s,void (*commandHandler)(void *,const SharedPtr<IpcConnection> &,const char *),void *arg) : + _handler(commandHandler), + _arg(arg), + _sock(s) +{ + Thread::start(this); +} + +IpcConnection::~IpcConnection() +{ + this->close(); +} + +void IpcConnection::printf(const char *format,...) +{ + va_list ap; + int n; + char tmp[65536]; + + Mutex::Lock _l(_writeLock); + + if (_sock <= 0) + return; + + va_start(ap,format); + n = (int)::vsnprintf(tmp,sizeof(tmp),format,ap); + va_end(ap); + + ::write(_sock,tmp,n); +} + +void IpcConnection::close() +{ + Mutex::Lock _l(_writeLock); + int s = _sock; + _sock = 0; + if (s > 0) { + ::shutdown(s,SHUT_RDWR); + ::close(s); + } + Thread::join(_thread); +} + +void IpcConnection::threadMain() + throw() +{ + char tmp[65536]; + char linebuf[65536]; + unsigned int lineptr = 0; + + while (_sock) { + int n = (int)::read(_sock,tmp,sizeof(tmp)); + if (n <= 0) + break; + for(int i=0;i<n;++i) { + char c = (linebuf[lineptr] = tmp[i]); + if ((c == '\r')||(c == '\n')||(lineptr == (sizeof(linebuf) - 1))) { + if (lineptr) { + linebuf[lineptr] = (char)0; + _handler(_arg,SharedPtr<IpcConnection>(this),linebuf); + lineptr = 0; + } + } else ++lineptr; + } + } +} + +} // namespace ZeroTier diff --git a/node/IpcConnection.hpp b/node/IpcConnection.hpp index 0636196a..60d34634 100644 --- a/node/IpcConnection.hpp +++ b/node/IpcConnection.hpp @@ -48,19 +48,34 @@ class IpcConnection : NonCopyable friend class SharedPtr<IpcConnection>; public: - IpcConnection(const char *endpoint); + /** + * 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 *,const SharedPtr<IpcConnection> &,const char *),void *arg); ~IpcConnection(); - void writeln(const char *format,...); + /** + * @param format Printf format string + * @param ... Printf arguments + */ + void printf(const char *format,...); + /** + * Close this connection + */ void close(); void threadMain() throw(); private: - // Used by IpcListener to construct connections from incoming attempts - IpcConnection(int s); + // Used by IpcListener to construct incoming connections + IpcConnection(int s,void (*commandHandler)(void *,const SharedPtr<IpcConnection> &,const char *),void *arg); void (*_handler)(void *,const SharedPtr<IpcConnection> &,const char *); void *_arg; diff --git a/node/IpcListener.cpp b/node/IpcListener.cpp index 5816d8a8..3cc5fb23 100644 --- a/node/IpcListener.cpp +++ b/node/IpcListener.cpp @@ -33,30 +33,31 @@ #include <set> #include "IpcListener.hpp" +#include "IpcConnection.hpp" #ifdef __WINDOWS__ #include <WinSock2.h> #include <Windows.h> #else #include <sys/socket.h> -#include <sys/ud.h> +#include <sys/un.h> #include <unistd.h> #endif namespace ZeroTier { -IpcListener::IpcListener(cosnt char *ep,void (*commandHandler)(void *,const SharedPtr<IpcConnection> &,const char *),void *arg) : +IpcListener::IpcListener(const char *ep,void (*commandHandler)(void *,const SharedPtr<IpcConnection> &,const char *),void *arg) : _endpoint(ep), _handler(commandHandler), _arg(arg), _sock(0) { +#ifdef __WINDOWS__ +#else struct sockaddr_un unaddr; - unaddr.sun_family = AF_UNIX; - if ((long)_endpoint.length() > (long)(sizeof(unaddr.sun_path) - 1)) - throw std::runtime_error("IPC endpoint path too long"); strncpy(unaddr.sun_path,_endpoint.c_str(),sizeof(unaddr.sun_path)); + unaddr.sun_path[sizeof(unaddr.sun_path) - 1] = (char)0; for(int tries=0;tries<3;++tries) { _sock = socket(AF_UNIX,SOCK_STREAM,0); @@ -85,12 +86,15 @@ IpcListener::IpcListener(cosnt char *ep,void (*commandHandler)(void *,const Shar ::close(_sock); throw std::runtime_error("listen() failed for bound AF_UNIX socket"); } +#endif _thread = Thread::start(this); } IpcListener::~IpcListener() { +#ifdef __WINDOWS__ +#else int s = _sock; _sock = 0; if (s > 0) { @@ -99,19 +103,23 @@ IpcListener::~IpcListener() } Thread::join(_thread); unlink(_endpoint.c_str()); +#endif } void IpcListener::threadMain() throw() { +#ifdef __WINDOWS__ +#else struct sockaddr_un unaddr; socklen_t socklen; int s; - unaddr.sun_family = AF_UNIX; - strncpy(unaddr.sun_path,_endpoint.c_str(),sizeof(unaddr.sun_path)); 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); + s = accept(_sock,(struct sockaddr *)&unaddr,&socklen); if (s <= 0) break; if (!_sock) { @@ -119,9 +127,10 @@ void IpcListener::threadMain() break; } try { - _handler(_arg,SharedPtr<IpcConnection>(new IpcConnection(s)),(const char *)0); + _handler(_arg,SharedPtr<IpcConnection>(new IpcConnection(s,_handler,_arg)),(const char *)0); } catch ( ... ) {} // handlers should not throw } +#endif } } // namespace ZeroTier diff --git a/node/IpcListener.hpp b/node/IpcListener.hpp index f48ca8e7..40beba0d 100644 --- a/node/IpcListener.hpp +++ b/node/IpcListener.hpp @@ -57,7 +57,7 @@ public: * @param arg First argument to pass to handler * @throws std::runtime_error Unable to bind to endpoint */ - IpcListener(cosnt char *ep,void (*commandHandler)(void *,const SharedPtr<IpcConnection> &,const char *),void *arg); + IpcListener(const char *ep,void (*commandHandler)(void *,const SharedPtr<IpcConnection> &,const char *),void *arg); ~IpcListener(); @@ -8,6 +8,8 @@ OBJS=\ node/HttpClient.o \ node/Identity.o \ node/InetAddress.o \ + node/IpcConnection.o \ + node/IpcListener.o \ node/Logger.o \ node/Multicaster.o \ node/Network.o \ |