You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
All of Linux, OS X and Windows are the same, call setsockopt with TCP_FASTOPEN option
// For Linux, value is the queue length of pending packetsintopt=5;
// For the others, just a boolean value for enable and disableintopt=1;
// Call it before listen()intret=setsockopt(socket, IPPROTO_TCP, TCP_FASTOPEN, &opt, sizeof(opt));
TcpStream
This is a bit more complicated than TcpListener, because we have to send SYN with the first data packet to make TFO works. APIs are completely different on different platforms:
Linux
Before 4.11, Linux uses MSG_FASTOPEN flag for sendto(), doesn't need to call connect()
// Send SYN with data in bufssize_tn=sendto(socket, buf, buf_length, MSG_FASTOPEN, saddr, saddr_len);
After 4.11, Linux provides a TCP_FASTOPEN_CONNECT option
intenable=1;
// Enable it before connect()intret=setsockopt(socket, IPPROTO_TCP, TCP_FASTOPEN_CONNECT, &enable, sizeof(enable));
// Call connect as usualintret=connect(socket, saddr, saddr_len);
BSDs (except Darwin)
Uses sendto() as Linux without MSG_FASTOPEN flag
// Set before sendto()intret=setsockopt(socket, IPPROTO_TCP, TCP_FASTOPEN, &opt, sizeof(opt));
// Call sendto() without flagsssize_tn=sendto(socket, buf, buf_length, 0, saddr, saddr_len);
Darwin (OS X)
Darwin supports TFO after OS X 10.11, iOS 9.0, tvOS 9.0 and watchOS 2.0.
// TCP_FASTOPEN is requiredint ret = setsockopt(socket, IPPROTO_TCP, TCP_FASTOPEN, &opt, sizeof(opt));
// Get LPFN_CONNECTEX
LPFN_CONNECTEX ConnectEx = ...;
// Call it with the first packet of data, SYN will send with this packet's data
LPDWORD bytesSent = 0;
int ret = ConnectEx(socket, saddr, saddr_len, buf, buf_length, &bytesSent, &overlapped);
Challenge
As we can see for those OSes' APIs, (except OS X and Linux > 4.10) connections are made with the first write(), which means that if we want to support TFO, we have to put those code in the first call of std::io::Write::write or tokio::AsyncWrite::poll_write.
There is no other way except customizing a TcpStream from socket() and call different APIs on different OSes while sending the first data packet.
I want to open a discussion here for how in Rust's world to support TFO gracefully.
TcpListenerAll of Linux, OS X and Windows are the same, call
setsockoptwithTCP_FASTOPENoptionTcpStreamThis is a bit more complicated than
TcpListener, because we have to sendSYNwith the first data packet to make TFO works. APIs are completely different on different platforms:Linux
Before 4.11, Linux uses
MSG_FASTOPENflag forsendto(), doesn't need to callconnect()After 4.11, Linux provides a
TCP_FASTOPEN_CONNECToptionBSDs (except Darwin)
Uses
sendto()as Linux withoutMSG_FASTOPENflagDarwin (OS X)
Darwin supports TFO after OS X 10.11, iOS 9.0, tvOS 9.0 and watchOS 2.0.
It supports with a new syscall
connectx.SYN will be sent with the first
writeorsend.Windows
Windows supports with
ConnectEx, since Windows 10. https://docs.microsoft.com/en-us/windows/win32/api/mswsock/nc-mswsock-lpfn_connectexChallenge
As we can see for those OSes' APIs, (except OS X and Linux > 4.10) connections are made with the first
write(), which means that if we want to support TFO, we have to put those code in the first call ofstd::io::Write::writeortokio::AsyncWrite::poll_write.There is no other way except customizing a
TcpStreamfromsocket()and call different APIs on different OSes while sending the first data packet.I want to open a discussion here for how in Rust's world to support TFO gracefully.
Related API PRs
connectxfor OS X: Add TCP FastOpen support for macOS libc#1635TCP_FASTOPEN_CONNECTfor Linux: Add TCP_FASTOPEN_CONNECT for Linux after 4.11 libc#1634TCP_FASTOPENfor Windows: Missing TCP_FASTOPEN retep998/winapi-rs#856