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