Skip to content

Commit fd27b81

Browse files
authored
std.socket: Add accept overload that returns peer address (#10941)
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.
1 parent 42c7d95 commit fd27b81

File tree

1 file changed

+64
-0
lines changed

1 file changed

+64
-0
lines changed

std/socket.d

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2966,6 +2966,43 @@ public:
29662966
return newSocket;
29672967
}
29682968

2969+
/**
2970+
* Accept an incoming connection and retrieve the peer `Address`. If the
2971+
* socket is blocking, `accept` waits for a connection request. Throws
2972+
* `SocketAcceptException` if unable to _accept. See `accepting` for use
2973+
* with derived classes.
2974+
*/
2975+
Socket accept(out Address peerAddress) @trusted
2976+
{
2977+
Address addr = createAddress();
2978+
socklen_t nameLen = addr.nameLen;
2979+
auto newsock = cast(socket_t).accept(sock, addr.name, &nameLen);
2980+
if (socket_t.init == newsock)
2981+
throw new SocketAcceptException("Unable to accept socket connection");
2982+
2983+
addr.setNameLen(nameLen);
2984+
peerAddress = addr;
2985+
2986+
Socket newSocket;
2987+
try
2988+
{
2989+
newSocket = accepting();
2990+
assert(newSocket.sock == socket_t.init);
2991+
2992+
newSocket.setSock(newsock);
2993+
version (Windows)
2994+
newSocket._blocking = _blocking; //inherits blocking mode
2995+
newSocket._family = _family; //same family
2996+
}
2997+
catch (Throwable o)
2998+
{
2999+
_close(newsock);
3000+
throw o;
3001+
}
3002+
3003+
return newSocket;
3004+
}
3005+
29693006
/// Disables sends and/or receives.
29703007
void shutdown(SocketShutdown how) @trusted nothrow @nogc
29713008
{
@@ -3687,6 +3724,10 @@ class UdpSocket: Socket
36873724
{
36883725
checkAttributes!q{@trusted}; assert(0);
36893726
}
3727+
@trusted Socket accept(out Address peerAddress)
3728+
{
3729+
checkAttributes!q{@trusted}; assert(0);
3730+
}
36903731
nothrow @nogc @trusted void shutdown(SocketShutdown how)
36913732
{
36923733
checkAttributes!q{nothrow @nogc @trusted};
@@ -3859,3 +3900,26 @@ Socket[2] socketPair() @trusted
38593900
pair[1].receive(buf);
38603901
assert(buf == data);
38613902
}
3903+
3904+
// Test accept with peer address
3905+
@safe unittest
3906+
{
3907+
auto listener = new TcpSocket();
3908+
scope(exit) listener.close();
3909+
listener.setOption(SocketOptionLevel.SOCKET, SocketOption.REUSEADDR, true);
3910+
listener.bind(new InternetAddress(INADDR_LOOPBACK, InternetAddress.PORT_ANY));
3911+
auto serverAddr = listener.localAddress;
3912+
listener.listen(1);
3913+
3914+
auto client = new TcpSocket(serverAddr);
3915+
scope(exit) client.close();
3916+
3917+
Address peerAddress;
3918+
auto server = listener.accept(peerAddress);
3919+
scope(exit) server.close();
3920+
3921+
assert(peerAddress !is null);
3922+
assert(peerAddress.addressFamily == AddressFamily.INET);
3923+
// The peer address should match the client's local address
3924+
assert(peerAddress.toAddrString() == client.localAddress.toAddrString());
3925+
}

0 commit comments

Comments
 (0)