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 +/