summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md5
-rw-r--r--source/tanya/async/event/epoll.d2
-rw-r--r--source/tanya/async/event/selector.d2
-rw-r--r--source/tanya/async/loop.d16
-rw-r--r--source/tanya/async/protocol.d2
-rw-r--r--source/tanya/async/transport.d2
-rw-r--r--source/tanya/async/watcher.d2
-rw-r--r--source/tanya/net/iface.d20
-rw-r--r--source/tanya/net/ip.d37
-rw-r--r--source/tanya/net/package.d1
-rw-r--r--source/tanya/net/socket.d (renamed from source/tanya/network/socket.d)212
-rw-r--r--source/tanya/network/package.d17
12 files changed, 66 insertions, 252 deletions
diff --git a/README.md b/README.md
index e58cd04..3e27532 100644
--- a/README.md
+++ b/README.md
@@ -35,9 +35,6 @@ type information at compile-time, to transform from one type to another. It has
also different algorithms for iterating, searching and modifying template
arguments.
* `net`: URL-Parsing, network programming.
-* `network`: Socket implementation. `network` is currently under rework.
-After finishing the new socket implementation will land in the `net` package and
-`network` will be deprecated.
* `os`: Platform-independent interfaces to operating system functionality.
* `range`: Generic functions and templates for D ranges.
* `test`: Test suite for unittest-blocks.
@@ -167,7 +164,7 @@ parameter is used)
| DMD | GCC |
|:-------:|:---------:|
-| 2.091.1 | gdc trunk |
+| 2.096.0 | 10.3 |
## Further characteristics
diff --git a/source/tanya/async/event/epoll.d b/source/tanya/async/event/epoll.d
index 7d3854d..c81d6ff 100644
--- a/source/tanya/async/event/epoll.d
+++ b/source/tanya/async/event/epoll.d
@@ -31,7 +31,7 @@ import tanya.async.transport;
import tanya.async.watcher;
import tanya.container.array;
import tanya.memory.allocator;
-import tanya.network.socket;
+import tanya.net.socket;
extern (C) nothrow @nogc
{
diff --git a/source/tanya/async/event/selector.d b/source/tanya/async/event/selector.d
index 897ad99..f954e8c 100644
--- a/source/tanya/async/event/selector.d
+++ b/source/tanya/async/event/selector.d
@@ -26,7 +26,7 @@ import tanya.async.watcher;
import tanya.container.array;
import tanya.container.buffer;
import tanya.memory.allocator;
-import tanya.network.socket;
+import tanya.net.socket;
/**
* Transport for stream sockets.
diff --git a/source/tanya/async/loop.d b/source/tanya/async/loop.d
index 6653282..1d88575 100644
--- a/source/tanya/async/loop.d
+++ b/source/tanya/async/loop.d
@@ -34,8 +34,9 @@
*
* void main()
* {
- * auto address = defaultAllocator.make!InternetAddress("127.0.0.1", cast(ushort) 8192);
- *
+ * auto address = address4("127.0.0.1");
+ * auto endpoint = Endpoint(address.get, cast(ushort) 8192);
+ *
* version (Windows)
* {
* auto sock = defaultAllocator.make!OverlappedStreamSocket(AddressFamily.inet);
@@ -46,19 +47,18 @@
* sock.blocking = false;
* }
*
- * sock.bind(address);
+ * sock.bind(endpoint);
* sock.listen(5);
- *
+ *
* auto io = defaultAllocator.make!ConnectionWatcher(sock);
* io.setProtocol!EchoProtocol;
- *
+ *
* defaultLoop.start(io);
* defaultLoop.run();
- *
+ *
* sock.shutdown();
* defaultAllocator.dispose(io);
* defaultAllocator.dispose(sock);
- * defaultAllocator.dispose(address);
* }
* ---
*
@@ -78,7 +78,7 @@ import tanya.bitmanip;
import tanya.container.buffer;
import tanya.container.list;
import tanya.memory.allocator;
-import tanya.network.socket;
+import tanya.net.socket;
version (DisableBackends)
{
diff --git a/source/tanya/async/protocol.d b/source/tanya/async/protocol.d
index 4a1b72c..c51dae5 100644
--- a/source/tanya/async/protocol.d
+++ b/source/tanya/async/protocol.d
@@ -19,7 +19,7 @@
module tanya.async.protocol;
import tanya.async.transport;
-import tanya.network.socket;
+import tanya.net.socket;
/**
* Common protocol interface.
diff --git a/source/tanya/async/transport.d b/source/tanya/async/transport.d
index 349abc3..87051e8 100644
--- a/source/tanya/async/transport.d
+++ b/source/tanya/async/transport.d
@@ -16,7 +16,7 @@
module tanya.async.transport;
import tanya.async.protocol;
-import tanya.network.socket;
+import tanya.net.socket;
/**
* Base transport interface.
diff --git a/source/tanya/async/watcher.d b/source/tanya/async/watcher.d
index 8656c94..1159779 100644
--- a/source/tanya/async/watcher.d
+++ b/source/tanya/async/watcher.d
@@ -20,7 +20,7 @@ import tanya.async.transport;
import tanya.container.buffer;
import tanya.container.list;
import tanya.memory.allocator;
-import tanya.network.socket;
+import tanya.net.socket;
/**
* A watcher is an opaque structure that you allocate and register to record
diff --git a/source/tanya/net/iface.d b/source/tanya/net/iface.d
index 9338745..8e2675a 100644
--- a/source/tanya/net/iface.d
+++ b/source/tanya/net/iface.d
@@ -142,3 +142,23 @@ String indexToName(uint index) @nogc nothrow @trusted
return String(findNullTerminated(buffer));
}
}
+
+/**
+ * $(D_PSYMBOL AddressFamily) specifies a communication domain; this selects
+ * the protocol family which will be used for communication.
+ */
+enum AddressFamily : int
+{
+ unspec = 0, /// Unspecified.
+ local = 1, /// Local to host (pipes and file-domain).
+ unix = local, /// POSIX name for PF_LOCAL.
+ inet = 2, /// IP protocol family.
+ ax25 = 3, /// Amateur Radio AX.25.
+ ipx = 4, /// Novell Internet Protocol.
+ appletalk = 5, /// Appletalk DDP.
+ netrom = 6, /// Amateur radio NetROM.
+ bridge = 7, /// Multiprotocol bridge.
+ atmpvc = 8, /// ATM PVCs.
+ x25 = 9, /// Reserved for X.25 project.
+ inet6 = 10, /// IP version 6.
+}
diff --git a/source/tanya/net/ip.d b/source/tanya/net/ip.d
index 8299f73..54a27e3 100644
--- a/source/tanya/net/ip.d
+++ b/source/tanya/net/ip.d
@@ -14,7 +14,6 @@
*/
module tanya.net.ip;
-import core.sys.posix.sys.socket;
import std.algorithm.comparison;
import std.ascii;
import std.typecons;
@@ -1331,7 +1330,7 @@ struct Address
*/
struct Endpoint
{
- private sa_family_t family = AF_UNSPEC;
+ private AddressFamily family = AddressFamily.unspec;
private ubyte[ushort.sizeof] service;
private Address4 address4; // Unused sin6_flowinfo if IPv6
private Address6 address6; // Unused if IPv4
@@ -1345,10 +1344,12 @@ struct Endpoint
* Constructs an endpoint.
*
* Params:
+ * T = Address type (IPv4 or IPv6).
* address = IP address that should be associated with the endpoint.
* port = Port number in network byte order.
*/
- this(Address address, const ushort port = anyPort)
+ this(T)(T address, const ushort port = anyPort)
+ if (is(T == Address) || is(T == Address4) || is(T == Address6))
{
this.address = address;
this.port = port;
@@ -1357,7 +1358,7 @@ struct Endpoint
/**
* Returns: Port number in network byte order.
*/
- @property ushort port() const @nogc nothrow pure @safe
+ @property inout(ushort) port() inout const @nogc nothrow pure @safe
{
return this.service[].toHostOrder!ushort();
}
@@ -1374,13 +1375,13 @@ struct Endpoint
/**
* Returns: IP address associated with the endpoint.
*/
- @property Address address() @nogc nothrow pure @safe
+ @property inout(Address) address() inout @nogc nothrow pure @safe
{
- if (this.family == AF_INET)
+ if (this.family == AddressFamily.inet)
{
return Address(this.address4);
}
- else if (this.family == AF_INET6)
+ else if (this.family == AddressFamily.inet6)
{
return Address(this.address6);
}
@@ -1395,14 +1396,26 @@ struct Endpoint
{
if (address.isV4())
{
- this.family = AF_INET;
- this.address4 = address.toV4();
+ this.address = address.toV4();
}
else if (address.isV6())
{
- this.family = AF_INET6;
- this.address4 = Address4(0);
- this.address6 = address.toV6();
+ this.address = address.toV6();
}
}
+
+ /// ditto
+ @property void address(Address4 address) @nogc nothrow pure @safe
+ {
+ this.family = AddressFamily.inet;
+ this.address4 = address;
+ }
+
+ /// ditto
+ @property void address(Address6 address) @nogc nothrow pure @safe
+ {
+ this.family = AddressFamily.inet6;
+ this.address4 = Address4(0);
+ this.address6 = address;
+ }
}
diff --git a/source/tanya/net/package.d b/source/tanya/net/package.d
index 536715c..37ac2cc 100644
--- a/source/tanya/net/package.d
+++ b/source/tanya/net/package.d
@@ -17,4 +17,5 @@ module tanya.net;
public import tanya.net.iface;
public import tanya.net.inet;
public import tanya.net.ip;
+public import tanya.net.socket;
public import tanya.net.uri;
diff --git a/source/tanya/network/socket.d b/source/tanya/net/socket.d
index bfd192f..0bdb84a 100644
--- a/source/tanya/network/socket.d
+++ b/source/tanya/net/socket.d
@@ -7,37 +7,6 @@
*
* Current API supports only server-side TCP communication.
*
- * Here is an example of a cross-platform blocking server:
- *
- * ---
- * import std.stdio;
- * import tanya.memory;
- * import tanya.network;
- *
- * void main()
- * {
- * auto socket = defaultAllocator.make!StreamSocket(AddressFamily.inet);
- * auto address = defaultAllocator.make!InternetAddress("127.0.0.1",
- * cast(ushort) 8192);
- *
- * socket.setOption(SocketOptionLevel.SOCKET, SocketOption.REUSEADDR, true);
- * socket.blocking = true;
- * socket.bind(address);
- * socket.listen(5);
- *
- * auto client = socket.accept();
- * client.send(cast(const(ubyte)[]) "Test\n");
- *
- * ubyte[100] buf;
- * auto response = client.receive(buf[]);
- *
- * writeln(cast(const(char)[]) buf[0 .. response]);
- *
- * defaultAllocator.dispose(client);
- * defaultAllocator.dispose(socket);
- * }
- * ---
- *
* For an example of an asynchronous server refer to the documentation of the
* $(D_PSYMBOL tanya.async.loop) module.
*
@@ -48,7 +17,7 @@
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/network/socket.d,
* tanya/network/socket.d)
*/
-module tanya.network.socket;
+module tanya.net.socket;
import core.stdc.errno;
import core.time;
@@ -57,6 +26,8 @@ import tanya.bitmanip;
import tanya.memory.allocator;
import tanya.meta.trait;
import tanya.os.error;
+import tanya.net.iface;
+import tanya.net.ip;
/// Value returned by socket operations on error.
enum int socketError = -1;
@@ -589,26 +560,6 @@ shared static this()
}
/**
- * $(D_PSYMBOL AddressFamily) specifies a communication domain; this selects
- * the protocol family which will be used for communication.
- */
-enum AddressFamily : int
-{
- unspec = 0, /// Unspecified.
- local = 1, /// Local to host (pipes and file-domain).
- unix = local, /// POSIX name for PF_LOCAL.
- inet = 2, /// IP protocol family.
- ax25 = 3, /// Amateur Radio AX.25.
- ipx = 4, /// Novell Internet Protocol.
- appletalk = 5, /// Appletalk DDP.
- netrom = 6, /// Amateur radio NetROM.
- bridge = 7, /// Multiprotocol bridge.
- atmpvc = 8, /// ATM PVCs.
- x25 = 9, /// Reserved for X.25 project.
- inet6 = 10, /// IP version 6.
-}
-
-/**
* $(D_PSYMBOL SocketException) should be thrown only if one of the socket functions
* $(D_PSYMBOL socketError) and sets $(D_PSYMBOL errno), because
* $(D_PSYMBOL SocketException) relies on the $(D_PSYMBOL errno) value.
@@ -1064,13 +1015,13 @@ class StreamSocket : Socket, ConnectionOrientedSocket
* Associate a local address with this socket.
*
* Params:
- * address = Local address.
+ * endpoint = Local address.
*
* Throws: $(D_PSYMBOL SocketException) if unable to bind.
*/
- void bind(Address address) const @trusted @nogc
+ void bind(const Endpoint endpoint) const @nogc
{
- if (.bind(handle_, address.name, address.length) == socketError)
+ if (.bind(handle_, cast(const(sockaddr)*) &endpoint, Endpoint.sizeof))
{
throw defaultAllocator.make!SocketException("Unable to bind socket");
}
@@ -1269,157 +1220,6 @@ class ConnectedSocket : Socket, ConnectionOrientedSocket
}
/**
- * Socket address representation.
- */
-abstract class Address
-{
- /**
- * Returns: Pointer to underlying $(D_PSYMBOL sockaddr) structure.
- */
- abstract @property inout(sockaddr)* name() inout pure nothrow @nogc;
-
- /**
- * Returns: Actual size of underlying $(D_PSYMBOL sockaddr) structure.
- */
- abstract @property inout(socklen_t) length() inout const pure nothrow @nogc;
-}
-
-class InternetAddress : Address
-{
- version (Windows)
- {
- /// Internal internet address representation.
- protected SOCKADDR_STORAGE storage;
- }
- else version (Posix)
- {
- /// Internal internet address representation.
- protected sockaddr_storage storage;
- }
- const ushort port_;
-
- enum ushort anyPort = 0;
-
- this(string host, const ushort port = anyPort) @nogc
- {
- if (getaddrinfoPointer is null || freeaddrinfoPointer is null)
- {
- throw make!SocketException(defaultAllocator,
- "Address info lookup is not available on this system");
- }
- addrinfo* ai_res;
- this.port_ = port;
-
- // Make C-string from host.
- auto node = cast(char[]) allocator.allocate(host.length + 1);
- node[0 .. $ - 1] = host;
- node[$ - 1] = '\0';
- scope (exit)
- {
- allocator.deallocate(node);
- }
-
- // Convert port to a C-string.
- char[6] service = [0, 0, 0, 0, 0, 0];
- const(char)* servicePointer;
- if (port)
- {
- ushort originalPort = port;
- ushort start;
- for (ushort j = 10, i = 4; i > 0; j *= 10, --i)
- {
- ushort rest = originalPort % 10;
- if (rest != 0)
- {
- service[i] = cast(char) (rest + '0');
- start = i;
- }
- originalPort /= 10;
- }
- servicePointer = service[start .. $].ptr;
- }
-
- auto ret = getaddrinfoPointer(node.ptr, servicePointer, null, &ai_res);
- if (ret)
- {
- throw defaultAllocator.make!SocketException("Address info lookup failed");
- }
- scope (exit)
- {
- freeaddrinfoPointer(ai_res);
- }
-
- ubyte* dp = cast(ubyte*) &storage, sp = cast(ubyte*) ai_res.ai_addr;
- for (auto i = ai_res.ai_addrlen; i > 0; --i, *dp++, *sp++)
- {
- *dp = *sp;
- }
- if (ai_res.ai_family != AddressFamily.inet && ai_res.ai_family != AddressFamily.inet6)
- {
- throw defaultAllocator.make!SocketException("Wrong address family");
- }
- }
-
- ///
- unittest
- {
- auto address = defaultAllocator.make!InternetAddress("127.0.0.1");
- assert(address.port == InternetAddress.anyPort);
- assert(address.name !is null);
- assert(address.family == AddressFamily.inet);
-
- defaultAllocator.dispose(address);
- }
-
- /**
- * Returns: Pointer to underlying $(D_PSYMBOL sockaddr) structure.
- */
- override @property inout(sockaddr)* name() inout pure nothrow @nogc
- {
- return cast(sockaddr*) &storage;
- }
-
- /**
- * Returns: Actual size of underlying $(D_PSYMBOL sockaddr) structure.
- */
- override @property inout(socklen_t) length() inout const pure nothrow @nogc
- {
- // FreeBSD wants to know the exact length of the address on bind.
- switch (family)
- {
- case AddressFamily.inet:
- return sockaddr_in.sizeof;
- case AddressFamily.inet6:
- return sockaddr_in6.sizeof;
- default:
- assert(false);
- }
- }
-
- /**
- * Returns: Family of this address.
- */
- @property inout(AddressFamily) family() inout const pure nothrow @nogc
- {
- return cast(AddressFamily) storage.ss_family;
- }
-
- @property inout(ushort) port() inout const pure nothrow @nogc
- {
- return port_;
- }
-
- ///
- unittest
- {
- auto address = defaultAllocator.make!InternetAddress("127.0.0.1",
- cast(ushort) 1234);
- assert(address.port == 1234);
- defaultAllocator.dispose(address);
- }
-}
-
-/**
* Checks if the last error is a serious error or just a special
* behaviour error of non-blocking sockets (for example an error
* returned because the socket would block or because the
diff --git a/source/tanya/network/package.d b/source/tanya/network/package.d
deleted file mode 100644
index 8c349ec..0000000
--- a/source/tanya/network/package.d
+++ /dev/null
@@ -1,17 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/**
- * Network programming.
- *
- * Copyright: Eugene Wissner 2016-2020.
- * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
- * Mozilla Public License, v. 2.0).
- * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
- * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/network/package.d,
- * tanya/network/package.d)
- */
-module tanya.network;
-
-public import tanya.network.socket;