Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions std/socket.d
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like the blanket use of trusted here, but I see it is used a lot elsewhere in this file?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the old overload has it too.

{
Address addr = createAddress();
socklen_t nameLen = addr.nameLen;
auto newsock = cast(socket_t).accept(sock, addr.name, &nameLen);
if (socket_t.init == newsock)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (newsock == socket_t.init), why the backwards check?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. That's how the old overload does it - as with the above, this overload is a copy-paste of the existing one with just the new feature, existing style and quirks are maintained for consistency
  2. Writing the constant first is considered best practice in some C style guides, because it makes a == that was typo'd as = an error rather than a silent bug (assignment)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. I figured, but 1 fair. It would be good to update the style though. Thanks!

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
{
Expand Down Expand Up @@ -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};
Expand Down Expand Up @@ -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());
}
Loading