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

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
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -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 *);
+54 −1
Original line number Diff line number Diff line
@@ -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);