Skip to content
This repository has been archived by the owner on May 4, 2018. It is now read-only.

windows: relay TCP bind errors via ipc #1384

Merged
merged 1 commit into from
Jul 31, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/uv-win.h
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);

#define UV_TCP_PRIVATE_FIELDS \
SOCKET socket; \
int bind_error; \
int delayed_error; \
union { \
struct { uv_tcp_server_fields }; \
struct { uv_tcp_connection_fields }; \
Expand Down
9 changes: 7 additions & 2 deletions src/win/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ extern UV_THREAD_LOCAL int uv__crt_assert_enabled;
/* Used by streams and UDP handles. */
#define UV_HANDLE_READING 0x00000100
#define UV_HANDLE_BOUND 0x00000200
#define UV_HANDLE_BIND_ERROR 0x00000400
#define UV_HANDLE_LISTENING 0x00000800
#define UV_HANDLE_CONNECTION 0x00001000
#define UV_HANDLE_CONNECTED 0x00002000
Expand Down Expand Up @@ -125,6 +124,12 @@ extern UV_THREAD_LOCAL int uv__crt_assert_enabled;
/*
* TCP
*/

typedef struct {
WSAPROTOCOL_INFOW socket_info;
int delayed_error;
} uv__ipc_socket_info_ex;

int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb);
int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client);
int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
Expand All @@ -143,7 +148,7 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp);
void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle);

int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info,
int uv_tcp_import(uv_tcp_t* tcp, uv__ipc_socket_info_ex* socket_info_ex,
int tcp_connection);

int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid,
Expand Down
25 changes: 14 additions & 11 deletions src/win/pipe.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ typedef struct uv__ipc_queue_item_s uv__ipc_queue_item_t;

struct uv__ipc_queue_item_s {
/*
* NOTE: It is important for socket_info to be the first field,
* NOTE: It is important for socket_info_ex to be the first field,
* because we will we assigning it to the pending_ipc_info.socket_info
*/
WSAPROTOCOL_INFOW socket_info;
uv__ipc_socket_info_ex socket_info_ex;
QUEUE member;
int tcp_connection;
};
Expand Down Expand Up @@ -73,7 +73,7 @@ typedef struct {
/* IPC frame, which contains an imported TCP socket stream. */
typedef struct {
uv_ipc_frame_header_t header;
WSAPROTOCOL_INFOW socket_info;
uv__ipc_socket_info_ex socket_info_ex;
} uv_ipc_frame_uv_stream;

static void eof_timer_init(uv_pipe_t* pipe);
Expand Down Expand Up @@ -408,7 +408,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
socket = WSASocketW(FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO,
&item->socket_info,
&item->socket_info_ex.socket_info,
0,
WSA_FLAG_OVERLAPPED);
free(item);
Expand Down Expand Up @@ -787,7 +787,7 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
item = QUEUE_DATA(q, uv__ipc_queue_item_t, member);

err = uv_tcp_import((uv_tcp_t*)client,
&item->socket_info,
&item->socket_info_ex,
item->tcp_connection);
if (err != 0)
return err;
Expand Down Expand Up @@ -1132,10 +1132,13 @@ static int uv_pipe_write_impl(uv_loop_t* loop,
tcp_send_handle = (uv_tcp_t*)send_handle;

err = uv_tcp_duplicate_socket(tcp_send_handle, handle->ipc_pid,
&ipc_frame.socket_info);
&ipc_frame.socket_info_ex.socket_info);
if (err) {
return err;
}

ipc_frame.socket_info_ex.delayed_error = tcp_send_handle->delayed_error;

ipc_frame.header.flags |= UV_IPC_TCP_SERVER;

if (tcp_send_handle->flags & UV_HANDLE_CONNECTION) {
Expand Down Expand Up @@ -1395,15 +1398,15 @@ static void uv_pipe_read_error_or_eof(uv_loop_t* loop, uv_pipe_t* handle,


void uv__pipe_insert_pending_socket(uv_pipe_t* handle,
WSAPROTOCOL_INFOW* info,
uv__ipc_socket_info_ex* info,
int tcp_connection) {
uv__ipc_queue_item_t* item;

item = (uv__ipc_queue_item_t*) malloc(sizeof(*item));
if (item == NULL)
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");

memcpy(&item->socket_info, info, sizeof(item->socket_info));
memcpy(&item->socket_info_ex, info, sizeof(item->socket_info_ex));
item->tcp_connection = tcp_connection;
QUEUE_INSERT_TAIL(&handle->pending_ipc_info.queue, &item->member);
handle->pending_ipc_info.queue_len++;
Expand Down Expand Up @@ -1469,11 +1472,11 @@ void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,

if (ipc_frame.header.flags & UV_IPC_TCP_SERVER) {
assert(avail - sizeof(ipc_frame.header) >=
sizeof(ipc_frame.socket_info));
sizeof(ipc_frame.socket_info_ex));

/* Read the TCP socket info. */
if (!ReadFile(handle->handle,
&ipc_frame.socket_info,
&ipc_frame.socket_info_ex,
sizeof(ipc_frame) - sizeof(ipc_frame.header),
&bytes,
NULL)) {
Expand All @@ -1487,7 +1490,7 @@ void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
/* Store the pending socket info. */
uv__pipe_insert_pending_socket(
handle,
&ipc_frame.socket_info,
&ipc_frame.socket_info_ex,
ipc_frame.header.flags & UV_IPC_TCP_CONNECTION);
}

Expand Down
48 changes: 23 additions & 25 deletions src/win/tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) {
handle->func_acceptex = NULL;
handle->func_connectex = NULL;
handle->processed_accepts = 0;
handle->delayed_error = 0;

return 0;
}
Expand Down Expand Up @@ -302,8 +303,7 @@ static int uv_tcp_try_bind(uv_tcp_t* handle,
err = WSAGetLastError();
if (err == WSAEADDRINUSE) {
/* Some errors are not to be reported until connect() or listen() */
handle->bind_error = err;
handle->flags |= UV_HANDLE_BIND_ERROR;
handle->delayed_error = err;
} else {
return err;
}
Expand Down Expand Up @@ -528,8 +528,8 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
return WSAEISCONN;
}

if (handle->flags & UV_HANDLE_BIND_ERROR) {
return handle->bind_error;
if (handle->delayed_error) {
return handle->delayed_error;
}

if (!(handle->flags & UV_HANDLE_BOUND)) {
Expand All @@ -539,8 +539,8 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
0);
if (err)
return err;
if (handle->flags & UV_HANDLE_BIND_ERROR)
return handle->bind_error;
if (handle->delayed_error)
return handle->delayed_error;
}

if (!handle->func_acceptex) {
Expand Down Expand Up @@ -712,8 +712,8 @@ static int uv_tcp_try_connect(uv_connect_t* req,
DWORD bytes;
int err;

if (handle->flags & UV_HANDLE_BIND_ERROR) {
return handle->bind_error;
if (handle->delayed_error) {
return handle->delayed_error;
}

if (!(handle->flags & UV_HANDLE_BOUND)) {
Expand All @@ -727,8 +727,8 @@ static int uv_tcp_try_connect(uv_connect_t* req,
err = uv_tcp_try_bind(handle, bind_addr, addrlen, 0);
if (err)
return err;
if (handle->flags & UV_HANDLE_BIND_ERROR)
return handle->bind_error;
if (handle->delayed_error)
return handle->delayed_error;
}

if (!handle->func_connectex) {
Expand Down Expand Up @@ -777,8 +777,8 @@ int uv_tcp_getsockname(const uv_tcp_t* handle,
return UV_EINVAL;
}

if (handle->flags & UV_HANDLE_BIND_ERROR) {
return uv_translate_sys_error(handle->bind_error);
if (handle->delayed_error) {
return uv_translate_sys_error(handle->delayed_error);
}

result = getsockname(handle->socket, name, namelen);
Expand All @@ -799,8 +799,8 @@ int uv_tcp_getpeername(const uv_tcp_t* handle,
return UV_EINVAL;
}

if (handle->flags & UV_HANDLE_BIND_ERROR) {
return uv_translate_sys_error(handle->bind_error);
if (handle->delayed_error) {
return uv_translate_sys_error(handle->delayed_error);
}

result = getpeername(handle->socket, name, namelen);
Expand Down Expand Up @@ -1117,14 +1117,13 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
}


int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info,
int uv_tcp_import(uv_tcp_t* tcp, uv__ipc_socket_info_ex* socket_info_ex,
int tcp_connection) {
int err;

SOCKET socket = WSASocketW(FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO,
socket_protocol_info,
&socket_info_ex->socket_info,
0,
WSA_FLAG_OVERLAPPED);

Expand All @@ -1141,7 +1140,7 @@ int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info,
err = uv_tcp_set_socket(tcp->loop,
tcp,
socket,
socket_protocol_info->iAddressFamily,
socket_info_ex->socket_info.iAddressFamily,
1);
if (err) {
closesocket(socket);
Expand All @@ -1156,6 +1155,8 @@ int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info,
tcp->flags |= UV_HANDLE_BOUND;
tcp->flags |= UV_HANDLE_SHARED_TCP_SOCKET;

tcp->delayed_error = socket_info_ex->delayed_error;

tcp->loop->active_tcp_streams++;
return 0;
}
Expand Down Expand Up @@ -1216,13 +1217,10 @@ int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid,
return ERROR_INVALID_PARAMETER;
}

/* Report any deferred bind errors now. */
if (handle->flags & UV_HANDLE_BIND_ERROR) {
return handle->bind_error;
}

if (listen(handle->socket, SOMAXCONN) == SOCKET_ERROR) {
return WSAGetLastError();
if (!(handle->delayed_error)) {
if (listen(handle->socket, SOMAXCONN) == SOCKET_ERROR) {
handle->delayed_error = WSAGetLastError();
}
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions test/run-tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
int ipc_helper(int listen_after_write);
int ipc_helper_tcp_connection(void);
int ipc_send_recv_helper(void);
int ipc_helper_bind_twice(void);
int stdio_over_pipes_helper(void);

static int maybe_run_test(int argc, char **argv);
Expand Down Expand Up @@ -82,6 +83,10 @@ static int maybe_run_test(int argc, char **argv) {
return ipc_helper_tcp_connection();
}

if (strcmp(argv[1], "ipc_helper_bind_twice") == 0) {
return ipc_helper_bind_twice();
}

if (strcmp(argv[1], "stdio_over_pipes_helper") == 0) {
return stdio_over_pipes_helper();
}
Expand Down
Loading