Created
April 2, 2019 15:18
-
-
Save nishidy/46f034239428d11f43ca6d5ea4205a3b to your computer and use it in GitHub Desktop.
TCP_DEFER_ACCEPT test program for server
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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() | |
#include <linux/tcp.h> //TCP_DEFER_ACCEPT | |
#include <time.h> // | |
#define MSGSIZE 32 | |
#define MAX_MSGSIZE 1024 | |
#define BUFSIZE (MSGSIZE + 1) | |
#define QUEUELIMIT 5 | |
int main(int argc, char *argv[]){ | |
int servSock; | |
struct sockaddr_in servSockAddr; | |
char recvBuffer[BUFSIZE]; | |
char sendBuffer[BUFSIZE]; | |
int byteRcvd; | |
int clientSock; | |
struct sockaddr_in clientSockAddr; | |
unsigned int clientLen; | |
unsigned int recvLen, sendLen; | |
int defer = 1; | |
time_t curtime; | |
FILE *fp; | |
char buf[BUFSIZE]; | |
if((servSock = 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 = htonl(INADDR_ANY); | |
servSockAddr.sin_port = htons(8080); | |
if(bind(servSock, (struct sockaddr *) &servSockAddr, sizeof(servSockAddr)) < 0){ | |
perror("bind() failed."); | |
exit(EXIT_FAILURE); | |
} | |
if(listen(servSock, QUEUELIMIT)<0){ | |
perror("listen() failed."); | |
exit(EXIT_FAILURE); | |
} | |
setsockopt(servSock, IPPROTO_TCP, TCP_DEFER_ACCEPT, &defer, sizeof(defer) ); | |
while(1){ | |
if((clientSock = accept(servSock, (struct sockaddr *) &clientSockAddr, &clientLen))<0){ | |
perror("accept() failed."); | |
exit(EXIT_FAILURE); | |
} | |
curtime = time(NULL); | |
//printf("[%s] accept() unblocked.\n",ctime(&curtime)); | |
if( (fp = popen("date +%T.%3N","r")) == NULL){ | |
perror("popen() failed."); | |
exit(EXIT_FAILURE); | |
} | |
fgets(buf, BUFSIZE, fp); | |
buf[strlen(buf)-1]='\0'; | |
printf("[%s] accept() unblocked.\n",buf); | |
while(1){ | |
if((recvLen = recv(clientSock, recvBuffer, BUFSIZE, 0)) < 0){ | |
printf("recv() failed."); | |
exit(EXIT_FAILURE); | |
} else if (recvLen == 0){ | |
printf("connection closed by foreign host.\n"); | |
break; | |
} | |
if( (fp = popen("date +%T.%3N","r")) == NULL){ | |
perror("popen() failed."); | |
exit(EXIT_FAILURE); | |
} | |
fgets(buf, BUFSIZE, fp); | |
buf[strlen(buf)-1]='\0'; | |
printf("[%s] received: %s\n",buf,recvBuffer); | |
sprintf(sendBuffer, "HTTP/1.1 200 OK"); | |
if((sendLen = send(clientSock, sendBuffer, strlen(sendBuffer), 0)) < 0){ | |
perror("send() failed."); | |
exit(EXIT_FAILURE); | |
} else if (sendLen == 0){ | |
printf("connection closed by foreign host.\n"); | |
break; | |
} | |
} | |
close(clientSock); | |
} | |
return 0; | |
} |
I want to confirm if TCP_DEFER_ACCEPT recovers from a packet loss of final ACK.
However, even if TCP_DEFER_ACCEPT is not enabled, it recovers from the packet loss.
I drop the packet by iptables as follows.
You can see it works because FIN packets are re-sent continuously since ACK packet is discarded.
On the other hand, data packets are sent successfully.
$ grep setsockopt server.c
//setsockopt(servSock, IPPROTO_TCP, TCP_DEFER_ACCEPT, &defer, sizeof(defer) );
$ gcc server.c -o server
$ ./server
[16:34:35.045] accept() unblocked.
[16:34:35.046] received: GET / HTTP/1.1
Host: localhost
connection closed by foreign host.
$ sudo iptables -A INPUT -s 127.0.0.1 -p tcp --tcp-flags SYN,RST,ACK,FIN,PSH ACK -j REJECT
$ 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:34:34.043650 IP localhost.47130 > localhost.webcache: Flags [S], seq 808598401, win 43690, options [mss 65495,sackOK,TS val 406069374 ecr 0,nop,wscale 7], length 0
16:34:34.043661 IP localhost.webcache > localhost.47130: Flags [S.], seq 3393701262, ack 808598402, win 43690, options [mss 65495,sackOK,TS val 406069375 ecr 406069374,nop,wscale 7], length 0
16:34:34.043671 IP localhost.47130 > localhost.webcache: Flags [.], ack 1, win 342, options [nop,nop,TS val 406069375 ecr 406069375], length 0
16:34:35.043931 IP localhost.47130 > localhost.webcache: Flags [P.], seq 1:33, ack 1, win 342, options [nop,nop,TS val 406070375 ecr 406069375], length 32: HTTP: GET / HTTP/1.1
16:34:35.043956 IP localhost.webcache > localhost.47130: Flags [.], ack 33, win 342, options [nop,nop,TS val 406070375 ecr 406070375], length 0
16:34:35.046965 IP localhost.webcache > localhost.47130: Flags [P.], seq 1:16, ack 33, win 342, options [nop,nop,TS val 406070378 ecr 406070375], length 15: HTTP: HTTP/1.1 200 OK[!http]
16:34:35.046974 IP localhost.47130 > localhost.webcache: Flags [.], ack 16, win 342, options [nop,nop,TS val 406070378 ecr 406070378], length 0
16:34:35.047200 IP localhost.47130 > localhost.webcache: Flags [F.], seq 33, ack 16, win 342, options [nop,nop,TS val 406070378 ecr 406070378], length 0
16:34:35.047230 IP localhost.webcache > localhost.47130: Flags [F.], seq 16, ack 34, win 342, options [nop,nop,TS val 406070378 ecr 406070378], length 0
16:34:35.047240 IP localhost.47130 > localhost.webcache: Flags [.], ack 17, win 342, options [nop,nop,TS val 406070378 ecr 406070378], length 0
16:34:37.019592 IP localhost.webcache > localhost.47130: Flags [F.], seq 16, ack 34, win 342, options [nop,nop,TS val 406072350 ecr 406070378], length 0
16:34:37.019607 IP localhost.47130 > localhost.webcache: Flags [.], ack 17, win 342, options [nop,nop,TS val 406072350 ecr 406070378], length 0
16:34:40.027580 IP localhost.webcache > localhost.47130: Flags [F.], seq 16, ack 34, win 342, options [nop,nop,TS val 406075358 ecr 406070378], length 0
16:34:40.027595 IP localhost.47130 > localhost.webcache: Flags [.], ack 17, win 342, options [nop,nop,TS val 406075358 ecr 406070378], length 0
16:34:45.915577 IP localhost.webcache > localhost.47130: Flags [F.], seq 16, ack 34, win 342, options [nop,nop,TS val 406081246 ecr 406070378], length 0
16:34:45.915591 IP localhost.47130 > localhost.webcache: Flags [.], ack 17, win 342, options [nop,nop,TS val 406081246 ecr 406070378], length 0
16:34:57.691576 IP localhost.webcache > localhost.47130: Flags [F.], seq 16, ack 34, win 342, options [nop,nop,TS val 406093022 ecr 406070378], length 0
16:34:57.691588 IP localhost.47130 > localhost.webcache: Flags [.], ack 17, win 342, options [nop,nop,TS val 406093022 ecr 406070378], length 0
16:35:22.011602 IP localhost.webcache > localhost.47130: Flags [F.], seq 16, ack 34, win 342, options [nop,nop,TS val 406117342 ecr 406070378], length 0
16:35:22.011613 IP localhost.47130 > localhost.webcache: Flags [.], ack 17, win 342, options [nop,nop,TS val 406117343 ecr 406070378], length 0
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
When TCP_DEFER_ACCEPT was not enabled, accept() was unblocked before the data was received.
When it was enabled, accept() was unblocked right after the data was received.