resizable packets
[chaz/yoink] / src / Moof / Socket.hh
1
2 /*] Copyright (c) 2009-2010, Charles McGarvey [**************************
3 **] All rights reserved.
4 *
5 * vi:ts=4 sw=4 tw=75
6 *
7 * Distributable under the terms and conditions of the 2-clause BSD license;
8 * see the file COPYING for a complete text of the license.
9 *
10 **************************************************************************/
11
12 #ifndef _MOOF_SOCKET_HH_
13 #define _MOOF_SOCKET_HH_
14
15 #include <cstring>
16 #include <sstream>
17 #include <string>
18 #include <vector>
19
20 #if defined(_WIN32)
21 #include <winsock2.h>
22 #include <ws2tcpip.h>
23 #include <wspiapi.h>
24 #else
25 #include <arpa/inet.h>
26 #include <netdb.h>
27 #include <sys/socket.h>
28 #include <sys/types.h>
29 #if HAVE_FCNTL_H
30 #include <fcntl.h>
31 #else
32 #include <sys/ioctl.h>
33 #endif
34 #endif
35
36 #include <Moof/Log.hh>
37 #include <Moof/Packet.hh>
38 #include <Moof/Thread.hh>
39
40
41 #ifndef SO_NONBLOCK
42 #define SO_NONBLOCK 1024
43 #endif
44
45
46 namespace Mf {
47
48
49 class SocketAddress
50 {
51 public:
52
53 SocketAddress() :
54 mSize(0),
55 mType(0)
56 {
57 mAddress.sa.sa_family = AF_UNSPEC;
58 mAddress.v4.sin_port = 0;
59 }
60
61 SocketAddress(const std::string& service, const std::string& name,
62 int type = SOCK_STREAM, int family = AF_UNSPEC)
63 {
64 init(service, name, type, family);
65 }
66
67 SocketAddress(const std::string& service,
68 int type = SOCK_STREAM, int family = AF_UNSPEC)
69 {
70 init(service, type, family);
71 }
72
73 SocketAddress(const struct addrinfo* addr, const std::string& name)
74 {
75 mType = addr->ai_socktype;
76 memcpy(&mAddress.sa, addr->ai_addr, addr->ai_addrlen);
77 mName = name;
78 mSize = addr->ai_addrlen;
79 }
80
81 SocketAddress(const struct sockaddr* addr, size_t size,
82 int type = SOCK_STREAM)
83 {
84 mType = type;
85 memcpy(&mAddress.sa, addr, size);
86 mSize = size;
87 setNameFromAddress();
88 }
89
90
91 static SocketAddress broadcast(const std::string& service)
92 {
93 std::istringstream stream(service);
94 unsigned short port;
95 stream >> port;
96
97 struct sockaddr_in addr;
98 addr.sin_family = AF_INET;
99 addr.sin_port = htons(port);
100 addr.sin_addr.s_addr = INADDR_BROADCAST;
101 memset(&addr.sin_zero, 0, sizeof(addr.sin_zero));
102 return SocketAddress((sockaddr*)&addr, sizeof(addr), SOCK_DGRAM);
103 }
104
105
106 void init(const std::string& service, const std::string& name = "",
107 int type = SOCK_STREAM, int family = AF_UNSPEC)
108 {
109 ASSERT(type == SOCK_STREAM || type == SOCK_DGRAM);
110 ASSERT(family == AF_INET || family == AF_INET6 || family == AF_UNSPEC);
111
112 struct addrinfo hints;
113 memset(&hints, 0, sizeof(hints));
114 hints.ai_family = family;
115 hints.ai_socktype = type;
116 hints.ai_flags = AI_PASSIVE;
117
118 struct addrinfo* addr;
119 int status = getaddrinfo(name.length() > 0 ? name.c_str() : 0,
120 service.c_str(), &hints, &addr);
121 if (status == 0)
122 {
123 mType = addr->ai_socktype;
124 memcpy(&mAddress.sa, addr->ai_addr, addr->ai_addrlen);
125 mSize = addr->ai_addrlen;
126
127 if (name != "") mName = name;
128 else setNameFromAddress();
129
130 freeaddrinfo(addr);
131 }
132 else
133 {
134 Mf::logWarning(gai_strerror(status));
135 mType = 0;
136 mSize = 0;
137 mAddress.sa.sa_family = AF_UNSPEC;
138 mAddress.v4.sin_port = 0;
139 }
140 }
141
142 void init(const std::string& service,
143 int type = SOCK_STREAM, int family = AF_UNSPEC)
144 {
145 init(service, "", type, family);
146 }
147
148
149 const std::string& name() const
150 {
151 return mName;
152 }
153
154 void setName(const std::string& name)
155 {
156 mName = name;
157 }
158
159 unsigned short port() const
160 {
161 return ntohs(mAddress.v4.sin_port);
162 }
163
164 int type() const
165 {
166 return mType;
167 }
168
169 int family() const
170 {
171 return mAddress.sa.sa_family;
172 }
173
174
175 const struct sockaddr* address() const
176 {
177 return mSize != 0 ? &mAddress.sa : 0;
178 }
179
180 size_t size() const
181 {
182 return mSize;
183 }
184
185
186 static int resolve(const std::string& service, const std::string& name,
187 int type, int family, std::vector<SocketAddress>& resolved)
188 {
189 ASSERT(type == SOCK_STREAM || type == SOCK_DGRAM);
190 ASSERT(family == AF_INET || family == AF_INET6 || family == AF_UNSPEC);
191
192 resolved.clear();
193
194 struct addrinfo hints;
195 memset(&hints, 0, sizeof(hints));
196 hints.ai_family = family;
197 hints.ai_socktype = type;
198 hints.ai_flags = AI_PASSIVE;
199
200 struct addrinfo* list;
201 int status = getaddrinfo(name.length() > 0 ? name.c_str() : 0,
202 service.length() > 0 ? service.c_str() : 0, &hints, &list);
203 if (status == 0)
204 {
205 for (struct addrinfo* addr = list;
206 addr != 0; addr = addr->ai_next)
207 {
208 resolved.push_back(SocketAddress(addr, name));
209 }
210
211 freeaddrinfo(list);
212 }
213 else
214 {
215 Mf::logWarning(gai_strerror(status));
216 }
217
218 return 0;
219 }
220
221
222 private:
223
224 void setNameFromAddress()
225 {
226 #if defined(_WIN32)
227 // inet_ntop was introduced in Vista
228 mName = inet_ntoa(mAddress.v4.sin_addr);
229 #else
230 char name[INET6_ADDRSTRLEN] = {'\0'};
231 inet_ntop(mAddress.sa.sa_family, &mAddress.sa, name, sizeof(name));
232 mName = name;
233 #endif
234 }
235
236
237 union
238 {
239 sockaddr sa;
240 sockaddr_in v4;
241 sockaddr_in6 v6;
242 sockaddr_storage storage;
243 } mAddress;
244 size_t mSize;
245 std::string mName;
246 int mType;
247 };
248
249
250 class Socket
251 {
252 public:
253
254 Socket(const SocketAddress& address) :
255 mFd(-1),
256 mAddress(address)
257 {
258 mFd = socket(address.family(), address.type(), 0);
259 }
260
261 ~Socket()
262 {
263 #if defined(_WIN32)
264 if (mFd != -1) closesocket(mFd);
265 #else
266 if (mFd != -1) close(mFd);
267 #endif
268 }
269
270
271 bool isConnected() const
272 {
273 return mFd != -1;
274 }
275
276 const SocketAddress& address() const
277 {
278 return mAddress;
279 }
280
281
282 int connect()
283 {
284 return ::connect(mFd, mAddress.address(), mAddress.size());
285 }
286
287 int bind()
288 {
289 return ::bind(mFd, mAddress.address(), mAddress.size());
290 }
291
292 int listen(int backlog = SOMAXCONN)
293 {
294 return ::listen(mFd, backlog > 0 ? backlog : SOMAXCONN);
295 }
296
297 Socket accept()
298 {
299 return Socket(mFd);
300 }
301
302
303 int set(int option, int value = 0)
304 {
305 if (option == SO_NONBLOCK)
306 {
307 #ifdef HAVE_FCNTL
308 int flags = fcntl(mFd, F_GETFL);
309 return fcntl(mFd, F_SETFL, (value ? O_NONBLOCK : 0) | flags);
310 #else
311 return ioctl(mFd, FIONBIO, value);
312 #endif
313 }
314 return setsockopt(mFd, SOL_SOCKET, option, &value, sizeof(value));
315 }
316
317 int set(int option, const std::string& value)
318 {
319 return setsockopt(mFd, SOL_SOCKET, option,
320 value.c_str(), value.length());
321 }
322
323 int get(int option, int& value)
324 {
325 if (option == SO_NONBLOCK)
326 {
327 #ifdef HAVE_FCNTL
328 int flags = fcntl(mFd, F_GETFL);
329 return flags & O_NONBLOCK;
330 #else
331 return ioctl(mFd, FIONBIO, &value);
332 #endif
333 }
334 socklen_t optlen = sizeof(value);
335 return getsockopt(mFd, SOL_SOCKET, option, &value, &optlen);
336 }
337
338 int get(int option, std::string& value)
339 {
340 char str[64] = {'\0'};
341 socklen_t optlen = sizeof(str);
342 int result = getsockopt(mFd, SOL_SOCKET, option, &str, &optlen);
343 value = str;
344 return result;
345 }
346
347 void write(const Packet& packet)
348 {
349 write(mAddress, packet);
350 }
351
352 void write(const SocketAddress& address, const Packet& packet)
353 {
354 sendto(mFd, packet.bytes(), packet.size(), 0,
355 address.address(), address.size());
356 }
357
358 Packet read()
359 {
360 char buffer[1024];
361 int size = recv(mFd, buffer, sizeof(buffer), 0);
362
363 return Packet(buffer, size);
364 }
365
366 Packet read(SocketAddress& address)
367 {
368 union
369 {
370 sockaddr sa;
371 sockaddr_storage storage;
372 } addr;
373 socklen_t length = sizeof(addr);
374
375 char buffer[1024];
376 int size = recvfrom(mFd, buffer, sizeof(buffer), 0,
377 &addr.sa, &length);
378
379 address = SocketAddress(&addr.sa, length, mAddress.type());
380 return Packet(buffer, size);
381 }
382
383
384 private:
385
386 Socket(int fd)
387 {
388 // for accepting a socket from fd
389 union
390 {
391 sockaddr sa;
392 sockaddr_storage storage;
393 } addr;
394 socklen_t length = sizeof(addr);
395
396 mFd = ::accept(fd, &addr.sa, &length);
397 mAddress = SocketAddress(&addr.sa, length);
398 }
399
400
401 int mFd;
402 SocketAddress mAddress;
403 };
404
405
406 class ResolverTask : public ThreadedTask
407 {
408 public:
409
410 ResolverTask(const std::string& service, const std::string& name,
411 int type = SOCK_STREAM, int family = AF_UNSPEC) :
412 mIsDone(false)
413 {
414 mFunction = boost::bind(&ResolverTask::resolve,
415 this, service, name, type, family);
416 }
417
418
419 bool isDone() const
420 {
421 return mIsDone;
422 }
423
424 void run()
425 {
426 if (!mThread) mThread = Mf::detachFunction(mFunction);
427 }
428
429
430 const std::vector<SocketAddress>& addresses() const
431 {
432 return mAddressList;
433 }
434
435
436 private:
437
438 int resolve(const std::string& service, const std::string& name,
439 int type, int family)
440 {
441 int status = SocketAddress::resolve(service, name,
442 type, family, mAddressList);
443 mIsDone = true;
444 return status;
445 }
446
447
448 std::vector<SocketAddress> mAddressList;
449 bool mIsDone;
450 Function mFunction;
451 };
452
453
454 } // namespace Mf
455
456 #endif // _MOOF_SOCKET_HH_
457
This page took 0.052709 seconds and 4 git commands to generate.