1 module more.os.posix.sock;
2 
3 import more.types : passfail;
4 import more.c : cint;
5 import more.os.posix.core :
6     FileHandle,
7     fcntlGetFlags,
8     fcntlSetFlags,
9     O_NONBLOCK;
10 
11 public import more.os.posix.core :
12     lastError;
13 
14 public import core.sys.posix.sys.socket :
15     socklen_t,
16     AF_UNSPEC,
17     AF_UNIX,
18     AF_IPX,
19     AF_APPLETALK,
20     AF_INET,
21     AF_INET6,
22 
23     SOCK_RAW,
24     SOCK_STREAM,
25     SOCK_DGRAM,
26     SOCK_SEQPACKET,
27     SOCK_RDM;
28 public import core.sys.posix.netinet.in_ :
29     IPPROTO_IP,
30     IPPROTO_IPV6,
31     IPPROTO_ICMP,
32     IPPROTO_IGMP,
33     IPPROTO_PUP,
34     IPPROTO_GGP,
35     IPPROTO_IDP,
36     IPPROTO_RAW,
37     IPPROTO_UDP,
38     IPPROTO_TCP;
39 
40 import more.net.sock :
41     AddressFamily, SocketType, Protocol,
42     SocketHandle, ntohl, sockaddr, Blocking;
43 
44 extern (C) nothrow @nogc
45 {
46     const(char)* inet_ntop(int addressFamily, const(void)* addr, char* dst, socklen_t size);
47     SocketHandle socket(cint domain, cint type, cint protocol);
48 }
49 
50 
51     version(linux)
52     {
53         enum : int
54         {
55             TCP_KEEPIDLE  = 4,
56             TCP_KEEPINTVL = 5
57         }
58     }
59 
60 
61 /+
62 /*
63 static import core.stdc.string;
64 
65 import std.format : format, formattedWrite;
66 import std.bitmanip : nativeToBigEndian;
67 import std.typecons : Flag, Yes, No;
68 */
69     import core.sys.posix.netdb;
70     import core.sys.posix.sys.un : sockaddr_un;
71     private import core.sys.posix.fcntl;
72     private import core.sys.posix.unistd;
73     private import core.sys.posix.arpa.inet;
74     private import core.sys.posix.netinet.tcp;
75     private import core.sys.posix.netinet.in_;
76     private import core.sys.posix.sys.time;
77     private import core.sys.posix.sys.select;
78     private import core.sys.posix.sys.socket;
79     private alias _ctimeval = core.sys.posix.sys.time.timeval;
80     private alias _clinger = core.sys.posix.sys.socket.linger;
81 
82     private import core.stdc.errno;
83 
84     alias socket_t = int;
85     enum invalidSocket = -1;
86     alias socklen_t = int;
87 
88     enum Shutdown
89     {
90       recv = SHUT_RD,
91       send = SHUT_WR,
92       both = SHUT_RDWR,
93     }
94 
95     int lastError() nothrow @nogc
96     {
97         return errno;
98     }
99 
100     socket_t createsocket(AddressFamily family, SocketType type, Protocol protocol)
101     {
102         return socket(family, type, protocol);
103     }
104     void closesocket(socket_t sock)
105     {
106       close(sock);
107     }
108     extern(C) sysresult_t bind(socket_t sock, const(sockaddr)* addr, socklen_t addrlen);
109     extern(C) sysresult_t listen(socket_t sock, uint backlog);
110     extern(C) socket_t accept(socket_t sock,  const(sockaddr)* addr, socklen_t* addrlen);
111     extern(C) ptrdiff_t recv(socket_t sock, ubyte* buffer, size_t len, uint flags);
112     extern(C) ptrdiff_t send(socket_t sock, const(ubyte)* buffer, size_t len, uint flags);
113     extern(C) sysresult_t getpeername(socket_t sock, sockaddr* addr, socklen_t* addrlen);
114     extern(C) sysresult_t shutdown(socket_t sock, Shutdown how);
115 +/
116 struct addrinfo
117 {
118     cint      ai_flags;
119     cint      ai_family;
120     cint      ai_socktype;
121     cint      ai_protocol;
122     socklen_t ai_addrlen;
123     sockaddr* ai_addr;
124     char*     ai_canonname;
125     addrinfo* ai_next;
126 }
127 extern(C) sysresult_t getaddrinfo(const(char)* node, const(char)* service,
128     const(addrinfo)* hints, addrinfo** res);
129 /+
130 alias in_port_t = ushort;
131 
132 bool isInvalid(socket_t sock)
133 {
134     return sock == invalidSocket;
135 }
136 T ntohs(T)(T value) if(T.sizeof == 2)
137 {
138     auto result = nativeToBigEndian(value);
139     return *(cast(T*)&result);
140 }
141 T htons(T)(T value) if(T.sizeof == 2)
142 {
143     auto result = nativeToBigEndian(value);
144     return *(cast(T*)&result);
145 }
146 ushort htons(ushort value)
147 {
148     auto result = nativeToBigEndian(value);
149     return *(cast(ushort*)&result);
150 }
151 T ntohl(T)(T value) if(T.sizeof == 4)
152 {
153     auto result = nativeToBigEndian(value);
154     return *(cast(T*)&result);
155 }
156 T htonl(T)(T value) if(T.sizeof == 4)
157 {
158     auto result = nativeToBigEndian(value);
159     return *(cast(T*)&result);
160 }
161 
162 
163 struct in_addr
164 {
165     @property static in_addr any() { return in_addr(0); }
166     uint s_addr;
167 }
168 struct in6_addr
169 {
170     @property static in6_addr any() { return in6_addr(); }
171     ubyte[16] s6_addr;
172 }
173 
174 union inet_addr
175 {
176     in_addr ipv4;
177     in6_addr ipv6;
178 }
179 
180 
181 struct sockaddr
182 {
183     AddressFamily sa_family;
184     char[14] sa_data;
185     /*
186     static void assign(sockaddr* dst, sockaddr* src)
187     {
188         auto size = sockaddrsize(src.sa_family);
189         (cast(ubyte*)dst)[0..size] == (cast(ubyte*)src)[0..size];
190     }
191     */
192 }
193 struct sockaddr_in
194 {
195     AddressFamily sin_family;
196     in_port_t    sin_port;
197     in_addr      sin_addr;
198     version(Windows)
199     {
200         char[] sin_zero;
201     }
202     bool equals(ref const(sockaddr_in) other) const
203     {
204         return sin_port == other.sin_port &&
205             sin_addr.s_addr == other.sin_addr.s_addr;
206     }
207     void toString(scope void delegate(const(char)[]) sink) const
208     {
209         assert(sin_family == AddressFamily.inet);
210         auto addr = ntohl(sin_addr.s_addr);
211         formattedWrite(sink, "%s.%s.%s.%s:%s",
212                       (addr >> 24),
213                       (addr >> 16) & 0xFF,
214                       (addr >>  8) & 0xFF,
215                       (addr >>  0) & 0xFF,
216                       ntohs(sin_port));
217     }
218 }
219 struct sockaddr_in6
220 {
221     AddressFamily sin6_family;
222     in_port_t   sin6_port;
223     uint        sin6_flowinfo;
224     in6_addr    sin6_addr;
225     uint        sin6_scope_id;
226 }
227 
228 private enum INET6_ADDRSTRLEN = 46;
229 
230 // a sockaddr meant to hold either an ipv4 or ipv6 socket address.
231 union inet_sockaddr
232 {
233     struct
234     {
235         AddressFamily family;
236         in_port_t in_port;
237     }
238     sockaddr     sa;
239     sockaddr_in  ipv4;
240     sockaddr_in6 ipv6;
241     this(const in_port_t sin_port, in_addr sin_addr)
242     {
243         ipv4.sin_family = AddressFamily.inet;
244         ipv4.sin_port   = sin_port;
245         ipv4.sin_addr   = sin_addr;
246     }
247     this(const in_port_t sin6_port, in6_addr sin6_addr)
248     {
249         ipv4.sin_family = AddressFamily.inet6;
250         ipv6.sin6_port   = sin6_port;
251         ipv6.sin6_addr   = sin6_addr;
252     }
253     void toString(scope void delegate(const(char)[]) sink) const
254     {
255         if(family == AddressFamily.inet)
256         {
257             ipv4.toString(sink);
258         }
259         else if(family == AddressFamily.inet6)
260         {
261             char[INET6_ADDRSTRLEN] str;
262             version(Windows)
263             {
264                 assert(0, "inet_sockaddr ipv6 toString not implemented");
265             }
266             else
267             {
268                 assert(inet_ntop(AddressFamily.inet6, &ipv6.sin6_addr, str.ptr, str.length),
269                     format("inet_ntop failed (e=%s)", lastError()));
270             }
271             formattedWrite(sink, "[%s]:%s", str.ptr[0..core.stdc.string.strlen(str.ptr)], ntohs(in_port));
272         } else {
273           formattedWrite(sink, "<unknown_family:%s>", family);
274         }
275     }
276     bool equals(ref const(inet_sockaddr) other) const
277     {
278         if(family != other.family || in_port != other.in_port)
279             return false;
280         if(family == AddressFamily.inet) {
281             return ipv4.sin_addr.s_addr == other.ipv4.sin_addr.s_addr;
282         } else if(family == AddressFamily.inet6) {
283             assert(0, "not implemented");
284         } else {
285             assert(0, "not currently handled");
286         }
287     }
288 }
289 
290 
291 pragma(inline)
292 sysresult_t bind(T)(socket_t sock, const(T)* addr)
293     if( is(T == inet_sockaddr) || is(T == sockaddr_in) /* add more types */ )
294 {
295     return bind(sock, cast(sockaddr*)addr, T.sizeof);
296 }
297 pragma(inline)
298 sysresult_t connect(T)(socket_t sock, const(T)* addr)
299     if( is(T == inet_sockaddr) || is(T == sockaddr_in) /* add more types */ )
300 {
301     return connect(sock, cast(sockaddr*)addr, T.sizeof);
302 }
303 pragma(inline)
304 socket_t accept(T)(socket_t sock, T* addr)
305     if( is(T == inet_sockaddr) || is(T == sockaddr_in) /* add more types */ )
306 {
307     socklen_t fromlen = T.sizeof;
308     return accept(sock, cast(sockaddr*)addr, &fromlen);
309 }
310 pragma(inline)
311 auto send(T)(socket_t sock, const(T)* buffer, size_t len, uint flags = 0)
312     if(T.sizeof == 1 && !is(T == ubyte))
313 {
314     return send(sock, cast(const(ubyte)*)buffer, len, flags);
315 }
316 pragma(inline)
317 auto send(T)(socket_t sock, const(T)[] buffer, uint flags = 0)
318     if(T.sizeof == 1)
319 {
320     return send(sock, cast(const(ubyte)*)buffer, buffer.length, flags);
321 }
322 pragma(inline)
323 auto recv(T)(socket_t sock, T* buffer, uint len, uint flags = 0)
324     if(T.sizeof == 1 && !is(T == ubyte))
325 {
326     return recv(sock, cast(ubyte*)buffer, len, flags);
327 }
328 pragma(inline)
329 auto recv(T)(socket_t sock, T[] buffer, uint flags = 0)
330     if(T.sizeof == 1)
331 {
332     return recv(sock, cast(ubyte*)buffer.ptr, buffer.length, flags);
333 }
334 pragma(inline)
335 auto recvfrom(T,U)(socket_t sock, T[] buffer, uint flags, U* from)
336     if(T.sizeof == 1 && is(U == inet_sockaddr) || is(U == sockaddr_in) /* add more types */ )
337 {
338     uint fromlen = U.sizeof;
339     return recvfrom(sock, cast(ubyte*)buffer.ptr, buffer.length, flags, cast(sockaddr*)from, &fromlen);
340 }
341 pragma(inline)
342 auto sendto(T,U)(socket_t sock, const(T)[] buffer, uint flags, const(U)* to)
343     if(T.sizeof == 1 && is(U == inet_sockaddr) || is(U == sockaddr_in) /* add more types */ )
344 {
345     return sendto(sock, cast(const(ubyte)*)buffer.ptr, buffer.length, flags, cast(const(sockaddr)*)to, U.sizeof);
346 }
347 +/