From 3826a82ede82c7d85a5c4f8074e05e63ccdee56a Mon Sep 17 00:00:00 2001 From: Vladimir Panteleev Date: Mon, 26 Jan 2026 18:24:50 +0000 Subject: [PATCH] std.socket: Add accept overload that returns peer address Add a new accept(out Address peerAddress) method to Socket that accepts an incoming connection while also retrieving the connecting peer's address. This avoids the need for a separate call to get the peer address after accepting, which also addresses a race condition which can occur when the peer disconnects between the accept and getPeerAddress calls. --- std/socket.d | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/std/socket.d b/std/socket.d index e48bf565971..8f29c78f59f 100644 --- a/std/socket.d +++ b/std/socket.d @@ -2966,6 +2966,43 @@ public: return newSocket; } + /** + * Accept an incoming connection and retrieve the peer `Address`. If the + * socket is blocking, `accept` waits for a connection request. Throws + * `SocketAcceptException` if unable to _accept. See `accepting` for use + * with derived classes. + */ + Socket accept(out Address peerAddress) @trusted + { + Address addr = createAddress(); + socklen_t nameLen = addr.nameLen; + auto newsock = cast(socket_t).accept(sock, addr.name, &nameLen); + if (socket_t.init == newsock) + throw new SocketAcceptException("Unable to accept socket connection"); + + addr.setNameLen(nameLen); + peerAddress = addr; + + Socket newSocket; + try + { + newSocket = accepting(); + assert(newSocket.sock == socket_t.init); + + newSocket.setSock(newsock); + version (Windows) + newSocket._blocking = _blocking; //inherits blocking mode + newSocket._family = _family; //same family + } + catch (Throwable o) + { + _close(newsock); + throw o; + } + + return newSocket; + } + /// Disables sends and/or receives. void shutdown(SocketShutdown how) @trusted nothrow @nogc { @@ -3687,6 +3724,10 @@ class UdpSocket: Socket { checkAttributes!q{@trusted}; assert(0); } + @trusted Socket accept(out Address peerAddress) + { + checkAttributes!q{@trusted}; assert(0); + } nothrow @nogc @trusted void shutdown(SocketShutdown how) { checkAttributes!q{nothrow @nogc @trusted}; @@ -3859,3 +3900,26 @@ Socket[2] socketPair() @trusted pair[1].receive(buf); assert(buf == data); } + +// Test accept with peer address +@safe unittest +{ + auto listener = new TcpSocket(); + scope(exit) listener.close(); + listener.setOption(SocketOptionLevel.SOCKET, SocketOption.REUSEADDR, true); + listener.bind(new InternetAddress(INADDR_LOOPBACK, InternetAddress.PORT_ANY)); + auto serverAddr = listener.localAddress; + listener.listen(1); + + auto client = new TcpSocket(serverAddr); + scope(exit) client.close(); + + Address peerAddress; + auto server = listener.accept(peerAddress); + scope(exit) server.close(); + + assert(peerAddress !is null); + assert(peerAddress.addressFamily == AddressFamily.INET); + // The peer address should match the client's local address + assert(peerAddress.toAddrString() == client.localAddress.toAddrString()); +}