]> Dogcows Code - chaz/yoink/blob - src/Moof/Socket.hh
948f9423785ea944087f29e580b5ef5b4f6f4391
[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 <algorithm>
16 #include <cstring>
17 #include <sstream>
18 #include <string>
19 #include <vector>
20
21 #if defined(_WIN32)
22 #include <winsock2.h>
23 #include <ws2tcpip.h>
24 #include <wspiapi.h>
25 #else
26 #include <arpa/inet.h>
27 #include <netdb.h>
28 #include <sys/socket.h>
29 #include <sys/types.h>
30 #if HAVE_FCNTL_H
31 #include <fcntl.h>
32 #else
33 #include <sys/ioctl.h>
34 #endif
35 #endif
36
37 #include <Moof/Log.hh>
38 #include <Moof/Packet.hh>
39 #include <Moof/Thread.hh>
40
41
42 #ifndef SO_NONBLOCK
43 #define SO_NONBLOCK 1024
44 #endif
45
46
47 namespace Mf {
48
49
50 class SocketAddress
51 {
52 public:
53
54 SocketAddress() :
55 mSize(0),
56 mType(0)
57 {
58 mAddr.sa.sa_family = AF_UNSPEC;
59 mAddr.in.sin_port = 0;
60 }
61
62 SocketAddress(const std::string& service, const std::string& name,
63 int type = SOCK_STREAM, int family = AF_UNSPEC)
64 {
65 init(service, name, type, family);
66 }
67
68 SocketAddress(const std::string& service,
69 int type = SOCK_STREAM, int family = AF_UNSPEC)
70 {
71 init(service, type, family);
72 }
73
74 SocketAddress(const struct addrinfo* addr, const std::string& name)
75 {
76 mType = addr->ai_socktype;
77 memcpy(&mAddr.sa, addr->ai_addr, addr->ai_addrlen);
78 mName = name;
79 mSize = addr->ai_addrlen;
80 }
81
82 SocketAddress(const struct sockaddr* addr, size_t size,
83 int type = SOCK_STREAM)
84 {
85 mType = type;
86 memcpy(&mAddr.sa, addr, size);
87 mSize = size;
88 setNameFromAddress();
89 }
90
91
92 static SocketAddress broadcast(const std::string& service)
93 {
94 std::istringstream stream(service);
95 unsigned short port;
96 stream >> port;
97
98 struct sockaddr_in addr;
99 addr.sin_family = AF_INET;
100 addr.sin_port = htons(port);
101 addr.sin_addr.s_addr = INADDR_BROADCAST;
102 memset(&addr.sin_zero, 0, sizeof(addr.sin_zero));
103 return SocketAddress((sockaddr*)&addr, sizeof(addr), SOCK_DGRAM);
104 }
105
106
107 void init(const std::string& service, const std::string& name = "",
108 int type = SOCK_STREAM, int family = AF_UNSPEC)
109 {
110 ASSERT(type == SOCK_STREAM || type == SOCK_DGRAM);
111 ASSERT(family == AF_INET || family == AF_INET6 || family == AF_UNSPEC);
112
113 struct addrinfo hints;
114 memset(&hints, 0, sizeof(hints));
115 hints.ai_family = family;
116 hints.ai_socktype = type;
117 hints.ai_flags = AI_PASSIVE;
118
119 struct addrinfo* addr;
120 int status = getaddrinfo(name.length() > 0 ? name.c_str() : 0,
121 service.c_str(), &hints, &addr);
122 if (status == 0)
123 {
124 mType = addr->ai_socktype;
125 memcpy(&mAddr.sa, addr->ai_addr, addr->ai_addrlen);
126 mSize = addr->ai_addrlen;
127
128 if (name != "") mName = name;
129 else setNameFromAddress();
130
131 freeaddrinfo(addr);
132 }
133 else
134 {
135 Mf::logWarning(gai_strerror(status));
136 mType = 0;
137 mSize = 0;
138 mAddr.sa.sa_family = AF_UNSPEC;
139 mAddr.in.sin_port = 0;
140 }
141 }
142
143 void init(const std::string& service,
144 int type = SOCK_STREAM, int family = AF_UNSPEC)
145 {
146 init(service, "", type, family);
147 }
148
149
150 const std::string& name() const
151 {
152 return mName;
153 }
154
155 void setName(const std::string& name)
156 {
157 mName = name;
158 }
159
160 unsigned short port() const
161 {
162 return ntohs(mAddr.in.sin_port);
163 }
164
165 int type() const
166 {
167 return mType;
168 }
169
170 int family() const
171 {
172 return mAddr.sa.sa_family;
173 }
174
175
176 const struct sockaddr* address() const
177 {
178 return mSize != 0 ? &mAddr.sa : 0;
179 }
180
181 size_t size() const
182 {
183 return mSize;
184 }
185
186
187 static int resolve(const std::string& service, const std::string& name,
188 int type, int family, std::vector<SocketAddress>& resolved)
189 {
190 ASSERT(type == SOCK_STREAM || type == SOCK_DGRAM);
191 ASSERT(family == AF_INET || family == AF_INET6 || family == AF_UNSPEC);
192
193 resolved.clear();
194
195 struct addrinfo hints;
196 memset(&hints, 0, sizeof(hints));
197 hints.ai_family = family;
198 hints.ai_socktype = type;
199 hints.ai_flags = AI_PASSIVE;
200
201 struct addrinfo* list;
202 int status = getaddrinfo(name.length() > 0 ? name.c_str() : 0,
203 service.length() > 0 ? service.c_str() : 0, &hints, &list);
204 if (status == 0)
205 {
206 for (struct addrinfo* addr = list;
207 addr != 0; addr = addr->ai_next)
208 {
209 resolved.push_back(SocketAddress(addr, name));
210 }
211
212 freeaddrinfo(list);
213 }
214 else
215 {
216 Mf::logWarning(gai_strerror(status));
217 return -1;
218 }
219
220 return 0;
221 }
222
223
224 private:
225
226 void setNameFromAddress()
227 {
228 #if defined(_WIN32)
229 // inet_ntop was introduced in Vista
230 mName = inet_ntoa(mAddr.in.sin_addr);
231 #else
232 char name[INET6_ADDRSTRLEN] = {'\0'};
233 inet_ntop(mAddr.sa.sa_family, &mAddr.sa, name, sizeof(name));
234 mName = name;
235 #endif
236 }
237
238
239 union
240 {
241 sockaddr sa;
242 sockaddr_in in;
243 sockaddr_storage storage;
244 } mAddr;
245 size_t mSize;
246 std::string mName;
247 int mType;
248 };
249
250
251 class Socket
252 {
253 struct Impl
254 {
255 int fd;
256 bool isConnected;
257 SocketAddress address;
258 };
259
260
261 public:
262
263 Socket() :
264 mFd(-1),
265 mIsConnected(false) {}
266
267 Socket(const SocketAddress& address) :
268 mFd(-1),
269 mIsConnected(false),
270 mAddress(address) {}
271
272 Socket(const std::string& service, const std::string& name,
273 int type = SOCK_STREAM, int family = AF_UNSPEC) :
274 mFd(-1),
275 mIsConnected(false),
276 mAddress(SocketAddress(service, name, type, family)) {}
277
278 Socket(const std::string& service,
279 int type = SOCK_STREAM, int family = AF_UNSPEC) :
280 mFd(-1),
281 mIsConnected(false),
282 mAddress(SocketAddress(service, type, family)) {}
283
284
285 Socket(Socket& move) :
286 mFd(move.mFd),
287 mIsConnected(move.mIsConnected),
288 mAddress(move.mAddress)
289 {
290 move.mFd = -1;
291 move.mIsConnected = false;
292 }
293
294 Socket(Impl move) :
295 mFd(move.fd),
296 mIsConnected(move.isConnected),
297 mAddress(move.address) {}
298
299 Socket& operator=(Socket& move)
300 {
301 #if defined(_WIN32)
302 if (mFd != -1) closesocket(mFd);
303 #else
304 if (mFd != -1) close(mFd);
305 #endif
306 mFd = move.mFd;
307 mIsConnected = move.mIsConnected;
308 mAddress = move.mAddress;
309 move.mFd = -1;
310 move.mIsConnected = false;
311 return *this;
312 }
313
314 Socket& operator=(Impl move)
315 {
316 #if defined(_WIN32)
317 if (mFd != -1) closesocket(mFd);
318 #else
319 if (mFd != -1) close(mFd);
320 #endif
321 mFd = move.fd;
322 mIsConnected = move.isConnected;
323 mAddress = move.address;
324 return *this;
325 }
326
327 operator Impl()
328 {
329 Impl impl;
330 impl.fd = mFd;
331 impl.isConnected = mIsConnected;
332 impl.address = mAddress;
333 mFd = -1;
334 mIsConnected = false;
335 return impl;
336 }
337
338
339 ~Socket()
340 {
341 #if defined(_WIN32)
342 if (mFd != -1) closesocket(mFd);
343 #else
344 if (mFd != -1) close(mFd);
345 #endif
346 }
347
348
349 bool isConnected() const
350 {
351 return mIsConnected;
352 }
353
354 const SocketAddress& address() const
355 {
356 return mAddress;
357 }
358
359
360 int connect()
361 {
362 if (mFd == -1) mFd = socket(mAddress.family(), mAddress.type(), 0);
363 int result = ::connect(mFd, mAddress.address(), mAddress.size());
364 mIsConnected = result != -1;
365 return result;
366 }
367
368 int bind()
369 {
370 if (mFd == -1) mFd = socket(mAddress.family(), mAddress.type(), 0);
371 return ::bind(mFd, mAddress.address(), mAddress.size());
372 }
373
374 int listen(int backlog = SOMAXCONN)
375 {
376 return ::listen(mFd, backlog > 0 ? backlog : SOMAXCONN);
377 }
378
379 int accept(Socket& socket)
380 {
381 Socket temp = Socket(mFd);
382 if (temp.mFd != -1)
383 {
384 socket = temp;
385 return socket.mFd;
386 }
387 return -1;
388 }
389
390
391 int set(int option, int value = 0)
392 {
393 if (option == SO_NONBLOCK)
394 {
395 #ifdef HAVE_FCNTL
396 int flags = fcntl(mFd, F_GETFL);
397 return fcntl(mFd, F_SETFL, (value ? O_NONBLOCK : 0) | flags);
398 #else
399 return ioctl(mFd, FIONBIO, value);
400 #endif
401 }
402 return setsockopt(mFd, SOL_SOCKET, option, &value, sizeof(value));
403 }
404
405 int set(int option, const std::string& value)
406 {
407 return setsockopt(mFd, SOL_SOCKET, option,
408 value.data(), value.length());
409 }
410
411 int get(int option, int& value)
412 {
413 if (option == SO_NONBLOCK)
414 {
415 #ifdef HAVE_FCNTL
416 int flags = fcntl(mFd, F_GETFL);
417 return flags & O_NONBLOCK;
418 #else
419 return ioctl(mFd, FIONBIO, &value);
420 #endif
421 }
422 socklen_t optlen = sizeof(value);
423 return getsockopt(mFd, SOL_SOCKET, option, &value, &optlen);
424 }
425
426 int get(int option, std::string& value)
427 {
428 char str[64] = {'\0'};
429 socklen_t optlen = sizeof(str);
430 int result = getsockopt(mFd, SOL_SOCKET, option, &str, &optlen);
431 value = str;
432 return result;
433 }
434
435
436 ssize_t write(const void* bytes, size_t size)
437 {
438 return send(mFd, bytes, size, 0);
439 }
440 ssize_t write(const void* bytes, size_t size,
441 const SocketAddress& address)
442 {
443 return sendto(mFd, bytes, size, 0,
444 address.address(), address.size());
445 }
446
447 ssize_t write(const Packet& packet)
448 {
449 return write(packet.bytes(), packet.size());
450 }
451
452 ssize_t write(const Packet& packet, const SocketAddress& address)
453 {
454 return write(packet.bytes(), packet.size(), address);
455 }
456
457
458 ssize_t read(void* bytes, size_t size)
459 {
460 return recv(mFd, bytes, size, 0);
461 }
462
463 ssize_t read(void* bytes, size_t size, SocketAddress& address)
464 {
465 union
466 {
467 sockaddr sa;
468 sockaddr_storage storage;
469 } addr;
470 socklen_t length = sizeof(addr);
471
472 ssize_t result = recvfrom(mFd, bytes, size, 0, &addr.sa, &length);
473 if (result != -1)
474 {
475 address = SocketAddress(&addr.sa, length, mAddress.type());
476 }
477 return result;
478 }
479
480 ssize_t read(Packet& packet)
481 {
482 char buffer[65536];
483 ssize_t result = read(buffer, sizeof(buffer));
484 if (result != -1) packet = Packet(buffer, result);
485 return result;
486 }
487
488 ssize_t read(Packet& packet, SocketAddress& address)
489 {
490 char buffer[65536];
491 ssize_t result = read(buffer, sizeof(buffer), address);
492 if (result != -1) packet = Packet(buffer, result);
493 return result;
494 }
495
496
497 private:
498
499 Socket(int fd)
500 {
501 // for accepting a socket from fd
502 union
503 {
504 sockaddr sa;
505 sockaddr_storage storage;
506 } addr;
507 socklen_t length = sizeof(addr);
508
509 mFd = ::accept(fd, &addr.sa, &length);
510 if (mFd != -1)
511 {
512 mIsConnected = true;
513 mAddress = SocketAddress(&addr.sa, length);
514 }
515 }
516
517
518 int mFd;
519 bool mIsConnected;
520 SocketAddress mAddress;
521 };
522
523
524 class ResolverTask : public ThreadedTask
525 {
526 public:
527
528 ResolverTask(const std::string& service, const std::string& name,
529 int type = SOCK_STREAM, int family = AF_UNSPEC) :
530 mIsDone(false)
531 {
532 mFunction = boost::bind(&ResolverTask::resolve,
533 this, service, name, type, family);
534 }
535
536
537 bool isDone() const
538 {
539 return mIsDone;
540 }
541
542 void run()
543 {
544 if (!mThread) mThread = Mf::detachFunction(mFunction);
545 }
546
547
548 const std::vector<SocketAddress>& addresses() const
549 {
550 return mAddressList;
551 }
552
553
554 private:
555
556 int resolve(const std::string& service, const std::string& name,
557 int type, int family)
558 {
559 int status = SocketAddress::resolve(service, name,
560 type, family, mAddressList);
561 mIsDone = true;
562 return status;
563 }
564
565
566 std::vector<SocketAddress> mAddressList;
567 bool mIsDone;
568 Function mFunction;
569 };
570
571
572 } // namespace Mf
573
574 #endif // _MOOF_SOCKET_HH_
575
This page took 0.053035 seconds and 3 git commands to generate.