aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc/socket.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2017-05-02 15:56:54 -0400
committerDavid S. Miller <davem@davemloft.net>2017-05-02 15:56:54 -0400
commit5d15af6778b8e4ed1fd41b040283af278e7a9a72 (patch)
treec52e9bc9f46009212362172962fe8f07e6fc6c76 /net/tipc/socket.c
parentb0e92279d3ec3656152c4dfa1c8b28fa40ca66d7 (diff)
parentec8a09fbbeff252c80daf62c7a78342003dddf9c (diff)
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>
Diffstat (limited to 'net/tipc/socket.c')
-rw-r--r--net/tipc/socket.c266
1 files changed, 122 insertions, 144 deletions
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 8a4e9fe5f9eb..7e45ef938c18 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -51,6 +51,7 @@
51#define TIPC_FWD_MSG 1 51#define TIPC_FWD_MSG 1
52#define TIPC_MAX_PORT 0xffffffff 52#define TIPC_MAX_PORT 0xffffffff
53#define TIPC_MIN_PORT 1 53#define TIPC_MIN_PORT 1
54#define TIPC_ACK_RATE 4 /* ACK at 1/4 of of rcv window size */
54 55
55enum { 56enum {
56 TIPC_LISTEN = TCP_LISTEN, 57 TIPC_LISTEN = TCP_LISTEN,
@@ -1290,7 +1291,7 @@ static int tipc_wait_for_rcvmsg(struct socket *sock, long *timeop)
1290/** 1291/**
1291 * tipc_recvmsg - receive packet-oriented message 1292 * tipc_recvmsg - receive packet-oriented message
1292 * @m: descriptor for message info 1293 * @m: descriptor for message info
1293 * @buf_len: total size of user buffer area 1294 * @buflen: length of user buffer area
1294 * @flags: receive flags 1295 * @flags: receive flags
1295 * 1296 *
1296 * Used for SOCK_DGRAM, SOCK_RDM, and SOCK_SEQPACKET messages. 1297 * 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)
1298 * 1299 *
1299 * Returns size of returned message data, errno otherwise 1300 * Returns size of returned message data, errno otherwise
1300 */ 1301 */
1301static int tipc_recvmsg(struct socket *sock, struct msghdr *m, size_t buf_len, 1302static int tipc_recvmsg(struct socket *sock, struct msghdr *m,
1302 int flags) 1303 size_t buflen, int flags)
1303{ 1304{
1304 struct sock *sk = sock->sk; 1305 struct sock *sk = sock->sk;
1305 struct tipc_sock *tsk = tipc_sk(sk); 1306 struct tipc_sock *tsk = tipc_sk(sk);
1306 struct sk_buff *buf; 1307 struct sk_buff *skb;
1307 struct tipc_msg *msg; 1308 struct tipc_msg *hdr;
1308 bool is_connectionless = tipc_sk_type_connectionless(sk); 1309 bool connected = !tipc_sk_type_connectionless(sk);
1309 long timeo; 1310 int rc, err, hlen, dlen, copy;
1310 unsigned int sz; 1311 long timeout;
1311 u32 err;
1312 int res, hlen;
1313 1312
1314 /* Catch invalid receive requests */ 1313 /* Catch invalid receive requests */
1315 if (unlikely(!buf_len)) 1314 if (unlikely(!buflen))
1316 return -EINVAL; 1315 return -EINVAL;
1317 1316
1318 lock_sock(sk); 1317 lock_sock(sk);
1319 1318 if (unlikely(connected && sk->sk_state == TIPC_OPEN)) {
1320 if (!is_connectionless && unlikely(sk->sk_state == TIPC_OPEN)) { 1319 rc = -ENOTCONN;
1321 res = -ENOTCONN;
1322 goto exit; 1320 goto exit;
1323 } 1321 }
1322 timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
1324 1323
1325 timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); 1324 do {
1326restart: 1325 /* Look at first msg in receive queue; wait if necessary */
1327 1326 rc = tipc_wait_for_rcvmsg(sock, &timeout);
1328 /* Look for a message in receive queue; wait if necessary */ 1327 if (unlikely(rc))
1329 res = tipc_wait_for_rcvmsg(sock, &timeo); 1328 goto exit;
1330 if (res) 1329 skb = skb_peek(&sk->sk_receive_queue);
1331 goto exit; 1330 hdr = buf_msg(skb);
1332 1331 dlen = msg_data_sz(hdr);
1333 /* Look at first message in receive queue */ 1332 hlen = msg_hdr_sz(hdr);
1334 buf = skb_peek(&sk->sk_receive_queue); 1333 err = msg_errcode(hdr);
1335 msg = buf_msg(buf); 1334 if (likely(dlen || err))
1336 sz = msg_data_sz(msg); 1335 break;
1337 hlen = msg_hdr_sz(msg);
1338 err = msg_errcode(msg);
1339
1340 /* Discard an empty non-errored message & try again */
1341 if ((!sz) && (!err)) {
1342 tsk_advance_rx_queue(sk); 1336 tsk_advance_rx_queue(sk);
1343 goto restart; 1337 } while (1);
1344 }
1345
1346 /* Capture sender's address (optional) */
1347 set_orig_addr(m, msg);
1348 1338
1349 /* Capture ancillary data (optional) */ 1339 /* Collect msg meta data, including error code and rejected data */
1350 res = tipc_sk_anc_data_recv(m, msg, tsk); 1340 set_orig_addr(m, hdr);
1351 if (res) 1341 rc = tipc_sk_anc_data_recv(m, hdr, tsk);
1342 if (unlikely(rc))
1352 goto exit; 1343 goto exit;
1353 1344
1354 /* Capture message data (if valid) & compute return value (always) */ 1345 /* Capture data if non-error msg, otherwise just set return value */
1355 if (!err) { 1346 if (likely(!err)) {
1356 if (unlikely(buf_len < sz)) { 1347 copy = min_t(int, dlen, buflen);
1357 sz = buf_len; 1348 if (unlikely(copy != dlen))
1358 m->msg_flags |= MSG_TRUNC; 1349 m->msg_flags |= MSG_TRUNC;
1359 } 1350 rc = skb_copy_datagram_msg(skb, hlen, m, copy);
1360 res = skb_copy_datagram_msg(buf, hlen, m, sz);
1361 if (res)
1362 goto exit;
1363 res = sz;
1364 } else { 1351 } else {
1365 if (is_connectionless || err == TIPC_CONN_SHUTDOWN || 1352 copy = 0;
1366 m->msg_control) 1353 rc = 0;
1367 res = 0; 1354 if (err != TIPC_CONN_SHUTDOWN && connected && !m->msg_control)
1368 else 1355 rc = -ECONNRESET;
1369 res = -ECONNRESET;
1370 } 1356 }
1357 if (unlikely(rc))
1358 goto exit;
1371 1359
1360 /* Caption of data or error code/rejected data was successful */
1372 if (unlikely(flags & MSG_PEEK)) 1361 if (unlikely(flags & MSG_PEEK))
1373 goto exit; 1362 goto exit;
1374 1363
1375 if (likely(!is_connectionless)) {
1376 tsk->rcv_unacked += tsk_inc(tsk, hlen + sz);
1377 if (unlikely(tsk->rcv_unacked >= (tsk->rcv_win / 4)))
1378 tipc_sk_send_ack(tsk);
1379 }
1380 tsk_advance_rx_queue(sk); 1364 tsk_advance_rx_queue(sk);
1365 if (likely(!connected))
1366 goto exit;
1367
1368 /* Send connection flow control ack when applicable */
1369 tsk->rcv_unacked += tsk_inc(tsk, hlen + dlen);
1370 if (tsk->rcv_unacked >= tsk->rcv_win / TIPC_ACK_RATE)
1371 tipc_sk_send_ack(tsk);
1381exit: 1372exit:
1382 release_sock(sk); 1373 release_sock(sk);
1383 return res; 1374 return rc ? rc : copy;
1384} 1375}
1385 1376
1386/** 1377/**
1387 * tipc_recv_stream - receive stream-oriented data 1378 * tipc_recvstream - receive stream-oriented data
1388 * @m: descriptor for message info 1379 * @m: descriptor for message info
1389 * @buf_len: total size of user buffer area 1380 * @buflen: total size of user buffer area
1390 * @flags: receive flags 1381 * @flags: receive flags
1391 * 1382 *
1392 * Used for SOCK_STREAM messages only. If not enough data is available 1383 * Used for SOCK_STREAM messages only. If not enough data is available
@@ -1394,111 +1385,98 @@ exit:
1394 * 1385 *
1395 * Returns size of returned message data, errno otherwise 1386 * Returns size of returned message data, errno otherwise
1396 */ 1387 */
1397static int tipc_recv_stream(struct socket *sock, struct msghdr *m, 1388static int tipc_recvstream(struct socket *sock, struct msghdr *m,
1398 size_t buf_len, int flags) 1389 size_t buflen, int flags)
1399{ 1390{
1400 struct sock *sk = sock->sk; 1391 struct sock *sk = sock->sk;
1401 struct tipc_sock *tsk = tipc_sk(sk); 1392 struct tipc_sock *tsk = tipc_sk(sk);
1402 struct sk_buff *buf; 1393 struct sk_buff *skb;
1403 struct tipc_msg *msg; 1394 struct tipc_msg *hdr;
1404 long timeo; 1395 struct tipc_skb_cb *skb_cb;
1405 unsigned int sz; 1396 bool peek = flags & MSG_PEEK;
1406 int target; 1397 int offset, required, copy, copied = 0;
1407 int sz_copied = 0; 1398 int hlen, dlen, err, rc;
1408 u32 err; 1399 long timeout;
1409 int res = 0, hlen;
1410 1400
1411 /* Catch invalid receive attempts */ 1401 /* Catch invalid receive attempts */
1412 if (unlikely(!buf_len)) 1402 if (unlikely(!buflen))
1413 return -EINVAL; 1403 return -EINVAL;
1414 1404
1415 lock_sock(sk); 1405 lock_sock(sk);
1416 1406
1417 if (unlikely(sk->sk_state == TIPC_OPEN)) { 1407 if (unlikely(sk->sk_state == TIPC_OPEN)) {
1418 res = -ENOTCONN; 1408 rc = -ENOTCONN;
1419 goto exit;
1420 }
1421
1422 target = sock_rcvlowat(sk, flags & MSG_WAITALL, buf_len);
1423 timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
1424
1425restart:
1426 /* Look for a message in receive queue; wait if necessary */
1427 res = tipc_wait_for_rcvmsg(sock, &timeo);
1428 if (res)
1429 goto exit; 1409 goto exit;
1430
1431 /* Look at first message in receive queue */
1432 buf = skb_peek(&sk->sk_receive_queue);
1433 msg = buf_msg(buf);
1434 sz = msg_data_sz(msg);
1435 hlen = msg_hdr_sz(msg);
1436 err = msg_errcode(msg);
1437
1438 /* Discard an empty non-errored message & try again */
1439 if ((!sz) && (!err)) {
1440 tsk_advance_rx_queue(sk);
1441 goto restart;
1442 }
1443
1444 /* Optionally capture sender's address & ancillary data of first msg */
1445 if (sz_copied == 0) {
1446 set_orig_addr(m, msg);
1447 res = tipc_sk_anc_data_recv(m, msg, tsk);
1448 if (res)
1449 goto exit;
1450 } 1410 }
1411 required = sock_rcvlowat(sk, flags & MSG_WAITALL, buflen);
1412 timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
1451 1413
1452 /* Capture message data (if valid) & compute return value (always) */ 1414 do {
1453 if (!err) { 1415 /* Look at first msg in receive queue; wait if necessary */
1454 u32 offset = TIPC_SKB_CB(buf)->bytes_read; 1416 rc = tipc_wait_for_rcvmsg(sock, &timeout);
1455 u32 needed; 1417 if (unlikely(rc))
1456 int sz_to_copy; 1418 break;
1457 1419 skb = skb_peek(&sk->sk_receive_queue);
1458 sz -= offset; 1420 skb_cb = TIPC_SKB_CB(skb);
1459 needed = (buf_len - sz_copied); 1421 hdr = buf_msg(skb);
1460 sz_to_copy = min(sz, needed); 1422 dlen = msg_data_sz(hdr);
1461 1423 hlen = msg_hdr_sz(hdr);
1462 res = skb_copy_datagram_msg(buf, hlen + offset, m, sz_to_copy); 1424 err = msg_errcode(hdr);
1463 if (res) 1425
1464 goto exit; 1426 /* Discard any empty non-errored (SYN-) message */
1427 if (unlikely(!dlen && !err)) {
1428 tsk_advance_rx_queue(sk);
1429 continue;
1430 }
1465 1431
1466 sz_copied += sz_to_copy; 1432 /* Collect msg meta data, incl. error code and rejected data */
1433 if (!copied) {
1434 set_orig_addr(m, hdr);
1435 rc = tipc_sk_anc_data_recv(m, hdr, tsk);
1436 if (rc)
1437 break;
1438 }
1467 1439
1468 if (sz_to_copy < sz) { 1440 /* Copy data if msg ok, otherwise return error/partial data */
1469 if (!(flags & MSG_PEEK)) 1441 if (likely(!err)) {
1470 TIPC_SKB_CB(buf)->bytes_read = 1442 offset = skb_cb->bytes_read;
1471 offset + sz_to_copy; 1443 copy = min_t(int, dlen - offset, buflen - copied);
1472 goto exit; 1444 rc = skb_copy_datagram_msg(skb, hlen + offset, m, copy);
1445 if (unlikely(rc))
1446 break;
1447 copied += copy;
1448 offset += copy;
1449 if (unlikely(offset < dlen)) {
1450 if (!peek)
1451 skb_cb->bytes_read = offset;
1452 break;
1453 }
1454 } else {
1455 rc = 0;
1456 if ((err != TIPC_CONN_SHUTDOWN) && !m->msg_control)
1457 rc = -ECONNRESET;
1458 if (copied || rc)
1459 break;
1473 } 1460 }
1474 } else {
1475 if (sz_copied != 0)
1476 goto exit; /* can't add error msg to valid data */
1477 1461
1478 if ((err == TIPC_CONN_SHUTDOWN) || m->msg_control) 1462 if (unlikely(peek))
1479 res = 0; 1463 break;
1480 else
1481 res = -ECONNRESET;
1482 }
1483 1464
1484 if (unlikely(flags & MSG_PEEK)) 1465 tsk_advance_rx_queue(sk);
1485 goto exit;
1486 1466
1487 tsk->rcv_unacked += tsk_inc(tsk, hlen + msg_data_sz(msg)); 1467 /* Send connection flow control advertisement when applicable */
1488 if (unlikely(tsk->rcv_unacked >= (tsk->rcv_win / 4))) 1468 tsk->rcv_unacked += tsk_inc(tsk, hlen + dlen);
1489 tipc_sk_send_ack(tsk); 1469 if (unlikely(tsk->rcv_unacked >= tsk->rcv_win / TIPC_ACK_RATE))
1490 tsk_advance_rx_queue(sk); 1470 tipc_sk_send_ack(tsk);
1491 1471
1492 /* Loop around if more data is required */ 1472 /* Exit if all requested data or FIN/error received */
1493 if ((sz_copied < buf_len) && /* didn't get all requested data */ 1473 if (copied == buflen || err)
1494 (!skb_queue_empty(&sk->sk_receive_queue) || 1474 break;
1495 (sz_copied < target)) && /* and more is ready or required */
1496 (!err)) /* and haven't reached a FIN */
1497 goto restart;
1498 1475
1476 } while (!skb_queue_empty(&sk->sk_receive_queue) || copied < required);
1499exit: 1477exit:
1500 release_sock(sk); 1478 release_sock(sk);
1501 return sz_copied ? sz_copied : res; 1479 return copied ? copied : rc;
1502} 1480}
1503 1481
1504/** 1482/**
@@ -2593,7 +2571,7 @@ static const struct proto_ops stream_ops = {
2593 .setsockopt = tipc_setsockopt, 2571 .setsockopt = tipc_setsockopt,
2594 .getsockopt = tipc_getsockopt, 2572 .getsockopt = tipc_getsockopt,
2595 .sendmsg = tipc_sendstream, 2573 .sendmsg = tipc_sendstream,
2596 .recvmsg = tipc_recv_stream, 2574 .recvmsg = tipc_recvstream,
2597 .mmap = sock_no_mmap, 2575 .mmap = sock_no_mmap,
2598 .sendpage = sock_no_sendpage 2576 .sendpage = sock_no_sendpage
2599}; 2577};