Support TCP fast open on Windows

This commit is contained in:
Linus Yang
2018-03-09 17:46:38 +08:00
parent 8adfc5cf24
commit f4c612f832
8 changed files with 265 additions and 5 deletions
+77 -1
View File
@@ -517,11 +517,56 @@ connect_to_remote(EV_P_ struct addrinfo *res,
remote_t *remote = new_remote(sockfd);
if (fast_open) {
int s = -1;
#if defined(MSG_FASTOPEN) && !defined(TCP_FASTOPEN_CONNECT)
int s = -1;
s = sendto(sockfd, server->buf->data, server->buf->len,
MSG_FASTOPEN, res->ai_addr, res->ai_addrlen);
#elif defined(TCP_FASTOPEN_WINSOCK)
DWORD s = -1;
DWORD err = 0;
do {
int optval = 1;
// Set fast open option
if(setsockopt(sockfd, IPPROTO_TCP, TCP_FASTOPEN,
&optval, sizeof(optval)) != 0) {
ERROR("setsockopt");
err = WSAEOPNOTSUPP;
break;
}
// Load ConnectEx function
LPFN_CONNECTEX ConnectEx = winsock_getconnectex();
if (ConnectEx == NULL) {
LOGE("Cannot load ConnectEx() function");
err = WSAEOPNOTSUPP;
break;
}
// ConnectEx requires a bound socket
if (winsock_dummybind(sockfd, res->ai_addr) != 0) {
ERROR("bind");
break;
}
// Call ConnectEx to send data
memset(&remote->olap, 0, sizeof(remote->olap));
remote->connect_ex_done = 0;
if (ConnectEx(sockfd, res->ai_addr, res->ai_addrlen,
server->buf->data, server->buf->len,
&s, &remote->olap)) {
remote->connect_ex_done = 1;
break;
};
// XXX: ConnectEx pending, check later in remote_send
if (WSAGetLastError() == ERROR_IO_PENDING) {
err = CONNECT_IN_PROGRESS;
break;
}
ERROR("ConnectEx");
} while(0);
// Set error number
if (err) {
SetLastError(err);
}
#else
int s = -1;
#if defined(TCP_FASTOPEN_CONNECT)
int optval = 1;
if(setsockopt(sockfd, IPPROTO_TCP, TCP_FASTOPEN_CONNECT,
@@ -1175,6 +1220,37 @@ remote_send_cb(EV_P_ ev_io *w, int revents)
}
if (!remote_send_ctx->connected) {
#ifdef TCP_FASTOPEN_WINSOCK
if (fast_open) {
// Check if ConnectEx is done
if (!remote->connect_ex_done) {
DWORD numBytes;
DWORD flags;
// Non-blocking way to fetch ConnectEx result
if (WSAGetOverlappedResult(remote->fd, &remote->olap,
&numBytes, FALSE, &flags)) {
remote->buf->len -= numBytes;
remote->buf->idx = numBytes;
remote->connect_ex_done = 1;
} else if (WSAGetLastError() == WSA_IO_INCOMPLETE) {
// XXX: ConnectEx still not connected, wait for next time
return;
} else {
ERROR("WSAGetOverlappedResult");
// not connected
close_and_free_remote(EV_A_ remote);
close_and_free_server(EV_A_ server);
return;
};
}
// Make getpeername work
if (setsockopt(remote->fd, SOL_SOCKET,
SO_UPDATE_CONNECT_CONTEXT, NULL, 0) != 0) {
ERROR("setsockopt");
}
}
#endif
struct sockaddr_storage addr;
socklen_t len = sizeof(struct sockaddr_storage);
memset(&addr, 0, len);