forked from Minki/linux
af_vsock: implement SEQPACKET receive loop
Add receive loop for SEQPACKET. It looks like receive loop for STREAM, but there are differences: 1) It doesn't call notify callbacks. 2) It doesn't care about 'SO_SNDLOWAT' and 'SO_RCVLOWAT' values, because there is no sense for these values in SEQPACKET case. 3) It waits until whole record is received. 4) It processes and sets 'MSG_TRUNC' flag. So to avoid extra conditions for two types of socket inside one loop, two independent functions were created. Signed-off-by: Arseny Krasnov <arseny.krasnov@kaspersky.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
19c1b90e19
commit
9942c192b2
@ -135,6 +135,10 @@ struct vsock_transport {
|
||||
bool (*stream_is_active)(struct vsock_sock *);
|
||||
bool (*stream_allow)(u32 cid, u32 port);
|
||||
|
||||
/* SEQ_PACKET. */
|
||||
ssize_t (*seqpacket_dequeue)(struct vsock_sock *vsk, struct msghdr *msg,
|
||||
int flags);
|
||||
|
||||
/* Notification. */
|
||||
int (*notify_poll_in)(struct vsock_sock *, size_t, bool *);
|
||||
int (*notify_poll_out)(struct vsock_sock *, size_t, bool *);
|
||||
|
@ -1974,6 +1974,56 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __vsock_seqpacket_recvmsg(struct sock *sk, struct msghdr *msg,
|
||||
size_t len, int flags)
|
||||
{
|
||||
const struct vsock_transport *transport;
|
||||
struct vsock_sock *vsk;
|
||||
ssize_t record_len;
|
||||
long timeout;
|
||||
int err = 0;
|
||||
DEFINE_WAIT(wait);
|
||||
|
||||
vsk = vsock_sk(sk);
|
||||
transport = vsk->transport;
|
||||
|
||||
timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
|
||||
|
||||
err = vsock_wait_data(sk, &wait, timeout, NULL, 0);
|
||||
if (err <= 0)
|
||||
goto out;
|
||||
|
||||
record_len = transport->seqpacket_dequeue(vsk, msg, flags);
|
||||
|
||||
if (record_len < 0) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (sk->sk_err) {
|
||||
err = -sk->sk_err;
|
||||
} else if (sk->sk_shutdown & RCV_SHUTDOWN) {
|
||||
err = 0;
|
||||
} else {
|
||||
/* User sets MSG_TRUNC, so return real length of
|
||||
* packet.
|
||||
*/
|
||||
if (flags & MSG_TRUNC)
|
||||
err = record_len;
|
||||
else
|
||||
err = len - msg_data_left(msg);
|
||||
|
||||
/* Always set MSG_TRUNC if real length of packet is
|
||||
* bigger than user's buffer.
|
||||
*/
|
||||
if (record_len > len)
|
||||
msg->msg_flags |= MSG_TRUNC;
|
||||
}
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
vsock_connectible_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
|
||||
int flags)
|
||||
@ -2029,7 +2079,10 @@ vsock_connectible_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = __vsock_stream_recvmsg(sk, msg, len, flags);
|
||||
if (sk->sk_type == SOCK_STREAM)
|
||||
err = __vsock_stream_recvmsg(sk, msg, len, flags);
|
||||
else
|
||||
err = __vsock_seqpacket_recvmsg(sk, msg, len, flags);
|
||||
|
||||
out:
|
||||
release_sock(sk);
|
||||
|
Loading…
Reference in New Issue
Block a user