Browse Source

More new socket I/O work...

Adam Ierymenko 11 years ago
parent
commit
bf5d8de999
3 changed files with 24 additions and 363 deletions
  1. 24 6
      node/SocketManager.cpp
  2. 0 239
      node/UdpSocket_old.cpp
  3. 0 118
      node/UdpSocket_old.hpp

+ 24 - 6
node/SocketManager.cpp

@@ -421,7 +421,7 @@ void SocketManager::poll(unsigned long timeout)
 		_udpV6Socket->notifyAvailableForRead(_udpV6Socket,this);
 		_udpV6Socket->notifyAvailableForRead(_udpV6Socket,this);
 
 
 	std::vector< SharedPtr<Socket> > ts;
 	std::vector< SharedPtr<Socket> > ts;
-	{
+	{ // grab copy of TCP sockets list because _tcpSockets[] might be changed in a handler
 		Mutex::Lock _l2(_tcpSockets_m);
 		Mutex::Lock _l2(_tcpSockets_m);
 		if (_tcpSockets.size()) {
 		if (_tcpSockets.size()) {
 			ts.reserve(_tcpSockets.size());
 			ts.reserve(_tcpSockets.size());
@@ -429,22 +429,40 @@ void SocketManager::poll(unsigned long timeout)
 				if (true) { // TODO: TCP expiration check
 				if (true) { // TODO: TCP expiration check
 					ts.push_back(s->second);
 					ts.push_back(s->second);
 					++s;
 					++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<Socket> >::iterator s(ts.begin());s!=ts.end();++s) {
 	for(std::vector< SharedPtr<Socket> >::iterator s(ts.begin());s!=ts.end();++s) {
 		if (FD_ISSET((*s)->_sock,&wfds)) {
 		if (FD_ISSET((*s)->_sock,&wfds)) {
 			if (!(*s)->notifyAvailableForWrite(*s,this)) {
 			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;
 				continue;
 			}
 			}
 		}
 		}
 		if (FD_ISSET((*s)->_sock,&rfds)) {
 		if (FD_ISSET((*s)->_sock,&rfds)) {
 			if (!(*s)->notifyAvailableForRead(*s,this)) {
 			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;
 				continue;
 			}
 			}
 		}
 		}

+ 0 - 239
node/UdpSocket_old.cpp

@@ -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 <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 <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include "Constants.hpp"
-
-#ifdef __WINDOWS__
-#include <WinSock2.h>
-#include <WS2tcpip.h>
-#include <Windows.h>
-#else
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <unistd.h>
-#include <signal.h>
-#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

+ 0 - 118
node/UdpSocket_old.hpp

@@ -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 <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 <stdexcept>
-
-#include "Constants.hpp"
-#include "Thread.hpp"
-#include "InetAddress.hpp"
-#include "Mutex.hpp"
-
-#ifdef __WINDOWS__
-#include <WinSock2.h>
-#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