Move most platform-specific code into overlay directories
authorMikko Rasa <tdb@tdb.fi>
Sun, 25 Sep 2016 22:28:16 +0000 (01:28 +0300)
committerMikko Rasa <tdb@tdb.fi>
Sun, 25 Sep 2016 22:28:16 +0000 (01:28 +0300)
Unix socket addresses can now be constructed on Windows, but can't be
actually used with sockets.

23 files changed:
Build
source/net/clientsocket.cpp
source/net/constants.cpp
source/net/datagramsocket.cpp
source/net/inet.cpp
source/net/inet6.cpp
source/net/resolve.cpp
source/net/sockaddr.cpp
source/net/sockaddr_private.h
source/net/socket.cpp
source/net/socket.h
source/net/socket_private.h
source/net/streamserversocket.cpp
source/net/streamsocket.cpp
source/net/unix.cpp
source/net/unix/platform_api.h [new file with mode: 0644]
source/net/unix/socket.cpp [new file with mode: 0644]
source/net/unix/socket_platform.h [new file with mode: 0644]
source/net/unix/unix.cpp [new file with mode: 0644]
source/net/windows/platform_api.h [new file with mode: 0644]
source/net/windows/socket.cpp [new file with mode: 0644]
source/net/windows/socket_platform.h [new file with mode: 0644]
source/net/windows/unix.cpp [new file with mode: 0644]

diff --git a/Build b/Build
index 7e4a693b8b24858380839d03616bcb1c7c8039f0..404ddbf42f6d8eb5a4426d17105c344f3b3a5ab3 100644 (file)
--- a/Build
+++ b/Build
@@ -14,6 +14,14 @@ package "mspnet"
        {
                source "source/net";
                source "source/http";
+               if_arch "windows"
+               {
+                       overlay "windows";
+               };
+               if_arch "!windows"
+               {
+                       overlay "unix";
+               };
                install true;
                install_map
                {
index cbf18e593bdadc458ed862ab9aba326025df0bd1..04d07000a7bb1286c105a1697fdc71f0bc880901 100644 (file)
@@ -1,9 +1,4 @@
-#ifdef _WIN32
-#include <winsock2.h>
-#else
-#include <cerrno>
-#include <sys/socket.h>
-#endif
+#include "platform_api.h"
 #include <msp/core/systemerror.h>
 #include "clientsocket.h"
 #include "socket_private.h"
@@ -74,16 +69,7 @@ unsigned ClientSocket::do_write(const char *buf, unsigned size)
        if(size==0)
                return 0;
 
-       int ret = ::send(priv->handle, buf, size, 0);
-       if(ret<0)
-       {
-               if(errno==EAGAIN)
-                       return 0;
-               else
-                       throw system_error("send");
-       }
-
-       return ret;
+       return check_sys_error(::send(priv->handle, buf, size, 0), "send");
 }
 
 unsigned ClientSocket::do_read(char *buf, unsigned size)
@@ -95,19 +81,12 @@ unsigned ClientSocket::do_read(char *buf, unsigned size)
        if(size==0)
                return 0;
 
-       int ret = ::recv(priv->handle, buf, size, 0);
-       if(ret<0)
-       {
-               if(errno==EAGAIN)
-                       return 0;
-               else
-                       throw system_error("recv");
-       }
-       else if(ret==0 && !eof_flag)
+       unsigned ret = check_sys_error(::recv(priv->handle, buf, size, 0), "recv");
+       if(ret==0 && !eof_flag)
        {
                eof_flag = true;
                signal_end_of_file.emit();
-               set_events(IO::P_NONE);
+               set_socket_events(S_NONE);
        }
 
        return ret;
index c98945c21123a70301f2273e96658d42ea1bcb83..5088e51953fcd5046b4cdbacb10ef496dd8a3571 100644 (file)
@@ -1,9 +1,5 @@
 #include <stdexcept>
-#ifdef _WIN32
-#include <winsock2.h>
-#else
-#include <sys/socket.h>
-#endif
+#include "platform_api.h"
 #include "constants.h"
 
 using namespace std;
index 0e405d6f0cb7972fed62e418d447a2dc4c303b31..fe01ef5c6a6ffc7e2419750679bfaed347238fd3 100644 (file)
@@ -1,7 +1,4 @@
-#ifdef _WIN32
-#include <winsock2.h>
-#endif
-#include <cerrno>
+#include "platform_api.h"
 #include <msp/core/systemerror.h>
 #include <msp/io/handle_private.h>
 #include <msp/strings/format.h>
@@ -15,25 +12,13 @@ namespace Net {
 DatagramSocket::DatagramSocket(Family f, int p):
        ClientSocket(f, SOCK_DGRAM, p)
 {
-#ifdef _WIN32
-       WSAEventSelect(priv->handle, *priv->event, FD_READ|FD_CLOSE);
-#endif
-       set_events(IO::P_INPUT);
+       set_socket_events(S_INPUT);
 }
 
 bool DatagramSocket::connect(const SockAddr &addr)
 {
        SockAddr::SysAddr sa = addr.to_sys();
-
-       int err = ::connect(priv->handle, reinterpret_cast<sockaddr *>(&sa.addr), sa.size);
-       if(err==-1)
-       {
-#ifdef _WIN32
-               throw system_error("connect", WSAGetLastError());
-#else
-               throw system_error("connect");
-#endif
-       }
+       check_sys_connect_error(::connect(priv->handle, reinterpret_cast<const sockaddr *>(&sa.addr), sa.size));
 
        delete peer_addr;
        peer_addr = addr.copy();
@@ -54,23 +39,7 @@ unsigned DatagramSocket::sendto(const char *buf, unsigned size, const SockAddr &
                return 0;
 
        SockAddr::SysAddr sa = addr.to_sys();
-
-       int ret = ::sendto(priv->handle, buf, size, 0, reinterpret_cast<sockaddr *>(&sa.addr), sa.size);
-       if(ret<0)
-       {
-               if(errno==EAGAIN)
-                       return 0;
-               else
-               {
-#ifdef _WIN32
-                       throw system_error("sendto", WSAGetLastError());
-#else
-                       throw system_error("sendto");
-#endif
-               }
-       }
-
-       return ret;
+       return check_sys_error(::sendto(priv->handle, buf, size, 0, reinterpret_cast<const sockaddr *>(&sa.addr), sa.size), "sendto");
 }
 
 unsigned DatagramSocket::recvfrom(char *buf, unsigned size, SockAddr *&from_addr)
@@ -79,21 +48,7 @@ unsigned DatagramSocket::recvfrom(char *buf, unsigned size, SockAddr *&from_addr
                return 0;
 
        SockAddr::SysAddr sa;
-       int ret = ::recvfrom(priv->handle, buf, size, 0, reinterpret_cast<sockaddr *>(&sa.addr), &sa.size);
-       if(ret<0)
-       {
-               if(errno==EAGAIN)
-                       return 0;
-               else
-               {
-#ifdef _WIN32
-                       throw system_error("recvfrom", WSAGetLastError());
-#else
-                       throw system_error("recvfrom");
-#endif
-               }
-       }
-
+       unsigned ret = check_sys_error(::recvfrom(priv->handle, buf, size, 0, reinterpret_cast<sockaddr *>(&sa.addr), &sa.size), "recvfrom");
        from_addr = SockAddr::new_from_sys(sa);
 
        return ret;
index f428492f04bb4e7817af30aa4230fb3e59a9e710..8e75cd89dfb1eb930b3e55a0217a93e42ab03e15 100644 (file)
@@ -1,8 +1,4 @@
-#ifdef _WIN32
-#include <winsock2.h>
-#else
-#include <netinet/in.h>
-#endif
+#include "platform_api.h"
 #include <msp/strings/format.h>
 #include "inet.h"
 #include "sockaddr_private.h"
index f33ed182305882d4753d2365116d31e4163a7263..77d757082379f70e713d7587bbf0d61df675ff75 100644 (file)
@@ -1,9 +1,4 @@
-#ifdef _WIN32
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#else
-#include <netinet/in.h>
-#endif
+#include "platform_api.h"
 #include <msp/strings/format.h>
 #include "inet6.h"
 #include "sockaddr_private.h"
index 6de883895eeb05f4b88a5cdf2cabc66b483274ac..10e8c656797fedfdd685b2edb48ad5f20a217996 100644 (file)
@@ -1,9 +1,4 @@
-#ifdef _WIN32
-#define _WIN32_WINNT 0x0501
-#include <ws2tcpip.h>
-#else
-#include <netdb.h>
-#endif
+#include "platform_api.h"
 #include <msp/core/systemerror.h>
 #include <msp/strings/format.h>
 #include "sockaddr_private.h"
index e9b14333b51586c69727b038a384bb4bec5e1fd3..db436fe17227218e193e71f7ad28b18cfac4cab0 100644 (file)
@@ -1,4 +1,5 @@
 #include <stdexcept>
+#include "platform_api.h"
 #include "inet.h"
 #include "inet6.h"
 #include "sockaddr_private.h"
index 4aa9231333fc854d7b5c445fbecc86b6279f23f1..909ef9255853e6a65f9669a8d688c1b75dba45de 100644 (file)
@@ -1,12 +1,12 @@
 #ifndef MSP_NET_SOCKADDR_PRIVATE_H_
 #define MSP_NET_SOCKADDR_PRIVATE_H_
 
-#ifdef _WIN32
-#include <winsock2.h>
-#else
-#include <sys/socket.h>
+#ifndef MSP_NET_PLATFORM_API_H_
+#error platform_api.h must be included to use private headers
 #endif
+
 #include "sockaddr.h"
+#include "socket_platform.h"
 
 namespace Msp {
 namespace Net {
@@ -14,11 +14,7 @@ namespace Net {
 struct SockAddr::SysAddr
 {
        struct sockaddr_storage addr;
-#ifdef _WIN32
-       int size;
-#else
        socklen_t size;
-#endif
 
        SysAddr();
 };
index 031d077c44dcc194a095455d06dde3def3a62ccd..e8e5eaf6275eddb27634a0d473377bed18570d8b 100644 (file)
@@ -1,46 +1,10 @@
-#ifdef _WIN32
-#include <winsock2.h>
-#else
-#include <cerrno>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/socket.h>
-#endif
-#include <iostream>
+#include "platform_api.h"
 #include <msp/core/systemerror.h>
 #include <msp/io/handle_private.h>
-#include <msp/strings/format.h>
-#include <msp/time/rawtime_private.h>
-#include <msp/time/units.h>
 #include "sockaddr_private.h"
 #include "socket.h"
 #include "socket_private.h"
 
-namespace {
-
-#ifdef _WIN32
-class WinSockHelper
-{
-public:
-       WinSockHelper()
-       {
-               WSADATA wsa_data;
-               int err = WSAStartup(0x0002, &wsa_data);
-               if(err)
-                       std::cerr<<"Failed to initialize WinSock: "<<err<<'\n';
-       }
-
-       ~WinSockHelper()
-       {
-               WSACleanup();
-       }
-};
-
-WinSockHelper wsh;
-#endif
-
-}
-
 namespace Msp {
 namespace Net {
 
@@ -56,11 +20,7 @@ Socket::Socket(const Private &p):
        getsockname(priv->handle, reinterpret_cast<sockaddr *>(&sa.addr), &sa.size);
        local_addr = SockAddr::new_from_sys(sa);
 
-#ifdef _WIN32
-       *priv->event = CreateEvent(0, false, false, 0);
-#else
-       *priv->event = priv->handle;
-#endif
+       platform_init();
 }
 
 Socket::Socket(Family af, int type, int proto):
@@ -71,21 +31,12 @@ Socket::Socket(Family af, int type, int proto):
 
        priv->handle = socket(family_to_sys(af), type, proto);
 
-#ifdef _WIN32
-       *priv->event = CreateEvent(0, false, false, 0);
-#else
-       *priv->event = priv->handle;
-#endif
+       platform_init();
 }
 
 Socket::~Socket()
 {
-#ifdef _WIN32
-       closesocket(priv->handle);
-       CloseHandle(*priv->event);
-#else
-       ::close(priv->handle);
-#endif
+       platform_cleanup();
 
        delete local_addr;
        delete priv;
@@ -97,13 +48,7 @@ void Socket::set_block(bool b)
        if(b)
                mode = (mode|IO::M_NONBLOCK);
 
-#ifdef _WIN32
-       u_long flag = !b;
-       ioctlsocket(priv->handle, FIONBIO, &flag);
-#else
-       int flags = fcntl(priv->handle, F_GETFL);
-       fcntl(priv->handle, F_SETFL, (flags&O_NONBLOCK)|(b?0:O_NONBLOCK));
-#endif
+       priv->set_block(b);
 }
 
 const IO::Handle &Socket::get_event_handle()
@@ -130,36 +75,16 @@ const SockAddr &Socket::get_local_address() const
        return *local_addr;
 }
 
-void Socket::set_timeout(const Time::TimeDelta &timeout)
-{
-#ifndef _WIN32
-       timeval tv = Time::rawtime_to_timeval(timeout.raw());
-       priv->set_option(SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(timeval));
-       priv->set_option(SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(timeval));
-#else
-       DWORD msecs = static_cast<DWORD>(timeout/Time::msec);
-       priv->set_option(SOL_SOCKET, SO_RCVTIMEO, &msecs, sizeof(DWORD));
-       priv->set_option(SOL_SOCKET, SO_SNDTIMEO, &msecs, sizeof(DWORD));
-#endif
-}
-
-
-int Socket::Private::set_option(int level, int optname, const void *optval, socklen_t optlen)
-{
-#ifdef _WIN32
-       return setsockopt(handle, level, optname, reinterpret_cast<const char *>(optval), optlen);
-#else
-       return setsockopt(handle, level, optname, optval, optlen);
-#endif
-}
-
-int Socket::Private::get_option(int level, int optname, void *optval, socklen_t *optlen)
+void Socket::set_socket_events(unsigned e)
 {
-#ifdef _WIN32
-       return getsockopt(handle, level, optname, reinterpret_cast<char *>(optval), optlen);
-#else
-       return getsockopt(handle, level, optname, optval, optlen);
-#endif
+       IO::PollEvent pe = static_cast<IO::PollEvent>(e&4095);
+       if(e&S_CONNECT)
+               pe = pe|IO::P_OUTPUT;
+       if(e&S_ACCEPT)
+               pe = pe|IO::P_INPUT;
+
+       set_platform_events(e);
+       set_events(pe);
 }
 
 } // namespace Net
index c830930d6d54b6787357e73f92e48a17882d1168..1f60f9bb2276942ce31e7eaf69612e4e67641f02 100644 (file)
@@ -20,6 +20,14 @@ public:
 class Socket: public IO::EventObject
 {
 protected:
+       enum SocketEvent
+       {
+               S_NONE = IO::P_NONE,
+               S_INPUT = IO::P_INPUT,
+               S_CONNECT = 4096,
+               S_ACCEPT = 8192
+       };
+
        struct Private;
 
        Private *priv;
@@ -27,6 +35,9 @@ protected:
 
        Socket(const Private &);
        Socket(Family, int, int);
+private:
+       void platform_init();
+       void platform_cleanup();
 public:
        ~Socket();
 
@@ -40,6 +51,9 @@ public:
        const SockAddr &get_local_address() const;
 
        void set_timeout(const Time::TimeDelta &);
+protected:
+       void set_socket_events(unsigned);
+       void set_platform_events(unsigned);
 };
 
 } // namespace Net
index 995ead0f3951b88bff1462d1cea515b97de10278..742877b4516514b718a623c0185a025a11ddb66f 100644 (file)
@@ -1,32 +1,34 @@
 #ifndef MSP_NET_SOCKET_PRIVATE_H_
 #define MSP_NET_SOCKET_PRIVATE_H_
 
+#ifndef MSP_NET_PLATFORM_API_H_
+#error platform_api.h must be included to use private headers
+#endif
+
 #include <msp/io/handle.h>
+#include "sockaddr.h"
 #include "socket.h"
+#include "socket_platform.h"
 
 namespace Msp {
 namespace Net {
 
-#ifdef _WIN32
-typedef int socklen_t;
-#endif
-
 struct Socket::Private
 {
-#ifdef _WIN32
-       SOCKET handle;
-#else
-       int handle;
-#endif
+       SocketHandle handle;
 
        /* On POSIX platforms this is the same as the handle.  This might seem
        strange but it allows the same syntax on both POSIX and Windows. */
        IO::Handle event;
 
+       void set_block(bool);
        int set_option(int, int, const void *, socklen_t);
        int get_option(int, int, void *, socklen_t *);
 };
 
+unsigned check_sys_error(int, const char *);
+bool check_sys_connect_error(int);
+
 } // namespace Net
 } // namespace Msp
 
index e408dcedfb6ae6c2506e3fd81565c7da7d04f947..9900e5d93953576d0b6140bd0629222978adead7 100644 (file)
@@ -1,7 +1,4 @@
-#ifdef _WIN32
-#include <winsock2.h>
-#endif
-#include <cerrno>
+#include "platform_api.h"
 #include <msp/core/refptr.h>
 #include <msp/core/systemerror.h>
 #include <msp/io/handle_private.h>
@@ -29,10 +26,7 @@ void StreamServerSocket::listen(const SockAddr &addr, unsigned backlog)
        if(err==-1)
                throw system_error("listen");
 
-#ifdef _WIN32
-       WSAEventSelect(priv->handle, *priv->event, FD_ACCEPT);
-#endif
-       set_events(IO::P_INPUT);
+       set_socket_events(S_ACCEPT);
 
        listening = true;
 }
index da5069cee21603110213dcfd3bf6ecc3904ae2ab..11887d398c4b09a894c088fb4b3656cd49bf8c45 100644 (file)
@@ -1,9 +1,4 @@
-#ifdef _WIN32
-#include <winsock2.h>
-#else
-#include <sys/socket.h>
-#endif
-#include <cerrno>
+#include "platform_api.h"
 #include <msp/core/systemerror.h>
 #include <msp/io/handle_private.h>
 #include <msp/io/poll.h>
@@ -18,10 +13,7 @@ namespace Net {
 StreamSocket::StreamSocket(const Private &p, const SockAddr &paddr):
        ClientSocket(p, paddr)
 {
-#ifdef _WIN32
-       WSAEventSelect(priv->handle, *priv->event, FD_READ|FD_CLOSE);
-#endif
-       set_events(IO::P_INPUT);
+       set_socket_events(S_INPUT);
 }
 
 StreamSocket::StreamSocket(Family af, int proto):
@@ -34,33 +26,13 @@ bool StreamSocket::connect(const SockAddr &addr)
                throw bad_socket_state("already connected");
 
        SockAddr::SysAddr sa = addr.to_sys();
-
-       int err = ::connect(priv->handle, reinterpret_cast<sockaddr *>(&sa.addr), sa.size);
-#ifdef _WIN32
-       if(err==SOCKET_ERROR)
+       int err = ::connect(priv->handle, reinterpret_cast<const sockaddr *>(&sa.addr), sa.size);
+       bool finished = check_sys_connect_error(err);
+       if(!finished)
        {
-               int err_code = WSAGetLastError();
-               if(err_code==WSAEWOULDBLOCK)
-               {
-                       connecting = true;
-                       WSAEventSelect(priv->handle, *priv->event, FD_CONNECT);
-                       set_events(IO::P_OUTPUT);
-               }
-               else
-                       throw system_error("connect", err_code);
-       }
-#else
-       if(err==-1)
-       {
-               if(errno==EINPROGRESS)
-               {
-                       connecting = true;
-                       set_events(IO::P_OUTPUT);
-               }
-               else
-                       throw system_error("connect");
+               connecting = true;
+               set_socket_events(S_CONNECT);
        }
-#endif
 
        delete peer_addr;
        peer_addr = addr.copy();
@@ -70,13 +42,10 @@ bool StreamSocket::connect(const SockAddr &addr)
        getsockname(priv->handle, reinterpret_cast<sockaddr *>(&lsa.addr), &lsa.size);
        local_addr = SockAddr::new_from_sys(lsa);
 
-       if(err==0)
+       if(finished)
        {
                connected = true;
-#ifdef _WIN32
-               WSAEventSelect(priv->handle, *priv->event, FD_READ|FD_CLOSE);
-#endif
-               set_events(IO::P_INPUT);
+               set_socket_events(S_INPUT);
                signal_connect_finished.emit(0);
        }
 
@@ -99,18 +68,11 @@ bool StreamSocket::poll_connect(const Time::TimeDelta &timeout)
 
                if(err!=0)
                {
-                       set_events(IO::P_NONE);
-#ifdef _WIN32
-                       throw system_error("connect", WSAGetLastError());
-#else
-                       throw system_error("connect");
-#endif
+                       set_socket_events(S_NONE);
+                       throw system_error("connect", err);
                }
 
-#ifdef _WIN32
-               WSAEventSelect(priv->handle, *priv->event, FD_READ|FD_CLOSE);
-#endif
-               set_events(IO::P_INPUT);
+               set_socket_events(S_INPUT);
 
                connected = true;
        }
@@ -142,10 +104,7 @@ void StreamSocket::on_event(IO::PollEvent ev)
                        peer_addr = 0;
                }
 
-#ifdef _WIN32
-               WSAEventSelect(priv->handle, *priv->event, FD_READ|FD_CLOSE);
-#endif
-               set_events((err==0) ? IO::P_INPUT : IO::P_NONE);
+               set_socket_events((err==0) ? S_INPUT : S_NONE);
        }
 }
 
index 9d8cf2780af0da1d99eb177136944b30659730bb..fe00020988bf92c1b915b7e6a7ef399ad7e9c4af 100644 (file)
@@ -1,8 +1,3 @@
-#include <stdexcept>
-#ifndef _WIN32
-#include <sys/un.h>
-#endif
-#include "sockaddr_private.h"
 #include "unix.h"
 
 using namespace std;
@@ -13,60 +8,6 @@ namespace Net {
 UnixAddr::UnixAddr():
        abstract(false)
 {
-#ifdef _WIN32
-       throw logic_error("no unix sockets on windows");
-#endif
-}
-
-UnixAddr::UnixAddr(const SysAddr &sa):
-       abstract(false)
-{
-#ifdef _WIN32
-       (void)sa;
-       throw logic_error("no unix sockets on windows");
-#else
-       const sockaddr_un &sau = reinterpret_cast<const sockaddr_un &>(sa.addr);
-       if(static_cast<size_t>(sa.size)>sizeof(sa_family_t))
-       {
-               abstract = (sau.sun_path[0]==0);
-               path.assign(sau.sun_path+abstract, sa.size-sizeof(sa_family_t)-abstract);
-       }
-#endif
-}
-
-UnixAddr::UnixAddr(const string &p, bool a):
-       path(p),
-       abstract(a)
-{
-#ifdef _WIN32
-       throw logic_error("no unix sockets on windows");
-#else
-       if(sizeof(sa_family_t)+path.size()+1>sizeof(sockaddr_storage))
-               throw invalid_argument("UnixAddr");
-#endif
-}
-
-SockAddr::SysAddr UnixAddr::to_sys() const
-{
-       SysAddr sa;
-#ifndef _WIN32
-       sa.size = sizeof(sa_family_t);
-       if(!path.empty())
-               sa.size += path.size()+1;
-
-       sockaddr_un &sau = reinterpret_cast<sockaddr_un &>(sa.addr);
-       sau.sun_family = AF_UNIX;
-       if(!path.empty())
-       {
-               if(abstract)
-                       sau.sun_path[0] = 0;
-               std::copy(path.begin(), path.end(), sau.sun_path+abstract);
-               if(!abstract)
-                       sau.sun_path[path.size()] = 0;
-       }
-#endif
-
-       return sa;
 }
 
 string UnixAddr::str() const
diff --git a/source/net/unix/platform_api.h b/source/net/unix/platform_api.h
new file mode 100644 (file)
index 0000000..016545f
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef MSP_NET_PLATFORM_API_H_
+#define MSP_NET_PLATFORM_API_H_
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#endif
diff --git a/source/net/unix/socket.cpp b/source/net/unix/socket.cpp
new file mode 100644 (file)
index 0000000..02ef7c3
--- /dev/null
@@ -0,0 +1,81 @@
+#include <cerrno>
+#include <unistd.h>
+#include <fcntl.h>
+#include "platform_api.h"
+#include <msp/core/systemerror.h>
+#include <msp/io/handle_private.h>
+#include <msp/time/rawtime_private.h>
+#include "sockaddr_private.h"
+#include "socket.h"
+#include "socket_private.h"
+
+namespace Msp {
+namespace Net {
+
+void Socket::platform_init()
+{
+       *priv->event = priv->handle;
+}
+
+void Socket::platform_cleanup()
+{
+       close(priv->handle);
+}
+
+void Socket::set_timeout(const Time::TimeDelta &timeout)
+{
+       timeval tv = Time::rawtime_to_timeval(timeout.raw());
+       priv->set_option(SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(timeval));
+       priv->set_option(SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(timeval));
+}
+
+void Socket::set_platform_events(unsigned)
+{
+}
+
+
+void Socket::Private::set_block(bool b)
+{
+       int flags = fcntl(handle, F_GETFL);
+       fcntl(handle, F_SETFL, (flags&O_NONBLOCK)|(b?0:O_NONBLOCK));
+}
+
+int Socket::Private::set_option(int level, int optname, const void *optval, socklen_t optlen)
+{
+       return setsockopt(handle, level, optname, optval, optlen);
+}
+
+int Socket::Private::get_option(int level, int optname, void *optval, socklen_t *optlen)
+{
+       return getsockopt(handle, level, optname, optval, optlen);
+}
+
+
+unsigned check_sys_error(int ret, const char *func)
+{
+       if(ret<0)
+       {
+               if(errno==EAGAIN)
+                       return 0;
+               else
+                       throw system_error(func);
+       }
+
+       return ret;
+}
+
+bool check_sys_connect_error(int ret)
+{
+       if(ret<0)
+       {
+               if(errno==EINPROGRESS)
+                       return false;
+               else
+                       throw system_error("connect");
+       }
+
+       return true;
+}
+
+} // namespace Net
+} // namespace Msp
diff --git a/source/net/unix/socket_platform.h b/source/net/unix/socket_platform.h
new file mode 100644 (file)
index 0000000..73c2fe0
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef MSP_NET_SOCKET_PLATFORM_H_
+#define MSP_NET_SOCKET_PLATFORM_H_
+
+namespace Msp {
+namespace Net {
+
+typedef int SocketHandle;
+
+} // namespace Net
+} // namespace Msp
+
+#endif
diff --git a/source/net/unix/unix.cpp b/source/net/unix/unix.cpp
new file mode 100644 (file)
index 0000000..6bb3436
--- /dev/null
@@ -0,0 +1,53 @@
+#include <stdexcept>
+#include <sys/un.h>
+#include "platform_api.h"
+#include "sockaddr_private.h"
+#include "unix.h"
+
+using namespace std;
+
+namespace Msp {
+namespace Net {
+
+UnixAddr::UnixAddr(const SysAddr &sa):
+       abstract(false)
+{
+       const sockaddr_un &sau = reinterpret_cast<const sockaddr_un &>(sa.addr);
+       if(static_cast<size_t>(sa.size)>sizeof(sa_family_t))
+       {
+               abstract = (sau.sun_path[0]==0);
+               path.assign(sau.sun_path+abstract, sa.size-sizeof(sa_family_t)-abstract);
+       }
+}
+
+UnixAddr::UnixAddr(const string &p, bool a):
+       path(p),
+       abstract(a)
+{
+       if(sizeof(sa_family_t)+path.size()+1>sizeof(sockaddr_storage))
+               throw invalid_argument("UnixAddr");
+}
+
+SockAddr::SysAddr UnixAddr::to_sys() const
+{
+       SysAddr sa;
+       sa.size = sizeof(sa_family_t);
+       if(!path.empty())
+               sa.size += path.size()+1;
+
+       sockaddr_un &sau = reinterpret_cast<sockaddr_un &>(sa.addr);
+       sau.sun_family = AF_UNIX;
+       if(!path.empty())
+       {
+               if(abstract)
+                       sau.sun_path[0] = 0;
+               std::copy(path.begin(), path.end(), sau.sun_path+abstract);
+               if(!abstract)
+                       sau.sun_path[path.size()] = 0;
+       }
+
+       return sa;
+}
+
+} // namespace Net
+} // namespace Msp
diff --git a/source/net/windows/platform_api.h b/source/net/windows/platform_api.h
new file mode 100644 (file)
index 0000000..b2ba90c
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef MSP_NET_PLATFORM_API_H_
+#define MSP_NET_PLATFORM_API_H_
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <windows.h>
+
+#endif
diff --git a/source/net/windows/socket.cpp b/source/net/windows/socket.cpp
new file mode 100644 (file)
index 0000000..f4fab44
--- /dev/null
@@ -0,0 +1,113 @@
+#include <iostream>
+#include "platform_api.h"
+#include <msp/core/systemerror.h>
+#include <msp/io/handle_private.h>
+#include "sockaddr_private.h"
+#include "socket.h"
+#include "socket_private.h"
+
+namespace {
+
+class WinSockHelper
+{
+public:
+       WinSockHelper()
+       {
+               WSADATA wsa_data;
+               int err = WSAStartup(0x0002, &wsa_data);
+               if(err)
+                       std::cerr<<"Failed to initialize WinSock: "<<err<<'\n';
+       }
+
+       ~WinSockHelper()
+       {
+               WSACleanup();
+       }
+};
+
+WinSockHelper wsh;
+
+}
+
+
+namespace Msp {
+namespace Net {
+
+void Socket::platform_init()
+{
+       *priv->event = CreateEvent(0, false, false, 0);
+}
+
+void Socket::platform_cleanup()
+{
+       closesocket(priv->handle);
+       CloseHandle(*priv->event);
+}
+
+void Socket::set_timeout(const Time::TimeDelta &timeout)
+{
+       DWORD msecs = static_cast<DWORD>(timeout/Time::msec);
+       priv->set_option(SOL_SOCKET, SO_RCVTIMEO, &msecs, sizeof(DWORD));
+       priv->set_option(SOL_SOCKET, SO_SNDTIMEO, &msecs, sizeof(DWORD));
+}
+
+void Socket::set_platform_events(unsigned e)
+{
+       long ws_events = 0;
+       if(e&S_INPUT)
+               ws_events |= FD_READ|FD_CLOSE;
+       if(e&S_CONNECT)
+               ws_events |= FD_CONNECT;
+       if(e&S_ACCEPT)
+               ws_events |= FD_ACCEPT;
+       WSAEventSelect(priv->handle, *priv->event, ws_events);
+}
+
+
+void Socket::Private::set_block(bool b)
+{
+       u_long flag = !b;
+       ioctlsocket(handle, FIONBIO, &flag);
+}
+
+int Socket::Private::set_option(int level, int optname, const void *optval, socklen_t optlen)
+{
+       return setsockopt(handle, level, optname, reinterpret_cast<const char *>(optval), optlen);
+}
+
+int Socket::Private::get_option(int level, int optname, void *optval, socklen_t *optlen)
+{
+       return getsockopt(handle, level, optname, reinterpret_cast<char *>(optval), optlen);
+}
+
+
+unsigned check_sys_error(int ret, const char *func)
+{
+       if(ret<0)
+       {
+               int err_code = WSAGetLastError();
+               if(err_code==WSAEWOULDBLOCK)
+                       return 0;
+               else
+                       throw system_error(func, err_code);
+       }
+
+       return ret;
+}
+
+bool check_sys_connect_error(int ret)
+{
+       if(ret==SOCKET_ERROR)
+       {
+               int err_code = WSAGetLastError();
+               if(err_code==WSAEWOULDBLOCK)
+                       return false;
+               else
+                       throw system_error("connect", err_code);
+       }
+
+       return true;
+}
+
+} // namespace Net
+} // namespace Msp
diff --git a/source/net/windows/socket_platform.h b/source/net/windows/socket_platform.h
new file mode 100644 (file)
index 0000000..5168579
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef MSP_NET_SOCKET_PLATFORM_H_
+#define MSP_NET_SOCKET_PLATFORM_H_
+
+namespace Msp {
+namespace Net {
+
+typedef int socklen_t;
+typedef SOCKET SocketHandle;
+
+} // namespace Net
+} // namespace Msp
+
+#endif
diff --git a/source/net/windows/unix.cpp b/source/net/windows/unix.cpp
new file mode 100644 (file)
index 0000000..2aa8857
--- /dev/null
@@ -0,0 +1,29 @@
+#include <stdexcept>
+#include "platform_api.h"
+#include "sockaddr_private.h"
+#include "unix.h"
+
+using namespace std;
+
+namespace Msp {
+namespace Net {
+
+UnixAddr::UnixAddr(const SysAddr &):
+       abstract(false)
+{
+       throw logic_error("AF_UNIX not supported");
+}
+
+UnixAddr::UnixAddr(const string &p, bool a):
+       path(p),
+       abstract(a)
+{
+}
+
+SockAddr::SysAddr UnixAddr::to_sys() const
+{
+       throw logic_error("AF_UNIX not supported");
+}
+
+} // namespace Net
+} // namespace Msp