Commit 9942c192 authored by Arseny Krasnov's avatar Arseny Krasnov Committed by David S. Miller

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: default avatarArseny Krasnov <arseny.krasnov@kaspersky.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 19c1b90e
......@@ -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 @@ static int __vsock_stream_recvmsg(struct sock *sk, struct msghdr *msg,
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;
}
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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment