1 /*******************************************************************************
2 
3     Internet address handling and conversion heper.
4 
5     Wraps a sockaddr_in or sockaddr_in6 struct instance together with the IP
6     address network <-> presentation and port number network <-> host conversion
7     functions.
8 
9     Aliases the following types and constants from <netinet/in.h>:
10 
11         Type                IPv4 name           IPv6 name           Alias name
12 
13         struct              sockaddr_in         sockaddr_in6        Addr
14         const int           INET_ADDRSTRLEN     INET6_ADDRSTRLEN    addrstrlen
15         const sa_family_t   AF_INET             AF_INET6            family
16 
17     Uses the following functions from <arpa/inet.h>:
18         - inet_ntop, inet_pton (IP address network <-> presentation conversion),
19         - htons, ntohs, htonl  (port number network <-> host conversion).
20 
21     For the whole misery see
22 
23     http://pubs.opengroup.org/onlinepubs/009604499/basedefs/netinet/in.h.html
24     http://pubs.opengroup.org/onlinepubs/009604499/functions/inet_ntop.html
25     http://pubs.opengroup.org/onlinepubs/009604499/functions/ntohs.html
26     http://www.openisbn.com/isbn/0131411551/
27 
28     Important note: To reinitialise the address, use clear() (do not assign
29                     .init).
30 
31     Copyright:
32         Copyright (c) 2009-2016 dunnhumby Germany GmbH.
33         All rights reserved.
34 
35     License:
36         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
37         Alternatively, this file may be distributed under the terms of the Tango
38         3-Clause BSD License (see LICENSE_BSD.txt for details).
39 
40 *******************************************************************************/
41 
42 module ocean.sys.socket.InetAddress;
43 
44 import ocean.core.TypeConvert;
45 import ocean.core.Verify;
46 import ocean.meta.types.Qualifiers;
47 
48 import core.stdc.errno: errno, EINVAL;
49 import core.stdc.string: strlen;
50 import core.sys.posix.netdb;
51 import core.sys.posix.arpa.inet: inet_ntop, inet_pton, ntohs, htons, htonl;
52 import core.sys.posix.netinet.in_ : sockaddr,
53            sockaddr_in,  AF_INET,  INET_ADDRSTRLEN,  INADDR_ANY,
54            sockaddr_in6, AF_INET6, INET6_ADDRSTRLEN;
55 
56 
57 /******************************************************************************
58 
59     Flags supported by getnameinfo().
60 
61  ******************************************************************************/
62 
63 public enum GetNameInfoFlags : int
64 {
65     None = 0,
66     NI_NUMERICHOST              = 1 << 0, /// Don't try to look up hostname.
67     NI_NUMERICSERV              = 1 << 1, /// Don't convert port number to name.
68     NI_NOFQDN                   = 1 << 2, /// Only return nodename portion.
69     NI_NAMEREQD                 = 1 << 3, /// Don't return numeric addresses.
70     NI_DGRAM                    = 1 << 4, /// Look up UDP service rather than TCP.
71     NI_IDN                      = 1 << 5, /// Convert name from IDN format.
72     NI_IDN_ALLOW_UNASSIGNED     = 1 << 6, /// Don't reject unassigned Unicode code points.
73     NI_IDN_USE_STD3_ASCII_RULES = 1 << 7  /// Validate strings according to STD3 rules.
74 }
75 
76 /******************************************************************************/
77 
78 struct InetAddress ( bool IPv6 = false )
79 {
80     /**************************************************************************
81 
82         Constants and aliases.
83 
84             - Addr aliases the "sin" internet address struct type, sockaddr_in
85               for IPv4 or sockaddr_in6 for IPv6, respectively.
86             - addrstrlen is the maximum length of a presentation address string
87               plus one (for the NUL-terminator).
88             - family is the address family identifier.
89             - addr_init is the initial value of an Addr instance with the family
90               field set appropriately.
91 
92      **************************************************************************/
93 
94     static if (IPv6)
95     {
96         alias sockaddr_in6 Addr;
97 
98         enum addrstrlen = INET6_ADDRSTRLEN,
99               family     = AF_INET6;
100 
101         enum Addr addr_init = {sin6_family: family};
102     }
103     else
104     {
105         alias sockaddr_in Addr;
106 
107         enum addrstrlen = INET_ADDRSTRLEN,
108               family     = AF_INET;
109 
110         enum Addr addr_init = {sin_family: family};
111     }
112 
113     /**************************************************************************
114 
115         Internet address struct instance.
116         The address and port fields should be accessed by port() and
117         inet_pton()/inet_ntop() unless they are copied from another instance.
118 
119      **************************************************************************/
120 
121     Addr addr = addr_init;
122 
123     /**************************************************************************
124 
125         Gets the port number from this.addr.
126 
127         Returns:
128             the port number.
129 
130      **************************************************************************/
131 
132     ushort port ( )
133     {
134         static if (IPv6)
135         {
136             return .ntohs(this.addr.sin6_port);
137         }
138         else
139         {
140             return .ntohs(this.addr.sin_port);
141         }
142     }
143 
144     /**************************************************************************
145 
146         Sets the port field (sin_port/sin6_port) of this.addr to p.
147 
148         Params:
149             p = port
150 
151         Returns:
152             p.
153 
154      **************************************************************************/
155 
156     ushort port ( ushort p )
157     {
158         static if (IPv6)
159         {
160             this.addr.sin6_port = .htons(p);
161 
162         }
163         else
164         {
165             this.addr.sin_port = .htons(p);
166         }
167 
168         return p;
169     }
170 
171     /**************************************************************************
172 
173         Sets the address field (sin_addr/sin6_addr) of this.addr to the address
174         represented by the string in src. src is expected to contain a valid IP
175         address.
176 
177         Params:
178             ip_address_str = input IP address
179 
180         Returns:
181             1 on success or 0 if src does not contain a valid IP address.
182 
183      **************************************************************************/
184 
185     int inet_pton ( cstring ip_address_str )
186     {
187         if (ip_address_str.length < this.addrstrlen)
188         {
189             char[this.addrstrlen] nultermbuf;
190 
191             nultermbuf[0 .. ip_address_str.length] = ip_address_str[];
192             nultermbuf[ip_address_str.length]      = '\0';
193 
194             return this.inet_pton(nultermbuf.ptr);
195         }
196         else
197         {
198             return 0;
199         }
200 
201     }
202 
203     /**************************************************************************
204 
205         Sets the address field (sin_addr/sin6_addr) of this.addr to the address
206         in ip_address_str. ip_address_str is expected be a NUL-terminated
207         string.
208 
209         Params:
210             ip_address_str = input IP address string
211 
212         Returns:
213             1 on success or 0 if src does not contain a valid IP address.
214 
215         (Note: The inet_pton() specs say it can return -1 with
216         errno = EAFNOSUPPORT; this is not possible unless there is a bug in this
217         struct template ;)
218 
219      **************************************************************************/
220 
221     int inet_pton ( in char* ip_address_str )
222     {
223         return .inet_pton(this.family, ip_address_str, this.address_n.ptr);
224     }
225 
226     /**************************************************************************
227 
228         Sets this.addr to the wildcard "any" IP address.
229 
230         Returns:
231 
232 
233      **************************************************************************/
234 
235     sockaddr* setAddressAny ( )
236     {
237         static if (IPv6)
238         {
239             this.addr.sin6_addr = this.addr.sin6_addr.init;
240         }
241         else
242         {
243             this.addr.sin_addr.s_addr = htonl(INADDR_ANY);
244         }
245 
246         return cast (sockaddr*) &this.addr;
247     }
248 
249     /**************************************************************************
250 
251         Renders the current address of this.addr as an IP address string,
252         writing to dst. dst.length is expected to be at least this.addstrlength.
253 
254         Params:
255             dst = destination string buffer
256 
257         Returns:
258             a slice to valid data in dst on success or null on failure.
259 
260         Errors:
261             ENOSPC - dst is too short.
262 
263         (Note: The inet_ntop() specs say it can fail with errno = EAFNOSUPPORT;
264         this is not possible unless there is a bug in this struct template ;)
265 
266      **************************************************************************/
267 
268     mstring inet_ntop ( mstring dst )
269     {
270         verify(
271             dst.length >= this.addrstrlen,
272             "dst.length expected to be at least addrstrlen"
273         );
274 
275         auto address_p = .inet_ntop(this.family, this.address_n.ptr, dst.ptr,
276             castFrom!(size_t).to!(int)(dst.length));
277 
278         return address_p? dst.ptr[0 .. strlen(dst.ptr)] : null;
279     }
280 
281     /**************************************************************************
282 
283         Sets this.addr to the IP address in ip_address_str and the port to port.
284 
285         Params:
286             ip_address_str = IP address string
287             port           = port
288 
289         Returns:
290             a sockaddr pointer to this.addr on success.
291             If ip_address_str does not contain a valid IP address, null is
292             returned and errno set to EINVAL (this error is reported by this
293             wrapper, not the underlying POSIX function).
294 
295      **************************************************************************/
296 
297     public sockaddr* opCall ( cstring ip_address_str, ushort port = 0 )
298     {
299         if (this.inet_pton(ip_address_str) == 1)
300         {
301             this.port = port;
302             return cast (sockaddr*) &this.addr;
303         }
304         else
305         {
306             .errno = EINVAL;
307             return null;
308         }
309     }
310 
311     /**************************************************************************
312 
313         Sets this.addr to the wildcard "any" IP address and the port to port.
314 
315         Params:
316             port = input port
317 
318         Returns:
319             a sockaddr pointer to this.addr.
320 
321      **************************************************************************/
322 
323     public sockaddr* opCall ( ushort port )
324     {
325         this.port = port;
326 
327         return this.setAddressAny();
328     }
329 
330     /**************************************************************************
331 
332         Copies addr to this.addr.
333 
334         Params:
335             addr = input address
336 
337         Returns:
338             a sockaddr pointer to this.addr.
339 
340      **************************************************************************/
341 
342     public sockaddr* opAssign ( Addr addr )
343     {
344         this.addr = addr;
345 
346         return cast (sockaddr*) &this.addr;
347     }
348 
349     /**************************************************************************
350 
351         Copies *addr to this.addr.
352 
353         Params:
354             addr = input address
355 
356         Returns:
357             a sockaddr pointer to this.addr.
358 
359         In:
360             addr must not be null.
361 
362      **************************************************************************/
363 
364     public sockaddr* opAssign ( Addr* addr )
365     {
366         verify(addr !is null);
367         this.addr = *addr;
368 
369         return cast (sockaddr*) &this.addr;
370     }
371 
372     /**************************************************************************
373 
374         Clears this.addr.
375 
376      **************************************************************************/
377 
378     public void clear ( )
379     {
380         this.addr = this.addr_init;
381     }
382 
383     /**************************************************************************
384 
385         Obtains a slice to the binary address in from this.addr, that is,
386         for IPv4 the sin_addr or for IPv6 the sin6_addr field, respectively.
387 
388         Returns:
389             a slice to the binary address data from this.addr.
390 
391      **************************************************************************/
392 
393     public void[] address_n ( )
394     {
395         with (this.addr) static if (IPv6)
396         {
397             return (cast (void*) &sin6_addr)[0 .. sin6_addr.sizeof];
398         }
399         else
400         {
401             return (cast (void*) &sin_addr)[0 .. sin_addr.sizeof];
402         }
403     }
404 
405     // TODO
406 
407     public int getnameinfo(mstring host, mstring serv,
408                            GetNameInfoFlags flags = GetNameInfoFlags.None)
409     {
410         return core.sys.posix.netdb.getnameinfo(
411             cast (sockaddr*) &this.addr, this.addr.sizeof,
412             host.ptr, castFrom!(size_t).to!(int)(host.length), serv.ptr,
413             castFrom!(size_t).to!(int)(serv.length), flags);
414     }
415 }