From 36af3d92ecb4148a74c14896f5b6a9dcea0c1700 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 12 Aug 2013 16:18:35 -0400 Subject: [PATCH] Windows build work: condition, mutex, thread, udp socket... --- node/Condition.hpp | 66 +++++++++++++++++++++++++++++++++++----------- node/Mutex.hpp | 8 +++--- node/Thread.hpp | 52 +++++++++++++++++++++++++++++++++++- node/UdpSocket.cpp | 47 +++++++++++++++++++++++++++++++-- node/UdpSocket.hpp | 2 ++ 5 files changed, 151 insertions(+), 24 deletions(-) diff --git a/node/Condition.hpp b/node/Condition.hpp index 2ce8c98f3..4b2d32cac 100644 --- a/node/Condition.hpp +++ b/node/Condition.hpp @@ -28,9 +28,57 @@ #ifndef _ZT_CONDITION_HPP #define _ZT_CONDITION_HPP +#include "Constants.hpp" #include "NonCopyable.hpp" -#if defined(__APPLE__) || defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux) +#ifdef __WINDOWS__ + +#include +#include + +#include "Utils.hpp" + +namespace ZeroTier { + +class Condition : NonCopyable +{ +public: + Condition() + throw() + { + _sem = CreateSemaphore(NULL,0,1,NULL); + } + + ~Condition() + { + CloseHandle(_sem); + } + + inline void wait() const + throw() + { + WaitForSingleObject(_sem,INFINITE); + } + + inline void wait(unsigned long ms) const + throw() + { + WaitForSingleObject(_sem,(DWORD)ms); + } + + inline void signal() const + throw() + { + ReleaseSemaphore(_sem,1,NULL); + } + +private: + HANDLE _sem; +}; + +} // namespace ZeroTier + +#else // !__WINDOWS__ #include #include @@ -88,20 +136,6 @@ private: } // namespace ZeroTier -#endif // Apple / Linux - -#ifdef _WIN32 - -#include -#include - -namespace ZeroTier { - -error need windoze; -// On Windows this will probably be implemented via Semaphores - -} // namespace ZeroTier - -#endif // _WIN32 +#endif // !__WINDOWS__ #endif diff --git a/node/Mutex.hpp b/node/Mutex.hpp index 493cc4252..b01302937 100644 --- a/node/Mutex.hpp +++ b/node/Mutex.hpp @@ -28,9 +28,10 @@ #ifndef _ZT_MUTEX_HPP #define _ZT_MUTEX_HPP +#include "Constants.hpp" #include "NonCopyable.hpp" -#if defined(__APPLE__) || defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux) +#ifdef __UNIX_LIKE__ #include #include @@ -112,7 +113,7 @@ private: #endif // Apple / Linux -#ifdef _WIN32 +#ifdef __WINDOWS__ #include #include @@ -157,9 +158,6 @@ public: (const_cast (this))->unlock(); } - /** - * Uses C++ contexts and constructor/destructor to lock/unlock automatically - */ class Lock : NonCopyable { public: diff --git a/node/Thread.hpp b/node/Thread.hpp index ea75297a8..d295fea38 100644 --- a/node/Thread.hpp +++ b/node/Thread.hpp @@ -35,7 +35,57 @@ #ifdef __WINDOWS__ -todo need windows; +#include +#include + +namespace ZeroTier { + +template +static DWORD WINAPI ___zt_threadMain(LPVOID lpParam) +{ + try { + ((C *)lpParam)->threadMain(); + } catch ( ... ) {} + return 0; +} + +class Thread +{ +public: + Thread() + throw() + { + _th = NULL; + } + + template + static inline Thread start(C *instance) + throw(std::runtime_error) + { + Thread t; + t._th = CreateThread(NULL,0,&___zt_threadMain,(LPVOID)instance,0,&t._tid); + if (t._th == NULL) + throw std::runtime_error("CreateThread() failed"); + return t; + } + + static inline void join(const Thread &t) + { + if (t._th != NULL) + WaitForSingleObject(t._th,INFINITE); + } + + static inline void sleep(unsigned long ms) + { + Sleep((DWORD)ms); + } + +private: + HANDLE _th; + DWORD _tid; +}; + +} // namespace ZeroTier #else diff --git a/node/UdpSocket.cpp b/node/UdpSocket.cpp index d1eb87d62..dfe2b11de 100644 --- a/node/UdpSocket.cpp +++ b/node/UdpSocket.cpp @@ -30,13 +30,16 @@ #include #include #include -#include #include -#include +#include #ifdef _WIN32 #include +#include +#include #else +#include +#include #include #include #endif @@ -61,7 +64,11 @@ UdpSocket::UdpSocket( _sock(0), _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"); @@ -71,6 +78,11 @@ UdpSocket::UdpSocket( if (_sock <= 0) throw std::runtime_error("unable to create IPv6 SOCK_DGRAM socket"); +#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 @@ -81,6 +93,7 @@ UdpSocket::UdpSocket( #endif #ifdef IPV6_MTU_DISCOVER no = 0; setsockopt(_sock,IPPROTO_IPV6,IPV6_MTU_DISCOVER,&no,sizeof(no)); +#endif #endif struct sockaddr_in6 sin6; @@ -91,7 +104,11 @@ UdpSocket::UdpSocket( 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 { @@ -99,12 +116,17 @@ UdpSocket::UdpSocket( if (_sock <= 0) throw std::runtime_error("unable to create IPv4 SOCK_DGRAM socket"); +#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; @@ -115,7 +137,11 @@ UdpSocket::UdpSocket( 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"); } } @@ -128,8 +154,13 @@ UdpSocket::~UdpSocket() int s = _sock; _sock = 0; if (s > 0) { +#ifdef __WINDOWS__ + ::shutdown(s,SD_BOTH); + ::closesocket(s); +#else ::shutdown(s,SHUT_RDWR); ::close(s); +#endif } Thread::join(_thread); } @@ -141,13 +172,25 @@ bool UdpSocket::send(const InetAddress &to,const void *data,unsigned int len,int 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 } } diff --git a/node/UdpSocket.hpp b/node/UdpSocket.hpp index c6200eac3..6b7d488ca 100644 --- a/node/UdpSocket.hpp +++ b/node/UdpSocket.hpp @@ -29,6 +29,8 @@ #define _ZT_UDPSOCKET_HPP #include + +#include "Constants.hpp" #include "Thread.hpp" #include "InetAddress.hpp" #include "Mutex.hpp"