From 1a0a6755b116214381567804514f01af091e3ca8 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 17 Mar 2014 16:18:44 -0700 Subject: [PATCH] UDP socket implementation. --- node/Socket.hpp | 1 - node/SocketManager.cpp | 18 +++++-- node/UdpSocket.cpp | 112 +++++++++++++++++++++++++++++++++++++++++ node/UdpSocket.hpp | 3 +- 4 files changed, 127 insertions(+), 7 deletions(-) create mode 100644 node/UdpSocket.cpp diff --git a/node/Socket.hpp b/node/Socket.hpp index e8ebfeb73..4eef01b3d 100644 --- a/node/Socket.hpp +++ b/node/Socket.hpp @@ -102,7 +102,6 @@ protected: virtual bool notifyAvailableForRead(const SharedPtr &self,SocketManager *sm) = 0; virtual bool notifyAvailableForWrite(const SharedPtr &self,SocketManager *sm) = 0; -private: #ifdef __WINDOWS__ SOCKET _sock; #else diff --git a/node/SocketManager.cpp b/node/SocketManager.cpp index 36def1e17..825d107e1 100644 --- a/node/SocketManager.cpp +++ b/node/SocketManager.cpp @@ -434,10 +434,20 @@ void SocketManager::poll(unsigned long timeout) } } for(std::vector< SharedPtr >::iterator s(ts.begin());s!=ts.end();++s) { - if (FD_ISSET((*s)->_sock,&rfds)) - (*s)->notifyAvailableForRead(*s,this); - if (FD_ISSET((*s)->_sock,&wfds)) - (*s)->notifyAvailableForWrite(*s,this); + if (FD_ISSET((*s)->_sock,&wfds)) { + if (!(*s)->notifyAvailableForWrite(*s,this)) { + Mutex::Lock _l2(_tcpSockets_m); + _tcpSockets.erase(((TcpSocket *)s->ptr())->_remote); + continue; + } + } + if (FD_ISSET((*s)->_sock,&rfds)) { + if (!(*s)->notifyAvailableForRead(*s,this)) { + Mutex::Lock _l2(_tcpSockets_m); + _tcpSockets.erase(((TcpSocket *)s->ptr())->_remote); + continue; + } + } } } diff --git a/node/UdpSocket.cpp b/node/UdpSocket.cpp new file mode 100644 index 000000000..03041cf31 --- /dev/null +++ b/node/UdpSocket.cpp @@ -0,0 +1,112 @@ +/* + * 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" +#include "UdpSocket.hpp" +#include "SocketManager.hpp" + +#ifdef __WINDOWS__ +#include +#include +#include +#else +#include +#include +#include +#include +#endif + +namespace ZeroTier { + +UdpSocket::~UdpSocket() +{ +#ifdef __WINDOWS__ + ::closesocket(_sock); +#else + ::close(_sock); +#endif +} + +bool UdpSocket::send(const InetAddress &to,const void *msg,unsigned int msglen) +{ + return sendWithHopLimit(to,msg,msglen,0); +} + +bool UdpSocket::sendWithHopLimit(const InetAddress &to,const void *msg,unsigned int msglen,int hopLimit) +{ + if (hopLimit <= 0) + hopLimit = 255; + if (to.isV6()) { +#ifdef __WINDOWS__ + DWORD hltmp = (DWORD)hopLimit; + setsockopt(_sock,IPPROTO_IPV6,IPV6_UNICAST_HOPS,(const char *)&hltmp,sizeof(hltmp)); + return ((int)sendto(_sock,(const char *)msg,msglen,0,to.saddr(),to.saddrLen()) == (int)msglen); +#else + setsockopt(_sock,IPPROTO_IPV6,IPV6_UNICAST_HOPS,&hopLimit,sizeof(hopLimit)); + return ((int)sendto(_sock,msg,msglen,0,to.saddr(),to.saddrLen()) == (int)msglen); +#endif + } else { +#ifdef __WINDOWS__ + DWORD hltmp = (DWORD)hopLimit; + setsockopt(_sock,IPPROTO_IP,IP_TTL,(const char *)&hltmp,sizeof(hltmp)); + return ((int)sendto(_sock,(const char *)msg,msglen,0,to.saddr(),to.saddrLen()) == (int)msglen); +#else + setsockopt(_sock,IPPROTO_IP,IP_TTL,&hopLimit,sizeof(hopLimit)); + return ((int)sendto(_sock,msg,msglen,0,to.saddr(),to.saddrLen()) == (int)msglen); +#endif + } +} + +bool UdpSocket::notifyAvailableForRead(const SharedPtr &self,SocketManager *sm) +{ + Buffer buf; + InetAddress from; + for(;;) { + socklen_t salen = from.saddrSpaceLen(); + int n = (int)recvfrom(_sock,buf.data(),ZT_SOCKET_MAX_MESSAGE_LEN,0,from.saddr(),&salen); + if (n > 0) { + buf.setSize((unsigned int)n); + sm->handleReceivedPacket(self,from,buf); + } else break; + } + return true; +} + +bool UdpSocket::notifyAvailableForWrite(const SharedPtr &self,SocketManager *sm) +{ + return true; +} + +} // namespace ZeroTier diff --git a/node/UdpSocket.hpp b/node/UdpSocket.hpp index 5e0f961a8..9566b9ca5 100644 --- a/node/UdpSocket.hpp +++ b/node/UdpSocket.hpp @@ -28,7 +28,7 @@ #ifndef ZT_UDPSOCKET_HPP #define ZT_UDPSOCKET_HPP -//#include "Socket.hpp" +#include "Socket.hpp" namespace ZeroTier { @@ -44,7 +44,6 @@ class UdpSocket : public Socket public: virtual ~UdpSocket(); - virtual bool send(const InetAddress &to,const void *msg,unsigned int msglen); /**