network: Migrate SIGPIPE generation into the socket module.

This removes the burden of determining whether to and then
actually sending SIGPIPE from the protocol modules, meaning
the MSG_NOSIGNAL flag can now be implemented entirely in
the socket module and not even passed further down the chain.

Change-Id: I9ba976c4aff60d533cb4b390bbba1560c0de423f
Reviewed-on: https://review.haiku-os.org/c/haiku/+/7124
Reviewed-by: Jérôme Duval <jerome.duval@gmail.com>
Reviewed-by: waddlesplash <waddlesplash@gmail.com>
This commit is contained in:
Augustin Cavalier 2023-11-22 23:44:25 -05:00 committed by waddlesplash
parent da2f2c65b7
commit 973f6d3320
4 changed files with 19 additions and 19 deletions

View File

@ -814,19 +814,15 @@ TCPEndpoint::SendData(net_buffer *buffer)
T(APICall(this, "senddata"));
const uint32 flags = buffer->flags;
if ((flags & ~(MSG_NOSIGNAL | MSG_DONTWAIT | MSG_OOB | MSG_EOF)) != 0)
if ((flags & ~(MSG_DONTWAIT | MSG_OOB | MSG_EOF)) != 0)
return EOPNOTSUPP;
if (fState == CLOSED)
return ENOTCONN;
if (fState == LISTEN)
return EDESTADDRREQ;
if (!is_writable(fState) && !is_establishing(fState)) {
// we only send signals when called from userland
if (gStackModule->is_syscall() && (flags & MSG_NOSIGNAL) == 0)
send_signal(find_thread(NULL), SIGPIPE);
if (!is_writable(fState) && !is_establishing(fState))
return EPIPE;
}
size_t left = buffer->size;
@ -849,12 +845,8 @@ TCPEndpoint::SendData(net_buffer *buffer)
return posix_error(status);
}
if (!is_writable(fState) && !is_establishing(fState)) {
// we only send signals when called from userland
if (gStackModule->is_syscall() && (flags & MSG_NOSIGNAL) == 0)
send_signal(find_thread(NULL), SIGPIPE);
if (!is_writable(fState) && !is_establishing(fState))
return EPIPE;
}
}
size_t size = fSendQueue.Free();

View File

@ -215,7 +215,7 @@ UnixDatagramEndpoint::Send(const iovec* vecs, size_t vecCount,
TRACE("[%" B_PRId32 "] %p->UnixDatagramEndpoint::Send()\n",
find_thread(NULL), this);
if ((flags & ~(MSG_DONTWAIT | MSG_NOSIGNAL)) != 0)
if ((flags & ~(MSG_DONTWAIT)) != 0)
return EOPNOTSUPP;
bigtime_t timeout = 0;
@ -307,8 +307,7 @@ UnixDatagramEndpoint::Send(const iovec* vecs, size_t vecCount,
switch (result) {
case EPIPE:
if (gStackModule->is_syscall() && (flags & MSG_NOSIGNAL) == 0)
send_signal(find_thread(NULL), SIGPIPE);
// The socket module will generate SIGPIPE for us, if necessary.
break;
case B_TIMED_OUT:
if (timeout == 0)

View File

@ -379,7 +379,7 @@ UnixStreamEndpoint::Send(const iovec* vecs, size_t vecCount,
TRACE("[%" B_PRId32 "] %p->UnixStreamEndpoint::Send(%p, %ld, %p)\n",
find_thread(NULL), this, vecs, vecCount, ancillaryData);
if ((flags & ~(MSG_DONTWAIT | MSG_NOSIGNAL)) != 0)
if ((flags & ~(MSG_DONTWAIT)) != 0)
return EOPNOTSUPP;
bigtime_t timeout = 0;
@ -452,10 +452,7 @@ UnixStreamEndpoint::Send(const iovec* vecs, size_t vecCount,
}
break;
case EPIPE:
// The peer closed connection or shutdown its read side. Reward
// the caller with a SIGPIPE.
if (gStackModule->is_syscall() && (flags & MSG_NOSIGNAL) == 0)
send_signal(find_thread(NULL), SIGPIPE);
// The socket module will generate SIGPIPE for us, if necessary.
break;
case B_TIMED_OUT:
// Translate non-blocking timeouts to the correct error code.

View File

@ -1333,6 +1333,9 @@ socket_send(net_socket* socket, msghdr* header, const void* data, size_t length,
socklen_t addressLength = 0;
size_t bytesLeft = length;
const bool nosignal = ((flags & MSG_NOSIGNAL) != 0);
flags &= ~MSG_NOSIGNAL;
if (length > SSIZE_MAX)
return B_BAD_VALUE;
@ -1398,6 +1401,11 @@ socket_send(net_socket* socket, msghdr* header, const void* data, size_t length,
ssize_t written = socket->first_info->send_data_no_buffer(
socket->first_protocol, vecs, vecCount, ancillaryData, address,
addressLength, flags);
// we only send signals when called from userland
if (written == EPIPE && is_syscall() && !nosignal)
send_signal(find_thread(NULL), SIGPIPE);
if (written > 0)
ancillaryDataDeleter.Detach();
return written;
@ -1473,6 +1481,10 @@ socket_send(net_socket* socket, msghdr* header, const void* data, size_t length,
status = socket->first_info->send_data(socket->first_protocol, buffer);
if (status != B_OK) {
// we only send signals when called from userland
if (status == EPIPE && is_syscall() && !nosignal)
send_signal(find_thread(NULL), SIGPIPE);
size_t sizeAfterSend = buffer->size;
gNetBufferModule.free(buffer);