unix: deduplicate socket creation code in tcp.c

Incidentally fixes a rather obscure bug where uv_tcp_connect() reconnected
and leaked a file descriptor when the handle was already busy connecting,
handle->fd was zero (unlikely) and uv_tcp_connect() got called again.
This commit is contained in:
Ben Noordhuis 2012-06-29 18:43:44 +02:00
parent e4a68bb5cb
commit 1a6b6b781c

View File

@ -34,6 +34,26 @@ int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* tcp) {
}
static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) {
int sockfd;
if (handle->fd != -1)
return 0;
sockfd = uv__socket(domain, SOCK_STREAM, 0);
if (sockfd == -1)
return uv__set_sys_error(handle->loop, errno);
if (uv__stream_open((uv_stream_t*)handle, sockfd, flags)) {
close(sockfd);
return -1;
}
return 0;
}
static int uv__bind(uv_tcp_t* tcp,
int domain,
struct sockaddr* addr,
@ -44,23 +64,8 @@ static int uv__bind(uv_tcp_t* tcp,
saved_errno = errno;
status = -1;
if (tcp->fd < 0) {
if ((tcp->fd = uv__socket(domain, SOCK_STREAM, 0)) == -1) {
uv__set_sys_error(tcp->loop, errno);
goto out;
}
if (uv__stream_open((uv_stream_t*)tcp,
tcp->fd,
UV_STREAM_READABLE | UV_STREAM_WRITABLE)) {
close(tcp->fd);
tcp->fd = -1;
status = -2;
goto out;
}
}
assert(tcp->fd >= 0);
if (maybe_new_socket(tcp, domain, UV_STREAM_READABLE|UV_STREAM_WRITABLE))
return -1;
tcp->delayed_error = 0;
if (bind(tcp->fd, addr, addrsize) == -1) {
@ -84,7 +89,6 @@ static int uv__connect(uv_connect_t* req,
struct sockaddr* addr,
socklen_t addrlen,
uv_connect_cb cb) {
int sockfd;
int r;
assert(handle->type == UV_TCP);
@ -92,18 +96,10 @@ static int uv__connect(uv_connect_t* req,
if (handle->connect_req)
return uv__set_sys_error(handle->loop, EALREADY);
if (handle->fd <= 0) {
sockfd = uv__socket(addr->sa_family, SOCK_STREAM, 0);
if (sockfd == -1)
return uv__set_sys_error(handle->loop, errno);
if (uv__stream_open((uv_stream_t*)handle,
sockfd,
UV_STREAM_READABLE | UV_STREAM_WRITABLE)) {
close(sockfd);
return -1;
}
if (maybe_new_socket(handle,
addr->sa_family,
UV_STREAM_READABLE|UV_STREAM_WRITABLE)) {
return -1;
}
handle->delayed_error = 0;
@ -231,33 +227,14 @@ out:
int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
int r;
if (tcp->delayed_error)
return uv__set_sys_error(tcp->loop, tcp->delayed_error);
if (tcp->delayed_error) {
uv__set_sys_error(tcp->loop, tcp->delayed_error);
if (maybe_new_socket(tcp, AF_INET, UV_STREAM_READABLE))
return -1;
}
if (tcp->fd < 0) {
if ((tcp->fd = uv__socket(AF_INET, SOCK_STREAM, 0)) == -1) {
uv__set_sys_error(tcp->loop, errno);
return -1;
}
if (uv__stream_open((uv_stream_t*)tcp, tcp->fd, UV_STREAM_READABLE)) {
close(tcp->fd);
tcp->fd = -1;
return -1;
}
}
assert(tcp->fd >= 0);
r = listen(tcp->fd, backlog);
if (r < 0) {
uv__set_sys_error(tcp->loop, errno);
return -1;
}
if (listen(tcp->fd, backlog))
return uv__set_sys_error(tcp->loop, errno);
tcp->connection_cb = cb;