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