From bf5d8de99920cc7652a41040e00576dbab1edaed Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 17 Mar 2014 16:29:53 -0700 Subject: More new socket I/O work... --- node/SocketManager.cpp | 30 +++++-- node/UdpSocket_old.cpp | 239 ------------------------------------------------- node/UdpSocket_old.hpp | 118 ------------------------ 3 files changed, 24 insertions(+), 363 deletions(-) delete mode 100644 node/UdpSocket_old.cpp delete mode 100644 node/UdpSocket_old.hpp diff --git a/node/SocketManager.cpp b/node/SocketManager.cpp index 825d107e..a9783082 100644 --- a/node/SocketManager.cpp +++ b/node/SocketManager.cpp @@ -421,7 +421,7 @@ void SocketManager::poll(unsigned long timeout) _udpV6Socket->notifyAvailableForRead(_udpV6Socket,this); std::vector< SharedPtr > ts; - { + { // grab copy of TCP sockets list because _tcpSockets[] might be changed in a handler Mutex::Lock _l2(_tcpSockets_m); if (_tcpSockets.size()) { ts.reserve(_tcpSockets.size()); @@ -429,22 +429,40 @@ void SocketManager::poll(unsigned long timeout) if (true) { // TODO: TCP expiration check ts.push_back(s->second); ++s; - } else _tcpSockets.erase(s++); + } else { + _fdSetLock.lock(); + FD_CLR(s->second->_sock,&_readfds); + FD_CLR(s->second->_sock,&_writefds); + _fdSetLock.unlock(); + _tcpSockets.erase(s++); + } } } } for(std::vector< SharedPtr >::iterator s(ts.begin());s!=ts.end();++s) { if (FD_ISSET((*s)->_sock,&wfds)) { if (!(*s)->notifyAvailableForWrite(*s,this)) { - Mutex::Lock _l2(_tcpSockets_m); - _tcpSockets.erase(((TcpSocket *)s->ptr())->_remote); + { + Mutex::Lock _l2(_tcpSockets_m); + _tcpSockets.erase(((TcpSocket *)s->ptr())->_remote); + } + _fdSetLock.lock(); + FD_CLR((*s)->_sock,&_readfds); + FD_CLR((*s)->_sock,&_writefds); + _fdSetLock.unlock(); continue; } } if (FD_ISSET((*s)->_sock,&rfds)) { if (!(*s)->notifyAvailableForRead(*s,this)) { - Mutex::Lock _l2(_tcpSockets_m); - _tcpSockets.erase(((TcpSocket *)s->ptr())->_remote); + { + Mutex::Lock _l2(_tcpSockets_m); + _tcpSockets.erase(((TcpSocket *)s->ptr())->_remote); + } + _fdSetLock.lock(); + FD_CLR((*s)->_sock,&_readfds); + FD_CLR((*s)->_sock,&_writefds); + _fdSetLock.unlock(); continue; } } diff --git a/node/UdpSocket_old.cpp b/node/UdpSocket_old.cpp deleted file mode 100644 index a3f551b3..00000000 --- a/node/UdpSocket_old.cpp +++ /dev/null @@ -1,239 +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 . - * - * -- - * - * 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 -#include -#include -#include - -#include "Constants.hpp" - -#ifdef __WINDOWS__ -#include -#include -#include -#else -#include -#include -#include -#include -#endif - -#include "UdpSocket.hpp" -#include "RuntimeEnvironment.hpp" -#include "Logger.hpp" -#include "Switch.hpp" - -namespace ZeroTier { - -UdpSocket::UdpSocket( - bool localOnly, - int localPort, - bool ipv6, - void (*packetHandler)(UdpSocket *,void *,const InetAddress &,const void *,unsigned int), - void *arg) - throw(std::runtime_error) : - _packetHandler(packetHandler), - _arg(arg), - _localPort(localPort), -#ifdef __WINDOWS__ - _sock(INVALID_SOCKET), -#else - _sock(0), -#endif - _v6(ipv6) -{ -#ifdef __WINDOWS__ - BOOL yes,no; -#else - int yes,no; -#endif - - if ((localPort <= 0)||(localPort > 0xffff)) - throw std::runtime_error("port is out of range"); - - if (ipv6) { - _sock = socket(AF_INET6,SOCK_DGRAM,0); -#ifdef __WINDOWS__ - if (_sock == INVALID_SOCKET) - throw std::runtime_error("unable to create IPv6 SOCK_DGRAM socket"); -#else - if (_sock <= 0) - throw std::runtime_error("unable to create IPv6 SOCK_DGRAM socket"); -#endif - -#ifdef __WINDOWS__ - yes = TRUE; setsockopt(_sock,IPPROTO_IPV6,IPV6_V6ONLY,(const char *)&yes,sizeof(yes)); - no = FALSE; setsockopt(_sock,SOL_SOCKET,SO_REUSEADDR,(const char *)&no,sizeof(no)); - no = FALSE; setsockopt(_sock,IPPROTO_IPV6,IPV6_DONTFRAG,(const char *)&no,sizeof(no)); -#else - yes = 1; setsockopt(_sock,IPPROTO_IPV6,IPV6_V6ONLY,(void *)&yes,sizeof(yes)); - no = 0; setsockopt(_sock,SOL_SOCKET,SO_REUSEADDR,(void *)&no,sizeof(no)); -#ifdef IP_DONTFRAG - no = 0; setsockopt(_sock,IPPROTO_IP,IP_DONTFRAG,&no,sizeof(no)); -#endif -#ifdef IP_MTU_DISCOVER - no = 0; setsockopt(_sock,IPPROTO_IP,IP_MTU_DISCOVER,&no,sizeof(no)); -#endif -#ifdef IPV6_MTU_DISCOVER - no = 0; setsockopt(_sock,IPPROTO_IPV6,IPV6_MTU_DISCOVER,&no,sizeof(no)); -#endif -#endif - - struct sockaddr_in6 sin6; - memset(&sin6,0,sizeof(sin6)); - sin6.sin6_family = AF_INET6; - sin6.sin6_port = htons(localPort); - if (localOnly) - memcpy(&(sin6.sin6_addr.s6_addr),InetAddress::LO6.rawIpData(),16); - else memcpy(&(sin6.sin6_addr),&in6addr_any,sizeof(struct in6_addr)); - if (::bind(_sock,(const struct sockaddr *)&sin6,sizeof(sin6))) { -#ifdef __WINDOWS__ - ::closesocket(_sock); -#else - ::close(_sock); -#endif - throw std::runtime_error("unable to bind to port"); - } - } else { - _sock = socket(AF_INET,SOCK_DGRAM,0); -#ifdef __WINDOWS__ - if (_sock == INVALID_SOCKET) - throw std::runtime_error("unable to create IPv4 SOCK_DGRAM socket"); -#else - if (_sock <= 0) - throw std::runtime_error("unable to create IPv4 SOCK_DGRAM socket"); -#endif - -#ifdef __WINDOWS__ - no = FALSE; setsockopt(_sock,SOL_SOCKET,SO_REUSEADDR,(const char *)&no,sizeof(no)); - no = FALSE; setsockopt(_sock,IPPROTO_IP,IP_DONTFRAGMENT,(const char *)&no,sizeof(no)); -#else - no = 0; setsockopt(_sock,SOL_SOCKET,SO_REUSEADDR,(void *)&no,sizeof(no)); -#ifdef IP_DONTFRAG - no = 0; setsockopt(_sock,IPPROTO_IP,IP_DONTFRAG,&no,sizeof(no)); -#endif -#ifdef IP_MTU_DISCOVER - no = 0; setsockopt(_sock,IPPROTO_IP,IP_MTU_DISCOVER,&no,sizeof(no)); -#endif -#endif - - struct sockaddr_in sin; - memset(&sin,0,sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_port = htons(localPort); - if (localOnly) - memcpy(&(sin.sin_addr.s_addr),InetAddress::LO4.rawIpData(),4); - else sin.sin_addr.s_addr = INADDR_ANY; - if (::bind(_sock,(const struct sockaddr *)&sin,sizeof(sin))) { -#ifdef __WINDOWS__ - ::closesocket(_sock); -#else - ::close(_sock); -#endif - throw std::runtime_error("unable to bind to port"); - } - } - - _thread = Thread::start(this); -} - -UdpSocket::~UdpSocket() -{ -#ifdef __WINDOWS__ - SOCKET s = _sock; - _sock = INVALID_SOCKET; - if (s != INVALID_SOCKET) { - ::shutdown(s,SD_BOTH); - ::closesocket(s); - } -#else - int s = _sock; - _sock = 0; - if (s > 0) { - ::shutdown(s,SHUT_RDWR); - ::close(s); - } -#endif - Thread::join(_thread); -} - -bool UdpSocket::send(const InetAddress &to,const void *data,unsigned int len,int hopLimit) - throw() -{ - Mutex::Lock _l(_sendLock); - if (to.isV6()) { - if (!_v6) - return false; -#ifdef __WINDOWS__ - DWORD hltmp = (DWORD)hopLimit; - setsockopt(_sock,IPPROTO_IPV6,IPV6_UNICAST_HOPS,(const char *)&hltmp,sizeof(hltmp)); - return ((int)sendto(_sock,(const char *)data,len,0,to.saddr(),to.saddrLen()) == (int)len); -#else - setsockopt(_sock,IPPROTO_IPV6,IPV6_UNICAST_HOPS,&hopLimit,sizeof(hopLimit)); - return ((int)sendto(_sock,data,len,0,to.saddr(),to.saddrLen()) == (int)len); -#endif - } else { - if (_v6) - return false; -#ifdef __WINDOWS__ - DWORD hltmp = (DWORD)hopLimit; - setsockopt(_sock,IPPROTO_IP,IP_TTL,(const char *)&hltmp,sizeof(hltmp)); - return ((int)sendto(_sock,(const char *)data,len,0,to.saddr(),to.saddrLen()) == (int)len); -#else - setsockopt(_sock,IPPROTO_IP,IP_TTL,&hopLimit,sizeof(hopLimit)); - return ((int)sendto(_sock,data,len,0,to.saddr(),to.saddrLen()) == (int)len); -#endif - } -} - -void UdpSocket::threadMain() - throw() -{ - char buf[65536]; - InetAddress from; - socklen_t salen; - int n; - - while (_sock > 0) { - salen = from.saddrSpaceLen(); - n = (int)recvfrom(_sock,buf,sizeof(buf),0,from.saddr(),&salen); - if (n < 0) { - if ((errno != EINTR)&&(errno != ETIMEDOUT)) - break; - } else if (n > 0) { - try { - _packetHandler(this,_arg,from,buf,(unsigned int)n); - } catch ( ... ) {} // should never be thrown from here anyway... - } - } -} - -} // namespace ZeroTier diff --git a/node/UdpSocket_old.hpp b/node/UdpSocket_old.hpp deleted file mode 100644 index b48dc759..00000000 --- a/node/UdpSocket_old.hpp +++ /dev/null @@ -1,118 +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 . - * - * -- - * - * 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 - -#include "Constants.hpp" -#include "Thread.hpp" -#include "InetAddress.hpp" -#include "Mutex.hpp" - -#ifdef __WINDOWS__ -#include -#endif - -namespace ZeroTier { - -/** - * A local UDP socket - * - * The socket listens in a background thread and sends packets to Switch. - */ -class UdpSocket -{ -public: - /** - * Create and bind a local UDP socket - * - * @param localOnly If true, bind to loopback address only - * @param localPort Local port to listen to - * @param ipv6 If true, bind this as an IPv6 socket, otherwise IPv4 - * @param packetHandler Function to call when packets are read - * @param arg First argument (after self) to function - * @throws std::runtime_error Unable to bind - */ - UdpSocket( - bool localOnly, - int localPort, - bool ipv6, - void (*packetHandler)(UdpSocket *,void *,const InetAddress &,const void *,unsigned int), - void *arg) - throw(std::runtime_error); - - ~UdpSocket(); - - /** - * @return Locally bound port - */ - inline int localPort() const throw() { return _localPort; } - - /** - * @return True if this is an IPv6 socket - */ - inline bool v6() const throw() { return _v6; } - - /** - * Send a packet - * - * Attempt to send V6 on a V4 or V4 on a V6 socket will return false. - * - * @param to Destination IP/port - * @param data Data to send - * @param len Length of data in bytes - * @param hopLimit IP hop limit for UDP packet or -1 for max (max: 255) - * @return True if packet successfully sent to link layer - */ - bool send(const InetAddress &to,const void *data,unsigned int len,int hopLimit) - throw(); - - /** - * Thread main method; do not call elsewhere - */ - void threadMain() - throw(); - -private: - Thread _thread; - void (*_packetHandler)(UdpSocket *,void *,const InetAddress &,const void *,unsigned int); - void *_arg; - int _localPort; -#ifdef __WINDOWS__ - volatile SOCKET _sock; -#else - volatile int _sock; -#endif - bool _v6; - Mutex _sendLock; -}; - -} // namespace ZeroTier - -#endif -- cgit v1.2.3