|
|
@ -371,11 +371,56 @@ server_recv_cb(EV_P_ ev_io *w, int revents) |
|
|
|
ev_io_start(EV_A_ & remote->send_ctx->io); |
|
|
|
ev_timer_start(EV_A_ & remote->send_ctx->watcher); |
|
|
|
} else { |
|
|
|
int s = -1; |
|
|
|
#if defined(MSG_FASTOPEN) && !defined(TCP_FASTOPEN_CONNECT) |
|
|
|
int s = -1; |
|
|
|
s = sendto(remote->fd, remote->buf->data, remote->buf->len, MSG_FASTOPEN, |
|
|
|
(struct sockaddr *)&(remote->addr), remote->addr_len); |
|
|
|
#elif defined(TCP_FASTOPEN_WINSOCK) |
|
|
|
DWORD s = -1; |
|
|
|
DWORD err = 0; |
|
|
|
do { |
|
|
|
int optval = 1; |
|
|
|
// Set fast open option |
|
|
|
if (setsockopt(remote->fd, IPPROTO_TCP, TCP_FASTOPEN, |
|
|
|
&optval, sizeof(optval)) != 0) { |
|
|
|
ERROR("setsockopt"); |
|
|
|
break; |
|
|
|
} |
|
|
|
// Load ConnectEx function |
|
|
|
LPFN_CONNECTEX ConnectEx = winsock_getconnectex(); |
|
|
|
if (ConnectEx == NULL) { |
|
|
|
LOGE("Cannot load ConnectEx() function"); |
|
|
|
err = WSAENOPROTOOPT; |
|
|
|
break; |
|
|
|
} |
|
|
|
// ConnectEx requires a bound socket |
|
|
|
if (winsock_dummybind(remote->fd, |
|
|
|
(struct sockaddr *)&(remote->addr)) != 0) { |
|
|
|
ERROR("bind"); |
|
|
|
break; |
|
|
|
} |
|
|
|
// Call ConnectEx to send data |
|
|
|
memset(&remote->olap, 0, sizeof(remote->olap)); |
|
|
|
remote->connect_ex_done = 0; |
|
|
|
if (ConnectEx(remote->fd, (const struct sockaddr *)&(remote->addr), |
|
|
|
remote->addr_len, remote->buf->data, remote->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(CONNECT_DATA_IDEMPOTENT) |
|
|
|
((struct sockaddr_in *)&(remote->addr))->sin_len = sizeof(struct sockaddr_in); |
|
|
|
sa_endpoints_t endpoints; |
|
|
@ -958,6 +1003,37 @@ remote_send_cb(EV_P_ ev_io *w, int revents) |
|
|
|
server_t *server = remote->server; |
|
|
|
|
|
|
|
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 addr; |
|
|
|
int r = getpeername(remote->fd, (struct sockaddr *)&addr, &len); |
|
|
|