comparison lphobos/std/socket.d @ 473:373489eeaf90

Applied downs' lphobos update
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Mon, 04 Aug 2008 19:28:49 +0200
parents
children 88e23f8c2354
comparison
equal deleted inserted replaced
472:15c804b6ce77 473:373489eeaf90
1 // Written in the D programming language
2
3 /*
4 Copyright (C) 2004-2005 Christopher E. Miller
5
6 This software is provided 'as-is', without any express or implied
7 warranty. In no event will the authors be held liable for any damages
8 arising from the use of this software.
9
10 Permission is granted to anyone to use this software for any purpose,
11 including commercial applications, and to alter it and redistribute it
12 freely, subject to the following restrictions:
13
14 1. The origin of this software must not be misrepresented; you must not
15 claim that you wrote the original software. If you use this software
16 in a product, an acknowledgment in the product documentation would be
17 appreciated but is not required.
18 2. Altered source versions must be plainly marked as such, and must not
19 be misrepresented as being the original software.
20 3. This notice may not be removed or altered from any source
21 distribution.
22
23 socket.d 1.3
24 Jan 2005
25
26 Thanks to Benjamin Herr for his assistance.
27 */
28
29 /* NOTE: This file has been patched from the original DMD distribution to
30 work with the GDC compiler.
31
32 Modified by David Friedman, April 2005
33 */
34
35 /**
36 * Notes: For Win32 systems, link with ws2_32.lib.
37 * Example: See /dmd/samples/d/listener.d.
38 * Authors: Christopher E. Miller
39 * Macros:
40 * WIKI=Phobos/StdSocket
41 */
42
43 module std.socket;
44
45 private import std.string, std.stdint, std.c.string, std.c.stdlib;
46
47
48 version(Unix) version = BsdSockets;
49
50 version (skyos) { /* nothging */ }
51 else
52 {
53 version = have_getservbyport;
54 version = have_getprotobynumber;
55 }
56
57
58 version(Win32)
59 {
60 private import std.c.windows.windows, std.c.windows.winsock;
61 private alias std.c.windows.winsock.timeval _ctimeval;
62
63 typedef SOCKET socket_t = INVALID_SOCKET;
64 private const int _SOCKET_ERROR = SOCKET_ERROR;
65
66
67 private int _lasterr()
68 {
69 return WSAGetLastError();
70 }
71 }
72 else version(BsdSockets)
73 {
74 version (Unix)
75 {
76 version(linux) {
77 import std.c.linux.socket, std.c.linux.linux;
78 const AF_UNSPEC=0, AF_UNIX=1, AF_INET=2, AF_IPX=4, AF_APPLETALK=5;
79 const MSG_NOSIGNAL=16384;
80 const FD_SETSIZE=64;
81 alias std.c.linux.linux.timeval _ctimeval;
82 } else {
83 import std.c.unix.unix;
84 alias std.c.unix.unix.timeval _ctimeval;
85 }
86 }
87
88 typedef int32_t socket_t = -1;
89 private const int _SOCKET_ERROR = -1;
90
91
92 private int _lasterr()
93 {
94 return getErrno();
95 }
96 }
97 else
98 {
99 static assert(0); // No socket support yet.
100 }
101
102
103 extern(C) char* strerror_r(int errnum, char* buf, size_t buflen);
104 /// Base exception thrown from a Socket.
105 class SocketException: Exception
106 {
107 int errorCode; /// Platform-specific error code.
108
109 this(string msg, int err = 0)
110 {
111 errorCode = err;
112
113 version(Unix)
114 {
115 if(errorCode > 0)
116 {
117 char[80] buf;
118 auto cs = strerror_r(errorCode, buf.ptr, buf.length);
119 auto len = strlen(cs);
120
121 if(cs[len - 1] == '\n')
122 len--;
123 if(cs[len - 1] == '\r')
124 len--;
125 msg = msg ~ ": " ~ cs[0 .. len];
126 }
127 }
128
129 super(msg);
130 }
131 }
132
133
134 static this()
135 {
136 version(Win32)
137 {
138 WSADATA wd;
139
140 // Winsock will still load if an older version is present.
141 // The version is just a request.
142 int val;
143 val = WSAStartup(0x2020, &wd);
144 if(val) // Request Winsock 2.2 for IPv6.
145 throw new SocketException("Unable to initialize socket library", val);
146 }
147 }
148
149
150 static ~this()
151 {
152 version(Win32)
153 {
154 WSACleanup();
155 }
156 }
157
158 /**
159 * The communication domain used to resolve an address.
160 */
161 enum AddressFamily: int
162 {
163 UNSPEC = AF_UNSPEC, ///
164 UNIX = AF_UNIX, /// local communication
165 INET = AF_INET, /// internet protocol version 4
166 IPX = AF_IPX, /// novell IPX
167 APPLETALK = AF_APPLETALK, /// appletalk
168 INET6 = AF_INET6, // internet protocol version 6
169 }
170
171
172 /**
173 * Communication semantics
174 */
175 enum SocketType: int
176 {
177 STREAM = SOCK_STREAM, /// sequenced, reliable, two-way communication-based byte streams
178 DGRAM = SOCK_DGRAM, /// connectionless, unreliable datagrams with a fixed maximum length; data may be lost or arrive out of order
179 RAW = SOCK_RAW, /// raw protocol access
180 RDM = SOCK_RDM, /// reliably-delivered message datagrams
181 SEQPACKET = SOCK_SEQPACKET, /// sequenced, reliable, two-way connection-based datagrams with a fixed maximum length
182 }
183
184
185 /**
186 * Protocol
187 */
188 enum ProtocolType: int
189 {
190 IP = IPPROTO_IP, /// internet protocol version 4
191 ICMP = IPPROTO_ICMP, /// internet control message protocol
192 IGMP = IPPROTO_IGMP, /// internet group management protocol
193 GGP = IPPROTO_GGP, /// gateway to gateway protocol
194 TCP = IPPROTO_TCP, /// transmission control protocol
195 PUP = IPPROTO_PUP, /// PARC universal packet protocol
196 UDP = IPPROTO_UDP, /// user datagram protocol
197 IDP = IPPROTO_IDP, /// Xerox NS protocol
198 IPV6 = IPPROTO_IPV6, /// internet protocol version 6
199 }
200
201
202 /**
203 * Protocol is a class for retrieving protocol information.
204 */
205 class Protocol
206 {
207 ProtocolType type; /// These members are populated when one of the following functions are called without failure:
208 string name; /// ditto
209 string[] aliases; /// ditto
210
211
212 void populate(protoent* proto)
213 {
214 type = cast(ProtocolType)proto.p_proto;
215 name = std.string.toString(proto.p_name).dup;
216
217 int i;
218 for(i = 0;; i++)
219 {
220 if(!proto.p_aliases[i])
221 break;
222 }
223
224 if(i)
225 {
226 aliases = new string[i];
227 for(i = 0; i != aliases.length; i++)
228 {
229 aliases[i] = std.string.toString(proto.p_aliases[i]).dup;
230 }
231 }
232 else
233 {
234 aliases = null;
235 }
236 }
237
238 /** Returns false on failure */
239 bool getProtocolByName(string name)
240 {
241 protoent* proto;
242 proto = getprotobyname(toStringz(name));
243 if(!proto)
244 return false;
245 populate(proto);
246 return true;
247 }
248
249
250 /** Returns false on failure */
251 // Same as getprotobynumber().
252 bool getProtocolByType(ProtocolType type)
253 {
254 version (have_getprotobynumber)
255 {
256 protoent* proto;
257 proto = getprotobynumber(type);
258 if(!proto)
259 return false;
260 populate(proto);
261 return true;
262 }
263 else
264 return false;
265 }
266 }
267
268
269 unittest
270 {
271 Protocol proto = new Protocol;
272 assert(proto.getProtocolByType(ProtocolType.TCP));
273 printf("About protocol TCP:\n\tName: %.*s\n",
274 cast(int) proto.name.length, proto.name.ptr);
275 foreach(string s; proto.aliases)
276 {
277 printf("\tAlias: %.*s\n", cast(int) s.length, s.ptr);
278 }
279 }
280
281
282 /**
283 * Service is a class for retrieving service information.
284 */
285 class Service
286 {
287 /** These members are populated when one of the following functions are called without failure: */
288 string name;
289 string[] aliases; /// ditto
290 ushort port; /// ditto
291 string protocolName; /// ditto
292
293
294 void populate(servent* serv)
295 {
296 name = std.string.toString(serv.s_name).dup;
297 port = ntohs(cast(ushort)serv.s_port);
298 protocolName = std.string.toString(serv.s_proto).dup;
299
300 int i;
301 for(i = 0;; i++)
302 {
303 if(!serv.s_aliases[i])
304 break;
305 }
306
307 if(i)
308 {
309 aliases = new string[i];
310 for(i = 0; i != aliases.length; i++)
311 {
312 aliases[i] = std.string.toString(serv.s_aliases[i]).dup;
313 }
314 }
315 else
316 {
317 aliases = null;
318 }
319 }
320
321 /**
322 * If a protocol name is omitted, any protocol will be matched.
323 * Returns: false on failure.
324 */
325 bool getServiceByName(string name, string protocolName)
326 {
327 servent* serv;
328 serv = getservbyname(toStringz(name), toStringz(protocolName));
329 if(!serv)
330 return false;
331 populate(serv);
332 return true;
333 }
334
335
336 // Any protocol name will be matched.
337 /// ditto
338 bool getServiceByName(string name)
339 {
340 servent* serv;
341 serv = getservbyname(toStringz(name), null);
342 if(!serv)
343 return false;
344 populate(serv);
345 return true;
346 }
347
348
349 /// ditto
350 bool getServiceByPort(ushort port, string protocolName)
351 {
352 version (have_getservbyport)
353 {
354 servent* serv;
355 serv = getservbyport(port, toStringz(protocolName));
356 if(!serv)
357 return false;
358 populate(serv);
359 return true;
360 }
361 else
362 return false;
363 }
364
365
366 // Any protocol name will be matched.
367 /// ditto
368 bool getServiceByPort(ushort port)
369 {
370 version (have_getservbyport)
371 {
372 servent* serv;
373 serv = getservbyport(port, null);
374 if(!serv)
375 return false;
376 populate(serv);
377 return true;
378 }
379 else
380 return false;
381 }
382 }
383
384
385 unittest
386 {
387 Service serv = new Service;
388 if(serv.getServiceByName("epmap", "tcp"))
389 {
390 printf("About service epmap:\n\tService: %.*s\n\tPort: %d\n\tProtocol: %.*s\n",
391 cast(int) serv.name.length, serv.name.ptr, serv.port,
392 cast(int) serv.protocolName.length, serv.protocolName.ptr);
393 foreach(char[] s; serv.aliases)
394 {
395 printf("\tAlias: %.*s\n", cast(int) s.length, s.ptr);
396 }
397 }
398 else
399 {
400 printf("No service for epmap.\n");
401 }
402 }
403
404
405 /**
406 * Base exception thrown from an InternetHost.
407 */
408 class HostException: Exception
409 {
410 int errorCode; /// Platform-specific error code.
411
412
413 this(string msg, int err = 0)
414 {
415 errorCode = err;
416 super(msg);
417 }
418 }
419
420 /**
421 * InternetHost is a class for resolving IPv4 addresses.
422 */
423 class InternetHost
424 {
425 /** These members are populated when one of the following functions are called without failure: */
426 string name;
427 string[] aliases; /// ditto
428 uint32_t[] addrList; /// ditto
429
430
431 void validHostent(hostent* he)
432 {
433 if(he.h_addrtype != cast(int)AddressFamily.INET || he.h_length != 4)
434 throw new HostException("Address family mismatch", _lasterr());
435 }
436
437
438 void populate(hostent* he)
439 {
440 int i;
441 char* p;
442
443 name = std.string.toString(he.h_name).dup;
444
445 for(i = 0;; i++)
446 {
447 p = he.h_aliases[i];
448 if(!p)
449 break;
450 }
451
452 if(i)
453 {
454 aliases = new string[i];
455 for(i = 0; i != aliases.length; i++)
456 {
457 aliases[i] = std.string.toString(he.h_aliases[i]).dup;
458 }
459 }
460 else
461 {
462 aliases = null;
463 }
464
465 for(i = 0;; i++)
466 {
467 p = he.h_addr_list[i];
468 if(!p)
469 break;
470 }
471
472 if(i)
473 {
474 addrList = new uint32_t[i];
475 for(i = 0; i != addrList.length; i++)
476 {
477 addrList[i] = ntohl(*(cast(uint32_t*)he.h_addr_list[i]));
478 }
479 }
480 else
481 {
482 addrList = null;
483 }
484 }
485
486 /**
487 * Resolve host name. Returns false if unable to resolve.
488 */
489 bool getHostByName(string name)
490 {
491 hostent* he;
492 synchronized(this.classinfo) he = gethostbyname(toStringz(name));
493 if(!he)
494 return false;
495 validHostent(he);
496 populate(he);
497 return true;
498 }
499
500
501 /**
502 * Resolve IPv4 address number. Returns false if unable to resolve.
503 */
504 bool getHostByAddr(uint addr)
505 {
506 uint x = htonl(addr);
507 hostent* he;
508 synchronized(this.classinfo) he = gethostbyaddr(&x, 4, cast(int)AddressFamily.INET);
509 if(!he)
510 return false;
511 validHostent(he);
512 populate(he);
513 return true;
514 }
515
516
517 /**
518 * Same as previous, but addr is an IPv4 address string in the
519 * dotted-decimal form $(I a.b.c.d).
520 * Returns false if unable to resolve.
521 */
522 bool getHostByAddr(string addr)
523 {
524 uint x = inet_addr(std.string.toStringz(addr));
525 hostent* he;
526 synchronized(this.classinfo) he = gethostbyaddr(&x, 4, cast(int)AddressFamily.INET);
527 if(!he)
528 return false;
529 validHostent(he);
530 populate(he);
531 return true;
532 }
533 }
534
535
536 unittest
537 {
538 InternetHost ih = new InternetHost;
539 assert(ih.getHostByName("www.digitalmars.com"));
540 printf("addrList.length = %d\n", ih.addrList.length);
541 assert(ih.addrList.length);
542 InternetAddress ia = new InternetAddress(ih.addrList[0], InternetAddress.PORT_ANY);
543 char[] sia = ia.toAddrString();
544 printf("IPaddress = %.*s\nname = %.*s\n", cast(int) sia.length, sia.ptr,
545 cast(int) ih.name.length, ih.name.ptr);
546 foreach(int i, string s; ih.aliases)
547 {
548 printf("aliases[%d] = %.*s\n", i, cast(int) s.length, s.ptr);
549 }
550
551 printf("---\n");
552
553 assert(ih.getHostByAddr(ih.addrList[0]));
554 printf("name = %.*s\n", cast(int) ih.name.length, ih.name.ptr);
555 foreach(int i, string s; ih.aliases)
556 {
557 printf("aliases[%d] = %.*s\n", i, cast(int) s.length, s.ptr);
558 }
559 }
560
561
562 /**
563 * Base exception thrown from an Address.
564 */
565 class AddressException: Exception
566 {
567 this(string msg)
568 {
569 super(msg);
570 }
571 }
572
573
574 /**
575 * Address is an abstract class for representing a network addresses.
576 */
577 abstract class Address
578 {
579 protected sockaddr* name();
580 protected int nameLen();
581 AddressFamily addressFamily(); /// Family of this address.
582 string toString(); /// Human readable string representing this address.
583 }
584
585 /**
586 *
587 */
588 class UnknownAddress: Address
589 {
590 protected:
591 sockaddr sa;
592
593
594 sockaddr* name()
595 {
596 return &sa;
597 }
598
599
600 int nameLen()
601 {
602 return sa.sizeof;
603 }
604
605
606 public:
607 AddressFamily addressFamily()
608 {
609 return cast(AddressFamily)sa.sa_family;
610 }
611
612
613 string toString()
614 {
615 return "Unknown";
616 }
617 }
618
619
620 /**
621 * InternetAddress is a class that represents an IPv4 (internet protocol version
622 * 4) address and port.
623 */
624 class InternetAddress: Address
625 {
626 protected:
627 sockaddr_in sin;
628
629
630 sockaddr* name()
631 {
632 return cast(sockaddr*)&sin;
633 }
634
635
636 int nameLen()
637 {
638 return sin.sizeof;
639 }
640
641
642 this()
643 {
644 }
645
646
647 public:
648 const uint ADDR_ANY = INADDR_ANY; /// Any IPv4 address number.
649 const uint ADDR_NONE = INADDR_NONE; /// An invalid IPv4 address number.
650 const ushort PORT_ANY = 0; /// Any IPv4 port number.
651
652 /// Overridden to return AddressFamily.INET.
653 AddressFamily addressFamily()
654 {
655 return cast(AddressFamily)AddressFamily.INET;
656 }
657
658 /// Returns the IPv4 port number.
659 ushort port()
660 {
661 return ntohs(sin.sin_port);
662 }
663
664 /// Returns the IPv4 address number.
665 uint addr()
666 {
667 return ntohl(sin.sin_addr.s_addr);
668 }
669
670 /**
671 * Params:
672 * addr = an IPv4 address string in the dotted-decimal form a.b.c.d,
673 * or a host name that will be resolved using an InternetHost
674 * object.
675 * port = may be PORT_ANY as stated below.
676 */
677 this(string addr, ushort port)
678 {
679 uint uiaddr = parse(addr);
680 if(ADDR_NONE == uiaddr)
681 {
682 InternetHost ih = new InternetHost;
683 if(!ih.getHostByName(addr))
684 //throw new AddressException("Invalid internet address");
685 throw new AddressException("Unable to resolve host '" ~ addr ~ "'");
686 uiaddr = ih.addrList[0];
687 }
688 sin.sin_addr.s_addr = htonl(uiaddr);
689 sin.sin_port = htons(port);
690 }
691
692 /**
693 * Construct a new Address. addr may be ADDR_ANY (default) and port may
694 * be PORT_ANY, and the actual numbers may not be known until a connection
695 * is made.
696 */
697 this(uint addr, ushort port)
698 {
699 sin.sin_addr.s_addr = htonl(addr);
700 sin.sin_port = htons(port);
701 }
702
703 /// ditto
704 this(ushort port)
705 {
706 sin.sin_addr.s_addr = 0; //any, "0.0.0.0"
707 sin.sin_port = htons(port);
708 }
709
710 /// Human readable string representing the IPv4 address in dotted-decimal form.
711 string toAddrString()
712 {
713 return std.string.toString(inet_ntoa(sin.sin_addr)).dup;
714 }
715
716 /// Human readable string representing the IPv4 port.
717 string toPortString()
718 {
719 return std.string.toString(port());
720 }
721
722 /// Human readable string representing the IPv4 address and port in the form $(I a.b.c.d:e).
723 string toString()
724 {
725 return toAddrString() ~ ":" ~ toPortString();
726 }
727
728 /**
729 * Parse an IPv4 address string in the dotted-decimal form $(I a.b.c.d)
730 * and return the number.
731 * If the string is not a legitimate IPv4 address,
732 * ADDR_NONE is returned.
733 */
734 static uint parse(string addr)
735 {
736 return ntohl(inet_addr(std.string.toStringz(addr)));
737 }
738 }
739
740
741 unittest
742 {
743 InternetAddress ia = new InternetAddress("63.105.9.61", 80);
744 assert(ia.toString() == "63.105.9.61:80");
745 }
746
747
748 /** */
749 class SocketAcceptException: SocketException
750 {
751 this(string msg, int err = 0)
752 {
753 super(msg, err);
754 }
755 }
756
757 /// How a socket is shutdown:
758 enum SocketShutdown: int
759 {
760 RECEIVE = SD_RECEIVE, /// socket receives are disallowed
761 SEND = SD_SEND, /// socket sends are disallowed
762 BOTH = SD_BOTH, /// both RECEIVE and SEND
763 }
764
765
766 /// Flags may be OR'ed together:
767 enum SocketFlags: int
768 {
769 NONE = 0, /// no flags specified
770
771 OOB = MSG_OOB, /// out-of-band stream data
772 PEEK = MSG_PEEK, /// peek at incoming data without removing it from the queue, only for receiving
773 DONTROUTE = MSG_DONTROUTE, /// data should not be subject to routing; this flag may be ignored. Only for sending
774 NOSIGNAL = MSG_NOSIGNAL, /// don't send SIGPIPE signal on socket write error and instead return EPIPE
775 }
776
777
778 /// Duration timeout value.
779 extern(C) struct timeval
780 {
781 // D interface
782 int seconds; /// Number of seconds.
783 int microseconds; /// Number of additional microseconds.
784
785 // C interface
786 deprecated
787 {
788 alias seconds tv_sec;
789 alias microseconds tv_usec;
790 }
791 }
792
793
794 /// A collection of sockets for use with Socket.select.
795 class SocketSet
796 {
797 private:
798 uint maxsockets; /// max desired sockets, the fd_set might be capable of holding more
799 fd_set set;
800
801
802 version(Win32)
803 {
804 uint count()
805 {
806 return set.fd_count;
807 }
808 }
809 else version(BsdSockets)
810 {
811 int maxfd;
812 uint count;
813 }
814
815
816 public:
817
818 /// Set the maximum amount of sockets that may be added.
819 this(uint max)
820 {
821 maxsockets = max;
822 reset();
823 }
824
825 /// Uses the default maximum for the system.
826 this()
827 {
828 this(FD_SETSIZE);
829 }
830
831 /// Reset the SocketSet so that there are 0 Sockets in the collection.
832 void reset()
833 {
834 FD_ZERO(&set);
835
836 version(BsdSockets)
837 {
838 maxfd = -1;
839 count = 0;
840 }
841 }
842
843
844 void add(socket_t s)
845 in
846 {
847 // Make sure too many sockets don't get added.
848 assert(count < maxsockets);
849 version(BsdSockets)
850 {
851 version(GNU)
852 {
853 // Tries to account for little and big endian..er needs work
854 // assert((s/NFDBITS+1)*NFDBITS/8 <= nbytes);
855 }
856 else
857 {
858 assert(FDELT(s) < (FD_SETSIZE / NFDBITS));
859 }
860 }
861 }
862 body
863 {
864 FD_SET(s, &set);
865
866 version(BsdSockets)
867 {
868 ++count;
869 if(s > maxfd)
870 maxfd = s;
871 }
872 }
873
874 /// Add a Socket to the collection. Adding more than the maximum has dangerous side affects.
875 void add(Socket s)
876 {
877 add(s.sock);
878 }
879
880 void remove(socket_t s)
881 {
882 FD_CLR(s, &set);
883 version(BsdSockets)
884 {
885 --count;
886 // note: adjusting maxfd would require scanning the set, not worth it
887 }
888 }
889
890
891 /// Remove this Socket from the collection.
892 void remove(Socket s)
893 {
894 remove(s.sock);
895 }
896
897 int isSet(socket_t s)
898 {
899 return FD_ISSET(s, &set);
900 }
901
902
903 /// Returns nonzero if this Socket is in the collection.
904 int isSet(Socket s)
905 {
906 return isSet(s.sock);
907 }
908
909
910 /// Return maximum amount of sockets that can be added, like FD_SETSIZE.
911 uint max()
912 {
913 return maxsockets;
914 }
915
916
917 fd_set* toFd_set()
918 {
919 return &set;
920 }
921
922
923 int selectn()
924 {
925 version(Win32)
926 {
927 return count;
928 }
929 else version(BsdSockets)
930 {
931 return maxfd + 1;
932 }
933 }
934 }
935
936
937 /// The level at which a socket option is defined:
938 enum SocketOptionLevel: int
939 {
940 SOCKET = SOL_SOCKET, /// socket level
941 IP = ProtocolType.IP, /// internet protocol version 4 level
942 ICMP = ProtocolType.ICMP, ///
943 IGMP = ProtocolType.IGMP, ///
944 GGP = ProtocolType.GGP, ///
945 TCP = ProtocolType.TCP, /// transmission control protocol level
946 PUP = ProtocolType.PUP, ///
947 UDP = ProtocolType.UDP, /// user datagram protocol level
948 IDP = ProtocolType.IDP, ///
949 IPV6 = ProtocolType.IPV6, /// internet protocol version 6 level
950 }
951
952
953 /// Linger information for use with SocketOption.LINGER.
954 extern(C) struct linger
955 {
956 version (BsdSockets)
957 version (GNU)
958 {
959 private alias std.c.unix.unix.linger __unix_linger;
960 static assert(linger.sizeof == __unix_linger.sizeof);
961 }
962 // D interface
963 version(Win32)
964 {
965 uint16_t on; /// Nonzero for on.
966 uint16_t time; /// Linger time.
967 }
968 else version(BsdSockets)
969 {
970 version (GNU)
971 {
972
973 typeof(__unix_linger.l_onoff) on;
974 typeof(__unix_linger.l_linger) time;
975
976 }
977 else
978 {
979 int32_t on;
980 int32_t time;
981 }
982 }
983
984 // C interface
985 deprecated
986 {
987 alias on l_onoff;
988 alias time l_linger;
989 }
990 }
991
992
993 /// Specifies a socket option:
994 enum SocketOption: int
995 {
996 DEBUG = SO_DEBUG, /// record debugging information
997 BROADCAST = SO_BROADCAST, /// allow transmission of broadcast messages
998 REUSEADDR = SO_REUSEADDR, /// allow local reuse of address
999 LINGER = SO_LINGER, /// linger on close if unsent data is present
1000 OOBINLINE = SO_OOBINLINE, /// receive out-of-band data in band
1001 SNDBUF = SO_SNDBUF, /// send buffer size
1002 RCVBUF = SO_RCVBUF, /// receive buffer size
1003 DONTROUTE = SO_DONTROUTE, /// do not route
1004
1005 // SocketOptionLevel.TCP:
1006 TCP_NODELAY = .TCP_NODELAY, /// disable the Nagle algorithm for send coalescing
1007
1008 // SocketOptionLevel.IPV6:
1009 IPV6_UNICAST_HOPS = .IPV6_UNICAST_HOPS, ///
1010 IPV6_MULTICAST_IF = .IPV6_MULTICAST_IF, ///
1011 IPV6_MULTICAST_LOOP = .IPV6_MULTICAST_LOOP, ///
1012 IPV6_JOIN_GROUP = .IPV6_JOIN_GROUP, ///
1013 IPV6_LEAVE_GROUP = .IPV6_LEAVE_GROUP, ///
1014 }
1015
1016
1017 /**
1018 * Socket is a class that creates a network communication endpoint using the
1019 * Berkeley sockets interface.
1020 */
1021 class Socket
1022 {
1023 private:
1024 socket_t sock;
1025 AddressFamily _family;
1026
1027 version(Win32)
1028 bool _blocking = false; /// Property to get or set whether the socket is blocking or nonblocking.
1029
1030
1031 // For use with accepting().
1032 protected this()
1033 {
1034 }
1035
1036
1037 public:
1038
1039 /**
1040 * Create a blocking socket. If a single protocol type exists to support
1041 * this socket type within the address family, the ProtocolType may be
1042 * omitted.
1043 */
1044 this(AddressFamily af, SocketType type, ProtocolType protocol)
1045 {
1046 sock = cast(socket_t)socket(af, type, protocol);
1047 if(sock == socket_t.init)
1048 throw new SocketException("Unable to create socket", _lasterr());
1049 _family = af;
1050 }
1051
1052
1053 // A single protocol exists to support this socket type within the
1054 // protocol family, so the ProtocolType is assumed.
1055 /// ditto
1056 this(AddressFamily af, SocketType type)
1057 {
1058 this(af, type, cast(ProtocolType)0); // Pseudo protocol number.
1059 }
1060
1061
1062 /// ditto
1063 this(AddressFamily af, SocketType type, string protocolName)
1064 {
1065 protoent* proto;
1066 proto = getprotobyname(toStringz(protocolName));
1067 if(!proto)
1068 throw new SocketException("Unable to find the protocol", _lasterr());
1069 this(af, type, cast(ProtocolType)proto.p_proto);
1070 }
1071
1072
1073 ~this()
1074 {
1075 close();
1076 }
1077
1078
1079 /// Get underlying socket handle.
1080 socket_t handle()
1081 {
1082 return sock;
1083 }
1084
1085 /**
1086 * Get/set socket's blocking flag.
1087 *
1088 * When a socket is blocking, calls to receive(), accept(), and send()
1089 * will block and wait for data/action.
1090 * A non-blocking socket will immediately return instead of blocking.
1091 */
1092 bool blocking()
1093 {
1094 version(Win32)
1095 {
1096 return _blocking;
1097 }
1098 else version(BsdSockets)
1099 {
1100 return !(fcntl(handle, F_GETFL, 0) & O_NONBLOCK);
1101 }
1102 }
1103
1104 /// ditto
1105 void blocking(bool byes)
1106 {
1107 version(Win32)
1108 {
1109 uint num = !byes;
1110 if(_SOCKET_ERROR == ioctlsocket(sock, FIONBIO, &num))
1111 goto err;
1112 _blocking = byes;
1113 }
1114 else version(BsdSockets)
1115 {
1116 int x = fcntl(sock, F_GETFL, 0);
1117 if(-1 == x)
1118 goto err;
1119 if(byes)
1120 x &= ~O_NONBLOCK;
1121 else
1122 x |= O_NONBLOCK;
1123 if(-1 == fcntl(sock, F_SETFL, x))
1124 goto err;
1125 }
1126 return; // Success.
1127
1128 err:
1129 throw new SocketException("Unable to set socket blocking", _lasterr());
1130 }
1131
1132
1133 /// Get the socket's address family.
1134 AddressFamily addressFamily() // getter
1135 {
1136 return _family;
1137 }
1138
1139 /// Property that indicates if this is a valid, alive socket.
1140 bool isAlive() // getter
1141 {
1142 int type, typesize = type.sizeof;
1143 return !getsockopt(sock, SOL_SOCKET, SO_TYPE, cast(char*)&type, &typesize);
1144 }
1145
1146 /// Associate a local address with this socket.
1147 void bind(Address addr)
1148 {
1149 if(_SOCKET_ERROR == .bind(sock, addr.name(), addr.nameLen()))
1150 throw new SocketException("Unable to bind socket", _lasterr());
1151 }
1152
1153 /**
1154 * Establish a connection. If the socket is blocking, connect waits for
1155 * the connection to be made. If the socket is nonblocking, connect
1156 * returns immediately and the connection attempt is still in progress.
1157 */
1158 void connect(Address to)
1159 {
1160 if(_SOCKET_ERROR == .connect(sock, to.name(), to.nameLen()))
1161 {
1162 int err;
1163 err = _lasterr();
1164
1165 if(!blocking)
1166 {
1167 version(Win32)
1168 {
1169 if(WSAEWOULDBLOCK == err)
1170 return;
1171 }
1172 else version(Unix)
1173 {
1174 if(EINPROGRESS == err)
1175 return;
1176 }
1177 else
1178 {
1179 static assert(0);
1180 }
1181 }
1182 throw new SocketException("Unable to connect socket", err);
1183 }
1184 }
1185
1186 /**
1187 * Listen for an incoming connection. bind must be called before you can
1188 * listen. The backlog is a request of how many pending incoming
1189 * connections are queued until accept'ed.
1190 */
1191 void listen(int backlog)
1192 {
1193 if(_SOCKET_ERROR == .listen(sock, backlog))
1194 throw new SocketException("Unable to listen on socket", _lasterr());
1195 }
1196
1197 /**
1198 * Called by accept when a new Socket must be created for a new
1199 * connection. To use a derived class, override this method and return an
1200 * instance of your class. The returned Socket's handle must not be set;
1201 * Socket has a protected constructor this() to use in this situation.
1202 */
1203 // Override to use a derived class.
1204 // The returned socket's handle must not be set.
1205 protected Socket accepting()
1206 {
1207 return new Socket;
1208 }
1209
1210 /**
1211 * Accept an incoming connection. If the socket is blocking, accept
1212 * waits for a connection request. Throws SocketAcceptException if unable
1213 * to accept. See accepting for use with derived classes.
1214 */
1215 Socket accept()
1216 {
1217 socket_t newsock;
1218 //newsock = cast(socket_t).accept(sock, null, null); // DMD 0.101 error: found '(' when expecting ';' following 'statement
1219 alias .accept topaccept;
1220 newsock = cast(socket_t)topaccept(sock, null, null);
1221 if(socket_t.init == newsock)
1222 throw new SocketAcceptException("Unable to accept socket connection", _lasterr());
1223
1224 Socket newSocket;
1225 try
1226 {
1227 newSocket = accepting();
1228 assert(newSocket.sock == socket_t.init);
1229
1230 newSocket.sock = newsock;
1231 version(Win32)
1232 newSocket._blocking = _blocking; //inherits blocking mode
1233 newSocket._family = _family; //same family
1234 }
1235 catch(Object o)
1236 {
1237 _close(newsock);
1238 throw o;
1239 }
1240
1241 return newSocket;
1242 }
1243
1244 /// Disables sends and/or receives.
1245 void shutdown(SocketShutdown how)
1246 {
1247 .shutdown(sock, cast(int)how);
1248 }
1249
1250
1251 private static void _close(socket_t sock)
1252 {
1253 version(Win32)
1254 {
1255 .closesocket(sock);
1256 }
1257 else version(BsdSockets)
1258 {
1259 .close(sock);
1260 }
1261 }
1262
1263
1264 /**
1265 * Immediately drop any connections and release socket resources.
1266 * Calling shutdown before close is recommended for connection-oriented
1267 * sockets. The Socket object is no longer usable after close.
1268 */
1269 //calling shutdown() before this is recommended
1270 //for connection-oriented sockets
1271 void close()
1272 {
1273 _close(sock);
1274 sock = socket_t.init;
1275 }
1276
1277
1278 private Address newFamilyObject()
1279 {
1280 Address result;
1281 switch(_family)
1282 {
1283 case cast(AddressFamily)AddressFamily.INET:
1284 result = new InternetAddress;
1285 break;
1286
1287 default:
1288 result = new UnknownAddress;
1289 }
1290 return result;
1291 }
1292
1293
1294 /// Returns the local machine's host name. Idea from mango.
1295 static string hostName() // getter
1296 {
1297 char[256] result; // Host names are limited to 255 chars.
1298 if(_SOCKET_ERROR == .gethostname(result.ptr, result.length))
1299 throw new SocketException("Unable to obtain host name", _lasterr());
1300 return std.string.toString(cast(char*)result).dup;
1301 }
1302
1303 /// Remote endpoint Address.
1304 Address remoteAddress()
1305 {
1306 Address addr = newFamilyObject();
1307 int nameLen = addr.nameLen();
1308 if(_SOCKET_ERROR == .getpeername(sock, addr.name(), &nameLen))
1309 throw new SocketException("Unable to obtain remote socket address", _lasterr());
1310 assert(addr.addressFamily() == _family);
1311 return addr;
1312 }
1313
1314 /// Local endpoint Address.
1315 Address localAddress()
1316 {
1317 Address addr = newFamilyObject();
1318 int nameLen = addr.nameLen();
1319 if(_SOCKET_ERROR == .getsockname(sock, addr.name(), &nameLen))
1320 throw new SocketException("Unable to obtain local socket address", _lasterr());
1321 assert(addr.addressFamily() == _family);
1322 return addr;
1323 }
1324
1325 /// Send or receive error code.
1326 const int ERROR = _SOCKET_ERROR;
1327
1328 /**
1329 * Send data on the connection. Returns the number of bytes actually
1330 * sent, or ERROR on failure. If the socket is blocking and there is no
1331 * buffer space left, send waits.
1332 */
1333 //returns number of bytes actually sent, or -1 on error
1334 int send(void[] buf, SocketFlags flags)
1335 {
1336 flags |= SocketFlags.NOSIGNAL;
1337 int sent = .send(sock, buf.ptr, buf.length, cast(int)flags);
1338 return sent;
1339 }
1340
1341 /// ditto
1342 int send(void[] buf)
1343 {
1344 return send(buf, SocketFlags.NOSIGNAL);
1345 }
1346
1347 /**
1348 * 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.
1349 */
1350 int sendTo(void[] buf, SocketFlags flags, Address to)
1351 {
1352 flags |= SocketFlags.NOSIGNAL;
1353 int sent = .sendto(sock, buf.ptr, buf.length, cast(int)flags, to.name(), to.nameLen());
1354 return sent;
1355 }
1356
1357 /// ditto
1358 int sendTo(void[] buf, Address to)
1359 {
1360 return sendTo(buf, SocketFlags.NONE, to);
1361 }
1362
1363
1364 //assumes you connect()ed
1365 /// ditto
1366 int sendTo(void[] buf, SocketFlags flags)
1367 {
1368 flags |= SocketFlags.NOSIGNAL;
1369 int sent = .sendto(sock, buf.ptr, buf.length, cast(int)flags, null, 0);
1370 return sent;
1371 }
1372
1373
1374 //assumes you connect()ed
1375 /// ditto
1376 int sendTo(void[] buf)
1377 {
1378 return sendTo(buf, SocketFlags.NONE);
1379 }
1380
1381
1382 /**
1383 * Receive data on the connection. Returns the number of bytes actually
1384 * received, 0 if the remote side has closed the connection, or ERROR on
1385 * failure. If the socket is blocking, receive waits until there is data
1386 * to be received.
1387 */
1388 //returns number of bytes actually received, 0 on connection closure, or -1 on error
1389 int receive(void[] buf, SocketFlags flags)
1390 {
1391 if(!buf.length) //return 0 and don't think the connection closed
1392 return 0;
1393 int read = .recv(sock, buf.ptr, buf.length, cast(int)flags);
1394 // if(!read) //connection closed
1395 return read;
1396 }
1397
1398 /// ditto
1399 int receive(void[] buf)
1400 {
1401 return receive(buf, SocketFlags.NONE);
1402 }
1403
1404 /**
1405 * Receive data and get the remote endpoint Address.
1406 * If the socket is blocking, receiveFrom waits until there is data to
1407 * be received.
1408 * Returns: the number of bytes actually received,
1409 * 0 if the remote side has closed the connection, or ERROR on failure.
1410 */
1411 int receiveFrom(void[] buf, SocketFlags flags, out Address from)
1412 {
1413 if(!buf.length) //return 0 and don't think the connection closed
1414 return 0;
1415 from = newFamilyObject();
1416 int nameLen = from.nameLen();
1417 int read = .recvfrom(sock, buf.ptr, buf.length, cast(int)flags, from.name(), &nameLen);
1418 assert(from.addressFamily() == _family);
1419 // if(!read) //connection closed
1420 return read;
1421 }
1422
1423
1424 /// ditto
1425 int receiveFrom(void[] buf, out Address from)
1426 {
1427 return receiveFrom(buf, SocketFlags.NONE, from);
1428 }
1429
1430
1431 //assumes you connect()ed
1432 /// ditto
1433 int receiveFrom(void[] buf, SocketFlags flags)
1434 {
1435 if(!buf.length) //return 0 and don't think the connection closed
1436 return 0;
1437 int read = .recvfrom(sock, buf.ptr, buf.length, cast(int)flags, null, null);
1438 // if(!read) //connection closed
1439 return read;
1440 }
1441
1442
1443 //assumes you connect()ed
1444 /// ditto
1445 int receiveFrom(void[] buf)
1446 {
1447 return receiveFrom(buf, SocketFlags.NONE);
1448 }
1449
1450
1451 /// Get a socket option. Returns the number of bytes written to result.
1452 //returns the length, in bytes, of the actual result - very different from getsockopt()
1453 int getOption(SocketOptionLevel level, SocketOption option, void[] result)
1454 {
1455 int len = result.length;
1456 if(_SOCKET_ERROR == .getsockopt(sock, cast(int)level, cast(int)option, result.ptr, &len))
1457 throw new SocketException("Unable to get socket option", _lasterr());
1458 return len;
1459 }
1460
1461
1462 /// Common case of getting integer and boolean options.
1463 int getOption(SocketOptionLevel level, SocketOption option, out int32_t result)
1464 {
1465 return getOption(level, option, (&result)[0 .. 1]);
1466 }
1467
1468
1469 /// Get the linger option.
1470 int getOption(SocketOptionLevel level, SocketOption option, out linger result)
1471 {
1472 //return getOption(cast(SocketOptionLevel)SocketOptionLevel.SOCKET, SocketOption.LINGER, (&result)[0 .. 1]);
1473 return getOption(level, option, (&result)[0 .. 1]);
1474 }
1475
1476 // Set a socket option.
1477 void setOption(SocketOptionLevel level, SocketOption option, void[] value)
1478 {
1479 if(_SOCKET_ERROR == .setsockopt(sock, cast(int)level, cast(int)option, value.ptr, value.length))
1480 throw new SocketException("Unable to set socket option", _lasterr());
1481 }
1482
1483
1484 /// Common case for setting integer and boolean options.
1485 void setOption(SocketOptionLevel level, SocketOption option, int32_t value)
1486 {
1487 setOption(level, option, (&value)[0 .. 1]);
1488 }
1489
1490
1491 /// Set the linger option.
1492 void setOption(SocketOptionLevel level, SocketOption option, linger value)
1493 {
1494 //setOption(cast(SocketOptionLevel)SocketOptionLevel.SOCKET, SocketOption.LINGER, (&value)[0 .. 1]);
1495 setOption(level, option, (&value)[0 .. 1]);
1496 }
1497
1498
1499 /**
1500 * Wait for a socket to change status. A wait timeout timeval or int microseconds may be specified; if a timeout is not specified or the timeval is null, the maximum timeout is used. The timeval timeout has an unspecified value when select returns. Returns the number of sockets with status changes, 0 on timeout, or -1 on interruption. If the return value is greater than 0, the SocketSets are updated to only contain the sockets having status changes. For a connecting socket, a write status change means the connection is established and it's able to send. For a listening socket, a read status change means there is an incoming connection request and it's able to accept.
1501 */
1502 //SocketSet's updated to include only those sockets which an event occured
1503 //returns the number of events, 0 on timeout, or -1 on interruption
1504 //for a connect()ing socket, writeability means connected
1505 //for a listen()ing socket, readability means listening
1506 //Winsock: possibly internally limited to 64 sockets per set
1507 static int select(SocketSet checkRead, SocketSet checkWrite, SocketSet checkError, timeval* tv)
1508 in
1509 {
1510 //make sure none of the SocketSet's are the same object
1511 if(checkRead)
1512 {
1513 assert(checkRead !is checkWrite);
1514 assert(checkRead !is checkError);
1515 }
1516 if(checkWrite)
1517 {
1518 assert(checkWrite !is checkError);
1519 }
1520 }
1521 body
1522 {
1523 fd_set* fr, fw, fe;
1524 int n = 0;
1525
1526 version(Win32)
1527 {
1528 // Windows has a problem with empty fd_set`s that aren't null.
1529 fr = (checkRead && checkRead.count()) ? checkRead.toFd_set() : null;
1530 fw = (checkWrite && checkWrite.count()) ? checkWrite.toFd_set() : null;
1531 fe = (checkError && checkError.count()) ? checkError.toFd_set() : null;
1532 }
1533 else
1534 {
1535 if(checkRead)
1536 {
1537 fr = checkRead.toFd_set();
1538 n = checkRead.selectn();
1539 }
1540 else
1541 {
1542 fr = null;
1543 }
1544
1545 if(checkWrite)
1546 {
1547 fw = checkWrite.toFd_set();
1548 int _n;
1549 _n = checkWrite.selectn();
1550 if(_n > n)
1551 n = _n;
1552 }
1553 else
1554 {
1555 fw = null;
1556 }
1557
1558 if(checkError)
1559 {
1560 fe = checkError.toFd_set();
1561 int _n;
1562 _n = checkError.selectn();
1563 if(_n > n)
1564 n = _n;
1565 }
1566 else
1567 {
1568 fe = null;
1569 }
1570 }
1571
1572 int result = .select(n, fr, fw, fe, cast(_ctimeval*)tv);
1573
1574 version(Win32)
1575 {
1576 if(_SOCKET_ERROR == result && WSAGetLastError() == WSAEINTR)
1577 return -1;
1578 }
1579 else version(Unix)
1580 {
1581 if(_SOCKET_ERROR == result && getErrno() == EINTR)
1582 return -1;
1583 }
1584 else
1585 {
1586 static assert(0);
1587 }
1588
1589 if(_SOCKET_ERROR == result)
1590 throw new SocketException("Socket select error", _lasterr());
1591
1592 return result;
1593 }
1594
1595
1596 /// ditto
1597 static int select(SocketSet checkRead, SocketSet checkWrite, SocketSet checkError, int microseconds)
1598 {
1599 timeval tv;
1600 tv.seconds = 0;
1601 tv.microseconds = microseconds;
1602 return select(checkRead, checkWrite, checkError, &tv);
1603 }
1604
1605
1606 /// ditto
1607 //maximum timeout
1608 static int select(SocketSet checkRead, SocketSet checkWrite, SocketSet checkError)
1609 {
1610 return select(checkRead, checkWrite, checkError, null);
1611 }
1612
1613
1614 /+
1615 bool poll(events)
1616 {
1617 int WSAEventSelect(socket_t s, WSAEVENT hEventObject, int lNetworkEvents); // Winsock 2 ?
1618 int poll(pollfd* fds, int nfds, int timeout); // Unix ?
1619 }
1620 +/
1621 }
1622
1623
1624 /// TcpSocket is a shortcut class for a TCP Socket.
1625 class TcpSocket: Socket
1626 {
1627 /// Constructs a blocking TCP Socket.
1628 this(AddressFamily family)
1629 {
1630 super(family, SocketType.STREAM, ProtocolType.TCP);
1631 }
1632
1633 /// Constructs a blocking TCP Socket.
1634 this()
1635 {
1636 this(cast(AddressFamily)AddressFamily.INET);
1637 }
1638
1639
1640 //shortcut
1641 /// Constructs a blocking TCP Socket and connects to an InternetAddress.
1642 this(Address connectTo)
1643 {
1644 this(connectTo.addressFamily());
1645 connect(connectTo);
1646 }
1647 }
1648
1649
1650 /// UdpSocket is a shortcut class for a UDP Socket.
1651 class UdpSocket: Socket
1652 {
1653 /// Constructs a blocking UDP Socket.
1654 this(AddressFamily family)
1655 {
1656 super(family, SocketType.DGRAM, ProtocolType.UDP);
1657 }
1658
1659
1660 /// Constructs a blocking UDP Socket.
1661 this()
1662 {
1663 this(cast(AddressFamily)AddressFamily.INET);
1664 }
1665 }
1666