Download Reference Manual
The Developer's Library for D
About Wiki Forums Source Search Contact

Ticket #563: SocketEnhanced.d

File SocketEnhanced.d, 63.0 kB (added by Nietsnie, 1 year ago)
Line 
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.SocketEnhanced;
64
65 private import  tango.sys.Common;
66
67 private import  tango.core.Exception;
68
69 private import  tango.core.Type : Interval;
70
71
72 /*******************************************************************************
73
74
75 *******************************************************************************/
76
77 version=Tango;
78 version (Tango)
79 {
80         private {
81         char[] toString (char[] tmp, int i)
82         {
83                 int j = tmp.length;
84                 do {
85                    tmp[--j] = i % 10 + '0';
86                    } while (i /= 10);
87
88                 return tmp [j .. $];
89         }
90         }
91 }
92
93 version (linux)
94          version = BsdSockets;
95
96 version (darwin)
97          version = BsdSockets;
98
99 version (Posix)
100          version = BsdSockets;
101
102
103 /*******************************************************************************
104
105
106 *******************************************************************************/
107
108 struct addrinfo
109 {
110     int         ai_flags;
111     int         ai_family;
112     int         ai_socktype;
113     int         ai_protocol;
114     size_t      ai_addrln;
115     sockaddr    *ai_addr;
116     char        *ai_canonname;
117     addrinfo    *ai_next;
118 };
119
120 private const int INET_ADDRSTRLEN = 16;
121 private const int NI_MAXHOST = 1025;
122 private const int NI_MAXSERVER = 32;
123 private const int AI_CANONNAME = 0x0002;
124
125
126 version (Win32)
127         {
128         pragma(lib, "ws2_32.lib");
129
130         private typedef int socket_t = ~0;
131
132         private const int IOCPARM_MASK =  0x7f;
133         private const int IOC_IN =        cast(int)0x80000000;
134         private const int FIONBIO =       cast(int) (IOC_IN | ((int.sizeof & IOCPARM_MASK) << 16) | (102 << 8) | 126);
135
136         private const int WSADESCRIPTION_LEN = 256;
137         private const int WSASYS_STATUS_LEN = 128;
138         private const int WSAEWOULDBLOCK =  10035;
139         private const int WSAEINTR =        10004;
140
141         struct WSADATA
142         {
143                         WORD wVersion;
144                         WORD wHighVersion;
145                         char szDescription[WSADESCRIPTION_LEN+1];
146                         char szSystemStatus[WSASYS_STATUS_LEN+1];
147                         ushort iMaxSockets;
148                         ushort iMaxUdpDg;
149                         char* lpVendorInfo;
150         }
151         alias WSADATA* LPWSADATA;
152
153         extern  (Windows)
154                 {
155                 int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);
156                 int WSACleanup();
157                 socket_t socket(int af, int type, int protocol);
158                 int ioctlsocket(socket_t s, int cmd, uint* argp);
159                 uint inet_addr(char* cp);
160                 int bind(socket_t s, sockaddr* name, int namelen);
161                 int connect(socket_t s, sockaddr* name, int namelen);
162                 int listen(socket_t s, int backlog);
163                 socket_t accept(socket_t s, sockaddr* addr, int* addrlen);
164                 int closesocket(socket_t s);
165                 int shutdown(socket_t s, int how);
166                 int getpeername(socket_t s, sockaddr* name, int* namelen);
167                 int getsockname(socket_t s, sockaddr* name, int* namelen);
168                 int send(socket_t s, void* buf, int len, int flags);
169                 int sendto(socket_t s, void* buf, int len, int flags, sockaddr* to, int tolen);
170                 int recv(socket_t s, void* buf, int len, int flags);
171                 int recvfrom(socket_t s, void* buf, int len, int flags, sockaddr* from, int* fromlen);
172                 int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* errorfds, timeval* timeout);
173                 //int __WSAFDIsSet(socket_t s, fd_set* fds);
174                 int getsockopt(socket_t s, int level, int optname, void* optval, int* optlen);
175                 int setsockopt(socket_t s, int level, int optname, void* optval, int optlen);
176                 int gethostname(void* namebuffer, int buflen);
177                 char* inet_ntoa(uint ina);
178                 char* inet_ntop(int af, void *src, char *dst, int len);
179                 int getaddrinfo(char *node, char *service, addrinfo *hints, addrinfo **res);
180                 void freeaddrinfo(addrinfo *res);
181                 int getnameinfo(sockaddr *sa, size_t len, char *host, size_t hostlen, char *server, size_t servlen, int flags);
182                 hostent* gethostbyname(char* name);
183                 hostent* gethostbyaddr(void* addr, int len, int type);
184                 int WSAGetLastError();
185                 }
186
187         static this()
188         {
189                 WSADATA wd;
190                 if (WSAStartup (0x0101, &wd))
191                     throw new SocketException("Unable to initialize socket library");
192         }
193
194
195         static ~this()
196         {
197                 WSACleanup();
198         }
199
200         }
201
202 version (BsdSockets)
203         {
204         private import tango.stdc.errno;
205
206         private typedef int socket_t = -1;
207
208         private const int F_GETFL       = 3;
209         private const int F_SETFL       = 4;
210         version (darwin)
211                  private const int O_NONBLOCK = 0x0004;
212            else
213                  private const int O_NONBLOCK = 04000;  // OCTAL! Thx to volcore
214
215         extern  (C)
216                 {
217                 socket_t socket(int af, int type, int protocol);
218                 int fcntl(socket_t s, int f, ...);
219                 uint inet_addr(char* cp);
220                 int bind(socket_t s, sockaddr* name, int namelen);
221                 int connect(socket_t s, sockaddr* name, int namelen);
222                 int listen(socket_t s, int backlog);
223                 socket_t accept(socket_t s, sockaddr* addr, int* addrlen);
224                 int close(socket_t s);
225                 int shutdown(socket_t s, int how);
226                 int getpeername(socket_t s, sockaddr* name, int* namelen);
227                 int getsockname(socket_t s, sockaddr* name, int* namelen);
228                 int send(socket_t s, void* buf, int len, int flags);
229                 int sendto(socket_t s, void* buf, int len, int flags, sockaddr* to, int tolen);
230                 int recv(socket_t s, void* buf, int len, int flags);
231                 int recvfrom(socket_t s, void* buf, int len, int flags, sockaddr* from, int* fromlen);
232                 int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* errorfds, timeval* timeout);
233                 int getsockopt(socket_t s, int level, int optname, void* optval, int* optlen);
234                 int setsockopt(socket_t s, int level, int optname, void* optval, int optlen);
235                 int gethostname(void* namebuffer, int buflen);
236                 char* inet_ntoa(uint ina);
237                 hostent* gethostbyname(char* name);
238                 hostent* gethostbyaddr(void* addr, int len, int type);
239                 char* inet_ntop(int af, void *src, char *dst, int len);
240                 int getaddrinfo(char *node, char *service, addrinfo *hints, addrinfo **res);
241                 int getnameinfo(sockaddr *sa, size_t len, char *host, size_t hostlen, char *server, size_t servlen, int flags);
242                 void freeaddrinfo(addrinfo *res);           
243                }
244         }
245
246
247 /*******************************************************************************
248
249
250 *******************************************************************************/
251
252 private const socket_t INVALID_SOCKET = socket_t.init;
253 private const int SOCKET_ERROR = -1;
254
255
256
257 /*******************************************************************************
258
259         Internal structs:
260
261 *******************************************************************************/
262
263 struct timeval
264 {
265         int tv_sec; //seconds
266         int tv_usec; //microseconds
267 }
268
269
270 //transparent
271 struct fd_set
272 {
273 }
274
275
276 struct sockaddr
277 {
278         ushort sa_family;
279         char[14] sa_data = [0];
280 }
281
282
283 struct hostent
284 {
285         char* h_name;
286         char** h_aliases;
287         version(Win32)
288         {
289                 short h_addrtype;
290                 short h_length;
291         }
292         else version(BsdSockets)
293         {
294                 int h_addrtype;
295                 int h_length;
296         }
297         char** h_addr_list;
298
299
300         char* h_addr()
301         {
302                 return h_addr_list[0];
303         }
304 }
305
306
307 /*******************************************************************************
308
309         conversions for network byte-order
310
311 *******************************************************************************/
312
313 version(BigEndian)
314 {
315         ushort htons(ushort x)
316         {
317                 return x;
318         }
319
320
321         uint htonl(uint x)
322         {
323                 return x;
324         }
325 }
326 else version(LittleEndian)
327 {
328         import tango.core.BitManip;
329
330
331         ushort htons(ushort x)
332         {
333                 return cast(ushort) ((x >> 8) | (x << 8));
334         }
335
336
337         uint htonl(uint x)
338         {
339                 return bswap(x);
340         }
341 }
342 else
343 {
344         static assert(0);
345 }
346
347
348 ushort ntohs(ushort x)
349 {
350         return htons(x);
351 }
352
353
354 uint ntohl(uint x)
355 {
356         return htonl(x);
357 }
358
359
360 /*******************************************************************************
361
362
363 *******************************************************************************/
364
365 private extern (C) int strlen(char*);
366
367 private static char[] toUtf8(char* s)
368 {
369         return s ? s[0 .. strlen(s)] : cast(char[])null;
370 }
371
372 private static char* convert2C (char[] input, char[] output)
373 {
374         output [0 .. input.length] = input;
375         output [input.length] = 0;
376         return output.ptr;
377 }
378
379
380 /*******************************************************************************
381
382         Public interface ...
383
384 *******************************************************************************/
385
386 public:
387
388
389 /*******************************************************************************
390
391
392 *******************************************************************************/
393
394 static int lastError ()
395 {
396         version (Win32)
397                 {
398                 return WSAGetLastError();
399                 }
400         version (Posix)
401                 {
402                 return errno;
403                 }
404 }
405
406
407 /***********************************************************************
408
409
410 ***********************************************************************/
411
412 version (Win32)
413 {
414         /***************************************************************
415
416
417         ***************************************************************/
418
419         enum SocketOption: int
420         {
421                 //consistent
422                 SO_DEBUG =         0x1,
423
424                 //possibly Winsock-only values
425                 SO_BROADCAST =  0x20,
426                 SO_REUSEADDR =  0x4,
427                 SO_LINGER =     0x80,
428                 SO_DONTLINGER = ~(SO_LINGER),
429                 SO_OOBINLINE =  0x100,
430                 SO_SNDBUF =     0x1001,
431                 SO_RCVBUF =     0x1002,
432                 SO_ERROR =      0x1007,
433
434                 SO_ACCEPTCONN =    0x2, // ?
435                 SO_KEEPALIVE =     0x8, // ?
436                 SO_DONTROUTE =     0x10, // ?
437                 SO_TYPE =          0x1008, // ?
438
439                 // OptionLevel.IP settings
440                 IP_MULTICAST_TTL = 10,
441                 IP_MULTICAST_LOOP = 11,
442                 IP_ADD_MEMBERSHIP = 12,
443                 IP_DROP_MEMBERSHIP = 13,
444
445                 // OptionLevel.TCP settings
446                 TCP_NODELAY = 0x0001,
447         }
448
449         /***************************************************************
450
451
452         ***************************************************************/
453
454         union linger
455         {
456                 struct {
457                        ushort l_onoff;          // option on/off
458                        ushort l_linger;         // linger time
459                        };
460                 ushort[2]       array;          // combined
461         }
462
463         /***************************************************************
464
465
466         ***************************************************************/
467
468         enum SocketOptionLevel
469         {
470                 SOCKET =  0xFFFF,
471                 IP =      0,
472                 TCP =     6,
473                 UDP =     17,
474         }
475 }
476 else version (darwin)
477 {
478         enum SocketOption: int
479         {
480                 SO_DEBUG        = 0x0001,       /* turn on debugging info recording */
481                 SO_BROADCAST    = 0x0020,       /* permit sending of broadcast msgs */
482                 SO_REUSEADDR    = 0x0004,       /* allow local address reuse */
483                 SO_LINGER       = 0x0080,       /* linger on close if data present */
484                 SO_DONTLINGER   = ~(SO_LINGER),
485                 SO_OOBINLINE    = 0x0100,       /* leave received OOB data in line */
486                 SO_ACCEPTCONN   = 0x0002,       /* socket has had listen() */
487                 SO_KEEPALIVE    = 0x0008,       /* keep connections alive */
488                 SO_DONTROUTE    = 0x0010,       /* just use interface addresses */
489                 SO_TYPE         = 0x1008,               /* get socket type */
490
491                 /*
492                  * Additional options, not kept in so_options.
493                  */
494                 SO_SNDBUF       = 0x1001,       /* send buffer size */
495                 SO_RCVBUF       = 0x1002,       /* receive buffer size */
496                 SO_ERROR        = 0x1007,       /* get error status and clear */
497
498                 // OptionLevel.IP settings
499                 IP_MULTICAST_TTL = 10,
500                 IP_MULTICAST_LOOP = 11,
501                 IP_ADD_MEMBERSHIP = 12,
502                 IP_DROP_MEMBERSHIP = 13,
503
504                 // OptionLevel.TCP settings
505                 TCP_NODELAY = 0x0001,
506         }
507
508         /***************************************************************
509
510
511         ***************************************************************/
512
513         union linger
514         {
515                 struct {
516                        int l_onoff;             // option on/off
517                        int l_linger;            // linger time
518                        };
519                 int[2]          array;          // combined
520         }
521
522         /***************************************************************
523
524                 Question: are these correct for Darwin?
525
526         ***************************************************************/
527
528         enum SocketOptionLevel
529         {
530                 SOCKET =  1,  // correct for linux on x86
531                 IP =      0,  // appears to be correct
532                 TCP =     6,  // appears to be correct
533                 UDP =     17, // appears to be correct
534         }
535 }
536 else version (linux)
537 {
538         /***************************************************************
539
540                 these appear to be compatible with x86 platforms,
541                 but not others!
542
543         ***************************************************************/
544
545         enum SocketOption: int
546         {
547                 //consistent
548                 SO_DEBUG        = 1,
549                 SO_BROADCAST    = 6,
550                 SO_REUSEADDR    = 2,
551                 SO_LINGER       = 13,
552                 SO_DONTLINGER   = ~(SO_LINGER),
553                 SO_OOBINLINE    = 10,
554                 SO_SNDBUF       = 7,
555                 SO_RCVBUF       = 8,
556                 SO_ERROR        = 4,
557
558                 SO_ACCEPTCONN   = 30,
559                 SO_KEEPALIVE    = 9,
560                 SO_DONTROUTE    = 5,
561                 SO_TYPE         = 3,
562
563                 // OptionLevel.IP settings
564                 IP_MULTICAST_TTL = 33,
565                 IP_MULTICAST_LOOP = 34,
566                 IP_ADD_MEMBERSHIP = 35,
567                 IP_DROP_MEMBERSHIP = 36,
568
569                 // OptionLevel.TCP settings
570                 TCP_NODELAY = 0x0001,
571         }
572
573         /***************************************************************
574
575
576         ***************************************************************/
577
578         union linger
579         {
580                 struct {
581                        int l_onoff;             // option on/off
582                        int l_linger;            // linger time
583                        };
584                 int[2]          array;          // combined
585         }
586
587         /***************************************************************
588
589
590         ***************************************************************/
591
592         enum SocketOptionLevel
593         {
594                 SOCKET =  1,  // correct for linux on x86
595                 IP =      0,  // appears to be correct
596                 TCP =     6,  // appears to be correct
597                 UDP =     17, // appears to be correct
598         }
599 } // end versioning
600
601 /***********************************************************************
602
603
604 ***********************************************************************/
605
606 enum SocketShutdown: int
607 {
608         RECEIVE =  0,
609         SEND =     1,
610         BOTH =     2,
611 }
612
613 /***********************************************************************
614
615
616 ***********************************************************************/
617
618 enum SocketFlags: int
619 {
620         NONE =           0,
621         OOB =            0x1, //out of band
622         PEEK =           0x02, //only for receiving
623         DONTROUTE =      0x04, //only for sending
624 }
625
626 /***********************************************************************
627
628          Communication semantics
629
630 ***********************************************************************/
631
632 enum SocketType: int
633 {
634         STREAM =     1,       /// sequenced, reliable, two-way communication-based byte streams
635         DGRAM =      2,        /// connectionless, unreliable datagrams with a fixed maximum length; data may be lost or arrive out of order
636         RAW =        3,          /// raw protocol access
637         RDM =        4,          /// reliably-delivered message datagrams
638         SEQPACKET =  5,    /// sequenced, reliable, two-way connection-based datagrams with a fixed maximum length
639 }
640
641
642 /***********************************************************************
643
644         Protocol
645
646 ***********************************************************************/
647
648 enum ProtocolType: int
649 {
650         IP =    0,     /// internet protocol version 4
651         ICMP =  1,   /// internet control message protocol
652         IGMP =  2,   /// internet group management protocol
653         GGP =   3,    /// gateway to gateway protocol
654         TCP =   6,    /// transmission control protocol
655         PUP =   12,    /// PARC universal packet protocol
656         UDP =   17,    /// user datagram protocol
657         IDP =   22,    /// Xerox NS protocol
658 }
659
660
661 /***********************************************************************
662
663
664 ***********************************************************************/
665
666 version(Win32)
667 {
668       &n