Skip to content

Commit db5353c

Browse files
authored
Added TcpFastOpenConnect sockopt (#2247)
From [tcp](https://man7.org/linux/man-pages/man7/tcp.7.html) man page: ``` TCP_FASTOPEN_CONNECT (since Linux 4.11) This option enables an alternative way to perform Fast Open on the active side (client). When this option is enabled, connect(2) would behave differently depending on if a Fast Open cookie is available for the destination. If a cookie is not available (i.e. first contact to the destination), connect(2) behaves as usual by sending a SYN immediately, except the SYN would include an empty Fast Open cookie option to solicit a cookie. If a cookie is available, connect(2) would return 0 immediately but the SYN transmission is deferred. A subsequent write(2) or sendmsg(2) would trigger a SYN with data plus cookie in the Fast Open option. In other words, the actual connect operation is deferred until data is supplied. Note: While this option is designed for convenience, enabling it does change the behaviors and certain system calls might set different errno values. With cookie present, write(2) or sendmsg(2) must be called right after connect(2) in order to send out SYN+data to complete 3WHS and establish connection. Calling read(2) right after connect(2) without write(2) will cause the blocking socket to be blocked forever. The application should either set TCP_FASTOPEN_CONNECT socket option before write(2) or sendmsg(2), or call write(2) or sendmsg(2) with MSG_FASTOPEN flag directly, instead of both on the same connection. Here is the typical call flow with this new option: s = socket(); setsockopt(s, IPPROTO_TCP, TCP_FASTOPEN_CONNECT, 1, ...); connect(s); write(s); /* write() should always follow connect() * in order to trigger SYN to go out. */ read(s)/write(s); /* ... */ close(s); ```
1 parent 9b39cf9 commit db5353c

File tree

3 files changed

+45
-0
lines changed

3 files changed

+45
-0
lines changed

changelog/2247.added.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Added `TcpFastOpenConnect` sockopt to support `TCP_FASTOPEN_CONNECT` available on linux.

src/sys/socket/sockopt.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,26 @@ sockopt_impl!(
600600
libc::TCP_USER_TIMEOUT,
601601
u32
602602
);
603+
#[cfg(linux_android)]
604+
#[cfg(feature = "net")]
605+
sockopt_impl!(
606+
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
607+
/// Enables TCP Fast Open (RFC 7413) on a connecting socket. If a fast open
608+
/// cookie is not available (first attempt to connect), `connect` syscall
609+
/// will behave as usual, except for internally trying to solicit a cookie
610+
/// from remote peer. When cookie is available, the next `connect` syscall
611+
/// will immediately succeed without actually establishing TCP connection.
612+
/// The connection establishment will be defered till the next `write` or
613+
/// `sendmsg` syscalls on the socket, allowing TCP prtocol to establish
614+
/// connection and send data in the same packets. Note: calling `read` right
615+
/// after `connect` without `write` on the socket will cause the blocking
616+
/// socket to be blocked forever.
617+
TcpFastOpenConnect,
618+
Both,
619+
libc::IPPROTO_TCP,
620+
libc::TCP_FASTOPEN_CONNECT,
621+
bool
622+
);
603623
sockopt_impl!(
604624
/// Sets or gets the maximum socket receive buffer in bytes.
605625
RcvBuf,

test/sys/test_sockopt.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,3 +576,27 @@ fn test_ip_bind_address_no_port() {
576576
"getting IP_BIND_ADDRESS_NO_PORT on an inet stream socket should succeed",
577577
));
578578
}
579+
580+
#[test]
581+
#[cfg(linux_android)]
582+
fn test_tcp_fast_open_connect() {
583+
let fd = socket(
584+
AddressFamily::Inet,
585+
SockType::Stream,
586+
SockFlag::empty(),
587+
SockProtocol::Tcp,
588+
)
589+
.unwrap();
590+
setsockopt(&fd, sockopt::TcpFastOpenConnect, &true).expect(
591+
"setting TCP_FASTOPEN_CONNECT on an inet stream socket should succeed",
592+
);
593+
assert!(getsockopt(&fd, sockopt::TcpFastOpenConnect).expect(
594+
"getting TCP_FASTOPEN_CONNECT on an inet stream socket should succeed",
595+
));
596+
setsockopt(&fd, sockopt::TcpFastOpenConnect, &false).expect(
597+
"unsetting TCP_FASTOPEN_CONNECT on an inet stream socket should succeed",
598+
);
599+
assert!(!getsockopt(&fd, sockopt::TcpFastOpenConnect).expect(
600+
"getting TCP_FASTOPEN_CONNECT on an inet stream socket should succeed",
601+
));
602+
}

0 commit comments

Comments
 (0)