]> git.tdb.fi Git - libs/net.git/blob - source/net/socket.cpp
7c162178eb1a822c43d9167d741bba67131674f0
[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
115 void Socket::bind(const SockAddr &addr)
116 {
117         SockAddr::SysAddr sa = addr.to_sys();
118
119         int err = ::bind(priv->handle, reinterpret_cast<sockaddr *>(&sa.addr), sa.size);
120         if(err==-1)
121                 throw system_error("bind");
122
123         delete local_addr;
124         local_addr = addr.copy();
125 }
126
127 const SockAddr &Socket::get_local_address() const
128 {
129         if(local_addr==0)
130                 throw bad_socket_state("not bound");
131         return *local_addr;
132 }
133
134 void Socket::set_timeout(const Time::TimeDelta &timeout)
135 {
136 #ifndef WIN32
137         timeval tv = Time::rawtime_to_timeval(timeout.raw());
138         priv->set_option(SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(timeval));
139         priv->set_option(SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(timeval));
140 #else
141         DWORD msecs = static_cast<DWORD>(timeout/Time::msec);
142         priv->set_option(SOL_SOCKET, SO_RCVTIMEO, &msecs, sizeof(DWORD));
143         priv->set_option(SOL_SOCKET, SO_SNDTIMEO, &msecs, sizeof(DWORD));
144 #endif
145 }
146
147
148 int Socket::Private::set_option(int level, int optname, const void *optval, socklen_t optlen)
149 {
150 #ifdef WIN32
151         return setsockopt(handle, level, optname, reinterpret_cast<const char *>(optval), optlen);
152 #else
153         return setsockopt(handle, level, optname, optval, optlen);
154 #endif
155 }
156
157 int Socket::Private::get_option(int level, int optname, void *optval, socklen_t *optlen)
158 {
159 #ifdef WIN32
160         return getsockopt(handle, level, optname, reinterpret_cast<char *>(optval), optlen);
161 #else
162         return getsockopt(handle, level, optname, optval, optlen);
163 #endif
164 }
165
166 } // namespace Net
167 } // namespace Msp