Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TCP Fast Open support #660

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/curl.1
Expand Up @@ -1742,6 +1742,8 @@ curl -T "img[1-1000].png" ftp://ftp.example.com/upload/
.IP "--tcp-nodelay"
Turn on the TCP_NODELAY option. See the \fIcurl_easy_setopt(3)\fP man page for
details about this option. (Added in 7.11.2)
.IP "--tcp-fastopen"
Enable use of TCP Fast Open (RFC7413). (Added in 7.49.0)
.IP "--tftp-blksize <value>"
(TFTP) Set TFTP BLKSIZE option (must be >512). This is the block size that
curl will try to use when transferring data to or from a TFTP server. By
Expand Down
47 changes: 47 additions & 0 deletions docs/libcurl/opts/CURLOPT_TCP_FASTOPEN.3
@@ -0,0 +1,47 @@
.\" **************************************************************************
.\" * _ _ ____ _
.\" * Project ___| | | | _ \| |
.\" * / __| | | | |_) | |
.\" * | (__| |_| | _ <| |___
.\" * \___|\___/|_| \_\_____|
.\" *
.\" * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
.\" *
.\" * This software is licensed as described in the file COPYING, which
.\" * you should have received as part of this distribution. The terms
.\" * are also available at https://curl.haxx.se/docs/copyright.html.
.\" *
.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell
.\" * copies of the Software, and permit persons to whom the Software is
.\" * furnished to do so, under the terms of the COPYING file.
.\" *
.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
.\" * KIND, either express or implied.
.\" *
.\" **************************************************************************
.\"
.TH CURLOPT_TCP_FASTOPEN 3 "16 Feb 2016" "libcurl 7.49.0" "curl_easy_setopt options"
.SH NAME
CURLOPT_TCP_FASTOPEN \- enable TCP Fast Open
.SH SYNOPSIS
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TCP_FASTOPEN, long enable);
.SH DESCRIPTION
Pass a long as parameter set to 1 to enable or 0 to disable.

TCP Fast Open (RFC7413) is a mechanism that allows data to be carried in the
SYN and SYN-ACK packets and consumed by the receiving end during the initial
connection handshake, saving up to one full round-trip time (RTT).
.SH DEFAULT
0
.SH PROTOCOLS
All
.SH EXAMPLE
TODO
.SH AVAILABILITY
Added in 7.49.0. This option is currently only supported on Linux and OS X
El Capitan.
.SH RETURN VALUE
Returns CURLE_OK if fast open is supported by the operating system, otherwise
returns CURLE_NOT_BUILT_IN.
3 changes: 3 additions & 0 deletions docs/libcurl/opts/Makefile.am
Expand Up @@ -103,6 +103,7 @@ man_MANS = CURLOPT_ACCEPT_ENCODING.3 CURLOPT_ACCEPTTIMEOUT_MS.3 \
CURLOPT_TLSAUTH_TYPE.3 CURLOPT_TLSAUTH_USERNAME.3 \
CURLOPT_TRANSFER_ENCODING.3 CURLOPT_TRANSFERTEXT.3 \
CURLOPT_UNRESTRICTED_AUTH.3 CURLOPT_UPLOAD.3 \
CURLOPT_TCP_FASTOPEN.3 \
CURLOPT_URL.3 CURLOPT_USERAGENT.3 CURLOPT_USERNAME.3 CURLOPT_USERPWD.3 \
CURLOPT_USE_SSL.3 CURLOPT_VERBOSE.3 CURLOPT_WILDCARDMATCH.3 \
CURLOPT_WRITEDATA.3 CURLOPT_WRITEFUNCTION.3 CURLOPT_XFERINFODATA.3 \
Expand Down Expand Up @@ -229,6 +230,7 @@ HTMLPAGES = CURLOPT_ACCEPT_ENCODING.html CURLOPT_ACCEPTTIMEOUT_MS.html \
CURLOPT_TFTP_BLKSIZE.html CURLOPT_TFTP_NO_OPTIONS.html \
CURLOPT_TIMECONDITION.html CURLOPT_TIMEOUT.html \
CURLOPT_TIMEOUT_MS.html CURLOPT_TIMEVALUE.html \
CURLOPT_TCP_FASTOPEN.html \
CURLOPT_TLSAUTH_PASSWORD.html CURLOPT_TLSAUTH_TYPE.html \
CURLOPT_TLSAUTH_USERNAME.html CURLOPT_TRANSFER_ENCODING.html \
CURLOPT_TRANSFERTEXT.html CURLOPT_UNRESTRICTED_AUTH.html \
Expand Down Expand Up @@ -360,6 +362,7 @@ PDFPAGES = CURLOPT_ACCEPT_ENCODING.pdf CURLOPT_ACCEPTTIMEOUT_MS.pdf \
CURLOPT_TCP_NODELAY.pdf CURLOPT_TELNETOPTIONS.pdf \
CURLOPT_TFTP_BLKSIZE.pdf CURLOPT_TFTP_NO_OPTIONS.pdf \
CURLOPT_TIMECONDITION.pdf CURLOPT_TIMEOUT.pdf \
CURLOPT_TCP_FASTOPEN.pdf \
CURLOPT_TIMEOUT_MS.pdf CURLOPT_TIMEVALUE.pdf \
CURLOPT_TLSAUTH_PASSWORD.pdf CURLOPT_TLSAUTH_TYPE.pdf \
CURLOPT_TLSAUTH_USERNAME.pdf CURLOPT_TRANSFER_ENCODING.pdf \
Expand Down
1 change: 1 addition & 0 deletions docs/libcurl/symbols-in-versions
Expand Up @@ -538,6 +538,7 @@ CURLOPT_TCP_KEEPALIVE 7.25.0
CURLOPT_TCP_KEEPIDLE 7.25.0
CURLOPT_TCP_KEEPINTVL 7.25.0
CURLOPT_TCP_NODELAY 7.11.2
CURLOPT_TCP_FASTOPEN 7.49.0
CURLOPT_TELNETOPTIONS 7.7
CURLOPT_TFTP_BLKSIZE 7.19.4
CURLOPT_TFTP_NO_OPTIONS 7.48.0
Expand Down
3 changes: 3 additions & 0 deletions include/curl/curl.h
Expand Up @@ -1686,6 +1686,9 @@ typedef enum {
overrides the URL's host:port (only for the network layer) */
CINIT(CONNECT_TO, STRINGPOINT, 243),

/* Set TCP Fast Open */
CINIT(TCP_FASTOPEN, LONG, 244),

CURLOPT_LASTENTRY /* the last unused */
} CURLoption;

Expand Down
25 changes: 22 additions & 3 deletions lib/connect.c
Expand Up @@ -668,7 +668,7 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
/* there's no connection! */
return;

if(!conn->bits.reuse) {
if(!conn->bits.reuse && !conn->bits.tcp_fastopen) {
int error;

len = sizeof(struct Curl_sockaddr_storage);
Expand Down Expand Up @@ -776,7 +776,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
trynextip(conn, sockindex, 1);
}
}
else if(rc == CURL_CSELECT_OUT) {
else if(rc == CURL_CSELECT_OUT || conn->bits.tcp_fastopen) {
if(verifyconnect(conn->tempsock[i], &error)) {
/* we are connected with TCP, awesome! */

Expand Down Expand Up @@ -1097,7 +1097,26 @@ static CURLcode singleipconnect(struct connectdata *conn,

/* Connect TCP sockets, bind UDP */
if(!isconnected && (conn->socktype == SOCK_STREAM)) {
rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
if(conn->bits.tcp_fastopen) {
#if defined(CONNECT_DATA_IDEMPOTENT) /* OS X */
sa_endpoints_t endpoints;
endpoints.sae_srcif = 0;
endpoints.sae_srcaddr = NULL;
endpoints.sae_srcaddrlen = 0;
endpoints.sae_dstaddr = &addr.sa_addr;
endpoints.sae_dstaddrlen = addr.addrlen;

rc = connectx(sockfd, &endpoints, SAE_ASSOCID_ANY,
CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT,
NULL, 0, NULL, NULL);
#elif defined(MSG_FASTOPEN) /* Linux */
rc = 0; /* Do nothing */
#endif
}
else {
rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
}

if(-1 == rc)
error = SOCKERRNO;
}
Expand Down
15 changes: 13 additions & 2 deletions lib/sendf.c
Expand Up @@ -254,7 +254,17 @@ ssize_t Curl_send_plain(struct connectdata *conn, int num,
const void *mem, size_t len, CURLcode *code)
{
curl_socket_t sockfd = conn->sock[num];
ssize_t bytes_written = swrite(sockfd, mem, len);
ssize_t bytes_written;

#ifdef MSG_FASTOPEN /* Linux */
if(conn->bits.tcp_fastopen) {
bytes_written = sendto(sockfd, mem, len, MSG_FASTOPEN,
conn->ip_addr->ai_addr, conn->ip_addr->ai_addrlen);
conn->bits.tcp_fastopen = FALSE;
}
else
#endif
bytes_written = swrite(sockfd, mem, len);

*code = CURLE_OK;
if(-1 == bytes_written) {
Expand All @@ -268,7 +278,8 @@ ssize_t Curl_send_plain(struct connectdata *conn, int num,
/* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
due to its inability to send off data without blocking. We therefor
treat both error codes the same here */
(EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err)
(EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err) ||
(EINPROGRESS == err)
#endif
) {
/* this is just a case of EWOULDBLOCK */
Expand Down
10 changes: 10 additions & 0 deletions lib/url.c
Expand Up @@ -595,6 +595,7 @@ CURLcode Curl_init_userdefined(struct UserDefined *set)
set->tcp_keepalive = FALSE;
set->tcp_keepintvl = 60;
set->tcp_keepidle = 60;
set->tcp_fastopen = FALSE;

set->ssl_enable_npn = TRUE;
set->ssl_enable_alpn = TRUE;
Expand Down Expand Up @@ -2631,6 +2632,13 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
case CURLOPT_TCP_KEEPINTVL:
data->set.tcp_keepintvl = va_arg(param, long);
break;
case CURLOPT_TCP_FASTOPEN:
#if defined(CONNECT_DATA_IDEMPOTENT) || defined(MSG_FASTOPEN)
data->set.tcp_fastopen = (0 != va_arg(param, long))?TRUE:FALSE;
#else
result = CURLE_NOT_BUILT_IN;
#endif
break;
case CURLOPT_SSL_ENABLE_NPN:
data->set.ssl_enable_npn = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
Expand Down Expand Up @@ -5975,6 +5983,8 @@ static CURLcode create_conn(struct SessionHandle *data,
conn->recv[SECONDARYSOCKET] = Curl_recv_plain;
conn->send[SECONDARYSOCKET] = Curl_send_plain;

conn->bits.tcp_fastopen = data->set.tcp_fastopen;

/***********************************************************************
* file: is a special case in that it doesn't need a network connection
***********************************************************************/
Expand Down
3 changes: 3 additions & 0 deletions lib/urldata.h
Expand Up @@ -544,6 +544,8 @@ struct ConnectBits {
connection */
bool type_set; /* type= was used in the URL */
bool multiplex; /* connection is multiplexed */

bool tcp_fastopen; /* use TCP Fast Open */
};

struct hostname {
Expand Down Expand Up @@ -1650,6 +1652,7 @@ struct UserDefined {
bool tcp_keepalive; /* use TCP keepalives */
long tcp_keepidle; /* seconds in idle before sending keepalive probe */
long tcp_keepintvl; /* seconds between TCP keepalive probes */
bool tcp_fastopen; /* use TCP Fast Open */

size_t maxconnects; /* Max idle connections in the connection cache */

Expand Down
1 change: 1 addition & 0 deletions src/tool_cfgable.h
Expand Up @@ -174,6 +174,7 @@ struct OperationConfig {
Kerberos 5 and SPNEGO */

bool tcp_nodelay;
bool tcp_fastopen;
long req_retry; /* number of retries */
long retry_delay; /* delay between retries (in seconds) */
long retry_maxtime; /* maximum time to keep retrying */
Expand Down
5 changes: 5 additions & 0 deletions src/tool_getparam.c
Expand Up @@ -229,6 +229,7 @@ static const struct LongShort aliases[]= {
{"Eq", "cert-status", FALSE},
{"Er", "false-start", FALSE},
{"Es", "ssl-no-revoke", FALSE},
{"Et", "tcp-fastopen", FALSE},
{"f", "fail", FALSE},
{"F", "form", TRUE},
{"Fs", "form-string", TRUE},
Expand Down Expand Up @@ -1415,6 +1416,10 @@ ParameterError getparameter(char *flag, /* f or -long-flag */
config->ssl_no_revoke = TRUE;
break;

case 't': /* --tcp-fastopen */
config->tcp_fastopen = TRUE;
break;

default: /* certificate file */
{
char *certname, *passphrase;
Expand Down
1 change: 1 addition & 0 deletions src/tool_help.c
Expand Up @@ -221,6 +221,7 @@ static const char *const helptext[] = {
" --ssl-no-revoke Disable cert revocation checks (WinSSL)",
" --stderr FILE Where to redirect stderr (use \"-\" for stdout)",
" --tcp-nodelay Use the TCP_NODELAY option",
" --tcp-fastopen Use TCP Fast Open",
" -t, --telnet-option OPT=VAL Set telnet option",
" --tftp-blksize VALUE Set TFTP BLKSIZE option (must be >512)",
" --tftp-no-options Do not send TFTP options requests",
Expand Down
3 changes: 3 additions & 0 deletions src/tool_operate.c
Expand Up @@ -794,6 +794,9 @@ static CURLcode operate_do(struct GlobalConfig *global,
if(config->tcp_nodelay)
my_setopt(curl, CURLOPT_TCP_NODELAY, 1L);

if(config->tcp_fastopen)
my_setopt(curl, CURLOPT_TCP_FASTOPEN, 1L);

/* where to store */
my_setopt(curl, CURLOPT_WRITEDATA, &outs);
if(metalink || !config->use_metalink)
Expand Down