aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorYing Xue <ying.xue@windriver.com>2012-11-29 18:51:19 -0500
committerPaul Gortmaker <paul.gortmaker@windriver.com>2012-12-07 17:23:21 -0500
commit584d24b3960e4c877fc623214815f278708f127c (patch)
tree7270e28a6d3df9f46cb096a6a9f640fa75e00b94 /net
parent7e6c131e1568dcc2033736739a9880dce1976886 (diff)
tipc: introduce non-blocking socket connect
TIPC has so far only supported blocking connect(), meaning that a call to connect() doesn't return until either the connection is fully established, or an error occurs. This has proved insufficient for many users, so we now introduce non-blocking connect(), analogous to how this is done in TCP and other protocols. With this feature, if a connection cannot be established instantly, connect() will return the error code "-EINPROGRESS". If the user later calls connect() again, he will either have the return code "-EALREADY" or "-EISCONN", depending on whether the connection has been established or not. The user must have explicitly set the socket to be non-blocking (SOCK_NONBLOCK or O_NONBLOCK, depending on method used), so unless for some reason they had set this already (the socket would anyway remain blocking in current TIPC) this change should be completely backwards compatible. It is also now possible to call select() or poll() to wait for the completion of a connection. An effect of the above is that the actual completion of a connection may now be performed asynchronously, independent of the calls from user space. Therefore, we now execute this code in BH context, in the function filter_rcv(), which is executed upon reception of messages in the socket. Signed-off-by: Ying Xue <ying.xue@windriver.com> Signed-off-by: Jon Maloy <jon.maloy@ericsson.com> [PG: minor refactoring for improved connect/disconnect function names] Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
Diffstat (limited to 'net')
-rw-r--r--net/tipc/socket.c158
1 files changed, 93 insertions, 65 deletions
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index d16a6de32ea1..dbce2745f0a8 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -775,16 +775,19 @@ exit:
775static int auto_connect(struct socket *sock, struct tipc_msg *msg) 775static int auto_connect(struct socket *sock, struct tipc_msg *msg)
776{ 776{
777 struct tipc_sock *tsock = tipc_sk(sock->sk); 777 struct tipc_sock *tsock = tipc_sk(sock->sk);
778 778 struct tipc_port *p_ptr;
779 if (msg_errcode(msg)) {
780 sock->state = SS_DISCONNECTING;
781 return -ECONNREFUSED;
782 }
783 779
784 tsock->peer_name.ref = msg_origport(msg); 780 tsock->peer_name.ref = msg_origport(msg);
785 tsock->peer_name.node = msg_orignode(msg); 781 tsock->peer_name.node = msg_orignode(msg);
786 tipc_connect(tsock->p->ref, &tsock->peer_name); 782 p_ptr = tipc_port_deref(tsock->p->ref);
787 tipc_set_portimportance(tsock->p->ref, msg_importance(msg)); 783 if (!p_ptr)
784 return -EINVAL;
785
786 __tipc_connect(tsock->p->ref, p_ptr, &tsock->peer_name);
787
788 if (msg_importance(msg) > TIPC_CRITICAL_IMPORTANCE)
789 return -EINVAL;
790 msg_set_importance(&p_ptr->phdr, (u32)msg_importance(msg));
788 sock->state = SS_CONNECTED; 791 sock->state = SS_CONNECTED;
789 return 0; 792 return 0;
790} 793}
@@ -1198,7 +1201,9 @@ static u32 filter_connect(struct tipc_sock *tsock, struct sk_buff **buf)
1198{ 1201{
1199 struct socket *sock = tsock->sk.sk_socket; 1202 struct socket *sock = tsock->sk.sk_socket;
1200 struct tipc_msg *msg = buf_msg(*buf); 1203 struct tipc_msg *msg = buf_msg(*buf);
1204 struct sock *sk = &tsock->sk;
1201 u32 retval = TIPC_ERR_NO_PORT; 1205 u32 retval = TIPC_ERR_NO_PORT;
1206 int res;
1202 1207
1203 if (msg_mcast(msg)) 1208 if (msg_mcast(msg))
1204 return retval; 1209 return retval;
@@ -1216,8 +1221,36 @@ static u32 filter_connect(struct tipc_sock *tsock, struct sk_buff **buf)
1216 break; 1221 break;
1217 case SS_CONNECTING: 1222 case SS_CONNECTING:
1218 /* Accept only ACK or NACK message */ 1223 /* Accept only ACK or NACK message */
1219 if (msg_connected(msg) || (msg_errcode(msg))) 1224 if (unlikely(msg_errcode(msg))) {
1225 sock->state = SS_DISCONNECTING;
1226 sk->sk_err = -ECONNREFUSED;
1227 retval = TIPC_OK;
1228 break;
1229 }
1230
1231 if (unlikely(!msg_connected(msg)))
1232 break;
1233
1234 res = auto_connect(sock, msg);
1235 if (res) {
1236 sock->state = SS_DISCONNECTING;
1237 sk->sk_err = res;
1220 retval = TIPC_OK; 1238 retval = TIPC_OK;
1239 break;
1240 }
1241
1242 /* If an incoming message is an 'ACK-', it should be
1243 * discarded here because it doesn't contain useful
1244 * data. In addition, we should try to wake up
1245 * connect() routine if sleeping.
1246 */
1247 if (msg_data_sz(msg) == 0) {
1248 kfree_skb(*buf);
1249 *buf = NULL;
1250 if (waitqueue_active(sk_sleep(sk)))
1251 wake_up_interruptible(sk_sleep(sk));
1252 }
1253 retval = TIPC_OK;
1221 break; 1254 break;
1222 case SS_LISTENING: 1255 case SS_LISTENING:
1223 case SS_UNCONNECTED: 1256 case SS_UNCONNECTED:
@@ -1361,8 +1394,6 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen,
1361 struct sock *sk = sock->sk; 1394 struct sock *sk = sock->sk;
1362 struct sockaddr_tipc *dst = (struct sockaddr_tipc *)dest; 1395 struct sockaddr_tipc *dst = (struct sockaddr_tipc *)dest;
1363 struct msghdr m = {NULL,}; 1396 struct msghdr m = {NULL,};
1364 struct sk_buff *buf;
1365 struct tipc_msg *msg;
1366 unsigned int timeout; 1397 unsigned int timeout;
1367 int res; 1398 int res;
1368 1399
@@ -1374,26 +1405,6 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen,
1374 goto exit; 1405 goto exit;
1375 } 1406 }
1376 1407
1377 /* For now, TIPC does not support the non-blocking form of connect() */
1378 if (flags & O_NONBLOCK) {
1379 res = -EOPNOTSUPP;
1380 goto exit;
1381 }
1382
1383 /* Issue Posix-compliant error code if socket is in the wrong state */
1384 if (sock->state == SS_LISTENING) {
1385 res = -EOPNOTSUPP;
1386 goto exit;
1387 }
1388 if (sock->state == SS_CONNECTING) {
1389 res = -EALREADY;
1390 goto exit;
1391 }
1392 if (sock->state != SS_UNCONNECTED) {
1393 res = -EISCONN;
1394 goto exit;
1395 }
1396
1397 /* 1408 /*
1398 * Reject connection attempt using multicast address 1409 * Reject connection attempt using multicast address
1399 * 1410 *
@@ -1405,49 +1416,66 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen,
1405 goto exit; 1416 goto exit;
1406 } 1417 }
1407 1418
1408 /* Reject any messages already in receive queue (very unlikely) */ 1419 timeout = (flags & O_NONBLOCK) ? 0 : tipc_sk(sk)->conn_timeout;
1409 reject_rx_queue(sk); 1420
1421 switch (sock->state) {
1422 case SS_UNCONNECTED:
1423 /* Send a 'SYN-' to destination */
1424 m.msg_name = dest;
1425 m.msg_namelen = destlen;
1426
1427 /* If connect is in non-blocking case, set MSG_DONTWAIT to
1428 * indicate send_msg() is never blocked.
1429 */
1430 if (!timeout)
1431 m.msg_flags = MSG_DONTWAIT;
1432
1433 res = send_msg(NULL, sock, &m, 0);
1434 if ((res < 0) && (res != -EWOULDBLOCK))
1435 goto exit;
1410 1436
1411 /* Send a 'SYN-' to destination */ 1437 /* Just entered SS_CONNECTING state; the only
1412 m.msg_name = dest; 1438 * difference is that return value in non-blocking
1413 m.msg_namelen = destlen; 1439 * case is EINPROGRESS, rather than EALREADY.
1414 res = send_msg(NULL, sock, &m, 0); 1440 */
1415 if (res < 0) 1441 res = -EINPROGRESS;
1442 break;
1443 case SS_CONNECTING:
1444 res = -EALREADY;
1445 break;
1446 case SS_CONNECTED:
1447 res = -EISCONN;
1448 break;
1449 default:
1450 res = -EINVAL;
1416 goto exit; 1451 goto exit;
1452 }
1417 1453
1418 /* Wait until an 'ACK' or 'RST' arrives, or a timeout occurs */ 1454 if (sock->state == SS_CONNECTING) {
1419 timeout = tipc_sk(sk)->conn_timeout; 1455 if (!timeout)
1420 release_sock(sk); 1456 goto exit;
1421 res = wait_event_interruptible_timeout(*sk_sleep(sk),
1422 (!skb_queue_empty(&sk->sk_receive_queue) ||
1423 (sock->state != SS_CONNECTING)),
1424 timeout ? (long)msecs_to_jiffies(timeout)
1425 : MAX_SCHEDULE_TIMEOUT);
1426 lock_sock(sk);
1427 1457
1428 if (res > 0) { 1458 /* Wait until an 'ACK' or 'RST' arrives, or a timeout occurs */
1429 buf = skb_peek(&sk->sk_receive_queue); 1459 release_sock(sk);
1430 if (buf != NULL) { 1460 res = wait_event_interruptible_timeout(*sk_sleep(sk),
1431 msg = buf_msg(buf); 1461 sock->state != SS_CONNECTING,
1432 res = auto_connect(sock, msg); 1462 timeout ? (long)msecs_to_jiffies(timeout)
1433 if (!res) { 1463 : MAX_SCHEDULE_TIMEOUT);
1434 if (!msg_data_sz(msg)) 1464 lock_sock(sk);
1435 advance_rx_queue(sk); 1465 if (res <= 0) {
1436 } 1466 if (res == 0)
1437 } else { 1467 res = -ETIMEDOUT;
1438 if (sock->state == SS_CONNECTED)
1439 res = -EISCONN;
1440 else 1468 else
1441 res = -ECONNREFUSED; 1469 ; /* leave "res" unchanged */
1470 goto exit;
1442 } 1471 }
1443 } else {
1444 if (res == 0)
1445 res = -ETIMEDOUT;
1446 else
1447 ; /* leave "res" unchanged */
1448 sock->state = SS_DISCONNECTING;
1449 } 1472 }
1450 1473
1474 if (unlikely(sock->state == SS_DISCONNECTING))
1475 res = sock_error(sk);
1476 else
1477 res = 0;
1478
1451exit: 1479exit:
1452 release_sock(sk); 1480 release_sock(sk);
1453 return res; 1481 return res;