diff --git a/headers/private/net/net_protocol.h b/headers/private/net/net_protocol.h index ef4745d95a..b01a36b739 100644 --- a/headers/private/net/net_protocol.h +++ b/headers/private/net/net_protocol.h @@ -112,7 +112,8 @@ struct net_protocol_module_info { int flags); ssize_t (*read_data_no_buffer)(net_protocol* self, const iovec* vecs, size_t vecCount, ancillary_data_container** _ancillaryData, - struct sockaddr* _address, socklen_t* _addressLength); + struct sockaddr* _address, socklen_t* _addressLength, + int flags); }; diff --git a/src/add-ons/kernel/network/protocols/unix/UnixDatagramEndpoint.cpp b/src/add-ons/kernel/network/protocols/unix/UnixDatagramEndpoint.cpp index 0af3bfb7ec..c497705a72 100644 --- a/src/add-ons/kernel/network/protocols/unix/UnixDatagramEndpoint.cpp +++ b/src/add-ons/kernel/network/protocols/unix/UnixDatagramEndpoint.cpp @@ -320,16 +320,19 @@ UnixDatagramEndpoint::Send(const iovec* vecs, size_t vecCount, ssize_t UnixDatagramEndpoint::Receive(const iovec* vecs, size_t vecCount, ancillary_data_container** _ancillaryData, struct sockaddr* _address, - socklen_t* _addressLength) + socklen_t* _addressLength, int flags) { TRACE("[%" B_PRId32 "] %p->UnixDatagramEndpoint::Receive()\n", find_thread(NULL), this); - bigtime_t timeout = absolute_timeout(socket->receive.timeout); - if (gStackModule->is_restarted_syscall()) - timeout = gStackModule->restore_syscall_restart_timeout(); - else - gStackModule->store_syscall_restart_timeout(timeout); + bigtime_t timeout = 0; + if ((flags & MSG_DONTWAIT) == 0) { + timeout = absolute_timeout(socket->receive.timeout); + if (gStackModule->is_restarted_syscall()) + timeout = gStackModule->restore_syscall_restart_timeout(); + else + gStackModule->store_syscall_restart_timeout(timeout); + } UnixDatagramEndpointLocker endpointLocker(this); diff --git a/src/add-ons/kernel/network/protocols/unix/UnixDatagramEndpoint.h b/src/add-ons/kernel/network/protocols/unix/UnixDatagramEndpoint.h index 7353ef4581..bc71ac99ef 100644 --- a/src/add-ons/kernel/network/protocols/unix/UnixDatagramEndpoint.h +++ b/src/add-ons/kernel/network/protocols/unix/UnixDatagramEndpoint.h @@ -39,7 +39,7 @@ public: ssize_t Receive(const iovec* vecs, size_t vecCount, ancillary_data_container** _ancillaryData, struct sockaddr* _address, - socklen_t* _addressLength) override; + socklen_t* _addressLength, int flags) override; ssize_t Sendable() override; ssize_t Receivable() override; diff --git a/src/add-ons/kernel/network/protocols/unix/UnixEndpoint.h b/src/add-ons/kernel/network/protocols/unix/UnixEndpoint.h index 143589bdde..8e21a0482f 100644 --- a/src/add-ons/kernel/network/protocols/unix/UnixEndpoint.h +++ b/src/add-ons/kernel/network/protocols/unix/UnixEndpoint.h @@ -59,7 +59,8 @@ public: socklen_t addressLength, int flags) = 0; virtual ssize_t Receive(const iovec* vecs, size_t vecCount, ancillary_data_container** _ancillaryData, - struct sockaddr* _address, socklen_t* _addressLength) = 0; + struct sockaddr* _address, socklen_t* _addressLength, + int flags) = 0; virtual ssize_t Sendable() = 0; virtual ssize_t Receivable() = 0; diff --git a/src/add-ons/kernel/network/protocols/unix/UnixStreamEndpoint.cpp b/src/add-ons/kernel/network/protocols/unix/UnixStreamEndpoint.cpp index 478b025d24..fc6e1a5e6b 100644 --- a/src/add-ons/kernel/network/protocols/unix/UnixStreamEndpoint.cpp +++ b/src/add-ons/kernel/network/protocols/unix/UnixStreamEndpoint.cpp @@ -468,16 +468,19 @@ UnixStreamEndpoint::Send(const iovec* vecs, size_t vecCount, ssize_t UnixStreamEndpoint::Receive(const iovec* vecs, size_t vecCount, ancillary_data_container** _ancillaryData, struct sockaddr* _address, - socklen_t* _addressLength) + socklen_t* _addressLength, int flags) { TRACE("[%" B_PRId32 "] %p->UnixStreamEndpoint::Receive(%p, %ld)\n", find_thread(NULL), this, vecs, vecCount); - bigtime_t timeout = absolute_timeout(socket->receive.timeout); - if (gStackModule->is_restarted_syscall()) - timeout = gStackModule->restore_syscall_restart_timeout(); - else - gStackModule->store_syscall_restart_timeout(timeout); + bigtime_t timeout = 0; + if ((flags & MSG_DONTWAIT) == 0) { + timeout = absolute_timeout(socket->receive.timeout); + if (gStackModule->is_restarted_syscall()) + timeout = gStackModule->restore_syscall_restart_timeout(); + else + gStackModule->store_syscall_restart_timeout(timeout); + } UnixStreamEndpointLocker locker(this); diff --git a/src/add-ons/kernel/network/protocols/unix/UnixStreamEndpoint.h b/src/add-ons/kernel/network/protocols/unix/UnixStreamEndpoint.h index fd773adecb..01adac032d 100644 --- a/src/add-ons/kernel/network/protocols/unix/UnixStreamEndpoint.h +++ b/src/add-ons/kernel/network/protocols/unix/UnixStreamEndpoint.h @@ -55,7 +55,7 @@ public: ssize_t Receive(const iovec* vecs, size_t vecCount, ancillary_data_container** _ancillaryData, struct sockaddr* _address, - socklen_t* _addressLength) override; + socklen_t* _addressLength, int flags) override; ssize_t Sendable() override; ssize_t Receivable() override; diff --git a/src/add-ons/kernel/network/protocols/unix/unix.cpp b/src/add-ons/kernel/network/protocols/unix/unix.cpp index 45ff2dd2de..4c848e9149 100644 --- a/src/add-ons/kernel/network/protocols/unix/unix.cpp +++ b/src/add-ons/kernel/network/protocols/unix/unix.cpp @@ -418,10 +418,10 @@ unix_send_data_no_buffer(net_protocol *_protocol, const iovec *vecs, ssize_t unix_read_data_no_buffer(net_protocol *_protocol, const iovec *vecs, size_t vecCount, ancillary_data_container **_ancillaryData, - struct sockaddr *_address, socklen_t *_addressLength) + struct sockaddr *_address, socklen_t *_addressLength, int flags) { return ((UnixEndpoint*)_protocol)->Receive(vecs, vecCount, _ancillaryData, - _address, _addressLength); + _address, _addressLength, flags); } diff --git a/src/add-ons/kernel/network/stack/net_socket.cpp b/src/add-ons/kernel/network/stack/net_socket.cpp index c15f51d292..4e7dcfbe7b 100644 --- a/src/add-ons/kernel/network/stack/net_socket.cpp +++ b/src/add-ons/kernel/network/stack/net_socket.cpp @@ -302,7 +302,7 @@ socket_receive_no_buffer(net_socket* socket, msghdr* header, void* data, ancillary_data_container* ancillaryData = NULL; ssize_t bytesRead = socket->first_info->read_data_no_buffer( socket->first_protocol, vecs, vecCount, &ancillaryData, address, - addressLen); + addressLen, flags); if (bytesRead < 0) return bytesRead; diff --git a/src/tests/system/network/Jamfile b/src/tests/system/network/Jamfile index fb9e07c487..265fc49c77 100644 --- a/src/tests/system/network/Jamfile +++ b/src/tests/system/network/Jamfile @@ -19,6 +19,7 @@ SimpleTest if_nameindex : if_nameindex.c : $(TARGET_NETWORK_LIBS) ; SimpleTest unix_dgram_test : unix_dgram_test.cpp : $(TARGET_NETWORK_LIBS) ; +SimpleTest unix_recv_test : unix_recv_test.c : $(TARGET_NETWORK_LIBS) ; SimpleTest unix_send_test : unix_send_test.c : $(TARGET_NETWORK_LIBS) ; SimpleTest tcp_connection_test : tcp_connection_test.cpp diff --git a/src/tests/system/network/unix_recv_test.c b/src/tests/system/network/unix_recv_test.c new file mode 100644 index 0000000000..9f699ec912 --- /dev/null +++ b/src/tests/system/network/unix_recv_test.c @@ -0,0 +1,46 @@ +#include +#include +#include +#include + +int main() { + int fds[2]; + int domain; + domain = AF_UNIX; + // domain = AF_INET; // works + printf("Domain: %i\n", domain); + int ret = socketpair(domain, SOCK_DGRAM, 0, fds); // try also: SOCK_STREAM + if(ret) { + perror("Could not get socketpair"); + return 1; + } + + /* + struct timeval v = { + .tv_sec = 1, + .tv_usec = 0 + }; + ret = setsockopt(fds[0], SOL_SOCKET, SO_RCVTIMEO, &v, sizeof(v)); + if(ret) { + perror("setsockopt"); + } + */ + + size_t bufLen = 1024; + char *buf = calloc(bufLen, 1); + int ok = 0; + while(true) { + printf("recv %i\n", ok); + ret = recv(fds[0], &buf[0], bufLen, MSG_DONTWAIT); + // expected: EWOULDBLOCK/EAGAIN (on Linux, macOS, Haiku) + printf("%i\n", ret); + if(ret < 0) { + perror("recv"); + break; + } else { + ok++; + } + } + + return 0; +}