Skip to content

Instantly share code, notes, and snippets.

@krrr
Last active October 22, 2017 13: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 krrr/8b5fec3c93dc332bc8109641206529b5 to your computer and use it in GitHub Desktop.
Save krrr/8b5fec3c93dc332bc8109641206529b5 to your computer and use it in GitHub Desktop.
Windows 10 TCP fast open sample
#include <stdio.h>
#include <WinSock2.h>
#include <MSWSock.h>
#include <WS2tcpip.h>
#pragma comment(lib, "Ws2_32.lib")
static LPFN_CONNECTEX ConnectEx = NULL;
static BOOL load_mswsock(void) {
/* Dummy socket needed for WSAIoctl */
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET)
return FALSE;
GUID guid = WSAID_CONNECTEX;
DWORD dwBytes;
if (WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER,
&guid, sizeof(guid),
&ConnectEx, sizeof(ConnectEx),
&dwBytes, NULL, NULL) != 0)
return FALSE;
closesocket(sock);
return TRUE;
}
int main(int argc, char *argv[]) {
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) {
printf("WSAStartup failed");
return 1;
}
if (!load_mswsock()) {
printf("Error loading mswsock functions: %d\n", WSAGetLastError());
return 1;
}
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET) {
printf("socket: %d\n", WSAGetLastError());
return 1;
}
char optVal = TRUE;
if (setsockopt(sock, IPPROTO_TCP, TCP_FASTOPEN, &optVal, sizeof(optVal)) != 0) {
printf("setsockopt failed: %d\n", WSAGetLastError());
return 1;
}
/* ConnectEx requires the socket to be initially bound. */
sockaddr_in addr;
ZeroMemory(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = 0;
if (bind(sock, (SOCKADDR*) &addr, sizeof(addr)) != 0) {
printf("bind failed: %d\n", WSAGetLastError());
return 1;
}
/* Issue ConnectEx and wait for the operation to complete. */
OVERLAPPED ol;
ZeroMemory(&ol, sizeof(ol));
// 198.35.26.96 en.wikipedia
inet_pton(AF_INET, "172.93.41.174", &addr.sin_addr.s_addr);
addr.sin_port = htons(80);
BYTE dat[] = "GET / HTTP/1.0\n\n";
DWORD bytesSent;
BOOL ok = ConnectEx(sock, (SOCKADDR*) &addr, sizeof(addr), dat, sizeof(dat)-1, &bytesSent, &ol);
if (ok) {
printf("ConnectEx succeeded immediately\n");
} else if (WSAGetLastError() == ERROR_IO_PENDING) {
ok = GetOverlappedResult((HANDLE) sock, &ol, &bytesSent, TRUE);
printf("ConnectEx pending\n");
if (!ok)
printf("ConnectEx failed: %d\n", WSAGetLastError());
} else {
printf("ConnectEx failed: %d\n", WSAGetLastError());
return 1;
}
char buf[4096];
recv(sock, buf, 4096, 0);
closesocket(sock);
WSACleanup();
printf("Done\n");
return 0;
}
@krrr
Copy link
Author

krrr commented Jun 27, 2017

连维基百科的443端口成功几率挺大的
然而连我自己服务器的80端口经常出现莫名其妙的延时3秒才回http响应,还有相当大的几率SYN+PSH包丢掉,fallback到传统三次握手。
更让人心寒的是SoftEther VPN内嵌的NAT造成tfo的第一个包100%被丢,然后windows会自动禁用tfo。断开vpn也不会马上恢复

这破玩意儿根本不能用嘛

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