Commit ec8a09fb authored by Jon Paul Maloy's avatar Jon Paul Maloy Committed by David S. Miller

tipc: refactor function tipc_sk_recv_stream()

We try to make this function more readable by improving variable names
and comments, using more stack variables, and doing some smaller changes
to the logics. We also rename the function to make it consistent with
naming conventions used elsewhere in the code.
Reviewed-by: default avatarParthasarathy Bhuvaragan <parthasarathy.bhuvaragan@ericsson.com>
Signed-off-by: default avatarJon Maloy <jon.maloy@ericsson.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e9f8b101
...@@ -1375,9 +1375,9 @@ static int tipc_recvmsg(struct socket *sock, struct msghdr *m, ...@@ -1375,9 +1375,9 @@ static int tipc_recvmsg(struct socket *sock, struct msghdr *m,
} }
/** /**
* tipc_recv_stream - receive stream-oriented data * tipc_recvstream - receive stream-oriented data
* @m: descriptor for message info * @m: descriptor for message info
* @buf_len: total size of user buffer area * @buflen: total size of user buffer area
* @flags: receive flags * @flags: receive flags
* *
* Used for SOCK_STREAM messages only. If not enough data is available * Used for SOCK_STREAM messages only. If not enough data is available
...@@ -1385,111 +1385,98 @@ static int tipc_recvmsg(struct socket *sock, struct msghdr *m, ...@@ -1385,111 +1385,98 @@ static int tipc_recvmsg(struct socket *sock, struct msghdr *m,
* *
* Returns size of returned message data, errno otherwise * Returns size of returned message data, errno otherwise
*/ */
static int tipc_recv_stream(struct socket *sock, struct msghdr *m, static int tipc_recvstream(struct socket *sock, struct msghdr *m,
size_t buf_len, int flags) size_t buflen, int flags)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct tipc_sock *tsk = tipc_sk(sk); struct tipc_sock *tsk = tipc_sk(sk);
struct sk_buff *buf; struct sk_buff *skb;
struct tipc_msg *msg; struct tipc_msg *hdr;
long timeo; struct tipc_skb_cb *skb_cb;
unsigned int sz; bool peek = flags & MSG_PEEK;
int target; int offset, required, copy, copied = 0;
int sz_copied = 0; int hlen, dlen, err, rc;
u32 err; long timeout;
int res = 0, hlen;
/* Catch invalid receive attempts */ /* Catch invalid receive attempts */
if (unlikely(!buf_len)) if (unlikely(!buflen))
return -EINVAL; return -EINVAL;
lock_sock(sk); lock_sock(sk);
if (unlikely(sk->sk_state == TIPC_OPEN)) { if (unlikely(sk->sk_state == TIPC_OPEN)) {
res = -ENOTCONN; rc = -ENOTCONN;
goto exit; goto exit;
} }
required = sock_rcvlowat(sk, flags & MSG_WAITALL, buflen);
timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
target = sock_rcvlowat(sk, flags & MSG_WAITALL, buf_len); do {
timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); /* Look at first msg in receive queue; wait if necessary */
rc = tipc_wait_for_rcvmsg(sock, &timeout);
restart: if (unlikely(rc))
/* Look for a message in receive queue; wait if necessary */ break;
res = tipc_wait_for_rcvmsg(sock, &timeo); skb = skb_peek(&sk->sk_receive_queue);
if (res) skb_cb = TIPC_SKB_CB(skb);
goto exit; hdr = buf_msg(skb);
dlen = msg_data_sz(hdr);
/* Look at first message in receive queue */ hlen = msg_hdr_sz(hdr);
buf = skb_peek(&sk->sk_receive_queue); err = msg_errcode(hdr);
msg = buf_msg(buf);
sz = msg_data_sz(msg);
hlen = msg_hdr_sz(msg);
err = msg_errcode(msg);
/* Discard an empty non-errored message & try again */ /* Discard any empty non-errored (SYN-) message */
if ((!sz) && (!err)) { if (unlikely(!dlen && !err)) {
tsk_advance_rx_queue(sk); tsk_advance_rx_queue(sk);
goto restart; continue;
} }
/* Optionally capture sender's address & ancillary data of first msg */ /* Collect msg meta data, incl. error code and rejected data */
if (sz_copied == 0) { if (!copied) {
set_orig_addr(m, msg); set_orig_addr(m, hdr);
res = tipc_sk_anc_data_recv(m, msg, tsk); rc = tipc_sk_anc_data_recv(m, hdr, tsk);
if (res) if (rc)
goto exit; break;
} }
/* Capture message data (if valid) & compute return value (always) */ /* Copy data if msg ok, otherwise return error/partial data */
if (!err) { if (likely(!err)) {
u32 offset = TIPC_SKB_CB(buf)->bytes_read; offset = skb_cb->bytes_read;
u32 needed; copy = min_t(int, dlen - offset, buflen - copied);
int sz_to_copy; rc = skb_copy_datagram_msg(skb, hlen + offset, m, copy);
if (unlikely(rc))
sz -= offset; break;
needed = (buf_len - sz_copied); copied += copy;
sz_to_copy = min(sz, needed); offset += copy;
if (unlikely(offset < dlen)) {
res = skb_copy_datagram_msg(buf, hlen + offset, m, sz_to_copy); if (!peek)
if (res) skb_cb->bytes_read = offset;
goto exit; break;
sz_copied += sz_to_copy;
if (sz_to_copy < sz) {
if (!(flags & MSG_PEEK))
TIPC_SKB_CB(buf)->bytes_read =
offset + sz_to_copy;
goto exit;
} }
} else { } else {
if (sz_copied != 0) rc = 0;
goto exit; /* can't add error msg to valid data */ if ((err != TIPC_CONN_SHUTDOWN) && !m->msg_control)
rc = -ECONNRESET;
if ((err == TIPC_CONN_SHUTDOWN) || m->msg_control) if (copied || rc)
res = 0; break;
else
res = -ECONNRESET;
} }
if (unlikely(flags & MSG_PEEK)) if (unlikely(peek))
goto exit; break;
tsk->rcv_unacked += tsk_inc(tsk, hlen + msg_data_sz(msg));
if (unlikely(tsk->rcv_unacked >= (tsk->rcv_win / 4)))
tipc_sk_send_ack(tsk);
tsk_advance_rx_queue(sk); tsk_advance_rx_queue(sk);
/* Loop around if more data is required */ /* Send connection flow control advertisement when applicable */
if ((sz_copied < buf_len) && /* didn't get all requested data */ tsk->rcv_unacked += tsk_inc(tsk, hlen + dlen);
(!skb_queue_empty(&sk->sk_receive_queue) || if (unlikely(tsk->rcv_unacked >= tsk->rcv_win / TIPC_ACK_RATE))
(sz_copied < target)) && /* and more is ready or required */ tipc_sk_send_ack(tsk);
(!err)) /* and haven't reached a FIN */
goto restart; /* Exit if all requested data or FIN/error received */
if (copied == buflen || err)
break;
} while (!skb_queue_empty(&sk->sk_receive_queue) || copied < required);
exit: exit:
release_sock(sk); release_sock(sk);
return sz_copied ? sz_copied : res; return copied ? copied : rc;
} }
/** /**
...@@ -2584,7 +2571,7 @@ static const struct proto_ops stream_ops = { ...@@ -2584,7 +2571,7 @@ static const struct proto_ops stream_ops = {
.setsockopt = tipc_setsockopt, .setsockopt = tipc_setsockopt,
.getsockopt = tipc_getsockopt, .getsockopt = tipc_getsockopt,
.sendmsg = tipc_sendstream, .sendmsg = tipc_sendstream,
.recvmsg = tipc_recv_stream, .recvmsg = tipc_recvstream,
.mmap = sock_no_mmap, .mmap = sock_no_mmap,
.sendpage = sock_no_sendpage .sendpage = sock_no_sendpage
}; };
......
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