aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYing Xue <ying.xue@windriver.com>2014-01-16 20:50:03 -0500
committerDavid S. Miller <davem@davemloft.net>2014-01-16 22:10:34 -0500
commit78eb3a5379a52f291556483ea55b8a37e2ed4d5b (patch)
treef1c7192e97fa5756a7a76d31a1f098def4e26d6e
parentabfce3ef58b6a6c95de389f9d20047a05b10e484 (diff)
tipc: standardize connect routine
Comparing the behaviour of how to wait for events in TIPC connect() with other stacks, the TIPC implementation might be perceived as different, and sometimes even incorrect. For instance, as both sock->state and sk_sleep() are directly fed to wait_event_interruptible_timeout() as its arguments, and socket lock has to be released before we call wait_event_interruptible_timeout(), the two variables associated with socket are exposed out of socket lock protection, thereby probably getting stale values so that the process of calling connect() cannot be woken up exactly even if correct event arrives or it is woken up improperly even if the wake condition is not satisfied in practice. Therefore, standardizing its behaviour with sk_stream_wait_connect routine can avoid these risks. Additionally the implementation of connect routine is simplified as a whole, allowing it to return correct values in all different cases. Signed-off-by: Ying Xue <ying.xue@windriver.com> Reviewed-by: Jon Maloy <jon.maloy@ericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/tipc/socket.c63
1 files changed, 33 insertions, 30 deletions
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index c8341d1f995e..b2ae25ae3038 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -1438,6 +1438,28 @@ static void wakeupdispatch(struct tipc_port *tport)
1438 sk->sk_write_space(sk); 1438 sk->sk_write_space(sk);
1439} 1439}
1440 1440
1441static int tipc_wait_for_connect(struct socket *sock, long *timeo_p)
1442{
1443 struct sock *sk = sock->sk;
1444 DEFINE_WAIT(wait);
1445 int done;
1446
1447 do {
1448 int err = sock_error(sk);
1449 if (err)
1450 return err;
1451 if (!*timeo_p)
1452 return -ETIMEDOUT;
1453 if (signal_pending(current))
1454 return sock_intr_errno(*timeo_p);
1455
1456 prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
1457 done = sk_wait_event(sk, timeo_p, sock->state != SS_CONNECTING);
1458 finish_wait(sk_sleep(sk), &wait);
1459 } while (!done);
1460 return 0;
1461}
1462
1441/** 1463/**
1442 * connect - establish a connection to another TIPC port 1464 * connect - establish a connection to another TIPC port
1443 * @sock: socket structure 1465 * @sock: socket structure
@@ -1453,7 +1475,8 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen,
1453 struct sock *sk = sock->sk; 1475 struct sock *sk = sock->sk;
1454 struct sockaddr_tipc *dst = (struct sockaddr_tipc *)dest; 1476 struct sockaddr_tipc *dst = (struct sockaddr_tipc *)dest;
1455 struct msghdr m = {NULL,}; 1477 struct msghdr m = {NULL,};
1456 unsigned int timeout; 1478 long timeout = (flags & O_NONBLOCK) ? 0 : tipc_sk(sk)->conn_timeout;
1479 socket_state previous;
1457 int res; 1480 int res;
1458 1481
1459 lock_sock(sk); 1482 lock_sock(sk);
@@ -1475,8 +1498,7 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen,
1475 goto exit; 1498 goto exit;
1476 } 1499 }
1477 1500
1478 timeout = (flags & O_NONBLOCK) ? 0 : tipc_sk(sk)->conn_timeout; 1501 previous = sock->state;
1479
1480 switch (sock->state) { 1502 switch (sock->state) {
1481 case SS_UNCONNECTED: 1503 case SS_UNCONNECTED:
1482 /* Send a 'SYN-' to destination */ 1504 /* Send a 'SYN-' to destination */
@@ -1498,41 +1520,22 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen,
1498 * case is EINPROGRESS, rather than EALREADY. 1520 * case is EINPROGRESS, rather than EALREADY.
1499 */ 1521 */
1500 res = -EINPROGRESS; 1522 res = -EINPROGRESS;
1501 break;
1502 case SS_CONNECTING: 1523 case SS_CONNECTING:
1503 res = -EALREADY; 1524 if (previous == SS_CONNECTING)
1525 res = -EALREADY;
1526 if (!timeout)
1527 goto exit;
1528 timeout = msecs_to_jiffies(timeout);
1529 /* Wait until an 'ACK' or 'RST' arrives, or a timeout occurs */
1530 res = tipc_wait_for_connect(sock, &timeout);
1504 break; 1531 break;
1505 case SS_CONNECTED: 1532 case SS_CONNECTED:
1506 res = -EISCONN; 1533 res = -EISCONN;
1507 break; 1534 break;
1508 default: 1535 default:
1509 res = -EINVAL; 1536 res = -EINVAL;
1510 goto exit; 1537 break;
1511 }
1512
1513 if (sock->state == SS_CONNECTING) {
1514 if (!timeout)
1515 goto exit;
1516
1517 /* Wait until an 'ACK' or 'RST' arrives, or a timeout occurs */
1518 release_sock(sk);
1519 res = wait_event_interruptible_timeout(*sk_sleep(sk),
1520 sock->state != SS_CONNECTING,
1521 timeout ? (long)msecs_to_jiffies(timeout)
1522 : MAX_SCHEDULE_TIMEOUT);
1523 if (res <= 0) {
1524 if (res == 0)
1525 res = -ETIMEDOUT;
1526 return res;
1527 }
1528 lock_sock(sk);
1529 } 1538 }
1530
1531 if (unlikely(sock->state == SS_DISCONNECTING))
1532 res = sock_error(sk);
1533 else
1534 res = 0;
1535
1536exit: 1539exit:
1537 release_sock(sk); 1540 release_sock(sk);
1538 return res; 1541 return res;