aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerrit Renker <gerrit@erg.abdn.ac.uk>2007-11-21 06:56:48 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 17:54:44 -0500
commit8e8c71f1ab0ca1c4e74efad14533b991524dcb6c (patch)
treeab9cf593ce85ca9eb278ccb1b683fbe459686cbd
parent9b91ad2747891767c0efb4fb965c5dfed8d4f88e (diff)
[DCCP]: Honour and make use of shutdown option set by user
This extends the DCCP socket API by honouring any shutdown(2) option set by the user. The behaviour is, as much as possible, made consistent with the API for TCP's shutdown. This patch exploits the information provided by the user via the socket API to reduce processing costs: * if the read end is closed (SHUT_RD), it is not necessary to deliver to input CCID; * if the write end is closed (SHUT_WR), the same idea applies, but with a difference - as long as the TX queue has not been drained, we need to receive feedback to keep congestion-control rates up to date. Hence SHUT_WR is honoured only after the last packet (under congestion control) has been sent; * although SHUT_RDWR seems nonsensical, it is nevertheless supported in the same manner as for TCP (and agrees with test for SHUTDOWN_MASK in dccp_poll() in net/dccp/proto.c). Furthermore, most of the code already honours the sk_shutdown flags (dccp_recvmsg() for instance sets the read length to 0 if SHUT_RD had been called); CCID handling is now added to this by the present patch. There will also no longer be any delivery when the socket is in the final stages, i.e. when one of dccp_close(), dccp_fin(), or dccp_done() has been called - which is fine since at that stage the connection is its final stages. Motivation and background are on http://www.erg.abdn.ac.uk/users/gerrit/dccp/notes/shutdown A FIXME has been added to notify the other end if SHUT_RD has been set (RFC 4340, 11.7). Note: There is a comment in inet_shutdown() in net/ipv4/af_inet.c which asks to "make sure the socket is a TCP socket". This should probably be extended to mean `TCP or DCCP socket' (the code is also used by UDP and raw sockets). Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk> Signed-off-by: Ian McDonald <ian.mcdonald@jandi.co.nz> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--Documentation/networking/dccp.txt2
-rw-r--r--net/dccp/input.c27
-rw-r--r--net/dccp/proto.c2
3 files changed, 23 insertions, 8 deletions
diff --git a/Documentation/networking/dccp.txt b/Documentation/networking/dccp.txt
index afb66f9a8aff..f771034e8f27 100644
--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -72,6 +72,8 @@ DCCP_SOCKOPT_CCID_TX_INFO
72 Returns a `struct tfrc_tx_info' in optval; the buffer for optval and 72 Returns a `struct tfrc_tx_info' in optval; the buffer for optval and
73 optlen must be set to at least sizeof(struct tfrc_tx_info). 73 optlen must be set to at least sizeof(struct tfrc_tx_info).
74 74
75On unidirectional connections it is useful to close the unused half-connection
76via shutdown (SHUT_WR or SHUT_RD): this will reduce per-packet processing costs.
75 77
76Sysctl variables 78Sysctl variables
77================ 79================
diff --git a/net/dccp/input.c b/net/dccp/input.c
index 1ce101062824..df0fb2c149a6 100644
--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -103,6 +103,21 @@ static void dccp_event_ack_recv(struct sock *sk, struct sk_buff *skb)
103 DCCP_SKB_CB(skb)->dccpd_ack_seq); 103 DCCP_SKB_CB(skb)->dccpd_ack_seq);
104} 104}
105 105
106static void dccp_deliver_input_to_ccids(struct sock *sk, struct sk_buff *skb)
107{
108 const struct dccp_sock *dp = dccp_sk(sk);
109
110 /* Don't deliver to RX CCID when node has shut down read end. */
111 if (!(sk->sk_shutdown & RCV_SHUTDOWN))
112 ccid_hc_rx_packet_recv(dp->dccps_hc_rx_ccid, sk, skb);
113 /*
114 * Until the TX queue has been drained, we can not honour SHUT_WR, since
115 * we need received feedback as input to adjust congestion control.
116 */
117 if (sk->sk_write_queue.qlen > 0 || !(sk->sk_shutdown & SEND_SHUTDOWN))
118 ccid_hc_tx_packet_recv(dp->dccps_hc_tx_ccid, sk, skb);
119}
120
106static int dccp_check_seqno(struct sock *sk, struct sk_buff *skb) 121static int dccp_check_seqno(struct sock *sk, struct sk_buff *skb)
107{ 122{
108 const struct dccp_hdr *dh = dccp_hdr(skb); 123 const struct dccp_hdr *dh = dccp_hdr(skb);
@@ -209,8 +224,9 @@ static int __dccp_rcv_established(struct sock *sk, struct sk_buff *skb,
209 case DCCP_PKT_DATAACK: 224 case DCCP_PKT_DATAACK:
210 case DCCP_PKT_DATA: 225 case DCCP_PKT_DATA:
211 /* 226 /*
212 * FIXME: check if sk_receive_queue is full, schedule DATA_DROPPED 227 * FIXME: schedule DATA_DROPPED (RFC 4340, 11.7.2) if and when
213 * option if it is. 228 * - sk_shutdown == RCV_SHUTDOWN, use Code 1, "Not Listening"
229 * - sk_receive_queue is full, use Code 2, "Receive Buffer"
214 */ 230 */
215 __skb_pull(skb, dh->dccph_doff * 4); 231 __skb_pull(skb, dh->dccph_doff * 4);
216 __skb_queue_tail(&sk->sk_receive_queue, skb); 232 __skb_queue_tail(&sk->sk_receive_queue, skb);
@@ -300,9 +316,7 @@ int dccp_rcv_established(struct sock *sk, struct sk_buff *skb,
300 DCCP_SKB_CB(skb)->dccpd_seq, 316 DCCP_SKB_CB(skb)->dccpd_seq,
301 DCCP_ACKVEC_STATE_RECEIVED)) 317 DCCP_ACKVEC_STATE_RECEIVED))
302 goto discard; 318 goto discard;
303 319 dccp_deliver_input_to_ccids(sk, skb);
304 ccid_hc_rx_packet_recv(dp->dccps_hc_rx_ccid, sk, skb);
305 ccid_hc_tx_packet_recv(dp->dccps_hc_tx_ccid, sk, skb);
306 320
307 return __dccp_rcv_established(sk, skb, dh, len); 321 return __dccp_rcv_established(sk, skb, dh, len);
308discard: 322discard:
@@ -543,8 +557,7 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
543 DCCP_ACKVEC_STATE_RECEIVED)) 557 DCCP_ACKVEC_STATE_RECEIVED))
544 goto discard; 558 goto discard;
545 559
546 ccid_hc_rx_packet_recv(dp->dccps_hc_rx_ccid, sk, skb); 560 dccp_deliver_input_to_ccids(sk, skb);
547 ccid_hc_tx_packet_recv(dp->dccps_hc_tx_ccid, sk, skb);
548 } 561 }
549 562
550 /* 563 /*
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index 7a3bea9c28c1..0aec73592124 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -981,7 +981,7 @@ EXPORT_SYMBOL_GPL(dccp_close);
981 981
982void dccp_shutdown(struct sock *sk, int how) 982void dccp_shutdown(struct sock *sk, int how)
983{ 983{
984 dccp_pr_debug("entry\n"); 984 dccp_pr_debug("called shutdown(%x)\n", how);
985} 985}
986 986
987EXPORT_SYMBOL_GPL(dccp_shutdown); 987EXPORT_SYMBOL_GPL(dccp_shutdown);