132
|
1 /*
|
|
2 Copyright (C) 2004 Christopher E. Miller
|
|
3
|
|
4 This software is provided 'as-is', without any express or implied
|
|
5 warranty. In no event will the authors be held liable for any damages
|
|
6 arising from the use of this software.
|
|
7
|
|
8 Permission is granted to anyone to use this software for any purpose,
|
|
9 including commercial applications, and to alter it and redistribute it
|
|
10 freely, subject to the following restrictions:
|
|
11
|
|
12 1. The origin of this software must not be misrepresented; you must not
|
|
13 claim that you wrote the original software. If you use this software
|
|
14 in a product, an acknowledgment in the product documentation would be
|
|
15 appreciated but is not required.
|
|
16
|
|
17 2. Altered source versions must be plainly marked as such, and must not be
|
|
18 misrepresented as being the original software.
|
|
19
|
|
20 3. This notice may not be removed or altered from any source distribution.
|
|
21
|
|
22 */
|
|
23
|
|
24 /*******************************************************************************
|
|
25
|
|
26 copyright: Copyright (c) 2004 Kris Bell. All rights reserved
|
|
27
|
|
28 license: BSD style: $(LICENSE)
|
|
29
|
|
30 version: Initial release: March 2004
|
|
31
|
|
32 author: Christopher Miller
|
|
33 Kris Bell
|
|
34 Anders F Bjorklund (Darwin patches)
|
|
35
|
|
36
|
|
37 The original code has been modified in several ways:
|
|
38
|
|
39 1) It has been altered to fit within the Tango environment, meaning
|
|
40 that certain original classes have been reorganized, and/or have
|
|
41 subclassed Tango base-classes. For example, the original Socket
|
|
42 class has been wrapped with three distinct subclasses, and now
|
|
43 derives from class tango.io.Resource.
|
|
44
|
|
45 2) All exception instances now subclass the Tango IOException.
|
|
46
|
|
47 3) Construction of new Socket instances via accept() is now
|
|
48 overloadable.
|
|
49
|
|
50 4) Constants and enums have been moved within a class boundary to
|
|
51 ensure explicit namespace usage.
|
|
52
|
|
53 5) changed Socket.select() to loop if it was interrupted.
|
|
54
|
|
55
|
|
56 All changes within the main body of code all marked with "Tango:"
|
|
57
|
|
58 For a good tutorial on socket-programming I highly recommend going
|
|
59 here: http://www.ecst.csuchico.edu/~beej/guide/net/
|
|
60
|
|
61 *******************************************************************************/
|
|
62
|
|
63 module tango.net.Socket;
|
|
64
|
|
65 private import tango.time.Time;
|
|
66
|
|
67 private import tango.sys.Common;
|
|
68
|
|
69 private import tango.core.Exception;
|
|
70
|
|
71
|
|
72 /*******************************************************************************
|
|
73
|
|
74
|
|
75 *******************************************************************************/
|
|
76
|
|
77 version=Tango;
|
|
78 version (Tango)
|
|
79 {
|
|
80 private char[] toString (char[] tmp, int i)
|
|
81 {
|
|
82 int j = tmp.length;
|
|
83 do {
|
|
84 tmp[--j] = i % 10 + '0';
|
|
85 } while (i /= 10);
|
|
86
|
|
87 return tmp [j .. $];
|
|
88 }
|
|
89 }
|
|
90
|
|
91 version (linux)
|
|
92 version = BsdSockets;
|
|
93
|
|
94 version (darwin)
|
|
95 version = BsdSockets;
|
|
96
|
|
97 version (Posix)
|
|
98 version = BsdSockets;
|
|
99
|
|
100
|
|
101 /*******************************************************************************
|
|
102
|
|
103
|
|
104 *******************************************************************************/
|
|
105
|
|
106 version (Win32)
|
|
107 {
|
|
108 pragma(lib, "ws2_32.lib");
|
|
109
|
|
110 private typedef int socket_t = ~0;
|
|
111
|
|
112 private const int IOCPARM_MASK = 0x7f;
|
|
113 private const int IOC_IN = cast(int)0x80000000;
|
|
114 private const int FIONBIO = cast(int) (IOC_IN | ((int.sizeof & IOCPARM_MASK) << 16) | (102 << 8) | 126);
|
|
115
|
|
116 private const int WSADESCRIPTION_LEN = 256;
|
|
117 private const int WSASYS_STATUS_LEN = 128;
|
|
118 private const int WSAEWOULDBLOCK = 10035;
|
|
119 private const int WSAEINTR = 10004;
|
|
120
|
|
121
|
|
122 struct WSADATA
|
|
123 {
|
|
124 WORD wVersion;
|
|
125 WORD wHighVersion;
|
|
126 char szDescription[WSADESCRIPTION_LEN+1];
|
|
127 char szSystemStatus[WSASYS_STATUS_LEN+1];
|
|
128 ushort iMaxSockets;
|
|
129 ushort iMaxUdpDg;
|
|
130 char* lpVendorInfo;
|
|
131 }
|
|
132 alias WSADATA* LPWSADATA;
|
|
133
|
|
134 extern (Windows)
|
|
135 {
|
|
136 int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);
|
|
137 int WSACleanup();
|
|
138 socket_t socket(int af, int type, int protocol);
|
|
139 int ioctlsocket(socket_t s, int cmd, uint* argp);
|
|
140 uint inet_addr(char* cp);
|
|
141 int bind(socket_t s, sockaddr* name, int namelen);
|
|
142 int connect(socket_t s, sockaddr* name, int namelen);
|
|
143 int listen(socket_t s, int backlog);
|
|
144 socket_t accept(socket_t s, sockaddr* addr, int* addrlen);
|
|
145 int closesocket(socket_t s);
|
|
146 int shutdown(socket_t s, int how);
|
|
147 int getpeername(socket_t s, sockaddr* name, int* namelen);
|
|
148 int getsockname(socket_t s, sockaddr* name, int* namelen);
|
|
149 int send(socket_t s, void* buf, int len, int flags);
|
|
150 int sendto(socket_t s, void* buf, int len, int flags, sockaddr* to, int tolen);
|
|
151 int recv(socket_t s, void* buf, int len, int flags);
|
|
152 int recvfrom(socket_t s, void* buf, int len, int flags, sockaddr* from, int* fromlen);
|
|
153 int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* errorfds, timeval* timeout);
|
|
154 //int __WSAFDIsSet(socket_t s, fd_set* fds);
|
|
155 int getsockopt(socket_t s, int level, int optname, void* optval, int* optlen);
|
|
156 int setsockopt(socket_t s, int level, int optname, void* optval, int optlen);
|
|
157 int gethostname(void* namebuffer, int buflen);
|
|
158 char* inet_ntoa(uint ina);
|
|
159 hostent* gethostbyname(char* name);
|
|
160 hostent* gethostbyaddr(void* addr, int len, int type);
|
|
161 int WSAGetLastError();
|
|
162 }
|
|
163
|
|
164 static this()
|
|
165 {
|
|
166 WSADATA wd;
|
|
167 if (WSAStartup (0x0101, &wd))
|
|
168 throw new SocketException("Unable to initialize socket library");
|
|
169 }
|
|
170
|
|
171
|
|
172 static ~this()
|
|
173 {
|
|
174 WSACleanup();
|
|
175 }
|
|
176
|
|
177 }
|
|
178
|
|
179 version (BsdSockets)
|
|
180 {
|
|
181 private import tango.stdc.errno;
|
|
182
|
|
183 private typedef int socket_t = -1;
|
|
184
|
|
185 private const int F_GETFL = 3;
|
|
186 private const int F_SETFL = 4;
|
|
187 version (darwin)
|
|
188 private const int O_NONBLOCK = 0x0004;
|
|
189 else
|
|
190 private const int O_NONBLOCK = 04000; // OCTAL! Thx to volcore
|
|
191
|
|
192 extern (C)
|
|
193 {
|
|
194 socket_t socket(int af, int type, int protocol);
|
|
195 int fcntl(socket_t s, int f, ...);
|
|
196 uint inet_addr(char* cp);
|
|
197 int bind(socket_t s, sockaddr* name, int namelen);
|
|
198 int connect(socket_t s, sockaddr* name, int namelen);
|
|
199 int listen(socket_t s, int backlog);
|
|
200 socket_t accept(socket_t s, sockaddr* addr, int* addrlen);
|
|
201 int close(socket_t s);
|
|
202 int shutdown(socket_t s, int how);
|
|
203 int getpeername(socket_t s, sockaddr* name, int* namelen);
|
|
204 int getsockname(socket_t s, sockaddr* name, int* namelen);
|
|
205 int send(socket_t s, void* buf, int len, int flags);
|
|
206 int sendto(socket_t s, void* buf, int len, int flags, sockaddr* to, int tolen);
|
|
207 int recv(socket_t s, void* buf, int len, int flags);
|
|
208 int recvfrom(socket_t s, void* buf, int len, int flags, sockaddr* from, int* fromlen);
|
|
209 int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* errorfds, timeval* timeout);
|
|
210 int getsockopt(socket_t s, int level, int optname, void* optval, int* optlen);
|
|
211 int setsockopt(socket_t s, int level, int optname, void* optval, int optlen);
|
|
212 int gethostname(void* namebuffer, int buflen);
|
|
213 char* inet_ntoa(uint ina);
|
|
214 hostent* gethostbyname(char* name);
|
|
215 hostent* gethostbyaddr(void* addr, int len, int type);
|
|
216 }
|
|
217 }
|
|
218
|
|
219
|
|
220 /*******************************************************************************
|
|
221
|
|
222
|
|
223 *******************************************************************************/
|
|
224
|
|
225 private const socket_t INVALID_SOCKET = socket_t.init;
|
|
226 private const int SOCKET_ERROR = -1;
|
|
227
|
|
228
|
|
229
|
|
230 /*******************************************************************************
|
|
231
|
|
232 Internal structs:
|
|
233
|
|
234 *******************************************************************************/
|
|
235
|
|
236 struct timeval
|
|
237 {
|
|
238 int tv_sec; //seconds
|
|
239 int tv_usec; //microseconds
|
|
240 }
|
|
241
|
|
242
|
|
243 //transparent
|
|
244 struct fd_set
|
|
245 {
|
|
246 }
|
|
247
|
|
248
|
|
249 struct sockaddr
|
|
250 {
|
|
251 ushort sa_family;
|
|
252 char[14] sa_data = [0];
|
|
253 }
|
|
254
|
|
255
|
|
256 struct hostent
|
|
257 {
|
|
258 char* h_name;
|
|
259 char** h_aliases;
|
|
260 version(Win32)
|
|
261 {
|
|
262 short h_addrtype;
|
|
263 short h_length;
|
|
264 }
|
|
265 else version(BsdSockets)
|
|
266 {
|
|
267 int h_addrtype;
|
|
268 int h_length;
|
|
269 }
|
|
270 char** h_addr_list;
|
|
271
|
|
272
|
|
273 char* h_addr()
|
|
274 {
|
|
275 return h_addr_list[0];
|
|
276 }
|
|
277 }
|
|
278
|
|
279
|
|
280 /*******************************************************************************
|
|
281
|
|
282 conversions for network byte-order
|
|
283
|
|
284 *******************************************************************************/
|
|
285
|
|
286 version(BigEndian)
|
|
287 {
|
|
288 ushort htons(ushort x)
|
|
289 {
|
|
290 return x;
|
|
291 }
|
|
292
|
|
293
|
|
294 uint htonl(uint x)
|
|
295 {
|
|
296 return x;
|
|
297 }
|
|
298 }
|
|
299 else version(LittleEndian)
|
|
300 {
|
|
301 import tango.core.BitManip;
|
|
302
|
|
303
|
|
304 ushort htons(ushort x)
|
|
305 {
|
|
306 return cast(ushort) ((x >> 8) | (x << 8));
|
|
307 }
|
|
308
|
|
309
|
|
310 uint htonl(uint x)
|
|
311 {
|
|
312 return bswap(x);
|
|
313 }
|
|
314 }
|
|
315 else
|
|
316 {
|
|
317 static assert(0);
|
|
318 }
|
|
319
|
|
320
|
|
321 ushort ntohs(ushort x)
|
|
322 {
|
|
323 return htons(x);
|
|
324 }
|
|
325
|
|
326
|
|
327 uint ntohl(uint x)
|
|
328 {
|
|
329 return htonl(x);
|
|
330 }
|
|
331
|
|
332
|
|
333 /*******************************************************************************
|
|
334
|
|
335
|
|
336 *******************************************************************************/
|
|
337
|
|
338 private extern (C) int strlen(char*);
|
|
339
|
|
340 private static char[] toString(char* s)
|
|
341 {
|
|
342 return s ? s[0 .. strlen(s)] : cast(char[])null;
|
|
343 }
|
|
344
|
|
345 private static char* convert2C (char[] input, char[] output)
|
|
346 {
|
|
347 output [0 .. input.length] = input;
|
|
348 output [input.length] = 0;
|
|
349 return output.ptr;
|
|
350 }
|
|
351
|
|
352
|
|
353 /*******************************************************************************
|
|
354
|
|
355 Public interface ...
|
|
356
|
|
357 *******************************************************************************/
|
|
358
|
|
359 public:
|
|
360
|
|
361
|
|
362 /*******************************************************************************
|
|
363
|
|
364
|
|
365 *******************************************************************************/
|
|
366
|
|
367 static int lastError ()
|
|
368 {
|
|
369 version (Win32)
|
|
370 {
|
|
371 return WSAGetLastError();
|
|
372 }
|
|
373 version (Posix)
|
|
374 {
|
|
375 return errno;
|
|
376 }
|
|
377 }
|
|
378
|
|
379
|
|
380 /***********************************************************************
|
|
381
|
|
382
|
|
383 ***********************************************************************/
|
|
384
|
|
385 version (Win32)
|
|
386 {
|
|
387 /***************************************************************
|
|
388
|
|
389
|
|
390 ***************************************************************/
|
|
391
|
|
392 enum SocketOption: int
|
|
393 {
|
|
394 //consistent
|
|
395 SO_DEBUG = 0x1,
|
|
396
|
|
397 //possibly Winsock-only values
|
|
398 SO_BROADCAST = 0x20,
|
|
399 SO_REUSEADDR = 0x4,
|
|
400 SO_LINGER = 0x80,
|
|
401 SO_DONTLINGER = ~(SO_LINGER),
|
|
402 SO_OOBINLINE = 0x100,
|
|
403 SO_SNDBUF = 0x1001,
|
|
404 SO_RCVBUF = 0x1002,
|
|
405 SO_ERROR = 0x1007,
|
|
406
|
|
407 SO_ACCEPTCONN = 0x2, // ?
|
|
408 SO_KEEPALIVE = 0x8, // ?
|
|
409 SO_DONTROUTE = 0x10, // ?
|
|
410 SO_TYPE = 0x1008, // ?
|
|
411
|
|
412 // OptionLevel.IP settings
|
|
413 IP_MULTICAST_TTL = 10,
|
|
414 IP_MULTICAST_LOOP = 11,
|
|
415 IP_ADD_MEMBERSHIP = 12,
|
|
416 IP_DROP_MEMBERSHIP = 13,
|
|
417
|
|
418 // OptionLevel.TCP settings
|
|
419 TCP_NODELAY = 0x0001,
|
|
420 }
|
|
421
|
|
422 /***************************************************************
|
|
423
|
|
424
|
|
425 ***************************************************************/
|
|
426
|
|
427 union linger
|
|
428 {
|
|
429 struct {
|
|
430 ushort l_onoff; // option on/off
|
|
431 ushort l_linger; // linger time
|
|
432 };
|
|
433 ushort[2] array; // combined
|
|
434 }
|
|
435
|
|
436 /***************************************************************
|
|
437
|
|
438
|
|
439 ***************************************************************/
|
|
440
|
|
441 enum SocketOptionLevel
|
|
442 {
|
|
443 SOCKET = 0xFFFF,
|
|
444 IP = 0,
|
|
445 TCP = 6,
|
|
446 UDP = 17,
|
|
447 }
|
|
448 }
|
|
449 else version (darwin)
|
|
450 {
|
|
451 enum SocketOption: int
|
|
452 {
|
|
453 SO_DEBUG = 0x0001, /* turn on debugging info recording */
|
|
454 SO_BROADCAST = 0x0020, /* permit sending of broadcast msgs */
|
|
455 SO_REUSEADDR = 0x0004, /* allow local address reuse */
|
|
456 SO_LINGER = 0x0080, /* linger on close if data present */
|
|
457 SO_DONTLINGER = ~(SO_LINGER),
|
|
458 SO_OOBINLINE = 0x0100, /* leave received OOB data in line */
|
|
459 SO_ACCEPTCONN = 0x0002, /* socket has had listen() */
|
|
460 SO_KEEPALIVE = 0x0008, /* keep connections alive */
|
|
461 SO_DONTROUTE = 0x0010, /* just use interface addresses */
|
|
462 SO_TYPE = 0x1008, /* get socket type */
|
|
463
|
|
464 /*
|
|
465 * Additional options, not kept in so_options.
|
|
466 */
|
|
467 SO_SNDBUF = 0x1001, /* send buffer size */
|
|
468 SO_RCVBUF = 0x1002, /* receive buffer size */
|
|
469 SO_ERROR = 0x1007, /* get error status and clear */
|
|
470
|
|
471 // OptionLevel.IP settings
|
|
472 IP_MULTICAST_TTL = 10,
|
|
473 IP_MULTICAST_LOOP = 11,
|
|
474 IP_ADD_MEMBERSHIP = 12,
|
|
475 IP_DROP_MEMBERSHIP = 13,
|
|
476
|
|
477 // OptionLevel.TCP settings
|
|
478 TCP_NODELAY = 0x0001,
|
|
479 }
|
|
480
|
|
481 /***************************************************************
|
|
482
|
|
483
|
|
484 ***************************************************************/
|
|
485
|
|
486 union linger
|
|
487 {
|
|
488 struct {
|
|
489 int l_onoff; // option on/off
|
|
490 int l_linger; // linger time
|
|
491 };
|
|
492 int[2] array; // combined
|
|
493 }
|
|
494
|
|
495 /***************************************************************
|
|
496
|
|
497 Question: are these correct for Darwin?
|
|
498
|
|
499 ***************************************************************/
|
|
500
|
|
501 enum SocketOptionLevel
|
|
502 {
|
|
503 SOCKET = 1, // correct for linux on x86
|
|
504 IP = 0, // appears to be correct
|
|
505 TCP = 6, // appears to be correct
|
|
506 UDP = 17, // appears to be correct
|
|
507 }
|
|
508 }
|
|
509 else version (linux)
|
|
510 {
|
|
511 /***************************************************************
|
|
512
|
|
513 these appear to be compatible with x86 platforms,
|
|
514 but not others!
|
|
515
|
|
516 ***************************************************************/
|
|
517
|
|
518 enum SocketOption: int
|
|
519 {
|
|
520 //consistent
|
|
521 SO_DEBUG = 1,
|
|
522 SO_BROADCAST = 6,
|
|
523 SO_REUSEADDR = 2,
|
|
524 SO_LINGER = 13,
|
|
525 SO_DONTLINGER = ~(SO_LINGER),
|
|
526 SO_OOBINLINE = 10,
|
|
527 SO_SNDBUF = 7,
|
|
528 SO_RCVBUF = 8,
|
|
529 SO_ERROR = 4,
|
|
530
|
|
531 SO_ACCEPTCONN = 30,
|
|
532 SO_KEEPALIVE = 9,
|
|
533 SO_DONTROUTE = 5,
|
|
534 SO_TYPE = 3,
|
|
535
|
|
536 // OptionLevel.IP settings
|
|
537 IP_MULTICAST_TTL = 33,
|
|
538 IP_MULTICAST_LOOP = 34,
|
|
539 IP_ADD_MEMBERSHIP = 35,
|
|
540 IP_DROP_MEMBERSHIP = 36,
|
|
541
|
|
542 // OptionLevel.TCP settings
|
|
543 TCP_NODELAY = 0x0001,
|
|
544 }
|
|
545
|
|
546 /***************************************************************
|
|
547
|
|
548
|
|
549 ***************************************************************/
|
|
550
|
|
551 union linger
|
|
552 {
|
|
553 struct {
|
|
554 int l_onoff; // option on/off
|
|
555 int l_linger; // linger time
|
|
556 };
|
|
557 int[2] array; // combined
|
|
558 }
|
|
559
|
|
560 /***************************************************************
|
|
561
|
|
562
|
|
563 ***************************************************************/
|
|
564
|
|
565 enum SocketOptionLevel
|
|
566 {
|
|
567 SOCKET = 1, // correct for linux on x86
|
|
568 IP = 0, // appears to be correct
|
|
569 TCP = 6, // appears to be correct
|
|
570 UDP = 17, // appears to be correct
|
|
571 }
|
|
572 } // end versioning
|
|
573
|
|
574 /***********************************************************************
|
|
575
|
|
576
|
|
577 ***********************************************************************/
|
|
578
|
|
579 enum SocketShutdown: int
|
|
580 {
|
|
581 RECEIVE = 0,
|
|
582 SEND = 1,
|
|
583 BOTH = 2,
|
|
584 }
|
|
585
|
|
586 /***********************************************************************
|
|
587
|
|
588
|
|
589 ***********************************************************************/
|
|
590
|
|
591 enum SocketFlags: int
|
|
592 {
|
|
593 NONE = 0,
|
|
594 OOB = 0x1, //out of band
|
|
595 PEEK = 0x02, //only for receiving
|
|
596 DONTROUTE = 0x04, //only for sending
|
|
597 }
|
|
598
|
|
599 /***********************************************************************
|
|
600
|
|
601 Communication semantics
|
|
602
|
|
603 ***********************************************************************/
|
|
604
|
|
605 enum SocketType: int
|
|
606 {
|
|
607 STREAM = 1, /// sequenced, reliable, two-way communication-based byte streams
|
|
608 DGRAM = 2, /// connectionless, unreliable datagrams with a fixed maximum length; data may be lost or arrive out of order
|
|
609 RAW = 3, /// raw protocol access
|
|
610 RDM = 4, /// reliably-delivered message datagrams
|
|
611 SEQPACKET = 5, /// sequenced, reliable, two-way connection-based datagrams with a fixed maximum length
|
|
612 }
|
|
613
|
|
614
|
|
615 /***********************************************************************
|
|
616
|
|
617 Protocol
|
|
618
|
|
619 ***********************************************************************/
|
|
620
|
|
621 enum ProtocolType: int
|
|
622 {
|
|
623 IP = 0, /// internet protocol version 4
|
|
624 ICMP = 1, /// internet control message protocol
|
|
625 IGMP = 2, /// internet group management protocol
|
|
626 GGP = 3, /// gateway to gateway protocol
|
|
627 TCP = 6, /// transmission control protocol
|
|
628 PUP = 12, /// PARC universal packet protocol
|
|
629 UDP = 17, /// user datagram protocol
|
|
630 IDP = 22, /// Xerox NS protocol
|
|
631 }
|
|
632
|
|
633
|
|
634 /***********************************************************************
|
|
635
|
|
636
|
|
637 ***********************************************************************/
|
|
638
|
|
639 version(Win32)
|
|
640 {
|
|
641 enum AddressFamily: int
|
|
642 {
|
|
643 UNSPEC = 0,
|
|
644 UNIX = 1,
|
|
645 INET = 2,
|
|
646 IPX = 6,
|
|
647 APPLETALK = 16,
|
|
648 //INET6 = ? // Need Windows XP ?
|
|
649 }
|
|
650 }
|
|
651 else version(BsdSockets)
|
|
652 {
|
|
653 version (darwin)
|
|
654 {
|
|
655 enum AddressFamily: int
|
|
656 {
|
|
657 UNSPEC = 0,
|
|
658 UNIX = 1,
|
|
659 INET = 2,
|
|
660 IPX = 23,
|
|
661 APPLETALK = 16,
|
|
662 //INET6 = 10,
|
|
663 }
|
|
664 }
|
|
665 else version (linux)
|
|
666 {
|
|
667 enum AddressFamily: int
|
|
668 {
|
|
669 UNSPEC = 0,
|
|
670 UNIX = 1,
|
|
671 INET = 2,
|
|
672 IPX = 4,
|
|
673 APPLETALK = 5,
|
|
674 //INET6 = 10,
|
|
675 }
|
|
676 } // end version
|
|
677 }
|
|
678
|
|
679
|
|
680
|
|
681 /*******************************************************************************
|
|
682
|
|
683 *******************************************************************************/
|
|
684
|
|
685 class Socket
|
|
686 {
|
|
687 socket_t sock;
|
|
688 SocketType type;
|
|
689 AddressFamily family;
|
|
690 ProtocolType protocol;
|
|
691
|
|
692 version(Win32)
|
|
693 private bool _blocking = false;
|
|
694
|
|
695 // For use with accept().
|
|
696 package this()
|
|
697 {
|
|
698 }
|
|
699
|
|
700
|
|
701 /**
|
|
702 * Describe a socket flavor. If a single protocol type exists to support
|
|
703 * this socket type within the address family, the ProtocolType may be
|
|
704 * omitted.
|
|
705 */
|
|
706 this(AddressFamily family, SocketType type, ProtocolType protocol, bool create=true)
|
|
707 {
|
|
708 this.type = type;
|
|
709 this.family = family;
|
|
710 this.protocol = protocol;
|
|
711 if (create)
|
|
712 initialize ();
|
|
713 }
|
|
714
|
|
715
|
|
716 /**
|
|
717 * Create or assign a socket
|
|
718 */
|
|
719 private void initialize (socket_t sock = sock.init)
|
|
720 {
|
|
721 if (this.sock)
|
|
722 this.detach;
|
|
723
|
|
724 if (sock is sock.init)
|
|
725 {
|
|
726 sock = cast(socket_t) socket(family, type, protocol);
|
|
727 if (sock is sock.init)
|
|
728 exception ("Unable to create socket: ");
|
|
729 }
|
|
730
|
|
731 this.sock = sock;
|
|
732 }
|
|
733
|
|
734 /***********************************************************************
|
|
735
|
|
736 Return the underlying OS handle of this Conduit
|
|
737
|
|
738 ***********************************************************************/
|
|
739
|
|
740 socket_t fileHandle ()
|
|
741 {
|
|
742 return sock;
|
|
743 }
|
|
744
|
|
745 /***********************************************************************
|
|
746
|
|
747 Is this socket still alive? A closed socket is considered to
|
|
748 be dead, but a shutdown socket is still alive.
|
|
749
|
|
750 ***********************************************************************/
|
|
751
|
|
752 bool isAlive()
|
|
753 {
|
|
754 int type, typesize = type.sizeof;
|
|
755 return getsockopt (sock, SocketOptionLevel.SOCKET,
|
|
756 SocketOption.SO_TYPE, cast(char*) &type,
|
|
757 &typesize) != SOCKET_ERROR;
|
|
758 }
|
|
759
|
|
760
|
|
761 /***********************************************************************
|
|
762
|
|
763
|
|
764 ***********************************************************************/
|
|
765
|
|
766 override char[] toString()
|
|
767 {
|
|
768 return "Socket";
|
|
769 }
|
|
770
|
|
771
|
|
772 /***********************************************************************
|
|
773
|
|
774 getter
|
|
775
|
|
776 ***********************************************************************/
|
|
777
|
|
778 bool blocking()
|
|
779 {
|
|
780 version(Win32)
|
|
781 {
|
|
782 return _blocking;
|
|
783 }
|
|
784 else version(BsdSockets)
|
|
785 {
|
|
786 return !(fcntl(sock, F_GETFL, 0) & O_NONBLOCK);
|
|
787 }
|
|
788 }
|
|
789
|
|
790
|
|
791 /***********************************************************************
|
|
792
|
|
793 setter
|
|
794
|
|
795 ***********************************************************************/
|
|
796
|
|
797 void blocking(bool byes)
|
|
798 {
|
|
799 version(Win32)
|
|
800 {
|
|
801 uint num = !byes;
|
|
802 if(SOCKET_ERROR == ioctlsocket(sock, FIONBIO, &num))
|
|
803 goto err;
|
|
804 _blocking = byes;
|
|
805 }
|
|
806 else version(BsdSockets)
|
|
807 {
|
|
808 int x = fcntl(sock, F_GETFL, 0);
|
|
809 if(byes)
|
|
810 x &= ~O_NONBLOCK;
|
|
811 else
|
|
812 x |= O_NONBLOCK;
|
|
813 if(SOCKET_ERROR == fcntl(sock, F_SETFL, x))
|
|
814 goto err;
|
|
815 }
|
|
816 return; //success
|
|
817
|
|
818 err:
|
|
819 exception("Unable to set socket blocking: ");
|
|
820 }
|
|
821
|
|
822
|
|
823 /***********************************************************************
|
|
824
|
|
825
|
|
826 ***********************************************************************/
|
|
827
|
|
828 AddressFamily addressFamily()
|
|
829 {
|
|
830 return family;
|
|
831 }
|
|
832
|
|
833
|
|
834 /***********************************************************************
|
|
835
|
|
836
|
|
837 ***********************************************************************/
|
|
838
|
|
839 Socket bind(Address addr)
|
|
840 {
|
|
841 if(SOCKET_ERROR == .bind (sock, addr.name(), addr.nameLen()))
|
|
842 exception ("Unable to bind socket: ");
|
|
843 return this;
|
|
844 }
|
|
845
|
|
846
|
|
847 /***********************************************************************
|
|
848
|
|
849
|
|
850 ***********************************************************************/
|
|
851
|
|
852 Socket connect(Address to)
|
|
853 {
|
|
854 if(SOCKET_ERROR == .connect (sock, to.name(), to.nameLen()))
|
|
855 {
|
|
856 if(!blocking)
|
|
857 {
|
|
858 version(Win32)
|
|
859 {
|
|
860 if(WSAEWOULDBLOCK == WSAGetLastError())
|
|
861 return this;
|
|
862 }
|
|
863 else version (Posix)
|
|
864 {
|
|
865 if(EINPROGRESS == errno)
|
|
866 return this;
|
|
867 }
|
|
868 else
|
|
869 {
|
|
870 static assert(0);
|
|
871 }
|
|
872 }
|
|
873 exception ("Unable to connect socket: ");
|
|
874 }
|
|
875 return this;
|
|
876 }
|
|
877
|
|
878
|
|
879 /***********************************************************************
|
|
880
|
|
881 need to bind() first
|
|
882
|
|
883 ***********************************************************************/
|
|
884
|
|
885 Socket listen(int backlog)
|
|
886 {
|
|
887 if(SOCKET_ERROR == .listen (sock, backlog))
|
|
888 exception ("Unable to listen on socket: ");
|
|
889 return this;
|
|
890 }
|
|
891
|
|
892 /**
|
|
893 * Accept an incoming connection. If the socket is blocking, accept
|
|
894 * waits for a connection request. Throws SocketAcceptException if unable
|
|
895 * to accept. See accepting for use with derived classes.
|
|
896 */
|
|
897 Socket accept ()
|
|
898 {
|
|
899 return accept (new Socket);
|
|
900 }
|
|
901
|
|
902 Socket accept (Socket target)
|
|
903 {
|
|
904 auto newsock = cast(socket_t).accept(sock, null, null); // DMD 0.101 error: found '(' when expecting ';' following 'statement
|
|
905 if (socket_t.init == newsock)
|
|
906 throw new SocketAcceptException("Unable to accept socket connection: " ~ SysError.lookup(lastError));
|
|
907
|
|
908 target.initialize (newsock);
|
|
909 version(Win32)
|
|
910 target._blocking = _blocking; //inherits blocking mode
|
|
911
|
|
912 target.protocol = protocol; //same protocol
|
|
913 target.family = family; //same family
|
|
914 target.type = type; //same type
|
|
915
|
|
916 return target; //return configured target
|
|
917 }
|
|
918
|
|
919 /***********************************************************************
|
|
920
|
|
921 The shutdown function shuts down the connection of the socket.
|
|
922 Depending on the argument value, it will:
|
|
923
|
|
924 - stop receiving data for this socket. If further data
|
|
925 arrives, it is rejected.
|
|
926
|
|
927 - stop trying to transmit data from this socket. Also
|
|
928 discards any data waiting to be sent. Stop looking for
|
|
929 acknowledgement of data already sent; don't retransmit
|
|
930 if any data is lost.
|
|
931
|
|
932 ***********************************************************************/
|
|
933
|
|
934 Socket shutdown(SocketShutdown how)
|
|
935 {
|
|
936 .shutdown (sock, how);
|
|
937 return this;
|
|
938 }
|
|
939
|
|
940
|
|
941 /***********************************************************************
|
|
942
|
|
943 Tango: added
|
|
944
|
|
945 ***********************************************************************/
|
|
946
|
|
947 Socket setLingerPeriod (int period)
|
|
948 {
|
|
949 linger l;
|
|
950
|
|
951 l.l_onoff = 1; //option on/off
|
|
952 l.l_linger = cast(ushort) period; //linger time
|
|
953
|
|
954 return setOption (SocketOptionLevel.SOCKET, SocketOption.SO_LINGER, l.array);
|
|
955 }
|
|
956
|
|
957
|
|
958 /***********************************************************************
|
|
959
|
|
960
|
|
961 Tango: added
|
|
962
|
|
963 ***********************************************************************/
|
|
964
|
|
965 Socket setAddressReuse (bool enabled)
|
|
966 {
|
|
967 int[1] x = enabled;
|
|
968 return setOption (SocketOptionLevel.SOCKET, SocketOption.SO_REUSEADDR, x);
|
|
969 }
|
|
970
|
|
971
|
|
972 /***********************************************************************
|
|
973
|
|
974
|
|
975 Tango: added
|
|
976
|
|
977 ***********************************************************************/
|
|
978
|
|
979 Socket setNoDelay (bool enabled)
|
|
980 {
|
|
981 int[1] x = enabled;
|
|
982 return setOption (SocketOptionLevel.TCP, SocketOption.TCP_NODELAY, x);
|
|
983 }
|
|
984
|
|
985
|
|
986 /***********************************************************************
|
|
987
|
|
988 Helper function to handle the adding and dropping of group
|
|
989 membership.
|
|
990
|
|
991 Tango: Added
|
|
992
|
|
993 ***********************************************************************/
|
|
994
|
|
995 void joinGroup (IPv4Address address, bool onOff)
|
|
996 {
|
|
997 assert (address, "Socket.joinGroup :: invalid null address");
|
|
998
|
|
999 struct ip_mreq
|
|
1000 {
|
|
1001 uint imr_multiaddr; /* IP multicast address of group */
|
|
1002 uint imr_interface; /* local IP address of interface */
|
|
1003 };
|
|
1004
|
|
1005 ip_mreq mrq;
|
|
1006
|
|
1007 auto option = (onOff) ? SocketOption.IP_ADD_MEMBERSHIP : SocketOption.IP_DROP_MEMBERSHIP;
|
|
1008 mrq.imr_interface = 0;
|
|
1009 mrq.imr_multiaddr = address.sin.sin_addr;
|
|
1010
|
|
1011 if (.setsockopt(sock, SocketOptionLevel.IP, option, &mrq, mrq.sizeof) == SOCKET_ERROR)
|
|
1012 exception ("Unable to perform multicast join: ");
|
|
1013 }
|
|
1014
|
|
1015
|
|
1016 /***********************************************************************
|
|
1017
|
|
1018 calling shutdown() before this is recommended for connection-
|
|
1019 oriented sockets
|
|
1020
|
|
1021 ***********************************************************************/
|
|
1022
|
|
1023 void detach ()
|
|
1024 {
|
|
1025 if (sock != sock.init)
|
|
1026 {
|
|
1027 version (TraceLinux)
|
|
1028 printf ("closing socket handle ...\n");
|
|
1029
|
|
1030 version(Win32)
|
|
1031 .closesocket (sock);
|
|
1032 else
|
|
1033 version(BsdSockets)
|
|
1034 .close (sock);
|
|
1035
|
|
1036 version (TraceLinux)
|
|
1037 printf ("socket handle closed\n");
|
|
1038
|
|
1039 sock = sock.init;
|
|
1040 }
|
|
1041 }
|
|
1042
|
|
1043 /***********************************************************************
|
|
1044
|
|
1045
|
|
1046 ***********************************************************************/
|
|
1047
|
|
1048 Address newFamilyObject ()
|
|
1049 {
|
|
1050 Address result;
|
|
1051 switch(family)
|
|
1052 {
|
|
1053 case AddressFamily.INET:
|
|
1054 result = new IPv4Address;
|
|
1055 break;
|
|
1056
|
|
1057 default:
|
|
1058 result = new UnknownAddress;
|
|
1059 }
|
|
1060 return result;
|
|
1061 }
|
|
1062
|
|
1063
|
|
1064 /***********************************************************************
|
|
1065
|
|
1066 Tango: added this to return the hostname
|
|
1067
|
|
1068 ***********************************************************************/
|
|
1069
|
|
1070 static char[] hostName ()
|
|
1071 {
|
|
1072 char[64] name;
|
|
1073
|
|
1074 if(SOCKET_ERROR == .gethostname (name.ptr, name.length))
|
|
1075 exception ("Unable to obtain host name: ");
|
|
1076 return name [0 .. strlen(name.ptr)].dup;
|
|
1077 }
|
|
1078
|
|
1079
|
|
1080 /***********************************************************************
|
|
1081
|
|
1082 Tango: added this to return the default host address (IPv4)
|
|
1083
|
|
1084 ***********************************************************************/
|
|
1085
|
|
1086 static uint hostAddress ()
|
|
1087 {
|
|
1088 NetHost ih = new NetHost;
|
|
1089
|
|
1090 char[] hostname = hostName();
|
|
1091 ih.getHostByName (hostname);
|
|
1092 assert (ih.addrList.length);
|
|
1093 return ih.addrList[0];
|
|
1094 }
|
|
1095
|
|
1096
|
|
1097 /***********************************************************************
|
|
1098
|
|
1099
|
|
1100 ***********************************************************************/
|
|
1101
|
|
1102 Address remoteAddress ()
|
|
1103 {
|
|
1104 Address addr = newFamilyObject ();
|
|
1105 int nameLen = addr.nameLen ();
|
|
1106 if(SOCKET_ERROR == .getpeername (sock, addr.name(), &nameLen))
|
|
1107 exception ("Unable to obtain remote socket address: ");
|
|
1108 assert (addr.addressFamily() == family);
|
|
1109 return addr;
|
|
1110 }
|
|
1111
|
|
1112
|
|
1113 /***********************************************************************
|
|
1114
|
|
1115
|
|
1116 ***********************************************************************/
|
|
1117
|
|
1118 Address localAddress ()
|
|
1119 {
|
|
1120 Address addr = newFamilyObject ();
|
|
1121 int nameLen = addr.nameLen();
|
|
1122 if(SOCKET_ERROR == .getsockname (sock, addr.name(), &nameLen))
|
|
1123 exception ("Unable to obtain local socket address: ");
|
|
1124 assert (addr.addressFamily() == family);
|
|
1125 return addr;
|
|
1126 }
|
|
1127
|
|
1128 /// Send or receive error code.
|
|
1129 const int ERROR = SOCKET_ERROR;
|
|
1130
|
|
1131
|
|
1132 /**
|
|
1133 * Send data on the connection. Returns the number of bytes actually
|
|
1134 * sent, or ERROR on failure. If the socket is blocking and there is no
|
|
1135 * buffer space left, send waits.
|
|
1136 */
|
|
1137 //returns number of bytes actually sent, or -1 on error
|
|
1138 int send(void[] buf, SocketFlags flags=SocketFlags.NONE)
|
|
1139 {
|
|
1140 return .send(sock, buf.ptr, buf.length, cast(int)flags);
|
|
1141 }
|
|
1142
|
|
1143 /**
|
|
1144 * Send data to a specific destination Address. If the destination address is not specified, a connection must have been made and that address is used. If the socket is blocking and there is no buffer space left, sendTo waits.
|
|
1145 */
|
|
1146 int sendTo(void[] buf, SocketFlags flags, Address to)
|
|
1147 {
|
|
1148 return .sendto(sock, buf.ptr, buf.length, cast(int)flags, to.name(), to.nameLen());
|
|
1149 }
|
|
1150
|
|
1151 /// ditto
|
|
1152 int sendTo(void[] buf, Address to)
|
|
1153 {
|
|
1154 return sendTo(buf, SocketFlags.NONE, to);
|
|
1155 }
|
|
1156
|
|
1157
|
|
1158 //assumes you connect()ed
|
|
1159 /// ditto
|
|
1160 int sendTo(void[] buf, SocketFlags flags=SocketFlags.NONE)
|
|
1161 {
|
|
1162 return .sendto(sock, buf.ptr, buf.length, cast(int)flags, null, 0);
|
|
1163 }
|
|
1164
|
|
1165
|
|
1166 /**
|
|
1167 * Receive data on the connection. Returns the number of bytes actually
|
|
1168 * received, 0 if the remote side has closed the connection, or ERROR on
|
|
1169 * failure. If the socket is blocking, receive waits until there is data
|
|
1170 * to be received.
|
|
1171 */
|
|
1172 //returns number of bytes actually received, 0 on connection closure, or -1 on error
|
|
1173 int receive(void[] buf, SocketFlags flags=SocketFlags.NONE)
|
|
1174 {
|
|
1175 if (!buf.length)
|
|
1176 badArg ("Socket.receive :: target buffer has 0 length");
|
|
1177
|
|
1178 return .recv(sock, buf.ptr, buf.length, cast(int)flags);
|
|
1179 }
|
|
1180
|
|
1181 /**
|
|
1182 * Receive data and get the remote endpoint Address. Returns the number of bytes actually received, 0 if the remote side has closed the connection, or ERROR on failure. If the socket is blocking, receiveFrom waits until there is data to be received.
|
|
1183 */
|
|
1184 int receiveFrom(void[] buf, SocketFlags flags, Address from)
|
|
1185 {
|
|
1186 if (!buf.length)
|
|
1187 badArg ("Socket.receiveFrom :: target buffer has 0 length");
|
|
1188
|
|
1189 assert(from.addressFamily() == family);
|
|
1190 int nameLen = from.nameLen();
|
|
1191 return .recvfrom(sock, buf.ptr, buf.length, cast(int)flags, from.name(), &nameLen);
|
|
1192 }
|
|
1193
|
|
1194
|
|
1195 /// ditto
|
|
1196 int receiveFrom(void[] buf, Address from)
|
|
1197 {
|
|
1198 return receiveFrom(buf, SocketFlags.NONE, from);
|
|
1199 }
|
|
1200
|
|
1201
|
|
1202 //assumes you connect()ed
|
|
1203 /// ditto
|
|
1204 int receiveFrom(void[] buf, SocketFlags flags = SocketFlags.NONE)
|
|
1205 {
|
|
1206 if (!buf.length)
|
|
1207 badArg ("Socket.receiveFrom :: target buffer has 0 length");
|
|
1208
|
|
1209 return .recvfrom(sock, buf.ptr, buf.length, cast(int)flags, null, null);
|
|
1210 }
|
|
1211
|
|
1212
|
|
1213 /***********************************************************************
|
|
1214
|
|
1215 returns the length, in bytes, of the actual result - very
|
|
1216 different from getsockopt()
|
|
1217
|
|
1218 ***********************************************************************/
|
|
1219
|
|
1220 int getOption (SocketOptionLevel level, SocketOption option, void[] result)
|
|
1221 {
|
|
1222 int len = result.length;
|
|
1223 if(SOCKET_ERROR == .getsockopt (sock, cast(int)level, cast(int)option, result.ptr, &len))
|
|
1224 exception ("Unable to get socket option: ");
|
|
1225 return len;
|
|
1226 }
|
|
1227
|
|
1228
|
|
1229 /***********************************************************************
|
|
1230
|
|
1231
|
|
1232 ***********************************************************************/
|
|
1233
|
|
1234 Socket setOption (SocketOptionLevel level, SocketOption option, void[] value)
|
|
1235 {
|
|
1236 if(SOCKET_ERROR == .setsockopt (sock, cast(int)level, cast(int)option, value.ptr, value.length))
|
|
1237 exception ("Unable to set socket option: ");
|
|
1238 return this;
|
|
1239 }
|
|
1240
|
|
1241
|
|
1242 /***********************************************************************
|
|
1243
|
|
1244 Tango: added this common function
|
|
1245
|
|
1246 ***********************************************************************/
|
|
1247
|
|
1248 protected static void exception (char[] msg)
|
|
1249 {
|
|
1250 throw new SocketException (msg ~ SysError.lookup(lastError));
|
|
1251 }
|
|
1252
|
|
1253
|
|
1254 /***********************************************************************
|
|
1255
|
|
1256 Tango: added this common function
|
|
1257
|
|
1258 ***********************************************************************/
|
|
1259
|
|
1260 protected static void badArg (char[] msg)
|
|
1261 {
|
|
1262 throw new IllegalArgumentException (msg);
|
|
1263 }
|
|
1264
|
|
1265
|
|
1266 /***********************************************************************
|
|
1267
|
|
1268 SocketSet's are updated to include only those sockets which an
|
|
1269 event occured.
|
|
1270
|
|
1271 Returns the number of events, 0 on timeout, or -1 on error
|
|
1272
|
|
1273 for a connect()ing socket, writeability means connected
|
|
1274 for a listen()ing socket, readability means listening
|
|
1275
|
|
1276 Winsock: possibly internally limited to 64 sockets per set
|
|
1277
|
|
1278 ***********************************************************************/
|
|
1279
|
|
1280 static int select (SocketSet checkRead, SocketSet checkWrite, SocketSet checkError, timeval* tv)
|
|
1281 in
|
|
1282 {
|
|
1283 //make sure none of the SocketSet's are the same object
|
|
1284 if(checkRead)
|
|
1285 {
|
|
1286 assert(checkRead !is checkWrite);
|
|
1287 assert(checkRead !is checkError);
|
|
1288 }
|
|
1289 if(checkWrite)
|
|
1290 {
|
|
1291 assert(checkWrite !is checkError);
|
|
1292 }
|
|
1293 }
|
|
1294 body
|
|
1295 {
|
|
1296 fd_set* fr, fw, fe;
|
|
1297
|
|
1298 version(Win32)
|
|
1299 {
|
|
1300 //Windows has a problem with empty fd_set's that aren't null
|
|
1301 fr = (checkRead && checkRead.count()) ? checkRead.toFd_set() : null;
|
|
1302 fw = (checkWrite && checkWrite.count()) ? checkWrite.toFd_set() : null;
|
|
1303 fe = (checkError && checkError.count()) ? checkError.toFd_set() : null;
|
|
1304 }
|
|
1305 else
|
|
1306 {
|
|
1307 fr = checkRead ? checkRead.toFd_set() : null;
|
|
1308 fw = checkWrite ? checkWrite.toFd_set() : null;
|
|
1309 fe = checkError ? checkError.toFd_set() : null;
|
|
1310 }
|
|
1311
|
|
1312 int result;
|
|
1313
|
|
1314 // Tango: if select() was interrupted, we now try again
|
|
1315 version(Win32)
|
|
1316 {
|
|
1317 while ((result = .select (socket_t.max - 1, fr, fw, fe, tv)) == -1)
|
|
1318 {
|
|
1319 if(WSAGetLastError() != WSAEINTR)
|
|
1320 break;
|
|
1321 }
|
|
1322 }
|
|
1323 else version (Posix)
|
|
1324 {
|
|
1325 socket_t maxfd = 0;
|
|
1326
|
|
1327 if (checkRead)
|
|
1328 maxfd = checkRead.maxfd;
|
|
1329
|
|
1330 if (checkWrite && checkWrite.maxfd > maxfd)
|
|
1331 maxfd = checkWrite.maxfd;
|
|
1332
|
|
1333 if (checkError && checkError.maxfd > maxfd)
|
|
1334 maxfd = checkError.maxfd;
|
|
1335
|
|
1336 while ((result = .select (maxfd + 1, fr, fw, fe, tv)) == -1)
|
|
1337 {
|
|
1338 if(errno() != EINTR)
|
|
1339 break;
|
|
1340 }
|
|
1341 }
|
|
1342 else
|
|
1343 {
|
|
1344 static assert(0);
|
|
1345 }
|
|
1346 // Tango: don't throw an exception here ... wait until we get
|
|
1347 // a bit further back along the control path
|
|
1348 //if(SOCKET_ERROR == result)
|
|
1349 // throw new SocketException("Socket select error.");
|
|
1350
|
|
1351 return result;
|
|
1352 }
|
|
1353
|
|
1354 /***********************************************************************
|
|
1355
|
|
1356 select with specified timeout
|
|
1357
|
|
1358 ***********************************************************************/
|
|
1359
|
|
1360 static int select (SocketSet checkRead, SocketSet checkWrite, SocketSet checkError, TimeSpan time)
|
|
1361 {
|
|
1362 auto tv = toTimeval (time);
|
|
1363 return select (checkRead, checkWrite, checkError, &tv);
|
|
1364 }
|
|
1365
|
|
1366 /***********************************************************************
|
|
1367
|
|
1368 select with maximum timeout
|
|
1369
|
|
1370 ***********************************************************************/
|
|
1371
|
|
1372 static int select (SocketSet checkRead, SocketSet checkWrite, SocketSet checkError)
|
|
1373 {
|
|
1374 return select (checkRead, checkWrite, checkError, null);
|
|
1375 }
|
|
1376
|
|
1377 /***********************************************************************
|
|
1378
|
|
1379 Handy utility for converting TimeSpan into timeval
|
|
1380
|
|
1381 ***********************************************************************/
|
|
1382
|
|
1383 static timeval toTimeval (TimeSpan time)
|
|
1384 {
|
|
1385 timeval tv;
|
|
1386 tv.tv_sec = cast(uint) time.seconds;
|
|
1387 tv.tv_usec = cast(uint) time.micros % 1_000_000;
|
|
1388 return tv;
|
|
1389 }
|
|
1390 }
|
|
1391
|
|
1392
|
|
1393
|
|
1394 /*******************************************************************************
|
|
1395
|
|
1396
|
|
1397 *******************************************************************************/
|
|
1398
|
|
1399 abstract class Address
|
|
1400 {
|
|
1401 protected sockaddr* name();
|
|
1402 protected int nameLen();
|
|
1403 AddressFamily addressFamily();
|
|
1404 char[] toString();
|
|
1405
|
|
1406 /***********************************************************************
|
|
1407
|
|
1408 Tango: added this common function
|
|
1409
|
|
1410 ***********************************************************************/
|
|
1411
|
|
1412 static void exception (char[] msg)
|
|
1413 {
|
|
1414 throw new AddressException (msg);
|
|
1415 }
|
|
1416
|
|
1417 }
|
|
1418
|
|
1419
|
|
1420 /*******************************************************************************
|
|
1421
|
|
1422
|
|
1423 *******************************************************************************/
|
|
1424
|
|
1425 class UnknownAddress: Address
|
|
1426 {
|
|
1427 protected:
|
|
1428 sockaddr sa;
|
|
1429
|
|
1430
|
|
1431 /***********************************************************************
|
|
1432
|
|
1433
|
|
1434 ***********************************************************************/
|
|
1435
|
|
1436 sockaddr* name()
|
|
1437 {
|
|
1438 return &sa;
|
|
1439 }
|
|
1440
|
|
1441
|
|
1442 /***********************************************************************
|
|
1443
|
|
1444
|
|
1445 ***********************************************************************/
|
|
1446
|
|
1447 int nameLen()
|
|
1448 {
|
|
1449 return sa.sizeof;
|
|
1450 }
|
|
1451
|
|
1452
|
|
1453 public:
|
|
1454 /***********************************************************************
|
|
1455
|
|
1456
|
|
1457 ***********************************************************************/
|
|
1458
|
|
1459 AddressFamily addressFamily()
|
|
1460 {
|
|
1461 return cast(AddressFamily) sa.sa_family;
|
|
1462 }
|
|
1463
|
|
1464
|
|
1465 /***********************************************************************
|
|
1466
|
|
1467
|
|
1468 ***********************************************************************/
|
|
1469
|
|
1470 char[] toString()
|
|
1471 {
|
|
1472 return "Unknown";
|
|
1473 }
|
|
1474 }
|
|
1475
|
|
1476
|
|
1477 /*******************************************************************************
|
|
1478
|
|
1479
|
|
1480 *******************************************************************************/
|
|
1481
|
|
1482 class NetHost
|
|
1483 {
|
|
1484 char[] name;
|
|
1485 char[][] aliases;
|
|
1486 uint[] addrList;
|
|
1487
|
|
1488
|
|
1489 /***********************************************************************
|
|
1490
|
|
1491
|
|
1492 ***********************************************************************/
|
|
1493
|
|
1494 protected void validHostent(hostent* he)
|
|
1495 {
|
|
1496 if(he.h_addrtype != cast(int)AddressFamily.INET || he.h_length != 4)
|
|
1497 throw new HostException("Address family mismatch.");
|
|
1498 }
|
|
1499
|
|
1500
|
|
1501 /***********************************************************************
|
|
1502
|
|
1503
|
|
1504 ***********************************************************************/
|
|
1505
|
|
1506 void populate(hostent* he)
|
|
1507 {
|
|
1508 int i;
|
|
1509 char* p;
|
|
1510
|
|
1511 name = .toString(he.h_name);
|
|
1512
|
|
1513 for(i = 0;; i++)
|
|
1514 {
|
|
1515 p = he.h_aliases[i];
|
|
1516 if(!p)
|
|
1517 break;
|
|
1518 }
|
|
1519
|
|
1520 if(i)
|
|
1521 {
|
|
1522 aliases = new char[][i];
|
|
1523 for(i = 0; i != aliases.length; i++)
|
|
1524 {
|
|
1525 aliases[i] = .toString(he.h_aliases[i]);
|
|
1526 }
|
|
1527 }
|
|
1528 else
|
|
1529 {
|
|
1530 aliases = null;
|
|
1531 }
|
|
1532
|
|
1533 for(i = 0;; i++)
|
|
1534 {
|
|
1535 p = he.h_addr_list[i];
|
|
1536 if(!p)
|
|
1537 break;
|
|
1538 }
|
|
1539
|
|
1540 if(i)
|
|
1541 {
|
|
1542 addrList = new uint[i];
|
|
1543 for(i = 0; i != addrList.length; i++)
|
|
1544 {
|
|
1545 addrList[i] = ntohl(*(cast(uint*)he.h_addr_list[i]));
|
|
1546 }
|
|
1547 }
|
|
1548 else
|
|
1549 {
|
|
1550 addrList = null;
|
|
1551 }
|
|
1552 }
|
|
1553
|
|
1554
|
|
1555 /***********************************************************************
|
|
1556
|
|
1557
|
|
1558 ***********************************************************************/
|
|
1559
|
|
1560 synchronized bool getHostByName(char[] name)
|
|
1561 {
|
|
1562 char[1024] tmp;
|
|
1563
|
|
1564 hostent* he = gethostbyname(convert2C (name, tmp));
|
|
1565 if(!he)
|
|
1566 return false;
|
|
1567 validHostent(he);
|
|
1568 populate(he);
|
|
1569 return true;
|
|
1570 }
|
|
1571
|
|
1572
|
|
1573 /***********************************************************************
|
|
1574
|
|
1575
|
|
1576 ***********************************************************************/
|
|
1577
|
|
1578 synchronized bool getHostByAddr(uint addr)
|
|
1579 {
|
|
1580 uint x = htonl(addr);
|
|
1581 hostent* he = gethostbyaddr(&x, 4, cast(int)AddressFamily.INET);
|
|
1582 if(!he)
|
|
1583 return false;
|
|
1584 validHostent(he);
|
|
1585 populate(he);
|
|
1586 return true;
|
|
1587 }
|
|
1588
|
|
1589
|
|
1590 /***********************************************************************
|
|
1591
|
|
1592
|
|
1593 ***********************************************************************/
|
|
1594
|
|
1595 //shortcut
|
|
1596 synchronized bool getHostByAddr(char[] addr)
|
|
1597 {
|
|
1598 char[64] tmp;
|
|
1599
|
|
1600 uint x = inet_addr(convert2C (addr, tmp));
|
|
1601 hostent* he = gethostbyaddr(&x, 4, cast(int)AddressFamily.INET);
|
|
1602 if(!he)
|
|
1603 return false;
|
|
1604 validHostent(he);
|
|
1605 populate(he);
|
|
1606 return true;
|
|
1607 }
|
|
1608 }
|
|
1609
|
|
1610
|
|
1611 debug (UnitText)
|
|
1612 {
|
|
1613 extern (C) int printf(char*, ...);
|
|
1614 unittest
|
|
1615 {
|
|
1616 try
|
|
1617 {
|
|
1618 NetHost ih = new NetHost;
|
|
1619 ih.getHostByName(Socket.hostName());
|
|
1620 assert(ih.addrList.length > 0);
|
|
1621 IPv4Address ia = new IPv4Address(ih.addrList[0], IPv4Address.PORT_ANY);
|
|
1622 printf("IP address = %.*s\nname = %.*s\n", ia.toAddrString(), ih.name);
|
|
1623 foreach(int i, char[] s; ih.aliases)
|
|
1624 {
|
|
1625 printf("aliases[%d] = %.*s\n", i, s);
|
|
1626 }
|
|
1627
|
|
1628 printf("---\n");
|
|
1629
|
|
1630 assert(ih.getHostByAddr(ih.addrList[0]));
|
|
1631 printf("name = %.*s\n", ih.name);
|
|
1632 foreach(int i, char[] s; ih.aliases)
|
|
1633 {
|
|
1634 printf("aliases[%d] = %.*s\n", i, s);
|
|
1635 }
|
|
1636 }
|
|
1637 catch( Object o )
|
|
1638 {
|
|
1639 assert( false );
|
|
1640 }
|
|
1641 }
|
|
1642 }
|
|
1643
|
|
1644
|
|
1645 /*******************************************************************************
|
|
1646
|
|
1647
|
|
1648 *******************************************************************************/
|
|
1649
|
|
1650 class IPv4Address: Address
|
|
1651 {
|
|
1652 protected:
|
|
1653 char[8] _port;
|
|
1654
|
|
1655 /***********************************************************************
|
|
1656
|
|
1657
|
|
1658 ***********************************************************************/
|
|
1659
|
|
1660 struct sockaddr_in
|
|
1661 {
|
|
1662 ushort sinfamily = AddressFamily.INET;
|
|
1663 ushort sin_port;
|
|
1664 uint sin_addr; //in_addr
|
|
1665 char[8] sin_zero = [0];
|
|
1666 }
|
|
1667
|
|
1668 sockaddr_in sin;
|
|
1669
|
|
1670
|
|
1671 /***********************************************************************
|
|
1672
|
|
1673
|
|
1674 ***********************************************************************/
|
|
1675
|
|
1676 sockaddr* name()
|
|
1677 {
|
|
1678 return cast(sockaddr*)&sin;
|
|
1679 }
|
|
1680
|
|
1681
|
|
1682 /***********************************************************************
|
|
1683
|
|
1684
|
|
1685 ***********************************************************************/
|
|
1686
|
|
1687 int nameLen()
|
|
1688 {
|
|
1689 return sin.sizeof;
|
|
1690 }
|
|
1691
|
|
1692
|
|
1693 public:
|
|
1694
|
|
1695 /***********************************************************************
|
|
1696
|
|
1697
|
|
1698 ***********************************************************************/
|
|
1699
|
|
1700 this()
|
|
1701 {
|
|
1702 }
|
|
1703
|
|
1704
|
|
1705 const uint ADDR_ANY = 0;
|
|
1706 const uint ADDR_NONE = cast(uint)-1;
|
|
1707 const ushort PORT_ANY = 0;
|
|
1708
|
|
1709
|
|
1710 /***********************************************************************
|
|
1711
|
|
1712
|
|
1713 ***********************************************************************/
|
|
1714
|
|
1715 AddressFamily addressFamily()
|
|
1716 {
|
|
1717 return AddressFamily.INET;
|
|
1718 }
|
|
1719
|
|
1720
|
|
1721 /***********************************************************************
|
|
1722
|
|
1723
|
|
1724 ***********************************************************************/
|
|
1725
|
|
1726 ushort port()
|
|
1727 {
|
|
1728 return ntohs(sin.sin_port);
|
|
1729 }
|
|
1730
|
|
1731
|
|
1732 /***********************************************************************
|
|
1733
|
|
1734
|
|
1735 ***********************************************************************/
|
|
1736
|
|
1737 uint addr()
|
|
1738 {
|
|
1739 return ntohl(sin.sin_addr);
|
|
1740 }
|
|
1741
|
|
1742
|
|
1743 /***********************************************************************
|
|
1744
|
|
1745 -port- can be PORT_ANY
|
|
1746 -addr- is an IP address or host name
|
|
1747
|
|
1748 ***********************************************************************/
|
|
1749
|
|
1750 this(char[] addr, int port = PORT_ANY)
|
|
1751 {
|
|
1752 uint uiaddr = parse(addr);
|
|
1753 if(ADDR_NONE == uiaddr)
|
|
1754 {
|
|
1755 NetHost ih = new NetHost;
|
|
1756 if(!ih.getHostByName(addr))
|
|
1757 exception ("Unable to resolve '"~addr~"': ");
|
|
1758 uiaddr = ih.addrList[0];
|
|
1759 }
|
|
1760 sin.sin_addr = htonl(uiaddr);
|
|
1761 sin.sin_port = htons(cast(ushort) port);
|
|
1762 }
|
|
1763
|
|
1764
|
|
1765 /***********************************************************************
|
|
1766
|
|
1767
|
|
1768 ***********************************************************************/
|
|
1769
|
|
1770 this(uint addr, ushort port)
|
|
1771 {
|
|
1772 sin.sin_addr = htonl(addr);
|
|
1773 sin.sin_port = htons(port);
|
|
1774 }
|
|
1775
|
|
1776
|
|
1777 /***********************************************************************
|
|
1778
|
|
1779
|
|
1780 ***********************************************************************/
|
|
1781
|
|
1782 this(ushort port)
|
|
1783 {
|
|
1784 sin.sin_addr = 0; //any, "0.0.0.0"
|
|
1785 sin.sin_port = htons(port);
|
|
1786 }
|
|
1787
|
|
1788 /***********************************************************************
|
|
1789
|
|
1790
|
|
1791 ***********************************************************************/
|
|
1792
|
|
1793 synchronized char[] toAddrString()
|
|
1794 {
|
|
1795 return .toString(inet_ntoa(sin.sin_addr)).dup;
|
|
1796 }
|
|
1797
|
|
1798
|
|
1799 /***********************************************************************
|
|
1800
|
|
1801
|
|
1802 ***********************************************************************/
|
|
1803
|
|
1804 char[] toPortString()
|
|
1805 {
|
|
1806 return .toString (_port, port());
|
|
1807 }
|
|
1808
|
|
1809
|
|
1810 /***********************************************************************
|
|
1811
|
|
1812
|
|
1813 ***********************************************************************/
|
|
1814
|
|
1815 char[] toString()
|
|
1816 {
|
|
1817 return toAddrString() ~ ":" ~ toPortString();
|
|
1818 }
|
|
1819
|
|
1820
|
|
1821 /***********************************************************************
|
|
1822
|
|
1823 -addr- is an IP address in the format "a.b.c.d"
|
|
1824 returns ADDR_NONE on failure
|
|
1825
|
|
1826 ***********************************************************************/
|
|
1827
|
|
1828 static uint parse(char[] addr)
|
|
1829 {
|
|
1830 char[64] tmp;
|
|
1831
|
|
1832 return ntohl(inet_addr(convert2C (addr, tmp)));
|
|
1833 }
|
|
1834 }
|
|
1835
|
|
1836 debug(Unittest)
|
|
1837 {
|
|
1838 unittest
|
|
1839 {
|
|
1840 IPv4Address ia = new IPv4Address("63.105.9.61", 80);
|
|
1841 assert(ia.toString() == "63.105.9.61:80");
|
|
1842 }
|
|
1843 }
|
|
1844
|
|
1845 /*******************************************************************************
|
|
1846
|
|
1847
|
|
1848 *******************************************************************************/
|
|
1849
|
|
1850 //a set of sockets for Socket.select()
|
|
1851 class SocketSet
|
|
1852 {
|
|
1853 // private:
|
|
1854 private uint nbytes; //Win32: excludes uint.size "count"
|
|
1855 private byte* buf;
|
|
1856
|
|
1857
|
|
1858 version(Win32)
|
|
1859 {
|
|
1860 uint count()
|
|
1861 {
|
|
1862 return *(cast(uint*)buf);
|
|
1863 }
|
|
1864
|
|
1865
|
|
1866 void count(int setter)
|
|
1867 {
|
|
1868 *(cast(uint*)buf) = setter;
|
|
1869 }
|
|
1870
|
|
1871
|
|
1872 socket_t* first()
|
|
1873 {
|
|
1874 return cast(socket_t*)(buf + uint.sizeof);
|
|
1875 }
|
|
1876 }
|
|
1877 else version (Posix)
|
|
1878 {
|
|
1879 import tango.core.BitManip;
|
|
1880
|
|
1881
|
|
1882 uint nfdbits;
|
|
1883 socket_t _maxfd = 0;
|
|
1884
|
|
1885 uint fdelt(socket_t s)
|
|
1886 {
|
|
1887 return cast(uint)s / nfdbits;
|
|
1888 }
|
|
1889
|
|
1890
|
|
1891 uint fdmask(socket_t s)
|
|
1892 {
|
|
1893 return 1 << cast(uint)s % nfdbits;
|
|
1894 }
|
|
1895
|
|
1896
|
|
1897 uint* first()
|
|
1898 {
|
|
1899 return cast(uint*)buf;
|
|
1900 }
|
|
1901
|
|
1902 public socket_t maxfd()
|
|
1903 {
|
|
1904 return _maxfd;
|
|
1905 }
|
|
1906 }
|
|
1907
|
|
1908
|
|
1909 public:
|
|
1910 /***********************************************************************
|
|
1911
|
|
1912
|
|
1913 ***********************************************************************/
|
|
1914
|
|
1915 this(uint max)
|
|
1916 {
|
|
1917 version(Win32)
|
|
1918 {
|
|
1919 nbytes = max * socket_t.sizeof;
|
|
1920 buf = (new byte[nbytes + uint.sizeof]).ptr;
|
|
1921 count = 0;
|
|
1922 }
|
|
1923 else version (Posix)
|
|
1924 {
|
|
1925 if(max <= 32)
|
|
1926 nbytes = 32 * uint.sizeof;
|
|
1927 else
|
|
1928 nbytes = max * uint.sizeof;
|
|
1929 buf = (new byte[nbytes]).ptr;
|
|
1930 nfdbits = nbytes * 8;
|
|
1931 //clear(); //new initializes to 0
|
|
1932 }
|
|
1933 else
|
|
1934 {
|
|
1935 static assert(0);
|
|
1936 }
|
|
1937 }
|
|
1938
|
|
1939
|
|
1940 /***********************************************************************
|
|
1941
|
|
1942
|
|
1943 ***********************************************************************/
|
|
1944
|
|
1945 this()
|
|
1946 {
|
|
1947 version(Win32)
|
|
1948 {
|
|
1949 this(64);
|
|
1950 }
|
|
1951 else version (Posix)
|
|
1952 {
|
|
1953 this(32);
|
|
1954 }
|
|
1955 else
|
|
1956 {
|
|
1957 static assert(0);
|
|
1958 }
|
|
1959 }
|
|
1960
|
|
1961
|
|
1962 /***********************************************************************
|
|
1963
|
|
1964
|
|
1965 ***********************************************************************/
|
|
1966
|
|
1967 void reset()
|
|
1968 {
|
|
1969 version(Win32)
|
|
1970 {
|
|
1971 count = 0;
|
|
1972 }
|
|
1973 else version (Posix)
|
|
1974 {
|
|
1975 buf[0 .. nbytes] = 0;
|
|
1976 _maxfd = 0;
|
|
1977 }
|
|
1978 else
|
|
1979 {
|
|
1980 static assert(0);
|
|
1981 }
|
|
1982 }
|
|
1983
|
|
1984
|
|
1985 /***********************************************************************
|
|
1986
|
|
1987
|
|
1988 ***********************************************************************/
|
|
1989
|
|
1990 void add(socket_t s)
|
|
1991 in
|
|
1992 {
|
|
1993 version(Win32)
|
|
1994 {
|
|
1995 assert(count < max); //added too many sockets; specify a higher max in the constructor
|
|
1996 }
|
|
1997 }
|
|
1998 body
|
|
1999 {
|
|
2000 version(Win32)
|
|
2001 {
|
|
2002 uint c = count;
|
|
2003 first[c] = s;
|
|
2004 count = c + 1;
|
|
2005 }
|
|
2006 else version (Posix)
|
|
2007 {
|
|
2008 if (s > _maxfd)
|
|
2009 _maxfd = s;
|
|
2010
|
|
2011 bts(cast(uint*)&first[fdelt(s)], cast(uint)s % nfdbits);
|
|
2012 }
|
|
2013 else
|
|
2014 {
|
|
2015 static assert(0);
|
|
2016 }
|
|
2017 }
|
|
2018
|
|
2019
|
|
2020 /***********************************************************************
|
|
2021
|
|
2022
|
|
2023 ***********************************************************************/
|
|
2024
|
|
2025 void add(Socket s)
|
|
2026 {
|
|
2027 add(s.sock);
|
|
2028 }
|
|
2029
|
|
2030
|
|
2031 /***********************************************************************
|
|
2032
|
|
2033
|
|
2034 ***********************************************************************/
|
|
2035
|
|
2036 void remove(socket_t s)
|
|
2037 {
|
|
2038 version(Win32)
|
|
2039 {
|
|
2040 uint c = count;
|
|
2041 socket_t* start = first;
|
|
2042 socket_t* stop = start + c;
|
|
2043
|
|
2044 for(; start != stop; start++)
|
|
2045 {
|
|
2046 if(*start == s)
|
|
2047 goto found;
|
|
2048 }
|
|
2049 return; //not found
|
|
2050
|
|
2051 found:
|
|
2052 for(++start; start != stop; start++)
|
|
2053 {
|
|
2054 *(start - 1) = *start;
|
|
2055 }
|
|
2056
|
|
2057 count = c - 1;
|
|
2058 }
|
|
2059 else version (Posix)
|
|
2060 {
|
|
2061 btr(cast(uint*)&first[fdelt(s)], cast(uint)s % nfdbits);
|
|
2062
|
|
2063 // If we're removing the biggest file descriptor we've
|
|
2064 // entered so far we need to recalculate this value
|
|
2065 // for the socket set.
|
|
2066 if (s == _maxfd)
|
|
2067 {
|
|
2068 while (--_maxfd >= 0)
|
|
2069 {
|
|
2070 if (isSet(_maxfd))
|
|
2071 {
|
|
2072 break;
|
|
2073 }
|
|
2074 }
|
|
2075 }
|
|
2076 }
|
|
2077 else
|
|
2078 {
|
|
2079 static assert(0);
|
|
2080 }
|
|
2081 }
|
|
2082
|
|
2083
|
|
2084 /***********************************************************************
|
|
2085
|
|
2086
|
|
2087 ***********************************************************************/
|
|
2088
|
|
2089 void remove(Socket s)
|
|
2090 {
|
|
2091 remove(s.sock);
|
|
2092 }
|
|
2093
|
|
2094
|
|
2095 /***********************************************************************
|
|
2096
|
|
2097
|
|
2098 ***********************************************************************/
|
|
2099
|
|
2100 int isSet(socket_t s)
|
|
2101 {
|
|
2102 version(Win32)
|
|
2103 {
|
|
2104 socket_t* start = first;
|
|
2105 socket_t* stop = start + count;
|
|
2106
|
|
2107 for(; start != stop; start++)
|
|
2108 {
|
|
2109 if(*start == s)
|
|
2110 return true;
|
|
2111 }
|
|
2112 return false;
|
|
2113 }
|
|
2114 else version (Posix)
|
|
2115 {
|
|
2116 //return bt(cast(uint*)&first[fdelt(s)], cast(uint)s % nfdbits);
|
|
2117 int index = cast(uint)s % nfdbits;
|
|
2118 return (cast(uint*)&first[fdelt(s)])[index / (uint.sizeof*8)] & (1 << (index & ((uint.sizeof*8) - 1)));
|
|
2119 }
|
|
2120 else
|
|
2121 {
|
|
2122 static assert(0);
|
|
2123 }
|
|
2124 }
|
|
2125
|
|
2126
|
|
2127 /***********************************************************************
|
|
2128
|
|
2129
|
|
2130 ***********************************************************************/
|
|
2131
|
|
2132 int isSet(Socket s)
|
|
2133 {
|
|
2134 return isSet(s.sock);
|
|
2135 }
|
|
2136
|
|
2137
|
|
2138 /***********************************************************************
|
|
2139
|
|
2140 max sockets that can be added, like FD_SETSIZE
|
|
2141
|
|
2142 ***********************************************************************/
|
|
2143
|
|
2144 uint max()
|
|
2145 {
|
|
2146 return nbytes / socket_t.sizeof;
|
|
2147 }
|
|
2148
|
|
2149
|
|
2150 /***********************************************************************
|
|
2151
|
|
2152
|
|
2153 ***********************************************************************/
|
|
2154
|
|
2155 fd_set* toFd_set()
|
|
2156 {
|
|
2157 return cast(fd_set*)buf;
|
|
2158 }
|
|
2159 }
|
|
2160
|