Minor cleanup
[libs/net.git] / source / net / socket.cpp
1 #ifdef _WIN32
2 #include <winsock2.h>
3 #else
4 #include <cerrno>
5 #include <unistd.h>
6 #include <fcntl.h>
7 #include <sys/socket.h>
8 #endif
9 #include <iostream>
10 #include <msp/core/systemerror.h>
11 #include <msp/io/handle_private.h>
12 #include <msp/strings/format.h>
13 #include <msp/time/rawtime_private.h>
14 #include <msp/time/units.h>
15 #include "sockaddr_private.h"
16 #include "socket.h"
17 #include "socket_private.h"
18
19 namespace {
20
21 #ifdef _WIN32
22 class WinSockHelper
23 {
24 public:
25         WinSockHelper()
26         {
27                 WSADATA wsa_data;
28                 int err = WSAStartup(0x0002, &wsa_data);
29                 if(err)
30                         std::cerr<<"Failed to initialize WinSock: "<<err<<'\n';
31         }
32
33         ~WinSockHelper()
34         {
35                 WSACleanup();
36         }
37 };
38
39 WinSockHelper wsh;
40 #endif
41
42 }
43
44 namespace Msp {
45 namespace Net {
46
47 Socket::Socket(const Private &p):
48         priv(new Private),
49         local_addr(0)
50 {
51         mode = IO::M_RDWR;
52
53         priv->handle = p.handle;
54
55         SockAddr::SysAddr sa;
56         getsockname(priv->handle, reinterpret_cast<sockaddr *>(&sa.addr), &sa.size);
57         local_addr = SockAddr::new_from_sys(sa);
58
59 #ifdef _WIN32
60         *priv->event = CreateEvent(0, false, false, 0);
61 #else
62         *priv->event = priv->handle;
63 #endif
64 }
65
66 Socket::Socket(Family af, int type, int proto):
67         priv(new Private),
68         local_addr(0)
69 {
70         mode = IO::M_RDWR;
71
72         priv->handle = socket(family_to_sys(af), type, proto);
73
74 #ifdef _WIN32
75         *priv->event = CreateEvent(0, false, false, 0);
76 #else
77         *priv->event = priv->handle;
78 #endif
79 }
80
81 Socket::~Socket()
82 {
83 #ifdef _WIN32
84         closesocket(priv->handle);
85         CloseHandle(*priv->event);
86 #else
87         ::close(priv->handle);
88 #endif
89
90         delete local_addr;
91         delete priv;
92 }
93
94 void Socket::set_block(bool b)
95 {
96         mode = (mode&~IO::M_NONBLOCK);
97         if(b)
98                 mode = (mode|IO::M_NONBLOCK);
99
100 #ifdef _WIN32
101         u_long flag = !b;
102         ioctlsocket(priv->handle, FIONBIO, &flag);
103 #else
104         int flags = fcntl(priv->handle, F_GETFL);
105         fcntl(priv->handle, F_SETFL, (flags&O_NONBLOCK)|(b?0:O_NONBLOCK));
106 #endif
107 }
108
109 const IO::Handle &Socket::get_event_handle()
110 {
111         return priv->event;
112 }
113
114 void Socket::bind(const SockAddr &addr)
115 {
116         SockAddr::SysAddr sa = addr.to_sys();
117
118         int err = ::bind(priv->handle, reinterpret_cast<sockaddr *>(&sa.addr), sa.size);
119         if(err==-1)
120                 throw system_error("bind");
121
122         delete local_addr;
123         local_addr = addr.copy();
124 }
125
126 const SockAddr &Socket::get_local_address() const
127 {
128         if(local_addr==0)
129                 throw bad_socket_state("not bound");
130         return *local_addr;
131 }
132
133 void Socket::set_timeout(const Time::TimeDelta &timeout)
134 {
135 #ifndef _WIN32
136         timeval tv = Time::rawtime_to_timeval(timeout.raw());
137         priv->set_option(SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(timeval));
138         priv->set_option(SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(timeval));
139 #else
140         DWORD msecs = static_cast<DWORD>(timeout/Time::msec);
141         priv->set_option(SOL_SOCKET, SO_RCVTIMEO, &msecs, sizeof(DWORD));
142         priv->set_option(SOL_SOCKET, SO_SNDTIMEO, &msecs, sizeof(DWORD));
143 #endif
144 }
145
146
147 int Socket::Private::set_option(int level, int optname, const void *optval, socklen_t optlen)
148 {
149 #ifdef _WIN32
150         return setsockopt(handle, level, optname, reinterpret_cast<const char *>(optval), optlen);
151 #else
152         return setsockopt(handle, level, optname, optval, optlen);
153 #endif
154 }
155
156 int Socket::Private::get_option(int level, int optname, void *optval, socklen_t *optlen)
157 {
158 #ifdef _WIN32
159         return getsockopt(handle, level, optname, reinterpret_cast<char *>(optval), optlen);
160 #else
161         return getsockopt(handle, level, optname, optval, optlen);
162 #endif
163 }
164
165 } // namespace Net
166 } // namespace Msp