Skip to content

Instantly share code, notes, and snippets.

@nishidy
Last active April 2, 2019 17:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nishidy/a1a8c829ff24439bbfce4bbd90de123f to your computer and use it in GitHub Desktop.
Save nishidy/a1a8c829ff24439bbfce4bbd90de123f to your computer and use it in GitHub Desktop.
TCP_DEFER_ACCEPT test program for client
#include <stdio.h> //printf(), fprintf(), perror()
#include <sys/socket.h> //socket(), connect(), recv()
#include <arpa/inet.h> // struct sockaddr_in, struct sockaddr, inet_ntoa(), inet_aton()
#include <stdlib.h> //atoi(), exit(), EXIT_FAILURE, EXIT_SUCCESS
#include <string.h> //memset()
#include <unistd.h> //close(), sleep()
#include <linux/tcp.h> //TCP_DEFER_ACCEPT
#define MSGSIZE 32
#define MAX_MSGSIZE 1024
#define BUFSIZE (MSGSIZE + 1)
int main(int argc, char *argv[]){
int clientSock;
struct sockaddr_in servSockAddr;
char sendBuffer[BUFSIZE];
char recvBuffer[BUFSIZE];
int byteRcvd;
int defer = 1;
if((clientSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0){
perror("socket() failed");
exit(EXIT_FAILURE);
}
memset(&servSockAddr, 0, sizeof(servSockAddr));
servSockAddr.sin_family = AF_INET;
servSockAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
/*
* host = gethostbyname("DNS");
* if(host != NULL){
* servSockAddr.sin_addr.s_addr = *(unsigned int *)host->h_addr_list[0];
* }
*/
servSockAddr.sin_port = htons(8080);
setsockopt(clientSock, IPPROTO_TCP, TCP_DEFER_ACCEPT, &defer, sizeof(defer) );
if(connect(clientSock, (struct sockaddr*) &servSockAddr, sizeof(servSockAddr)) < 0){
perror("connect() failed.");
exit(EXIT_FAILURE);
}
printf("connect to %s\n", inet_ntoa(servSockAddr.sin_addr));
sleep(1);
sprintf(sendBuffer, "%s", "GET / HTTP/1.1\r\nHost: localhost");
if(send(clientSock, sendBuffer, MSGSIZE, 0) <= 0){
printf("%s\n",sendBuffer);
}
if(recv(clientSock, recvBuffer, MSGSIZE, 0) < 0){
printf("recv() failed.");
exit(EXIT_FAILURE);
}
printf("received: %s\n",recvBuffer);
return 0;
}
@nishidy
Copy link
Author

nishidy commented Apr 2, 2019

TCP_DEFER_ACCEPT on connecting at client side delays final ACK until the first data packet is sent.
However, it only waits up to 200 ms.

$ sudo tcpdump -i lo tcp port 8080
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes

16:44:16.988481 IP localhost.47148 > localhost.webcache: Flags [S], seq 276406526, win 43690, options [mss 65495,sackOK,TS val 406652320 ecr 0,nop,wscale 7], length 0
16:44:16.988490 IP localhost.webcache > localhost.47148: Flags [S.], seq 3041469912, ack 276406527, win 43690, options [mss 65495,sackOK,TS val 406652320 ecr 406652320,nop,wscale 7], length 0
16:44:17.191601 IP localhost.47148 > localhost.webcache: Flags [.], ack 1, win 342, options [nop,nop,TS val 406652523 ecr 406652320], length 0
16:44:17.988721 IP localhost.47148 > localhost.webcache: Flags [P.], seq 1:33, ack 1, win 342, options [nop,nop,TS val 406653321 ecr 406652320], length 32: HTTP: GET / HTTP/1.1
16:44:17.988732 IP localhost.webcache > localhost.47148: Flags [.], ack 33, win 342, options [nop,nop,TS val 406653321 ecr 406653321], length 0
16:44:17.990332 IP localhost.webcache > localhost.47148: Flags [P.], seq 1:16, ack 33, win 342, options [nop,nop,TS val 406653322 ecr 406653321], length 15: HTTP: HTTP/1.1 200 OK[!http]
16:44:17.990349 IP localhost.47148 > localhost.webcache: Flags [.], ack 16, win 342, options [nop,nop,TS val 406653322 ecr 406653322], length 0
16:44:17.990417 IP localhost.47148 > localhost.webcache: Flags [F.], seq 33, ack 16, win 342, options [nop,nop,TS val 406653322 ecr 406653322], length 0
16:44:17.990456 IP localhost.webcache > localhost.47148: Flags [F.], seq 16, ack 34, win 342, options [nop,nop,TS val 406653322 ecr 406653322], length 0
16:44:17.990466 IP localhost.47148 > localhost.webcache: Flags [.], ack 17, win 342, options [nop,nop,TS val 406653322 ecr 406653322], length 0

16:44:36.008776 IP localhost.47150 > localhost.webcache: Flags [S], seq 3668638430, win 43690, options [mss 65495,sackOK,TS val 406671341 ecr 0,nop,wscale 7], length 0
16:44:36.008785 IP localhost.webcache > localhost.47150: Flags [S.], seq 1139238639, ack 3668638431, win 43690, options [mss 65495,sackOK,TS val 406671341 ecr 406671341,nop,wscale 7], length 0
16:44:36.211570 IP localhost.47150 > localhost.webcache: Flags [.], ack 1, win 342, options [nop,nop,TS val 406671543 ecr 406671341], length 0
16:44:37.009055 IP localhost.47150 > localhost.webcache: Flags [P.], seq 1:33, ack 1, win 342, options [nop,nop,TS val 406672341 ecr 406671341], length 32: HTTP: GET / HTTP/1.1
16:44:37.009070 IP localhost.webcache > localhost.47150: Flags [.], ack 33, win 342, options [nop,nop,TS val 406672341 ecr 406672341], length 0
16:44:37.010655 IP localhost.webcache > localhost.47150: Flags [P.], seq 1:16, ack 33, win 342, options [nop,nop,TS val 406672342 ecr 406672341], length 15: HTTP: HTTP/1.1 200 OK[!http]
16:44:37.010660 IP localhost.47150 > localhost.webcache: Flags [.], ack 16, win 342, options [nop,nop,TS val 406672342 ecr 406672342], length 0
16:44:37.010732 IP localhost.47150 > localhost.webcache: Flags [F.], seq 33, ack 16, win 342, options [nop,nop,TS val 406672343 ecr 406672342], length 0
16:44:37.010762 IP localhost.webcache > localhost.47150: Flags [F.], seq 16, ack 34, win 342, options [nop,nop,TS val 406672343 ecr 406672343], length 0
16:44:37.010772 IP localhost.47150 > localhost.webcache: Flags [.], ack 17, win 342, options [nop,nop,TS val 406672343 ecr 406672343], length 0

16:44:58.133843 IP localhost.47152 > localhost.webcache: Flags [S], seq 2477185902, win 43690, options [mss 65495,sackOK,TS val 406693466 ecr 0,nop,wscale 7], length 0
16:44:58.133853 IP localhost.webcache > localhost.47152: Flags [S.], seq 2921685133, ack 2477185903, win 43690, options [mss 65495,sackOK,TS val 406693466 ecr 406693466,nop,wscale 7], length 0
16:44:58.335577 IP localhost.47152 > localhost.webcache: Flags [.], ack 1, win 342, options [nop,nop,TS val 406693667 ecr 406693466], length 0
16:44:59.134168 IP localhost.47152 > localhost.webcache: Flags [P.], seq 1:33, ack 1, win 342, options [nop,nop,TS val 406694466 ecr 406693466], length 32: HTTP: GET / HTTP/1.1
16:44:59.134180 IP localhost.webcache > localhost.47152: Flags [.], ack 33, win 342, options [nop,nop,TS val 406694466 ecr 406694466], length 0
16:44:59.135789 IP localhost.webcache > localhost.47152: Flags [P.], seq 1:16, ack 33, win 342, options [nop,nop,TS val 406694468 ecr 406694466], length 15: HTTP: HTTP/1.1 200 OK[!http]
16:44:59.135796 IP localhost.47152 > localhost.webcache: Flags [.], ack 16, win 342, options [nop,nop,TS val 406694468 ecr 406694468], length 0
16:44:59.135872 IP localhost.47152 > localhost.webcache: Flags [F.], seq 33, ack 16, win 342, options [nop,nop,TS val 406694468 ecr 406694468], length 0
16:44:59.135903 IP localhost.webcache > localhost.47152: Flags [F.], seq 16, ack 34, win 342, options [nop,nop,TS val 406694468 ecr 406694468], length 0
16:44:59.135914 IP localhost.47152 > localhost.webcache: Flags [.], ack 17, win 342, options [nop,nop,TS val 406694468 ecr 406694468], length 0

@nishidy
Copy link
Author

nishidy commented Apr 2, 2019

If I remove sleep(1) right after connect(), we can find that the first data packet is sent with the final ACK. (piggybacking)

$ grep sleep client.c 
#include <unistd.h> //close(), sleep()
	//sleep(1);
$ gcc client.c -o client
$ ./client              
connect to 127.0.0.1
received: HTTP/1.1 200 OK
$ sudo tcpdump -i lo tcp port 8080
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes

17:07:14.709483 IP localhost.47208 > localhost.webcache: Flags [S], seq 2354986443, win 43690, options [mss 65495,sackOK,TS val 408030044 ecr 0,nop,wscale 7], length 0
17:07:14.709493 IP localhost.webcache > localhost.47208: Flags [S.], seq 3089570465, ack 2354986444, win 43690, options [mss 65495,sackOK,TS val 408030044 ecr 408030044,nop,wscale 7], length 0
17:07:14.709609 IP localhost.47208 > localhost.webcache: Flags [P.], seq 1:33, ack 1, win 342, options [nop,nop,TS val 408030044 ecr 408030044], length 32: HTTP: GET / HTTP/1.1
17:07:14.709622 IP localhost.webcache > localhost.47208: Flags [.], ack 33, win 342, options [nop,nop,TS val 408030044 ecr 408030044], length 0
17:07:14.712511 IP localhost.webcache > localhost.47208: Flags [P.], seq 1:16, ack 33, win 342, options [nop,nop,TS val 408030047 ecr 408030044], length 15: HTTP: HTTP/1.1 200 OK[!http]
17:07:14.712650 IP localhost.47208 > localhost.webcache: Flags [F.], seq 33, ack 16, win 342, options [nop,nop,TS val 408030047 ecr 408030047], length 0
17:07:14.712688 IP localhost.webcache > localhost.47208: Flags [F.], seq 16, ack 34, win 342, options [nop,nop,TS val 408030047 ecr 408030047], length 0
17:07:14.712699 IP localhost.47208 > localhost.webcache: Flags [.], ack 17, win 342, options [nop,nop,TS val 408030047 ecr 408030047], length 0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment