77#include "util/debug.h"
88
99#include <unistd.h>
10+ #include <sys/poll.h>
1011#include <sys/time.h>
1112#include <sys/socket.h>
1213#include <netdb.h>
@@ -25,18 +26,35 @@ static const char* tryTcpFastOpen(FFNetworkingState* state)
2526 #else
2627 FF_DEBUG ("Attempting to use TCP Fast Open to connect to %s" , state -> host .chars );
2728
29+ #ifndef __APPLE__ // On macOS, TCP_FASTOPEN doesn't seem to be needed
2830 // Set TCP Fast Open
29- int qlen = 5 ;
30- if (setsockopt (state -> sockfd , IPPROTO_TCP , TCP_FASTOPEN , & qlen , sizeof (qlen )) != 0 ) {
31+ #ifdef __linux__
32+ int flag = 5 ; // the queue length of pending packets
33+ #else
34+ int flag = 1 ; // enable TCP Fast Open
35+ #endif
36+ if (setsockopt (state -> sockfd , IPPROTO_TCP ,
37+ #ifdef __APPLE__
38+ // https://github.com/rust-lang/libc/pull/3135
39+ 0x218 // TCP_FASTOPEN_FORCE_ENABLE
40+ #else
41+ TCP_FASTOPEN
42+ #endif
43+ , & flag , sizeof (flag )) != 0 ) {
3144 FF_DEBUG ("Failed to set TCP_FASTOPEN option: %s" , strerror (errno ));
45+ return "setsockopt(TCP_FASTOPEN) failed" ;
3246 } else {
33- FF_DEBUG ("Successfully set TCP_FASTOPEN option, queue length: %d" , qlen );
47+ #ifdef __linux__
48+ FF_DEBUG ("Successfully set TCP_FASTOPEN option, queue length: %d" , flag );
49+ #elif defined(__APPLE__ )
50+ FF_DEBUG ("Successfully set TCP_FASTOPEN_FORCE_ENABLE option" );
51+ #else
52+ FF_DEBUG ("Successfully set TCP_FASTOPEN option" );
53+ #endif
3454 }
55+ #endif
3556
36- // Try to send data using Fast Open
37- #ifdef __APPLE__
38- ssize_t sent = 0 ;
39- #else
57+ #ifndef __APPLE__
4058 FF_DEBUG ("Using sendto() + MSG_FASTOPEN to send %u bytes of data" , state -> command .length );
4159 ssize_t sent = sendto (state -> sockfd ,
4260 state -> command .chars ,
@@ -47,6 +65,28 @@ static const char* tryTcpFastOpen(FFNetworkingState* state)
4765 MSG_DONTWAIT ,
4866 state -> addr -> ai_addr ,
4967 state -> addr -> ai_addrlen );
68+ #else
69+ if (fcntl (state -> sockfd , F_SETFL , O_NONBLOCK ) == -1 ) {
70+ FF_DEBUG ("fcntl(F_SETFL) failed: %s" , strerror (errno ));
71+ return "fcntl(F_SETFL) failed" ;
72+ }
73+ FF_DEBUG ("Using connectx() to send %u bytes of data" , state -> command .length );
74+ // Use connectx to establish connection and send data in one call
75+ size_t sent ;
76+ if (connectx (state -> sockfd ,
77+ & (sa_endpoints_t ) {
78+ .sae_dstaddr = state -> addr -> ai_addr ,
79+ .sae_dstaddrlen = state -> addr -> ai_addrlen ,
80+ },
81+ SAE_ASSOCID_ANY , CONNECT_DATA_IDEMPOTENT ,
82+ & (struct iovec ) {
83+ .iov_base = state -> command .chars ,
84+ .iov_len = state -> command .length ,
85+ }, 1 , & sent , NULL ) != 0 ) sent = 0 ;
86+ if (fcntl (state -> sockfd , F_SETFL , 0 ) == -1 ) {
87+ FF_DEBUG ("fcntl(F_SETFL) failed: %s" , strerror (errno ));
88+ return "fcntl(F_SETFL) failed" ;
89+ }
5090 #endif
5191 if (sent >= 0 || (errno == EAGAIN || errno == EWOULDBLOCK ))
5292 {
@@ -68,7 +108,11 @@ static const char* tryTcpFastOpen(FFNetworkingState* state)
68108 {
69109 // Fast Open failed
70110 FF_DEBUG ("TCP Fast Open failed: %s (errno=%d)" , strerror (errno ), errno );
111+ #ifdef __APPLE__
112+ return "connectx() failed" ;
113+ #else
71114 return "sendto() failed" ;
115+ #endif
72116 }
73117 #endif
74118}
@@ -313,6 +357,26 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
313357 return "ffNetworkingSendHttpRequest() failed" ;
314358 }
315359
360+ // Set larger initial receive buffer instead of small repeated receives
361+ int rcvbuf = 65536 ; // 64KB
362+ setsockopt (state -> sockfd , SOL_SOCKET , SO_RCVBUF , & rcvbuf , sizeof (rcvbuf ));
363+
364+ #ifdef __APPLE__
365+ // poll for the socket to be readable.
366+ // Because of the non-blocking connectx() call, the connection might not be established yet
367+ FF_DEBUG ("Using poll() to check if socket is readable" );
368+ if (poll (& (struct pollfd ) {
369+ .fd = state -> sockfd ,
370+ .events = POLLIN
371+ }, 1 , timeout > 0 ? (int ) timeout : -1 ) == -1 )
372+ {
373+ FF_DEBUG ("poll() failed: %s (errno=%d)" , strerror (errno ), errno );
374+ close (state -> sockfd );
375+ state -> sockfd = -1 ;
376+ return "poll() failed" ;
377+ }
378+ FF_DEBUG ("Socket is readable, proceeding to receive data" );
379+ #else
316380 if (timeout > 0 )
317381 {
318382 FF_DEBUG ("Setting receive timeout: %u ms" , timeout );
@@ -321,10 +385,7 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
321385 timev .tv_usec = (__typeof__ (timev .tv_usec )) ((timeout % 1000 ) * 1000 ); //milliseconds to microseconds
322386 setsockopt (state -> sockfd , SOL_SOCKET , SO_RCVTIMEO , & timev , sizeof (timev ));
323387 }
324-
325- // Set larger initial receive buffer instead of small repeated receives
326- int rcvbuf = 65536 ; // 64KB
327- setsockopt (state -> sockfd , SOL_SOCKET , SO_RCVBUF , & rcvbuf , sizeof (rcvbuf ));
388+ #endif
328389
329390 FF_DEBUG ("Starting data reception" );
330391 FF_MAYBE_UNUSED int recvCount = 0 ;
0 commit comments