diff --git a/src/server.c b/src/server.c index f92bb6c3..7a7a48b8 100644 --- a/src/server.c +++ b/src/server.c @@ -165,10 +165,11 @@ int create_and_bind(const char *host, const char *port) return listen_sock; } -struct remote *connect_to_remote(struct addrinfo *res, const char *iface) +struct remote *connect_to_remote(struct addrinfo *res, struct server *server) { int sockfd; int opt = 1; + const char *iface = server->listen_ctx->iface; // initilize remote socks sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); @@ -192,7 +193,33 @@ struct remote *connect_to_remote(struct addrinfo *res, const char *iface) if (iface) setinterface(sockfd, iface); #endif - connect(sockfd, res->ai_addr, res->ai_addrlen); +#ifdef TCP_FASTOPEN + if (fast_open) { + ssize_t s = sendto(sockfd, server->buf + server->buf_idx, server->buf_len, MSG_FASTOPEN, res->ai_addr, res->ai_addrlen); + if (s == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + // The remote server doesn't support tfo or it's the first connection to the server. + // It will automatically fall back to conventional TCP. + } + else if (errno == EOPNOTSUPP || errno == EPROTONOSUPPORT || errno == ENOPROTOOPT) { + LOGE("fast open is not supported on this platform"); + connect(sockfd, res->ai_addr, res->ai_addrlen); + } + else { + ERROR("sendto"); + } + } + else if (s < server->buf_len) { + server->buf_idx += s; + server->buf_len -= s; + } + else { + server->buf_idx = 0; + server->buf_len = 0; + } + } else +#endif + connect(sockfd, res->ai_addr, res->ai_addrlen); return remote; } @@ -547,7 +574,7 @@ static void server_resolve_cb(EV_P_ ev_io *w, int revents) rp = result; } - struct remote *remote = connect_to_remote(rp, server->listen_ctx->iface); + struct remote *remote = connect_to_remote(rp, server); if (remote == NULL) { diff --git a/src/server.h b/src/server.h index 44769055..d56204a9 100644 --- a/src/server.h +++ b/src/server.h @@ -95,7 +95,7 @@ static void server_resolve_cb(EV_P_ ev_io *w, int revents); static void server_timeout_cb(EV_P_ ev_timer *watcher, int revents); struct remote* new_remote(int fd); -struct remote *connect_to_remote(struct addrinfo *res, const char *iface); +struct remote *connect_to_remote(struct addrinfo *res, struct server *server); void free_remote(struct remote *remote); void close_and_free_remote(EV_P_ struct remote *remote); struct server* new_server(int fd, struct listen_ctx *listener);