]> Dogcows Code - chaz/yoink/blob - src/Moof/Socket.hh
better broadcast support
[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 struct addrinfo* addr = list;
206 while (addr != 0)
207 {
208 resolved.push_back(SocketAddress(addr, name));
209 addr = addr->ai_next;
210 }
211
212 freeaddrinfo(list);
213 }
214 else
215 {
216 Mf::logWarning(gai_strerror(status));
217 }
218
219 return 0;
220 }
221
222
223 private:
224
225 void setNameFromAddress()
226 {
227 #if defined(_WIN32)
228 // inet_ntop was introduced in Vista
229 mName = inet_ntoa(mAddress.v4.sin_addr);
230 #else
231 char name[INET6_ADDRSTRLEN] = {'\0'};
232 inet_ntop(mAddress.sa.sa_family, &mAddress.sa, name, sizeof(name));
233 mName = name;
234 #endif
235 }
236
237
238 union
239 {
240 sockaddr sa;
241 sockaddr_in v4;
242 sockaddr_in6 v6;
243 sockaddr_storage storage;
244 } mAddress;
245 size_t mSize;
246 std::string mName;
247 int mType;
248 };
249
250
251 class Socket
252 {
253 public:
254
255 Socket(const SocketAddress& address) :
256 mFd(-1),
257 mAddress(address)
258 {
259 mFd = socket(address.family(), address.type(), 0);
260 }
261
262 ~Socket()
263 {
264 #if defined(_WIN32)
265 if (mFd != -1) closesocket(mFd);
266 #else
267 if (mFd != -1) close(mFd);
268 #endif
269 }
270
271
272 bool isConnected() const
273 {
274 return mFd != -1;
275 }
276
277 const SocketAddress& address() const
278 {
279 return mAddress;
280 }
281
282
283 int connect()
284 {
285 return ::connect(mFd, mAddress.address(), mAddress.size());
286 }
287
288 int bind()
289 {
290 return ::bind(mFd, mAddress.address(), mAddress.size());
291 }
292
293 int listen(int backlog = SOMAXCONN)
294 {
295 return ::listen(mFd, backlog > 0 ? backlog : SOMAXCONN);
296 }
297
298 Socket accept()
299 {
300 return Socket(mFd);
301 }
302
303
304 int set(int option, int value = 0)
305 {
306 if (option == SO_NONBLOCK)
307 {
308 #ifdef HAVE_FCNTL
309 int flags = fcntl(mFd, F_GETFL);
310 return fcntl(mFd, F_SETFL, (value ? O_NONBLOCK : 0) | flags);
311 #else
312 return ioctl(mFd, FIONBIO, value);
313 #endif
314 }
315 return setsockopt(mFd, SOL_SOCKET, option, &value, sizeof(value));
316 }
317
318 int set(int option, const std::string& value)
319 {
320 return setsockopt(mFd, SOL_SOCKET, option,
321 value.c_str(), value.length());
322 }
323
324 int get(int option, int& value)
325 {
326 if (option == SO_NONBLOCK)
327 {
328 #ifdef HAVE_FCNTL
329 int flags = fcntl(mFd, F_GETFL);
330 return flags & O_NONBLOCK;
331 #else
332 return ioctl(mFd, FIONBIO, &value);
333 #endif
334 }
335 socklen_t optlen = sizeof(value);
336 return getsockopt(mFd, SOL_SOCKET, option, &value, &optlen);
337 }
338
339 int get(int option, std::string& value)
340 {
341 char str[64] = {'\0'};
342 socklen_t optlen = sizeof(str);
343 int result = getsockopt(mFd, SOL_SOCKET, option, &str, &optlen);
344 value = str;
345 return result;
346 }
347
348 void write(const Packet& packet)
349 {
350 write(mAddress, packet);
351 }
352
353 void write(const SocketAddress& address, const Packet& packet)
354 {
355 sendto(mFd, packet.bytes(), packet.size(), 0,
356 address.address(), address.size());
357 }
358
359 Packet read()
360 {
361 char buffer[1024];
362 int size = recv(mFd, buffer, sizeof(buffer), 0);
363
364 return Packet(buffer, size);
365 }
366
367 Packet read(SocketAddress& address)
368 {
369 union
370 {
371 sockaddr sa;
372 sockaddr_storage storage;
373 } addr;
374 socklen_t length = sizeof(addr);
375
376 char buffer[1024];
377 int size = recvfrom(mFd, buffer, sizeof(buffer), 0,
378 &addr.sa, &length);
379
380 address = SocketAddress(&addr.sa, length, mAddress.type());
381 return Packet(buffer, size);
382 }
383
384
385 private:
386
387 Socket(int fd)
388 {
389 // for accepting a socket from fd
390 union
391 {
392 sockaddr sa;
393 sockaddr_storage storage;
394 } addr;
395 socklen_t length = sizeof(addr);
396
397 mFd = ::accept(fd, &addr.sa, &length);
398 mAddress = SocketAddress(&addr.sa, length);
399 }
400
401
402 int mFd;
403 SocketAddress mAddress;
404 };
405
406
407 class ResolverTask : public ThreadedTask
408 {
409 public:
410
411 ResolverTask(const std::string& service, const std::string& name,
412 int type = SOCK_STREAM, int family = AF_UNSPEC) :
413 mIsDone(false)
414 {
415 mFunction = boost::bind(&ResolverTask::resolve,
416 this, service, name, type, family);
417 }
418
419
420 bool isDone() const
421 {
422 return mIsDone;
423 }
424
425 void run()
426 {
427 if (!mThread) mThread = Mf::detachFunction(mFunction);
428 }
429
430
431 const std::vector<SocketAddress>& addresses() const
432 {
433 return mAddressList;
434 }
435
436
437 private:
438
439 int resolve(const std::string& service, const std::string& name,
440 int type, int family)
441 {
442 int status = SocketAddress::resolve(service, name,
443 type, family, mAddressList);
444 mIsDone = true;
445 return status;
446 }
447
448
449 std::vector<SocketAddress> mAddressList;
450 bool mIsDone;
451 Function mFunction;
452 };
453
454
455 } // namespace Mf
456
457 #endif // _MOOF_SOCKET_HH_
458
This page took 0.049068 seconds and 5 git commands to generate.