Merge branch 'tipc-refactor-socket-receive-functions'
Jon Maloy says: ==================== tipc: refactor socket receive functions We try to make the functions tipc_sk_recvmsg() and tipc_sk_recvstream() more readable. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>zero-colors
commit
5d15af6778
|
@ -51,6 +51,7 @@
|
||||||
#define TIPC_FWD_MSG 1
|
#define TIPC_FWD_MSG 1
|
||||||
#define TIPC_MAX_PORT 0xffffffff
|
#define TIPC_MAX_PORT 0xffffffff
|
||||||
#define TIPC_MIN_PORT 1
|
#define TIPC_MIN_PORT 1
|
||||||
|
#define TIPC_ACK_RATE 4 /* ACK at 1/4 of of rcv window size */
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
TIPC_LISTEN = TCP_LISTEN,
|
TIPC_LISTEN = TCP_LISTEN,
|
||||||
|
@ -1290,7 +1291,7 @@ static int tipc_wait_for_rcvmsg(struct socket *sock, long *timeop)
|
||||||
/**
|
/**
|
||||||
* tipc_recvmsg - receive packet-oriented message
|
* tipc_recvmsg - receive packet-oriented message
|
||||||
* @m: descriptor for message info
|
* @m: descriptor for message info
|
||||||
* @buf_len: total size of user buffer area
|
* @buflen: length of user buffer area
|
||||||
* @flags: receive flags
|
* @flags: receive flags
|
||||||
*
|
*
|
||||||
* Used for SOCK_DGRAM, SOCK_RDM, and SOCK_SEQPACKET messages.
|
* Used for SOCK_DGRAM, SOCK_RDM, and SOCK_SEQPACKET messages.
|
||||||
|
@ -1298,95 +1299,85 @@ static int tipc_wait_for_rcvmsg(struct socket *sock, long *timeop)
|
||||||
*
|
*
|
||||||
* Returns size of returned message data, errno otherwise
|
* Returns size of returned message data, errno otherwise
|
||||||
*/
|
*/
|
||||||
static int tipc_recvmsg(struct socket *sock, struct msghdr *m, size_t buf_len,
|
static int tipc_recvmsg(struct socket *sock, struct msghdr *m,
|
||||||
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;
|
||||||
bool is_connectionless = tipc_sk_type_connectionless(sk);
|
bool connected = !tipc_sk_type_connectionless(sk);
|
||||||
long timeo;
|
int rc, err, hlen, dlen, copy;
|
||||||
unsigned int sz;
|
long timeout;
|
||||||
u32 err;
|
|
||||||
int res, hlen;
|
|
||||||
|
|
||||||
/* Catch invalid receive requests */
|
/* Catch invalid receive requests */
|
||||||
if (unlikely(!buf_len))
|
if (unlikely(!buflen))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
lock_sock(sk);
|
lock_sock(sk);
|
||||||
|
if (unlikely(connected && sk->sk_state == TIPC_OPEN)) {
|
||||||
if (!is_connectionless && unlikely(sk->sk_state == TIPC_OPEN)) {
|
rc = -ENOTCONN;
|
||||||
res = -ENOTCONN;
|
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
|
||||||
|
|
||||||
timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
|
do {
|
||||||
restart:
|
/* Look at first msg in receive queue; wait if necessary */
|
||||||
|
rc = tipc_wait_for_rcvmsg(sock, &timeout);
|
||||||
/* Look for a message in receive queue; wait if necessary */
|
if (unlikely(rc))
|
||||||
res = tipc_wait_for_rcvmsg(sock, &timeo);
|
|
||||||
if (res)
|
|
||||||
goto exit;
|
|
||||||
|
|
||||||
/* Look at first message in receive queue */
|
|
||||||
buf = skb_peek(&sk->sk_receive_queue);
|
|
||||||
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 */
|
|
||||||
if ((!sz) && (!err)) {
|
|
||||||
tsk_advance_rx_queue(sk);
|
|
||||||
goto restart;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Capture sender's address (optional) */
|
|
||||||
set_orig_addr(m, msg);
|
|
||||||
|
|
||||||
/* Capture ancillary data (optional) */
|
|
||||||
res = tipc_sk_anc_data_recv(m, msg, tsk);
|
|
||||||
if (res)
|
|
||||||
goto exit;
|
|
||||||
|
|
||||||
/* Capture message data (if valid) & compute return value (always) */
|
|
||||||
if (!err) {
|
|
||||||
if (unlikely(buf_len < sz)) {
|
|
||||||
sz = buf_len;
|
|
||||||
m->msg_flags |= MSG_TRUNC;
|
|
||||||
}
|
|
||||||
res = skb_copy_datagram_msg(buf, hlen, m, sz);
|
|
||||||
if (res)
|
|
||||||
goto exit;
|
goto exit;
|
||||||
res = sz;
|
skb = skb_peek(&sk->sk_receive_queue);
|
||||||
} else {
|
hdr = buf_msg(skb);
|
||||||
if (is_connectionless || err == TIPC_CONN_SHUTDOWN ||
|
dlen = msg_data_sz(hdr);
|
||||||
m->msg_control)
|
hlen = msg_hdr_sz(hdr);
|
||||||
res = 0;
|
err = msg_errcode(hdr);
|
||||||
else
|
if (likely(dlen || err))
|
||||||
res = -ECONNRESET;
|
break;
|
||||||
}
|
tsk_advance_rx_queue(sk);
|
||||||
|
} while (1);
|
||||||
|
|
||||||
|
/* Collect msg meta data, including error code and rejected data */
|
||||||
|
set_orig_addr(m, hdr);
|
||||||
|
rc = tipc_sk_anc_data_recv(m, hdr, tsk);
|
||||||
|
if (unlikely(rc))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
/* Capture data if non-error msg, otherwise just set return value */
|
||||||
|
if (likely(!err)) {
|
||||||
|
copy = min_t(int, dlen, buflen);
|
||||||
|
if (unlikely(copy != dlen))
|
||||||
|
m->msg_flags |= MSG_TRUNC;
|
||||||
|
rc = skb_copy_datagram_msg(skb, hlen, m, copy);
|
||||||
|
} else {
|
||||||
|
copy = 0;
|
||||||
|
rc = 0;
|
||||||
|
if (err != TIPC_CONN_SHUTDOWN && connected && !m->msg_control)
|
||||||
|
rc = -ECONNRESET;
|
||||||
|
}
|
||||||
|
if (unlikely(rc))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
/* Caption of data or error code/rejected data was successful */
|
||||||
if (unlikely(flags & MSG_PEEK))
|
if (unlikely(flags & MSG_PEEK))
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
if (likely(!is_connectionless)) {
|
|
||||||
tsk->rcv_unacked += tsk_inc(tsk, hlen + sz);
|
|
||||||
if (unlikely(tsk->rcv_unacked >= (tsk->rcv_win / 4)))
|
|
||||||
tipc_sk_send_ack(tsk);
|
|
||||||
}
|
|
||||||
tsk_advance_rx_queue(sk);
|
tsk_advance_rx_queue(sk);
|
||||||
|
if (likely(!connected))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
/* Send connection flow control ack when applicable */
|
||||||
|
tsk->rcv_unacked += tsk_inc(tsk, hlen + dlen);
|
||||||
|
if (tsk->rcv_unacked >= tsk->rcv_win / TIPC_ACK_RATE)
|
||||||
|
tipc_sk_send_ack(tsk);
|
||||||
exit:
|
exit:
|
||||||
release_sock(sk);
|
release_sock(sk);
|
||||||
return res;
|
return rc ? rc : copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
|
@ -1394,111 +1385,98 @@ exit:
|
||||||
*
|
*
|
||||||
* 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);
|
||||||
|
if (unlikely(rc))
|
||||||
|
break;
|
||||||
|
skb = skb_peek(&sk->sk_receive_queue);
|
||||||
|
skb_cb = TIPC_SKB_CB(skb);
|
||||||
|
hdr = buf_msg(skb);
|
||||||
|
dlen = msg_data_sz(hdr);
|
||||||
|
hlen = msg_hdr_sz(hdr);
|
||||||
|
err = msg_errcode(hdr);
|
||||||
|
|
||||||
restart:
|
/* Discard any empty non-errored (SYN-) message */
|
||||||
/* Look for a message in receive queue; wait if necessary */
|
if (unlikely(!dlen && !err)) {
|
||||||
res = tipc_wait_for_rcvmsg(sock, &timeo);
|
tsk_advance_rx_queue(sk);
|
||||||
if (res)
|
continue;
|
||||||
goto exit;
|
|
||||||
|
|
||||||
/* Look at first message in receive queue */
|
|
||||||
buf = skb_peek(&sk->sk_receive_queue);
|
|
||||||
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 */
|
|
||||||
if ((!sz) && (!err)) {
|
|
||||||
tsk_advance_rx_queue(sk);
|
|
||||||
goto restart;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Optionally capture sender's address & ancillary data of first msg */
|
|
||||||
if (sz_copied == 0) {
|
|
||||||
set_orig_addr(m, msg);
|
|
||||||
res = tipc_sk_anc_data_recv(m, msg, tsk);
|
|
||||||
if (res)
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Capture message data (if valid) & compute return value (always) */
|
|
||||||
if (!err) {
|
|
||||||
u32 offset = TIPC_SKB_CB(buf)->bytes_read;
|
|
||||||
u32 needed;
|
|
||||||
int sz_to_copy;
|
|
||||||
|
|
||||||
sz -= offset;
|
|
||||||
needed = (buf_len - sz_copied);
|
|
||||||
sz_to_copy = min(sz, needed);
|
|
||||||
|
|
||||||
res = skb_copy_datagram_msg(buf, hlen + offset, m, sz_to_copy);
|
|
||||||
if (res)
|
|
||||||
goto exit;
|
|
||||||
|
|
||||||
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 {
|
|
||||||
if (sz_copied != 0)
|
|
||||||
goto exit; /* can't add error msg to valid data */
|
|
||||||
|
|
||||||
if ((err == TIPC_CONN_SHUTDOWN) || m->msg_control)
|
/* Collect msg meta data, incl. error code and rejected data */
|
||||||
res = 0;
|
if (!copied) {
|
||||||
else
|
set_orig_addr(m, hdr);
|
||||||
res = -ECONNRESET;
|
rc = tipc_sk_anc_data_recv(m, hdr, tsk);
|
||||||
}
|
if (rc)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (unlikely(flags & MSG_PEEK))
|
/* Copy data if msg ok, otherwise return error/partial data */
|
||||||
goto exit;
|
if (likely(!err)) {
|
||||||
|
offset = skb_cb->bytes_read;
|
||||||
|
copy = min_t(int, dlen - offset, buflen - copied);
|
||||||
|
rc = skb_copy_datagram_msg(skb, hlen + offset, m, copy);
|
||||||
|
if (unlikely(rc))
|
||||||
|
break;
|
||||||
|
copied += copy;
|
||||||
|
offset += copy;
|
||||||
|
if (unlikely(offset < dlen)) {
|
||||||
|
if (!peek)
|
||||||
|
skb_cb->bytes_read = offset;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rc = 0;
|
||||||
|
if ((err != TIPC_CONN_SHUTDOWN) && !m->msg_control)
|
||||||
|
rc = -ECONNRESET;
|
||||||
|
if (copied || rc)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
tsk->rcv_unacked += tsk_inc(tsk, hlen + msg_data_sz(msg));
|
if (unlikely(peek))
|
||||||
if (unlikely(tsk->rcv_unacked >= (tsk->rcv_win / 4)))
|
break;
|
||||||
tipc_sk_send_ack(tsk);
|
|
||||||
tsk_advance_rx_queue(sk);
|
|
||||||
|
|
||||||
/* Loop around if more data is required */
|
tsk_advance_rx_queue(sk);
|
||||||
if ((sz_copied < buf_len) && /* didn't get all requested data */
|
|
||||||
(!skb_queue_empty(&sk->sk_receive_queue) ||
|
|
||||||
(sz_copied < target)) && /* and more is ready or required */
|
|
||||||
(!err)) /* and haven't reached a FIN */
|
|
||||||
goto restart;
|
|
||||||
|
|
||||||
|
/* Send connection flow control advertisement when applicable */
|
||||||
|
tsk->rcv_unacked += tsk_inc(tsk, hlen + dlen);
|
||||||
|
if (unlikely(tsk->rcv_unacked >= tsk->rcv_win / TIPC_ACK_RATE))
|
||||||
|
tipc_sk_send_ack(tsk);
|
||||||
|
|
||||||
|
/* 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2593,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
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue