aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp.c
diff options
context:
space:
mode:
authorYuchung Cheng <ycheng@google.com>2012-07-19 02:43:09 -0400
committerDavid S. Miller <davem@davemloft.net>2012-07-19 14:02:03 -0400
commitcf60af03ca4e71134206809ea892e49b92a88896 (patch)
tree478ee362f10d0737fbc4e6642e2966abe0cd1397 /net/ipv4/tcp.c
parent8e4178c1c7b52f7c99f5fd22ef7af6b2bff409e3 (diff)
net-tcp: Fast Open client - sendmsg(MSG_FASTOPEN)
sendmsg() (or sendto()) with MSG_FASTOPEN is a combo of connect(2) and write(2). The application should replace connect() with it to send data in the opening SYN packet. For blocking socket, sendmsg() blocks until all the data are buffered locally and the handshake is completed like connect() call. It returns similar errno like connect() if the TCP handshake fails. For non-blocking socket, it returns the number of bytes queued (and transmitted in the SYN-data packet) if cookie is available. If cookie is not available, it transmits a data-less SYN packet with Fast Open cookie request option and returns -EINPROGRESS like connect(). Using MSG_FASTOPEN on connecting or connected socket will result in simlar errno like repeating connect() calls. Therefore the application should only use this flag on new sockets. The buffer size of sendmsg() is independent of the MSS of the connection. Signed-off-by: Yuchung Cheng <ycheng@google.com> Acked-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp.c')
-rw-r--r--net/ipv4/tcp.c61
1 files changed, 56 insertions, 5 deletions
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 4252cd8f39fd..581ecf02c6b5 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -270,6 +270,7 @@
270#include <linux/slab.h> 270#include <linux/slab.h>
271 271
272#include <net/icmp.h> 272#include <net/icmp.h>
273#include <net/inet_common.h>
273#include <net/tcp.h> 274#include <net/tcp.h>
274#include <net/xfrm.h> 275#include <net/xfrm.h>
275#include <net/ip.h> 276#include <net/ip.h>
@@ -982,26 +983,67 @@ static inline int select_size(const struct sock *sk, bool sg)
982 return tmp; 983 return tmp;
983} 984}
984 985
986void tcp_free_fastopen_req(struct tcp_sock *tp)
987{
988 if (tp->fastopen_req != NULL) {
989 kfree(tp->fastopen_req);
990 tp->fastopen_req = NULL;
991 }
992}
993
994static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg, int *size)
995{
996 struct tcp_sock *tp = tcp_sk(sk);
997 int err, flags;
998
999 if (!(sysctl_tcp_fastopen & TFO_CLIENT_ENABLE))
1000 return -EOPNOTSUPP;
1001 if (tp->fastopen_req != NULL)
1002 return -EALREADY; /* Another Fast Open is in progress */
1003
1004 tp->fastopen_req = kzalloc(sizeof(struct tcp_fastopen_request),
1005 sk->sk_allocation);
1006 if (unlikely(tp->fastopen_req == NULL))
1007 return -ENOBUFS;
1008 tp->fastopen_req->data = msg;
1009
1010 flags = (msg->msg_flags & MSG_DONTWAIT) ? O_NONBLOCK : 0;
1011 err = __inet_stream_connect(sk->sk_socket, msg->msg_name,
1012 msg->msg_namelen, flags);
1013 *size = tp->fastopen_req->copied;
1014 tcp_free_fastopen_req(tp);
1015 return err;
1016}
1017
985int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, 1018int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
986 size_t size) 1019 size_t size)
987{ 1020{
988 struct iovec *iov; 1021 struct iovec *iov;
989 struct tcp_sock *tp = tcp_sk(sk); 1022 struct tcp_sock *tp = tcp_sk(sk);
990 struct sk_buff *skb; 1023 struct sk_buff *skb;
991 int iovlen, flags, err, copied; 1024 int iovlen, flags, err, copied = 0;
992 int mss_now = 0, size_goal; 1025 int mss_now = 0, size_goal, copied_syn = 0, offset = 0;
993 bool sg; 1026 bool sg;
994 long timeo; 1027 long timeo;
995 1028
996 lock_sock(sk); 1029 lock_sock(sk);
997 1030
998 flags = msg->msg_flags; 1031 flags = msg->msg_flags;
1032 if (flags & MSG_FASTOPEN) {
1033 err = tcp_sendmsg_fastopen(sk, msg, &copied_syn);
1034 if (err == -EINPROGRESS && copied_syn > 0)
1035 goto out;
1036 else if (err)
1037 goto out_err;
1038 offset = copied_syn;
1039 }
1040
999 timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); 1041 timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
1000 1042
1001 /* Wait for a connection to finish. */ 1043 /* Wait for a connection to finish. */
1002 if ((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) 1044 if ((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT))
1003 if ((err = sk_stream_wait_connect(sk, &timeo)) != 0) 1045 if ((err = sk_stream_wait_connect(sk, &timeo)) != 0)
1004 goto out_err; 1046 goto do_error;
1005 1047
1006 if (unlikely(tp->repair)) { 1048 if (unlikely(tp->repair)) {
1007 if (tp->repair_queue == TCP_RECV_QUEUE) { 1049 if (tp->repair_queue == TCP_RECV_QUEUE) {
@@ -1037,6 +1079,15 @@ int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
1037 unsigned char __user *from = iov->iov_base; 1079 unsigned char __user *from = iov->iov_base;
1038 1080
1039 iov++; 1081 iov++;
1082 if (unlikely(offset > 0)) { /* Skip bytes copied in SYN */
1083 if (offset >= seglen) {
1084 offset -= seglen;
1085 continue;
1086 }
1087 seglen -= offset;
1088 from += offset;
1089 offset = 0;
1090 }
1040 1091
1041 while (seglen > 0) { 1092 while (seglen > 0) {
1042 int copy = 0; 1093 int copy = 0;
@@ -1199,7 +1250,7 @@ out:
1199 if (copied && likely(!tp->repair)) 1250 if (copied && likely(!tp->repair))
1200 tcp_push(sk, flags, mss_now, tp->nonagle); 1251 tcp_push(sk, flags, mss_now, tp->nonagle);
1201 release_sock(sk); 1252 release_sock(sk);
1202 return copied; 1253 return copied + copied_syn;
1203 1254
1204do_fault: 1255do_fault:
1205 if (!skb->len) { 1256 if (!skb->len) {
@@ -1212,7 +1263,7 @@ do_fault:
1212 } 1263 }
1213 1264
1214do_error: 1265do_error:
1215 if (copied) 1266 if (copied + copied_syn)
1216 goto out; 1267 goto out;
1217out_err: 1268out_err:
1218 err = sk_stream_error(sk, flags, err); 1269 err = sk_stream_error(sk, flags, err);