mirror of
https://github.com/shadowsocks/shadowsocks-libev.git
synced 2026-11-02 07:53:43 +00:00
Support TCP fast open on Windows
This commit is contained in:
+77
-1
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user