net: sockets: Implement MSG_WAITALL recv flag
Implement MSG_WAITALL flag for stream sockets. Setting this flag on `recv()` call will make it wait until the requested amount of data is received. In case both, MSG_WAITALL all is set and SO_RCVTIMEO option configured on a socket, follow the Linux behavior, i. e. when the requested amount of data is not received until the timeout expires, return the data received so far w/o an error. Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
This commit is contained in:
parent
a81765bbe4
commit
d47e803976
|
@ -57,6 +57,8 @@ struct zsock_pollfd {
|
|||
#define ZSOCK_MSG_PEEK 0x02
|
||||
/** zsock_recv/zsock_send: Override operation to non-blocking */
|
||||
#define ZSOCK_MSG_DONTWAIT 0x40
|
||||
/** zsock_recv: block until the full amount of data can be returned */
|
||||
#define ZSOCK_MSG_WAITALL 0x100
|
||||
|
||||
/* Well-known values, e.g. from Linux man 2 shutdown:
|
||||
* "The constants SHUT_RD, SHUT_WR, SHUT_RDWR have the value 0, 1, 2,
|
||||
|
@ -772,6 +774,7 @@ static inline char *inet_ntop(sa_family_t family, const void *src, char *dst,
|
|||
|
||||
#define MSG_PEEK ZSOCK_MSG_PEEK
|
||||
#define MSG_DONTWAIT ZSOCK_MSG_DONTWAIT
|
||||
#define MSG_WAITALL ZSOCK_MSG_WAITALL
|
||||
|
||||
#define SHUT_RD ZSOCK_SHUT_RD
|
||||
#define SHUT_WR ZSOCK_SHUT_WR
|
||||
|
|
|
@ -29,6 +29,7 @@ static inline int socketpair(int family, int type, int proto, int sv[2])
|
|||
|
||||
#define MSG_PEEK ZSOCK_MSG_PEEK
|
||||
#define MSG_DONTWAIT ZSOCK_MSG_DONTWAIT
|
||||
#define MSG_WAITALL ZSOCK_MSG_WAITALL
|
||||
|
||||
static inline int shutdown(int sock, int how)
|
||||
{
|
||||
|
|
|
@ -1028,6 +1028,8 @@ static inline ssize_t zsock_recv_stream(struct net_context *ctx,
|
|||
size_t recv_len = 0;
|
||||
struct net_pkt_cursor backup;
|
||||
int res;
|
||||
uint64_t end;
|
||||
const bool waitall = flags & ZSOCK_MSG_WAITALL;
|
||||
|
||||
if (!net_context_is_used(ctx)) {
|
||||
errno = EBADF;
|
||||
|
@ -1045,9 +1047,12 @@ static inline ssize_t zsock_recv_stream(struct net_context *ctx,
|
|||
net_context_get_option(ctx, NET_OPT_RCVTIMEO, &timeout, NULL);
|
||||
}
|
||||
|
||||
end = z_timeout_end_calc(timeout);
|
||||
|
||||
do {
|
||||
struct net_pkt *pkt;
|
||||
size_t data_len;
|
||||
size_t data_len, read_len;
|
||||
bool release_pkt = true;
|
||||
|
||||
if (sock_is_eof(ctx)) {
|
||||
return 0;
|
||||
|
@ -1066,7 +1071,10 @@ static inline ssize_t zsock_recv_stream(struct net_context *ctx,
|
|||
* due to connection closure by peer.
|
||||
*/
|
||||
NET_DBG("NULL return from fifo");
|
||||
if (sock_is_eof(ctx)) {
|
||||
|
||||
if (waitall && (recv_len > 0)) {
|
||||
return recv_len;
|
||||
} else if (sock_is_eof(ctx)) {
|
||||
return 0;
|
||||
} else {
|
||||
errno = EAGAIN;
|
||||
|
@ -1077,19 +1085,22 @@ static inline ssize_t zsock_recv_stream(struct net_context *ctx,
|
|||
net_pkt_cursor_backup(pkt, &backup);
|
||||
|
||||
data_len = net_pkt_remaining_data(pkt);
|
||||
recv_len = data_len;
|
||||
if (recv_len > max_len) {
|
||||
recv_len = max_len;
|
||||
read_len = data_len;
|
||||
if (recv_len + read_len > max_len) {
|
||||
read_len = max_len - recv_len;
|
||||
release_pkt = false;
|
||||
}
|
||||
|
||||
/* Actually copy data to application buffer */
|
||||
if (net_pkt_read(pkt, buf, recv_len)) {
|
||||
if (net_pkt_read(pkt, (uint8_t *)buf + recv_len, read_len)) {
|
||||
errno = ENOBUFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
recv_len += read_len;
|
||||
|
||||
if (!(flags & ZSOCK_MSG_PEEK)) {
|
||||
if (recv_len == data_len) {
|
||||
if (release_pkt) {
|
||||
/* Finished processing head pkt in
|
||||
* the fifo. Drop it from there.
|
||||
*/
|
||||
|
@ -1108,7 +1119,19 @@ static inline ssize_t zsock_recv_stream(struct net_context *ctx,
|
|||
} else {
|
||||
net_pkt_cursor_restore(pkt, &backup);
|
||||
}
|
||||
} while (recv_len == 0);
|
||||
|
||||
/* Update the timeout value in case loop is repeated. */
|
||||
if (!K_TIMEOUT_EQ(timeout, K_NO_WAIT) &&
|
||||
!K_TIMEOUT_EQ(timeout, K_FOREVER)) {
|
||||
int64_t remaining = end - z_tick_get();
|
||||
|
||||
if (remaining <= 0) {
|
||||
timeout = K_NO_WAIT;
|
||||
} else {
|
||||
timeout = Z_TIMEOUT_TICKS(remaining);
|
||||
}
|
||||
}
|
||||
} while ((recv_len == 0) || (waitall && (recv_len < max_len)));
|
||||
|
||||
if (!(flags & ZSOCK_MSG_PEEK)) {
|
||||
net_context_update_recv_wnd(ctx, recv_len);
|
||||
|
|
Loading…
Reference in a new issue