diff options
Diffstat (limited to 'net/tipc/socket.c')
| -rw-r--r-- | net/tipc/socket.c | 330 |
1 files changed, 197 insertions, 133 deletions
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index e741416d1d24..aab4948f0aff 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c | |||
| @@ -55,9 +55,6 @@ struct tipc_sock { | |||
| 55 | #define tipc_sk(sk) ((struct tipc_sock *)(sk)) | 55 | #define tipc_sk(sk) ((struct tipc_sock *)(sk)) |
| 56 | #define tipc_sk_port(sk) (tipc_sk(sk)->p) | 56 | #define tipc_sk_port(sk) (tipc_sk(sk)->p) |
| 57 | 57 | ||
| 58 | #define tipc_rx_ready(sock) (!skb_queue_empty(&sock->sk->sk_receive_queue) || \ | ||
| 59 | (sock->state == SS_DISCONNECTING)) | ||
| 60 | |||
| 61 | static int backlog_rcv(struct sock *sk, struct sk_buff *skb); | 58 | static int backlog_rcv(struct sock *sk, struct sk_buff *skb); |
| 62 | static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf); | 59 | static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf); |
| 63 | static void wakeupdispatch(struct tipc_port *tport); | 60 | static void wakeupdispatch(struct tipc_port *tport); |
| @@ -239,7 +236,6 @@ static int tipc_sk_create(struct net *net, struct socket *sock, int protocol, | |||
| 239 | int tipc_sock_create_local(int type, struct socket **res) | 236 | int tipc_sock_create_local(int type, struct socket **res) |
| 240 | { | 237 | { |
| 241 | int rc; | 238 | int rc; |
| 242 | struct sock *sk; | ||
| 243 | 239 | ||
| 244 | rc = sock_create_lite(AF_TIPC, type, 0, res); | 240 | rc = sock_create_lite(AF_TIPC, type, 0, res); |
| 245 | if (rc < 0) { | 241 | if (rc < 0) { |
| @@ -248,8 +244,6 @@ int tipc_sock_create_local(int type, struct socket **res) | |||
| 248 | } | 244 | } |
| 249 | tipc_sk_create(&init_net, *res, 0, 1); | 245 | tipc_sk_create(&init_net, *res, 0, 1); |
| 250 | 246 | ||
| 251 | sk = (*res)->sk; | ||
| 252 | |||
| 253 | return 0; | 247 | return 0; |
| 254 | } | 248 | } |
| 255 | 249 | ||
| @@ -570,6 +564,31 @@ static int dest_name_check(struct sockaddr_tipc *dest, struct msghdr *m) | |||
| 570 | return 0; | 564 | return 0; |
| 571 | } | 565 | } |
| 572 | 566 | ||
| 567 | static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p) | ||
| 568 | { | ||
| 569 | struct sock *sk = sock->sk; | ||
| 570 | struct tipc_port *tport = tipc_sk_port(sk); | ||
| 571 | DEFINE_WAIT(wait); | ||
| 572 | int done; | ||
| 573 | |||
| 574 | do { | ||
| 575 | int err = sock_error(sk); | ||
| 576 | if (err) | ||
| 577 | return err; | ||
| 578 | if (sock->state == SS_DISCONNECTING) | ||
| 579 | return -EPIPE; | ||
| 580 | if (!*timeo_p) | ||
| 581 | return -EAGAIN; | ||
| 582 | if (signal_pending(current)) | ||
| 583 | return sock_intr_errno(*timeo_p); | ||
| 584 | |||
| 585 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | ||
| 586 | done = sk_wait_event(sk, timeo_p, !tport->congested); | ||
| 587 | finish_wait(sk_sleep(sk), &wait); | ||
| 588 | } while (!done); | ||
| 589 | return 0; | ||
| 590 | } | ||
| 591 | |||
| 573 | /** | 592 | /** |
| 574 | * send_msg - send message in connectionless manner | 593 | * send_msg - send message in connectionless manner |
| 575 | * @iocb: if NULL, indicates that socket lock is already held | 594 | * @iocb: if NULL, indicates that socket lock is already held |
| @@ -589,9 +608,9 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, | |||
| 589 | { | 608 | { |
| 590 | struct sock *sk = sock->sk; | 609 | struct sock *sk = sock->sk; |
| 591 | struct tipc_port *tport = tipc_sk_port(sk); | 610 | struct tipc_port *tport = tipc_sk_port(sk); |
| 592 | struct sockaddr_tipc *dest = (struct sockaddr_tipc *)m->msg_name; | 611 | DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name); |
| 593 | int needs_conn; | 612 | int needs_conn; |
| 594 | long timeout_val; | 613 | long timeo; |
| 595 | int res = -EINVAL; | 614 | int res = -EINVAL; |
| 596 | 615 | ||
| 597 | if (unlikely(!dest)) | 616 | if (unlikely(!dest)) |
| @@ -628,8 +647,7 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, | |||
| 628 | reject_rx_queue(sk); | 647 | reject_rx_queue(sk); |
| 629 | } | 648 | } |
| 630 | 649 | ||
| 631 | timeout_val = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); | 650 | timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); |
| 632 | |||
| 633 | do { | 651 | do { |
| 634 | if (dest->addrtype == TIPC_ADDR_NAME) { | 652 | if (dest->addrtype == TIPC_ADDR_NAME) { |
| 635 | res = dest_name_check(dest, m); | 653 | res = dest_name_check(dest, m); |
| @@ -663,14 +681,9 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, | |||
| 663 | sock->state = SS_CONNECTING; | 681 | sock->state = SS_CONNECTING; |
| 664 | break; | 682 | break; |
| 665 | } | 683 | } |
| 666 | if (timeout_val <= 0L) { | 684 | res = tipc_wait_for_sndmsg(sock, &timeo); |
| 667 | res = timeout_val ? timeout_val : -EWOULDBLOCK; | 685 | if (res) |
| 668 | break; | 686 | break; |
| 669 | } | ||
| 670 | release_sock(sk); | ||
| 671 | timeout_val = wait_event_interruptible_timeout(*sk_sleep(sk), | ||
| 672 | !tport->congested, timeout_val); | ||
| 673 | lock_sock(sk); | ||
| 674 | } while (1); | 687 | } while (1); |
| 675 | 688 | ||
| 676 | exit: | 689 | exit: |
| @@ -679,6 +692,34 @@ exit: | |||
| 679 | return res; | 692 | return res; |
| 680 | } | 693 | } |
| 681 | 694 | ||
| 695 | static int tipc_wait_for_sndpkt(struct socket *sock, long *timeo_p) | ||
| 696 | { | ||
| 697 | struct sock *sk = sock->sk; | ||
| 698 | struct tipc_port *tport = tipc_sk_port(sk); | ||
| 699 | DEFINE_WAIT(wait); | ||
| 700 | int done; | ||
| 701 | |||
| 702 | do { | ||
| 703 | int err = sock_error(sk); | ||
| 704 | if (err) | ||
| 705 | return err; | ||
| 706 | if (sock->state == SS_DISCONNECTING) | ||
| 707 | return -EPIPE; | ||
| 708 | else if (sock->state != SS_CONNECTED) | ||
| 709 | return -ENOTCONN; | ||
| 710 | if (!*timeo_p) | ||
| 711 | return -EAGAIN; | ||
| 712 | if (signal_pending(current)) | ||
| 713 | return sock_intr_errno(*timeo_p); | ||
| 714 | |||
| 715 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | ||
| 716 | done = sk_wait_event(sk, timeo_p, | ||
| 717 | (!tport->congested || !tport->connected)); | ||
| 718 | finish_wait(sk_sleep(sk), &wait); | ||
| 719 | } while (!done); | ||
| 720 | return 0; | ||
| 721 | } | ||
| 722 | |||
| 682 | /** | 723 | /** |
| 683 | * send_packet - send a connection-oriented message | 724 | * send_packet - send a connection-oriented message |
| 684 | * @iocb: if NULL, indicates that socket lock is already held | 725 | * @iocb: if NULL, indicates that socket lock is already held |
| @@ -695,9 +736,9 @@ static int send_packet(struct kiocb *iocb, struct socket *sock, | |||
| 695 | { | 736 | { |
| 696 | struct sock *sk = sock->sk; | 737 | struct sock *sk = sock->sk; |
| 697 | struct tipc_port *tport = tipc_sk_port(sk); | 738 | struct tipc_port *tport = tipc_sk_port(sk); |
| 698 | struct sockaddr_tipc *dest = (struct sockaddr_tipc *)m->msg_name; | 739 | DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name); |
| 699 | long timeout_val; | 740 | int res = -EINVAL; |
| 700 | int res; | 741 | long timeo; |
| 701 | 742 | ||
| 702 | /* Handle implied connection establishment */ | 743 | /* Handle implied connection establishment */ |
| 703 | if (unlikely(dest)) | 744 | if (unlikely(dest)) |
| @@ -709,30 +750,24 @@ static int send_packet(struct kiocb *iocb, struct socket *sock, | |||
| 709 | if (iocb) | 750 | if (iocb) |
| 710 | lock_sock(sk); | 751 | lock_sock(sk); |
| 711 | 752 | ||
| 712 | timeout_val = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); | 753 | if (unlikely(sock->state != SS_CONNECTED)) { |
| 754 | if (sock->state == SS_DISCONNECTING) | ||
| 755 | res = -EPIPE; | ||
| 756 | else | ||
| 757 | res = -ENOTCONN; | ||
| 758 | goto exit; | ||
| 759 | } | ||
| 713 | 760 | ||
| 761 | timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); | ||
| 714 | do { | 762 | do { |
| 715 | if (unlikely(sock->state != SS_CONNECTED)) { | ||
| 716 | if (sock->state == SS_DISCONNECTING) | ||
| 717 | res = -EPIPE; | ||
| 718 | else | ||
| 719 | res = -ENOTCONN; | ||
| 720 | break; | ||
| 721 | } | ||
| 722 | |||
| 723 | res = tipc_send(tport->ref, m->msg_iov, total_len); | 763 | res = tipc_send(tport->ref, m->msg_iov, total_len); |
| 724 | if (likely(res != -ELINKCONG)) | 764 | if (likely(res != -ELINKCONG)) |
| 725 | break; | 765 | break; |
| 726 | if (timeout_val <= 0L) { | 766 | res = tipc_wait_for_sndpkt(sock, &timeo); |
| 727 | res = timeout_val ? timeout_val : -EWOULDBLOCK; | 767 | if (res) |
| 728 | break; | 768 | break; |
| 729 | } | ||
| 730 | release_sock(sk); | ||
| 731 | timeout_val = wait_event_interruptible_timeout(*sk_sleep(sk), | ||
| 732 | (!tport->congested || !tport->connected), timeout_val); | ||
| 733 | lock_sock(sk); | ||
| 734 | } while (1); | 769 | } while (1); |
| 735 | 770 | exit: | |
| 736 | if (iocb) | 771 | if (iocb) |
| 737 | release_sock(sk); | 772 | release_sock(sk); |
| 738 | return res; | 773 | return res; |
| @@ -770,16 +805,11 @@ static int send_stream(struct kiocb *iocb, struct socket *sock, | |||
| 770 | 805 | ||
| 771 | /* Handle special cases where there is no connection */ | 806 | /* Handle special cases where there is no connection */ |
| 772 | if (unlikely(sock->state != SS_CONNECTED)) { | 807 | if (unlikely(sock->state != SS_CONNECTED)) { |
| 773 | if (sock->state == SS_UNCONNECTED) { | 808 | if (sock->state == SS_UNCONNECTED) |
| 774 | res = send_packet(NULL, sock, m, total_len); | 809 | res = send_packet(NULL, sock, m, total_len); |
| 775 | goto exit; | 810 | else |
| 776 | } else if (sock->state == SS_DISCONNECTING) { | 811 | res = sock->state == SS_DISCONNECTING ? -EPIPE : -ENOTCONN; |
| 777 | res = -EPIPE; | 812 | goto exit; |
| 778 | goto exit; | ||
| 779 | } else { | ||
| 780 | res = -ENOTCONN; | ||
| 781 | goto exit; | ||
| 782 | } | ||
| 783 | } | 813 | } |
| 784 | 814 | ||
| 785 | if (unlikely(m->msg_name)) { | 815 | if (unlikely(m->msg_name)) { |
| @@ -876,7 +906,7 @@ static int auto_connect(struct socket *sock, struct tipc_msg *msg) | |||
| 876 | */ | 906 | */ |
| 877 | static void set_orig_addr(struct msghdr *m, struct tipc_msg *msg) | 907 | static void set_orig_addr(struct msghdr *m, struct tipc_msg *msg) |
| 878 | { | 908 | { |
| 879 | struct sockaddr_tipc *addr = (struct sockaddr_tipc *)m->msg_name; | 909 | DECLARE_SOCKADDR(struct sockaddr_tipc *, addr, m->msg_name); |
| 880 | 910 | ||
| 881 | if (addr) { | 911 | if (addr) { |
| 882 | addr->family = AF_TIPC; | 912 | addr->family = AF_TIPC; |
| @@ -961,6 +991,37 @@ static int anc_data_recv(struct msghdr *m, struct tipc_msg *msg, | |||
| 961 | return 0; | 991 | return 0; |
| 962 | } | 992 | } |
| 963 | 993 | ||
| 994 | static int tipc_wait_for_rcvmsg(struct socket *sock, long timeo) | ||
| 995 | { | ||
| 996 | struct sock *sk = sock->sk; | ||
| 997 | DEFINE_WAIT(wait); | ||
| 998 | int err; | ||
| 999 | |||
| 1000 | for (;;) { | ||
| 1001 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | ||
| 1002 | if (skb_queue_empty(&sk->sk_receive_queue)) { | ||
| 1003 | if (sock->state == SS_DISCONNECTING) { | ||
| 1004 | err = -ENOTCONN; | ||
| 1005 | break; | ||
| 1006 | } | ||
| 1007 | release_sock(sk); | ||
| 1008 | timeo = schedule_timeout(timeo); | ||
| 1009 | lock_sock(sk); | ||
| 1010 | } | ||
| 1011 | err = 0; | ||
| 1012 | if (!skb_queue_empty(&sk->sk_receive_queue)) | ||
| 1013 | break; | ||
| 1014 | err = sock_intr_errno(timeo); | ||
| 1015 | if (signal_pending(current)) | ||
| 1016 | break; | ||
| 1017 | err = -EAGAIN; | ||
| 1018 | if (!timeo) | ||
| 1019 | break; | ||
| 1020 | } | ||
| 1021 | finish_wait(sk_sleep(sk), &wait); | ||
| 1022 | return err; | ||
| 1023 | } | ||
| 1024 | |||
| 964 | /** | 1025 | /** |
| 965 | * recv_msg - receive packet-oriented message | 1026 | * recv_msg - receive packet-oriented message |
| 966 | * @iocb: (unused) | 1027 | * @iocb: (unused) |
| @@ -980,7 +1041,7 @@ static int recv_msg(struct kiocb *iocb, struct socket *sock, | |||
| 980 | struct tipc_port *tport = tipc_sk_port(sk); | 1041 | struct tipc_port *tport = tipc_sk_port(sk); |
| 981 | struct sk_buff *buf; | 1042 | struct sk_buff *buf; |
| 982 | struct tipc_msg *msg; | 1043 | struct tipc_msg *msg; |
| 983 | long timeout; | 1044 | long timeo; |
| 984 | unsigned int sz; | 1045 | unsigned int sz; |
| 985 | u32 err; | 1046 | u32 err; |
| 986 | int res; | 1047 | int res; |
| @@ -996,25 +1057,13 @@ static int recv_msg(struct kiocb *iocb, struct socket *sock, | |||
| 996 | goto exit; | 1057 | goto exit; |
| 997 | } | 1058 | } |
| 998 | 1059 | ||
| 999 | timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); | 1060 | timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); |
| 1000 | restart: | 1061 | restart: |
| 1001 | 1062 | ||
| 1002 | /* Look for a message in receive queue; wait if necessary */ | 1063 | /* Look for a message in receive queue; wait if necessary */ |
| 1003 | while (skb_queue_empty(&sk->sk_receive_queue)) { | 1064 | res = tipc_wait_for_rcvmsg(sock, timeo); |
| 1004 | if (sock->state == SS_DISCONNECTING) { | 1065 | if (res) |
| 1005 | res = -ENOTCONN; | 1066 | goto exit; |
| 1006 | goto exit; | ||
| 1007 | } | ||
| 1008 | if (timeout <= 0L) { | ||
| 1009 | res = timeout ? timeout : -EWOULDBLOCK; | ||
| 1010 | goto exit; | ||
| 1011 | } | ||
| 1012 | release_sock(sk); | ||
| 1013 | timeout = wait_event_interruptible_timeout(*sk_sleep(sk), | ||
| 1014 | tipc_rx_ready(sock), | ||
| 1015 | timeout); | ||
| 1016 | lock_sock(sk); | ||
| 1017 | } | ||
| 1018 | 1067 | ||
| 1019 | /* Look at first message in receive queue */ | 1068 | /* Look at first message in receive queue */ |
| 1020 | buf = skb_peek(&sk->sk_receive_queue); | 1069 | buf = skb_peek(&sk->sk_receive_queue); |
| @@ -1086,7 +1135,7 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock, | |||
| 1086 | struct tipc_port *tport = tipc_sk_port(sk); | 1135 | struct tipc_port *tport = tipc_sk_port(sk); |
| 1087 | struct sk_buff *buf; | 1136 | struct sk_buff *buf; |
| 1088 | struct tipc_msg *msg; | 1137 | struct tipc_msg *msg; |
| 1089 | long timeout; | 1138 | long timeo; |
| 1090 | unsigned int sz; | 1139 | unsigned int sz; |
| 1091 | int sz_to_copy, target, needed; | 1140 | int sz_to_copy, target, needed; |
| 1092 | int sz_copied = 0; | 1141 | int sz_copied = 0; |
| @@ -1099,31 +1148,19 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock, | |||
| 1099 | 1148 | ||
| 1100 | lock_sock(sk); | 1149 | lock_sock(sk); |
| 1101 | 1150 | ||
| 1102 | if (unlikely((sock->state == SS_UNCONNECTED))) { | 1151 | if (unlikely(sock->state == SS_UNCONNECTED)) { |
| 1103 | res = -ENOTCONN; | 1152 | res = -ENOTCONN; |
| 1104 | goto exit; | 1153 | goto exit; |
| 1105 | } | 1154 | } |
| 1106 | 1155 | ||
| 1107 | target = sock_rcvlowat(sk, flags & MSG_WAITALL, buf_len); | 1156 | target = sock_rcvlowat(sk, flags & MSG_WAITALL, buf_len); |
| 1108 | timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); | 1157 | timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); |
| 1109 | 1158 | ||
| 1110 | restart: | 1159 | restart: |
| 1111 | /* Look for a message in receive queue; wait if necessary */ | 1160 | /* Look for a message in receive queue; wait if necessary */ |
| 1112 | while (skb_queue_empty(&sk->sk_receive_queue)) { | 1161 | res = tipc_wait_for_rcvmsg(sock, timeo); |
| 1113 | if (sock->state == SS_DISCONNECTING) { | 1162 | if (res) |
| 1114 | res = -ENOTCONN; | 1163 | goto exit; |
| 1115 | goto exit; | ||
| 1116 | } | ||
| 1117 | if (timeout <= 0L) { | ||
| 1118 | res = timeout ? timeout : -EWOULDBLOCK; | ||
| 1119 | goto exit; | ||
| 1120 | } | ||
| 1121 | release_sock(sk); | ||
| 1122 | timeout = wait_event_interruptible_timeout(*sk_sleep(sk), | ||
| 1123 | tipc_rx_ready(sock), | ||
| 1124 | timeout); | ||
| 1125 | lock_sock(sk); | ||
| 1126 | } | ||
| 1127 | 1164 | ||
| 1128 | /* Look at first message in receive queue */ | 1165 | /* Look at first message in receive queue */ |
| 1129 | buf = skb_peek(&sk->sk_receive_queue); | 1166 | buf = skb_peek(&sk->sk_receive_queue); |
| @@ -1327,14 +1364,12 @@ static u32 filter_connect(struct tipc_sock *tsock, struct sk_buff **buf) | |||
| 1327 | static unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *buf) | 1364 | static unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *buf) |
| 1328 | { | 1365 | { |
| 1329 | struct tipc_msg *msg = buf_msg(buf); | 1366 | struct tipc_msg *msg = buf_msg(buf); |
| 1330 | unsigned int limit; | ||
| 1331 | 1367 | ||
| 1332 | if (msg_connected(msg)) | 1368 | if (msg_connected(msg)) |
| 1333 | limit = sysctl_tipc_rmem[2]; | 1369 | return sysctl_tipc_rmem[2]; |
| 1334 | else | 1370 | |
| 1335 | limit = sk->sk_rcvbuf >> TIPC_CRITICAL_IMPORTANCE << | 1371 | return sk->sk_rcvbuf >> TIPC_CRITICAL_IMPORTANCE << |
| 1336 | msg_importance(msg); | 1372 | msg_importance(msg); |
| 1337 | return limit; | ||
| 1338 | } | 1373 | } |
| 1339 | 1374 | ||
| 1340 | /** | 1375 | /** |
| @@ -1448,6 +1483,28 @@ static void wakeupdispatch(struct tipc_port *tport) | |||
| 1448 | sk->sk_write_space(sk); | 1483 | sk->sk_write_space(sk); |
| 1449 | } | 1484 | } |
| 1450 | 1485 | ||
| 1486 | static int tipc_wait_for_connect(struct socket *sock, long *timeo_p) | ||
| 1487 | { | ||
| 1488 | struct sock *sk = sock->sk; | ||
| 1489 | DEFINE_WAIT(wait); | ||
| 1490 | int done; | ||
| 1491 | |||
| 1492 | do { | ||
| 1493 | int err = sock_error(sk); | ||
| 1494 | if (err) | ||
| 1495 | return err; | ||
| 1496 | if (!*timeo_p) | ||
| 1497 | return -ETIMEDOUT; | ||
| 1498 | if (signal_pending(current)) | ||
| 1499 | return sock_intr_errno(*timeo_p); | ||
| 1500 | |||
| 1501 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | ||
| 1502 | done = sk_wait_event(sk, timeo_p, sock->state != SS_CONNECTING); | ||
| 1503 | finish_wait(sk_sleep(sk), &wait); | ||
| 1504 | } while (!done); | ||
| 1505 | return 0; | ||
| 1506 | } | ||
| 1507 | |||
| 1451 | /** | 1508 | /** |
| 1452 | * connect - establish a connection to another TIPC port | 1509 | * connect - establish a connection to another TIPC port |
| 1453 | * @sock: socket structure | 1510 | * @sock: socket structure |
| @@ -1463,7 +1520,8 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen, | |||
| 1463 | struct sock *sk = sock->sk; | 1520 | struct sock *sk = sock->sk; |
| 1464 | struct sockaddr_tipc *dst = (struct sockaddr_tipc *)dest; | 1521 | struct sockaddr_tipc *dst = (struct sockaddr_tipc *)dest; |
| 1465 | struct msghdr m = {NULL,}; | 1522 | struct msghdr m = {NULL,}; |
| 1466 | unsigned int timeout; | 1523 | long timeout = (flags & O_NONBLOCK) ? 0 : tipc_sk(sk)->conn_timeout; |
| 1524 | socket_state previous; | ||
| 1467 | int res; | 1525 | int res; |
| 1468 | 1526 | ||
| 1469 | lock_sock(sk); | 1527 | lock_sock(sk); |
| @@ -1485,8 +1543,7 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen, | |||
| 1485 | goto exit; | 1543 | goto exit; |
| 1486 | } | 1544 | } |
| 1487 | 1545 | ||
| 1488 | timeout = (flags & O_NONBLOCK) ? 0 : tipc_sk(sk)->conn_timeout; | 1546 | previous = sock->state; |
| 1489 | |||
| 1490 | switch (sock->state) { | 1547 | switch (sock->state) { |
| 1491 | case SS_UNCONNECTED: | 1548 | case SS_UNCONNECTED: |
| 1492 | /* Send a 'SYN-' to destination */ | 1549 | /* Send a 'SYN-' to destination */ |
| @@ -1508,43 +1565,22 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen, | |||
| 1508 | * case is EINPROGRESS, rather than EALREADY. | 1565 | * case is EINPROGRESS, rather than EALREADY. |
| 1509 | */ | 1566 | */ |
| 1510 | res = -EINPROGRESS; | 1567 | res = -EINPROGRESS; |
| 1511 | break; | ||
| 1512 | case SS_CONNECTING: | 1568 | case SS_CONNECTING: |
| 1513 | res = -EALREADY; | 1569 | if (previous == SS_CONNECTING) |
| 1570 | res = -EALREADY; | ||
| 1571 | if (!timeout) | ||
| 1572 | goto exit; | ||
| 1573 | timeout = msecs_to_jiffies(timeout); | ||
| 1574 | /* Wait until an 'ACK' or 'RST' arrives, or a timeout occurs */ | ||
| 1575 | res = tipc_wait_for_connect(sock, &timeout); | ||
| 1514 | break; | 1576 | break; |
| 1515 | case SS_CONNECTED: | 1577 | case SS_CONNECTED: |
| 1516 | res = -EISCONN; | 1578 | res = -EISCONN; |
| 1517 | break; | 1579 | break; |
| 1518 | default: | 1580 | default: |
| 1519 | res = -EINVAL; | 1581 | res = -EINVAL; |
| 1520 | goto exit; | 1582 | break; |
| 1521 | } | ||
| 1522 | |||
| 1523 | if (sock->state == SS_CONNECTING) { | ||
| 1524 | if (!timeout) | ||
| 1525 | goto exit; | ||
| 1526 | |||
| 1527 | /* Wait until an 'ACK' or 'RST' arrives, or a timeout occurs */ | ||
| 1528 | release_sock(sk); | ||
| 1529 | res = wait_event_interruptible_timeout(*sk_sleep(sk), | ||
| 1530 | sock->state != SS_CONNECTING, | ||
| 1531 | timeout ? (long)msecs_to_jiffies(timeout) | ||
| 1532 | : MAX_SCHEDULE_TIMEOUT); | ||
| 1533 | lock_sock(sk); | ||
| 1534 | if (res <= 0) { | ||
| 1535 | if (res == 0) | ||
| 1536 | res = -ETIMEDOUT; | ||
| 1537 | else | ||
| 1538 | ; /* leave "res" unchanged */ | ||
| 1539 | goto exit; | ||
| 1540 | } | ||
| 1541 | } | 1583 | } |
| 1542 | |||
| 1543 | if (unlikely(sock->state == SS_DISCONNECTING)) | ||
| 1544 | res = sock_error(sk); | ||
| 1545 | else | ||
| 1546 | res = 0; | ||
| 1547 | |||
| 1548 | exit: | 1584 | exit: |
| 1549 | release_sock(sk); | 1585 | release_sock(sk); |
| 1550 | return res; | 1586 | return res; |
| @@ -1575,6 +1611,42 @@ static int listen(struct socket *sock, int len) | |||
| 1575 | return res; | 1611 | return res; |
| 1576 | } | 1612 | } |
| 1577 | 1613 | ||
| 1614 | static int tipc_wait_for_accept(struct socket *sock, long timeo) | ||
| 1615 | { | ||
| 1616 | struct sock *sk = sock->sk; | ||
| 1617 | DEFINE_WAIT(wait); | ||
| 1618 | int err; | ||
| 1619 | |||
| 1620 | /* True wake-one mechanism for incoming connections: only | ||
| 1621 | * one process gets woken up, not the 'whole herd'. | ||
| 1622 | * Since we do not 'race & poll' for established sockets | ||
| 1623 | * anymore, the common case will execute the loop only once. | ||
| 1624 | */ | ||
| 1625 | for (;;) { | ||
| 1626 | prepare_to_wait_exclusive(sk_sleep(sk), &wait, | ||
| 1627 | TASK_INTERRUPTIBLE); | ||
| 1628 | if (skb_queue_empty(&sk->sk_receive_queue)) { | ||
| 1629 | release_sock(sk); | ||
| 1630 | timeo = schedule_timeout(timeo); | ||
| 1631 | lock_sock(sk); | ||
| 1632 | } | ||
| 1633 | err = 0; | ||
| 1634 | if (!skb_queue_empty(&sk->sk_receive_queue)) | ||
| 1635 | break; | ||
| 1636 | err = -EINVAL; | ||
| 1637 | if (sock->state != SS_LISTENING) | ||
| 1638 | break; | ||
| 1639 | err = sock_intr_errno(timeo); | ||
| 1640 | if (signal_pending(current)) | ||
| 1641 | break; | ||
| 1642 | err = -EAGAIN; | ||
| 1643 | if (!timeo) | ||
| 1644 | break; | ||
| 1645 | } | ||
| 1646 | finish_wait(sk_sleep(sk), &wait); | ||
| 1647 | return err; | ||
| 1648 | } | ||
| 1649 | |||
| 1578 | /** | 1650 | /** |
| 1579 | * accept - wait for connection request | 1651 | * accept - wait for connection request |
| 1580 | * @sock: listening socket | 1652 | * @sock: listening socket |
| @@ -1591,7 +1663,7 @@ static int accept(struct socket *sock, struct socket *new_sock, int flags) | |||
| 1591 | struct tipc_port *new_tport; | 1663 | struct tipc_port *new_tport; |
| 1592 | struct tipc_msg *msg; | 1664 | struct tipc_msg *msg; |
| 1593 | u32 new_ref; | 1665 | u32 new_ref; |
| 1594 | 1666 | long timeo; | |
| 1595 | int res; | 1667 | int res; |
| 1596 | 1668 | ||
| 1597 | lock_sock(sk); | 1669 | lock_sock(sk); |
| @@ -1601,18 +1673,10 @@ static int accept(struct socket *sock, struct socket *new_sock, int flags) | |||
| 1601 | goto exit; | 1673 | goto exit; |
| 1602 | } | 1674 | } |
| 1603 | 1675 | ||
| 1604 | while (skb_queue_empty(&sk->sk_receive_queue)) { | 1676 | timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); |
| 1605 | if (flags & O_NONBLOCK) { | 1677 | res = tipc_wait_for_accept(sock, timeo); |
| 1606 | res = -EWOULDBLOCK; | 1678 | if (res) |
| 1607 | goto exit; | 1679 | goto exit; |
| 1608 | } | ||
| 1609 | release_sock(sk); | ||
| 1610 | res = wait_event_interruptible(*sk_sleep(sk), | ||
| 1611 | (!skb_queue_empty(&sk->sk_receive_queue))); | ||
| 1612 | lock_sock(sk); | ||
| 1613 | if (res) | ||
| 1614 | goto exit; | ||
| 1615 | } | ||
| 1616 | 1680 | ||
| 1617 | buf = skb_peek(&sk->sk_receive_queue); | 1681 | buf = skb_peek(&sk->sk_receive_queue); |
| 1618 | 1682 | ||
