From 260937e4fb899b9084b4b380da3be468f6b6d3da Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Sat, 3 Jun 2017 13:20:32 +0200 Subject: [PATCH] Put socket overlapped I/O docs into a D_Ddoc block --- source/tanya/network/socket.d | 325 +++++++++++++++++++++++----------- 1 file changed, 217 insertions(+), 108 deletions(-) diff --git a/source/tanya/network/socket.d b/source/tanya/network/socket.d index 1634607..709c546 100644 --- a/source/tanya/network/socket.d +++ b/source/tanya/network/socket.d @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /** - * Socket programming. + * Low-level socket programming. * * Copyright: Eugene Wissner 2016-2017. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, @@ -15,12 +15,12 @@ module tanya.network.socket; import core.stdc.errno; import core.time; import std.algorithm.comparison; -public import std.socket : Linger, SocketOptionLevel, SocketOption, - AddressInfo; +public import std.socket : SocketOptionLevel, SocketOption; import std.traits; import std.typecons; import tanya.memory; +/// Value returned by socket operations on error. enum int socketError = -1; version (Posix) @@ -37,6 +37,8 @@ version (Posix) { init = -1, } + + private alias LingerField = int; } else version (Windows) { @@ -52,16 +54,18 @@ else version (Windows) init = ~0, } + private alias LingerField = ushort; + enum : uint { IOC_UNIX = 0x00000000, IOC_WS2 = 0x08000000, IOC_PROTOCOL = 0x10000000, - IOC_VOID = 0x20000000, /// No parameters. - IOC_OUT = 0x40000000, /// Copy parameters back. - IOC_IN = 0x80000000, /// Copy parameters into. + IOC_VOID = 0x20000000, // No parameters. + IOC_OUT = 0x40000000, // Copy parameters back. + IOC_IN = 0x80000000, // Copy parameters into. IOC_VENDOR = 0x18000000, - IOC_INOUT = (IOC_IN | IOC_OUT), /// Copy parameter into and get back. + IOC_INOUT = (IOC_IN | IOC_OUT), // Copy parameter into and get back. } template _WSAIO(int x, int y) @@ -235,36 +239,13 @@ else version (Windows) private WSABUF buffer; } - /** - * Socket returned if a connection has been established. - */ class OverlappedConnectedSocket : ConnectedSocket { - /** - * Create a socket. - * - * Params: - * handle = Socket handle. - * af = Address family. - */ this(SocketType handle, AddressFamily af) @nogc { super(handle, af); } - /** - * Begins to asynchronously receive data from a connected socket. - * - * Params: - * buffer = Storage location for the received data. - * flags = Flags. - * overlapped = Unique operation identifier. - * - * Returns: $(D_KEYWORD true) if the operation could be finished synchronously. - * $(D_KEYWORD false) otherwise. - * - * Throws: $(D_PSYMBOL SocketException) if unable to receive. - */ bool beginReceive(ubyte[] buffer, SocketState overlapped, Flags flags = Flags(Flag.none)) @nogc @trusted @@ -291,16 +272,6 @@ else version (Windows) return result == 0; } - /** - * Ends a pending asynchronous read. - * - * Params - * overlapped = Unique operation identifier. - * - * Returns: Number of bytes received. - * - * Throws: $(D_PSYMBOL SocketException) if unable to receive. - */ int endReceive(SocketState overlapped) @nogc @trusted out (count) { @@ -325,19 +296,6 @@ else version (Windows) return lpNumber; } - /** - * Sends data asynchronously to a connected socket. - * - * Params: - * buffer = Data to be sent. - * flags = Flags. - * overlapped = Unique operation identifier. - * - * Returns: $(D_KEYWORD true) if the operation could be finished synchronously. - * $(D_KEYWORD false) otherwise. - * - * Throws: $(D_PSYMBOL SocketException) if unable to send. - */ bool beginSend(ubyte[] buffer, SocketState overlapped, Flags flags = Flags(Flag.none)) @nogc @trusted @@ -363,16 +321,6 @@ else version (Windows) return result == 0; } - /** - * Ends a pending asynchronous send. - * - * Params - * overlapped = Unique operation identifier. - * - * Returns: Number of bytes sent. - * - * Throws: $(D_PSYMBOL SocketException) if unable to receive. - */ int endSend(SocketState overlapped) @nogc @trusted out (count) { @@ -396,17 +344,9 @@ else version (Windows) class OverlappedStreamSocket : StreamSocket { - /// Accept extension function pointer. + // Accept extension function pointer. package LPFN_ACCEPTEX acceptExtension; - /** - * Create a socket. - * - * Params: - * af = Address family. - * - * Throws: $(D_PSYMBOL SocketException) on errors. - */ this(AddressFamily af) @nogc @trusted { super(af); @@ -435,17 +375,6 @@ else version (Windows) } } - /** - * Begins an asynchronous operation to accept an incoming connection attempt. - * - * Params: - * overlapped = Unique operation identifier. - * - * Returns: $(D_KEYWORD true) if the operation could be finished synchronously. - * $(D_KEYWORD false) otherwise. - * - * Throws: $(D_PSYMBOL SocketException) on accept errors. - */ bool beginAccept(SocketState overlapped) @nogc @trusted { auto socket = cast(SocketType) socket(addressFamily, 1, 0); @@ -461,7 +390,7 @@ else version (Windows) overlapped.handle = cast(HANDLE) socket; overlapped.event = OverlappedSocketEvent.accept; - immutable len = (sockaddr_in.sizeof + 16) * 2; + const len = (sockaddr_in.sizeof + 16) * 2; overlapped.buffer.len = len; overlapped.buffer.buf = cast(char*) defaultAllocator.allocate(len).ptr; @@ -481,17 +410,6 @@ else version (Windows) return result == TRUE; } - /** - * Asynchronously accepts an incoming connection attempt and creates a - * new socket to handle remote host communication. - * - * Params: - * overlapped = Unique operation identifier. - * - * Returns: Connected socket. - * - * Throws: $(D_PSYMBOL SocketException) if unable to accept. - */ OverlappedConnectedSocket endAccept(SocketState overlapped) @nogc @trusted { scope (exit) @@ -512,6 +430,197 @@ else version (Windows) } } } +else version (D_Ddoc) +{ + /// Native socket representation type. + enum SocketType; + + /** + * Socket returned if a connection has been established. + * + * Note: Available only on Windows. + */ + class OverlappedConnectedSocket : ConnectedSocket + { + /** + * Create a socket. + * + * Params: + * handle = Socket handle. + * af = Address family. + */ + this(SocketType handle, AddressFamily af) @nogc; + + /** + * Begins to asynchronously receive data from a connected socket. + * + * Params: + * buffer = Storage location for the received data. + * flags = Flags. + * overlapped = Unique operation identifier. + * + * Returns: $(D_KEYWORD true) if the operation could be finished synchronously. + * $(D_KEYWORD false) otherwise. + * + * Throws: $(D_PSYMBOL SocketException) if unable to receive. + */ + bool beginReceive(ubyte[] buffer, + SocketState overlapped, + Flags flags = Flags(Flag.none)) @nogc @trusted; + + /** + * Ends a pending asynchronous read. + * + * Params: + * overlapped = Unique operation identifier. + * + * Returns: Number of bytes received. + * + * Throws: $(D_PSYMBOL SocketException) if unable to receive. + * + * Postcondition: $(D_INLINECODE result >= 0). + */ + int endReceive(SocketState overlapped) @nogc @trusted + out (count) + { + assert(count >= 0); + } + + /** + * Sends data asynchronously to a connected socket. + * + * Params: + * buffer = Data to be sent. + * flags = Flags. + * overlapped = Unique operation identifier. + * + * Returns: $(D_KEYWORD true) if the operation could be finished synchronously. + * $(D_KEYWORD false) otherwise. + * + * Throws: $(D_PSYMBOL SocketException) if unable to send. + */ + bool beginSend(ubyte[] buffer, + SocketState overlapped, + Flags flags = Flags(Flag.none)) @nogc @trusted; + + /** + * Ends a pending asynchronous send. + * + * Params: + * overlapped = Unique operation identifier. + * + * Returns: Number of bytes sent. + * + * Throws: $(D_PSYMBOL SocketException) if unable to receive. + * + * Postcondition: $(D_INLINECODE result >= 0). + */ + int endSend(SocketState overlapped) @nogc @trusted + out (count) + { + assert(count >= 0); + } + } + + /** + * Windows stream socket overlapped I/O. + */ + class OverlappedStreamSocket : StreamSocket + { + /** + * Create a socket. + * + * Params: + * af = Address family. + * + * Throws: $(D_PSYMBOL SocketException) on errors. + */ + this(AddressFamily af) @nogc @trusted; + + /** + * Begins an asynchronous operation to accept an incoming connection attempt. + * + * Params: + * overlapped = Unique operation identifier. + * + * Returns: $(D_KEYWORD true) if the operation could be finished synchronously. + * $(D_KEYWORD false) otherwise. + * + * Throws: $(D_PSYMBOL SocketException) on accept errors. + */ + bool beginAccept(SocketState overlapped) @nogc @trusted; + + /** + * Asynchronously accepts an incoming connection attempt and creates a + * new socket to handle remote host communication. + * + * Params: + * overlapped = Unique operation identifier. + * + * Returns: Connected socket. + * + * Throws: $(D_PSYMBOL SocketException) if unable to accept. + */ + OverlappedConnectedSocket endAccept(SocketState overlapped) + @nogc @trusted; + } +} + +/** + * Socket option that specifies what should happen when the socket that + * promises reliable delivery still has untransmitted messages when + * it is closed. + */ +struct Linger +{ + /// If nonzero, $(D_PSYMBOL close) and $(D_PSYMBOL shutdown) block until + /// the data are transmitted or the timeout period has expired. + LingerField l_onoff; + + /// Time, in seconds to wait before any buffered data to be sent is + /// discarded. + LingerField l_linger; + + /** + * Params: + * value = Whether to linger after the socket is closed. + * + * See_Also: $(D_PSYMBOL time). + */ + @property enabled(const bool value) pure nothrow @safe @nogc + { + this.l_onoff = value; + } + + /** + * Returns: Whether to linger after the socket is closed. + */ + @property bool enabled() const pure nothrow @safe @nogc + { + return this.l_onoff != 0; + } + + /** + * Returns: Timeout period, in seconds, to wait before closing the socket + * if the $(D_PSYMBOL Linger) is $(D_PSYMBOL enabled). + */ + @property ushort time() const pure nothrow @safe @nogc + { + return this.l_linger & ushort.max; + } + + /** + * Sets timeout period, to wait before closing the socket if the + * $(D_PSYMBOL Linger) is $(D_PSYMBOL enabled), ignored otherwise. + * + * Params: + * timeout = Timeout period, in seconds. + */ + @property void time(ushort timeout) pure nothrow @safe @nogc + { + this.l_linger = timeout; + } +} version (linux) { @@ -541,7 +650,7 @@ else version (DragonFlyBSD) version (MacBSD) { - enum ESOCKTNOSUPPORT = 44; /// Socket type not suppoted. + enum ESOCKTNOSUPPORT = 44; // Socket type not suppoted. } private immutable @@ -628,7 +737,7 @@ enum SocketError : int */ class SocketException : Exception { - immutable SocketError error = SocketError.unknown; + const SocketError error = SocketError.unknown; /** * Params: @@ -807,7 +916,7 @@ abstract class Socket SocketOption option, out size_t result) const @trusted @nogc { - return getOption(level, option, (&result)[0..1]); + return getOption(level, option, (&result)[0 .. 1]); } /// Ditto. @@ -815,7 +924,7 @@ abstract class Socket SocketOption option, out Linger result) const @trusted @nogc { - return getOption(level, option, (&result.clinger)[0..1]); + return getOption(level, option, (&result)[0 .. 1]); } /// Ditto. @@ -828,7 +937,7 @@ abstract class Socket version (Posix) { timeval tv; - auto ret = getOption(level, option, (&tv)[0..1]); + auto ret = getOption(level, option, (&tv)[0 .. 1]); result = dur!"seconds"(tv.tv_sec) + dur!"usecs"(tv.tv_usec); } else version (Windows) @@ -872,14 +981,14 @@ abstract class Socket void setOption(SocketOptionLevel level, SocketOption option, size_t value) const @trusted @nogc { - setOption(level, option, (&value)[0..1]); + setOption(level, option, (&value)[0 .. 1]); } /// Ditto. void setOption(SocketOptionLevel level, SocketOption option, Linger value) const @trusted @nogc { - setOption(level, option, (&value.clinger)[0..1]); + setOption(level, option, (&value)[0 .. 1]); } /// Ditto. @@ -890,7 +999,7 @@ abstract class Socket { timeval tv; value.split!("seconds", "usecs")(tv.tv_sec, tv.tv_usec); - setOption(level, option, (&tv)[0..1]); + setOption(level, option, (&tv)[0 .. 1]); } else version (Windows) { @@ -914,7 +1023,7 @@ abstract class Socket } else version (Windows) { - return blocking_; + return this.blocking_; } } @@ -947,7 +1056,7 @@ abstract class Socket throw make!SocketException(defaultAllocator, "Unable to set socket blocking"); } - blocking_ = yes; + this.blocking_ = yes; } } @@ -1309,7 +1418,7 @@ class InternetAddress : Address /// Internal internet address representation. protected sockaddr_storage storage; } - immutable ushort port_; + const ushort port_; enum { @@ -1328,7 +1437,7 @@ class InternetAddress : Address // Make C-string from host. auto node = cast(char[]) allocator.allocate(host.length + 1); - node[0.. $ - 1] = host; + node[0 .. $ - 1] = host; node[$ - 1] = '\0'; scope (exit) { @@ -1351,7 +1460,7 @@ class InternetAddress : Address } port /= 10; } - servicePointer = service[start..$].ptr; + servicePointer = service[start .. $].ptr; } auto ret = getaddrinfoPointer(node.ptr, servicePointer, null, &ai_res);