comparison C++/Socket.cpp @ 170:fd138f2a9773

Add C++ portable sockets
author David Demelier <markand@malikania.fr>
date Tue, 10 Sep 2013 15:17:56 +0200
parents
children 9f22bd478f21
comparison
equal deleted inserted replaced
169:29531c2f8213 170:fd138f2a9773
1 /*
2 * Socket.cpp -- portable C++ socket wrappers
3 *
4 * Copyright (c) 2013, David Demelier <markand@malikania.fr>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <cerrno>
20
21 #include "Socket.h"
22 #include "SocketAddress.h"
23
24 /* --------------------------------------------------------
25 * SocketError implementation
26 * -------------------------------------------------------- */
27
28 SocketError::SocketError(const std::string &error)
29 {
30 m_error = error;
31 }
32
33 const char *SocketError::what() const throw()
34 {
35 return m_error.c_str();
36 }
37
38 /* --------------------------------------------------------
39 * Socket implementation
40 * -------------------------------------------------------- */
41
42 void Socket::init()
43 {
44 #if defined(_WIN32)
45 WSADATA wsa;
46 WSAStartup(MAKEWORD(2, 2), &wsa);
47 #endif
48 }
49
50 /* --------------------------------------------------------
51 * System dependent code
52 * -------------------------------------------------------- */
53
54 #if defined(_WIN32)
55
56 string Socket::getLastSysError()
57 {
58 LPSTR str = nullptr;
59 string errmsg = "Unknown error";
60
61 FormatMessageA(
62 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
63 NULL,
64 WSAGetLastError(),
65 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
66 (LPSTR)&str, 0, NULL);
67
68
69 if (str)
70 {
71 errmsg = string(str);
72 LocalFree(str);
73 }
74
75 return errmsg;
76 }
77
78 #else
79
80 std::string Socket::getLastSysError()
81 {
82 return strerror(errno);
83 }
84
85 #endif
86
87 void Socket::finish()
88 {
89 #if defined(_WIN32)
90 WSACleanup();
91 #endif
92 }
93
94 Socket::Socket()
95 {
96 }
97
98 Socket::Socket(int domain, int type, int protocol)
99 {
100 m_socket = socket(domain, type, protocol);
101
102 if (m_socket == INVALID_SOCKET)
103 throw SocketError(getLastSysError());
104 }
105
106 Socket::Socket(Socket::Type sock)
107 : m_socket(sock)
108 {
109 }
110
111 Socket::~Socket()
112 {
113 }
114
115 Socket::Type Socket::getSocket() const
116 {
117 return m_socket;
118 }
119
120 void Socket::set(int level, int name, const void *arg, unsigned argLen)
121 {
122 if (setsockopt(m_socket, level, name, (Socket::ConstArg)arg, argLen) == SOCKET_ERROR)
123 throw SocketError(getLastSysError());
124 }
125
126 void Socket::blockMode(bool block)
127 {
128 #if defined(O_NONBLOCK) && !defined(_WIN32)
129 int flags;
130
131 if ((flags = fcntl(m_socket, F_GETFL, 0)) == -1)
132 flags = 0;
133
134 if (!block)
135 flags &= ~(O_NONBLOCK);
136 else
137 flags |= O_NONBLOCK;
138
139 if (fcntl(m_socket, F_SETFL, flags) == -1)
140 throw SocketError(getLastSysError());
141 #else
142 unsigned long flags = (block) ? 0 : 1;
143
144 if (ioctlsocket(m_socket, FIONBIO, &flags) == SOCKET_ERROR)
145 throw SocketError(getLastSysError());
146 #endif
147 }
148
149 void Socket::bind(const SocketAddress &addr)
150 {
151 const sockaddr_storage &sa = addr.address();
152 size_t addrlen = addr.length();
153
154 if (::bind(m_socket, (sockaddr *)&sa, addrlen) == SOCKET_ERROR)
155 throw SocketError(getLastSysError());
156 }
157
158 void Socket::connect(const SocketAddress &addr)
159 {
160 const sockaddr_storage &sa = addr.address();
161 size_t addrlen = addr.length();
162
163 if (::connect(m_socket, (sockaddr *)&sa, addrlen) == SOCKET_ERROR)
164 throw SocketError(getLastSysError());
165 }
166
167 Socket Socket::accept()
168 {
169 SocketAddress dummy;
170
171 return accept(dummy);
172 }
173
174 Socket Socket::accept(SocketAddress &info)
175 {
176 Socket::Type sock;
177
178 info.m_addrlen = sizeof (sockaddr_storage);
179 sock = ::accept(m_socket, (sockaddr *)&info.m_addr, &info.m_addrlen);
180
181 if (sock == INVALID_SOCKET)
182 throw SocketError(getLastSysError());
183
184 return Socket(sock);
185 }
186
187 void Socket::listen(int max)
188 {
189 if (::listen(m_socket, max) == SOCKET_ERROR)
190 throw SocketError(getLastSysError());
191 }
192
193 unsigned Socket::recv(void *data, unsigned dataLen)
194 {
195 int nbread;
196
197 nbread = ::recv(m_socket, (Socket::Arg)data, dataLen, 0);
198 if (nbread == SOCKET_ERROR)
199 throw SocketError(getLastSysError());
200
201 return (unsigned)nbread;
202 }
203
204 unsigned Socket::send(const void *data, unsigned dataLen)
205 {
206 int nbsent;
207
208 nbsent = ::send(m_socket, (Socket::ConstArg)data, dataLen, 0);
209 if (nbsent == SOCKET_ERROR)
210 throw SocketError(getLastSysError());
211
212 return (unsigned)nbsent;
213 }
214
215 unsigned Socket::send(const std::string &message)
216 {
217 return Socket::send(message.c_str(), message.length());
218 }
219
220 unsigned Socket::recvfrom(void *data, unsigned dataLen)
221 {
222 SocketAddress dummy;
223
224 return recvfrom(data, dataLen, dummy);
225 }
226
227 unsigned Socket::recvfrom(void *data, unsigned dataLen, SocketAddress &info)
228 {
229 int nbread;
230
231 info.m_addrlen = sizeof (struct sockaddr_storage);
232 nbread = ::recvfrom(m_socket, (Socket::Arg)data, dataLen, 0,
233 (sockaddr *)&info.m_addr, &info.m_addrlen);
234
235 if (nbread == SOCKET_ERROR)
236 throw SocketError(getLastSysError());
237
238 return (unsigned)nbread;
239 }
240
241 unsigned Socket::sendto(const void *data, unsigned dataLen, const SocketAddress &info)
242 {
243 int nbsent;
244
245 nbsent = ::sendto(m_socket, (Socket::ConstArg)data, dataLen, 0,
246 (const sockaddr *)&info.m_addr, info.m_addrlen);
247 if (nbsent == SOCKET_ERROR)
248 throw SocketError(getLastSysError());
249
250 return (unsigned)nbsent;
251 }
252
253 unsigned Socket::sendto(const std::string &message, const SocketAddress &info)
254 {
255 return sendto(message.c_str(), message.length(), info);
256 }
257
258 void Socket::close()
259 {
260 (void)closesocket(m_socket);
261 }
262
263 bool operator==(const Socket &s1, const Socket &s2)
264 {
265 return s1.getSocket() == s2.getSocket();
266 }