diff options
Diffstat (limited to 'node')
-rw-r--r-- | node/Socket.hpp | 57 | ||||
-rw-r--r-- | node/SocketManager.hpp | 110 | ||||
-rw-r--r-- | node/TcpSocket.cpp | 183 | ||||
-rw-r--r-- | node/TcpSocket.hpp | 106 | ||||
-rw-r--r-- | node/UdpSocket.cpp | 107 | ||||
-rw-r--r-- | node/UdpSocket.hpp | 63 |
6 files changed, 120 insertions, 506 deletions
diff --git a/node/Socket.hpp b/node/Socket.hpp index e91ce4de..d2525329 100644 --- a/node/Socket.hpp +++ b/node/Socket.hpp @@ -34,12 +34,6 @@ #include "SharedPtr.hpp" #include "NonCopyable.hpp" -#ifdef __WINDOWS__ -#include <WinSock2.h> -#include <WS2tcpip.h> -#include <Windows.h> -#endif - /** * Maximum discrete message length supported by all socket types */ @@ -48,25 +42,22 @@ namespace ZeroTier { class Socket; -class SocketManager; /** - * Base class of all socket types - * - * Socket implementations are tightly bound to SocketManager. + * Base class for transport-layer socket implementations */ class Socket : NonCopyable { - friend class SocketManager; friend class SharedPtr<Socket>; public: enum Type { - ZT_SOCKET_TYPE_UDP_V4, - ZT_SOCKET_TYPE_UDP_V6, - ZT_SOCKET_TYPE_TCP_IN, // incoming connection, not listen - ZT_SOCKET_TYPE_TCP_OUT + ZT_SOCKET_TYPE_UDP_V4 = 1, + ZT_SOCKET_TYPE_UDP_V6 = 2, + ZT_SOCKET_TYPE_TCP_IN = 3, // incoming connection accepted from listen socket + ZT_SOCKET_TYPE_TCP_OUT = 4, // outgoing connection to remote endpoint + ZT_SOCKET_TYPE_ETHERNET = 5 // unused, for future SDN backplane support }; virtual ~Socket() {} @@ -74,29 +65,17 @@ public: /** * @return Socket type */ - inline Type type() const - throw() - { - return _type; - } + inline Type type() const throw() { return _type; } /** * @return True if this is a UDP socket */ - inline bool udp() const - throw() - { - return ((_type == ZT_SOCKET_TYPE_UDP_V4)||(_type == ZT_SOCKET_TYPE_UDP_V6)); - } + inline bool udp() const throw() { return ((_type == ZT_SOCKET_TYPE_UDP_V4)||(_type == ZT_SOCKET_TYPE_UDP_V6)); } /** * @return True if this is a TCP socket */ - inline bool tcp() const - throw() - { - return ((_type == ZT_SOCKET_TYPE_TCP_IN)||(_type == ZT_SOCKET_TYPE_TCP_OUT)); - } + inline bool tcp() const throw() { return ((_type == ZT_SOCKET_TYPE_TCP_IN)||(_type == ZT_SOCKET_TYPE_TCP_OUT)); } /** * Send a ZeroTier message packet @@ -109,25 +88,9 @@ public: virtual bool send(const InetAddress &to,const void *msg,unsigned int msglen) = 0; protected: -#ifdef __WINDOWS__ - Socket(Type t,SOCKET s) : -#else - Socket(Type t,int s) : -#endif - _sock(s), - _type(t) {} - - // Called only by SocketManager, should return false if socket is no longer open/valid (e.g. connection drop or other fatal error) - virtual bool notifyAvailableForRead(const SharedPtr<Socket> &self,SocketManager *sm) = 0; - virtual bool notifyAvailableForWrite(const SharedPtr<Socket> &self,SocketManager *sm) = 0; + Socket(const Type &t) : _type(t) {} -#ifdef __WINDOWS__ - SOCKET _sock; -#else - int _sock; -#endif Type _type; - AtomicCounter __refCount; }; diff --git a/node/SocketManager.hpp b/node/SocketManager.hpp new file mode 100644 index 00000000..3ac53e3d --- /dev/null +++ b/node/SocketManager.hpp @@ -0,0 +1,110 @@ +/* + * 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_SOCKETMANAGER_HPP +#define ZT_SOCKETMANAGER_HPP + +#include <stdio.h> +#include <stdlib.h> + +#include <map> +#include <stdexcept> + +#include "Constants.hpp" +#include "InetAddress.hpp" +#include "Buffer.hpp" +#include "NonCopyable.hpp" +#include "Socket.hpp" + +namespace ZeroTier { + +/** + * Socket I/O implementation + */ +class SocketManager : NonCopyable +{ +public: + SocketManager(void (*packetHandler)(const SharedPtr<Socket> &,void *,const InetAddress &,Buffer<ZT_SOCKET_MAX_MESSAGE_LEN> &),void *arg) : + _packetHandler(packetHandler), + _arg(arg) {} + virtual ~SocketManager() {} + + /** + * Send a message to a remote peer + * + * @param to Destination address + * @param tcp Use TCP? + * @param autoConnectTcp If true, automatically initiate TCP connection if there is none + * @param msg Message to send + * @param msglen Length of message + */ + virtual bool send( + const InetAddress &to, + bool tcp, + bool autoConnectTcp, + const void *msg, + unsigned int msglen) = 0; + + /** + * Send a message to a remote peer via UDP (shortcut for setting both TCP params to false in send) + * + * @param to Destination address + * @param msg Message to send + * @param msglen Length of message + */ + inline bool sendUdp( + const InetAddress &to, + const void *msg, + unsigned int msglen) { return send(to,false,false,msg,msglen); } + + /** + * Perform I/O polling operation (e.g. select()) + * + * If called concurrently, one will block until the other completes. + * + * @param timeout Timeout in milliseconds, may return sooner if whack() is called + */ + virtual void poll(unsigned long timeout) = 0; + + /** + * Cause current or next blocking poll() operation to timeout immediately + */ + virtual void whack() = 0; + + /** + * Close TCP sockets + */ + virtual void closeTcpSockets() = 0; + +protected: + void (*_packetHandler)(const SharedPtr<Socket> &,void *,const InetAddress &,Buffer<ZT_SOCKET_MAX_MESSAGE_LEN> &); + void *_arg; +}; + +} // namespace ZeroTier + +#endif diff --git a/node/TcpSocket.cpp b/node/TcpSocket.cpp deleted file mode 100644 index bc0357fd..00000000 --- a/node/TcpSocket.cpp +++ /dev/null @@ -1,183 +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 <string.h> -#include <stdlib.h> -#include <fcntl.h> -#include <time.h> -#include <errno.h> -#include <sys/types.h> - -#include "Constants.hpp" -#include "TcpSocket.hpp" -#include "SocketManager.hpp" - -#ifdef __WINDOWS__ -#include <WinSock2.h> -#include <WS2tcpip.h> -#include <Windows.h> -#else -#include <unistd.h> -#include <sys/socket.h> -#include <arpa/inet.h> -#include <signal.h> -#endif - -namespace ZeroTier { - -TcpSocket::~TcpSocket() -{ -#ifdef __WINDOWS__ - ::closesocket(_sock); -#else - ::close(_sock); -#endif - //printf("!!! TCP SOCKET DESTROYED @%.16llx to %s\r\n",(unsigned long long)this,_remote.toString().c_str()); -} - -bool TcpSocket::send(const InetAddress &to,const void *msg,unsigned int msglen) -{ - if (msglen > ZT_SOCKET_MAX_MESSAGE_LEN) - return false; // message too big - if (!msglen) - return true; // sanity check - - Mutex::Lock _l(_writeLock); - - bool writeInProgress = ((_outptr != 0)||(_connecting)); - - if ((_outptr + 5 + msglen) > (unsigned int)sizeof(_outbuf)) - return false; - - _outbuf[_outptr++] = 0x17; // look like TLS data - _outbuf[_outptr++] = 0x03; - _outbuf[_outptr++] = 0x03; // look like TLS 1.2 - _outbuf[_outptr++] = (unsigned char)((msglen >> 8) & 0xff); - _outbuf[_outptr++] = (unsigned char)(msglen & 0xff); - for(unsigned int i=0;i<msglen;++i) - _outbuf[_outptr++] = ((const unsigned char *)msg)[i]; - - if (!writeInProgress) { - // If no output was enqueued before this, try to send() it and then - // start a queued write if any remains after that. - - int n = (int)::send(_sock,(const char *)_outbuf,_outptr,0); - if (n > 0) - memmove(_outbuf,_outbuf + (unsigned int)n,_outptr -= (unsigned int)n); - - if (_outptr) { - _sm->startNotifyWrite(this); - _sm->whack(); - } - } // else just leave in _outbuf[] to get written when stream is available for write - - return true; -} - -bool TcpSocket::notifyAvailableForRead(const SharedPtr<Socket> &self,SocketManager *sm) -{ - unsigned char buf[65536]; - - // will not be called concurrently since only SocketManager::poll() calls this - - int n = (int)::recv(_sock,(char *)buf,sizeof(buf),0); - if (n <= 0) - return false; // read error, stream probably closed - - unsigned int p = _inptr,pl = 0; - for(int k=0;k<n;++k) { - _inbuf[p++] = buf[k]; - if (p >= (int)sizeof(_inbuf)) - return false; // read overrun, packet too large or invalid - - if ((!pl)&&(p >= 5)) { - if (_inbuf[0] == 0x17) { - // fake TLS data frame, next two bytes are TLS version and are ignored - pl = (((unsigned int)_inbuf[3] << 8) | (unsigned int)_inbuf[4]) + 5; - } else return false; // in the future we may support fake TLS handshakes - } - - if ((pl)&&(p >= pl)) { - Buffer<ZT_SOCKET_MAX_MESSAGE_LEN> data(_inbuf + 5,pl - 5); - memmove(_inbuf,_inbuf + pl,p -= pl); - try { - sm->handleReceivedPacket(self,_remote,data); - } catch ( ... ) {} // handlers should not throw - pl = 0; - } - } - _inptr = p; - - return true; -} - -bool TcpSocket::notifyAvailableForWrite(const SharedPtr<Socket> &self,SocketManager *sm) -{ - Mutex::Lock _l(_writeLock); - - if (_connecting) - _connecting = false; - - if (_outptr) { - int n = (int)::send(_sock,(const char *)_outbuf,_outptr,0); -#ifdef __WINDOWS__ - if (n == SOCKET_ERROR) { - switch(WSAGetLastError()) { - case WSAEINTR: - case WSAEWOULDBLOCK: - break; - default: - return false; - } -#else - if (n <= 0) { - switch(errno) { -#ifdef EAGAIN - case EAGAIN: -#endif -#if defined(EWOULDBLOCK) && ( !defined(EAGAIN) || (EWOULDBLOCK != EAGAIN) ) - case EWOULDBLOCK: -#endif -#ifdef EINTR - case EINTR: -#endif - break; - default: - return false; - } -#endif - } else memmove(_outbuf,_outbuf + (unsigned int)n,_outptr -= (unsigned int)n); - } - - if (!_outptr) - sm->stopNotifyWrite(this); - - return true; -} - -} // namespace ZeroTier diff --git a/node/TcpSocket.hpp b/node/TcpSocket.hpp deleted file mode 100644 index 59d1ec0b..00000000 --- a/node/TcpSocket.hpp +++ /dev/null @@ -1,106 +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_TCPSOCKET_HPP -#define ZT_TCPSOCKET_HPP - -#include <stdint.h> - -#include "InetAddress.hpp" -#include "Mutex.hpp" -#include "Utils.hpp" -#include "Socket.hpp" - -namespace ZeroTier { - -class SocketManager; - -/** - * A TCP socket encapsulating ZeroTier packets over a TCP stream connection - * - * This implements a simple packet encapsulation that is designed to look like - * a TLS connection. It's not a TLS connection, but it sends TLS format record - * headers. It could be extended in the future to implement a fake TLS - * handshake. - * - * At the moment, each packet is just made to look like TLS application data: - * <[1] TLS content type> - currently 0x17 for "application data" - * <[1] TLS major version> - currently 0x03 for TLS 1.2 - * <[1] TLS minor version> - currently 0x03 for TLS 1.2 - * <[2] payload length> - 16-bit length of payload in bytes - * <[...] payload> - Message payload - * - * The primary purpose of TCP sockets is to work over ports like HTTPS(443), - * allowing users behind particularly fascist firewalls to at least reach - * ZeroTier's supernodes. UDP is the preferred method of communication as - * encapsulating L2 and L3 protocols over TCP is inherently inefficient - * due to double-ACKs. So TCP is only used as a fallback. - */ -class TcpSocket : public Socket -{ - friend class SharedPtr<Socket>; - friend class SocketManager; - -public: - virtual ~TcpSocket(); - virtual bool send(const InetAddress &to,const void *msg,unsigned int msglen); - -protected: -#ifdef __WINDOWS__ - TcpSocket(SocketManager *sm,SOCKET s,Socket::Type t,bool c,const InetAddress &r) : -#else - TcpSocket(SocketManager *sm,int s,Socket::Type t,bool c,const InetAddress &r) : -#endif - Socket(t,s), - _lastActivity(Utils::now()), - _sm(sm), - _inptr(0), - _outptr(0), - _connecting(c), - _remote(r) - { - //printf("!!! TCP SOCKET CREATED @%.16llx to %s\r\n",(unsigned long long)this,_remote.toString().c_str()); - } - - virtual bool notifyAvailableForRead(const SharedPtr<Socket> &self,SocketManager *sm); - virtual bool notifyAvailableForWrite(const SharedPtr<Socket> &self,SocketManager *sm); - -private: - unsigned char _inbuf[ZT_SOCKET_MAX_MESSAGE_LEN]; - unsigned char _outbuf[ZT_SOCKET_MAX_MESSAGE_LEN * 4]; - uint64_t _lastActivity; // updated whenever data is received, checked directly by SocketManager for stale TCP cleanup - SocketManager *_sm; - unsigned int _inptr; - unsigned int _outptr; - bool _connecting; // manipulated directly by SocketManager, true if connect() is in progress - InetAddress _remote; - Mutex _writeLock; -}; - -} // namespace ZeroTier - -#endif diff --git a/node/UdpSocket.cpp b/node/UdpSocket.cpp deleted file mode 100644 index 1f699027..00000000 --- a/node/UdpSocket.cpp +++ /dev/null @@ -1,107 +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 <string.h> -#include <stdlib.h> -#include <fcntl.h> -#include <time.h> -#include <errno.h> -#include <sys/types.h> - -#include "Constants.hpp" -#include "UdpSocket.hpp" -#include "SocketManager.hpp" - -#ifdef __WINDOWS__ -#include <WinSock2.h> -#include <WS2tcpip.h> -#include <Windows.h> -#else -#include <unistd.h> -#include <sys/socket.h> -#include <arpa/inet.h> -#include <signal.h> -#endif - -// Uncomment to intentionally break UDP in order to test TCP fallback -// This is here so I can commit it to the repo and drive myself insane. -//#define ZT_BREAK_UDP - -namespace ZeroTier { - -UdpSocket::~UdpSocket() -{ -#ifdef __WINDOWS__ - ::closesocket(_sock); -#else - ::close(_sock); -#endif -} - -bool UdpSocket::send(const InetAddress &to,const void *msg,unsigned int msglen) -{ -#ifdef ZT_BREAK_UDP - return true; -#else - if (to.isV6()) { -#ifdef __WINDOWS__ - return ((int)sendto(_sock,(const char *)msg,msglen,0,to.saddr(),to.saddrLen()) == (int)msglen); -#else - return ((int)sendto(_sock,msg,msglen,0,to.saddr(),to.saddrLen()) == (int)msglen); -#endif - } else { -#ifdef __WINDOWS__ - return ((int)sendto(_sock,(const char *)msg,msglen,0,to.saddr(),to.saddrLen()) == (int)msglen); -#else - return ((int)sendto(_sock,msg,msglen,0,to.saddr(),to.saddrLen()) == (int)msglen); -#endif - } -#endif -} - -bool UdpSocket::notifyAvailableForRead(const SharedPtr<Socket> &self,SocketManager *sm) -{ - Buffer<ZT_SOCKET_MAX_MESSAGE_LEN> buf; - InetAddress from; - socklen_t salen = from.saddrSpaceLen(); - int n = (int)recvfrom(_sock,(char *)(buf.data()),ZT_SOCKET_MAX_MESSAGE_LEN,0,from.saddr(),&salen); - if (n > 0) { - buf.setSize((unsigned int)n); -#ifndef ZT_BREAK_UDP - sm->handleReceivedPacket(self,from,buf); -#endif - } - return true; -} - -bool UdpSocket::notifyAvailableForWrite(const SharedPtr<Socket> &self,SocketManager *sm) -{ - return true; -} - -} // namespace ZeroTier diff --git a/node/UdpSocket.hpp b/node/UdpSocket.hpp deleted file mode 100644 index 7673b013..00000000 --- a/node/UdpSocket.hpp +++ /dev/null @@ -1,63 +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_UDPSOCKET_HPP -#define ZT_UDPSOCKET_HPP - -#include "Socket.hpp" - -namespace ZeroTier { - -class SocketManager; - -/** - * Locally bound UDP socket - */ -class UdpSocket : public Socket -{ - friend class SharedPtr<Socket>; - friend class SocketManager; - -public: - virtual ~UdpSocket(); - virtual bool send(const InetAddress &to,const void *msg,unsigned int msglen); - -protected: -#ifdef __WINDOWS__ - UdpSocket(Type t,SOCKET s) : -#else - UdpSocket(Type t,int s) : -#endif - Socket(t,s) {} - - virtual bool notifyAvailableForRead(const SharedPtr<Socket> &self,SocketManager *sm); - virtual bool notifyAvailableForWrite(const SharedPtr<Socket> &self,SocketManager *sm); -}; - -} // namespace ZeroTier - -#endif |