diff options
-rw-r--r-- | node/IpcConnection.hpp | 76 | ||||
-rw-r--r-- | node/IpcListener.cpp | 127 | ||||
-rw-r--r-- | node/IpcListener.hpp | 77 |
3 files changed, 280 insertions, 0 deletions
diff --git a/node/IpcConnection.hpp b/node/IpcConnection.hpp new file mode 100644 index 00000000..0636196a --- /dev/null +++ b/node/IpcConnection.hpp @@ -0,0 +1,76 @@ +/* + * 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" +#include "SharedPtr.hpp" +#include "AtomicCounter.hpp" + +namespace ZeroTier { + +class IpcListener; + +/** + * Interprocess communication connection + */ +class IpcConnection : NonCopyable +{ + friend class IpcListener; + friend class SharedPtr<IpcConnection>; + +public: + IpcConnection(const char *endpoint); + ~IpcConnection(); + + void writeln(const char *format,...); + + void close(); + + void threadMain() + throw(); + +private: + // Used by IpcListener to construct connections from incoming attempts + IpcConnection(int s); + + void (*_handler)(void *,const SharedPtr<IpcConnection> &,const char *); + void *_arg; + volatile int _sock; + Thread _thread; + Mutex _writeLock; + + AtomicCounter __refCount; +}; + +} // namespace ZeroTier + +#endif diff --git a/node/IpcListener.cpp b/node/IpcListener.cpp new file mode 100644 index 00000000..5816d8a8 --- /dev/null +++ b/node/IpcListener.cpp @@ -0,0 +1,127 @@ +/* + * 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 <set> + +#include "IpcListener.hpp" + +#ifdef __WINDOWS__ +#include <WinSock2.h> +#include <Windows.h> +#else +#include <sys/socket.h> +#include <sys/ud.h> +#include <unistd.h> +#endif + +namespace ZeroTier { + +IpcListener::IpcListener(cosnt char *ep,void (*commandHandler)(void *,const SharedPtr<IpcConnection> &,const char *),void *arg) : + _endpoint(ep), + _handler(commandHandler), + _arg(arg), + _sock(0) +{ + 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)); + + for(int tries=0;tries<3;++tries) { + _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); + if (errno == EADDRINUSE) { + 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 indicates nothing is listening on other end, so unlink and try again + ::close(testSock); + unlink(_endpoint.c_str()); + } else { + // success means endpoint is being actively listened to by a process + ::close(testSock); + throw std::runtime_error("IPC endpoint address in use"); + } + } else 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"); + } + + _thread = Thread::start(this); +} + +IpcListener::~IpcListener() +{ + int s = _sock; + _sock = 0; + if (s > 0) { + ::shutdown(s,SHUT_RDWR); + ::close(s); + } + Thread::join(_thread); + unlink(_endpoint.c_str()); +} + +void IpcListener::threadMain() + throw() +{ + 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) { + socklen = sizeof(unaddr); + s = accept(_sock,(struct sockaddr *)unaddr,&socklen); + if (s <= 0) + break; + if (!_sock) { + ::close(s); + break; + } + try { + _handler(_arg,SharedPtr<IpcConnection>(new IpcConnection(s)),(const char *)0); + } catch ( ... ) {} // handlers should not throw + } +} + +} // namespace ZeroTier diff --git a/node/IpcListener.hpp b/node/IpcListener.hpp new file mode 100644 index 00000000..f48ca8e7 --- /dev/null +++ b/node/IpcListener.hpp @@ -0,0 +1,77 @@ +/* + * 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 "SharedPtr.hpp" + +#include <string> +#include <stdexcept> + +#ifdef __WINDOWS__ +#define ZT_IPC_ENDPOINT "\\\\.\\pipe\\ZeroTierOne-control" +#else +#define ZT_IPC_ENDPOINT "/tmp/.ZeroTierOne-control" +#endif + +namespace ZeroTier { + +class IpcConnection; + +/** + * IPC incoming connection listener (Unix domain sockets or named pipes on Windows) + */ +class IpcListener : NonCopyable +{ +public: + /** + * @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(cosnt char *ep,void (*commandHandler)(void *,const SharedPtr<IpcConnection> &,const char *),void *arg); + + ~IpcListener(); + + void threadMain() + throw(); + +private: + std::string _endpoint; + void (*_handler)(void *,const SharedPtr<IpcConnection> &,const char *); + void *_arg; + volatile int _sock; + Thread _thread; +}; + +} // namespace ZeroTier + +#endif |